diff --git a/.appveyor.yml b/.appveyor.yml index 2b72b508a288f..ee4818c7917e0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,5 +1,5 @@ version: '{branch}.{build}' -image: Previous Visual Studio 2019 +image: Visual Studio 2019 configuration: Release platform: x64 shallow_clone: true diff --git a/.clang-tidy b/.clang-tidy index 77f4f5274f2a0..6bebf2ef578c9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -35,8 +35,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --modernize-use-transparent-functors,\ --performance-for-range-copy,\ -performance-inefficient-vector-operation,\ -performance-noexcept-move-constructor,\ -performance-implicit-conversion-in-loop,\ diff --git a/.gitignore b/.gitignore index 5776d2ca2ed77..e5a0613ca1770 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,9 @@ Cataclysm.exe.lastcodeanalysissucceeded #Visual Studio 2017 /msvc-full-features/PredictedInputCache_Debug_x64.dat +#vcpkg +/msvc-full-features/vcpkg_installed + # PVS Studio /msvc-full-features/*PVS-Studio* diff --git a/build-scripts/build.sh b/build-scripts/build.sh index c7cdd1a135996..eebe7f135dedc 100755 --- a/build-scripts/build.sh +++ b/build-scripts/build.sh @@ -124,7 +124,6 @@ then else remaining_cpp_files="$all_cpp_files" fi - set -x function analyze_files_in_random_order { @@ -142,6 +141,7 @@ then echo "Analyzing remaining files" analyze_files_in_random_order "$remaining_cpp_files" + set -x else # Regular build make -j$num_jobs diff --git a/build-scripts/clang-tidy-wrapper.sh b/build-scripts/clang-tidy-wrapper.sh index b1ea138356676..4ff613644422e 100755 --- a/build-scripts/clang-tidy-wrapper.sh +++ b/build-scripts/clang-tidy-wrapper.sh @@ -5,7 +5,6 @@ set -o pipefail plugin=build/tools/clang-tidy-plugin/libCataAnalyzerPlugin.so -set -x if [ -f "$plugin" ] then LD_PRELOAD=$plugin "$CATA_CLANG_TIDY" "$@" diff --git a/data/core/basic.json b/data/core/basic.json index 8ea36066cbbf7..b825d6e455bfe 100644 --- a/data/core/basic.json +++ b/data/core/basic.json @@ -12,8 +12,8 @@ "category": "food", "name": { "str_sp": "water" }, "description": "Water, the stuff of life, the best thirst-quencher available. It would be safer to drink once purified.", - "weight": 250, - "volume": 1, + "weight": "250 g", + "volume": "250 ml", "price": 50, "symbol": "~", "color": "light_blue", diff --git a/data/json/artifact/relic_procgen_data.json b/data/json/artifact/relic_procgen_data.json new file mode 100644 index 0000000000000..b9c8593b5ea80 --- /dev/null +++ b/data/json/artifact/relic_procgen_data.json @@ -0,0 +1,125 @@ +[ + { + "type": "relic_procgen_data", + "id": "cult", + "passive_add_procgen_values": [ + { "weight": 100, "min_value": -1, "max_value": 1, "type": "STRENGTH", "increment": 1, "power_per_increment": 250 }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "DEXTERITY", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "PERCEPTION", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "INTELLIGENCE", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -100, + "max_value": 25, + "type": "SPEED", + "increment": 5, + "power_per_increment": 200 + } + ], + "type_weights": [ { "weight": 100, "value": "passive_enchantment_add" } ], + "items": [ { "weight": 100, "item": "spoon" } ] + }, + { + "type": "relic_procgen_data", + "id": "netherum_tunnels", + "passive_add_procgen_values": [ + { "weight": 100, "min_value": -1, "max_value": 1, "type": "STRENGTH", "increment": 1, "power_per_increment": 250 }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "DEXTERITY", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "PERCEPTION", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "INTELLIGENCE", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -100, + "max_value": 25, + "type": "SPEED", + "increment": 5, + "power_per_increment": 200 + } + ], + "type_weights": [ { "weight": 100, "value": "passive_enchantment_add" } ], + "items": [ { "weight": 100, "item": "spoon" } ] + }, + { + "type": "relic_procgen_data", + "id": "alien_reality", + "passive_add_procgen_values": [ + { "weight": 100, "min_value": -1, "max_value": 1, "type": "STRENGTH", "increment": 1, "power_per_increment": 250 }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "DEXTERITY", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "PERCEPTION", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "INTELLIGENCE", + "increment": 1, + "power_per_increment": 250 + }, + { + "weight": 100, + "min_value": -100, + "max_value": 25, + "type": "SPEED", + "increment": 5, + "power_per_increment": 200 + } + ], + "type_weights": [ { "weight": 100, "value": "passive_enchantment_add" } ], + "items": [ { "weight": 100, "item": "spoon" } ] + } +] diff --git a/data/json/ascii_arts.json b/data/json/ascii_arts.json index 67d8c18292ba8..942de32c24045 100644 --- a/data/json/ascii_arts.json +++ b/data/json/ascii_arts.json @@ -219,5 +219,502 @@ " ║ HEAVY ║", " ╚═══════════════╝" ] + }, + { + "type": "ascii_art", + "id": "mp3", + "picture": [ + "", + "", + "            /\\         /\\", + "           /  \\       /  \\", + "          /    \\     /    \\", + "         /      \\   /      \\", + "         ║       \\ /       ║", + "      ___║        |        ║___", + "     |   /        |        \\   |", + "     |__/         |         \\__|", + "                  |", + "                  |", + "                  |", + "     ╔═══════════════════════════╗", + "     ║  ╔═════════════════════╗  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ║                     ║  ║", + "     ║  ╚═════════════════════╝  ║", + "     ║                           ║", + "     ║         .........         ║", + "     ║      ...         ...      ║", + "     ║     .     MENU      .     ║", + "     ║    .      .....      .    ║", + "     ║   .      .     .      .   ║", + "     ║   .  ⏮  .   ⏯   .  ⏭  .   ║", + "     ║   .      .     .      .   ║", + "     ║    .      .....      .    ║", + "     ║     .               .     ║", + "     ║      ...   VOL   ...      ║", + "     ║         .........         ║", + "     ║                           ║", + "     ╚═╦═════════════════════════╝", + "       ║          |", + "       \\          |", + "        \\        /", + "         \\      /", + "          \\    /", + "           \\  /", + "            \\/" + ] + }, + { + "type": "ascii_art", + "id": "lajatang", + "picture": [ + "", + "  .                  .", + " ..                  ..", + " ..                  ..", + " ...                ...", + " ....              ....", + "  ....            ....", + "    .....      .....", + "      ............", + "        ........", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "           ||", + "          ||", + "          ||", + "           ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "          ||", + "           ||", + "           ||", + "           ||", + "           ||", + "           ||", + "          ||", + "          ||", + "       ........", + "     ............", + "    .....      .....", + "  ....            ....", + " ....              ....", + " ...                ...", + " ..                  ..", + " ..                  ..", + "  .                  ." + ] + }, + { + "type": "ascii_art", + "id": "wristwatch", + "picture": [ + "", + "   _____", + "       /     \\", + "        │  o  │", + "        │     │", + "        │  o  │", + "        │     │", + "        │  o  │", + "        │     │", + "        │  o  │", + "        │     │", + "        │  o  │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "       .........", + "    ...   12    ...", + "   .   11  │   1   .", + "  . 10     │      2 .", + " .         │         .", + " . 9       └───     3.", + " .                   .", + "  . 8             4 .", + "   .   7       5   .", + "    ...    6    ...", + "       .........", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        │     │", + "        └─────┘", + "        ║  ║  ║", + "        ╚══╩══╝" + ] + }, + { + "type": "ascii_art", + "id": "mobile_memory_card", + "picture": [ + "", + "", + " ______________", + "   /  ╔╗╔╗╔╗╔╗╔╗╔╗|", + "  /╔╗ ╚╝╚╝╚╝╚╝╚╝╚╝|", + " / ╚╝            |", + " |                |", + " |                |", + " |                |", + " |                |", + " |                |", + " | MADE IN CHINA  |", + " |________________|" + ] + }, + { + "type": "ascii_art", + "id": "halberd", + "picture": [ + "", + "        .", + "        .", + "        .", + "        .", + "       ...", + "       ...", + "       ...", + "       ...      ...", + "       ...     .......", + "       ...    ..........", + "      .....  ............", + "     .....................", + "    .......................", + "   ........................", + "  .........................", + " ...    ..  ..............", + " .      ..   ............", + "        ..    ..........", + "        ..     .......", + "        ..      ...", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        ..", + "        .." + ] + }, + { + "type": "ascii_art", + "id": "1st_aid", + "picture": [ + "", + "", + "            ╔═══════════╗", + "   ════════════════════════════════╗", + "  /         ║           ║          / ║", + " ╔═════════╩═══════════╩═════════╗  ║", + "  ║                               ║  ║", + "  ║             ╔═══╗             ║  ║", + "  ║             ║   ║             ║  ║", + " ║         ╔═══╝   ╚═══╗         ║  ║", + " ║         ║           ║         ║  ║", + "  ║         ╚═══╗   ╔═══╝         ║  ║", + " ║             ║   ║             ║  ║", + " ║             ╚═══╝             ║  ║", + "  ║                               ║ /", + "  ╚═══════════════════════════════╝" + ] + }, + { + "type": "ascii_art", + "id": "thermometer", + "picture": [ + "", + "", + "         :::::::::", + "      :::         :::", + "    ::      ┌─┐      ::", + "   :120_____│ │------50:", + "  :     ____│ │----     :", + " :      ____│ │----      :", + " :100 ______│ │------ 40 :", + " :      ____│ │----      :", + " :      ____│ │----      :", + " : 80 ______│ │------ 30 :", + " :      ____│ │----      :", + " :      ----│ │----      :", + " :      ----││------ 20 :", + " : 60 ------││----      :", + " :      ----││----      :", + " :      ----││------ 10 :", + " :      ----││----      :", + " : 40 ------││----      :", + " :      ____││______ 0  :", + " :      ____││____      :", + " : 20 ______││____      :", + " :      ____││____      :", + " :      ____││------ -10:", + " :      ____││----      :", + " :  0 ------││----      :", + " :          ││------ -20:", + " :          ││          :", + " :          ││          :", + " :  °F      ││      °C  :", + " :          ││          :", + " :          ││          :", + " :::::::::::::::::::::::::" + ] + }, + { + "type": "ascii_art", + "id": "umbrella", + "picture": [ + "", + "", + "                :::::::::::", + "           :::::###########:::::", + "         ::####:###########:####::", + "       ::#####:#############:#####::", + "      :######:###############:######:", + "     :#######:###############:#######:", + "    :#######:#################:#######:", + "   :##:::::::#####:::::::#####:::::::##:", + "  :#::       ::#::  I|I  ::#::       ::#:", + "  :::         :::   I|I   :::         :::", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                    I|I", + "                J   JJJ", + "                JJJJJJJ", + "                 JJJJJ" + ] + }, + { + "type": "ascii_art", + "id": "badge_deputy", + "picture": [ + "", + "                   ⚪", + "                  / \\", + "                 /   \\", + "                /     \\", + "      ⚪ _______/       \\_______ ⚪", + "       \\                        /", + "        \\          /", + "         \\    ════════════    /", + "          \\     DEPUTY     /", + "         /    SHERIFF     \\", + "        /     ════════════    \\", + "       /            \\", + "      /_______           _______\\", + "     ⚪         \\       /         ⚪", + "                \\     /", + "                 \\   /", + "                  \\ /", + "                   ⚪" + ] + }, + { + "type": "ascii_art", + "id": "box_cigarette", + "picture": [ + "", + "                     ╔══╗", + "                ╔══╗   ", + "┌───────────────    ───────────────┐", + "│          ╔══╗                     │", + "│                   ╔══╗          │", + "│     ╔══╗                      │", + "│                             │", + "│                    ╔══╗     │", + "│                           │", + "├─┐                       ┌─┤", + "│ └┐                     ┌┘ │", + "│                         │", + "│                         │", + "│ └──╨──╨─╨──╨─╨──╨─╨──╨─╨──╨─╨──╨──┘ │", + "│                                       │", + "│ _________ .__ │", + "│ \\_ ___ \\|__| ____ ______ │", + "│ / \\ \\/| |/ ___\\/ ___/ │", + "│ \\ \\___| / /_/ >___ \\ │", + "│ \\______ /__\\___ /____ > │", + "│ \\/ /_____/ \\/ │", + "│ ________ __ │", + "│ \\______ \\ _____ _______| | __ │", + "│ | | \\\\__ \\\\_ __ \\ |/ / │", + "│ | ` \\/ __ \\| | \\/ < │", + "│ /_______ (____ /__| |__|_ \\ │", + "│ \\/ \\/ \\/ │", + "│ .____ │", + "│ | | __ __ ____ ____ _____ │", + "│ | | | | \\/ \\ / ___\\/ ___/│", + "│ | |___| | / | \\/ /_/ >___ \\ │", + "│ |_______ \\____/|___| /\\___ /____ >│", + "│ \\/ \\//_____/ \\/ │", + "│ _____ .__ ._ │", + "│ / _ \\ | |__ ____ _____ __| |│", + "│ / /_\\ \\| | \\_/ __ \\\\__ \\ / __ |│", + "│/ | \\ Y \\ ___/ / __ \\_/ /_/ |│", + "│\\____|__ /___| /\\___ >____ /\\____ |│", + "│ \\/ \\/ \\/ \\/ \\/│", + "│                                       │", + "└───────────────────────────────────────┘" + ] + }, + { + "type": "ascii_art", + "id": "textbook_chemistry", + "picture": [ + "", + "   /════════════════════════════════════╗", + "  /───────────────────────────────────┐│", + " /───────────────────────────────────┐││", + "╔═══════════════════════════════════╗│││", + "   Textbook by K.M. Pozdro     │││", + "     ╔═╗╦ ╦╔═╗╔╦╗╦╔═╗╔╦╗╦═╗╦ ╦     │││", + "     ║ ╠═╣║╣ ║║║║╚═╗ ║ ╠╦╝╚╦╝     │││", + "     ╚═╝╩ ╩╚═╝╩ ╩╩╚═╝ ╩ ╩╚═ ╩      │││", + "                        _____     │││", + "                             \\\\   │││", + "                              \\\\  │││", + "                //            /   │││", + "               //            /    │││", + " \\             \\             \\\\   │││", + "  \\             \\_____        \\\\  │││", + "  /       ///   /     \\       /   │││", + " /       ///   /       \\     /    │││", + " \\       /     \\      //     \\    │││", + "  \\_____/       \\____//       \\   │││", + "  /     \\       /             /   │││", + " /       \\_____/        _____/    │││", + " \\       //    \\             \\    │││", + "  \\_____//      \\_____        \\   │││", + "        \\       /    \\\\       //  │││", + "         \\_____/      \\\\     //   │││", + " \\       /     \\       /     \\    │││", + "  \\_____/       \\_____/       \\   │││", + "  /     \\       /             /   │││", + " /       \\_____/        _____/    │││", + "               \\       /          │││", + "                \\_____/           │││", + "                                 ││/", + "                                 │/", + "╚═══════════════════════════════════╝" + ] + }, + { + "type": "ascii_art", + "id": "electrohack", + "picture": [ + "", + "                     ┌────┐", + "                     │□  □│", + "                         ", + "      ╔════════════════════════╗", + "      001100010011001100110011", + "      001101110100100000110100", + "      011110000011000001110010", + "       ╚════════════════════════╝", + "        ╚╝╚╝╚╝               ", + "                             ", + "                             ╚══──", + "                            ╚════──", + "                           ╚══════──" + ] + }, + { + "type": "ascii_art", + "id": "manual_first_aid", + "picture": [ + "   /════════════════════════════════════╗", + "  /───────────────────────────────────┐│║", + " /───────────────────────────────────┐││║", + "╔═══════════════════════════════════╗│││║", + "║                                   │││║", + "║                                   │││║", + "╔╦╗╦ ╦╔═╗ ╔╗ ╦╔═╗ ╔╗ ╔═╗╔═╗╦╔═  │││║", + "║ ╠═╣║╣ ╠╩╗║║ ╦ ╠╩╗║ ║║ ║╠╩╗  │││║", + "╩ ╩ ╩╚═╝ ╚═╝╩╚═╝ ╚═╝╚═╝╚═╝╩ ╩ │││║", + "║  ╔═╗╔═╗ ╔═╗╦╦═╗╔═╗╔╦╗ ╔═╗╦╔╦╗   │││║", + "║  ║ ║╠╣ ╠╣ ║╠╦╝╚═╗ ║ ╠═╣║ ║║   │││║", + "║  ╚═╝╚ ╚ ╩╩╚═╚═╝ ╩ ╩ ╩╩═╩╝   │││║", + "║                                   │││║", + "║              │││║", + "║              │││║", + "║              │││║", + "║              ╔═════╗          │││║", + "║              ║     ║          │││║", + "║              ║     ║          │││║", + "║              ║     ║          │││║", + "║       ╔══════╝     ╚══════╗   │││║", + "║       ║                   ║   │││║", + "║       ║                   ║   │││║", + "║       ╚══════╗     ╔══════╝   │││║", + "║              ║     ║          │││║", + "║              ║     ║              │││║", + "║              ║     ║              │││║", + "║              ╚═════╝              │││║", + "║                                   │││║", + "║                                   │││║", + "║             By C. Red             │││║", + "║                                   ││/", + "║                                   │/", + "╚═══════════════════════════════════╝" + ] } ] diff --git a/data/json/body_parts.json b/data/json/body_parts.json index 21a845e65be0c..c55f0943ac93b 100644 --- a/data/json/body_parts.json +++ b/data/json/body_parts.json @@ -109,6 +109,7 @@ "hot_morale_mod": 0.5, "cold_morale_mod": 0.5, "squeamish_penalty": 5, + "is_limb": true, "base_hp": 60, "bionic_slots": 20 }, @@ -133,6 +134,7 @@ "hot_morale_mod": 0.5, "cold_morale_mod": 0.5, "squeamish_penalty": 5, + "is_limb": true, "base_hp": 60, "bionic_slots": 20 }, @@ -206,6 +208,7 @@ "hot_morale_mod": 0.5, "cold_morale_mod": 0.5, "squeamish_penalty": 5, + "is_limb": true, "base_hp": 60, "bionic_slots": 30 }, @@ -231,6 +234,7 @@ "hot_morale_mod": 0.5, "cold_morale_mod": 0.5, "squeamish_penalty": 5, + "is_limb": true, "base_hp": 60, "bionic_slots": 30 }, diff --git a/data/json/construction.json b/data/json/construction.json index 87b51e6bfc103..98ad90a7e180e 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -115,10 +115,24 @@ "pre_terrain": "t_door_frame", "post_terrain": "f_beaded_door" }, + { + "type": "construction", + "id": "constr_sdoor_frame", + "description": "Build Makeshift Door", + "//": "Step 1: door frame", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 1 ] ], + "time": "60 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ] ], + "components": [ [ [ "2x4", 12 ] ], [ [ "nail", 24 ] ] ], + "pre_special": "check_empty", + "post_terrain": "t_door_frame" + }, { "type": "construction", "id": "constr_door_makeshift", "description": "Build Makeshift Door", + "//": "Step 2: Makeshift Door", "category": "CONSTRUCT", "required_skills": [ [ "fabrication", 2 ] ], "time": "30 m", @@ -2145,10 +2159,24 @@ "pre_special": "check_empty", "post_terrain": "f_mailbox" }, + { + "type": "construction", + "id": "constr_mbdoor_frame", + "description": "Build Bar Door", + "//": "step 1: door frame", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 6 ] ], + "time": "90 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M", "level": 1 } ] ], + "components": [ [ [ "spike", 8 ] ], [ [ "steel_chunk", 4 ], [ "scrap", 12 ] ] ], + "pre_special": "check_empty", + "post_terrain": "t_mdoor_frame" + }, { "type": "construction", "id": "constr_door_bar", "description": "Build Bar Door", + "//": "step 2: Bar Door", "category": "CONSTRUCT", "required_skills": [ [ "fabrication", 6 ] ], "time": "180 m", @@ -2615,6 +2643,40 @@ "pre_terrain": "t_rock", "post_special": "done_mine_upstair" }, + { + "type": "construction", + "id": "constr_concrete_ramp_low", + "description": "Build Low End of a Concrete Ramp", + "//": "Builds a low end of a concrete ramp going up on this level and down on the level above.", + "pre_note": "Build a concrete ramp leading to the next z-level above, and the corresponding ramp down leading from the z-level above to this level. The high end of a ramp must be built adjacent to allow moving between z-levels in both directions.", + "category": "DIG", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "150 m", + "tools": [ [ [ "con_mix", 125 ] ] ], + "qualities": [ [ { "id": "SMOOTH", "level": 1 } ] ], + "components": [ [ [ "concrete", 5 ] ], [ [ "water", 5 ] ] ], + "pre_terrain": "t_pit_shallow", + "pre_special": "check_ramp_low", + "post_terrain": "t_ramp_up_low", + "post_special": "done_ramp_low" + }, + { + "type": "construction", + "id": "constr_concrete_ramp_high", + "description": "Build High End of a Concrete Ramp", + "//": "Builds a high end of a concrete ramp going up on this level and down on the level above.", + "pre_note": "Build a concrete ramp leading to the next z-level above, and the corresponding ramp down leading from the z-level above to this level. It must be built next to a low end of a ramp to allow moving between z-levels in both directions.", + "category": "DIG", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "150 m", + "tools": [ [ [ "con_mix", 125 ] ] ], + "qualities": [ [ { "id": "SMOOTH", "level": 1 } ] ], + "components": [ [ [ "concrete", 5 ] ], [ [ "water", 5 ] ] ], + "pre_terrain": "t_pit_shallow", + "pre_special": "check_ramp_high", + "post_terrain": "t_ramp_up_high", + "post_special": "done_ramp_high" + }, { "type": "construction", "id": "constr_veh", @@ -3163,6 +3225,91 @@ "pre_special": "check_empty", "post_terrain": "t_junk_floor" }, + { + "type": "construction", + "id": "constr_scrap_bridge_1", + "description": "Build Scrap Metal Bridge Using Bolts", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 4 ] ], + "time": "180 m", + "qualities": [ + [ { "id": "SAW_M", "level": 1 } ], + [ { "id": "HAMMER", "level": 1 } ], + [ { "id": "WRENCH", "level": 2 } ], + [ { "id": "DRILL", "level": 1 } ] + ], + "components": [ + [ [ "wire", 16 ], [ "spike", 16 ], [ "nail", 32 ] ], + [ [ "sheet_metal_small", 10 ], [ "scrap", 10 ] ], + [ [ "sheet_metal", 2 ], [ "steel_plate", 2 ], [ "frame", 2 ], [ "hdframe", 1 ], [ "xlframe", 4 ] ], + [ [ "rebar", 2 ], [ "pipe", 4 ] ] + ], + "pre_special": "check_empty", + "post_terrain": "f_scrap_bridge" + }, + { + "type": "construction", + "id": "constr_scrap_bridge_2", + "description": "Build Scrap Metal Bridge Using Welder", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 4 ] ], + "time": "120 m", + "qualities": [ [ { "id": "SAW_M", "level": 1 } ] ], + "using": [ [ "welding_standard", 2 ] ], + "components": [ + [ [ "wire", 2 ] ], + [ [ "sheet_metal_small", 10 ], [ "scrap", 10 ] ], + [ [ "sheet_metal", 2 ], [ "steel_plate", 2 ], [ "frame", 2 ], [ "hdframe", 1 ], [ "xlframe", 4 ] ], + [ [ "rebar", 2 ], [ "pipe", 4 ] ] + ], + "pre_special": "check_empty", + "post_terrain": "f_scrap_bridge" + }, + { + "type": "construction", + "id": "constr_metal_bench", + "description": "Build Scrap Metal Bench", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 2 ] ], + "time": "90 m", + "qualities": [ [ { "id": "SAW_M", "level": 1 } ], [ { "id": "WRENCH", "level": 2 } ], [ { "id": "DRILL", "level": 1 } ] ], + "components": [ + [ [ "pipe_fittings", 1 ], [ "steel_chunk", 2 ] ], + [ [ "sheet_metal_small", 3 ], [ "scrap", 3 ] ], + [ [ "sheet_metal", 1 ] ], + [ [ "pipe", 1 ] ] + ], + "pre_special": "check_empty", + "post_terrain": "f_metal_bench" + }, + { + "type": "construction", + "id": "constr_metal_table", + "description": "Build Scrap Metal Table", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 2 ] ], + "time": "90 m", + "qualities": [ [ { "id": "SAW_M", "level": 1 } ], [ { "id": "WRENCH", "level": 2 } ], [ { "id": "DRILL", "level": 1 } ] ], + "components": [ + [ [ "pipe_fittings", 2 ], [ "steel_chunk", 3 ] ], + [ [ "sheet_metal_small", 4 ], [ "scrap", 4 ] ], + [ [ "sheet_metal", 1 ] ], + [ [ "pipe", 1 ] ] + ], + "pre_special": "check_empty", + "post_terrain": "f_metal_table" + }, + { + "type": "construction", + "id": "constr_ground_cable", + "description": "Lay down decorative ground cable", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 0 ] ], + "time": "1 m", + "components": [ [ [ "cable", 4 ] ] ], + "pre_special": "check_empty", + "post_terrain": "f_ground_cable" + }, { "type": "construction", "id": "constr_pillow_fort", diff --git a/data/json/effects.json b/data/json/effects.json index 770121b0e0f43..85d00550d67e7 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -934,15 +934,97 @@ { "type": "effect_type", "id": "bleed", - "name": [ "Bleeding", "Bad Bleeding", "Heavy Bleeding" ], - "desc": [ "You are slowly losing blood.", "You are losing blood.", "You are rapidly losing blood." ], + "name": [ + "Minor Bleeding", + "Minor Bleeding", + "Minor Bleeding", + "Minor Bleeding", + "Minor Bleeding", + "Bleeding", + "Bleeding", + "Bleeding", + "Bleeding", + "Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Bad Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding", + "Heavy Arterial Bleeding" + ], + "desc": [ + "Tis but a scratch.", + "Tis but a scratch.", + "Tis but a scratch.", + "Tis but a scratch.", + "Tis but a scratch.", + "You are slowly losing blood.", + "You are slowly losing blood.", + "You are slowly losing blood.", + "You are slowly losing blood.", + "You are slowly losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "You are rapidly losing blood.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain.", + "Blood is gushing from you like a fountain." + ], "main_parts_only": true, "apply_message": "You're bleeding!", "rating": "bad", - "max_intensity": 3, - "int_decay_tick": 120, - "int_add_val": 1, - "base_mods": { "str_mod": [ -1 ], "per_mod": [ -1 ] }, + "max_intensity": 40, + "int_dur_factor": 60, + "max_duration": 2400, + "scaling_mods": { "str_mod": [ -0.1 ], "per_mod": [ -0.1 ] }, "show_in_info": true }, { @@ -1594,16 +1676,75 @@ { "type": "effect_type", "id": "anemia", - "name": [ "Iron deficiency", "Early anemia", "Anemia" ], - "desc": [ "A lack of iron in your diet will result in progressively worsening anemia." ], + "name": [ "Early iron deficiency", "Iron deficiency", "Acute iron deficiency" ], + "desc": [ + "A lack of iron in your diet has hampered efficiency and regeneration of your red blood cells.", + "Prolonged lack of iron in your diet has compromised efficiency and regeneration of your red blood cells.", + "Severe lack of iron in your diet results in your red blood cells dying faster then they are regenerating." + ], "apply_message": "You begin feeling increasingly tired and listless.", - "remove_message": "You no longer feel anemic.", + "remove_message": "You are no longer in risk of becoming anemic.", "decay_messages": [ - [ "Your iron deficiency is nearly resolved.", "good" ], - [ "Your feel stronger as your anemia starts to improve.", "good" ] + [ "Your irom deficiency is nearly resolved.", "good" ], + [ "Your feel stronger as your iron deficiency starts to improve.", "good" ] ], "max_intensity": 3, - "rating": "bad" + "rating": "bad", + "base_mods": { + "str_mod": [ -1 ], + "stamina_min": [ -100 ], + "stamina_max": [ -200 ], + "stamina_chance": [ 900 ], + "fatigue_min": [ 10 ], + "fatigue_max": [ 20 ], + "fatigue_chance": [ 900 ], + "h_mod_min": [ -1 ], + "h_mod_min_val": [ 0 ], + "h_mod_chance": [ 900 ] + }, + "scaling_mods": { + "str_mod": [ -2 ], + "stamina_max": [ -500 ], + "fatigue_max": [ 20 ], + "stamina_chance": [ -300 ], + "fatigue_chance": [ -300 ], + "h_mod_min": [ -1 ], + "h_mod_min_val": [ -50 ], + "h_mod_chance": [ -200 ] + } + }, + { + "type": "effect_type", + "id": "redcells_anemia", + "name": [ "Early anemia", "Anemia", "Acute anemia" ], + "desc": [ "Loss of red blood cells results in progressively worsening anemia." ], + "apply_message": "You begin feeling increasingly tired and listless.", + "remove_message": "You no longer feel anemic.", + "decay_messages": [ [ "Your anemia is nearly resolved.", "good" ], [ "Your feel stronger as your anemia starts to improve.", "good" ] ], + "max_intensity": 3, + "rating": "bad", + "base_mods": { + "str_mod": [ -1 ], + "stamina_min": [ -100 ], + "stamina_max": [ -200 ], + "stamina_chance": [ 900 ], + "fatigue_min": [ 10 ], + "fatigue_max": [ 20 ], + "fatigue_chance": [ 900 ], + "h_mod_min": [ -1 ], + "h_mod_min_val": [ 0 ], + "h_mod_chance": [ 900 ] + }, + "scaling_mods": { + "str_mod": [ -2 ], + "stamina_max": [ -500 ], + "fatigue_max": [ 20 ], + "stamina_chance": [ -300 ], + "fatigue_chance": [ -300 ], + "h_mod_min": [ -1 ], + "h_mod_min_val": [ -50 ], + "h_mod_chance": [ -200 ] + } }, { "type": "effect_type", @@ -1682,6 +1823,27 @@ "//": "No morale_mod is currently possible in effects, for some reason. As soon as it's implemented, it goes here.", "rating": "bad" }, + { + "type": "effect_type", + "id": "hypovolemia", + "name": [ "Mild hypovolemic shock", "Moderate hypovolemic shock", "Advanced hypovolemic shock", "Severe hypovolemic shock" ], + "desc": [ + "You've lost some blood and look somewhat pale.", + "You've lost large amount of blood, and you're not feeling well.", + "You've lost an awful lot of blood, and your condition is severe. Seek medical attention.", + "You've lost tremendous amount of blood, and you're standing on death's door. Transfusion might save you." + ], + "apply_message": "You have lost lot of blood, and your condition worsens.", + "remove_message": "You are no longer in shock.", + "decay_messages": [ + [ "Your blood level increase, and you feel better, but still look pale.", "good" ], + [ "Your feel stronger as your blood levels starts to improve.", "good" ], + [ "You're not dying from lack of blood, but you're not out of the woods yet.", "good" ] + ], + "max_intensity": 4, + "scaling_mods": { "str_mod": [ -1 ], "per_mod": [ -1 ], "dex_mod": [ -1 ], "int_mod": [ -1 ], "speed_mod": [ -10 ] }, + "rating": "bad" + }, { "type": "effect_type", "id": "cough_suppress" diff --git a/data/json/emit.json b/data/json/emit.json index f0053ab79d09e..ccdb67bb86dca 100644 --- a/data/json/emit.json +++ b/data/json/emit.json @@ -338,5 +338,20 @@ "field": "fd_extinguisher", "intensity": 1, "qty": 10 + }, + { + "id": "emit_rad_leak", + "type": "emit", + "field": "fd_nuke_gas", + "intensity": 1, + "qty": 1 + }, + { + "id": "emit_rad_cloud", + "//": "Negative, negative, it's a large reactor leak, very dangerous", + "type": "emit", + "field": "fd_nuke_gas", + "intensity": 3, + "qty": 100 } ] diff --git a/data/json/furniture_and_terrain/furniture-alien.json b/data/json/furniture_and_terrain/furniture-alien.json new file mode 100644 index 0000000000000..000bc9d0ade37 --- /dev/null +++ b/data/json/furniture_and_terrain/furniture-alien.json @@ -0,0 +1,625 @@ +[ + { + "type": "furniture", + "id": "f_alien_tendril", + "name": "glowing tendril", + "description": "A willowy tendril growing from the floor, gently waving back and forth. A faint light spills from it.", + "symbol": "i", + "color": "blue", + "move_cost_mod": 4, + "coverage": 10, + "light_emitted": 15, + "required_str": -1, + "flags": [ "TRANSPARENT" ], + "bash": { + "str_min": 8, + "str_max": 20, + "sound": "splorch!", + "sound_fail": "whump!", + "furn_set": "f_alien_scar", + "items": [ { "item": "fetid_goop", "count": [ 3, 5 ], "prob": 100 } ] + } + }, + { + "type": "furniture", + "id": "f_alien_anemone", + "name": "wafting anemone", + "description": "A fleshy white protuberance growing from the floor, with a cluster of tendrils pouring out of it. It looks almost exactly like a sea anemone, even waving gently as though underwater.", + "symbol": "V", + "color": "white", + "move_cost_mod": 6, + "coverage": 30, + "required_str": -1, + "light_emitted": 3, + "flags": [ "TRANSPARENT", "EMITTER" ], + "emissions": [ "emit_hot_air_migo_seep" ], + "bash": { + "str_min": 13, + "str_max": 26, + "sound": "splorch!", + "sound_fail": "whump!", + "furn_set": "f_alien_scar", + "items": [ { "item": "fetid_goop", "count": [ 3, 7 ], "prob": 100 } ] + } + }, + { + "type": "furniture", + "id": "f_alien_gasper", + "name": "gasping tube", + "description": "This is a meaty green stalactite with a thickened hide like that of a starfish, extending from the floor to the ceiling. In the center is a series of ports somewhat like mouths, from which pour bursts of a vile-smelling gas.", + "symbol": "{", + "color": "green", + "move_cost_mod": 6, + "coverage": 40, + "required_str": -1, + "flags": [ "TRANSPARENT", "EMITTER" ], + "emissions": [ "emit_migo_atmosphere", "emit_hot_air_migo_blast" ], + "//": "TODO: Make a custom toxic gas emission that is not visible to the player", + "bash": { + "str_min": 30, + "str_max": 60, + "sound": "splorch!", + "sound_fail": "whump!", + "furn_set": "f_alien_scar", + "items": [ { "item": "fetid_goop", "count": [ 15, 25 ], "prob": 100 } ] + } + }, + { + "type": "furniture", + "id": "f_alien_zapper", + "name": "twitching frond", + "description": "A spine resembling moth antennae juts from the ground, swaying gently in the air. Every so often, a cascade of energy arcs along it and discharges into the ceiling.", + "symbol": "F", + "color": "light_blue", + "move_cost_mod": 4, + "coverage": 20, + "required_str": -1, + "flags": [ "TRANSPARENT", "EMITTER" ], + "emissions": [ "emit_glimmer", "emit_shock_burst" ], + "//": "TODO: Make a custom toxic gas emission that is not visible to the player", + "bash": { "str_min": 30, "str_max": 60, "sound": "splorch!", "sound_fail": "whump!", "furn_set": "f_alien_scar" } + }, + { + "type": "furniture", + "id": "f_alien_scar", + "name": "scarred lump", + "description": "This is a pile of nondescript alien flesh, twitching and belching strange gases out of injured orifices.", + "symbol": "{", + "color": "green", + "move_cost_mod": 6, + "coverage": 40, + "required_str": -1, + "flags": [ "TRANSPARENT", "EMITTER" ], + "emissions": [ "emit_hot_air_migo_seep", "emit_shock_burst" ], + "//": "TODO: Make a custom toxic gas emission that is not visible to the player", + "bash": { + "str_min": 250, + "str_max": 600, + "sound": "splorch!", + "sound_fail": "splat!", + "items": [ { "item": "fetid_goop", "count": [ 6, 13 ], "prob": 100 } ] + } + }, + { + "type": "furniture", + "id": "f_alien_pod", + "name": "slimy pod", + "description": "This is a slick, translucent pod suspended on a thin stalk. It is covered in a thick mucus, obscuring whatever is floating in the gel-like substance inside.", + "symbol": "0", + "color": "magenta", + "move_cost_mod": -1, + "coverage": 40, + "required_str": -1, + "flags": [ "TRANSPARENT" ], + "bash": { + "str_min": 25, + "str_max": 60, + "sound": "splorch!", + "sound_fail": "whump.", + "items": [ { "item": "fetid_goop", "count": [ 5, 10 ], "prob": 100 } ] + } + }, + { + "type": "furniture", + "id": "f_alien_pod_organ", + "name": "organ pod", + "description": "This is a translucent pod suspended on a thin stalk. Inside you can see the dimly outlined shape of human organs, floating in some kind of preservative goo.", + "symbol": "0", + "color": "yellow", + "move_cost_mod": -1, + "coverage": 40, + "required_str": -1, + "light_emitted": 3, + "flags": [ "TRANSPARENT" ], + "bash": { "str_min": 25, "str_max": 60, "sound": "splorch!", "sound_fail": "whump." } + }, + { + "type": "furniture", + "id": "f_alien_pod_resin", + "name": "resin pod", + "description": "This is a translucent pod suspended on a thin stalk. Inside is a clean, clear resinous-looking fluid. You could fairly easily tear it from the stalk and take it with you.", + "symbol": "0", + "color": "light_blue", + "move_cost_mod": -1, + "coverage": 40, + "required_str": -1, + "flags": [ "TRANSPARENT", "EASY_DECONSTRUCT" ], + "deconstruct": { "items": [ { "item": "alien_pod_resin", "charges": [ 2, 6 ] } ] }, + "bash": { "str_min": 25, "str_max": 60, "sound": "splorch!", "sound_fail": "whump." } + }, + { + "type": "furniture", + "id": "f_alien_table", + "name": "fleshy altar", + "description": "This pulsing protuberance juts from the floor, its sides covered in scaled, oozing skin. The surface is flat, but undulates softly. A handful of unidentifiable appendages reach from the sides, suggesting a sort of nightmarish living autodoc.", + "symbol": "n", + "color": "pink", + "move_cost_mod": -1, + "coverage": 40, + "required_str": -1, + "light_emitted": 12, + "flags": [ "TRANSPARENT" ], + "bash": { "str_min": 45, "str_max": 60, "sound": "splorch!", "sound_fail": "whump.", "furn_set": "f_alien_scar" } + }, + { + "type": "furniture", + "id": "f_scrap_antenna", + "name": "scrap antenna", + "looks_like": "t_radio_tower", + "description": "This contraption looks like some sort of cobbled-together transmitter or receiver antenna. It consists of a number of mismatched blinking lights, spinning servos, and dangling wires connected to a heft metal box.", + "symbol": "d", + "color": "light_gray", + "move_cost_mod": 2, + "coverage": 30, + "required_str": 11, + "flags": [ "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 30, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "pipe_fittings", "count": [ 0, 3 ] }, + { "item": "sheet_metal", "count": [ 1, 2 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] }, + { "item": "antenna", "count": [ 0, 1 ] }, + { "item": "exodii_module", "count": [ 0, 1 ] }, + { "item": "exodii_motor", "count": [ 0, 1 ] }, + { "item": "cable", "count": [ 0, 2 ] }, + { "item": "scrap_copper", "count": [ 2, 10 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_botrack", + "name": "rack of robots", + "looks_like": "f_server_stack", + "description": "This is a wire cage containing a number of robot parts, from chassis to limbs, firmly clamped on to sturdy hanging rods. It looks like it would be exceptionally difficult to open it and get at them without damaging them, probably by design.", + "symbol": "E", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 70, + "required_str": -1, + "max_volume": "1500 L", + "flags": [ "MOUNTABLE", "BLOCKSDOOR" ], + "bash": { + "str_min": 60, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "wire", "count": [ 3, 10 ] }, + { "item": "sheet_metal", "count": [ 0, 2 ] }, + { "item": "sheet_metal_small", "count": [ 20, 30 ] }, + { "item": "exodii_chassis", "count": [ 0, 1 ] }, + { "item": "exodii_drone_chassis", "count": [ 0, 1 ] }, + { "item": "scrap_copper", "count": [ 5, 20 ] }, + { "item": "e_scrap", "count": [ 5, 20 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_scanner", + "name": "spinning dish", + "looks_like": "t_machinery_light", + "description": "This is a slowly spinning parabolic dish engraved with an unrecognizable pattern of symbols that might, at a guess, be some sort of circuitry pattern - or maybe a religious incantation. It is mounted on a completely mismatched electric motor that looks fairly mundane.", + "symbol": "W", + "color": "light_gray", + "move_cost_mod": 2, + "coverage": 30, + "required_str": 11, + "flags": [ "TRANSPARENT", "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 30, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] }, + { "item": "scrap_copper", "count": [ 2, 10 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] }, + { "item": "exodii_motor", "count": [ 0, 1 ] }, + { "item": "cable", "count": [ 0, 3 ] }, + { "item": "exodii_scanner_dish", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_lamp", + "name": "scavenged utility light", + "looks_like": "t_utility_light", + "description": "The bulbs emit an eery greenish glow, and some parts of it have a curved appearance as though the metal were grown in a lab, but by and large this isn't a particularly unusual looking area light.", + "symbol": "T", + "color": "light_gray", + "move_cost_mod": 3, + "coverage": 30, + "required_str": 6, + "light_emitted": 20, + "flags": [ "TRANSPARENT", "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 20, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] }, + { "item": "scrap_copper", "count": [ 2, 10 ] }, + { "item": "amplifier", "count": [ 0, 5 ] }, + { "item": "power_supply", "count": [ 0, 1 ] }, + { "item": "cable", "count": [ 0, 5 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_pump", + "name": "clanking fluid pump", + "looks_like": "t_machinery_heavy", + "description": "The huge sweating pipes and large tank reveal this clanking and tortuous piece of equipment to be some sort of fluid pump. It is cobbled from several apparently ill-fitting parts that have been fitted together with some very strange looking but surprisingly clever adaptors.", + "symbol": "0", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 80, + "required_str": 14, + "flags": [ "TRANSPARENT", "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 40, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 2, 4 ] }, + { "item": "55gal_drum", "count": [ 0, 1 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] }, + { "item": "scrap_copper", "count": [ 5, 10 ] }, + { "item": "exodii_module", "count": [ 0, 1 ] }, + { "item": "exodii_motor", "count": [ 0, 2 ] }, + { "item": "pipe_fittings", "count": [ 2, 6 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_printer_large", + "name": "metalloid printer", + "looks_like": "t_broken_generator", + "description": "This huge device actually resembles a 3D printer fairly closely, aside from its industrial size. Huge spools of various thin metallic wires top it and feed into what seems to be some sort of nozzle, and massive electrical cables disappear into the wall behind it.", + "symbol": "U", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 80, + "required_str": 14, + "flags": [ "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 90, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 20, 120 ] }, + { "item": "pipe", "count": [ 20, 40 ] }, + { "item": "sheet_metal_small", "count": [ 20, 100 ] }, + { "item": "scrap_copper", "count": [ 50, 100 ] }, + { "item": "pipe_fittings", "count": [ 2, 6 ] }, + { "item": "exodii_module", "count": [ 0, 6 ] }, + { "item": "exodii_motor", "count": [ 0, 8 ] }, + { "item": "exodii_computer", "count": [ 0, 2 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_printer_small", + "name": "circuit printer", + "looks_like": "t_machinery_electronic", + "description": "This is a tall device with a lattice of pipes and nozzles. Based on the pile of products sitting in the output hopper, it looks like it’s used as a printer for complex electronic components.", + "symbol": "U", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 80, + "required_str": 14, + "flags": [ "TRANSPARENT", "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 90, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 20, 120 ] }, + { "item": "pipe", "count": [ 10, 20 ] }, + { "item": "pipe_fittings", "count": [ 2, 4 ] }, + { "item": "sheet_metal_small", "count": [ 10, 30 ] }, + { "item": "scrap_copper", "count": [ 20, 40 ] }, + { "item": "e_scrap", "count": [ 20, 40 ] }, + { "item": "exodii_module", "count": [ 0, 5 ] }, + { "item": "exodii_motor", "count": [ 0, 6 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_generator_1", + "name": "Mavrik 10-101 power core", + "description": "There is a faded metallic plaque on the side of this cylindrical device. The lettering is a strange combination of English and Cyrillic script. It reads:\nMavrik 10-101\nStabиlиtи\nSaфetи\nA нyuclиar фyutuр ви bilив iн", + "symbol": "G", + "color": "white", + "move_cost_mod": -1, + "coverage": 60, + "required_str": -1, + "flags": [ "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 60, + "str_max": 400, + "explosive": 25, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] }, + { "item": "sheet_metal_small", "count": [ 10, 30 ] }, + { "item": "scrap_copper", "count": [ 20, 40 ] }, + { "item": "e_scrap", "count": [ 20, 40 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 4, 8 ] }, + { "item": "exodii_module", "count": [ 0, 5 ] }, + { "item": "exodii_motor", "count": [ 0, 6 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_generator_2", + "name": "spherical generator", + "description": "This huge steel plated sphere gives off a soft hum as it, presumably, generates power. A heavy lead plate bolted to the front might describe what it is, but it is written in something that looks vaguely like cuneiform.", + "symbol": "G", + "color": "red", + "move_cost_mod": -1, + "coverage": 70, + "required_str": -1, + "flags": [ "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 60, + "str_max": 400, + "explosive": 25, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "steel_armor", "count": [ 2, 4 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] }, + { "item": "sheet_metal_small", "count": [ 10, 30 ] }, + { "item": "scrap_copper", "count": [ 20, 40 ] }, + { "item": "e_scrap", "count": [ 20, 40 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 4, 8 ] }, + { "item": "exodii_module", "count": [ 0, 5 ] }, + { "item": "exodii_motor", "count": [ 0, 6 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_generator_3", + "name": "fluidic generator", + "description": "Twisting reams of copper and steel pipes wrap around a central core that thrums softly. Although there are no labels in any language you recognize, the cables connected to the base suggest that this is some sort of power generator.", + "symbol": "G", + "color": "green", + "move_cost_mod": -1, + "coverage": 50, + "required_str": -1, + "flags": [ "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 60, + "str_max": 400, + "explosive": 25, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "cu_pipe", "count": [ 2, 4 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "pipe_fittings", "count": [ 0, 3 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] }, + { "item": "sheet_metal_small", "count": [ 10, 30 ] }, + { "item": "scrap_copper", "count": [ 10, 30 ] }, + { "item": "e_scrap", "count": [ 10, 20 ] }, + { "item": "circuit", "count": [ 2, 5 ] }, + { "item": "power_supply", "count": [ 4, 8 ] }, + { "item": "exodii_module", "count": [ 0, 5 ] }, + { "item": "exodii_motor", "count": [ 0, 6 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_generator_4", + "name": "rusty generator", + "description": "This is a tall, unremarkable cylinder capped by a wide flat saucer. There is heavy rusting at the base. A series of connected cables suggest that it's some sort of power generator.", + "symbol": "G", + "color": "yellow_red", + "move_cost_mod": -1, + "coverage": 60, + "required_str": -1, + "flags": [ "NOITEM", "BLOCKSDOOR" ], + "bash": { + "str_min": 60, + "str_max": 400, + "explosive": 25, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "sheet_metal", "count": [ 5, 10 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] }, + { "item": "sheet_metal_small", "count": [ 10, 30 ] }, + { "item": "scrap_copper", "count": [ 10, 30 ] }, + { "item": "e_scrap", "count": [ 15, 30 ] }, + { "item": "circuit", "count": [ 2, 5 ] }, + { "item": "power_supply", "count": [ 2, 8 ] }, + { "item": "exodii_module", "count": [ 0, 5 ] }, + { "item": "exodii_motor", "count": [ 0, 6 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_charger", + "name": "personal charging station", + "description": "The cyborg equivalent of a bed, this is a custom-shaped near-vertical booth designed to mount a heavy metal frame and connect it to a central power supply and nutrient source.", + "symbol": "{", + "color": "light_green", + "move_cost_mod": 6, + "coverage": 80, + "required_str": -1, + "flags": [ "TRANSPARENT" ], + "bash": { + "str_min": 18, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "cable", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 0, 1 ] }, + { "item": "sheet_metal_small", "count": [ 4, 8 ] }, + { "item": "e_scrap", "count": [ 2, 6 ] }, + { "item": "metal_tank_little", "count": [ 0, 1 ] }, + { "item": "pipe", "count": [ 0, 4 ] }, + { "item": "circuit", "count": [ 2, 5 ] }, + { "item": "amplifier", "count": [ 2, 5 ] }, + { "item": "power_supply", "count": [ 2, 8 ] }, + { "item": "exodii_module", "count": [ 0, 2 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_charger_cheap", + "name": "simple charging station", + "description": "This is a simple, unadorned, corroded metal charging and refeeding station, with hookups for two units somewhat larger than a human to stand side by side and be recharged and refueled.", + "symbol": "Y", + "color": "light_green", + "move_cost_mod": 6, + "coverage": 80, + "required_str": -1, + "flags": [ "TRANSPARENT" ], + "bash": { + "str_min": 19, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "cable", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 0, 1 ] }, + { "item": "sheet_metal_small", "count": [ 4, 8 ] }, + { "item": "e_scrap", "count": [ 2, 6 ] }, + { "item": "metal_tank_little", "count": [ 0, 1 ] }, + { "item": "pipe", "count": [ 0, 4 ] }, + { "item": "circuit", "count": [ 2, 5 ] }, + { "item": "amplifier", "count": [ 2, 5 ] }, + { "item": "power_supply", "count": [ 2, 8 ] }, + { "item": "large_storage_battery", "count": [ 0, 1 ] }, + { "item": "exodii_module", "count": [ 0, 2 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_portal_tower", + "name": "shimmering superstructure", + "description": "A simple metal superstructure like you might see holding up a radio tower, this one seems to give off just the faintest hint of shimmer, like heat waves. The metal has a burnt, iridescent pattern. There is a boxy, unimpressive looking device at the top of the tower.", + "symbol": "H", + "color": "light_cyan", + "move_cost_mod": -1, + "coverage": 50, + "required_str": -1, + "flags": [ "NOITEM", "TRANSPARENT", "MOUNTABLE" ], + "bash": { + "str_min": 45, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "cable", "count": [ 1, 4 ] }, + { "item": "pipe", "count": [ 0, 4 ] }, + { "item": "circuit", "count": [ 2, 5 ] }, + { "item": "amplifier", "count": [ 2, 5 ] }, + { "item": "power_supply", "count": [ 2, 8 ] }, + { "item": "exodii_module", "count": [ 0, 2 ] }, + { "item": "exodii_portalizer", "count": [ 0, 4 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_exodii_portal_enclosure", + "name": "portal enclosure", + "description": "A heavy metal ring attached to dozens of wires, charred by residue that gives off an acrid, unfamiliar smell.", + "symbol": "Q", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 50, + "required_str": -1, + "flags": [ "NOITEM", "TRANSPARENT", "MOUNTABLE" ], + "bash": { + "str_min": 45, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "cable", "count": [ 1, 4 ] }, + { "item": "sheet_metal_small", "count": [ 0, 4 ] }, + { "item": "circuit", "count": [ 1, 3 ] }, + { "item": "amplifier", "count": [ 1, 3 ] }, + { "item": "power_supply", "count": [ 1, 4 ] }, + { "item": "exodii_module", "count": [ 0, 1 ] }, + { "item": "exodii_portalizer", "count": [ 0, 2 ] }, + { "item": "exodii_computer", "count": [ 0, 1 ] } + ] + } + } +] diff --git a/data/json/furniture_and_terrain/furniture-appliances.json b/data/json/furniture_and_terrain/furniture-appliances.json index ec76bf4111e23..7f99d8fed25f0 100644 --- a/data/json/furniture_and_terrain/furniture-appliances.json +++ b/data/json/furniture_and_terrain/furniture-appliances.json @@ -3,7 +3,7 @@ "type": "furniture", "id": "f_air_conditioner", "name": "cooling unit", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A large, blocky appliance encased in sheet metal. This commonplace fixture is used for cooling large indoor areas.", "symbol": "{", "bgcolor": "white", @@ -397,7 +397,7 @@ "symbol": "#", "description": "An old device for pushing air into a blacksmith's forge to strengthen the fire and maintain a high temperature. Useless in its current state, but good for parts.", "color": "dark_gray", - "looks_like": "t_machinery_old", + "looks_like": "f_machinery_old", "move_cost_mod": 2, "coverage": 60, "required_str": 10, @@ -431,7 +431,7 @@ "symbol": "#", "description": "An anvil with a large metal hammer suspended above it in a metal framework. If it were working, it would be useful for shaping softened metal plates, though now it is only useful for parts.", "color": "white", - "looks_like": "t_machinery_old", + "looks_like": "f_machinery_old", "move_cost_mod": 2, "coverage": 60, "required_str": 10, diff --git a/data/json/furniture_and_terrain/furniture-industrial.json b/data/json/furniture_and_terrain/furniture-industrial.json index d1d94b09dc9bb..d41e378ec97ff 100644 --- a/data/json/furniture_and_terrain/furniture-industrial.json +++ b/data/json/furniture_and_terrain/furniture-industrial.json @@ -46,6 +46,7 @@ { "type": "furniture", "id": "f_chemical_mixer", + "looks_like": "f_machinery_light", "description": "A large vat with a motorized mixing device for combining large quantities of chemicals.", "name": "chemical mixer", "symbol": "0", @@ -78,10 +79,311 @@ ] } }, + { + "type": "furniture", + "id": "f_generator_broken", + "name": "broken generator", + "looks_like": "f_machinery_old", + "description": "This generator is broken and will not help you produce usable electricity.", + "symbol": "&", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 30, + "required_str": 16, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT", "MOUNTABLE", "PERMEABLE", "BLOCKS_DOOR" ], + "bash": { + "str_min": 20, + "str_max": 150, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "steel_lump", "prob": 50 }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "scrap", "count": [ 3, 7 ] }, + { "item": "pipe", "count": [ 0, 1 ] } + ] + }, + "deconstruct": { + "items": [ + { "item": "cable", "charges": [ 1, 2 ] }, + { "item": "steel_chunk", "count": [ 1, 2 ] }, + { "item": "scrap", "count": [ 4, 6 ] }, + { "item": "motor_small", "count": [ 0, 1 ] }, + { "item": "jerrycan", "count": [ 0, 1 ] }, + { "item": "pipe", "count": [ 0, 1 ] }, + { "item": "pipe_fittings", "count": [ 0, 1 ] }, + { "item": "frame", "count": [ 0, 1 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_compact_ASRG_containment", + "name": "Compact Advanced Sterling Radioisotope Generator", + "looks_like": "t_plut_generator", + "description": "This hefty lump of steel and lead is the housing unit for a small nuclear reactor. It is plastered with warning signs. You could probably ignore those and salvage the steel and lead shielding, what could possibly go wrong?", + "symbol": "0", + "color": "green_white", + "move_cost_mod": -1, + "coverage": 80, + "required_str": -1, + "flags": [ "NOITEM", "SEALED", "REDUCE_SCENT", "PERMEABLE" ], + "bash": { + "str_min": 70, + "str_max": 400, + "explosive": 100, + "sound": "metal screeching!", + "sound_fail": "clang!", + "furn_set": "f_reactor_meltdown", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] } + ] + }, + "deconstruct": { + "furn_set": "f_compact_ASRG", + "items": [ + { "item": "lead", "count": [ 40, 80 ] }, + { "item": "cable", "charges": [ 8, 16 ] }, + { "item": "steel_plate", "count": [ 2, 4 ] }, + { "item": "mil_plate", "count": [ 2, 4 ] }, + { "item": "large_lcd_screen", "count": 1 }, + { "item": "scrap", "count": [ 8, 16 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_compact_ASRG", + "name": "Compact Advanced Sterling Radioisotope Generator", + "looks_like": "f_compact_ASRG_containment", + "description": "Some insane fool has removed the outer containment on this small-scale nuclear reactor. It is still fairly safe as it is: the reactor has considerable built-in containment as well. Nevertheless, you probably don't want to stand too close for too long.", + "symbol": "0", + "color": "green", + "move_cost_mod": -1, + "coverage": 50, + "required_str": -1, + "flags": [ "TRANSPARENT", "NOITEM", "SEALED", "REDUCE_SCENT", "PERMEABLE" ], + "emissions": [ "emit_rad_leak" ], + "bash": { + "str_min": 20, + "str_max": 400, + "explosive": 100, + "sound": "metal screeching!", + "sound_fail": "clang!", + "furn_set": "f_reactor_meltdown", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_machinery_light", + "name": "light machinery", + "looks_like": "t_machinery_light", + "description": "Assorted light machinery. You could scavenge it for parts.", + "symbol": "$", + "color": "dark_gray", + "move_cost_mod": 10, + "coverage": 65, + "required_str": -1, + "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "FLAMMABLE", "PLACE_ITEM" ], + "deconstruct": { + "items": [ + { "item": "wire", "count": [ 1, 3 ] }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 40 }, + { "item": "cu_pipe", "prob": 40 }, + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "hose", "count": 1 }, + { "item": "steel_chunk", "count": [ 1, 5 ] }, + { "item": "bearing", "charges": [ 4, 12 ] }, + { "item": "frame", "prob": 50 }, + { "item": "motor", "prob": 50 } + ] + }, + "bash": { + "str_min": 16, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": 2, "prob": 40 }, + { "item": "chain", "prob": 20 }, + { "item": "cu_pipe", "prob": 10 }, + { "item": "scrap", "count": [ 3, 8 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "bearing", "charges": [ 2, 8 ] }, + { "item": "frame", "prob": 20 }, + { "item": "motor", "prob": 10 } + ] + } + }, + { + "type": "furniture", + "id": "f_machinery_heavy", + "name": "heavy machinery", + "looks_like": "t_machinery_heavy", + "description": "Assorted heavy machinery. You could scavenge it for parts.", + "symbol": "%", + "color": "light_gray", + "move_cost_mod": 10, + "coverage": 75, + "required_str": -1, + "flags": [ "BASHABLE", "CONTAINER", "SEALED", "PLACE_ITEM" ], + "deconstruct": { + "items": [ + { "item": "wire", "count": [ 1, 3 ] }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 60 }, + { "item": "cu_pipe", "prob": 20 }, + { "item": "steel_lump", "count": [ 1, 2 ] }, + { "item": "hose", "count": 1 }, + { "item": "sheet_metal", "count": [ 1, 3 ] }, + { "item": "steel_chunk", "count": [ 1, 3 ] }, + { "item": "bearing", "charges": [ 4, 12 ] }, + { "item": "frame", "prob": 60 }, + { "item": "motor", "prob": 30 }, + { "item": "metal_tank", "prob": 30 }, + { "item": "motor_large", "prob": 10 } + ] + }, + "bash": { + "str_min": 18, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": 1 }, + { "item": "chain", "prob": 20 }, + { "item": "steel_lump", "count": 1 }, + { "item": "scrap", "count": [ 1, 5 ] }, + { "item": "sheet_metal", "count": 2 }, + { "item": "steel_chunk", "count": [ 1, 2 ] }, + { "item": "bearing", "charges": [ 2, 8 ] }, + { "item": "frame", "prob": 30 }, + { "item": "motor", "prob": 10 }, + { "item": "metal_tank", "prob": 20 }, + { "item": "motor_large", "prob": 5 } + ] + } + }, + { + "type": "furniture", + "id": "f_machinery_old", + "name": "old machinery", + "looks_like": "t_machinery_old", + "description": "Assorted old, rusty machinery. You could scavenge it for parts.", + "symbol": "&", + "color": "brown", + "move_cost_mod": 4, + "coverage": 55, + "required_str": -1, + "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "FLAMMABLE", "PLACE_ITEM" ], + "deconstruct": { + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 40 }, + { "item": "cu_pipe", "prob": 60 }, + { "item": "scrap", "count": [ 1, 3 ] }, + { "item": "hose", "count": 1 }, + { "item": "steel_chunk", "count": [ 1, 3 ] }, + { "item": "bearing", "charges": [ 1, 5 ] }, + { "item": "frame", "prob": 30 }, + { "item": "motor", "prob": 30 }, + { "item": "splinter", "count": 3, "prob": 30 }, + { "item": "2x4", "count": [ 1, 4 ] }, + { "item": "nail", "charges": [ 3, 10 ] } + ] + }, + "bash": { + "str_min": 10, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 20 }, + { "item": "cu_pipe", "prob": 10 }, + { "item": "scrap", "count": [ 1, 5 ] }, + { "item": "steel_chunk", "count": [ 1, 2 ] }, + { "item": "motor", "prob": 10 }, + { "item": "splinter", "count": [ 4, 8 ] }, + { "item": "2x4", "count": 2 }, + { "item": "nail", "charges": [ 2, 5 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_machinery_electronic", + "name": "electronic machinery", + "looks_like": "t_machinery_electronic", + "description": "Assorted electronic machinery. You could scavenge it for parts.", + "symbol": "$", + "color": "yellow", + "move_cost_mod": 8, + "coverage": 55, + "required_str": -1, + "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "SEALED", "FLAMMABLE", "PLACE_ITEM" ], + "deconstruct": { + "items": [ + { "item": "wire", "count": [ 1, 3 ] }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "bearing", "charges": [ 2, 6 ] }, + { "item": "motor", "prob": 40 }, + { "item": "processor", "count": 1 }, + { "item": "RAM", "count": [ 1, 4 ] }, + { "item": "cable", "charges": [ 1, 4 ] }, + { "item": "small_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 5, 10 ] }, + { "item": "circuit", "count": [ 3, 8 ] }, + { "item": "power_supply", "count": [ 1, 3 ] }, + { "item": "amplifier", "count": [ 1, 3 ] }, + { "item": "plastic_chunk", "count": [ 2, 8 ] }, + { "item": "scrap", "count": [ 1, 5 ] } + ] + }, + "bash": { + "str_min": 10, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "items": [ + { "item": "wire", "prob": 40 }, + { "item": "pipe", "prob": 40 }, + { "item": "steel_chunk", "prob": 40 }, + { "item": "bearing", "charges": [ 2, 4 ] }, + { "item": "motor", "prob": 10 }, + { "item": "processor", "prob": 40 }, + { "item": "RAM", "count": [ 1, 2 ] }, + { "item": "cable", "charges": [ 1, 2 ] }, + { "item": "small_lcd_screen", "prob": 40 }, + { "item": "e_scrap", "count": [ 3, 8 ] }, + { "item": "circuit", "count": [ 1, 3 ] }, + { "item": "power_supply", "prob": 40 }, + { "item": "amplifier", "prob": 40 }, + { "item": "plastic_chunk", "count": [ 2, 8 ] }, + { "item": "scrap", "count": [ 3, 8 ] } + ] + } + }, { "type": "furniture", "id": "f_robotic_arm", "name": "robotic arm", + "looks_like": "f_machinery_electronic", "description": "An automated robotic arm used in assembly lines, which appears to be more general-purpose than specially designed assemblers. Despite being functionless now, the parts could be useful.", "symbol": "&", "bgcolor": "yellow", @@ -119,5 +421,55 @@ { "item": "motor", "prob": 30 } ] } + }, + { + "type": "furniture", + "id": "f_ground_cable", + "name": "ground cable", + "looks_like": "t_sewer_pipe", + "description": "A bunch of loose cables snake along the floor.", + "symbol": "}", + "color": "white", + "move_cost_mod": 1, + "required_str": -1, + "flags": [ "TRANSPARENT", "EASY_DECONSTRUCT", "NOCOLLIDE" ], + "bash": { + "str_min": 10, + "str_max": 100, + "sound": "shred!", + "sound_fail": "thud!", + "items": [ { "item": "scrap_copper", "count": [ 1, 4 ] }, { "item": "cable", "count": [ 1, 4 ] } ] + }, + "deconstruct": { "items": [ { "item": "cable", "count": 4 } ] } + }, + { + "type": "furniture", + "id": "f_capacitor", + "name": "capacitor bank", + "looks_like": "f_machinery_electronic", + "description": "A bank of heavy metal cylinders connected by large wires.", + "symbol": "=", + "color": "light_blue", + "move_cost_mod": 4, + "coverage": 40, + "required_str": -1, + "flags": [ "TRANSPARENT", "MOUNTABLE" ], + "bash": { + "str_min": 25, + "str_max": 200, + "explosive": 15, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "cable", "count": [ 1, 8 ] }, + { "item": "pipe", "count": [ 0, 4 ] }, + { "item": "circuit", "count": [ 0, 5 ] }, + { "item": "e_scrap", "count": [ 2, 8 ] }, + { "item": "amplifier", "count": [ 0, 4 ] }, + { "item": "power_supply", "count": [ 0, 2 ] }, + { "item": "metal_tank_little", "count": [ 0, 6 ] } + ] + } } ] diff --git a/data/json/furniture_and_terrain/furniture-medical.json b/data/json/furniture_and_terrain/furniture-medical.json index 294ffca2b19a1..660d1d9efe73c 100644 --- a/data/json/furniture_and_terrain/furniture-medical.json +++ b/data/json/furniture_and_terrain/furniture-medical.json @@ -408,7 +408,7 @@ "move_cost_mod": -1, "coverage": 40, "required_str": 12, - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "flags": [ "TRANSPARENT" ], "deconstruct": { "items": [ @@ -453,7 +453,7 @@ "move_cost_mod": -1, "coverage": 40, "required_str": 18, - "looks_like": "t_machinery_old", + "looks_like": "f_machinery_old", "flags": [ "BLOCKSDOOR" ], "deconstruct": { "items": [ @@ -498,7 +498,7 @@ "move_cost_mod": -1, "coverage": 45, "required_str": -1, - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "flags": [ "TRANSPARENT" ], "deconstruct": { "items": [ @@ -539,7 +539,7 @@ "move_cost_mod": -1, "coverage": 65, "required_str": -1, - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "deconstruct": { "items": [ { "item": "scrap", "count": [ 2, 6 ] }, @@ -578,7 +578,7 @@ "bgcolor": "white", "move_cost_mod": -1, "required_str": -1, - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "deconstruct": { "items": [ { "item": "scrap", "count": [ 2, 6 ] }, @@ -619,7 +619,7 @@ "coverage": 65, "required_str": -1, "flags": [ "PLACE_ITEM", "CONTAINER" ], - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "deconstruct": { "items": [ { "item": "scrap", "count": [ 2, 6 ] }, @@ -660,7 +660,7 @@ "coverage": 65, "required_str": -1, "flags": [ "PLACE_ITEM", "CONTAINER" ], - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "deconstruct": { "items": [ { "item": "scrap", "count": [ 2, 6 ] }, @@ -921,5 +921,45 @@ { "item": "scrap", "count": [ 2, 7 ] } ] } + }, + { + "type": "furniture", + "id": "f_centrifuge", + "name": "centrifuge", + "looks_like": "f_machinery_electronic", + "description": "This is a centrifuge, a liquid separating device with an automated analyzer unit. For some reason, this one has an attached battery pack. It could be used to analyze a medical fluid sample, such as blood, if a test tube was placed in it.", + "symbol": "{", + "color": "magenta", + "move_cost_mod": -1, + "coverage": 30, + "required_str": -1, + "flags": [ "TRANSPARENT", "PERMEABLE" ], + "deconstruct": { + "items": [ + { "item": "circuit", "count": 4 }, + { "item": "scrap", "count": 5 }, + { "item": "motor_small", "count": 1 }, + { "item": "spectrophotometer", "count": 1 }, + { "item": "storage_battery", "count": 1 }, + { "item": "betavoltaic", "count": [ 1, 4 ] }, + { "item": "steel_chunk", "count": 3 }, + { "item": "sheet_metal", "count": 3 }, + { "item": "cable", "charges": 5 } + ] + }, + "bash": { + "str_min": 3, + "str_max": 45, + "sound": "crunch!", + "sound_fail": "whack!", + "items": [ + { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, + { "item": "circuit", "count": [ 1, 6 ], "prob": 50 }, + { "item": "scrap", "count": [ 2, 5 ] }, + { "item": "steel_chunk", "count": [ 0, 3 ] }, + { "item": "sheet_metal", "count": [ 1, 3 ] }, + { "item": "cable", "charges": [ 1, 15 ] } + ] + } } ] diff --git a/data/json/furniture_and_terrain/furniture-migo.json b/data/json/furniture_and_terrain/furniture-migo.json deleted file mode 100644 index 471df355ec15c..0000000000000 --- a/data/json/furniture_and_terrain/furniture-migo.json +++ /dev/null @@ -1,164 +0,0 @@ -[ - { - "type": "furniture", - "id": "f_alien_tendril", - "name": "glowing tendril", - "description": "A willowy tendril growing from the floor, gently waving back and forth. A faint light spills from it.", - "symbol": "i", - "color": "blue", - "move_cost_mod": 4, - "coverage": 10, - "light_emitted": 15, - "required_str": -1, - "flags": [ "TRANSPARENT" ], - "bash": { - "str_min": 8, - "str_max": 20, - "sound": "splorch!", - "sound_fail": "whump!", - "furn_set": "f_alien_scar", - "items": [ { "item": "fetid_goop", "count": [ 3, 5 ], "prob": 100 } ] - } - }, - { - "type": "furniture", - "id": "f_alien_anemone", - "name": "wafting anemone", - "description": "A fleshy white protuberance growing from the floor, with a cluster of tendrils pouring out of it. It looks almost exactly like a sea anemone, even waving gently as though underwater.", - "symbol": "V", - "color": "white", - "move_cost_mod": 6, - "coverage": 30, - "required_str": -1, - "light_emitted": 3, - "flags": [ "TRANSPARENT", "EMITTER" ], - "emissions": [ "emit_hot_air_migo_seep" ], - "bash": { - "str_min": 13, - "str_max": 26, - "sound": "splorch!", - "sound_fail": "whump!", - "furn_set": "f_alien_scar", - "items": [ { "item": "fetid_goop", "count": [ 3, 7 ], "prob": 100 } ] - } - }, - { - "type": "furniture", - "id": "f_alien_gasper", - "name": "gasping tube", - "description": "This is a meaty green stalactite with a thickened hide like that of a starfish, extending from the floor to the ceiling. In the center is a series of ports somewhat like mouths, from which pour bursts of a vile-smelling gas.", - "symbol": "{", - "color": "green", - "move_cost_mod": 6, - "coverage": 40, - "required_str": -1, - "flags": [ "TRANSPARENT", "EMITTER" ], - "emissions": [ "emit_migo_atmosphere", "emit_hot_air_migo_blast" ], - "//": "TODO: Make a custom toxic gas emission that is not visible to the player", - "bash": { - "str_min": 30, - "str_max": 60, - "sound": "splorch!", - "sound_fail": "whump!", - "furn_set": "f_alien_scar", - "items": [ { "item": "fetid_goop", "count": [ 15, 25 ], "prob": 100 } ] - } - }, - { - "type": "furniture", - "id": "f_alien_zapper", - "name": "twitching frond", - "description": "A spine resembling moth antennae juts from the ground, swaying gently in the air. Every so often, a cascade of energy arcs along it and discharges into the ceiling.", - "symbol": "F", - "color": "light_blue", - "move_cost_mod": 4, - "coverage": 20, - "required_str": -1, - "flags": [ "TRANSPARENT", "EMITTER" ], - "emissions": [ "emit_glimmer", "emit_shock_burst" ], - "//": "TODO: Make a custom toxic gas emission that is not visible to the player", - "bash": { "str_min": 30, "str_max": 60, "sound": "splorch!", "sound_fail": "whump!", "furn_set": "f_alien_scar" } - }, - { - "type": "furniture", - "id": "f_alien_scar", - "name": "scarred lump", - "description": "This is a pile of nondescript alien flesh, twitching and belching strange gases out of injured orifices.", - "symbol": "{", - "color": "green", - "move_cost_mod": 6, - "coverage": 40, - "required_str": -1, - "flags": [ "TRANSPARENT", "EMITTER" ], - "emissions": [ "emit_hot_air_migo_seep", "emit_shock_burst" ], - "//": "TODO: Make a custom toxic gas emission that is not visible to the player", - "bash": { - "str_min": 250, - "str_max": 600, - "sound": "splorch!", - "sound_fail": "splat!", - "items": [ { "item": "fetid_goop", "count": [ 6, 13 ], "prob": 100 } ] - } - }, - { - "type": "furniture", - "id": "f_alien_pod", - "name": "slimy pod", - "description": "This is a slick, translucent pod suspended on a thin stalk. It is covered in a thick mucus, obscuring whatever is floating in the gel-like substance inside.", - "symbol": "0", - "color": "magenta", - "move_cost_mod": -1, - "coverage": 40, - "required_str": -1, - "flags": [ "TRANSPARENT" ], - "bash": { - "str_min": 25, - "str_max": 60, - "sound": "splorch!", - "sound_fail": "whump.", - "items": [ { "item": "fetid_goop", "count": [ 5, 10 ], "prob": 100 } ] - } - }, - { - "type": "furniture", - "id": "f_alien_pod_organ", - "name": "organ pod", - "description": "This is a translucent pod suspended on a thin stalk. Inside you can see the dimly outlined shape of human organs, floating in some kind of preservative goo.", - "symbol": "0", - "color": "yellow", - "move_cost_mod": -1, - "coverage": 40, - "required_str": -1, - "light_emitted": 3, - "flags": [ "TRANSPARENT" ], - "bash": { "str_min": 25, "str_max": 60, "sound": "splorch!", "sound_fail": "whump." } - }, - { - "type": "furniture", - "id": "f_alien_pod_resin", - "name": "resin pod", - "description": "This is a translucent pod suspended on a thin stalk. Inside is a clean, clear resinous-looking fluid. You could fairly easily tear it from the stalk and take it with you.", - "symbol": "0", - "color": "light_blue", - "move_cost_mod": -1, - "coverage": 40, - "required_str": -1, - "flags": [ "TRANSPARENT", "EASY_DECONSTRUCT" ], - "deconstruct": { "items": [ { "item": "alien_pod_resin", "charges": [ 2, 6 ] } ] }, - "bash": { "str_min": 25, "str_max": 60, "sound": "splorch!", "sound_fail": "whump." } - }, - { - "type": "furniture", - "id": "f_alien_table", - "name": "fleshy altar", - "description": "This pulsing protuberance juts from the floor, its sides covered in scaled, oozing skin. The surface is flat, but undulates softly. A handful of unidentifiable appendages reach from the sides, suggesting a sort of nightmarish living autodoc.", - "symbol": "n", - "color": "pink", - "move_cost_mod": -1, - "coverage": 40, - "required_str": -1, - "light_emitted": 12, - "flags": [ "TRANSPARENT" ], - "bash": { "str_min": 45, "str_max": 60, "sound": "splorch!", "sound_fail": "whump.", "furn_set": "f_alien_scar" } - } -] diff --git a/data/json/furniture_and_terrain/furniture-plumbing.json b/data/json/furniture_and_terrain/furniture-plumbing.json index 630dbce5bc55e..b580206f2b30c 100644 --- a/data/json/furniture_and_terrain/furniture-plumbing.json +++ b/data/json/furniture_and_terrain/furniture-plumbing.json @@ -62,6 +62,7 @@ "coverage": 60, "required_str": -1, "flags": [ "TRANSPARENT", "FLAMMABLE_HARD", "CONTAINER", "PLACE_ITEM", "MOUNTABLE" ], + "//connects_to": "COUNTER", "bash": { "str_min": 8, "str_max": 30, diff --git a/data/json/furniture_and_terrain/furniture-recreation.json b/data/json/furniture_and_terrain/furniture-recreation.json index 87ae45ae4cd6b..58ae31a1257f8 100644 --- a/data/json/furniture_and_terrain/furniture-recreation.json +++ b/data/json/furniture_and_terrain/furniture-recreation.json @@ -4,12 +4,13 @@ "id": "f_exercise", "name": "exercise machine", "symbol": "T", - "description": "A heavy set of weightlifting equipment for strength training, with a pair of heavy weights affixed to opposite ends of a sturdy pipe. The weights are huge, and using them without a spotter would be a good way to seriously injure yourself.", + "description": "A heavy set of weightlifting equipment for strength training, with a pair of heavy weights affixed to opposite ends of a sturdy pipe. You can adjust the set by hand-picking the weights you wish to use.", "color": "dark_gray", "move_cost_mod": 1, "coverage": 35, "required_str": 8, - "flags": [ "TRANSPARENT", "MINEABLE" ], + "flags": [ "TRANSPARENT", "MINEABLE", "WORKOUT_ARMS" ], + "examine_action": "workout", "deconstruct": { "items": [ { "item": "pipe", "count": 1 }, @@ -250,6 +251,47 @@ ] } }, + { + "type": "furniture", + "id": "f_ergometer_mechanical", + "name": "mechanical ergometer", + "description": "An exercise machine with a set of handles and plates meant to emulate rowing a boat. This an older model with mechanical resistance adjustments, but it works without power.", + "symbol": "5", + "color": "dark_gray", + "move_cost_mod": 2, + "required_str": 8, + "looks_like": "f_ergometer", + "flags": [ "BLOCKSDOOR", "TRANSPARENT", "MOUNTABLE", "WORKOUT_ARMS", "WORKOUT_LEGS" ], + "deconstruct": { + "items": [ + { "item": "foot_crank", "count": [ 1, 1 ] }, + { "item": "plastic_chunk", "count": [ 8, 10 ] }, + { "item": "scrap", "count": [ 2, 4 ] }, + { "item": "chain", "count": 1 }, + { "item": "pipe", "count": [ 4, 5 ] }, + { "item": "saddle", "count": [ 1, 1 ] }, + { "item": "wheel_small", "count": [ 1, 1 ] }, + { "item": "nail", "charges": [ 6, 8 ] } + ] + }, + "examine_action": "workout", + "bash": { + "str_min": 6, + "str_max": 25, + "sound": "smash!", + "sound_fail": "thump!", + "items": [ + { "item": "foot_crank", "prob": 50 }, + { "item": "plastic_chunk", "count": [ 4, 6 ] }, + { "item": "scrap", "count": [ 0, 2 ] }, + { "item": "chain", "prob": 50 }, + { "item": "pipe", "count": [ 0, 4 ] }, + { "item": "saddle", "prob": 50 }, + { "item": "wheel_small", "prob": 50 }, + { "item": "nail", "charges": [ 2, 6 ] } + ] + } + }, { "type": "furniture", "id": "f_treadmill", @@ -267,6 +309,7 @@ { "item": "pipe", "count": [ 4, 3 ] }, { "item": "small_lcd_screen", "count": 1 }, { "item": "RAM", "count": 1 }, + { "item": "motor_tiny", "count": 1 }, { "item": "nail", "charges": [ 6, 8 ] } ] }, @@ -281,6 +324,40 @@ { "item": "pipe", "count": [ 0, 4 ] }, { "item": "small_lcd_screen", "prob": 50 }, { "item": "RAM", "count": [ 0, 1 ] }, + { "item": "motor_tiny", "count": [ 0, 1 ] }, + { "item": "nail", "charges": [ 2, 6 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_treadmill_mechanical", + "name": "gravity treadmill", + "description": "A gravity driven conveyor belt with a mechanical control panel for running in place. Conveyor belt is positioned in a steep, but adjustable incline, so it slides back under your weight.", + "symbol": "L", + "color": "dark_gray", + "move_cost_mod": 1, + "required_str": 12, + "looks_like": "f_treadmill", + "flags": [ "BLOCKSDOOR", "TRANSPARENT", "MOUNTABLE", "WORKOUT_LEGS" ], + "deconstruct": { + "items": [ + { "item": "plastic_chunk", "count": [ 10, 14 ] }, + { "item": "scrap", "count": [ 2, 10 ] }, + { "item": "pipe", "count": [ 4, 6 ] }, + { "item": "nail", "charges": [ 6, 8 ] } + ] + }, + "examine_action": "workout", + "bash": { + "str_min": 12, + "str_max": 40, + "sound": "smash!", + "sound_fail": "thump!", + "items": [ + { "item": "plastic_chunk", "count": [ 4, 10 ] }, + { "item": "scrap", "count": [ 0, 5 ] }, + { "item": "pipe", "count": [ 0, 4 ] }, { "item": "nail", "charges": [ 2, 6 ] } ] } @@ -297,7 +374,8 @@ "move_cost_mod": -1, "coverage": 65, "required_str": 10, - "flags": [ "BASHABLE", "BLOCKSDOOR", "PLACE_ITEM", "ORGANIC" ], + "flags": [ "BASHABLE", "BLOCKSDOOR", "PLACE_ITEM", "ORGANIC", "WORKOUT_ARMS" ], + "examine_action": "workout", "bash": { "str_min": 15, "str_max": 20, diff --git a/data/json/furniture_and_terrain/furniture-seats.json b/data/json/furniture_and_terrain/furniture-seats.json index 6ccae0c950855..7193141d4f74c 100644 --- a/data/json/furniture_and_terrain/furniture-seats.json +++ b/data/json/furniture_and_terrain/furniture-seats.json @@ -233,5 +233,39 @@ { "item": "rag", "count": [ 5, 10 ] } ] } + }, + { + "type": "furniture", + "id": "f_metal_bench", + "name": "metal bench", + "description": "A bench made of scrap metal. Not the most comfortable furniture you've ever seen.", + "symbol": "h", + "color": "light_gray", + "move_cost_mod": 1, + "coverage": 30, + "required_str": 7, + "comfort": 1, + "floor_bedding_warmth": -2000, + "bonus_fire_warmth_feet": 1000, + "flags": [ "TRANSPARENT", "MOUNTABLE", "SHORT", "CAN_SIT" ], + "bash": { + "str_min": 15, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 0, 1 ] }, + { "item": "pipe", "count": [ 0, 4 ] } + ] + }, + "deconstruct": { + "items": [ + { "item": "pipe_fittings", "count": 1 }, + { "item": "scrap", "count": 3 }, + { "item": "sheet_metal", "count": 1 }, + { "item": "pipe", "count": 4 } + ] + } } ] diff --git a/data/json/furniture_and_terrain/furniture-storage.json b/data/json/furniture_and_terrain/furniture-storage.json index 2c13322251517..120f285782beb 100644 --- a/data/json/furniture_and_terrain/furniture-storage.json +++ b/data/json/furniture_and_terrain/furniture-storage.json @@ -878,6 +878,100 @@ "items": [ { "item": "scrap", "count": [ 8, 32 ] }, { "item": "water_faucet", "prob": 50 } ] } }, + { + "type": "furniture", + "id": "f_gas_tank", + "name": "fuel tank", + "description": "A tank filled with gasoline.", + "looks_like": "f_standing_tank", + "symbol": "Q", + "color": "brown_red", + "move_cost_mod": -1, + "coverage": 70, + "required_str": -1, + "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "SEALED", "CONTAINER", "REDUCE_SCENT" ], + "bash": { + "str_min": 40, + "str_max": 100, + "explosive": 20, + "sound": "metal screeching!", + "sound_fail": "clang!", + "furn_set": "f_gas_tank_smashed" + } + }, + { + "type": "furniture", + "id": "f_gas_tank_smashed", + "name": "broken fuel tank", + "description": "A broken tank which was filled with gasoline.", + "looks_like": "f_wreckage", + "symbol": "Q", + "color": "light_red", + "move_cost_mod": 6, + "coverage": 30, + "required_str": -1, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT" ], + "bash": { + "str_min": 40, + "str_max": 100, + "explosive": 40, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "steel_lump", "count": [ 1, 4 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 1, 4 ] }, + { "item": "scrap", "count": [ 3, 7 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_diesel_tank", + "name": "fuel tank", + "description": "A tank filled with diesel.", + "looks_like": "f_standing_tank", + "symbol": "Q", + "color": "brown_green", + "move_cost_mod": -1, + "coverage": 70, + "required_str": -1, + "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "SEALED", "CONTAINER", "REDUCE_SCENT" ], + "bash": { + "str_min": 40, + "str_max": 100, + "explosive": 20, + "sound": "metal screeching!", + "sound_fail": "clang!", + "furn_set": "f_diesel_tank_smashed" + } + }, + { + "type": "furniture", + "id": "f_diesel_tank_smashed", + "name": "broken fuel tank", + "description": "A broken tank which was filled with diesel.", + "looks_like": "f_wreckage", + "symbol": "Q", + "color": "light_green", + "move_cost_mod": 6, + "coverage": 30, + "required_str": -1, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT" ], + "bash": { + "str_min": 40, + "str_max": 100, + "explosive": 40, + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "steel_lump", "count": [ 1, 4 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 1, 4 ] }, + { "item": "scrap", "count": [ 3, 7 ] } + ] + } + }, { "type": "furniture", "id": "f_dumpster", @@ -930,5 +1024,81 @@ { "item": "splinter", "count": [ 1, 20 ] } ] } + }, + { + "type": "furniture", + "id": "f_metal_crate_r", + "name": "riveted metal crate", + "looks_like": "f_metal_crate_c", + "description": "This huge box is made of a dull metal, riveted together. There is no obvious opening mechanism, and the rivets don't match any of your tools. The only way in would be to smash it.", + "//": "To-do: There should be an exodii riveting tool that can convert this to f_metal_crate_c", + "symbol": "X", + "color": "light_gray", + "move_cost_mod": 5, + "coverage": 80, + "required_str": 12, + "max_volume": "1000 L", + "flags": [ "CONTAINER", "SEALED", "BLOCKSDOOR", "MOUNTABLE" ], + "bash": { + "str_min": 30, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "sheet_metal", "count": [ 0, 3 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_metal_crate_c", + "name": "sealed metal crate", + "looks_like": "t_crate_c", + "description": "This is a huge, tightly sealed storage crate made from welded and riveted sheet metal. The sealing mechanism is too tight to open bare-handed and would need some kind of prying instrument to release.", + "symbol": "X", + "color": "light_gray", + "move_cost_mod": 5, + "coverage": 80, + "required_str": 12, + "max_volume": "1000 L", + "flags": [ "CONTAINER", "SEALED", "BLOCKSDOOR", "MOUNTABLE", "FLAT_SURF" ], + "bash": { + "str_min": 30, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "sheet_metal", "count": [ 0, 3 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_metal_crate_o", + "name": "open metal crate", + "looks_like": "f_metal_crate_c", + "description": "This large metal crate’s lid is unsealed, and hinges open easily to reveal a number of storage shelves inside. Once open, the side panels also swing wider for easy access.", + "symbol": "X", + "color": "light_gray", + "move_cost_mod": 5, + "coverage": 80, + "required_str": 12, + "max_volume": "1000 L", + "flags": [ "CONTAINER", "PLACE_ITEM", "NO_SIGHT", "HIDE_PLACE", "BLOCKSDOOR", "MOUNTABLE" ], + "bash": { + "str_min": 30, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "pipe", "count": [ 0, 3 ] }, + { "item": "sheet_metal", "count": [ 0, 3 ] }, + { "item": "sheet_metal_small", "count": [ 2, 10 ] } + ] + } } ] diff --git a/data/json/furniture_and_terrain/furniture-surfaces.json b/data/json/furniture_and_terrain/furniture-surfaces.json index 69359619cea6a..272d466d732e0 100644 --- a/data/json/furniture_and_terrain/furniture-surfaces.json +++ b/data/json/furniture_and_terrain/furniture-surfaces.json @@ -10,6 +10,7 @@ "coverage": 60, "required_str": 10, "flags": [ "TRANSPARENT", "FLAMMABLE", "ORGANIC", "MOUNTABLE", "SHORT", "FLAT_SURF" ], + "//connects_to": "COUNTER", "deconstruct": { "items": [ { "item": "2x4", "count": 4 }, { "item": "wood_panel", "count": 1 }, { "item": "nail", "charges": [ 6, 10 ] } ] }, @@ -34,6 +35,7 @@ "coverage": 55, "required_str": -1, "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "CONTAINER", "PLACE_ITEM", "ORGANIC", "MOUNTABLE", "FLAT_SURF" ], + "//connects_to": "COUNTER", "deconstruct": { "items": [ { "item": "2x4", "count": 3 }, { "item": "wood_panel", "count": 1 }, { "item": "nail", "charges": [ 6, 8 ] } ] }, @@ -311,5 +313,38 @@ }, "examine_action": "workbench", "workbench": { "multiplier": 0.85, "mass": 200000, "volume": "75L" } + }, + { + "type": "furniture", + "id": "f_metal_table", + "name": "metal table", + "description": "A serviceable but simple table made of scrap metal.", + "symbol": "T", + "color": "light_gray", + "move_cost_mod": 4, + "coverage": 40, + "required_str": 8, + "flags": [ "TRANSPARENT", "MOUNTABLE", "FLAT_SURF", "SHORT" ], + "bash": { + "str_min": 20, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 0, 1 ] }, + { "item": "pipe", "count": [ 0, 4 ] } + ] + }, + "deconstruct": { + "items": [ + { "item": "pipe_fittings", "count": 2 }, + { "item": "scrap", "count": 4 }, + { "item": "sheet_metal", "count": 1 }, + { "item": "pipe", "count": 4 } + ] + }, + "examine_action": "workbench", + "workbench": { "multiplier": 1.1, "mass": 500000, "volume": "300L" } } ] diff --git a/data/json/furniture_and_terrain/furniture-terrains.json b/data/json/furniture_and_terrain/furniture-terrains.json index 0708175a0f9d8..cda62fcb1c497 100644 --- a/data/json/furniture_and_terrain/furniture-terrains.json +++ b/data/json/furniture_and_terrain/furniture-terrains.json @@ -590,6 +590,33 @@ ], "examine_action": "rubble" }, + { + "type": "furniture", + "id": "f_reactor_meltdown", + "name": "radioactive slag", + "description": "A pile of melted slag from a destroyed nuclear reactor. What are you doing looking at this? Get the hell out of here, you nutcase!", + "looks_like": "f_wreckage", + "symbol": "#", + "color": "light_green", + "move_cost_mod": 6, + "max_volume": "750 L", + "required_str": -1, + "emissions": [ "emit_rad_cloud" ], + "flags": [ + "TRANSPARENT", + "UNSTABLE", + "ROUGH", + "SHARP", + "PLACE_ITEM", + "MOUNTABLE", + "CONTAINER", + "SEALED", + "ALLOW_FIELD_EFFECT", + "SHORT", + "RUBBLE", + "EMITTER" + ] + }, { "type": "furniture", "id": "f_ash", @@ -746,5 +773,35 @@ { "item": "scrap", "count": [ 3, 5 ] } ] } + }, + { + "type": "furniture", + "id": "f_scrap_bridge", + "name": "scrap metal bridge", + "description": "A simple bridge made of riveted sheet metal.", + "move_cost_mod": 0, + "symbol": "]", + "color": "light_gray", + "required_str": -1, + "flags": [ "TRANSPARENT", "NOCOLLIDE" ], + "deconstruct": { + "items": [ + { "item": "scrap", "count": 10 }, + { "item": "sheet_metal", "count": 2 }, + { "item": "rebar", "count": 2 }, + { "item": "wire", "count": 2 } + ] + }, + "bash": { + "str_min": 25, + "str_max": 200, + "sound": "metal screeching!", + "sound_fail": "crash!", + "items": [ + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "sheet_metal", "count": [ 0, 1 ] }, + { "item": "rebar", "count": [ 0, 2 ] } + ] + } } ] diff --git a/data/json/furniture_and_terrain/furniture-tools.json b/data/json/furniture_and_terrain/furniture-tools.json index 52208dbed4da3..fbd610073b17c 100644 --- a/data/json/furniture_and_terrain/furniture-tools.json +++ b/data/json/furniture_and_terrain/furniture-tools.json @@ -1,8 +1,106 @@ [ + { + "type": "furniture", + "id": "f_console_broken", + "name": "broken console", + "looks_like": "t_console_broken", + "description": "This is a standalone computer terminal. It doesn't seem to be working. It's the broken screen and shattered circuit boards that's telling you that.", + "symbol": "6", + "color": "light_gray", + "move_cost_mod": -1, + "coverage": 50, + "required_str": -1, + "flags": [ "TRANSPARENT", "NOITEM", "INDOORS", "SHORT", "PERMEABLE" ], + "//connects_to": "COUNTER", + "deconstruct": { + "furn_set": "f_counter", + "items": [ + { "item": "processor", "count": [ 1, 2 ] }, + { "item": "RAM", "count": [ 4, 8 ] }, + { "item": "cable", "charges": [ 4, 6 ] }, + { "item": "large_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 10, 16 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 2, 4 ] }, + { "item": "amplifier", "count": [ 2, 4 ] }, + { "item": "plastic_chunk", "count": [ 10, 12 ] }, + { "item": "scrap", "count": [ 6, 8 ] } + ] + }, + "bash": { + "str_min": 16, + "str_max": 150, + "sound": "crunch!", + "sound_fail": "whack!", + "furn_set": "f_counter", + "items": [ + { "item": "processor", "prob": 25 }, + { "item": "RAM", "count": [ 0, 2 ], "prob": 50 }, + { "item": "cable", "charges": [ 1, 2 ], "prob": 50 }, + { "item": "large_lcd_screen", "prob": 25 }, + { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, + { "item": "circuit", "count": [ 0, 2 ], "prob": 50 }, + { "item": "power_supply", "prob": 25 }, + { "item": "amplifier", "prob": 25 }, + { "item": "plastic_chunk", "count": [ 4, 10 ], "prob": 50 }, + { "item": "scrap", "count": [ 2, 6 ], "prob": 50 } + ] + } + }, + { + "type": "furniture", + "id": "f_console", + "name": "computer console", + "looks_like": "t_console", + "description": "This is a standalone computer terminal. It can be used to view contents and perform any allowed functions. It might even be possible to hack it, given the skills.", + "symbol": "6", + "color": "blue", + "move_cost_mod": -1, + "coverage": 50, + "required_str": -1, + "light_emitted": 10, + "flags": [ "TRANSPARENT", "CONSOLE", "NOITEM", "INDOORS", "SHORT", "PERMEABLE" ], + "//connects_to": "COUNTER", + "deconstruct": { + "furn_set": "f_counter", + "items": [ + { "item": "processor", "count": [ 1, 2 ] }, + { "item": "RAM", "count": [ 4, 8 ] }, + { "item": "cable", "charges": [ 4, 6 ] }, + { "item": "large_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 10, 16 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 2, 4 ] }, + { "item": "amplifier", "count": [ 2, 4 ] }, + { "item": "plastic_chunk", "count": [ 10, 12 ] }, + { "item": "scrap", "count": [ 6, 8 ] } + ] + }, + "bash": { + "str_min": 8, + "str_max": 150, + "sound": "crunch!", + "sound_fail": "whack!", + "furn_set": "f_console_broken", + "items": [ + { "item": "processor", "prob": 25 }, + { "item": "RAM", "count": [ 0, 2 ], "prob": 50 }, + { "item": "cable", "charges": [ 1, 2 ], "prob": 50 }, + { "item": "large_lcd_screen", "prob": 25 }, + { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, + { "item": "circuit", "count": [ 0, 2 ], "prob": 50 }, + { "item": "power_supply", "prob": 25 }, + { "item": "amplifier", "prob": 25 }, + { "item": "plastic_chunk", "count": [ 4, 10 ], "prob": 50 }, + { "item": "scrap", "count": [ 2, 6 ], "prob": 50 } + ] + } + }, { "type": "furniture", "id": "f_forge", "name": "forge", + "looks_like": "f_fireplace", "description": "Metalworking station typically used in combination with an anvil.", "symbol": "^", "color": "light_red", @@ -25,6 +123,7 @@ "type": "furniture", "id": "f_anvil", "name": "anvil", + "looks_like": "f_boulder", "description": "Used in metalworking.", "symbol": "^", "color": "light_red", @@ -56,6 +155,7 @@ "type": "furniture", "id": "f_kiln_empty", "name": "charcoal kiln", + "looks_like": "f_fireplace", "description": "A rock kiln designed to burn wood and organic material into charcoal in absence of oxygen.", "symbol": "U", "color": "brown", @@ -101,6 +201,7 @@ "type": "furniture", "id": "f_kiln_metal_empty", "name": "metal charcoal kiln", + "looks_like": "f_kiln_empty", "description": "A metal kiln designed to burn wood and organic material into charcoal in absence of oxygen.", "symbol": "U", "color": "blue", @@ -208,6 +309,7 @@ "type": "furniture", "id": "f_smoking_rack", "name": "smoking rack", + "looks_like": "f_rack", "description": "A special rack designed to smoke food for better preservation and taste. Works as a charcoal smoker in crafting recipes.", "symbol": "=", "bgcolor": "brown", @@ -296,6 +398,7 @@ "type": "furniture", "id": "f_forge_rock", "name": "rock forge", + "looks_like": "f_fireplace", "description": "Metalworking station made of rock, typically used in combination with an anvil. Works as a charcoal forge in crafting recipes.", "symbol": "^", "color": "light_red", @@ -318,6 +421,7 @@ "type": "furniture", "id": "f_clay_kiln", "name": "clay kiln", + "looks_like": "f_fireplace", "description": "A kiln designed to bake clay pottery and bricks.", "symbol": "^", "color": "light_red", @@ -365,7 +469,7 @@ "type": "furniture", "id": "f_arc_furnace", "name": "electric arc furnace", - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "description": "Not the kind of furnace you'd heat your house with, this is a device for heating things to extreme temperatures as part of industrial fabrication processes.", "symbol": "0", "color": "white_red", @@ -399,7 +503,7 @@ "type": "furniture", "id": "f_drill_press", "name": "drill press", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A powerful drill mounted on a slide that lets it drop precisely down. Useful in all kinds of projects from industrial fabrication to home woodworking.", "symbol": "7", "color": "yellow_red", @@ -436,7 +540,7 @@ "type": "furniture", "id": "f_tablesaw", "name": "tablesaw", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A rotating saw blade set into a large flat table, for making straight measured cuts. One of the key tools in a carpenter's arsenal.", "symbol": "7", "color": "yellow_red", @@ -474,7 +578,7 @@ "type": "furniture", "id": "f_mitresaw", "name": "mitre saw", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A circular saw blade on an arm that can slide and rotate in several directions, this is a staple tool for nearly any carpentry.", "symbol": "7", "color": "yellow_cyan", @@ -512,7 +616,7 @@ "type": "furniture", "id": "f_bandsaw", "name": "bandsaw", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A ribbonlike sawblade runs in a single direction in this tool, allowing precise cuts at almost any angle.", "symbol": "7", "color": "yellow_cyan", @@ -549,7 +653,7 @@ "type": "furniture", "id": "f_router", "name": "router table", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "This table has an inset router, a rotating motor with an exchangeable blade head for cutting specific profiles and grooves and stuff.", "symbol": "7", "color": "yellow_green", @@ -586,7 +690,7 @@ "type": "furniture", "id": "f_planer", "name": "planer", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A hefty tool that will take in a board and cut it smooth and flat to a specific width. Particularly great if working with raw lumber stock, but also good just for shaving wood down to size.", "symbol": "7", "color": "yellow_white", @@ -623,7 +727,7 @@ "type": "furniture", "id": "f_jointer", "name": "jointer", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "A table-shaped tool with a rotating blade that will cut down, smooth out, and square off a board to make it very smooth and nice indeed.", "symbol": "7", "color": "yellow_magenta", @@ -660,7 +764,7 @@ "type": "furniture", "id": "f_hydraulic_press", "name": "hydraulic press", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "If you really want to squash something a lot, this would be exactly the right industrial tool for you. If, you know, it had power.", "symbol": "9", "color": "black_red", @@ -697,7 +801,7 @@ "type": "furniture", "id": "f_heavy_lathe", "name": "power lathe", - "looks_like": "t_machinery_light", + "looks_like": "f_machinery_light", "description": "An industrial-grade lathe, for turning chunks of metal and other hard things into round chunks of metal and other hard things.", "symbol": "4", "color": "cyan_red", @@ -773,6 +877,7 @@ "type": "furniture", "id": "f_fvat_empty", "name": "fermenting vat", + "looks_like": "f_standing_tank", "description": "A sealable vat for fermenting vinegar and various alcoholic brews.", "symbol": "O", "color": "brown", @@ -808,6 +913,7 @@ "type": "furniture", "id": "f_fvat_full", "name": "filled fermenting vat", + "looks_like": "f_fvat_empty", "description": "A sealable vat for fermenting vinegar and various alcoholic brews.", "symbol": "O", "color": "brown_cyan", @@ -843,6 +949,7 @@ "type": "furniture", "id": "f_butcher_rack", "name": "butchering rack", + "looks_like": "f_rack", "description": "Butchering rack designed to hang a carcass in the air.", "symbol": "^", "bgcolor": "brown", @@ -871,6 +978,7 @@ "type": "furniture", "id": "f_metal_butcher_rack", "name": "metal butchering rack", + "looks_like": "f_butcher_rack", "description": "Metal butchering rack designed to hang a carcass in the air. It can be deconstructed and folded for easy transportation.", "symbol": "^", "bgcolor": "light_gray", @@ -892,6 +1000,7 @@ "id": "f_hanging_meathook", "type": "furniture", "name": "hanging meathook", + "looks_like": "f_butcher_rack", "description": "A hefty hook suspended from a chain for stringing up corpses.", "symbol": "g", "required_str": -1, @@ -929,6 +1038,7 @@ "type": "furniture", "id": "f_wind_mill_active", "name": "active wind mill", + "looks_like": "f_wind_mill", "description": "A small wind-powered mill that can convert starchy products into flour. Its brake has been removed and it is turning.", "symbol": "T", "bgcolor": "red", @@ -981,6 +1091,7 @@ "type": "furniture", "id": "f_water_mill_active", "name": "active water mill", + "looks_like": "f_water_mill", "description": "A small water-powered mill that can convert starchy products into flour. Its brake has been removed and it is turning.", "symbol": "*", "bgcolor": "red", @@ -1008,7 +1119,7 @@ "type": "furniture", "id": "f_aut_gas_console", "name": "automated gas console", - "looks_like": "t_console", + "looks_like": "f_console", "description": "Automated gas flow control console.", "symbol": "9", "color": "blue", @@ -1023,7 +1134,7 @@ "type": "furniture", "id": "f_aut_gas_console_o", "name": "broken automated gas console", - "looks_like": "t_console_broken", + "looks_like": "f_console_broken", "description": "Automated gas flow control console. Broken. This is not a good thing.", "symbol": "9", "color": "dark_gray", @@ -1075,7 +1186,7 @@ "type": "furniture", "id": "f_vending_c", "name": "vending machine", - "looks_like": "t_console", + "looks_like": "f_console", "symbol": "{", "description": "Buy stuff with a cash card.", "color": "light_cyan", @@ -1099,7 +1210,7 @@ "type": "furniture", "id": "f_vending_o", "name": "broken vending machine", - "looks_like": "t_console_broken", + "looks_like": "f_console_broken", "description": "Ponder if you could buy stuff, as it's broken. Maybe if you broke it more, you wouldn't need to pay at all!", "symbol": "{", "color": "dark_gray", @@ -1120,5 +1231,26 @@ { "item": "scrap_copper", "count": [ 0, 2 ] } ] } + }, + { + "type": "furniture", + "id": "f_rope_up", + "name": "rope leading up", + "looks_like": "t_rope_up", + "description": "A rope. You could climb it up.", + "symbol": "<", + "color": "white", + "move_cost_mod": 1, + "required_str": 10, + "flags": [ "LADDER", "TRANSPARENT", "SEEN_FROM_ABOVE" ], + "examine_action": "deployed_furniture", + "deployed_item": "grapnel", + "bash": { + "str_min": 3, + "str_max": 40, + "sound": "smash!", + "sound_fail": "whump.", + "items": [ { "item": "grip_hook", "count": [ 4, 4 ] }, { "item": "rope_30", "count": [ 1, 1 ] } ] + } } ] diff --git a/data/json/furniture_and_terrain/terrain-fences-gates.json b/data/json/furniture_and_terrain/terrain-fences-gates.json index e38358b49e8fc..873df1c6b81d0 100644 --- a/data/json/furniture_and_terrain/terrain-fences-gates.json +++ b/data/json/furniture_and_terrain/terrain-fences-gates.json @@ -947,6 +947,25 @@ ] } }, + { + "type": "terrain", + "id": "t_guardrail_hw_air", + "name": "guard rail", + "description": "A section of metal railing, put in place to prevent people from falling or taking the easy way out.", + "symbol": "#", + "color": "light_gray", + "looks_like": "t_guardrail_bg_dp", + "move_cost": 3, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT", "MOUNTABLE", "SHORT", "THIN_OBSTACLE", "ROAD", "BURROWABLE" ], + "bash": { + "str_min": 8, + "str_max": 150, + "sound": "crunch!", + "sound_fail": "clang!", + "ter_set": "t_pavement_hw_air", + "items": [ { "item": "pipe", "count": [ 1, 2 ] }, { "item": "scrap", "count": [ 3, 6 ] } ] + } + }, { "type": "terrain", "id": "t_guardrail_bg_dp", diff --git a/data/json/furniture_and_terrain/terrain-flesh.json b/data/json/furniture_and_terrain/terrain-flesh.json new file mode 100644 index 0000000000000..61dda64871e97 --- /dev/null +++ b/data/json/furniture_and_terrain/terrain-flesh.json @@ -0,0 +1,41 @@ +[ + { + "type": "terrain", + "id": "t_thconc_floor_flesh", + "name": "overgrown floor", + "description": "A bare concrete floor, almost completely covered by twitching filaments of grey flesh.", + "symbol": ".", + "color": "red_yellow", + "move_cost": 5, + "roof": "t_flat_roof", + "flags": [ "TRANSPARENT", "SUPPORTS_ROOF", "COLLAPSES", "INDOORS", "FLAT" ], + "bash": { + "sound": "SMASH!", + "ter_set": "t_concrete", + "str_min": 10, + "str_max": 20, + "str_min_supported": 10, + "items": [ { "item": "meat_tainted", "count": [ 5, 10 ] } ] + } + }, + { + "type": "terrain", + "id": "t_concrete_wall_flesh", + "name": "overgrown wall", + "description": "A concrete wall overgrown by a grotesque grid of veins and knotted flesh.", + "symbol": "LINE_OXOX", + "color": "magenta_yellow", + "move_cost": 0, + "coverage": 100, + "roof": "t_flat_roof", + "flags": [ "NOITEM", "SUPPORTS_ROOF", "WALL", "NO_SCENT", "AUTO_WALL_SYMBOL", "MINEABLE", "BLOCK_WIND" ], + "bash": { + "str_min": 10, + "str_max": 20, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_strconc_wall", + "items": [ { "item": "meat_tainted", "count": [ 5, 10 ] } ] + } + } +] diff --git a/data/json/furniture_and_terrain/terrain-floors-indoor.json b/data/json/furniture_and_terrain/terrain-floors-indoor.json index cf0510527912a..e952ff1cb1ba8 100644 --- a/data/json/furniture_and_terrain/terrain-floors-indoor.json +++ b/data/json/furniture_and_terrain/terrain-floors-indoor.json @@ -29,7 +29,7 @@ "description": "A bare and cold concrete floor with a streak of yellow paint, could still insulate from the outdoors but roof collapse is possible if supporting walls are broken down.", "symbol": ".", "color": "yellow", - "looks_like": "t_wall_y", + "looks_like": "t_pavement_y", "move_cost": 2, "roof": "t_flat_roof", "flags": [ "TRANSPARENT", "SUPPORTS_ROOF", "COLLAPSES", "INDOORS", "FLAT", "ROAD" ], @@ -479,6 +479,7 @@ "copy-from": "t_carpet_base_concrete", "name": "industrial red carpet", "alias": "t_carpet_concrete", + "looks_like": "t_carpet_red", "symbol": ".", "color": "red", "move_cost": 2, @@ -552,6 +553,7 @@ "symbol": ".", "color": "red", "move_cost": 2, + "looks_like": "t_carpet_red", "description": "Firm, low-pile, totally non-flammable carpet in a red color, with an insulation layer beneath.", "flags": [ "TRANSPARENT", "SUPPORTS_ROOF", "COLLAPSES", "INDOORS", "FLAT", "RUG", "EASY_DECONSTRUCT" ], "deconstruct": { "items": [ { "item": "r_carpet", "charges": 1 }, { "item": "nail", "charges": 5 } ], "ter_set": "t_metal_floor" } diff --git a/data/json/furniture_and_terrain/terrain-highways.json b/data/json/furniture_and_terrain/terrain-highways.json new file mode 100644 index 0000000000000..7eeaa08f1d3eb --- /dev/null +++ b/data/json/furniture_and_terrain/terrain-highways.json @@ -0,0 +1,59 @@ +[ + { + "type": "terrain", + "id": "t_pavement_hw_air", + "name": "bridge pavement", + "description": "A bridge section made out of metal and concrete.", + "looks_like": "t_pavement", + "symbol": ".", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAT", "ROAD", "MINEABLE" ], + "bash": { + "str_min": 70, + "str_max": 300, + "sound": "concrete cracking and metal screeching!", + "sound_fail": "whump!", + "ter_set": "t_open_air", + "items": [ { "item": "rock", "count": [ 4, 20 ] }, { "item": "rebar", "count": [ 10, 20 ] } ] + } + }, + { + "type": "terrain", + "id": "t_pavement_y_hw_air", + "name": "bridge yellow pavement", + "description": "A bridge section made out of metal and concrete. It's painted yellow.", + "looks_like": "t_pavement_y", + "symbol": ".", + "color": "yellow", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAT", "ROAD", "MINEABLE" ], + "bash": { + "str_min": 70, + "str_max": 300, + "sound": "concrete cracking and metal screeching!", + "sound_fail": "whump!", + "ter_set": "t_open_air", + "items": [ { "item": "rock", "count": [ 4, 20 ] }, { "item": "rebar", "count": [ 10, 20 ] } ] + } + }, + { + "type": "terrain", + "id": "t_sidewalk_hw_air", + "name": "bridge sidewalk", + "description": "The sidewalk section of a concrete bridge.", + "looks_like": "t_sidewalk", + "symbol": ".", + "color": "light_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAT", "ROAD", "MINEABLE" ], + "bash": { + "str_min": 70, + "str_max": 300, + "sound": "concrete cracking and metal screeching!", + "sound_fail": "whump!", + "ter_set": "t_open_air", + "items": [ { "item": "rock", "count": [ 4, 20 ] }, { "item": "rebar", "count": [ 10, 20 ] } ] + } + } +] diff --git a/data/json/furniture_and_terrain/terrain-manufactured.json b/data/json/furniture_and_terrain/terrain-manufactured.json index a25bb63a2cc99..1079ab1182944 100644 --- a/data/json/furniture_and_terrain/terrain-manufactured.json +++ b/data/json/furniture_and_terrain/terrain-manufactured.json @@ -4,7 +4,7 @@ "id": "t_recycler", "name": "metal compactor", "description": "A hydraulic compactor that can accept items made of various metals, and press them into basic shapes, ready for further crafting.", - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "symbol": "&", "color": "green", "move_cost": 0, @@ -24,56 +24,11 @@ ] } }, - { - "type": "terrain", - "id": "t_gas_tank", - "name": "fuel tank", - "description": "A tank filled with gasoline.", - "looks_like": "f_standing_tank", - "symbol": "Q", - "color": "brown_red", - "move_cost": 0, - "coverage": 50, - "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "SEALED", "CONTAINER", "REDUCE_SCENT" ], - "bash": { - "str_min": 40, - "str_max": 100, - "explosive": 40, - "sound": "metal screeching!", - "sound_fail": "clang!", - "ter_set": "t_gas_tank_smashed" - } - }, - { - "type": "terrain", - "id": "t_gas_tank_smashed", - "name": "broken fuel tank", - "description": "A broken tank which was filled with gasoline.", - "looks_like": "f_wreckage", - "symbol": "Q", - "color": "light_red", - "move_cost": 0, - "coverage": 50, - "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "REDUCE_SCENT" ], - "bash": { - "str_min": 40, - "str_max": 100, - "explosive": 40, - "sound": "metal screeching!", - "sound_fail": "clang!", - "ter_set": "t_pavement", - "items": [ - { "item": "steel_lump", "count": [ 1, 4 ] }, - { "item": "steel_chunk", "count": [ 1, 4 ] }, - { "item": "scrap", "count": [ 3, 7 ] } - ] - } - }, { "type": "terrain", "id": "t_gas_pump", "name": "gasoline pump", - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "description": "Precious GASOLINE. The former world bowed to their petroleum god as it led them to their ruin. There's plenty left over to fuel your inner road warrior. If this gas dispenser doesn't give up the goods for free, you may have to pay at a nearby terminal.", "symbol": "&", "color": "red", @@ -129,51 +84,6 @@ ] } }, - { - "type": "terrain", - "id": "t_diesel_tank", - "name": "fuel tank", - "description": "A tank filled with diesel.", - "looks_like": "f_standing_tank", - "symbol": "Q", - "color": "brown_green", - "move_cost": 0, - "coverage": 50, - "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "SEALED", "CONTAINER", "REDUCE_SCENT" ], - "bash": { - "str_min": 40, - "str_max": 100, - "explosive": 40, - "sound": "metal screeching!", - "sound_fail": "clang!", - "ter_set": "t_diesel_tank_smashed" - } - }, - { - "type": "terrain", - "id": "t_diesel_tank_smashed", - "name": "broken fuel tank", - "description": "A broken tank which was filled with diesel.", - "looks_like": "f_wreckage", - "symbol": "Q", - "color": "light_green", - "move_cost": 0, - "coverage": 50, - "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "REDUCE_SCENT" ], - "bash": { - "str_min": 40, - "str_max": 100, - "explosive": 40, - "sound": "metal screeching!", - "sound_fail": "clang!", - "ter_set": "t_pavement", - "items": [ - { "item": "steel_lump", "count": [ 1, 4 ] }, - { "item": "steel_chunk", "count": [ 1, 4 ] }, - { "item": "scrap", "count": [ 3, 7 ] } - ] - } - }, { "type": "terrain", "id": "t_diesel_pump", @@ -322,30 +232,6 @@ }, "deconstruct": { "ter_set": "t_metal_floor_no_roof", "items": [ { "item": "scrap", "count": [ 8, 16 ] } ] } }, - { - "type": "terrain", - "id": "t_generator_broken", - "name": "broken generator", - "description": "This generator is broken and will not help you produce usable electricity.", - "symbol": "&", - "color": "light_gray", - "looks_like": "t_machinery_old", - "move_cost": 0, - "coverage": 30, - "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT", "MOUNTABLE", "PERMEABLE" ], - "bash": { - "str_min": 20, - "str_max": 150, - "sound": "metal screeching!", - "sound_fail": "clang!", - "ter_set": "t_pavement", - "items": [ - { "item": "steel_lump", "prob": 50 }, - { "item": "steel_chunk", "count": [ 1, 4 ] }, - { "item": "scrap", "count": [ 3, 7 ] } - ] - } - }, { "type": "terrain", "id": "t_missile", @@ -416,7 +302,7 @@ "description": "This console appears to control a nearby radio transmission tower. It doesn't seem to be fully operational.", "symbol": "6", "color": "green", - "looks_like": "t_console_broken", + "looks_like": "f_console_broken", "move_cost": 0, "coverage": 50, "flags": [ "TRANSPARENT", "NOITEM", "PERMEABLE" ], @@ -481,7 +367,7 @@ "description": "This unpowered pump previously would have moved fluids around in a hurry.", "symbol": "&", "color": "light_gray", - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "move_cost": 0, "coverage": 50, "flags": [ "NOITEM", "REDUCE_SCENT", "MOUNTABLE" ], @@ -498,32 +384,6 @@ ] } }, - { - "type": "terrain", - "id": "t_centrifuge", - "name": "centrifuge", - "description": "This is a centrifuge, a liquid separating device with an automated analyzer unit. It could be used to analyze a medical fluid sample, such as blood, if a test tube was placed in it.", - "symbol": "{", - "color": "magenta", - "move_cost": 0, - "coverage": 30, - "flags": [ "TRANSPARENT", "PERMEABLE" ], - "bash": { - "str_min": 3, - "str_max": 45, - "sound": "crunch!", - "sound_fail": "whack!", - "ter_set": "t_rock_floor", - "items": [ - { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, - { "item": "circuit", "count": [ 1, 6 ], "prob": 50 }, - { "item": "scrap", "count": [ 2, 5 ] }, - { "item": "steel_chunk", "count": [ 0, 3 ] }, - { "item": "sheet_metal", "count": [ 1, 3 ] }, - { "item": "cable", "charges": [ 1, 15 ] } - ] - } - }, { "type": "terrain", "id": "t_cvdbody", @@ -554,7 +414,7 @@ "description": "This is a VERY expensive-looking apparatus that's labeled 'Chemical Vapor Deposition Machine'. With the input of certain exceptionally rare chemicals and elements, one could conceivably coat one's weapon with diamond. While the process is extremely complicated, a previous user has helpfully sketched: Hydrogen + charcoal = smiley face.", "symbol": "&", "color": "cyan", - "looks_like": "t_console", + "looks_like": "f_console", "move_cost": 0, "coverage": 50, "flags": [ "TRANSPARENT", "NOITEM", "PERMEABLE" ], @@ -617,7 +477,7 @@ "symbol": "&", "description": "A small computer panel attached to a nanofabricator. It has a single slot for reading templates.", "color": "red", - "looks_like": "t_console", + "looks_like": "f_console", "move_cost": 0, "coverage": 50, "flags": [ "WALL", "NOITEM", "PERMEABLE" ], @@ -701,7 +561,7 @@ "type": "terrain", "id": "t_water_pump", "name": "water pump", - "looks_like": "t_machinery_heavy", + "looks_like": "f_machinery_heavy", "description": "Deep well collecting ground water. Installed water pump allows to draw water from it.", "symbol": "&", "color": "light_gray", @@ -748,46 +608,6 @@ }, "examine_action": "clean_water_source" }, - { - "type": "terrain", - "id": "t_plut_generator", - "name": "plutonium generator", - "description": "This imposing apparatus harnesses the power of the atom. Refined nuclear fuel is 'burned' to provide nearly limitless electrical power. It's not doing much good here though. Perhaps it could be salvaged for other purposes.", - "symbol": "0", - "color": "light_green", - "looks_like": "t_machinery_electronic", - "move_cost": 0, - "flags": [ "TRANSPARENT", "NOITEM", "SEALED", "REDUCE_SCENT", "PERMEABLE" ], - "bash": { - "str_min": 50, - "str_max": 400, - "explosive": 25, - "ter_set": "t_concrete", - "sound": "metal screeching!", - "sound_fail": "clang!", - "items": [ - { "item": "scrap", "count": [ 4, 16 ] }, - { "item": "steel_chunk", "count": [ 1, 6 ] }, - { "item": "plutonium", "charges": [ 0, 3 ] }, - { "item": "lead", "charges": [ 12, 18 ] } - ] - }, - "deconstruct": { - "ter_set": "t_concrete", - "items": [ - { "item": "RAM", "count": [ 4, 8 ] }, - { "item": "cable", "charges": [ 8, 16 ] }, - { "item": "small_lcd_screen", "count": [ 2, 4 ] }, - { "item": "large_lcd_screen", "count": 1 }, - { "item": "e_scrap", "count": [ 12, 24 ] }, - { "item": "circuit", "count": [ 6, 10 ] }, - { "item": "power_supply", "count": [ 4, 8 ] }, - { "item": "amplifier", "count": [ 3, 6 ] }, - { "item": "plutonium", "charges": [ 2, 8 ] }, - { "item": "scrap", "count": [ 8, 16 ] } - ] - } - }, { "type": "terrain", "id": "t_sai_box", @@ -795,7 +615,7 @@ "description": "A cabinet full of telecoms equipment. With the lines down, you might be able to take it apart for its useful electronics.", "symbol": "#", "color": "light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 90, "flags": [ "NOITEM", "WALL" ], @@ -861,7 +681,7 @@ "description": "A circuit breaker that uses oil in its arc suppression chamber.", "symbol": "B", "color": "light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 90, "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "WALL", "PERMEABLE" ], @@ -898,7 +718,7 @@ "description": "A small circuit breaker that uses oil in its arc suppression chamber.", "symbol": "b", "color": "light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 65, "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "WALL", "PERMEABLE" ], @@ -935,7 +755,7 @@ "description": "A switchgear panel. It's covered in breaker switches, fuses, and gauges.", "symbol": "H", "color": "i_light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 90, "flags": [ "TRANSPARENT", "NOITEM", "WALL", "PERMEABLE" ], @@ -974,7 +794,7 @@ "description": "A small switchgear panel. It's covered in breaker switches, fuses, and gauges.", "symbol": "L", "color": "i_light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 65, "flags": [ "TRANSPARENT", "NOITEM", "WALL", "PERMEABLE" ], @@ -1017,7 +837,7 @@ "description": "A component designed to protect insulation and conductors in an electrical system by directing lightning through itself and into the ground.", "symbol": "}", "color": "i_light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "flags": [ "TRANSPARENT", "NOITEM", "WALL", "PERMEABLE" ], "bash": { @@ -1051,7 +871,7 @@ "description": "A switch used to make sure an electrical system doesn't have any current flowing through it, for maintenance periods.", "symbol": "h", "color": "light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "flags": [ "TRANSPARENT", "NOITEM", "WALL", "PERMEABLE" ], "bash": { @@ -1093,7 +913,7 @@ "description": "An electronic component used to transform the voltage of a current.", "symbol": "{", "color": "light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 50, "flags": [ "TRANSPARENT", "NOITEM", "WALL", "PERMEABLE" ], @@ -1131,7 +951,7 @@ "description": "A specialized type of electrical transformer, ", "symbol": "8", "color": "i_light_gray", - "looks_like": "t_machinery_electronic", + "looks_like": "f_machinery_electronic", "move_cost": 0, "coverage": 50, "flags": [ "TRANSPARENT", "NOITEM", "WALL", "PERMEABLE" ], @@ -1191,203 +1011,6 @@ "items": [ { "item": "pipe", "count": [ 1, 3 ] }, { "item": "chain", "prob": 10 }, { "item": "scrap", "count": [ 1, 5 ] } ] } }, - { - "type": "terrain", - "id": "t_machinery_light", - "name": "light machinery", - "description": "Assorted light machinery. You could scavenge it for parts.", - "symbol": "$", - "color": "dark_gray", - "move_cost": 10, - "coverage": 65, - "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "FLAMMABLE", "PLACE_ITEM" ], - "deconstruct": { - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": [ 1, 3 ] }, - { "item": "pipe", "count": [ 1, 2 ] }, - { "item": "chain", "prob": 40 }, - { "item": "cu_pipe", "prob": 40 }, - { "item": "scrap", "count": [ 1, 4 ] }, - { "item": "hose", "count": 1 }, - { "item": "steel_chunk", "count": [ 1, 5 ] }, - { "item": "bearing", "charges": [ 4, 12 ] }, - { "item": "frame", "prob": 50 }, - { "item": "motor", "prob": 50 } - ] - }, - "bash": { - "str_min": 16, - "str_max": 80, - "sound": "clang!", - "sound_fail": "ting.", - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": 1 }, - { "item": "pipe", "count": 2, "prob": 40 }, - { "item": "chain", "prob": 20 }, - { "item": "cu_pipe", "prob": 10 }, - { "item": "scrap", "count": [ 3, 8 ] }, - { "item": "steel_chunk", "count": [ 1, 4 ] }, - { "item": "bearing", "charges": [ 2, 8 ] }, - { "item": "frame", "prob": 20 }, - { "item": "motor", "prob": 10 } - ] - } - }, - { - "type": "terrain", - "id": "t_machinery_heavy", - "name": "heavy machinery", - "description": "Assorted heavy machinery. You could scavenge it for parts.", - "symbol": "%", - "color": "light_gray", - "move_cost": 0, - "coverage": 75, - "flags": [ "BASHABLE", "CONTAINER", "SEALED", "PLACE_ITEM" ], - "deconstruct": { - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": [ 1, 3 ] }, - { "item": "pipe", "count": [ 1, 2 ] }, - { "item": "chain", "prob": 60 }, - { "item": "cu_pipe", "prob": 20 }, - { "item": "steel_lump", "count": [ 1, 2 ] }, - { "item": "hose", "count": 1 }, - { "item": "sheet_metal", "count": [ 1, 3 ] }, - { "item": "steel_chunk", "count": [ 1, 3 ] }, - { "item": "bearing", "charges": [ 4, 12 ] }, - { "item": "frame", "prob": 60 }, - { "item": "motor", "prob": 30 }, - { "item": "metal_tank", "prob": 30 }, - { "item": "motor_large", "prob": 10 } - ] - }, - "bash": { - "str_min": 18, - "str_max": 80, - "sound": "clang!", - "sound_fail": "ting.", - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": 1 }, - { "item": "pipe", "count": 1 }, - { "item": "chain", "prob": 20 }, - { "item": "steel_lump", "count": 1 }, - { "item": "scrap", "count": [ 1, 5 ] }, - { "item": "sheet_metal", "count": 2 }, - { "item": "steel_chunk", "count": [ 1, 2 ] }, - { "item": "bearing", "charges": [ 2, 8 ] }, - { "item": "frame", "prob": 30 }, - { "item": "motor", "prob": 10 }, - { "item": "metal_tank", "prob": 20 }, - { "item": "motor_large", "prob": 5 } - ] - } - }, - { - "type": "terrain", - "id": "t_machinery_old", - "name": "old machinery", - "description": "Assorted old machinery. You could scavenge it for parts.", - "symbol": "&", - "color": "brown", - "move_cost": 4, - "coverage": 55, - "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "FLAMMABLE", "PLACE_ITEM" ], - "deconstruct": { - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": 1 }, - { "item": "pipe", "count": [ 1, 2 ] }, - { "item": "chain", "prob": 40 }, - { "item": "cu_pipe", "prob": 60 }, - { "item": "scrap", "count": [ 1, 3 ] }, - { "item": "hose", "count": 1 }, - { "item": "steel_chunk", "count": [ 1, 3 ] }, - { "item": "bearing", "charges": [ 1, 5 ] }, - { "item": "frame", "prob": 30 }, - { "item": "motor", "prob": 30 }, - { "item": "splinter", "count": 3, "prob": 30 }, - { "item": "2x4", "count": [ 1, 4 ] }, - { "item": "nail", "charges": [ 3, 10 ] } - ] - }, - "bash": { - "str_min": 10, - "str_max": 80, - "sound": "clang!", - "sound_fail": "ting.", - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": 1 }, - { "item": "pipe", "count": [ 1, 2 ] }, - { "item": "chain", "prob": 20 }, - { "item": "cu_pipe", "prob": 10 }, - { "item": "scrap", "count": [ 1, 5 ] }, - { "item": "steel_chunk", "count": [ 1, 2 ] }, - { "item": "motor", "prob": 10 }, - { "item": "splinter", "count": [ 4, 8 ] }, - { "item": "2x4", "count": 2 }, - { "item": "nail", "charges": [ 2, 5 ] } - ] - } - }, - { - "type": "terrain", - "id": "t_machinery_electronic", - "name": "electronic machinery", - "description": "Assorted electronic machinery. You could scavenge it for parts.", - "symbol": "$", - "color": "yellow", - "move_cost": 8, - "coverage": 55, - "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "SEALED", "FLAMMABLE", "PLACE_ITEM" ], - "deconstruct": { - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "count": [ 1, 3 ] }, - { "item": "pipe", "count": [ 1, 2 ] }, - { "item": "steel_chunk", "count": [ 1, 4 ] }, - { "item": "bearing", "charges": [ 2, 6 ] }, - { "item": "motor", "prob": 40 }, - { "item": "processor", "count": 1 }, - { "item": "RAM", "count": [ 1, 4 ] }, - { "item": "cable", "charges": [ 1, 4 ] }, - { "item": "small_lcd_screen", "count": 1 }, - { "item": "e_scrap", "count": [ 5, 10 ] }, - { "item": "circuit", "count": [ 3, 8 ] }, - { "item": "power_supply", "count": [ 1, 3 ] }, - { "item": "amplifier", "count": [ 1, 3 ] }, - { "item": "plastic_chunk", "count": [ 2, 8 ] }, - { "item": "scrap", "count": [ 1, 5 ] } - ] - }, - "bash": { - "str_min": 10, - "str_max": 80, - "sound": "clang!", - "sound_fail": "ting.", - "ter_set": "t_rock_floor", - "items": [ - { "item": "wire", "prob": 40 }, - { "item": "pipe", "prob": 40 }, - { "item": "steel_chunk", "prob": 40 }, - { "item": "bearing", "charges": [ 2, 4 ] }, - { "item": "motor", "prob": 10 }, - { "item": "processor", "prob": 40 }, - { "item": "RAM", "count": [ 1, 2 ] }, - { "item": "cable", "charges": [ 1, 2 ] }, - { "item": "small_lcd_screen", "prob": 40 }, - { "item": "e_scrap", "count": [ 3, 8 ] }, - { "item": "circuit", "count": [ 1, 3 ] }, - { "item": "power_supply", "prob": 40 }, - { "item": "amplifier", "prob": 40 }, - { "item": "plastic_chunk", "count": [ 2, 8 ] }, - { "item": "scrap", "count": [ 3, 8 ] } - ] - } - }, { "id": "t_milking_machine", "type": "terrain", diff --git a/data/json/furniture_and_terrain/terrain-mechanisms.json b/data/json/furniture_and_terrain/terrain-mechanisms.json index 8b8f350a6fc14..fee4d9657cf33 100644 --- a/data/json/furniture_and_terrain/terrain-mechanisms.json +++ b/data/json/furniture_and_terrain/terrain-mechanisms.json @@ -1,97 +1,4 @@ [ - { - "type": "terrain", - "id": "t_console_broken", - "name": "broken console", - "description": "This is a standalone computer terminal. It doesn't seem to be working. It's the broken screen and shattered circuit boards that's telling you that.", - "symbol": "6", - "color": "light_gray", - "move_cost": 0, - "coverage": 50, - "roof": "t_flat_roof", - "flags": [ "TRANSPARENT", "NOITEM", "INDOORS", "SHORT", "PERMEABLE" ], - "deconstruct": { - "ter_set": "t_floor", - "items": [ - { "item": "processor", "count": [ 1, 2 ] }, - { "item": "RAM", "count": [ 4, 8 ] }, - { "item": "cable", "charges": [ 4, 6 ] }, - { "item": "large_lcd_screen", "count": 1 }, - { "item": "e_scrap", "count": [ 10, 16 ] }, - { "item": "circuit", "count": [ 6, 10 ] }, - { "item": "power_supply", "count": [ 2, 4 ] }, - { "item": "amplifier", "count": [ 2, 4 ] }, - { "item": "plastic_chunk", "count": [ 10, 12 ] }, - { "item": "scrap", "count": [ 6, 8 ] } - ] - }, - "bash": { - "str_min": 16, - "str_max": 150, - "sound": "crunch!", - "sound_fail": "whack!", - "ter_set": "t_floor", - "items": [ - { "item": "processor", "prob": 25 }, - { "item": "RAM", "count": [ 0, 2 ], "prob": 50 }, - { "item": "cable", "charges": [ 1, 2 ], "prob": 50 }, - { "item": "large_lcd_screen", "prob": 25 }, - { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, - { "item": "circuit", "count": [ 0, 2 ], "prob": 50 }, - { "item": "power_supply", "prob": 25 }, - { "item": "amplifier", "prob": 25 }, - { "item": "plastic_chunk", "count": [ 4, 10 ], "prob": 50 }, - { "item": "scrap", "count": [ 2, 6 ], "prob": 50 } - ] - } - }, - { - "type": "terrain", - "id": "t_console", - "name": "computer console", - "description": "This is a standalone computer terminal. It can be used to view contents and perform any allowed functions. It might even be possible to hack it, given the skills.", - "symbol": "6", - "color": "blue", - "move_cost": 0, - "coverage": 50, - "light_emitted": 10, - "roof": "t_flat_roof", - "flags": [ "TRANSPARENT", "CONSOLE", "NOITEM", "INDOORS", "SHORT", "PERMEABLE" ], - "deconstruct": { - "ter_set": "t_floor", - "items": [ - { "item": "processor", "count": [ 1, 2 ] }, - { "item": "RAM", "count": [ 4, 8 ] }, - { "item": "cable", "charges": [ 4, 6 ] }, - { "item": "large_lcd_screen", "count": 1 }, - { "item": "e_scrap", "count": [ 10, 16 ] }, - { "item": "circuit", "count": [ 6, 10 ] }, - { "item": "power_supply", "count": [ 2, 4 ] }, - { "item": "amplifier", "count": [ 2, 4 ] }, - { "item": "plastic_chunk", "count": [ 10, 12 ] }, - { "item": "scrap", "count": [ 6, 8 ] } - ] - }, - "bash": { - "str_min": 8, - "str_max": 150, - "sound": "crunch!", - "sound_fail": "whack!", - "ter_set": "t_console_broken", - "items": [ - { "item": "processor", "prob": 25 }, - { "item": "RAM", "count": [ 0, 2 ], "prob": 50 }, - { "item": "cable", "charges": [ 1, 2 ], "prob": 50 }, - { "item": "large_lcd_screen", "prob": 25 }, - { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, - { "item": "circuit", "count": [ 0, 2 ], "prob": 50 }, - { "item": "power_supply", "prob": 25 }, - { "item": "amplifier", "prob": 25 }, - { "item": "plastic_chunk", "count": [ 4, 10 ], "prob": 50 }, - { "item": "scrap", "count": [ 2, 6 ], "prob": 50 } - ] - } - }, { "type": "terrain", "id": "t_gates_mech_control", diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 78806eabccd06..85b99df7262e5 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -39,6 +39,7 @@ "type": "terrain", "id": "t_wall_half", "name": "half-built wall", + "looks_like": "t_wall", "description": "An incomplete wall of refined wood, dotted with carefully placed nails to provide proper support. It requires some more two by fours and nails before it'd be considered a suitable wall.", "symbol": "#", "color": "light_red", @@ -98,6 +99,7 @@ "type": "terrain", "id": "t_wall_r", "alias": [ "t_wall_h_r", "t_wall_v_r" ], + "looks_like": "t_wall", "name": "red wall", "description": "Wall painted red.", "symbol": "LINE_OXOX", @@ -119,6 +121,7 @@ "type": "terrain", "id": "t_wall_w", "alias": [ "t_wall_h_w", "t_wall_v_w" ], + "looks_like": "t_wall", "name": "white wall", "description": "Wall painted white.", "symbol": "LINE_OXOX", @@ -140,6 +143,7 @@ "type": "terrain", "id": "t_wall_b", "alias": [ "t_wall_h_b", "t_wall_v_b" ], + "looks_like": "t_wall", "name": "blue wall", "description": "Wall painted blue.", "symbol": "LINE_OXOX", @@ -161,6 +165,7 @@ "type": "terrain", "id": "t_wall_g", "alias": [ "t_wall_h_g", "t_wall_v_g" ], + "looks_like": "t_wall", "name": "green wall", "description": "Wall painted green.", "symbol": "LINE_OXOX", @@ -182,6 +187,7 @@ "type": "terrain", "id": "t_wall_y", "alias": [ "t_wall_h_y", "t_wall_v_y" ], + "looks_like": "t_wall", "name": "yellow wall", "description": "Wall painted yellow.", "symbol": "LINE_OXOX", @@ -203,6 +209,7 @@ "type": "terrain", "id": "t_wall_P", "alias": [ "t_wall_h_P", "t_wall_v_P" ], + "looks_like": "t_wall", "name": "pink wall", "description": "Wall painted pink.", "symbol": "LINE_OXOX", @@ -223,6 +230,7 @@ "type": "terrain", "id": "t_wall_p", "alias": [ "t_wall_h_p", "t_wall_v_p" ], + "looks_like": "t_wall", "name": "purple wall", "description": "Wall painted purple.", "symbol": "LINE_OXOX", @@ -243,6 +251,7 @@ { "type": "terrain", "id": "t_brick_wall_halfway", + "looks_like": "t_brick_wall", "name": "half-built brick wall", "description": "Half of a brick wall, looks like it still requires some more resources and effort before being considered a real wall.", "symbol": "#", @@ -284,6 +293,7 @@ "type": "terrain", "id": "t_rock_wall", "name": "stone wall", + "looks_like": "t_rock", "description": "A sturdy stone wall.", "symbol": "LINE_OXOX", "color": "light_gray", @@ -304,6 +314,7 @@ { "type": "terrain", "id": "t_rock_wall_half", + "looks_like": "t_rock_wall", "name": "half-built stone wall", "description": "Half of a sturdy stone wall. Some work still needs to be done before this stone wall is complete.", "symbol": "#", @@ -325,6 +336,7 @@ "type": "terrain", "id": "t_rock_smooth", "name": "smoothed rock", + "looks_like": "t_rock", "description": "A block of stone that's been smoothed and shaped, commonly granite or marble for funerary chapels and mausoleums.", "symbol": "LINE_OXOX", "//": "use pillars, 't_column', as a compliment.", @@ -389,6 +401,7 @@ "id": "t_concrete_wall", "alias": [ "t_concrete_h", "t_concrete_v" ], "name": "concrete wall", + "looks_like": "t_rock", "description": "An aesthetically pleasing design with simple lines, this type of concrete was used with a weaker chemical mixture in order to have faster setting times. Not ideal for multi-story buildings, but still capable of supporting a roof.", "symbol": "LINE_OXOX", "color": "dark_gray", @@ -434,6 +447,7 @@ "type": "terrain", "id": "t_sconc_wall", "name": "simple concrete wall", + "looks_like": "t_concrete_wall", "description": "A durable and uniform concrete wall, quite drab without decoration. More than capable of supporting a roof, as well as keeping out most anything, save for vehicles.", "symbol": "LINE_OXOX", "color": "light_gray", @@ -455,6 +469,7 @@ "type": "terrain", "id": "t_sconc_wall_halfway", "name": "half-built simple concrete wall", + "looks_like": "t_sconc_wall", "description": "A partially poured concrete wall that could probably keep anything behind it quite safe if it were finished.", "symbol": "*", "color": "light_gray", @@ -475,6 +490,7 @@ "type": "terrain", "id": "t_strconc_wall", "name": "reinforced concrete wall", + "looks_like": "t_concrete_wall", "description": "An extremely resilient wall, filled with concrete and rebar. Best suited for supporting multi-level buildings, only serious explosives and high-speed impacts would be capable of damaging this wall.", "symbol": "LINE_OXOX", "color": "light_gray", @@ -496,6 +512,7 @@ "type": "terrain", "id": "t_strconc_wall_halfway", "name": "half-built reinforced concrete wall", + "looks_like": "t_sconc_wall_halfway", "description": "Poured concrete with methodically placed rebar sticking out, which isn't practical for supporting roofs or shelter. It appears to need more resources before being considered complete.", "symbol": "*", "color": "light_gray", @@ -535,6 +552,7 @@ "type": "terrain", "id": "t_scrap_wall", "name": "simple metal wall", + "looks_like": "t_metal_wall", "description": "A relatively simple wall made of scraped together metal. It's still capable of blocking intruders and supporting a roof with adjacent walls.", "symbol": "LINE_OXOX", "color": "dark_gray", @@ -556,6 +574,7 @@ "type": "terrain", "id": "t_scrap_wall_halfway", "name": "half-built simple metal wall", + "looks_like": "t_scrap_wall", "description": "A partially built makeshift wall of metal that could potentially support a roof if it were completed.", "symbol": "#", "color": "dark_gray", @@ -575,6 +594,7 @@ "type": "terrain", "id": "t_wall_wood", "name": "wooden wall", + "looks_like": "t_wall", "description": "A finished wall of planks and support beams, capable of supporting an upper level or roof. Still highly flammable.", "symbol": "LINE_OXOX", "color": "light_red", @@ -601,6 +621,7 @@ "type": "terrain", "id": "t_wall_wood_chipped", "name": "chipped wood wall", + "looks_like": "t_wall_wood", "description": "A wall of aligned two by fours that's starting to crack and break open. Some cut wood and a number of nails could patch this up quick.", "symbol": "LINE_OXOX", "color": "light_red", @@ -626,6 +647,7 @@ "type": "terrain", "id": "t_wall_wood_broken", "name": "broken wood wall", + "looks_like": "t_wall_wood_chipped", "description": "A number of planks are missing and the structure is beginning to sag and fall apart. It's going to need quite a bit of work to repair this wall.", "symbol": "&", "color": "light_red", @@ -650,6 +672,7 @@ "type": "terrain", "id": "t_wall_log_half", "name": "half-built log wall", + "looks_like": "t_wall_log", "description": "A half-constructed wall of notched logs that interlock to provide stability. Needs a few more logs to hold up a roof. Looks flammable.", "symbol": "#", "color": "brown", @@ -670,6 +693,7 @@ "type": "terrain", "id": "t_wall_log", "name": "log wall", + "looks_like": "t_wall_wood", "description": "A tall wall of timber suitable for housing and insulating from the weather. Quite flammable.", "symbol": "LINE_OXOX", "color": "brown", @@ -691,6 +715,7 @@ "type": "terrain", "id": "t_wall_log_chipped", "name": "chipped log wall", + "looks_like": "t_wall_log", "description": "A moderately damaged wall, could probably be patched up with some planks and nails.", "symbol": "LINE_OXOX", "color": "brown", @@ -711,6 +736,7 @@ "type": "terrain", "id": "t_wall_log_broken", "name": "broken log wall", + "looks_like": "t_wall_log_chipped", "description": "A destroyed wood wall, with only a supporting log left, ready to collapse. Looks repairable if the damage was replaced and patched together with nails and planks.", "symbol": "&", "color": "brown", @@ -729,6 +755,7 @@ "type": "terrain", "id": "t_palisade", "name": "palisade wall", + "looks_like": "t_wall_log", "description": "An age-old type of fortification consisting of hefty lumber staked into the ground and cabled together.", "symbol": "#", "color": "brown", @@ -748,6 +775,7 @@ "id": "t_wall_wattle", "type": "terrain", "name": "wattle-and-daub wall", + "looks_like": "t_wall_wood", "description": "A relatively primitive wall made by daubing together a lattice of wooden strips using some combination of wet soil, clay, sand, animal dung and straw.", "symbol": "LINE_OXOX", "color": "light_red", @@ -768,6 +796,7 @@ "id": "t_wall_wattle_broken", "type": "terrain", "name": "broken wattle-and-daub wall", + "looks_like": "t_wall_wattle", "description": "This wattle-and-daub wall section has been destroyed, leaving mostly just frame, and is barely held together.", "symbol": "&", "color": "light_red", @@ -786,6 +815,7 @@ "id": "t_wall_wattle_half", "type": "terrain", "name": "half-built wattle-and-daub wall", + "looks_like": "t_wall_wattle", "description": "This wattle-and-daub wall has some of the wooden strip lattice in place, and still requires the rest of the lattice and supporting wet compound to be filled in.", "symbol": "#", "color": "light_red", @@ -831,6 +861,7 @@ "type": "terrain", "id": "t_wall_rammed_earth", "name": "rammed earth wall", + "looks_like": "t_rock", "description": "A solid wall of compressed dirt, sturdy enough to support a roof with enough walls and keep out some unwanted visitors.", "symbol": "LINE_OXOX", "color": "brown", @@ -873,6 +904,7 @@ "id": "t_wall_glass", "alias": [ "t_wall_glass_h", "t_wall_glass_v" ], "name": "glass wall", + "looks_like": "t_window", "description": "A barrier made of glass, it's nothing complicated, and looks extremely fragile. Some contain glass break sensors or window sensors that trigger if the glass is tampered.", "symbol": "LINE_OXOX", "color": "light_cyan", @@ -986,6 +1018,7 @@ "type": "terrain", "id": "t_reinforced_glass_shutter", "name": "reinforced glass with closed shutters", + "looks_like": "t_wall_metal", "description": "A secondary layer of protection over reinforced glass, these metal shutters are typically used to ward off criminals or protect against damage from extreme weather. Looks like it can only be opened from the inside. Even with the installed shutters, it isn't feasible in supporting a roof.", "symbol": "LINE_OXOX", "color": "light_gray", @@ -1082,6 +1115,7 @@ "type": "terrain", "id": "t_root_wall", "name": "root wall", + "looks_like": "t_rock", "description": "A dirt wall covered with roots.", "symbol": "#", "color": "brown", @@ -1150,6 +1184,7 @@ "type": "terrain", "id": "t_rock_red", "name": "red stone", + "looks_like": "t_rock", "description": "A red stone.", "symbol": "#", "color": "red", @@ -1169,6 +1204,7 @@ "type": "terrain", "id": "t_rock_green", "name": "green stone", + "looks_like": "t_rock", "description": "A green stone.", "symbol": "#", "color": "green", @@ -1188,6 +1224,7 @@ "type": "terrain", "id": "t_rock_blue", "name": "blue stone", + "looks_like": "t_rock", "description": "A blue stone.", "symbol": "#", "color": "blue", @@ -1227,6 +1264,7 @@ "type": "terrain", "id": "t_column_halfway", "name": "half-built column", + "looks_like": "t_column", "description": "An empty wooden frame in the shape of a column, built around a concrete and rebar foundation. It isn't capable of supporting roofs or shelter, and appears to need more resources before being considered complete.", "symbol": "*", "color": "light_gray", @@ -1246,6 +1284,7 @@ "type": "terrain", "id": "t_column", "name": "column", + "looks_like": "t_rock_wall", "description": "A concrete column.", "symbol": "1", "color": "light_gray", @@ -1265,6 +1304,7 @@ "type": "terrain", "id": "t_support_l", "name": "large metal support", + "looks_like": "t_wall_metal", "description": "A heavy-duty metal support beam.", "symbol": "T", "color": "light_gray", @@ -1298,6 +1338,7 @@ "type": "terrain", "id": "t_support_s", "name": "small metal support", + "looks_like": "t_support_l", "description": "A metal support beam.", "symbol": "l", "color": "light_gray", @@ -1331,6 +1372,7 @@ "type": "terrain", "id": "t_drystone_wall", "name": "field stone wall", + "looks_like": "t_rock_wall", "description": "A sturdy dry stone wall. Just rocks fitted together without mortar.", "symbol": "LINE_OXOX", "color": "light_gray", @@ -1351,6 +1393,7 @@ { "type": "terrain", "id": "t_drystone_wall_half", + "looks_like": "t_rock_wall_half", "name": "field stone half-wall", "description": "A half height sturdy dry stone wall. Just rocks fitted together without mortar. Complete as is or with extensive work it could be doubled in height.", "symbol": "#", diff --git a/data/json/furniture_and_terrain/terrain-zlevel-transitions.json b/data/json/furniture_and_terrain/terrain-zlevel-transitions.json index eee796b62309c..e5898ac8f49eb 100644 --- a/data/json/furniture_and_terrain/terrain-zlevel-transitions.json +++ b/data/json/furniture_and_terrain/terrain-zlevel-transitions.json @@ -165,6 +165,86 @@ "move_cost": 2, "flags": [ "TRANSPARENT", "GOES_DOWN", "PLACE_ITEM", "DIFFICULT_Z" ] }, + { + "type": "terrain", + "id": "t_ramp_down_high", + "name": "road ramp down (high end)", + "description": "The upper end of an asphalt ramp leading down.", + "symbol": ">", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "ROAD", "Z_TRANSPARENT" ] + }, + { + "type": "terrain", + "id": "t_ramp_down_low", + "name": "road ramp down (low end)", + "description": "The lower end of an asphalt ramp leading down.", + "symbol": ">", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "ROAD", "RAMP_DOWN", "Z_TRANSPARENT" ] + }, + { + "type": "terrain", + "id": "t_ramp_up_high", + "name": "road ramp up (high end)", + "description": "The upper end of an asphalt ramp leading up.", + "symbol": "<", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "ROAD", "RAMP_UP" ] + }, + { + "type": "terrain", + "id": "t_ramp_up_low", + "name": "road ramp up (low end)", + "description": "The lower end of an asphalt ramp leading up.", + "symbol": "<", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "ROAD" ] + }, + { + "type": "terrain", + "id": "t_sidewalk_ramp_down_high", + "name": "sidewalk ramp down (high end)", + "description": "The upper end of a sidewalk ramp leading down.", + "symbol": ">", + "color": "light_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "ROAD", "Z_TRANSPARENT" ] + }, + { + "type": "terrain", + "id": "t_sidewalk_ramp_down_low", + "name": "sidewalk ramp down (low end)", + "description": "The lower end of a sidewalk ramp leading down.", + "symbol": ">", + "color": "light_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "ROAD", "RAMP_DOWN", "Z_TRANSPARENT" ] + }, + { + "type": "terrain", + "id": "t_sidewalk_ramp_up_high", + "name": "sidewalk ramp up (high end)", + "description": "The upper end of a sidewalk ramp leading up.", + "symbol": "<", + "color": "light_gray", + "move_cost": 2, + "flags": [ "ROAD", "RAMP_UP" ] + }, + { + "type": "terrain", + "id": "t_sidewalk_ramp_up_low", + "name": "sidewalk ramp up (low end)", + "description": "The lower end of a sidewalk ramp leading up.", + "symbol": "<", + "color": "light_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "ROAD" ] + }, { "type": "terrain", "id": "t_slope_down", diff --git a/data/json/itemgroups/Clothing_Gear/hazmat_gear.json b/data/json/itemgroups/Clothing_Gear/hazmat_gear.json new file mode 100644 index 0000000000000..19774d32b373c --- /dev/null +++ b/data/json/itemgroups/Clothing_Gear/hazmat_gear.json @@ -0,0 +1,16 @@ +[ + { + "id": "decontamination_room", + "type": "item_group", + "subtype": "collection", + "entries": [ + { "item": "hazmat_suit", "prob": 60 }, + { "item": "mask_gas", "prob": 60 }, + { "item": "gasfilter_m", "prob": 60 }, + { "item": "rad_monitor", "prob": 33 }, + { "item": "iodine", "prob": 33 }, + { "item": "1st_aid", "prob": 15 }, + { "item": "geiger_off", "prob": 15 } + ] + } +] diff --git a/data/json/itemgroups/Drugs_Tobacco_Alcohol/drugs.json b/data/json/itemgroups/Drugs_Tobacco_Alcohol/drugs.json index dc36a2b0cb48f..32ca1ed8875bd 100644 --- a/data/json/itemgroups/Drugs_Tobacco_Alcohol/drugs.json +++ b/data/json/itemgroups/Drugs_Tobacco_Alcohol/drugs.json @@ -12,7 +12,8 @@ "items": [ [ "1st_aid", 5 ], [ "aspirin", 50 ], - [ "bandages", 50 ], + [ "bandages", 30 ], + [ "adhesive_bandages", 30 ], [ "cotton_ball", 40 ], [ "disinfectant", 30 ], [ "eyedrops", 10 ], @@ -27,7 +28,7 @@ "id": "drugs_emergency", "type": "item_group", "//": "Medical consumables for emergency use excluduing painkillers", - "items": [ [ "adrenaline_injector", 50 ], [ "inhaler", 100 ], [ "quikclot", 50 ], [ "smoxygen_tank", 70 ] ] + "items": [ [ "adrenaline_injector", 50 ], [ "inhaler", 100 ], [ "quikclot", 50 ], [ "smoxygen_tank", 70 ], [ "ifak", 40 ] ] }, { "id": "drugs_misc", @@ -71,7 +72,7 @@ "subtype": "distribution", "//": "Healing items appropriate for soldiers and other paramilitary forces", "entries": [ - { "item": "1st_aid", "prob": 50 }, + { "item": "ifak", "prob": 50 }, { "item": "antibiotics", "prob": 20 }, { "item": "bandages", "prob": 100 }, { "item": "morphine", "prob": 20 }, @@ -97,7 +98,8 @@ "type": "item_group", "id": "softdrugs", "items": [ - [ "bandages", 50 ], + [ "bandages", 30 ], + [ "adhesive_bandages", 30 ], [ "cotton_ball", 50 ], [ "1st_aid", 35 ], [ "saline", 25 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations.json b/data/json/itemgroups/Locations_MapExtras/locations.json index 917cdc8435894..2b9d4821172fe 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations.json +++ b/data/json/itemgroups/Locations_MapExtras/locations.json @@ -168,7 +168,8 @@ [ "iodine", 5 ], [ "prussian_blue", 5 ], { "item": "bleach", "prob": 20, "charges-min": 10 }, - [ "bandages", 50 ], + [ "bandages", 30 ], + [ "adhesive_bandages", 30 ], [ "cotton_ball", 50 ], [ "syringe", 8 ], [ "adrenaline_injector", 5 ], @@ -285,7 +286,8 @@ "entries": [ { "item": "aspirin", "prob": 50 }, { "item": "1st_aid", "prob": 40 }, - { "item": "bandages", "prob": 30 }, + { "item": "bandages", "prob": 15 }, + { "item": "adhesive_bandages", "prob": 15 }, { "item": "duct_tape", "prob": 20 }, { "item": "sewing_kit", "prob": 10 }, { "item": "mouthpiece", "prob": 10 }, @@ -1108,7 +1110,8 @@ "type": "item_group", "id": "methlab", "items": [ - [ "bandages", 50 ], + [ "bandages", 25 ], + [ "adhesive_bandages", 25 ], [ "cotton_ball", 50 ], [ "pan", 60 ], [ "coke", 10 ], @@ -2153,8 +2156,10 @@ [ "coffee_raw", 15 ], [ "cheese_hard", 5 ], [ "bandages", 50 ], + [ "adhesive_bandages", 50 ], [ "cotton_ball", 50 ], [ "1st_aid", 35 ], + [ "ifak", 35 ], [ "survival_kit", 35 ], [ "premium_survival_kit", 8 ], [ "saline", 10 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json index 72f83068e3fac..978634fba5b7b 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json @@ -1711,7 +1711,8 @@ "//": "for veterinarian", "type": "item_group", "items": [ - [ "bandages", 50 ], + [ "bandages", 30 ], + [ "adhesive_bandages", 30 ], [ "1st_aid", 10 ], [ "saline", 20 ], [ "vitamins", 15 ], @@ -1825,7 +1826,7 @@ [ "shorts", 30 ], [ "coke", 3 ], [ "longshirt", 30 ], - [ "bandages", 10 ], + [ "adhesive_bandages", 10 ], [ "heatpack", 10 ], [ "gum", 12 ], [ "soap", 10 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json index 659b5e9373e3f..0409096ce32a2 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json @@ -17,7 +17,8 @@ [ "bum_wine", 10 ], [ "chem_ethanol", 12 ], { "group": "salty_snacks", "prob": 135 }, - [ "bandages", 50 ], + [ "bandages", 25 ], + [ "adhesive_bandages", 25 ], [ "cotton_ball", 50 ], [ "caffeine", 25 ], [ "oxycodone", 7 ], diff --git a/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json b/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json index 6edd1a04cdf29..2d66d35efe772 100644 --- a/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json +++ b/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json @@ -68,8 +68,9 @@ "id": "vitamin_shop", "type": "item_group", "items": [ - [ "bandages", 25 ], - [ "1st_aid", 20 ], + [ "adhesive_bandages", 25 ], + [ "1st_aid", 15 ], + [ "ifak", 15 ], [ "vitamins", 75 ], [ "calcium_tablet", 75 ], [ "aspirin", 45 ], diff --git a/data/json/itemgroups/Locations_MapExtras/mansion.json b/data/json/itemgroups/Locations_MapExtras/mansion.json index a19a757a66a30..ce1f3ebd42f00 100644 --- a/data/json/itemgroups/Locations_MapExtras/mansion.json +++ b/data/json/itemgroups/Locations_MapExtras/mansion.json @@ -690,7 +690,7 @@ "id": "bath_linens", "type": "item_group", "subtype": "distribution", - "items": [ [ "sheet", 40 ], [ "towel", 30 ], [ "rag", 20 ], [ "bandages", 10 ] ] + "items": [ [ "sheet", 40 ], [ "towel", 30 ], [ "rag", 20 ], [ "bandages", 5 ], [ "adhesive_bandages", 5 ] ] }, { "id": "creepy", @@ -1024,7 +1024,8 @@ [ "towel", 20 ], [ "protein_shake", 8 ], [ "coke", 3 ], - [ "bandages", 10 ], + [ "bandages", 5 ], + [ "adhesive_bandages", 5 ], [ "heatpack", 10 ], [ "gum", 12 ], [ "yoghurt", 12 ], @@ -1103,7 +1104,8 @@ [ "hoodie", 50 ], [ "shorts", 60 ], [ "longshirt", 60 ], - [ "bandages", 10 ], + [ "bandages", 5 ], + [ "adhesive_bandages", 5 ], [ "heatpack", 10 ], [ "gum", 12 ], [ "soap", 10 ], diff --git a/data/json/itemgroups/SUS/domestic.json b/data/json/itemgroups/SUS/domestic.json index d2827d3f4bca7..7ff493f5b08e4 100644 --- a/data/json/itemgroups/SUS/domestic.json +++ b/data/json/itemgroups/SUS/domestic.json @@ -740,7 +740,12 @@ "prob": 75 }, { - "distribution": [ { "item": "bandages", "prob": 60 }, { "item": "medical_gauze", "prob": 20 }, { "item": "1st_aid", "prob": 10 } ], + "distribution": [ + { "item": "adhesive_bandages", "prob": 40 }, + { "item": "bandages", "prob": 20 }, + { "item": "medical_gauze", "prob": 20 }, + { "item": "1st_aid", "prob": 10 } + ], "prob": 20 }, { "item": "disinfectant", "prob": 40, "charges-min": 1 }, diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index 6dc8b256c884e..442258abe872b 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -3,7 +3,8 @@ "type": "item_group", "id": "sports", "items": [ - [ "bandages", 50 ], + [ "bandages", 25 ], + [ "adhesive_bandages", 25 ], [ "cotton_ball", 50 ], [ "aspirin", 85 ], [ "bat", 60 ], diff --git a/data/json/itemgroups/military.json b/data/json/itemgroups/military.json index 6448782a295fe..2569db5a1b919 100644 --- a/data/json/itemgroups/military.json +++ b/data/json/itemgroups/military.json @@ -80,7 +80,7 @@ "id": "infantry_medical_gear", "subtype": "collection", "entries": [ - { "item": "1st_aid", "prob": 90 }, + { "item": "ifak", "prob": 90 }, { "item": "quikclot", "prob": 60 }, { "collection": [ { "item": "morphine" }, { "item": "syringe" } ], "prob": 30 } ] @@ -118,7 +118,8 @@ { "item": "water_clean", "prob": 90 }, { "item": "knuckle_brass", "prob": 15 }, { "item": "battery_ups", "prob": 10 }, - { "item": "bandages", "prob": 50 }, + { "item": "bandages", "prob": 30 }, + { "item": "adhesive_bandages", "prob": 20 }, { "item": "cotton_ball", "prob": 20 }, { "item": "iodine", "prob": 5 }, { "item": "prussian_blue", "prob": 5 }, @@ -296,6 +297,7 @@ { "item": "radio", "prob": 10, "charges-min": 10, "charges-max": 95 }, { "item": "boots_combat", "prob": 50 }, { "item": "bandages", "prob": 10, "charges-min": 1, "charges-max": 3 }, + { "item": "adhesive_bandages", "prob": 10, "charges-min": 1, "charges-max": 6 }, { "item": "cig", "prob": 60, "charges-min": 1, "charges-max": 20 }, { "item": "knife_combat", "prob": 30 }, { "item": "pockknife", "prob": 30 }, @@ -453,7 +455,7 @@ { "item": "neccowafers", "prob": 30 }, { "item": "can_beans", "prob": 40 }, { "item": "pork_beans", "prob": 40 }, - { "item": "1st_aid", "prob": 35 }, + { "item": "ifak", "prob": 35 }, { "item": "saline", "prob": 10 }, { "item": "con_milk", "prob": 10 }, { "item": "milk_UHT", "prob": 25 }, diff --git a/data/json/itemgroups/misc.json b/data/json/itemgroups/misc.json index 5254385ac1db4..c8f4b665db50c 100644 --- a/data/json/itemgroups/misc.json +++ b/data/json/itemgroups/misc.json @@ -133,7 +133,7 @@ { "item": "lighter", "charges": 100 }, { "item": "pockknife" }, { "item": "multitool" }, - { "item": "1st_aid" }, + { "item": "ifak" }, { "item": "rollmat" }, { "item": "sleeping_bag_roll" }, { "item": "ear_plugs" }, diff --git a/data/json/itemgroups/science_and_tech.json b/data/json/itemgroups/science_and_tech.json index 045a071109350..3b7b925a68b33 100644 --- a/data/json/itemgroups/science_and_tech.json +++ b/data/json/itemgroups/science_and_tech.json @@ -413,6 +413,7 @@ [ "prussian_blue", 5 ], [ "autoclave", 5 ], [ "bandages", 50 ], + [ "adhesive_bandages", 20 ], [ "cotton_ball", 50 ], [ "scalpel", 48 ], [ "syringe", 8 ], diff --git a/data/json/items/ammo.json b/data/json/items/ammo.json index a4f7924cc0974..c26e2276baed8 100644 --- a/data/json/items/ammo.json +++ b/data/json/items/ammo.json @@ -29,6 +29,7 @@ "weight": "1 mg", "color": "white", "flags": [ "TRADER_AVOID" ], + "phase": "liquid", "ammo_type": "butane" }, { diff --git a/data/json/items/ammo/10mm.json b/data/json/items/ammo/10mm.json index 0ed5e796e9cfe..4aea51b6f297b 100644 --- a/data/json/items/ammo/10mm.json +++ b/data/json/items/ammo/10mm.json @@ -5,7 +5,7 @@ "name": { "str": "10mm Auto FMJ" }, "description": "A jacketed 10mm Auto round. The 10mm Auto cartridge is a rather powerful handgun round and the progenitor to the more popular .40 S&W.", "weight": "9 g", - "volume": "250 ml", + "volume": "117 ml", "price": 400, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/20x66mm.json b/data/json/items/ammo/20x66mm.json index 3618f33b38f80..c46761a6132d1 100644 --- a/data/json/items/ammo/20x66mm.json +++ b/data/json/items/ammo/20x66mm.json @@ -117,7 +117,7 @@ "//": "2.5x the Generic Rate of $1/shot", "description": "20x66mm caseless shotgun rounds, buckshot type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "weight": "56 g", - "volume": "250 ml", + "volume": "415 ml", "price": 1500, "price_postapoc": 4000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/22.json b/data/json/items/ammo/22.json index fcbcda4300296..b0eb8be83634c 100644 --- a/data/json/items/ammo/22.json +++ b/data/json/items/ammo/22.json @@ -28,7 +28,7 @@ "name": { "str": ".22 LR" }, "description": ".22 Long Rifle ammunition with 40gr unjacketed bullets. The .22LR round is extremely weak with very low stopping power, short range, and negligible recoil. It is most useful for rifle training, and hunting small animals.", "weight": "3 g", - "volume": "250 ml", + "volume": "65 ml", "price": 150, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/223.json b/data/json/items/ammo/223.json index 0920cde8c0d42..34f66b290c308 100644 --- a/data/json/items/ammo/223.json +++ b/data/json/items/ammo/223.json @@ -5,7 +5,7 @@ "name": { "str": ".223 Remington" }, "description": ".223 Remington ammunition with 36gr JHP bullets. The .223 round has been very popular with civilian shooters for almost a century, finding use in a wide variety of weapons. It generates lower pressure than 5.56 NATO leading to slightly decreased accuracy and recoil.", "weight": "12 g", - "volume": "250 ml", + "volume": "194 ml", "price": 280, "price_postapoc": 900, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/270win.json b/data/json/items/ammo/270win.json index d9812da22a13a..c433098d960f5 100644 --- a/data/json/items/ammo/270win.json +++ b/data/json/items/ammo/270win.json @@ -5,7 +5,7 @@ "name": { "str": ".270 Winchester JSP" }, "description": ".270 Winchester ammunition with 130gr soft point bullets. The .270 round was not initially successful, but over a few decades it became one of the most popular rifle cartridges for hunting and silhouette shooting. It is a powerful round capable of taking down large targets with ease.", "weight": "20 g", - "volume": "250 ml", + "volume": "189 ml", "price": 170, "price_postapoc": 600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/300.json b/data/json/items/ammo/300.json index d0a05c6f90e9f..0e5455cbffbc7 100644 --- a/data/json/items/ammo/300.json +++ b/data/json/items/ammo/300.json @@ -5,7 +5,7 @@ "name": { "str": ".300 Winchester Magnum" }, "description": ".300 Winchester Magnum rounds with 220gr JHP bullets. The 300WM round is an extremely powerful and accurate rifle round introduced in 1963. It has proven popular with hunters and snipers, although it is not as common as .308 or .30-06.", "weight": "28 g", - "volume": "250 ml", + "volume": "169 ml", "price": 220, "price_postapoc": 400, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/3006.json b/data/json/items/ammo/3006.json index d4fd0091d45a9..eda24b798537f 100644 --- a/data/json/items/ammo/3006.json +++ b/data/json/items/ammo/3006.json @@ -5,7 +5,7 @@ "name": { "str": ".30-06 Springfield" }, "description": ".30-06 Springfield rounds with 165gr soft point bullets. The .30-06 cartridge has excellent accuracy, range, and stopping power making it popular with hunters and snipers for well over a century.", "weight": "20 g", - "volume": "250 ml", + "volume": "192 ml", "price": 160, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/300blk.json b/data/json/items/ammo/300blk.json index 1d1f2407bdbb1..171c1d3d5095b 100644 --- a/data/json/items/ammo/300blk.json +++ b/data/json/items/ammo/300blk.json @@ -5,7 +5,7 @@ "name": { "str": ".300 AAC Blackout" }, "description": "A .300 AAC Blackout round with a 125gr open tip match bullet. 300 BLK is an intermediate cartridge necked up from 5.56x45mm, designed to achieve similar ballistics to 7.62x39mm. It is compatible with standard AR-15 lower receivers and will feed from STANAG magazines.", "weight": "18 g", - "volume": "250 ml", + "volume": "194 ml", "price": 290, "price_postapoc": 1500, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/308.json b/data/json/items/ammo/308.json index 3691c8269a384..0924126081723 100644 --- a/data/json/items/ammo/308.json +++ b/data/json/items/ammo/308.json @@ -5,7 +5,7 @@ "name": { "str": ".308 Winchester" }, "description": ".308 Winchester ammunition with 168gr hollow point bullets. The .308 round is one of the most popular hunting cartridges in the world due to its accuracy and power.", "weight": "18 g", - "volume": "250 ml", + "volume": "158 ml", "price": 180, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/32.json b/data/json/items/ammo/32.json index df6067a0cadbe..0d153ce5795ba 100644 --- a/data/json/items/ammo/32.json +++ b/data/json/items/ammo/32.json @@ -5,7 +5,7 @@ "name": { "str": ".32 ACP" }, "description": "The .32 ACP was a popular handgun cartridge in the 20th century. Not so powerful as the .38 or the 9x19mm though.", "weight": "5 g", - "volume": "250 ml", + "volume": "116 ml", "price": 160, "price_postapoc": 1600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/357mag.json b/data/json/items/ammo/357mag.json index 74bfec49915a6..74218a588890e 100644 --- a/data/json/items/ammo/357mag.json +++ b/data/json/items/ammo/357mag.json @@ -5,7 +5,7 @@ "name": { "str": ".357 magnum FMJ" }, "description": "Jacketed .357 magnum ammunition. The .357 magnum round is derived from the earlier .38 special, with a marginally longer case and generating greater pressure.", "weight": "8 g", - "volume": "250 ml", + "volume": "145 ml", "price": 140, "price_postapoc": 1000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/357sig.json b/data/json/items/ammo/357sig.json index 095acfc0f7d9d..e1b15fc0fc059 100644 --- a/data/json/items/ammo/357sig.json +++ b/data/json/items/ammo/357sig.json @@ -5,7 +5,7 @@ "name": { "str": ".357 SIG FMJ" }, "description": "Jacketed .357 SIG ammunition. The .357 SIG round is a high velocity pistol cartridge, giving it a flatter trajectory than many handgun rounds.", "weight": "8 g", - "volume": "250 ml", + "volume": "132 ml", "price": 370, "price_postapoc": 1000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/36paper.json b/data/json/items/ammo/36paper.json index 407aa0d1e7fc3..d94448307ca25 100644 --- a/data/json/items/ammo/36paper.json +++ b/data/json/items/ammo/36paper.json @@ -5,7 +5,7 @@ "name": { "str": ".36 paper cartridge" }, "description": "A paper cartridge containing a premeasured amount of black powder and a .36 projectile. Used by the Colt M1861 Navy.", "weight": "6 g", - "volume": "250 ml", + "volume": "11 ml", "price": 400, "price_postapoc": 1000, "material": [ "paper", "powder", "lead" ], diff --git a/data/json/items/ammo/38.json b/data/json/items/ammo/38.json index 336f65bbafd6b..44adc85c0a9f1 100644 --- a/data/json/items/ammo/38.json +++ b/data/json/items/ammo/38.json @@ -13,7 +13,7 @@ "name": { "str": ".38 Special" }, "description": ".38 Special ammunition with 130gr FMJ bullets. The .38 Special round was extremely common among US police forces during the 20th century.", "weight": "8 g", - "volume": "250 ml", + "volume": "113 ml", "price": 210, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/380.json b/data/json/items/ammo/380.json index d7956141ecba3..333d1eb1db35b 100644 --- a/data/json/items/ammo/380.json +++ b/data/json/items/ammo/380.json @@ -5,7 +5,7 @@ "name": { "str": ".380 ACP FMJ" }, "description": ".380 ACP ammunition with a brass jacketed 95gr bullet. Popular in pocket pistols for over a century, it is often considered the weakest caliber to consider carrying. One should be careful not to chamber it in 9x18mm Makarov or 9x19mm firearms.", "weight": "6 g", - "volume": "250 ml", + "volume": "89 ml", "price": 140, "price_postapoc": 1000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/38super.json b/data/json/items/ammo/38super.json index f11b34e732653..8ac784d86148c 100644 --- a/data/json/items/ammo/38super.json +++ b/data/json/items/ammo/38super.json @@ -5,7 +5,7 @@ "name": { "str": ".38 Super FMJ" }, "description": ".38 Super ammunition with 147gr FMJ bullets. The .38 Super round was developed from .38 ACP in the 1920s, designed to penetrate the body armor of the era.", "weight": "8 g", - "volume": "250 ml", + "volume": "97 ml", "price": 210, "price_postapoc": 1200, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/40.json b/data/json/items/ammo/40.json index 8b8f0fcc914d1..540c66ecbbd15 100644 --- a/data/json/items/ammo/40.json +++ b/data/json/items/ammo/40.json @@ -13,7 +13,7 @@ "name": { "str": ".40 S&W JHP" }, "description": ".40 S&W ammunition with 135gr JHP bullets. The .40 S&W round is a descended from the 10mm Auto cartridge and maintains most of its predecessor's strengths while reducing recoil.", "weight": "9 g", - "volume": "250 ml", + "volume": "106 ml", "price": 220, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/410shot.json b/data/json/items/ammo/410shot.json index 757b9b403a3ef..f671fa68ef1bf 100644 --- a/data/json/items/ammo/410shot.json +++ b/data/json/items/ammo/410shot.json @@ -5,7 +5,7 @@ "name": { "str": ".410 000 shot" }, "description": "A .410 shell with 5 000 pellets. Good for a hunting or combat load.", "weight": "16 g", - "volume": "250 ml", + "volume": "170 ml", "price": 175, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/44.json b/data/json/items/ammo/44.json index 5fb3c5572891c..12a6dbdf19d47 100644 --- a/data/json/items/ammo/44.json +++ b/data/json/items/ammo/44.json @@ -13,7 +13,7 @@ "name": { "str": ".44 Magnum" }, "description": ".44 magnum ammunition with 240gr JHP bullets. The .44 magnum round is one of the most powerful handgun cartridges available. It has excellent stopping power but suffers from extremely high recoil for a handgun round.", "weight": "13 g", - "volume": "250 ml", + "volume": "87 ml", "price": 175, "price_postapoc": 600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/44paper.json b/data/json/items/ammo/44paper.json index 277fbb1fde8a7..4e8aac11438e2 100644 --- a/data/json/items/ammo/44paper.json +++ b/data/json/items/ammo/44paper.json @@ -5,7 +5,7 @@ "name": { "str": ".44 paper cartridge" }, "description": "A paper cartridge containing a premeasured amount of black powder and a .44 projectile. Used by the Colt M1860 Army.", "weight": "7 g", - "volume": "250 ml", + "volume": "20 ml", "price": 350, "price_postapoc": 1000, "material": [ "paper", "powder", "lead" ], diff --git a/data/json/items/ammo/45.json b/data/json/items/ammo/45.json index ad35f3146cb7b..efbc4137e9372 100644 --- a/data/json/items/ammo/45.json +++ b/data/json/items/ammo/45.json @@ -13,7 +13,7 @@ "name": { "str": ".45 ACP JHP" }, "description": ".45 ACP ammunition with 185gr JHP bullets. The .45 ACP round was developed to replace the .38 Long Colt cartridge in the early 20th century. It has good stopping power but above average recoil.", "weight": "10 g", - "volume": "250 ml", + "volume": "112 ml", "price": 180, "price_postapoc": 600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/454.json b/data/json/items/ammo/454.json index d46502dbd2c42..00fb52e2a7be5 100644 --- a/data/json/items/ammo/454.json +++ b/data/json/items/ammo/454.json @@ -5,7 +5,7 @@ "name": { "str": ".454 Casull" }, "description": ".454 Casull ammunition with 300gr jacketed soft point bullets. The .454 Casull round is derived from .45 Long Colt with a stronger, lengthened case. It is an exceptionally powerful cartridge with higher stopping power than many rifle rounds, although it suffers from extreme recoil making it unsuitable for most purposes.", "weight": "16 g", - "volume": "250 ml", + "volume": "79 ml", "price": 500, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/4570.json b/data/json/items/ammo/4570.json index 8ecb9882c0c68..5ebae6226c854 100644 --- a/data/json/items/ammo/4570.json +++ b/data/json/items/ammo/4570.json @@ -5,7 +5,7 @@ "name": { "str": ".45-70 SP" }, "description": ".45-70 Government ammunition loaded with a 305 grain soft point round. One of the oldest cartridges still in use, it is still a favorite for large game hunting at short ranges.", "weight": "35 g", - "volume": "250 ml", + "volume": "167 ml", "price": 125, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/45colt.json b/data/json/items/ammo/45colt.json index 2932999efae2a..bbdc072ca8cec 100644 --- a/data/json/items/ammo/45colt.json +++ b/data/json/items/ammo/45colt.json @@ -5,7 +5,7 @@ "name": { "str": ".45 Colt JHP" }, "description": ".45 Colt ammunition with 250gr jacketed hollow point bullets. Originally designed for the Colt Single Action Army, and still used for modern reproduction revolvers. Originally a black powder cartridge, modern loads can make this round competitive in the new era.", "weight": "12 g", - "volume": "250 ml", + "volume": "190 ml", "price": 200, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/46.json b/data/json/items/ammo/46.json index 37650e0ab4db3..b6e46642af770 100644 --- a/data/json/items/ammo/46.json +++ b/data/json/items/ammo/46.json @@ -5,7 +5,7 @@ "name": { "str": "4.6x30mm" }, "description": "4.6x30mm ammunition with 31gr copper plated steel bullets. The 4.6x30mm round was developed by H&K to compete with FN Herstal's 5.7x28mm cartridge. It has low recoil and excellent armor penetration.", "weight": "5 g", - "volume": "250 ml", + "volume": "156 ml", "price": 300, "price_postapoc": 1600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/50.json b/data/json/items/ammo/50.json index 0a0eff6245bd5..619f68301ff7a 100644 --- a/data/json/items/ammo/50.json +++ b/data/json/items/ammo/50.json @@ -15,7 +15,7 @@ "name": { "str": ".50 BMG M33 Ball" }, "description": ".50 BMG ammunition with mild steel cored 661gr FMJ bullets. The .50 BMG is a very powerful rifle round designed for anti-aircraft use, later adapted to anti-vehicular and anti-personnel roles. Its stupendous energy and armor piercing capabilities make it one of the most deadly rounds available, offset only by its drastic recoil and noise.", "weight": "114 g", - "volume": "250 ml", + "volume": "451 ml", "price": 2200, "price_postapoc": 2500, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/500.json b/data/json/items/ammo/500.json index 1f115ef4770c6..2deef17dabe57 100644 --- a/data/json/items/ammo/500.json +++ b/data/json/items/ammo/500.json @@ -5,7 +5,7 @@ "name": { "str": ".500 S&W Magnum" }, "description": ".500 S&W Magnum ammunition with 500gr bullets. The .500 S&W Magnum round is a colossally powerful handgun cartridge capable of killing almost any target with one hit. It has extremely high damage and recoil to match.", "weight": "15 g", - "volume": "250 ml", + "volume": "82 ml", "price": 200, "price_postapoc": 1000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/545x39.json b/data/json/items/ammo/545x39.json index 67b9e40515881..abcbb7940770d 100644 --- a/data/json/items/ammo/545x39.json +++ b/data/json/items/ammo/545x39.json @@ -6,7 +6,7 @@ "//": "Mainlined from Icecoon's Weapons Pack.", "description": "5.45x39mm 7N10 ammunition with 56gr FMJ bullets. The 5.45x39mm round was introduced along with the AK-74 in 1974. It has superior wounding potential to the older 7.62x39mm round and quickly replaced it in Soviet military use.", "weight": "10 g", - "volume": "250 ml", + "volume": "134 ml", "price": 100, "price_postapoc": 900, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/57.json b/data/json/items/ammo/57.json index 8213a2379c543..a6aac6c2c8490 100644 --- a/data/json/items/ammo/57.json +++ b/data/json/items/ammo/57.json @@ -5,7 +5,7 @@ "name": { "str": "5.7x28mm SS190" }, "description": "5.7x28mm ammunition with 31gr AP FMJ bullets. The 5.7x28mm cartridge was designed by FN Herstal to replace the 9x19mm round in NATO use. Although the project to replace 9x19mm Parabellum was effectively canceled the 5.7x28mm round has seen action in many conflicts and has proven to be reliable. It has very low recoil and its armor penetration is a defining feature.", "weight": "6 g", - "volume": "250 ml", + "volume": "121 ml", "price": 350, "price_postapoc": 1600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/5x50.json b/data/json/items/ammo/5x50.json index c1a285cb912a6..82811ce0a5228 100644 --- a/data/json/items/ammo/5x50.json +++ b/data/json/items/ammo/5x50.json @@ -5,7 +5,7 @@ "name": { "str": "RA110 5x50mm flechette" }, "description": "Designed to defeat modern body armor, the Rivtech 5x50mm flechette round features a biodegradable sabot and a single, fin-stabilized penetrator.", "weight": "8 g", - "volume": "250 ml", + "volume": "144 ml", "price": 1125, "material": [ "plastic", "powder", "steel" ], "symbol": "=", diff --git a/data/json/items/ammo/700nx.json b/data/json/items/ammo/700nx.json index 7eb5b7e653e6d..5655276b2a155 100644 --- a/data/json/items/ammo/700nx.json +++ b/data/json/items/ammo/700nx.json @@ -5,7 +5,7 @@ "name": { "str": ".700 NX" }, "description": "The .700 Nitro Express is a very powerful rifle round designed for long-range use. Its stupendous accuracy and armor piercing capabilities make it one of the most deadly rounds available, offset only by its drastic recoil and noise.", "weight": "80 g", - "volume": "250 ml", + "volume": "165 ml", "price": 5700, "price_postapoc": 2000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/762.json b/data/json/items/ammo/762.json index 7f770d227c134..8b974c3a8fee0 100644 --- a/data/json/items/ammo/762.json +++ b/data/json/items/ammo/762.json @@ -5,7 +5,7 @@ "name": { "str": "7.62x39mm 57-N-231" }, "description": "7.62x39mm 57-N-231 ammunition with 121.9gr steel core FMJ bullets. Developed in WW2 by the Soviet Union the 7.62x39mm round rapidly became extremely popular all over the world. The bullet has poor wounding potential due to its stability, only beginning to yaw after 26cm.", "weight": "16 g", - "volume": "250 ml", + "volume": "113 ml", "price": 120, "price_postapoc": 900, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/762R.json b/data/json/items/ammo/762R.json index 805a79dc09d58..dc61c187481c0 100644 --- a/data/json/items/ammo/762R.json +++ b/data/json/items/ammo/762R.json @@ -5,7 +5,7 @@ "name": { "str": "7.62x54mmR" }, "description": "7.62x54mmR ammunition with 150gr FMJ bullets. The 7.62x54mmR round is one of the oldest still in common use, primarily due to the popularity of the Mosin-Nagant rifle. Although it has not been used by militaries for several decades it remains popular with civilians. It is a powerful cartridge capable of killing most targets with one shot.", "weight": "18 g", - "volume": "250 ml", + "volume": "185 ml", "price": 200, "price_postapoc": 600, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/762x25.json b/data/json/items/ammo/762x25.json index b383f45be5e81..b710af263f010 100644 --- a/data/json/items/ammo/762x25.json +++ b/data/json/items/ammo/762x25.json @@ -5,7 +5,7 @@ "name": { "str": "7.62x25mm JHP" }, "description": "A commercial version of the 7.62x25mm cartridge created for the armed forces of Soviet Russia. It was derived from the 7.63x25mm cartridge used by the C96 pistol.", "weight": "10 g", - "volume": "250 ml", + "volume": "107 ml", "price": 100, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/8x40mm.json b/data/json/items/ammo/8x40mm.json index 25d9b16a37b46..ccc64636b94b3 100644 --- a/data/json/items/ammo/8x40mm.json +++ b/data/json/items/ammo/8x40mm.json @@ -16,7 +16,7 @@ "//": "Cased ammo tends to be roughly $1/shot, more or less. Rivtech ammo, being New and Proprietary and Expensive, $2-2.50 or so.", "description": "8x40mm caseless rounds. Proprietary ammunition for Rivtech firearms. Being caseless rounds, these cannot be disassembled or reloaded.", "weight": "12 g", - "volume": "250 ml", + "volume": "230 ml", "price": 225, "price_postapoc": 8000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/9mm.json b/data/json/items/ammo/9mm.json index f429d6ac5a2e5..a3d86fd9a0bd7 100644 --- a/data/json/items/ammo/9mm.json +++ b/data/json/items/ammo/9mm.json @@ -5,7 +5,7 @@ "name": { "str": "9x19mm JHP" }, "description": "9x19mm ammunition with a 116gr jacketed hollow point bullet. JHP rounds have inferior penetration to FMJ rounds but their expansion slightly increases stopping power against unarmored targets and reduces overpenetration.", "weight": "7 g", - "volume": "250 ml", + "volume": "115 ml", "price": 150, "price_postapoc": 1000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/9x18.json b/data/json/items/ammo/9x18.json index 92485acef56ba..345dd5966bc7e 100644 --- a/data/json/items/ammo/9x18.json +++ b/data/json/items/ammo/9x18.json @@ -5,7 +5,7 @@ "name": { "str": "9x18mm 57-N-181S" }, "description": "9x18mm Makarov ammunition with 93gr steel core FMJ bullets. The 9x18mm round was very common in the Eastern Bloc during the 20th century and remained in Russian military service into the 21st century.", "weight": "8 g", - "volume": "250 ml", + "volume": "97 ml", "price": 100, "price_postapoc": 1000, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/flintlock.json b/data/json/items/ammo/flintlock.json index f7fc54e73daac..11e39af83f301 100644 --- a/data/json/items/ammo/flintlock.json +++ b/data/json/items/ammo/flintlock.json @@ -5,7 +5,7 @@ "name": { "str": "paper cartridge" }, "description": "A paper cartridge containing black powder and a metallic projectile. Historically used to reload muzzleloaders in a more reasonable time.", "weight": "40 g", - "volume": "250 ml", + "volume": "10 ml", "price": 1100, "price_postapoc": 1200, "material": [ "lead", "powder" ], @@ -27,7 +27,7 @@ "name": { "str": "paper shot cartridge" }, "description": "A paper cartridge containing black powder and metallic shot. Historically used to reload muzzleloaders in a more reasonable time.", "weight": "40 g", - "volume": "250 ml", + "volume": "10 ml", "price": 1100, "price_postapoc": 1200, "material": [ "lead", "powder" ], diff --git a/data/json/items/ammo/shot.json b/data/json/items/ammo/shot.json index 49b5723185fec..88544919ee865 100644 --- a/data/json/items/ammo/shot.json +++ b/data/json/items/ammo/shot.json @@ -94,7 +94,7 @@ "name": { "str": "00 shot" }, "description": "A shell filled with metal pellets. Extremely damaging, plus the spread makes it very accurate at short range. Favored by SWAT forces.", "weight": "32 g", - "volume": "250 ml", + "volume": "439 ml", "price": 500, "price_postapoc": 800, "flags": [ "IRREPLACEABLE_CONSUMABLE" ], diff --git a/data/json/items/ammo/signal_flare.json b/data/json/items/ammo/signal_flare.json index df4e447f95f66..c346a97e0199b 100644 --- a/data/json/items/ammo/signal_flare.json +++ b/data/json/items/ammo/signal_flare.json @@ -5,7 +5,7 @@ "name": { "str": "signal flare" }, "description": "A heavy plastic cartridge made for use in flare guns. It appears to be a modified 12 gauge shotgun shell.", "weight": "32 g", - "volume": "250 ml", + "volume": "377 ml", "price": 500, "price_postapoc": 500, "material": [ "plastic", "powder" ], diff --git a/data/json/items/armor/bandolier.json b/data/json/items/armor/bandolier.json index 808131da8664d..98bb2f86fafa3 100644 --- a/data/json/items/armor/bandolier.json +++ b/data/json/items/armor/bandolier.json @@ -184,7 +184,7 @@ "8x40mm": 4, "4570": 4, "50": 4, - "700nx": 40 + "700nx": 4 }, "moves": 20 } diff --git a/data/json/items/armor/belts.json b/data/json/items/armor/belts.json index 8213a4ff36063..8c644d0ad7604 100644 --- a/data/json/items/armor/belts.json +++ b/data/json/items/armor/belts.json @@ -19,8 +19,8 @@ "pocket_data": [ { "max_contains_volume": "2 L", - "max_contains_weight": "4 kg", - "max_item_length": "70 cm", + "max_contains_weight": "6 kg", + "max_item_length": "90 cm", "moves": 50, "flag_restriction": [ "BELT_CLIP" ], "holster": true diff --git a/data/json/items/armor/jewelry.json b/data/json/items/armor/jewelry.json index 6982965d88a4b..44428ce2fa0b6 100644 --- a/data/json/items/armor/jewelry.json +++ b/data/json/items/armor/jewelry.json @@ -1293,6 +1293,7 @@ "price_postapoc": 100, "to_hit": -1, "material": [ "plastic", "steel" ], + "ascii_picture": "wristwatch", "symbol": "[", "color": "dark_gray", "covers": [ "HAND_EITHER" ], @@ -1343,7 +1344,8 @@ "copy-from": "badge_abstract", "type": "ARMOR", "name": { "str": "deputy badge" }, - "description": "A tarnished silver star gives an air of authority to the wearer." + "description": "A tarnished silver star gives an air of authority to the wearer.", + "ascii_picture": "badge_deputy" }, { "id": "badge_detective", diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index 836b8a59c04ad..d7964bdbb4315 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -1310,6 +1310,7 @@ "moves": 300 } ], + "warmth": 10, "material_thickness": 2, "flags": [ "WATER_FRIENDLY", "STURDY", "BELTED", "OVERSIZE" ] }, @@ -1340,6 +1341,7 @@ "moves": 300 } ], + "warmth": 6, "material_thickness": 2, "flags": [ "WATER_FRIENDLY", "STURDY", "BELTED" ] }, @@ -1370,6 +1372,7 @@ "moves": 300 } ], + "warmth": 8, "material_thickness": 2, "flags": [ "WATER_FRIENDLY", "STURDY", "BELTED", "OVERSIZE" ] }, @@ -1400,6 +1403,7 @@ "moves": 250 } ], + "warmth": 2, "material_thickness": 2, "flags": [ "WATER_FRIENDLY", "STURDY", "BELTED" ] }, diff --git a/data/json/items/armor/suits_protection.json b/data/json/items/armor/suits_protection.json index 4d3b7eaacc234..bbdb71035f115 100644 --- a/data/json/items/armor/suits_protection.json +++ b/data/json/items/armor/suits_protection.json @@ -851,10 +851,7 @@ "symbol": "[", "looks_like": "touring_suit", "color": "dark_gray", - "covers": [ "LEGS", "TORSO", "ARMS" ], - "coverage": 95, - "encumbrance": 12, - "max_encumbrance": 25, + "armor_portion_data": [ { "covers": [ "torso", "LEGS", "ARMS" ], "coverage": 95, "encumbrance": [ 12, 25 ] } ], "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, diff --git a/data/json/items/book/chemistry.json b/data/json/items/book/chemistry.json index fa29d746e9ecb..a60e354da1a3d 100644 --- a/data/json/items/book/chemistry.json +++ b/data/json/items/book/chemistry.json @@ -259,6 +259,7 @@ "price_postapoc": 2000, "bashing": 5, "material": [ "paper" ], + "ascii_picture": "textbook_chemistry", "symbol": "?", "color": "blue", "skill": "chemistry", diff --git a/data/json/items/book/firstaid.json b/data/json/items/book/firstaid.json index b2920e02f7acc..8409c02d90902 100644 --- a/data/json/items/book/firstaid.json +++ b/data/json/items/book/firstaid.json @@ -47,6 +47,7 @@ "price": 2500, "price_postapoc": 1250, "material": [ "paper" ], + "ascii_picture": "manual_first_aid", "symbol": "?", "color": "green", "skill": "firstaid", diff --git a/data/json/items/chemicals_and_resources.json b/data/json/items/chemicals_and_resources.json index adfcf09242462..3b83ab8d64e7a 100644 --- a/data/json/items/chemicals_and_resources.json +++ b/data/json/items/chemicals_and_resources.json @@ -1020,6 +1020,7 @@ "id": "pur_tablets", "name": "water purification tablet", "category": "chems", + "material": [ "powder" ], "weight": "1 g", "color": "white", "use_action": [ "WATER_PURIFIER" ], diff --git a/data/json/items/comestibles/bread.json b/data/json/items/comestibles/bread.json index 42f7197fd7c5d..5a4096e0fa027 100644 --- a/data/json/items/comestibles/bread.json +++ b/data/json/items/comestibles/bread.json @@ -37,10 +37,10 @@ "color": "white", "use_action": { "target": "sourdough_starter", - "msg": "After feeding it and caring for it for weeks, your sourdough starter is finally ready for the big leagues.", + "msg": "After feeding it and caring for it for a week, your sourdough starter is finally ready for the big leagues.", "moves": 50, "type": "delayed_transform", - "transform_age": 200000, + "transform_age": 518400, "not_ready_msg": "You've been caring for your starter for a while, but it's going to need longer before you can do anything tasty with it." } }, @@ -49,7 +49,7 @@ "type": "GENERIC", "category": "food", "name": { "str": "freshly fed sourdough starter" }, - "description": "This jar contains a floury paste with sourdough starter mixed in. It needs a few hours to recover its strength before it can be used again.", + "description": "This jar contains a floury paste with sourdough starter mixed in. It needs a day to recover its strength before it can be used again.", "weight": "52 g", "volume": "250 ml", "price": 10, @@ -64,7 +64,7 @@ "msg": "The starter is now stinky and bubbly, and looks ready for cooking.", "moves": 50, "type": "delayed_transform", - "transform_age": 180000, + "transform_age": 86400, "not_ready_msg": "The starter isn't quite ready to go." } }, diff --git a/data/json/items/comestibles/carnivore.json b/data/json/items/comestibles/carnivore.json index 7373949410ee3..6ae7a556bfbe9 100644 --- a/data/json/items/comestibles/carnivore.json +++ b/data/json/items/comestibles/carnivore.json @@ -570,7 +570,7 @@ "type": "COMESTIBLE", "id": "blood", "name": { "str_sp": "blood" }, - "weight": "265 g", + "weight": "262 g", "color": "red", "container": "bag_iv", "comestible_type": "DRINK", diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 39ca8c3237680..85e121bfc4f10 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -98,6 +98,7 @@ "stim": 1, "quench": 34, "healthy": 1, + "calories": 9, "description": "A healthy beverage made from bee balm steeped in boiling water. Can be used to reduce negative effects of common cold or flu.", "price": 100, "price_postapoc": 25, @@ -146,7 +147,7 @@ "material": [ "milk", "water" ], "volume": "250 ml", "phase": "liquid", - "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], + "flags": [ "EATEN_HOT" ], "fun": 14 }, { @@ -159,6 +160,7 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, + "calories": 0, "description": "A healthy beverage made from chamomile flowers steeped in boiling water. Can be used to treat insomnia.", "price": 100, "price_postapoc": 25, @@ -384,14 +386,14 @@ "symbol": "~", "quench": 48, "healthy": 1, - "calories": 9, + "calories": 26, "description": "A healthy beverage made from dandelion roots steeped in boiling water.", "price": 50, "price_postapoc": 25, "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], + "flags": [ "EATEN_HOT" ], "fun": 2 }, { @@ -404,14 +406,14 @@ "symbol": "~", "quench": 48, "healthy": 2, - "calories": 12, + "calories": 77, "description": "A healthy beverage made from dandelion and burdock roots steeped in boiling water. The additional ingredient makes it slightly healthier and fun.", "price": 50, "price_postapoc": 25, "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], + "flags": [ "EATEN_HOT" ], "fun": 3 }, { @@ -499,9 +501,8 @@ "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], - "fun": 4, - "vitamins": [ [ "iron", 1 ] ] + "flags": [ "EATEN_HOT" ], + "fun": 4 }, { "id": "hot_chocolate", @@ -630,6 +631,7 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, + "calories": 0, "description": "A healthy beverage made from lotus flowers steeped in boiling water.", "price": 100, "price_postapoc": 25, @@ -911,6 +913,7 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, + "calories": 0, "description": "A healthy beverage made from spurge flowers steeped in boiling water. Can be used to prevent asthma attacks.", "price": 100, "price_postapoc": 25, @@ -975,7 +978,7 @@ "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], + "flags": [ "EATEN_HOT" ], "fun": 6 }, { @@ -995,7 +998,7 @@ "volume": "500 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], + "flags": [ "EATEN_HOT" ], "fun": -5 }, { @@ -1059,7 +1062,7 @@ "name": "fruit tea", "copy-from": "tea", "color": "red", - "calories": 6, + "calories": 0, "fatigue_mod": 0, "stim": 0, "description": "A tasty beverage made with herbs and dried fruit from plants other than the tea plant. While colloquially called 'tea', technically it's an infusion.", diff --git a/data/json/items/comestibles/med.json b/data/json/items/comestibles/med.json index 36ccd8e75e7c6..7c0d48dfa3ea4 100644 --- a/data/json/items/comestibles/med.json +++ b/data/json/items/comestibles/med.json @@ -4,12 +4,29 @@ "type": "GENERIC", "category": "drugs", "name": { "str": "first aid kit" }, - "description": "A full medical kit, with bandages, local anesthetics, and rapid healing agents. Used for healing large amounts of damage. Disassemble to get its content.", + "description": "A typical universal first aid kit, one you'd see in a car or in a household. It contains a variety of common medical items stored in case of accidents and injuries. Disassemble to get its content.", + "weight": "1750 g", + "volume": "1250 ml", + "price": 3000, + "price_postapoc": 3000, + "material": "plastic", + "symbol": "!", + "color": "red", + "use_action": "DISASSEMBLE", + "flags": [ "NO_REPAIR" ] + }, + { + "id": "ifak", + "type": "GENERIC", + "category": "drugs", + "name": { "str": "IFAK" }, + "description": "An IFAK, or individual first aid kit, is a specialized set of wound dressings and accessories, and being of military origin focuses on combat trauma and preventing blood loss. Disassemble to get its content.", "weight": "1750 g", "volume": "1250 ml", "price": 3000, "price_postapoc": 3000, "material": [ "plastic" ], + "ascii_picture": "1st_aid", "symbol": "!", "color": "red", "use_action": [ "DISASSEMBLE" ], @@ -56,6 +73,23 @@ "flags": [ "NPC_SAFE", "IRREPLACEABLE_CONSUMABLE" ], "use_action": { "type": "consume_drug", "activation_message": "You take some adderall." } }, + { + "id": "adhesive_bandages", + "type": "COMESTIBLE", + "comestible_type": "MED", + "name": { "str": "adhesive bandage" }, + "description": "A set of small medical dressings, each made of a piece of sterile cloth and a sticky tape, used for small injuries not serious enough to require a full-size bandage.", + "weight": "40 g", + "volume": "150 ml", + "price": 600, + "price_postapoc": 200, + "material": "cotton", + "symbol": "!", + "color": "white", + "charges": 10, + "flags": [ "NO_INGEST" ], + "use_action": { "type": "heal", "bandages_power": 1, "bleed": 4, "move_cost": 200 } + }, { "id": "adrenaline_injector", "type": "COMESTIBLE", @@ -153,7 +187,7 @@ "type": "COMESTIBLE", "comestible_type": "MED", "name": { "str": "bandage" }, - "description": "Simple cloth bandages. Used for healing small amounts of damage.", + "description": "Simple cloth bandages. Used for stopping bloodloss and protecting wounds from external factors.", "weight": "70 g", "volume": "250 ml", "price": 600, @@ -164,7 +198,7 @@ "charges": 3, "stack_size": 9, "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "bandages_power": 4, "bleed": 0.9, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 4, "bleed": 15, "move_cost": 300 } }, { "id": "bandages_makeshift", @@ -173,8 +207,8 @@ "copy-from": "bandages", "description": "Simple cloth bandages. Better than nothing.", "price_postapoc": 100, - "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "bandages_power": 2, "bleed": 0.9, "move_cost": 300 } + "flags": [ "NO_INGEST", "BLIND_EASY" ], + "use_action": { "type": "heal", "bandages_power": 2, "bleed": 10, "move_cost": 300 } }, { "id": "bandages_makeshift_bleached", @@ -184,7 +218,7 @@ "description": "Simple cloth bandages. It is white, as real bandages should be.", "price_postapoc": 150, "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "bandages_power": 3, "bleed": 0.9, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 3, "bleed": 10, "move_cost": 300 } }, { "id": "bandages_makeshift_boiled", @@ -194,7 +228,7 @@ "description": "Simple cloth bandages. It was boiled to make it more sterile.", "price_postapoc": 150, "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "bandages_power": 3, "bleed": 0.9, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 3, "bleed": 10, "move_cost": 300 } }, { "id": "bfipowder", @@ -464,13 +498,13 @@ "volume": "250 ml", "price": 500, "price_postapoc": 50, - "charges": 2, + "charges": 10, "material": [ "cotton" ], "symbol": "*", "color": "white", "container": "bag_plastic", "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "bandages_power": 2, "bleed": 0.9, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 2, "bleed": 3, "move_cost": 300 } }, { "id": "crack", @@ -1155,7 +1189,7 @@ "symbol": ",", "color": "white", "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "bandages_power": 4, "bleed": 0.5, "move_cost": 200 } + "use_action": { "type": "heal", "bandages_power": 4, "bleed": 5, "move_cost": 200 } }, { "id": "meth", @@ -1444,7 +1478,7 @@ "color": "light_gray", "container": "bag_plastic", "flags": [ "NO_INGEST", "IRREPLACEABLE_CONSUMABLE" ], - "use_action": { "type": "heal", "bleed": 0.9, "move_cost": 100 } + "use_action": { "type": "heal", "bleed": 20, "move_cost": 100 } }, { "id": "saline", @@ -1789,7 +1823,7 @@ "description": "Fluffy balls of clean white cotton. Now soaked with antiseptic, they are somewhat useful to disinfect a wound.", "weight": "25 g", "//": "Can't copy-from cotton_ball, breaks volume", - "volume": "125 ml", + "volume": "30 ml", "price": 250, "price_postapoc": 50, "material": [ "cotton" ], diff --git a/data/json/items/comestibles/veggy_dishes.json b/data/json/items/comestibles/veggy_dishes.json index a21d87f3eaecb..8badc03dbe885 100644 --- a/data/json/items/comestibles/veggy_dishes.json +++ b/data/json/items/comestibles/veggy_dishes.json @@ -224,7 +224,8 @@ "type": "COMESTIBLE", "id": "deluxe_veggy_beans", "name": { "str_sp": "vegetarian baked beans" }, - "weight": "270 g", + "weight": "350 g", + "//": "real world measurements: 250ml of cooked beans is 240g with 316 calores, and 250ml of veggies is ~100g with ~100 calories", "color": "brown", "spoils_in": "15 days", "comestible_type": "FOOD", @@ -237,7 +238,6 @@ "price_postapoc": 100, "material": [ "veggy", "bean" ], "volume": "500 ml", - "//": "one beans + one veggy", "flags": [ "EATEN_HOT" ], "fun": 4 }, @@ -245,14 +245,15 @@ "type": "COMESTIBLE", "id": "dry_rice", "name": { "str_sp": "dried rice" }, - "weight": "40 g", + "weight": "200 g", + "//": "real world measurements: 250ml of dry rice weighs 200g and has 720 calories", "color": "white", "spoils_in": "360 days", "container": "bag_plastic", "comestible_type": "FOOD", "symbol": "%", "quench": -6, - "calories": 222, + "calories": 720, "description": "Dehydrated long-grain rice. Tasty and nutritious when cooked, virtually inedible when dry.", "price": 500, "price_postapoc": 300, @@ -270,17 +271,17 @@ "id": "rice_cooked", "name": { "str_sp": "cooked rice" }, "copy-from": "dry_rice", - "weight": "62 g", + "//": "real world measurements: 250ml of cooked rice weighs 200g and has 260 calores, rice roughly triples when cooked", "color": "light_gray", "spoils_in": "10 days", "quench": 0, + "calories": 260, "healthy": 1, "description": "A hearty serving of cooked long-grain white rice.", "price": 100, "price_postapoc": 50, "flags": [ "EATEN_HOT", "FREEZERBURN" ], "fun": 2, - "//": "rice triples in size when cooked", "charges": 1, "vitamins": [ [ "vitA", 1 ], [ "iron", 11 ] ] }, @@ -288,7 +289,8 @@ "type": "COMESTIBLE", "id": "deluxe_veggy_rice", "name": { "str_sp": "fried rice" }, - "weight": "135 g", + "weight": "300 g", + "//": "real world measurements: 250ml cooked rice is 200g with 260 calores, 250mL of veggies is ~100g with ~100 calories", "color": "yellow", "spoils_in": "15 days", "comestible_type": "FOOD", @@ -299,7 +301,7 @@ "price": 700, "price_postapoc": 150, "material": [ "veggy" ], - "volume": "250 ml", + "volume": "500 ml", "flags": [ "EATEN_HOT", "FREEZERBURN" ], "fun": 5, "vitamins": [ [ "vitA", 2 ], [ "vitC", 4 ], [ "calcium", 3 ], [ "iron", 3 ] ] @@ -308,18 +310,19 @@ "type": "COMESTIBLE", "id": "beansnrice", "name": { "str_sp": "beans and rice" }, - "weight": "70 g", + "weight": "440 g", + "//": "real world measurements: 250ml of cooked beans weighs 240g wiht 316 calories, 250ml of cooked rice weighs 200g with 260 calories", "color": "light_gray", "spoils_in": "10 days", "comestible_type": "FOOD", "symbol": "%", "healthy": 1, - "calories": 425, + "calories": 566, "description": "A serving of beans and rice that has been cooked together. Delicious and healthy!", "price": 500, "price_postapoc": 150, "material": [ "veggy", "bean" ], - "volume": "250 ml", + "volume": "500 ml", "flags": [ "EATEN_HOT", "FREEZERBURN" ], "fun": 2, "vitamins": [ [ "vitC", 14 ], [ "calcium", 4 ], [ "iron", 16 ] ] @@ -369,19 +372,19 @@ "type": "COMESTIBLE", "id": "deluxe_veggy_beansnrice", "name": { "str_sp": "deluxe vegetarian beans and rice" }, - "weight": "140 g", + "weight": "540 g", + "//": "real world measurements: 250 mL of cooked beans is 240g w 316 calories, 250ml cooked rice is 200g w 260 calories, and 250mL of veggies is ~100g w ~100 calories", "color": "brown", "spoils_in": "15 days", "comestible_type": "FOOD", "symbol": "%", "healthy": 1, - "calories": 459, + "calories": 600, "description": "Slow-cooked beans and rice with vegetables and seasonings. Tasty and very filling.", "price": 750, "price_postapoc": 200, "material": [ "veggy", "bean" ], "volume": "750 ml", - "//": "one bean + one rice + one veggy", "flags": [ "EATEN_HOT", "FREEZERBURN" ], "fun": 4, "vitamins": [ [ "vitC", 28 ], [ "calcium", 8 ], [ "iron", 32 ] ] @@ -716,7 +719,7 @@ "symbol": "%", "quench": -1, "healthy": 1, - "calories": 200, + "calories": 267, "description": "A serving of sticky vinegared rice commonly used in sushi.", "price": 100, "price_postapoc": 400, diff --git a/data/json/items/containers.json b/data/json/items/containers.json index f088a75b17cfc..f591fcd4e6e52 100644 --- a/data/json/items/containers.json +++ b/data/json/items/containers.json @@ -4,6 +4,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "2.5L canteen" }, + "looks_like": "bottle_plastic", "description": "A large plastic water canteen, with a 2.5 liter capacity and carrying strap.", "weight": "155 g", "volume": "2625 ml", @@ -32,6 +33,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "30 gallon barrel" }, + "looks_like": "55gal_drum", "description": "A huge plastic barrel with a resealable lid.", "weight": "6800 g", "volume": "118125 ml", @@ -57,6 +59,7 @@ "id": "30gal_drum", "type": "GENERIC", "category": "container", + "looks_like": "30gal_barrel", "name": { "str": "steel drum (100L)", "str_pl": "steel drums (100L)" }, "description": "A huge steel barrel with a resealable lid.", "weight": "12000 g", @@ -83,6 +86,7 @@ "id": "55gal_drum", "type": "GENERIC", "category": "container", + "looks_like": "30gal_drum", "name": { "str": "steel drum (200L)", "str_pl": "steel drums (200L)" }, "description": "A massive steel barrel with a resealable lid.", "weight": "20000 g", @@ -110,6 +114,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "canvas sack" }, + "looks_like": "bag_plastic", "description": "A large and sturdy canvas sack. Smells faintly of earth and hard work.", "weight": "415 g", "volume": "1 L", @@ -126,6 +131,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "canvas bag" }, + "looks_like": "bag_canvas", "description": "Small bag made of canvas. Looks fine to store dried herbs in.", "weight": "5 g", "volume": "250 ml", @@ -142,6 +148,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "plastic bag" }, + "looks_like": "bag_canvas", "description": "A small, open plastic bag. Essentially trash.", "weight": "5 g", "volume": "10 ml", @@ -194,8 +201,9 @@ "name": { "str": "body bag" }, "looks_like": "bag_canvas", "description": "A large, human size, rectangular bag made of strong plastic, with a zipper in the middle. Used to hold a dead body.", - "weight": "500 g", + "weight": "1500 g", "volume": "1 L", + "longest_side": "40 cm", "price": 0, "price_postapoc": 10, "to_hit": -5, @@ -207,6 +215,7 @@ "watertight": true, "max_contains_volume": "100 L", "max_contains_weight": "100 kg", + "max_item_length": "200 cm", "moves": 400 } ], @@ -244,6 +253,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "glass bottle" }, + "looks_like": "bottle_plastic", "description": "A resealable glass bottle, holds 750 ml of liquid.", "weight": "200 g", "volume": "787 ml", @@ -300,6 +310,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "condiment bottle" }, + "looks_like": "bottle_plastic", "description": "An inverted plastic bottle for condiments. Still sealed from factory, preserves content from rot until opened.", "weight": "19 g", "volume": "525 ml", @@ -328,6 +339,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "condiment bottle" }, + "looks_like": "condiment_bottle_sealed", "description": "An inverted plastic bottle for condiments.", "weight": "19 g", "volume": "525 ml", @@ -355,6 +367,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "small plastic bottle" }, + "looks_like": "bottle_plastic", "description": "A resealable plastic bottle, holds 250 ml of liquid.", "weight": "7 g", "volume": "251 ml", @@ -381,6 +394,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "large plastic bottle" }, + "looks_like": "bottle_plastic", "description": "It's a two-liter plastic bottle that can hold a lot of soda, or, nowadays, boiled water.", "weight": "13 g", "volume": "2003 ml", @@ -406,6 +420,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "clay bowl" }, + "looks_like": "bowl_plastic", "description": "A clay bowl with a waterproofed hide lid. Can be used as a container or as a tool. Holds 250 ml of liquid.", "weight": "60 g", "volume": "255 ml", @@ -431,12 +446,14 @@ "type": "GENERIC", "category": "container", "name": { "str": "pack" }, + "looks_like": "box_small", "description": "SURGEON GENERAL'S WARNING: Smoking Causes Lung Cancer, Heart Disease, Emphysema And May Complicate Pregnancy.", "weight": "15 g", "volume": "253 ml", "price": 0, "price_postapoc": 0, "material": [ "paper" ], + "ascii_picture": "box_cigarette", "symbol": ")", "color": "white", "pocket_data": [ { "pocket_type": "CONTAINER", "rigid": true, "max_contains_volume": "250 ml", "max_contains_weight": "3 kg" } ] @@ -449,7 +466,7 @@ "description": "A small cardboard box. No bigger than a foot in dimension.", "weight": "151 g", "volume": "1 L", - "pocket_data": [ { "pocket_type": "CONTAINER", "rigid": false, "max_contains_volume": "990 ml", "max_contains_weight": "4 kg" } ], + "pocket_data": [ { "pocket_type": "CONTAINER", "rigid": true, "max_contains_volume": "990 ml", "max_contains_weight": "4 kg" } ], "price": 0, "price_postapoc": 0, "material": [ "cardboard" ], @@ -461,6 +478,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "cardboard box", "str_pl": "cardboard boxes" }, + "looks_like": "box_small", "description": "A sturdy cardboard box, about the size of a banana box. Great for packing.", "weight": "850 g", "volume": "2100 ml", @@ -485,6 +503,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "large cardboard box", "str_pl": "large cardboard boxes" }, + "looks_like": "box_medium", "description": "A very large cardboard box, the sort children would have loved to hide in, when there were still children.", "weight": "1250 g", "volume": "3150 ml", @@ -535,6 +554,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "hydration pack" }, + "looks_like": "runner_bag", "description": "A slim and lightweight insulated plastic bladder worn on the back. It has a large pocket and a capped mouth for filling with liquid with a hose that allows the wearer to drink hands-free.", "weight": "286 g", "volume": "2503 ml", @@ -591,6 +611,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "paper carton" }, + "looks_like": "box_small", "description": "A half gallon carton constructed of a paper, aluminum, and plastic laminate. It has a threaded cap for easy resealing.", "weight": "28 g", "volume": "2003 ml", @@ -616,6 +637,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "vacuum-packed bag" }, + "looks_like": "bag_plastic", "description": "This is a bag of vacuum-packed food.", "weight": "2 g", "volume": "10 ml", @@ -639,6 +661,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "small tin can" }, + "looks_like": "can_drink", "description": "A small tin can, like what tuna comes in.", "//": "Represents a 4 cm radius x 5 cm height steel can.", "weight": "40 g", @@ -687,6 +710,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "plastic canteen" }, + "looks_like": "2lcanteen", "description": "A military-style water canteen with a 1.5 liter capacity. Commonly worn at the hip.", "weight": "155 g", "volume": "1503 ml", @@ -714,6 +738,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "thermos", "str_pl": "thermoses" }, + "looks_like": "bottle_plastic", "description": "A Thermos brand vacuum flask. Built for temperature retention, helps keep things hot or cold. Contains 1L of liquid.", "weight": "530 g", "price": 1595, @@ -738,6 +763,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "clay canister" }, + "looks_like": "bowl_clay", "description": "A fragile clay vessel. It can be used to make crude impact grenades or to store liquid.", "weight": "268 g", "volume": "253 ml", @@ -763,6 +789,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "clay hydria" }, + "looks_like": "bowl_clay", "description": "A 15-liter clay pot with three handles for carrying and for pouring.", "weight": "1955 g", "volume": "15003 ml", @@ -789,6 +816,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "large clay pot" }, + "looks_like": "bowl_clay", "description": "A bulky and heavy clay pot with a waterproofed hide lid, meant to store water, but can carry other liquids in a pinch.", "weight": "4887 g", "volume": "37500 ml", @@ -840,6 +868,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "glass flask" }, + "looks_like": "bottle_glass", "description": "A 250 ml laboratory conical flask, with a rubber bung.", "weight": "48 g", "volume": "251 ml", @@ -866,6 +895,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "test tube" }, + "looks_like": "flask_glass", "description": "A 10ml laboratory cylindrical test tube, with a rubber stopper.", "weight": "36 g", "volume": "11ml", @@ -892,6 +922,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "beaker" }, + "looks_like": "flask_glass", "description": "A 250ml laboratory beaker. Basically a cup with delusions of grandeur.", "weight": "150 g", "volume": "251ml", @@ -918,6 +949,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "graduated cylinder" }, + "looks_like": "flask_glass", "description": "A tall, narrow glass cylinder with precise markings for measuring fluid quantities. An important science tool, it is also useful for anal retentive chefs.", "weight": "150 g", "volume": "101ml", @@ -945,6 +977,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "microcentrifuge tube" }, + "looks_like": "test_tube", "description": "These plastic tubes, with little built in snap-caps, are a great way to store a tiny amount of liquid. Great for jello shooters if 1mL is enough for a shot for you. Cool people call these \"eppies\".", "weight": "1 g", "volume": "2ml", @@ -970,6 +1003,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "hip flask" }, + "looks_like": "2lcanteen", "description": "A 250 ml metal flask with a hinged screw-on lid, commonly used to discreetly transport alcohol.", "weight": "120 g", "volume": "251 ml", @@ -999,6 +1033,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "3L glass jar" }, + "looks_like": "jar_glass", "description": "A three-liter glass jar with a metal screw top lid, used for canning.", "weight": "365 g", "volume": "3003 ml", @@ -1044,6 +1079,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "glass jar" }, + "looks_like": "jar_glass", "description": "A half-liter glass jar with a metal screw top lid, used for canning.", "weight": "150 g", "volume": "502 ml", @@ -1112,6 +1148,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "steel jerrycan" }, + "looks_like": "jerrycan", "description": "A steel jerrycan, meant to carry fuel, but can carry other liquids in a pinch.", "weight": "4815 g", "volume": "20002 ml", @@ -1139,6 +1176,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "clay jug" }, + "looks_like": "bowl_clay", "description": "A clay container with a lid, used to hold and pour liquids.", "weight": "400 g", "volume": "1002 ml", @@ -1164,6 +1202,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "gallon jug" }, + "looks_like": "bottle_plastic", "description": "A standard plastic jug used for milk and household cleaning chemicals.", "weight": "190 g", "volume": "3752 ml", @@ -1189,6 +1228,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "aluminum keg" }, + "looks_like": "30l_barrel", "description": "A reusable lightweight aluminum keg, used for shipping beer. It has a capacity of 50 liters.", "weight": "5040 g", "volume": "50050 ml", @@ -1216,6 +1256,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "steel keg" }, + "looks_like": "keg", "description": "A reusable heavy steel keg, used for shipping beer. It has a capacity of 50 liters.", "weight": "12600 g", "volume": "50050 ml", @@ -1267,6 +1308,7 @@ "id": "metal_tank", "type": "GENERIC", "category": "container", + "looks_like": "keg", "name": { "str": "metal tank (60L)", "str_pl": "metal tanks (60L)" }, "description": "A large metal tank for holding liquids. Useful for crafting.", "weight": "5668 g", @@ -1293,6 +1335,7 @@ "id": "metal_tank_little", "type": "GENERIC", "category": "container", + "looks_like": "keg", "name": { "str": "metal tank (2L)", "str_pl": "metal tanks (2L)" }, "description": "A small metal tank for gas or liquids. Useful for crafting.", "weight": "800 g", @@ -1320,6 +1363,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "wooden canteen" }, + "looks_like": "canteen", "description": "A water canteen made from wood, secured by metal bands and sealed with wax or pitch. Holds 1.5 liters and has a simple carry strap.", "weight": "232 g", "volume": "1750 ml", @@ -1372,6 +1416,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "small waterskin" }, + "looks_like": "canvas_bag", "description": "A small watertight leather bag with a carrying strap, can hold 1.5 liters of water.", "weight": "453 g", "volume": "250 ml", @@ -1399,6 +1444,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "waterskin" }, + "looks_like": "waterskin", "description": "A watertight leather bag with a carrying strap, can hold 3 liters of water.", "weight": "783 g", "volume": "500 ml", @@ -1426,6 +1472,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "large waterskin" }, + "looks_like": "waterskin2", "description": "A large watertight leather bag with a carrying strap, can hold 5 liters of water.", "weight": "990 g", "volume": "750 ml", @@ -1453,6 +1500,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "wooden barrel" }, + "looks_like": "30l_barrel", "description": "Traditionally made of white oak; these vessels are known for delivering delicious whiskey to the future. It has a capacity of 100 liters.", "weight": "42408 g", "volume": "101 L", @@ -1497,6 +1545,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "styrofoam cup" }, + "looks_like": "cup_plastic", "description": "A cheap, disposable cup with a plastic lid and straw.", "weight": "50 g", "volume": "501 ml", @@ -1570,6 +1619,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "large tin can" }, + "looks_like": "can_food", "description": "A large tin can, like what beans come in. Holds a substantial amount of food.", "weight": "350 g", "volume": "3003 ml", @@ -1594,6 +1644,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "survival kit box", "str_pl": "survival kit boxes" }, + "looks_like": "box_small", "description": "An aluminum box that used to contain a small survival kit. Can hold 1 liter of liquid.", "weight": "200 g", "volume": "1002 ml", @@ -1618,6 +1669,7 @@ "type": "GENERIC", "category": "container", "name": { "str": "small cardboard box of tea bags", "str_pl": "small cardboard boxes of tea bags" }, + "looks_like": "box_small", "description": "A very small cardboard box with tea brand written on it.", "weight": "10 g", "volume": "105 ml", diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 56c232bcc8776..b182e41840127 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -331,6 +331,7 @@ "price": 0, "material": [ "chitin" ], "flags": [ "NO_SALVAGE" ], + "milling": { "into": "meal_chitin_piece", "conversion_rate": 4 }, "weight": "89 g", "volume": "300 ml", "bashing": 1 @@ -424,7 +425,7 @@ "type": "GENERIC", "category": "spare_parts", "name": { "str": "bundle of planks", "str_pl": "bundles of planks" }, - "description": "Ten construction planks securely lashed together with a rope. Disassemble to unpack.", + "description": "Ten construction planks securely tied together for easier transport. Disassemble to untie them.", "//": "total volume is equal to 10 planks, assuming uniformity and tight stacking", "volume": "44 L", "weight": "26 kg", @@ -440,7 +441,7 @@ "type": "GENERIC", "category": "spare_parts", "name": { "str": "bundle of stout branches", "str_pl": "bundles of stout branches" }, - "description": "Ten stout branches securely lashed together with a rope. Disassemble to untie them.", + "description": "Ten stout branches securely tied together for easier transport. Disassemble to untie them.", "//": "total volume is greater than 10 stout branches; irregular dimensions leave air gaps", "volume": "30 L", "weight": "15 kg", @@ -451,6 +452,22 @@ "symbol": "H", "color": "brown" }, + { + "id": "bundle_branch_long", + "type": "GENERIC", + "category": "spare_parts", + "name": { "str": "bundle of long stout branches", "str_pl": "bundles of long stout branches" }, + "description": "Five long stout branches securely tied together for easier transport. Disassemble to untie them.", + "//": "total volume is greater than 5 long stout branches, since they are rough lumber and do not stack perfectly", + "volume": "30 L", + "weight": "15 kg", + "longest_side": "260 cm", + "price": 0, + "price_postapoc": 50, + "material": [ "wood" ], + "symbol": "H", + "color": "brown" + }, { "type": "GENERIC", "id": "sample_t_substrate", @@ -1768,6 +1785,7 @@ "price": 1000, "price_postapoc": 10, "material": [ "plastic" ], + "ascii_picture": "mobile_memory_card", "flags": [ "MC_MOBILE", "MC_RANDOM_STUFF", "MC_MAY_BE_ENCRYPTED", "MC_TURN_USED" ], "weight": "5 g", "volume": "2 ml" @@ -1782,6 +1800,7 @@ "price": 500, "price_postapoc": 10, "material": [ "plastic" ], + "ascii_picture": "mobile_memory_card", "flags": [ "MC_MOBILE", "MC_USED" ], "weight": "5 g", "volume": "1 ml" @@ -3023,6 +3042,15 @@ "to_hit": -3, "flags": [ "TRADER_AVOID", "NO_REPAIR" ] }, + { + "type": "GENERIC", + "id": "broken_robofac_laserturret_mk1", + "symbol": ",", + "color": "green", + "name": { "str": "broken laser turret" }, + "weight": "40 kg", + "copy-from": "broken_turret" + }, { "type": "GENERIC", "id": "fire_brick", diff --git a/data/json/items/generic/music.json b/data/json/items/generic/music.json index b77aeabc02625..4c9b508d056b5 100644 --- a/data/json/items/generic/music.json +++ b/data/json/items/generic/music.json @@ -39,7 +39,7 @@ "type": "GENERIC", "id": "microphone_xlr_generic", "name": { "str": "XLR microphone" }, - "description": "A typical microphone used to record or amplify voice. Comes with a clip. Has a 3-pin XLR connector on the bottom in order to connect to am amp.", + "description": "A typical microphone used to record or amplify voice. Comes with a clip. Has a 3-pin XLR connector on the bottom in order to connect to an amp.", "symbol": "i", "color": "dark_gray", "volume": "550 ml", diff --git a/data/json/items/generic/toys_and_sports.json b/data/json/items/generic/toys_and_sports.json index fc737f5880585..d39878db21e59 100644 --- a/data/json/items/generic/toys_and_sports.json +++ b/data/json/items/generic/toys_and_sports.json @@ -141,9 +141,10 @@ "price": 3000, "price_postapoc": 10, "material": [ "ceramic" ], - "weight": "2000 g", - "volume": "2500 ml", - "bashing": 16, + "weight": "7257 g", + "volume": "5277 ml", + "longest_side": "216 mm", + "bashing": 18, "to_hit": -2 }, { diff --git a/data/json/items/gun/20x66mm.json b/data/json/items/gun/20x66mm.json index 06227545f14d0..5d007280c1538 100644 --- a/data/json/items/gun/20x66mm.json +++ b/data/json/items/gun/20x66mm.json @@ -23,7 +23,7 @@ "dispersion": 285, "durability": 9, "clip_size": 5, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ], diff --git a/data/json/items/gun/22.json b/data/json/items/gun/22.json index 57f61e61c8a72..97d7ebdbfa5be 100644 --- a/data/json/items/gun/22.json +++ b/data/json/items/gun/22.json @@ -22,7 +22,7 @@ "durability": 6, "min_cycle_recoil": 39, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 6 ] ], - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 3 ], [ "barrel", 1 ], @@ -88,6 +88,7 @@ "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ], "flags": [ "RELOAD_ONE" ], "pocket_data": [ + { "pocket_type": "MAGAZINE", "ammo_restriction": { "22": 19 } }, { "pocket_type": "MAGAZINE_WELL", "holster": true, @@ -157,7 +158,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], @@ -194,7 +195,7 @@ "dispersion": 110, "durability": 8, "min_cycle_recoil": 39, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], diff --git a/data/json/items/gun/223.json b/data/json/items/gun/223.json index 26a10ce9d8ce7..9abd349707c84 100644 --- a/data/json/items/gun/223.json +++ b/data/json/items/gun/223.json @@ -21,7 +21,7 @@ "durability": 8, "min_cycle_recoil": 1350, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "built_in_mods": [ "folding_stock" ], "pocket_data": [ { @@ -109,11 +109,26 @@ "symbol": "(", "color": "dark_gray", "ammo": [ "223" ], + "skill": "pistol", "range": -6, "ranged_damage": { "damage_type": "bullet", "amount": -9 }, "dispersion": 380, "durability": 6, "min_cycle_recoil": 1350, + "valid_mod_locations": [ + [ "accessories", 4 ], + [ "barrel", 1 ], + [ "bore", 1 ], + [ "brass catcher", 1 ], + [ "grip", 1 ], + [ "mechanism", 4 ], + [ "magazine", 1 ], + [ "muzzle", 1 ], + [ "rail mount", 2 ], + [ "sights", 1 ], + [ "stock mount", 1 ], + [ "underbarrel", 1 ] + ], "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", @@ -507,6 +522,7 @@ "description": "An AR-15 derivative pistol manufactured by Olympic Arms in the nineties. The main difference compared to the AR-15 is that the recoil spring has been moved to the top of the gun, circumventing the necessity for a solid buttstock.", "weight": "2023 g", "volume": "2135 ml", + "longest_side": "456 mm", "price": 125000, "price_postapoc": 5500, "to_hit": -2, @@ -515,11 +531,26 @@ "symbol": "(", "color": "dark_gray", "ammo": [ "223" ], + "skill": "pistol", "range": -6, "ranged_damage": { "damage_type": "bullet", "amount": -11 }, "dispersion": 380, "durability": 6, "min_cycle_recoil": 1350, + "valid_mod_locations": [ + [ "accessories", 4 ], + [ "barrel", 1 ], + [ "bore", 1 ], + [ "brass catcher", 1 ], + [ "grip", 1 ], + [ "mechanism", 4 ], + [ "magazine", 1 ], + [ "muzzle", 1 ], + [ "rail mount", 2 ], + [ "sights", 1 ], + [ "stock mount", 1 ], + [ "underbarrel mount", 1 ] + ], "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", @@ -565,7 +596,7 @@ "dispersion": 100, "durability": 8, "min_cycle_recoil": 1350, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], diff --git a/data/json/items/gun/270win.json b/data/json/items/gun/270win.json index ed30c99112066..9403867f8c948 100644 --- a/data/json/items/gun/270win.json +++ b/data/json/items/gun/270win.json @@ -20,7 +20,7 @@ "durability": 8, "blackpowder_tolerance": 24, "clip_size": 4, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "flags": [ "RELOAD_ONE", "NEVER_JAMS" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "270win": 4 } } ] } diff --git a/data/json/items/gun/300.json b/data/json/items/gun/300.json index ce542b7b24ab3..ba50a5915a5c1 100644 --- a/data/json/items/gun/300.json +++ b/data/json/items/gun/300.json @@ -19,7 +19,7 @@ "dispersion": 90, "durability": 8, "min_cycle_recoil": 4770, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "flags": [ "NEVER_JAMS" ], "pocket_data": [ { @@ -53,7 +53,7 @@ "durability": 8, "blackpowder_tolerance": 24, "clip_size": 3, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "flags": [ "RELOAD_ONE" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "300": 3 } } ] }, @@ -78,7 +78,7 @@ "durability": 8, "blackpowder_tolerance": 24, "clip_size": 3, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "flags": [ "RELOAD_ONE" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "300": 3 } } ] } diff --git a/data/json/items/gun/3006.json b/data/json/items/gun/3006.json index 5ed0ebb3026d8..0f6bc77d9fa09 100644 --- a/data/json/items/gun/3006.json +++ b/data/json/items/gun/3006.json @@ -21,7 +21,7 @@ "dispersion": 90, "durability": 7, "blackpowder_tolerance": 24, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -113,7 +113,7 @@ "durability": 8, "blackpowder_tolerance": 60, "clip_size": 5, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -130,6 +130,7 @@ ], "flags": [ "RELOAD_ONE" ], "pocket_data": [ + { "pocket_type": "MAGAZINE", "ammo_restriction": { "3006": 5 } }, { "pocket_type": "MAGAZINE_WELL", "holster": true, @@ -161,7 +162,7 @@ "durability": 8, "min_cycle_recoil": 3420, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 3 ] ], - "barrel_length": "1000 ml", + "barrel_volume": "1000 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -207,7 +208,7 @@ "durability": 8, "blackpowder_tolerance": 24, "clip_size": 4, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "flags": [ "RELOAD_ONE", "NEVER_JAMS" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "3006": 4 } } ] } diff --git a/data/json/items/gun/300BLK.json b/data/json/items/gun/300BLK.json index 7dca2e1c4c5d8..3e8b18b02ce2d 100644 --- a/data/json/items/gun/300BLK.json +++ b/data/json/items/gun/300BLK.json @@ -21,7 +21,7 @@ "durability": 8, "min_cycle_recoil": 1700, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "built_in_mods": [ "folding_stock" ], "pocket_data": [ { diff --git a/data/json/items/gun/308.json b/data/json/items/gun/308.json index 6f04272046c33..c754a7acf984e 100644 --- a/data/json/items/gun/308.json +++ b/data/json/items/gun/308.json @@ -7,7 +7,8 @@ "name": { "str_sp": "FN FAL" }, "description": "Originally designed during the Cold War, the FN FAL is probably the most successful battle rifle ever designed. Even though often labeled as obsolete, its high rate of fire and powerful ammunition make it perfectly capable of holding its ground against modern competitors.", "weight": "4250 g", - "volume": "2 L", + "volume": "4511 ml", + "longest_side": "1090 mm", "price": 350000, "price_postapoc": 5500, "to_hit": -1, @@ -21,7 +22,7 @@ "durability": 8, "min_cycle_recoil": 2700, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", @@ -40,7 +41,8 @@ "name": { "str_sp": "H&K G3" }, "description": "An early battle rifle developed after the end of WWII. The G3 is designed to unload large amounts of deadly ammunition, but it is less suitable over long ranges.", "weight": "4380 g", - "volume": "2 L", + "volume": "3724 ml", + "longest_side": "1025 mm", "price": 205000, "price_postapoc": 6000, "to_hit": -1, @@ -72,7 +74,8 @@ "name": { "str": "M134D-H Minigun" }, "description": "The M134D-H Minigun is a (relatively) lightweight heavy rotary machine gun. Its six barrels are rotated by an electric motor, powered by UPS or vehicle. If you could find enough ammo for it, it would become a devastating weapon. It must be mounted on a vehicle before use.", "weight": "19770 g", - "volume": "6 L", + "volume": "8300 ml", + "longest_side": "800 mm", "price": 5500000, "price_postapoc": 10000, "to_hit": -4, @@ -109,6 +112,8 @@ "name": { "str_sp": "M14 EBR-RI" }, "description": "A highly modified version of the M14 rifle designed to cover both CQB and designated marksman roles. A very powerful and versatile rifle, if somewhat heavy.", "weight": "5070 g", + "volume": "3672 ml", + "longest_side": "889 mm", "price": 195000, "price_postapoc": 6500, "material": [ "steel", "plastic" ], @@ -136,7 +141,8 @@ "name": { "str_sp": "M1A" }, "description": "The child of the M1 Garand World War 2 rifle, the M1A is a semi-automatic variant of the M14, favored for its accuracy and modular use.", "weight": "4230 g", - "volume": "2250 ml", + "volume": "3970 ml", + "longest_side": "1126 mm", "price": 130000, "price_postapoc": 3500, "to_hit": -1, @@ -149,7 +155,7 @@ "dispersion": 110, "durability": 8, "min_cycle_recoil": 2700, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -181,8 +187,9 @@ "type": "GUN", "name": { "str": "M240" }, "description": "The M240 is a medium machine gun used by the US military, replacing the older M60. Quite inaccurate and difficult to control, the M240 is designed to fire many rounds very quickly.", - "weight": "12400 g", - "volume": "3 L", + "weight": "12500 g", + "volume": "11780 ml", + "longest_side": "1260 mm", "price": 1000000, "price_postapoc": 7500, "to_hit": -1, @@ -228,7 +235,8 @@ "name": { "str": "M60" }, "description": "The M60 is a general-purpose machine gun developed to replace the .30-caliber M1918 and M1919. Heavy and difficult to handle fired from the shoulder, as most people aren't action-movie heroes.", "weight": "10500 g", - "volume": "3 L", + "volume": "10900 ml", + "longest_side": "1105 mm", "price": 1000000, "price_postapoc": 7500, "to_hit": -1, @@ -282,8 +290,9 @@ "type": "GUN", "name": { "str_sp": "Savage 111F" }, "description": "A very accurate rifle chambered for the powerful .308 round. Its very low ammo capacity is offset by its accuracy and near-complete lack of recoil.", - "weight": "2993 g", - "volume": "3 L", + "weight": "3630 g", + "volume": "2875 ml", + "longest_side": "1041 mm", "price": 53000, "price_postapoc": 4250, "to_hit": -1, @@ -296,7 +305,7 @@ "durability": 9, "blackpowder_tolerance": 24, "clip_size": 3, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "flags": [ "RELOAD_ONE", "NEVER_JAMS" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "308": 3 } } ] }, @@ -307,7 +316,9 @@ "type": "GUN", "name": { "str_sp": "FN SCAR-H" }, "description": "A highly accurate and modular battle rifle specially designed for the United States Special Operations Command. The 'H' in its name stands for heavy, as it uses the powerful .308 round.", - "weight": "3640 g", + "weight": "3630 g", + "volume": "5427 ml", + "longest_side": "906 mm", "ammo": [ "308" ], "ranged_damage": { "damage_type": "bullet", "amount": -3 }, "min_cycle_recoil": 2700, @@ -342,7 +353,7 @@ "dispersion": 85, "durability": 9, "min_cycle_recoil": 2700, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "default_mods": [ "rifle_scope", "bipod" ], "clip_size": 5, "valid_mod_locations": [ @@ -370,7 +381,8 @@ "name": { "str": "HK417 A2" }, "description": "A German battle rifle with a 13\" barrel and telescopic stock. It is a gas operated, rotating bolt rifle with a short-stroke piston design similar to that of the G36.", "weight": "4220 g", - "volume": "1750 ml", + "volume": "4000 ml", + "longest_side": "914 mm", "price": 320000, "price_postapoc": 6000, "to_hit": -1, @@ -402,8 +414,9 @@ "type": "GUN", "name": { "str": "M110A1" }, "description": "A derivative of H&K's G28 with an aluminum upper receiver to meet US Army weight requirements. It is a gas operated, rotating bolt rifle accurate to 1.5 MOA with standard ammunition.", - "weight": "4330 g", - "volume": "2 L", + "weight": "3800 g", + "volume": "4000 ml", + "longest_side": "1028 mm", "price": 320000, "price_postapoc": 6000, "to_hit": -1, @@ -435,7 +448,8 @@ "name": { "str": "AR-10" }, "description": "Somewhat similar to the later AR-15, the AR-10 is a gas operated, rotating bolt rifle chambered for 7.62x51mm rounds.", "weight": "3290 g", - "volume": "2 L", + "volume": "4250 ml", + "longest_side": "1050 mm", "price": 120000, "price_postapoc": 5500, "to_hit": -1, diff --git a/data/json/items/gun/38.json b/data/json/items/gun/38.json index 7194df6a79bf1..a233817460245 100644 --- a/data/json/items/gun/38.json +++ b/data/json/items/gun/38.json @@ -118,7 +118,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], diff --git a/data/json/items/gun/40.json b/data/json/items/gun/40.json index 1abf3c1842973..1ad19f058240a 100644 --- a/data/json/items/gun/40.json +++ b/data/json/items/gun/40.json @@ -136,7 +136,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], @@ -222,7 +222,7 @@ "min_cycle_recoil": 425, "modes": [ [ "DEFAULT", "burst", 5 ] ], "loudness": 25, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 3 ], [ "barrel", 1 ], diff --git a/data/json/items/gun/410shot.json b/data/json/items/gun/410shot.json index ef2cbf0cc4e24..6c699c2b976c7 100644 --- a/data/json/items/gun/410shot.json +++ b/data/json/items/gun/410shot.json @@ -16,7 +16,7 @@ "material": [ "steel", "plastic" ], "dispersion": 395, "durability": 7, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "ammo": [ "410shot" ], "flags": [ "NEVER_JAMS" ], "pocket_data": [ @@ -41,6 +41,7 @@ "longest_side": "1152 mm", "price_postapoc": 2000, "blackpowder_tolerance": 80, - "ammo": [ "410shot" ] + "ammo": [ "410shot" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "410shot": 1 } } ] } ] diff --git a/data/json/items/gun/44.json b/data/json/items/gun/44.json index 44873ec8b9058..702f3bcd8ae4a 100644 --- a/data/json/items/gun/44.json +++ b/data/json/items/gun/44.json @@ -109,7 +109,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], diff --git a/data/json/items/gun/45.json b/data/json/items/gun/45.json index cb3c0764ec544..a1131ded07107 100644 --- a/data/json/items/gun/45.json +++ b/data/json/items/gun/45.json @@ -219,7 +219,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], @@ -258,7 +258,7 @@ "min_cycle_recoil": 456, "modes": [ [ "DEFAULT", "burst", 5 ] ], "loudness": 25, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 3 ], [ "barrel", 1 ], @@ -332,7 +332,7 @@ "durability": 7, "min_cycle_recoil": 540, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 3 ], [ "barrel", 1 ], diff --git a/data/json/items/gun/50.json b/data/json/items/gun/50.json index e8380986ca2a1..a3d2580414955 100644 --- a/data/json/items/gun/50.json +++ b/data/json/items/gun/50.json @@ -19,7 +19,7 @@ "ranged_damage": { "damage_type": "bullet", "amount": -5 }, "dispersion": 130, "durability": 8, - "barrel_length": "1250 ml", + "barrel_volume": "1250 ml", "default_mods": [ "bipod", "rifle_scope", "muzzle_brake" ], "flags": [ "NEVER_JAMS" ], "pocket_data": [ @@ -52,7 +52,7 @@ "dispersion": 250, "durability": 8, "reload": 400, - "barrel_length": "1250 ml", + "barrel_volume": "1250 ml", "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 3 ] ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -106,7 +106,7 @@ "price": -1210000, "ranged_damage": { "damage_type": "bullet", "amount": -4 }, "dispersion": 60, - "barrel_length": "-250 ml" + "barrel_volume": "-250 ml" }, "flags": [ "RELOAD_EJECT" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "holster": true, "rigid": true, "ammo_restriction": { "50": 1 } } ] @@ -131,7 +131,7 @@ "dispersion": 80, "durability": 7, "reload": 400, - "barrel_length": "1250 ml", + "barrel_volume": "1250 ml", "default_mods": [ "bipod", "rifle_scope", "muzzle_brake" ], "flags": [ "NEVER_JAMS" ], "pocket_data": [ @@ -164,7 +164,7 @@ "dispersion": 50, "durability": 8, "reload": 450, - "barrel_length": "1250 ml", + "barrel_volume": "1250 ml", "default_mods": [ "recoil_stock", "bipod", "rifle_scope", "muzzle_brake" ], "flags": [ "NEVER_JAMS" ], "pocket_data": [ @@ -196,7 +196,7 @@ "ranged_damage": { "damage_type": "bullet", "amount": -5 }, "dispersion": 110, "durability": 8, - "barrel_length": "1250 ml", + "barrel_volume": "1250 ml", "default_mods": [ "bipod", "rifle_scope", "muzzle_brake" ], "clip_size": 1, "flags": [ "NEVER_JAMS", "RELOAD_ONE" ], diff --git a/data/json/items/gun/545x39.json b/data/json/items/gun/545x39.json index f0776a85b9ad5..b7d13c6bde593 100644 --- a/data/json/items/gun/545x39.json +++ b/data/json/items/gun/545x39.json @@ -22,7 +22,7 @@ "dispersion": 150, "durability": 8, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], diff --git a/data/json/items/gun/5x50.json b/data/json/items/gun/5x50.json index 8587b8ab3d017..aaef493348292 100644 --- a/data/json/items/gun/5x50.json +++ b/data/json/items/gun/5x50.json @@ -21,7 +21,7 @@ "ranged_damage": { "damage_type": "bullet", "amount": 10 }, "dispersion": 220, "durability": 9, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "5 rd.", 5 ], [ "AUTO", "auto", 4 ] ], "valid_mod_locations": [ [ "accessories", 3 ], diff --git a/data/json/items/gun/700nx.json b/data/json/items/gun/700nx.json index 162df5e7d97ee..8e30c1839f744 100644 --- a/data/json/items/gun/700nx.json +++ b/data/json/items/gun/700nx.json @@ -21,7 +21,7 @@ "durability": 8, "clip_size": 1, "reload": 600, - "barrel_length": "1000 ml", + "barrel_volume": "1000 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ], diff --git a/data/json/items/gun/762.json b/data/json/items/gun/762.json index 8ee6fec7d9b75..0fa8861aadb03 100644 --- a/data/json/items/gun/762.json +++ b/data/json/items/gun/762.json @@ -68,7 +68,7 @@ "dispersion": 160, "durability": 9, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "default_mods": [ "folding_stock" ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -117,7 +117,7 @@ "dispersion": 90, "durability": 8, "clip_size": 10, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "built_in_mods": [ "inter_bayonet" ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -135,6 +135,7 @@ ], "flags": [ "RELOAD_ONE", "NEVER_JAMS" ], "pocket_data": [ + { "pocket_type": "MAGAZINE", "ammo_restriction": { "762": 10 } }, { "pocket_type": "MAGAZINE_WELL", "holster": true, diff --git a/data/json/items/gun/762R.json b/data/json/items/gun/762R.json index 96e20fedc44e7..34bb7a4bd7225 100644 --- a/data/json/items/gun/762R.json +++ b/data/json/items/gun/762R.json @@ -13,7 +13,7 @@ "range": -6, "ranged_damage": { "damage_type": "bullet", "amount": -3 }, "dispersion": 60, - "barrel_length": "-500 ml" + "barrel_volume": "-500 ml" } }, { @@ -61,7 +61,7 @@ "dispersion": 90, "durability": 10, "clip_size": 5, - "barrel_length": "1000 ml", + "barrel_volume": "1000 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -73,6 +73,7 @@ ], "flags": [ "RELOAD_ONE" ], "pocket_data": [ + { "pocket_type": "MAGAZINE", "ammo_restriction": { "762R": 5 } }, { "pocket_type": "MAGAZINE_WELL", "holster": true, diff --git a/data/json/items/gun/762x25.json b/data/json/items/gun/762x25.json index ad54b53cb58dc..4d0b550bed311 100644 --- a/data/json/items/gun/762x25.json +++ b/data/json/items/gun/762x25.json @@ -23,7 +23,7 @@ "dispersion": 120, "durability": 8, "min_cycle_recoil": 270, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 5 ] ], "valid_mod_locations": [ [ "accessories", 3 ], diff --git a/data/json/items/gun/8x40mm.json b/data/json/items/gun/8x40mm.json index 5394c071d09d9..b9142e827b2e7 100644 --- a/data/json/items/gun/8x40mm.json +++ b/data/json/items/gun/8x40mm.json @@ -65,7 +65,7 @@ "dispersion": 10, "durability": 9, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 2 ] ], - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "built_in_mods": [ "riv_scope", "riv_suppressor" ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -154,7 +154,7 @@ "durability": 9, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 6 ] ], "reload": 400, - "barrel_length": "1500 ml", + "barrel_volume": "1500 ml", "valid_mod_locations": [ [ "barrel", 1 ], [ "grip", 1 ], [ "mechanism", 4 ], [ "rail", 1 ], [ "sights", 1 ], [ "sling", 1 ], [ "stock", 1 ] ], "flags": [ "WATERPROOF_GUN", "NEVER_JAMS" ], "pocket_data": [ @@ -231,7 +231,7 @@ "dispersion": 70, "durability": 9, "reload": 200, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "4 rd.", 4 ], [ "AUTO", "auto", 6 ] ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -275,7 +275,7 @@ "dispersion": 30, "durability": 9, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ], diff --git a/data/json/items/gun/9mm.json b/data/json/items/gun/9mm.json index 6c5fa335940cc..26b02aa303d26 100644 --- a/data/json/items/gun/9mm.json +++ b/data/json/items/gun/9mm.json @@ -104,7 +104,7 @@ "dispersion": 180, "durability": 10, "min_cycle_recoil": 450, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -338,7 +338,7 @@ "dispersion": 180, "durability": 7, "min_cycle_recoil": 450, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "built_in_mods": [ "folding_stock" ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -453,7 +453,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "750 ml", + "barrel_volume": "750 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], @@ -492,7 +492,7 @@ "min_cycle_recoil": 380, "modes": [ [ "DEFAULT", "burst", 5 ] ], "loudness": 25, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 3 ], [ "barrel", 1 ], diff --git a/data/json/items/gun/combination.json b/data/json/items/gun/combination.json index 8d2cf9b286f88..8e35cad95c27c 100644 --- a/data/json/items/gun/combination.json +++ b/data/json/items/gun/combination.json @@ -22,7 +22,7 @@ "blackpowder_tolerance": 56, "clip_size": 1, "loudness": 25, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "built_in_mods": [ "combination_gun_shotgun" ], "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ], "valid_mod_locations": [ diff --git a/data/json/items/gun/exodii.json b/data/json/items/gun/exodii.json index 8342b7e18ef4b..d76c98fa2fbd5 100644 --- a/data/json/items/gun/exodii.json +++ b/data/json/items/gun/exodii.json @@ -21,7 +21,7 @@ "durability": 9, "min_cycle_recoil": 3820, "modes": [ [ "DEFAULT", "auto", 2 ], [ "AUTO", "auto", 5 ] ], - "barrel_length": "1200 ml", + "barrel_volume": "1200 ml", "faults": [ "fault_gun_blackpowder", "fault_gun_dirt", "fault_gun_chamber_spent" ], "pocket_data": [ { @@ -52,7 +52,7 @@ "dispersion": 100, "durability": 8, "modes": [ [ "DEFAULT", "auto", 5 ] ], - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", diff --git a/data/json/items/gun/monster_gun.json b/data/json/items/gun/monster_gun.json index 8e0b7e9200b59..4bfc73c060e37 100644 --- a/data/json/items/gun/monster_gun.json +++ b/data/json/items/gun/monster_gun.json @@ -61,5 +61,34 @@ "range": 12, "dispersion": 150, "durability": 8 + }, + { + "id": "feral_human_thrown_rock", + "type": "GUN", + "symbol": "%", + "color": "red", + "name": { "str": "hurled rubble" }, + "description": "Stone at the ready to crush that which isn't part of the blob.", + "material": [ "stone" ], + "flags": [ + "PRIMITIVE_RANGED_WEAPON", + "NEVER_JAMS", + "NONCONDUCTIVE", + "NO_REPAIR", + "WATERPROOF_GUN", + "NO_SALVAGE", + "NO_UNLOAD", + "NO_AMMO" + ], + "skill": "throw", + "ranged_damage": { "damage_type": "bash", "amount": 1 }, + "weight": "540 g", + "volume": "750ml", + "bashing": 2, + "to_hit": 1, + "loudness": 2, + "range": 6, + "dispersion": 150, + "durability": 8 } ] diff --git a/data/json/items/gun/shot.json b/data/json/items/gun/shot.json index 82de9e4b1edb0..8a393c133a150 100644 --- a/data/json/items/gun/shot.json +++ b/data/json/items/gun/shot.json @@ -7,7 +7,8 @@ "name": { "str": "12 gauge pistol" }, "description": "A single shot pistol that loads 12 gauge shotgun shells, handcrafted from scrap.", "weight": "828 g", - "volume": "500 ml", + "volume": "800 ml", + "longest_side": "35 cm", "price": 100000, "price_postapoc": 500, "to_hit": -2, @@ -43,6 +44,7 @@ "description": "An electrically driven six barrel gatling shotgun, fed from handmade cloth belts. Even properly mounted, this seems like an unwieldy beast, and the six separate barrels make for difficult zeroing. The externally driven action means this is much less likely to jam.", "weight": "4980 g", "volume": "4500 ml", + "longest_side": "110 cm", "price": 180000, "price_postapoc": 1750, "to_hit": -2, @@ -71,9 +73,10 @@ "looks_like": "remington_870", "type": "GUN", "name": { "str": "handmade lever shotgun" }, - "description": "A short homemade lever-action shotgun with a small internal tube magazine. While still a primitive pipe and 2x4 design, it is a formiddable shotgun in it's own right with room for improvement.", + "description": "A short homemade lever-action shotgun with a small internal tube magazine. While still a primitive pipe and 2x4 design, it is a formiddable shotgun in its own right with room for improvement.", "weight": "2311 g", "volume": "2 L", + "longest_side": "85 cm", "price": 10000, "price_postapoc": 2250, "to_hit": -1, @@ -82,7 +85,7 @@ "ranged_damage": { "damage_type": "bullet", "amount": -2 }, "dispersion": 550, "durability": 6, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -107,8 +110,9 @@ "type": "GUN", "name": { "str": "Browning Auto 5" }, "description": "This humble looking shotgun was the earliest successful semi-automatic shotgun, and the second most successful in U.S. history, with over 2.7 million made between 1902 and 1998. The recoil tuning mechanism under the handguard and long dwell time of the action make for pleasant shooting.", - "weight": "4100 g", + "weight": "3090 g", "volume": "3525 ml", + "longest_side": "1263 mm", "looks_like": "remington_870", "price": 80000, "price_postapoc": 2000, @@ -131,6 +135,7 @@ "description": "A bullpup pump-action shotgun, the Kel-Tec KSG uses a pair of magazine tubes to increase its capacity. Each tube has to be loaded separately, but this offers the option of loading different ammunition for different situations.", "weight": "1550 g", "volume": "3371 ml", + "longest_side": "672 mm", "price": 99000, "price_postapoc": 2250, "to_hit": -1, @@ -166,6 +171,7 @@ "description": "A bullpup pump-action shotgun, the Kel-Tec KSG-25 uses a pair of magazine tubes to increase its capacity. Each tube has to be loaded separately, but this offers the option of loading different ammunition for different situations. The big brother of the KSG, it has a longer barrel and longer magazine tubes.", "weight": "2100 g", "volume": "4495 ml", + "longest_side": "971 mm", "price": 140000, "to_hit": -1, "bashing": 9, @@ -198,8 +204,9 @@ "type": "GUN", "name": { "str": "M1014 shotgun" }, "description": "Benelli's first gas-operated shotgun, featuring dual pistons for enhanced reliability with various loads and a collapsible buttstock that reduces length by almost 8 inches. Adopted in 1999 as the M1014 Joint Service Combat Shotgun, the Benelli M4 is one of the finest combat shotguns available.", - "weight": "3550 g", - "volume": "2500 ml", + "weight": "3629 g", + "volume": "6302 ml", + "longest_side": "1021 mm", "price": 169900, "price_postapoc": 3500, "to_hit": -1, @@ -230,13 +237,14 @@ "type": "GUN", "name": { "str_sp": "Mossberg 500 Field" }, "description": "The Mossberg 500 is a popular series of pump-action shotguns, often acquired for military use. It is noted for its high durability and low recoil. This one is fitted with a 28 inch barrel with sight rib.", - "weight": "3180 g", + "weight": "3402 g", "volume": "2450 ml", + "longest_side": "1166 mm", "price": 53800, "price_postapoc": 2250, "to_hit": -1, "bashing": 13, - "barrel_length": "186 ml", + "barrel_volume": "186 ml", "material": [ "steel", "aluminum", "plastic" ], "dispersion": 325, "ranged_damage": { "damage_type": "bullet", "amount": 4 }, @@ -252,11 +260,12 @@ "description": "The Mossberg 500 is a popular series of pump-action shotguns, often acquired for military use. It is noted for its high durability and low recoil. This one is fitted with an 18.5 inch barrel.", "weight": "3062 g", "volume": "2386 ml", + "longest_side": "1016 mm", "looks_like": "mossberg_500", "price": 53800, "price_postapoc": 2250, "bashing": 12, - "barrel_length": "28 ml", + "barrel_volume": "28 ml", "dispersion": 375, "ranged_damage": { "damage_type": "bullet", "amount": 1 } }, @@ -268,10 +277,11 @@ "description": "The Mossberg 590A1 is a military and police oriented version of the Mossberg 500. It features a heavier barrel, a bayonet lug, and a different magazine tube for easier cleaning and maintenance.", "weight": "3289 g", "volume": "2548 ml", + "longest_side": "1043 mm", "looks_like": "mossberg_500", "default_mods": [ "sights_mount", "underbarrel_mount" ], "price": 70000, - "barrel_length": "0 ml", + "barrel_volume": "0 ml", "clip_size": 9, "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 9 } } ] }, @@ -283,6 +293,7 @@ "description": "This semi-automatic offering from Mossberg features a recoil reducing gas system, rifle style sights and a factory-installed picatinny rail. Affordable pricing and decent ergonomics make this a popular entry-level 3-gun shotgun.", "weight": "3402 g", "volume": "2623 ml", + "longest_side": "994 mm", "looks_like": "m1014", "price": 60000, "price_postapoc": 2250, @@ -319,7 +330,7 @@ "clip_size": 2, "modes": [ [ "DEFAULT", "single", 1 ], [ "DOUBLE", "double", 2 ] ], "relative": { "weight": "500 g", "volume": "250 ml", "price": 5000 }, - "barrel_length": "72 ml", + "barrel_volume": "72 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "sling", 1 ], @@ -342,6 +353,7 @@ "description": "A home-made shotgun. It is simply a pipe attached to a stock, with a hammer to strike the single round it holds.", "weight": "2267 g", "volume": "2250 ml", + "longest_side": "95 cm", "price": 20000, "price_postapoc": 500, "to_hit": -1, @@ -352,7 +364,7 @@ "durability": 6, "clip_size": 1, "reload": 200, - "barrel_length": "36 ml", + "barrel_volume": "36 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "sling", 1 ], @@ -376,6 +388,7 @@ "description": "With over 10 million made, the Remington 870 is one of the most popular shotguns on the market, and finds use with hunters and law enforcement agencies alike thanks to its high accuracy and muzzle velocity. This one is a 28 inch barreled model for hunting fowl and game.", "weight": "3400 g", "volume": "2487 ml", + "longest_side": "1234 mm", "price": 58700, "price_postapoc": 2500, "to_hit": -1, @@ -385,7 +398,7 @@ "ranged_damage": { "damage_type": "bullet", "amount": 6 }, "durability": 8, "clip_size": 5, - "barrel_length": "229 ml", + "barrel_volume": "229 ml", "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 5 } } ] }, { @@ -396,6 +409,7 @@ "description": "This Remington 870 Modular Combat System shotgun is currently setup for breaching operations, with a 10 inch barrel and no stock. It is small enough to carry as a secondary weapon, specifically to pop open any pesky doors you might come across. The grip's design makes for controllable yet unpleasant recoil, and the barrel lacks any sights.", "weight": "2812 g", "volume": "1284 ml", + "longest_side": "53 cm", "looks_like": "remington_870", "ranged_damage": { "damage_type": "bullet", "amount": -5 }, "skill": "pistol", @@ -405,7 +419,7 @@ "clip_size": 4, "price": 53800, "price_postapoc": 2250, - "barrel_length": "0 ml", + "barrel_volume": "0 ml", "built_in_mods": [ "breacher_grip" ], "valid_mod_locations": [ [ "accessories", 4 ], @@ -431,11 +445,12 @@ "description": "With over 10 million made, the Remington 870 is one of the most popular shotguns on the market, and finds use with hunters and law enforcement agencies alike thanks to its high accuracy and muzzle velocity. This one is an 18.5 inch barreled defensive model.", "weight": "3402 g", "volume": "2365 ml", + "longest_side": "983 mm", "looks_like": "remington_870", "ranged_damage": { "damage_type": "bullet", "amount": 1 }, "dispersion": 345, "clip_size": 7, - "barrel_length": "20 ml", + "barrel_volume": "20 ml", "price": 33800, "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 7 } } ] }, @@ -447,6 +462,7 @@ "description": "This semi-automatic shotgun features a self compensating gas system that will feed a wide array of shells while also reducing recoil. Introduced in 1963, it is favored by law enforcement, hunters and competition shooters, and has been the best-selling autoloading shotgun in U.S. history. This is the nickel finished, teflon coated competition model, with a full length magazine tube and 30 inch barrel.", "weight": "3742 g", "volume": "2626 ml", + "longest_side": "1288 mm", "price_postapoc": 3250, "looks_like": "remington_870", "price": 130000, @@ -457,7 +473,7 @@ "ranged_damage": { "damage_type": "bullet", "amount": 6 }, "durability": 8, "clip_size": 10, - "barrel_length": "299 ml", + "barrel_volume": "299 ml", "built_in_mods": [ "match_trigger" ], "default_mods": [ "recoil_stock" ], "valid_mod_locations": [ @@ -473,7 +489,7 @@ [ "underbarrel mount", 1 ] ], "extend": { "flags": [ "RELOAD_ONE" ] }, - "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 10 } } ] + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 5 } } ] }, { "id": "revolver_shotgun", @@ -484,6 +500,7 @@ "description": "A shotgun modified to use a revolver cylinder mechanism, it can hold 6 cartridges.", "weight": "5443 g", "volume": "3 L", + "longest_side": "60 cm", "price": 75000, "price_postapoc": 1250, "to_hit": -1, @@ -493,7 +510,7 @@ "durability": 6, "clip_size": 6, "reload": 200, - "barrel_length": "36 ml", + "barrel_volume": "36 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "sling", 1 ], @@ -514,8 +531,9 @@ "type": "GUN", "name": { "str": "Saiga-12" }, "description": "The Saiga-12 is a semi-automatic shotgun designed on the same Kalashnikov pattern as the AK47 rifle. It reloads with a magazine, rather than one shell at a time like most shotguns. It is one of the last designs of Mikhail Kalashnikov, and was popular in open division shotgun competitions prior to its ban from import via executive order.", - "weight": "3600 g", - "volume": "2750 ml", + "weight": "3225 g", + "volume": "3064 ml", + "longest_side": "1068 mm", "price": 189000, "price_postapoc": 4500, "to_hit": -1, @@ -523,7 +541,7 @@ "material": [ "steel", "plastic" ], "dispersion": 395, "durability": 7, - "barrel_length": "81 ml", + "barrel_volume": "81 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "sling", 1 ], @@ -558,7 +576,7 @@ "volume": "2946 ml", "price": 39900, "price_postapoc": 2000, - "barrel_length": "234 ml", + "barrel_volume": "234 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -583,6 +601,7 @@ "description": "An old shotgun, possibly antique. It is little more than a barrel, a wood stock, and a hammer to strike the cartridge. Its simple design keeps it both light and accurate.", "weight": "2494 g", "volume": "2044 ml", + "longest_side": "95 cm", "price": 10000, "price_postapoc": 1500, "to_hit": -1, @@ -591,7 +610,7 @@ "dispersion": 210, "durability": 9, "clip_size": 1, - "barrel_length": "117 ml", + "barrel_volume": "117 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -614,8 +633,9 @@ "type": "GUN", "name": { "str": "Cobray Streetsweeper" }, "description": "Less shotgun and more comically oversized revolver, the Cobray Streetsweeper sold poorly before it was deemed a destructive device. The cylinder is driven by a clockspring, cannot be indexed by hand, and must be ejected with an ejector rod. Its unique design allows for all 12 shells to be fired in under 3 seconds, as demonstrated by the ATF technical branch.", - "weight": "419 g", + "weight": "4200 g", "volume": "3193 ml", + "longest_side": "592 mm", "looks_like": "revolver_shotgun", "price": 120000, "price_postapoc": 3500, @@ -626,7 +646,7 @@ "durability": 6, "clip_size": 12, "reload": 220, - "barrel_length": "36 ml", + "barrel_volume": "36 ml", "default_mods": [ "grip" ], "built_in_mods": [ "wire_stock" ], "modes": [ [ "DEFAULT", "single", 1 ], [ "AUTO", "3 rd.", 3 ] ], @@ -654,6 +674,7 @@ "description": "Mean and intimidating looking, the SPAS 12 has the dubious honor of being declared a destructive device and being banned from import by name, adding to its already considerable appeal. It is a combination pump-action and semi-automatic firearm, with an arm stabilizing hook for one handed shooting.", "weight": "4400 g", "volume": "2768 ml", + "longest_side": "835 mm", "looks_like": "m1014", "price": 180000, "price_postapoc": 4750, @@ -687,8 +708,9 @@ "type": "GUN", "name": { "str": "Tavor TS12" }, "description": "This is a triple tube magazine fed, gas-operated bullpup shotgun of Israeli Weapon Industries make. It is capable of loading 15 shells, all in a relatively small package. Like many other modern IWI designs, this looks more like a sci-fi prop gun than a firearm. An integral top rail is provided for mounting sights.", - "weight": "4200 g", + "weight": "3429 g", "volume": "4040 ml", + "longest_side": "725 mm", "looks_like": "ksg", "price": 180000, "price_postapoc": 5500, @@ -724,6 +746,7 @@ "description": "The USAS 12 looks like a boxy upsized caricature of the M16A2. Like its Auto Assault-12 predecessor, it is a select-fire shotgun fed from large box or drum magazines. The in-line recoil system and sheer weight make for pleasant shooting.", "weight": "5450 g", "volume": "4695 ml", + "longest_side": "962 mm", "looks_like": "saiga_12", "price": 300000, "price_postapoc": 5000, @@ -732,7 +755,7 @@ "material": [ "steel", "plastic" ], "dispersion": 510, "durability": 6, - "barrel_length": "54 ml", + "barrel_volume": "54 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "mechanism", 4 ], @@ -764,6 +787,7 @@ "description": "One of the first commercially successful repeating shotguns, the Winchester 1887 was specifically made lever-action at Winchester's request. Though later overshadowed in success by pump designs, the 1887 remains popular today. This one has a very short barrel, no stock, and would pair nicely with a motorcycle jacket and a Harley Davidson.", "weight": "2994 g", "volume": "1127 ml", + "longest_side": "708 mm", "looks_like": "browning_blr", "price": 100800, "price_postapoc": 2250, @@ -799,6 +823,7 @@ "description": "The Winchester 1897 was one of the first commercially successful pump action shotguns. In its 'trench' configuraton it has become a heavily romanticized American icon of World War 1. With its barrel shroud, bayonet lug and 17 inch bayonet, this shotgun is undeniably fearsome in appearance. There aren't any more trenches to clear, so the next zombie infested town will have to suffice.", "weight": "3629 g", "volume": "2564 ml", + "longest_side": "989 mm", "looks_like": "remington_870_express", "price": 850000, "price_postapoc": 2500, @@ -827,13 +852,14 @@ "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 6 } } ] }, { - "id": "slam_shotgun", + "id": "slamfire_shotgun", "copy-from": "shotgun_base", "type": "GUN", - "name": { "str": "makeshift shotgun" }, + "name": { "str": "slam-fire pipe shotgun" }, "description": "A crude shotgun, composed of two thick steel pipes, an end cap and a nail. The lack of sights make this weapon only useful at point-blank range.", "weight": "3629 g", "volume": "2264 ml", + "longest_side": "65 cm", "looks_like": "pipe", "price": 8500, "price_postapoc": 1000, @@ -848,5 +874,19 @@ "valid_mod_locations": [ [ "sling", 1 ], [ "sights mount", 1 ], [ "underbarrel mount", 1 ] ], "flags": [ "RELOAD_EJECT" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 1 } } ] + }, + { + "id": "slamfire_shotgun_d", + "copy-from": "slamfire_shotgun", + "type": "GUN", + "name": { "str": "double slam-fire pipe shotgun" }, + "description": "A crude shotgun, composed of four thick steel pipes, two end caps and two nails. The lack of sights make this weapon only useful at point-blank range.", + "weight": "7260 g", + "volume": "4530 ml", + "clip_size": 2, + "reload": 900, + "modes": [ [ "DEFAULT", "double", 2 ] ], + "//": "no provision for separate triggers", + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "shot": 2 } } ] } ] diff --git a/data/json/items/melee/spears_and_polearms.json b/data/json/items/melee/spears_and_polearms.json index ba1c803d2a06c..578423d3415b9 100644 --- a/data/json/items/melee/spears_and_polearms.json +++ b/data/json/items/melee/spears_and_polearms.json @@ -287,6 +287,7 @@ "description": "This is a versatile polearm with an axe blade, a spike, and other fun things attached to a long sturdy stick.", "price": 50000, "material": [ "wood", "steel" ], + "ascii_picture": "halberd", "flags": [ "DURABLE_MELEE", "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND" ], "techniques": [ "WBLOCK_1", "WIDE", "SWEEP" ], "weight": "3175 g", @@ -306,6 +307,7 @@ "description": "This is a dull, cheaply made replica of a polearm with an axe blade, a spike, and other fun things attached to a thick pole.", "price": 5000, "material": [ "wood", "aluminum" ], + "ascii_picture": "halberd", "flags": [ "REACH_ATTACK", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "ALWAYS_TWOHAND", "FRAGILE_MELEE" ], "techniques": [ "WBLOCK_1", "SWEEP" ], "weight": "1644 g", diff --git a/data/json/items/melee/swords_and_blades.json b/data/json/items/melee/swords_and_blades.json index b522cba17549d..ddfeaab699e21 100644 --- a/data/json/items/melee/swords_and_blades.json +++ b/data/json/items/melee/swords_and_blades.json @@ -1411,7 +1411,7 @@ "longest_side": "90 cm", "bashing": 17, "cutting": 8, - "to_hit": 2, + "to_hit": 1, "category": "weapons", "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 9 ] ] }, @@ -1713,6 +1713,7 @@ "price": 12000, "price_postapoc": 1250, "material": [ "wood", "iron" ], + "ascii_picture": "lajatang", "techniques": [ "WBLOCK_1", "SPIN" ], "flags": [ "DURABLE_MELEE", "NONCONDUCTIVE", "ALWAYS_TWOHAND" ], "weight": "2500 g", diff --git a/data/json/items/migration.json b/data/json/items/migration.json index 5733fd4dd7373..697712907fc35 100644 --- a/data/json/items/migration.json +++ b/data/json/items/migration.json @@ -1233,5 +1233,10 @@ "id": "carton_unsealed", "type": "MIGRATION", "replace": "carton_sealed" + }, + { + "id": "four_winds_shotgun", + "type": "MIGRATION", + "replace": "slamfire_shotgun" } ] diff --git a/data/json/items/obsolete.json b/data/json/items/obsolete.json index 156876806e8b2..51786c71aace5 100644 --- a/data/json/items/obsolete.json +++ b/data/json/items/obsolete.json @@ -2691,7 +2691,7 @@ "skill": "rifle", "dispersion": 150, "durability": 7, - "barrel_length": "250 ml", + "barrel_volume": "250 ml", "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "2 rd.", 2 ], [ "AUTO", "auto", 4 ] ], "valid_mod_locations": [ [ "accessories", 4 ], diff --git a/data/json/items/ranged/spearguns.json b/data/json/items/ranged/spearguns.json index 8c56203fdb4bb..e624d1101a5bc 100644 --- a/data/json/items/ranged/spearguns.json +++ b/data/json/items/ranged/spearguns.json @@ -11,6 +11,7 @@ "material": [ "wood" ], "volume": "250 ml", "weight": "18 g", + "longest_side": "120 cm", "bashing": 1, "ammo_type": "fishspear", "damage": { "damage_type": "stab", "amount": 12, "armor_penetration": 4 }, @@ -32,6 +33,7 @@ "material": [ "kevlar_rigid" ], "volume": "250 ml", "weight": "12 g", + "longest_side": "120 cm", "bashing": 1, "ammo_type": "fishspear", "damage": { "damage_type": "stab", "amount": 14, "armor_penetration": 12 }, @@ -53,6 +55,7 @@ "material": [ "iron" ], "volume": "250 ml", "weight": "28 g", + "longest_side": "120 cm", "bashing": 1, "ammo_type": "fishspear", "damage": { "damage_type": "stab", "amount": 14, "armor_penetration": 8 }, @@ -79,6 +82,7 @@ "ammo": [ "fishspear" ], "weight": "3460 g", "volume": "2 L", + "longest_side": "90 cm", "bashing": 8, "to_hit": -2, "ranged_damage": { "damage_type": "stab", "amount": 12 }, @@ -116,6 +120,7 @@ "ammo": [ "fishspear" ], "weight": "3060 g", "volume": "2 L", + "longest_side": "90 cm", "bashing": 8, "to_hit": -2, "ranged_damage": { "damage_type": "stab", "amount": 6 }, @@ -152,6 +157,7 @@ "ammo": [ "fishspear" ], "weight": "840 g", "volume": "1 L", + "longest_side": "35 cm", "bashing": 7, "to_hit": -2, "dispersion": 120, @@ -185,6 +191,7 @@ "ammo": [ "fishspear" ], "weight": "2100 g", "volume": "1750 ml", + "longest_side": "90 cm", "bashing": 7, "to_hit": -2, "ranged_damage": { "damage_type": "stab", "amount": 6 }, diff --git a/data/json/items/resources/alien.json b/data/json/items/resources/alien.json index 67e06a51fab9e..ca2c5fab78c0e 100644 --- a/data/json/items/resources/alien.json +++ b/data/json/items/resources/alien.json @@ -84,7 +84,7 @@ { "type": "GENERIC", "id": "exodii_module", - "name": { "str": "inscribed metal plates" }, + "name": { "str_sp": "inscribed metal plates" }, "description": "This device looks electronic, but is unfamiliar. It is a series of tightly fitted coppery-looking rings, set concentrically. Wires run from each ring to an axis in the middle.", "symbol": "i", "color": "dark_gray", @@ -119,5 +119,31 @@ "price": 2000, "material": [ "steel", "copper" ], "category": "spare_parts" + }, + { + "type": "GENERIC", + "id": "exodii_scanner_dish", + "name": { "str": "engraved parabolic dish", "str_pl": "engraved parabolic dishes" }, + "description": "This hefty parabolic dish is engraved with an unrecognizable pattern of symbols that might, at a guess, be some sort of circuitry pattern - or maybe a religious incantation.", + "symbol": "o", + "color": "blue", + "weight": "5 kg", + "volume": "1000 ml", + "price": 2000, + "material": [ "steel", "lead" ], + "category": "spare_parts" + }, + { + "type": "GENERIC", + "id": "exodii_portalizer", + "name": { "str": "oblong device" }, + "description": "Perfectly smooth, cool to the touch, and a dull blue-grey colour, this looks almost like a perfect riverstone at first glance. Its artificial nature is betrayed on closer inspection by a network of intricate patterns visible as a slight difference in the reflection of light off its surface.", + "symbol": "0", + "color": "blue", + "weight": "2 kg", + "volume": "1500 ml", + "price": 2000, + "material": [ "copper", "ceramic" ], + "category": "spare_parts" } ] diff --git a/data/json/items/tool/cooking.json b/data/json/items/tool/cooking.json index a3aa05e6f0818..12e20e5d28174 100644 --- a/data/json/items/tool/cooking.json +++ b/data/json/items/tool/cooking.json @@ -27,6 +27,8 @@ "looks_like": "knife_butcher", "weight": "1170 g", "volume": "800 ml", + "longest_side": "40 cm", + "//": "butcher knives and carving knives are between 30-40cm.", "price": 8000, "price_postapoc": 150, "qualities": [ [ "CUT", 1 ], [ "CUT_FINE", 1 ], [ "BUTCHER", 37 ] ] @@ -71,6 +73,7 @@ "description": "An electric meat carver powered by batteries. Two serrated blades that vibrate together to slice just about anything from turkey to ham… even zombies!", "weight": "1106 g", "volume": "1500 ml", + "longest_side": "30 cm", "price": 2000, "price_postapoc": 50, "bashing": 2, @@ -116,6 +119,7 @@ "description": "Using this item on a container full of water will purify the water using layered charcoal. Once the charcoal has purified enough water, it will become unusable and can be disassembled and recycled. Water taken from uncertain sources like a river may be dirty.", "weight": "1820 g", "volume": "3750 ml", + "longest_side": "30 cm", "price": 4000, "price_postapoc": 2000, "to_hit": -3, @@ -135,8 +139,9 @@ "type": "TOOL", "name": { "str": "charcoal smoker" }, "description": "This is a portable charcoal smoker. Good for weekend barbecuing and preserving meat with smoke.", - "weight": "2600 g", - "volume": "5 L", + "weight": "4000 g", + "volume": "20 L", + "longest_side": "60 cm", "price": 10000, "price_postapoc": 1500, "to_hit": -2, @@ -154,8 +159,9 @@ "type": "TOOL", "name": { "str": "charcoal cooker" }, "description": "This is a little metal tank for holding charcoal with a pilot light attached. You could use it for cooking food.", - "weight": "405 g", - "volume": "1250 ml", + "weight": "450 g", + "volume": "2 L", + "longest_side": "30 cm", "price": 5000, "price_postapoc": 250, "to_hit": -1, @@ -227,8 +233,9 @@ "type": "TOOL", "name": { "str": "coffeemaker" }, "description": "This is a heating element with pot and frame for holding coffee or other powders. It's got a battery compartment for use when the power goes out. You can use it to make coffee, or other drinks if you so choose.", - "weight": "3100 g", - "volume": "750 ml", + "weight": "1000 g", + "volume": "7 L", + "longest_side": "25 cm", "price": 2000, "price_postapoc": 50, "to_hit": -5, @@ -256,8 +263,8 @@ "type": "TOOL", "name": { "str": "food dehydrator" }, "description": "This is a portable electric food dehydrator. It's powered by batteries, and could be invaluable in preserving food.", - "weight": "4200 g", - "volume": "4500 ml", + "weight": "2500 g", + "volume": "13 L", "price": 6000, "price_postapoc": 2000, "to_hit": -2, @@ -306,8 +313,8 @@ "type": "TOOL", "name": { "str": "hexamine stove" }, "description": "Known as an Esbit stove, this is a lightweight, folding stove designed to use small hexamine tablets for cooking.", - "weight": "180 g", - "volume": "750 ml", + "weight": "92 g", + "volume": "147 ml", "price": 2000, "price_postapoc": 100, "to_hit": -1, @@ -356,8 +363,8 @@ "category": "tools", "name": { "str": "food processor" }, "description": "This is a kitchen appliance capable of slicing, chopping, shredding, grinding, pureeing and mixing.", - "weight": "3000 g", - "volume": "2 L", + "weight": "1224 g", + "volume": "5500 ml", "price": 50, "price_postapoc": 250, "to_hit": -1, @@ -383,7 +390,7 @@ "type": "TOOL", "name": { "str": "gasoline cooker" }, "description": "This is a simple heater powered by gasoline. It is designed for cooking food.", - "weight": "1944 g", + "weight": "800 g", "volume": "1250 ml", "price": 5000, "price_postapoc": 250, @@ -394,7 +401,7 @@ "color": "green", "ammo": [ "gasoline" ], "sub": "hotplate", - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "gasoline": 500 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "gasoline": 500 }, "watertight": true, "rigid": true } ], "initial_charges": 500, "max_charges": 500, "charges_per_use": 1, @@ -459,8 +466,9 @@ "type": "TOOL", "name": { "str": "hotplate" }, "description": "This is a small heating element on a stand, powered by batteries. It is indispensable for cooking and chemistry. Try not to burn yourself.", - "weight": "2835 g", - "volume": "1250 ml", + "weight": "795 g", + "volume": "5 L", + "longest_side": "35 cm", "price": 2500, "price_postapoc": 250, "to_hit": -1, @@ -556,8 +564,9 @@ "type": "TOOL", "name": { "str": "makeshift vacuum sealer" }, "description": "This is a homemade heat sealer unit with an air pump. It's used for vacuum packing food to preserve it.", - "weight": "3218 g", - "volume": "2 L", + "weight": "2000 g", + "volume": "5 L", + "longest_side": "35 cm", "price": 1000, "price_postapoc": 250, "to_hit": -1, @@ -764,7 +773,7 @@ "color": "green", "ammo": [ "lamp_oil" ], "sub": "hotplate", - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "lamp_oil": 800 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "lamp_oil": 800 }, "watertight": true, "rigid": true } ], "initial_charges": 800, "max_charges": 800, "charges_per_use": 1, @@ -776,7 +785,7 @@ "category": "tools", "name": { "str": "pasta extruder" }, "description": "A pasta extruder run by a hand-crank. Useful in making pasta. It comes with various heads to make various kinds of pasta.", - "weight": "2628 g", + "weight": "650 g", "volume": "1 L", "price": 2000, "price_postapoc": 100, @@ -826,7 +835,7 @@ "color": "light_gray", "ammo": [ "conc_alcohol" ], "sub": "hotplate", - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "conc_alcohol": 500 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "conc_alcohol": 500 }, "watertight": true, "rigid": true } ], "initial_charges": 500, "max_charges": 500, "charges_per_use": 1, @@ -954,7 +963,7 @@ "color": "brown", "ammo": [ "lamp_oil" ], "sub": "hotplate", - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "lamp_oil": 800 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "lamp_oil": 800 }, "watertight": true, "rigid": true } ], "max_charges": 800, "charges_per_use": 1, "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "CHEM", 1 ] ], @@ -983,8 +992,9 @@ "type": "TOOL", "name": { "str": "vacuum sealer" }, "description": "This is a portable heat sealer unit with an air pump. It's used for vacuum packing food to preserve it.", - "weight": "2449 g", - "volume": "1250 ml", + "weight": "1770 g", + "volume": "4100 ml", + "longest_side": "35cm", "price": 2500, "price_postapoc": 2000, "to_hit": -1, @@ -1012,7 +1022,7 @@ "name": { "str": "waffle iron" }, "description": "A waffle iron. For making waffles.", "weight": "2628 g", - "volume": "1 L", + "volume": "5 L", "price": 2000, "price_postapoc": 10, "to_hit": 2, diff --git a/data/json/items/tool/electronics.json b/data/json/items/tool/electronics.json index e687cdd3b0fde..8620d9f8e610b 100644 --- a/data/json/items/tool/electronics.json +++ b/data/json/items/tool/electronics.json @@ -3,7 +3,7 @@ "id": "adv_UPS_off", "type": "TOOL", "name": { "str": "advanced UPS", "str_pl": "advanced UPS's" }, - "description": "This is an advanced version of the unified power supply, or UPS. This device has been significantly redesigned to provide better efficiency as well as to consume plutonium fuel cells rather than batteries. Sadly, its plutonium reactor can't be charged in UPS charging station.", + "description": "This is an advanced version of the unified power supply, or UPS. This device has been significantly redesigned to provide better efficiency as well as to consume plutonium fuel batteries rather than regular batteries. Sadly, its plutonium reactor can't be charged in UPS charging station.", "weight": "453 g", "volume": "2 L", "price": 560000, @@ -13,8 +13,16 @@ "material": [ "aluminum", "plastic" ], "symbol": ";", "color": "light_green", - "ammo": [ "plutonium" ], - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "plutonium": 2500 } } ], + "ammo": [ "battery" ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "heavy_atomic_battery_cell" ] + } + ], "flags": [ "IS_UPS" ] }, { @@ -223,6 +231,7 @@ "to_hit": 1, "bashing": 5, "material": [ "plastic", "aluminum" ], + "ascii_picture": "electrohack", "symbol": ",", "color": "green", "ammo": [ "battery" ], @@ -385,6 +394,7 @@ "price": 3000, "price_postapoc": 100, "material": [ "aluminum", "plastic" ], + "ascii_picture": "mp3", "symbol": ";", "color": "dark_gray", "ammo": [ "battery" ], diff --git a/data/json/items/tool/explosives.json b/data/json/items/tool/explosives.json index 476a2192988f7..40fb855d9c7b6 100644 --- a/data/json/items/tool/explosives.json +++ b/data/json/items/tool/explosives.json @@ -673,7 +673,7 @@ "type": "TOOL", "category": "weapons", "name": { "str": "EMP grenade" }, - "description": "This is a grenade that generates an electromagnetic pulse with a low-inductance capacitor bank discharged into a single-loop antenna. Use this item to pull the pin and light the fuse, turning it into an active EMP grenade. You will then have three turns before it detonates, creating an EMP field that damages robots and drains bionic energy.", + "description": "This is a grenade that generates an electromagnetic pulse with a low-inductance capacitor bank discharged into a single-loop antenna. It also produces a mild electric shock cloud. Use this item to pull the pin and light the fuse, turning it into an active EMP grenade. You will then have three turns before it detonates, creating an EMP field that damages robots and drains bionic energy.", "weight": "400 g", "volume": "250 ml", "price": 6000, @@ -700,7 +700,7 @@ "type": "TOOL", "category": "weapons", "name": { "str": "active EMP grenade" }, - "description": "This EMP grenade is active, and will shortly detonate, creating a large EMP field that damages robots and drains bionic energy. You may not want to be holding it much longer.", + "description": "This EMP grenade is active, and will shortly detonate, creating a large EMP field that damages robots and drains bionic energy as well as a mild electric shock cloud. You may not want to be holding it much longer.", "weight": "400 g", "volume": "250 ml", "price": 0, @@ -715,8 +715,10 @@ "turns_per_charge": 1, "use_action": { "type": "explosion", - "draw_explosion_radius": 4, - "draw_explosion_color": "light_blue", + "fields_type": "fd_electricity", + "fields_radius": 2, + "fields_min_intensity": 3, + "fields_max_intensity": 3, "emp_blast_radius": 4, "sound_volume": 0, "sound_msg": "Tick.", diff --git a/data/json/items/tool/fire.json b/data/json/items/tool/fire.json index 142937578c0f3..2456464fbbc1d 100644 --- a/data/json/items/tool/fire.json +++ b/data/json/items/tool/fire.json @@ -104,7 +104,7 @@ "rand_charges": [ 1, 10, 12, 15, 16, 22, 44, 50, 67, 75, 82, 100 ], "max_charges": 100, "charges_per_use": 1, - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "butane": 100 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "butane": 100 }, "watertight": true } ], "use_action": { "type": "firestarter", "moves": 50 }, "flags": [ "FIRESTARTER", "NO_UNLOAD" ] }, @@ -139,7 +139,7 @@ "initial_charges": 20, "max_charges": 20, "charges_per_use": 1, - "pocket_data": [ { "pocket_type": "MAGAZINE", "holster": true, "ammo_restriction": { "match": 20 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "holster": true, "ammo_restriction": { "match": 20 } } ], "use_action": { "type": "firestarter", "moves": 40, "moves_slow": 1000 }, "flags": [ "FIRESTARTER", "NO_RELOAD", "NO_UNLOAD" ] }, diff --git a/data/json/items/tool/firefighting.json b/data/json/items/tool/firefighting.json index 36e62708d7c11..5525c81a809ad 100644 --- a/data/json/items/tool/firefighting.json +++ b/data/json/items/tool/firefighting.json @@ -81,7 +81,7 @@ "longest_side": "60 cm", "price": 7500, "price_postapoc": 1500, - "bashing": 40, + "bashing": 45, "cutting": 5, "material": [ "steel" ], "symbol": ";", diff --git a/data/json/items/tool/lighting.json b/data/json/items/tool/lighting.json index 3af4420f42209..0f3643b35f684 100644 --- a/data/json/items/tool/lighting.json +++ b/data/json/items/tool/lighting.json @@ -199,8 +199,8 @@ "material": [ "plastic", "aluminum" ], "symbol": ";", "color": "blue", - "weight": "400 g", - "volume": "500 ml", + "weight": "200 g", + "volume": "200 ml", "price": 500, "price_postapoc": 100, "charges_per_use": 1, diff --git a/data/json/items/tool/med.json b/data/json/items/tool/med.json index e0415752eb74d..fdde5da93823b 100644 --- a/data/json/items/tool/med.json +++ b/data/json/items/tool/med.json @@ -158,6 +158,7 @@ "price_postapoc": 10, "to_hit": -3, "material": [ "plastic" ], + "ascii_picture": "thermometer", "symbol": ";", "color": "red", "use_action": [ "WEATHER_TOOL" ], @@ -208,7 +209,7 @@ "watertight": true, "rigid": true, "max_contains_volume": "250 ml", - "max_contains_weight": "50 g" + "max_contains_weight": "262 g" } ] }, diff --git a/data/json/items/tool/misc.json b/data/json/items/tool/misc.json index dc4ce3b901890..1c3fdaecf882a 100644 --- a/data/json/items/tool/misc.json +++ b/data/json/items/tool/misc.json @@ -56,7 +56,7 @@ "volume": "500 ml", "price": 1500, "price_postapoc": 250, - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "butane": 30 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "butane": 30 }, "watertight": true, "rigid": true } ], "initial_charges": 30, "max_charges": 30, "charges_per_use": 1, @@ -253,8 +253,8 @@ "category": "tools", "name": { "str": "grappling hook" }, "description": "A folding grappling hook attached to a stout 30-foot long piece of lightweight cord. Useful for keeping yourself safe from falls. Can be used in place of a long rope for butchering, in a pinch.", - "weight": "760 g", - "volume": "750 ml", + "weight": "1980 g", + "volume": "2500 ml", "price_postapoc": 500, "to_hit": -2, "bashing": 12, @@ -264,7 +264,8 @@ "color": "light_gray", "techniques": [ "SPIN", "WRAP" ], "qualities": [ [ "COOK", 1 ] ], - "flags": [ "DURABLE_MELEE", "NONCONDUCTIVE" ] + "flags": [ "DURABLE_MELEE", "NONCONDUCTIVE" ], + "use_action": { "type": "deploy_furn", "furn_type": "f_rope_up" } }, { "type": "TOOL", @@ -808,6 +809,7 @@ "bashing": 6, "cutting": 4, "material": [ "plastic", "aluminum" ], + "ascii_picture": "umbrella", "symbol": "/", "color": "magenta", "techniques": [ "WBLOCK_1" ], diff --git a/data/json/items/tool/science.json b/data/json/items/tool/science.json index 7324786c49992..05362ab506e1a 100644 --- a/data/json/items/tool/science.json +++ b/data/json/items/tool/science.json @@ -1208,7 +1208,7 @@ "to_hit": -5, "bashing": 2, "material": [ "aluminum", "steel", "plastic" ], - "looks_like": "t_centrifuge", + "looks_like": "f_centrifuge", "symbol": "n", "color": "white", "ammo": [ "battery" ], diff --git a/data/json/items/tool/toileteries.json b/data/json/items/tool/toileteries.json index d6a91037f1cf2..b46a5b4de3307 100644 --- a/data/json/items/tool/toileteries.json +++ b/data/json/items/tool/toileteries.json @@ -90,7 +90,7 @@ "material": [ "cotton" ], "symbol": ",", "color": "white", - "use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 0.5, "limb_power": 0 }, "WASH_HARD_ITEMS" ], + "use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 5, "limb_power": 0 }, "WASH_HARD_ITEMS" ], "flags": [ "NO_SALVAGE" ] }, { @@ -182,8 +182,9 @@ "type": "TOOL", "name": { "str": "washboard" }, "description": "This is a wooden washboard. You can use it to wash filthy clothing if it's supplied with cleansing agent.", - "weight": "90 g", - "volume": "250 ml", + "weight": "786 g", + "volume": "1966 ml", + "longest_side": "40 cm", "price": 1000, "price_postapoc": 50, "to_hit": -1, @@ -198,8 +199,9 @@ "type": "TOOL", "name": { "str": "washing kit" }, "description": "A combination kit of a washboard and a scrubbing tool. Everything you need to clean items after the apocalypse.", - "weight": "100 g", - "volume": "275 ml", + "weight": "866 g", + "volume": "2246 ml", + "longest_side": "40 cm", "price": 0, "price_postapoc": 50, "material": [ "wood", "plastic" ], diff --git a/data/json/items/tool/traps.json b/data/json/items/tool/traps.json index a26f41f8db1d1..e44491720afa0 100644 --- a/data/json/items/tool/traps.json +++ b/data/json/items/tool/traps.json @@ -210,16 +210,16 @@ "id": "shotgun_trap", "type": "TOOL", "name": { "str": "shotgun trap" }, - "description": "This is a simple tripwire is attached to the trigger of a loaded double-barreled shotgun. When pulled, the shotgun fires. Two shells are loaded; the first time the trigger is pulled, one or both shells may be discharged.", + "description": "This is a simple tripwire is attached to the trigger of a loaded double slamfire shotgun. When pulled, the shotgun fires. Two shells are loaded; the first time the trigger is pulled, one or both shells may be discharged.", "weight": "2922 g", "volume": "1750 ml", "price": 25000, "price_postapoc": 1000, "to_hit": -2, "bashing": 12, - "material": [ "steel", "wood" ], + "material": [ "steel" ], "symbol": ";", - "color": "brown", + "color": "dark_gray", "use_action": { "type": "place_trap", "trap": "tr_shotgun_2", diff --git a/data/json/items/tool/woodworking.json b/data/json/items/tool/woodworking.json index a20dabbe0f7c8..d2af6062b9bab 100644 --- a/data/json/items/tool/woodworking.json +++ b/data/json/items/tool/woodworking.json @@ -32,7 +32,7 @@ "symbol": "/", "color": "red", "ammo": [ "gasoline" ], - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "gasoline": 450 } } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "gasoline": 450 }, "watertight": true, "rigid": true } ], "charges_per_use": 5, "max_charges": 450, "techniques": [ "SWEEP" ], diff --git a/data/json/items/tool/workshop.json b/data/json/items/tool/workshop.json index ed256a47020e6..28322a5f4e7b1 100644 --- a/data/json/items/tool/workshop.json +++ b/data/json/items/tool/workshop.json @@ -339,8 +339,8 @@ "volume": "500 ml", "price": 200, "price_postapoc": 100, - "to_hit": 3, - "bashing": 4, + "to_hit": -1, + "bashing": 2, "material": [ "rubber" ], "symbol": ",", "color": "green", diff --git a/data/json/items/tool_armor.json b/data/json/items/tool_armor.json index a0a718705bb39..9cd31dec4a587 100644 --- a/data/json/items/tool_armor.json +++ b/data/json/items/tool_armor.json @@ -33,6 +33,60 @@ "encumbrance": 140, "flags": [ "OVERSIZE", "WATER_FRIENDLY", "OUTER", "SPLINT" ] }, + { + "id": "tourniquet_upper", + "type": "ARMOR", + "name": { "str": "tourniquet (arm)", "str_pl": "tourniquets (arm)" }, + "description": "First aid device used to apply pressure to a limb or extremity in order to limit blood flow. Should be employed only to manage heavy bleedings, because prolonged use will harm the limb. It can be adjusted in size to fit different limbs.", + "weight": "300 g", + "volume": "300 ml", + "price": 20000, + "price_postapoc": 50, + "material": [ "wood", "leather" ], + "symbol": "{", + "looks_like": "armguard_hard", + "color": "red", + "covers": [ "ARM_EITHER" ], + "coverage": 10, + "encumbrance": 70, + "warmth": 0, + "material_thickness": 1, + "use_action": { "target": "tourniquet_upper_XL", "msg": "You adjust the tourniquet.", "menu_text": "Adjust", "type": "transform" }, + "flags": [ "WATER_FRIENDLY", "OUTER", "TOURNIQUET" ] + }, + { + "id": "tourniquet_upper_XL", + "type": "ARMOR", + "name": { "str": "tourniquet (arm XL)", "str_pl": "tourniquets (arm XL)" }, + "description": "First aid device used to apply pressure to a limb or extremity in order to limit blood flow. Should be employed only to manage heavy bleedings, because prolonged use will harm the limb. It can be adjusted in size to fit different limbs.", + "copy-from": "tourniquet_upper", + "looks_like": "tourniquet_upper", + "covers": [ "ARM_EITHER" ], + "use_action": { "target": "tourniquet_lower", "msg": "You adjust the tourniquet.", "menu_text": "Adjust", "type": "transform" }, + "flags": [ "WATER_FRIENDLY", "OUTER", "TOURNIQUET", "OVERSIZE" ] + }, + { + "id": "tourniquet_lower", + "type": "ARMOR", + "name": { "str": "tourniquet (leg)", "str_pl": "tourniquets (leg)" }, + "description": "First aid device used to apply pressure to a limb or extremity in order to limit blood flow. Should be employed only to manage heavy bleedings, because prolonged use will harm the limb. It can be adjusted in size to fit different limbs.", + "copy-from": "tourniquet_upper", + "looks_like": "tourniquet_upper", + "covers": [ "LEG_EITHER" ], + "use_action": { "target": "tourniquet_lower_XL", "msg": "You adjust the tourniquet.", "menu_text": "Adjust", "type": "transform" }, + "flags": [ "WATER_FRIENDLY", "OUTER", "TOURNIQUET" ] + }, + { + "id": "tourniquet_lower_XL", + "type": "ARMOR", + "name": { "str": "tourniquet (leg)", "str_pl": "tourniquets (leg)" }, + "description": "First aid device used to apply pressure to a limb or extremity in order to limit blood flow. Should be employed only to manage heavy bleedings, because prolonged use will harm the limb. It can be adjusted in size to fit different limbs.", + "copy-from": "tourniquet_upper", + "looks_like": "tourniquet_upper", + "covers": [ "LEG_EITHER" ], + "use_action": { "target": "tourniquet_upper", "msg": "You adjust the tourniquet.", "menu_text": "Adjust", "type": "transform" }, + "flags": [ "WATER_FRIENDLY", "OUTER", "TOURNIQUET", "OVERSIZE" ] + }, { "id": "blindfold", "type": "ARMOR", @@ -365,8 +419,17 @@ "covers": [ "TORSO", "HEAD", "ARMS", "LEGS" ], "coverage": 65, "encumbrance": 10, - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "plutonium": 1000 } } ], - "ammo": "plutonium", + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "light_atomic_battery_cell" ] + } + ], + "ammo": "battery", "initial_charges": 500, "charges_per_use": 25, "warmth": 10, @@ -876,7 +939,7 @@ "symbol": "[", "color": "dark_gray", "name": { "str": "RM13 combat armor" }, - "description": "Internally powered by a maximum of ten plutonium fuel cells, this full-body suit of sleek black military armor represents the pinnacle of Rivtech's non-rigid powered armor technology. Use it to turn it on.", + "description": "Internally powered by plutonium fuel batteries, exclusively, this full-body suit of sleek black military armor represents the pinnacle of Rivtech's non-rigid powered armor technology. Use it to turn it on.", "flags": [ "VARSIZE", "STURDY", "WATERPROOF", "RAINPROOF", "WATCH", "ALARMCLOCK", "SWIM_GOGGLES", "SUN_GLASSES", "RAD_RESIST" ], "price": 50000000, "price_postapoc": 10000, @@ -884,8 +947,17 @@ "weight": "6820 g", "volume": "9 L", "to_hit": -3, - "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "plutonium": 5000 } } ], - "ammo": "plutonium", + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "heavy_atomic_battery_cell" ] + } + ], + "ammo": "battery", "charges_per_use": 5, "use_action": [ "RM13ARMOR_OFF" ], "covers": [ "HEAD", "MOUTH", "EYES", "TORSO", "ARMS", "HANDS", "LEGS", "FEET" ], @@ -901,7 +973,7 @@ "repairs_like": "rm13_armor", "type": "TOOL_ARMOR", "name": { "str": "RM13 combat armor (on)", "str_pl": "RM13 combat armors (on)" }, - "description": "Internally powered by a maximum of ten plutonium fuel cells, this full-body suit of sleek black military armor represents the pinnacle of Rivtech's non-rigid powered armor technology. It is turned on, and continually draining power. Use it to turn it off.", + "description": "Internally powered by plutonium fuel batteries, exclusively, this full-body suit of sleek black military armor represents the pinnacle of Rivtech's non-rigid powered armor technology. It is turned on, and continually draining power. Use it to turn it off.", "flags": [ "VARSIZE", "STURDY", @@ -939,8 +1011,17 @@ "material": [ "ceramic", "kevlar" ], "weight": "1250 g", "volume": "4500 ml", - "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "plutonium": 1000 } } ], - "ammo": "plutonium", + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "medium_atomic_battery_cell" ] + } + ], + "ammo": "battery", "initial_charges": 1000, "use_action": { "type": "transform", @@ -990,8 +1071,17 @@ "material": [ "carbide" ], "weight": "1250 g", "volume": "4500 ml", - "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "plutonium": 2500 } } ], - "ammo": "plutonium", + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "heavy_atomic_battery_cell" ] + } + ], + "ammo": "battery", "initial_charges": 1000, "use_action": { "type": "transform", @@ -1878,10 +1968,11 @@ "material_thickness": 2, "pocket_data": [ { - "pocket_type": "CONTAINER", + "holster": true, "min_item_volume": "250 ml", "max_contains_volume": "1 L", - "max_contains_weight": "1 kg", + "max_contains_weight": "2 kg", + "max_item_length": "70 cm", "moves": 3, "flag_restriction": [ "SHEATH_KNIFE", "SHEATH_SWORD" ] } @@ -2871,7 +2962,7 @@ "id": "solarpack", "type": "TOOL_ARMOR", "name": { "str": "solar backpack (folded)", "str_pl": "solar backpacks (folded)" }, - "description": "Personal portable charging system consisting of an array of solar panels neatly folded in a form of a large backpack. It can be worn as one, and has an integrated cable to plug it into a cable charger system.", + "description": "Personal portable charging system consisting of an array of solar panels neatly folded in a form of a large backpack. It can be worn as one, and has an integrated cable to plug it into a cable charger system CBM.", "weight": "7500 g", "volume": "5 L", "price": 500000, @@ -2893,7 +2984,7 @@ "type": "TOOL_ARMOR", "repairs_like": "solarpack", "name": { "str": "solar backpack (unfolded)", "str_pl": "solar backpacks (unfolded)" }, - "description": "Unfolded array of portable solar panels ready to push some power into an active cable charger system.", + "description": "Unfolded array of portable solar panels ready to push some power into an active cable charger system CBM.", "weight": "7500 g", "volume": "15 L", "price": 500000, diff --git a/data/json/items/toolmod.json b/data/json/items/toolmod.json index 75cb729e61490..2c843e8380ba5 100644 --- a/data/json/items/toolmod.json +++ b/data/json/items/toolmod.json @@ -28,6 +28,14 @@ "description": "A battery compartment mod that allows using vehicle batteries and small storage batteries in regular tools.", "color": "light_green", "acceptable_ammo": [ "battery" ], + "pocket_mods": [ + { + "pocket_type": "MAGAZINE_WELL", + "item_restriction": [ "small_storage_battery", "battery_car", "battery_motorbike" ], + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg" + } + ], "magazine_adaptor": [ [ "battery", [ "small_storage_battery", "battery_car", "battery_motorbike" ] ] ] }, { @@ -39,6 +47,22 @@ "description": "A battery compartment mod that allows the use of light batteries in tools that otherwise could not.", "color": "light_green", "acceptable_ammo": [ "battery" ], + "pocket_mods": [ + { + "pocket_type": "MAGAZINE_WELL", + "item_restriction": [ + "light_minus_battery_cell", + "light_minus_atomic_battery_cell", + "light_minus_disposable_cell", + "light_battery_cell", + "light_plus_battery_cell", + "light_atomic_battery_cell", + "light_disposable_cell" + ], + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg" + } + ], "magazine_adaptor": [ [ "battery", @@ -63,6 +87,14 @@ "description": "A battery compartment mod that allows the use of medium batteries in tools that otherwise could not.", "color": "light_green", "acceptable_ammo": [ "battery" ], + "pocket_mods": [ + { + "pocket_type": "MAGAZINE_WELL", + "item_restriction": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg" + } + ], "magazine_adaptor": [ [ "battery", @@ -79,6 +111,14 @@ "description": "A battery compartment mod that allows the use of heavy batteries in tools that otherwise could not.", "color": "light_green", "acceptable_ammo": [ "battery" ], + "pocket_mods": [ + { + "pocket_type": "MAGAZINE_WELL", + "item_restriction": [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ], + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg" + } + ], "magazine_adaptor": [ [ "battery", [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ] ] ] diff --git a/data/json/mapgen/Glassblower.json b/data/json/mapgen/Glassblower.json index 420d56b1095c0..29ac505654610 100644 --- a/data/json/mapgen/Glassblower.json +++ b/data/json/mapgen/Glassblower.json @@ -35,15 +35,15 @@ "terrain": { ".": "t_floor", "s": "t_sidewalk", - "u": "t_dirt", + "u": "t_region_groundcover_barren", "_": "t_pavement", "U": "t_pavement", - " ": [ "t_grass", "t_dirt" ], - "H": "t_grass", - "1": "t_shrub_hydrangea", - "2": [ "t_tree_walnut", "t_tree_apple" ], - "4": "t_underbrush", - "5": "t_grass", + " ": "t_region_groundcover_urban", + "H": "t_region_groundcover_urban", + "1": "t_region_shrub_decorative", + "2": "t_region_tree_fruit", + "4": "t_region_shrub", + "5": "t_region_groundcover_urban", "-": "t_wall_glass", "|": "t_rock_wall", "%": "t_wall_wood", @@ -55,7 +55,6 @@ "x": "t_window_no_curtains", "v": "t_window_domestic", "c": "t_floor", - "C": "t_console_broken", "L": "t_thconc_floor", "'": "t_thconc_floor", "Q": "t_thconc_floor", @@ -76,6 +75,7 @@ "<": "t_stairs_up" }, "furniture": { + "C": "f_console_broken", "H": "f_bench", "S": "f_sink", "T": "f_stool", @@ -94,7 +94,7 @@ "q": "f_crate_c", "E": "f_displaycase", "U": "f_dumpster", - "5": [ "f_flower_tulip", "f_bluebell", "f_dandelion" ], + "5": "f_region_weed", "z": "f_cupboard", "d": "f_dresser", "@": "f_bed", diff --git a/data/json/mapgen/Metalworker.json b/data/json/mapgen/Metalworker.json index 3c21c9f55c07c..1f8f6889cc198 100644 --- a/data/json/mapgen/Metalworker.json +++ b/data/json/mapgen/Metalworker.json @@ -46,13 +46,13 @@ "U": "t_pavement", "2": "t_pavement", ".": "t_strconc_floor", - "3": "t_machinery_heavy", - "1": "t_machinery_old", "#": "t_strconc_floor", "<": "t_ladder_up", "4": "t_gutter_downspout" }, "furniture": { + "3": "f_machinery_heavy", + "1": "f_machinery_old", "H": "f_bench", "S": "f_sink", "#": "f_stool", diff --git a/data/json/mapgen/Pottery_Sewing_Shops.json b/data/json/mapgen/Pottery_Sewing_Shops.json index 3691f3f517911..b4251b73fb3ba 100644 --- a/data/json/mapgen/Pottery_Sewing_Shops.json +++ b/data/json/mapgen/Pottery_Sewing_Shops.json @@ -39,14 +39,14 @@ "_": "t_pavement", "U": "t_pavement", ",": "t_pavement_y", - ";": "t_grass", - "H": "t_grass", - "b": "t_grass", - "1": "t_shrub_hydrangea", - "2": "t_tree_walnut", - "3": "t_tree_apple", - "4": "t_underbrush", - "5": "t_grass", + ";": "t_region_groundcover_urban", + "H": "t_region_groundcover_urban", + "b": "t_region_groundcover_urban", + "1": "t_region_shrub_decorative", + "2": "t_region_tree_nut", + "3": "t_region_tree_fruit", + "4": "t_region_shrub", + "5": "t_region_groundcover_urban", "-": "t_wall_glass", "|": "t_brick_wall", "+": "t_door_glass_c", @@ -54,7 +54,6 @@ "S": "t_linoleum_gray", "w": "t_linoleum_gray", "t": "t_linoleum_gray", - "C": "t_console_broken", "*": "t_thconc_floor", "Q": "t_thconc_floor", "Y": "t_thconc_floor", @@ -66,6 +65,7 @@ "<": "t_stairs_up" }, "furniture": { + "C": "f_console_broken", "H": "f_bench", "S": "f_sink", "T": "f_stool", diff --git a/data/json/mapgen/airport/s_airport_private.json b/data/json/mapgen/airport/s_airport_private.json index 0a06dc150c0a9..b557bce2ff983 100644 --- a/data/json/mapgen/airport/s_airport_private.json +++ b/data/json/mapgen/airport/s_airport_private.json @@ -52,7 +52,6 @@ "+": "t_door_c", ")": "t_door_glass_c", "d": "t_conveyor", - "j": "t_console_broken", "c": "t_chainfence", "<": "t_stairs_up", "^": "t_gutter_downspout", @@ -60,7 +59,7 @@ "|": "t_wall_metal", "Q": "t_metal_floor", "q": "t_pavement", - "e": "t_machinery_light", + "e": "t_thconc_floor", "1": "t_gas_pump", "2": "t_water_pump", "3": "t_sewage_pipe", @@ -69,15 +68,18 @@ "f": "t_thconc_floor", "=": "t_door_metal_locked", "&": "t_gates_control_metal", - "4": "t_generator_broken" + "4": "t_region_groundcover_urban" }, "furniture": { + "4": "f_generator_broken", "q": "f_dumpster", + "e": "f_machinery_light", "f": "f_locker", "g": "f_crate_o", "h": "f_bench", "I": "f_desk", "i": "f_counter", + "j": "f_console_broken", "J": "f_counter", "k": "f_table", "l": "f_trashcan", @@ -278,11 +280,10 @@ " ": "t_open_air", "d": "t_stairs_down", ".": "t_linoleum_white", - "f": "t_console_broken", "g": "t_door_glass_c", "h": "t_metal_floor" }, - "furniture": { "e": "f_table", "E": "f_chair" }, + "furniture": { "f": "f_console_broken", "e": "f_table", "E": "f_chair" }, "place_loot": [ { "group": "office_mess", "chance": 80, "repeat": [ 5 ], "x": [ 10, 13 ], "y": [ 2, 5 ] } ] } } diff --git a/data/json/mapgen/animalpound.json b/data/json/mapgen/animalpound.json index 309f487b88a63..29bea45bf1b3d 100644 --- a/data/json/mapgen/animalpound.json +++ b/data/json/mapgen/animalpound.json @@ -63,16 +63,15 @@ "terrain": { " ": "t_pavement", ",": "t_pavement_y", - "%": "t_console_broken", - "*": "t_shrub", + "*": "t_region_shrub", "+": "t_door_c", "M": "t_door_metal_pickable", "i": "t_door_locked_interior", "-": "t_wall_w", ".": "t_floor", "<": "t_stairs_up", - "=": "t_chainfence_h", - "|": "t_chainfence_v", + "=": "t_chainfence", + "|": "t_chainfence", "a": "t_chaingate_l", "l": "t_linoleum_white", "#": "t_linoleum_white", @@ -82,11 +81,12 @@ "k": "t_linoleum_white", "F": "t_linoleum_white", "Q": "t_linoleum_white", - "'": "t_grass", + "'": "t_region_groundcover_urban", "4": "t_gutter_downspout", "~": "t_sidewalk" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "C": "f_counter", "D": "f_trashcan", diff --git a/data/json/mapgen/animalshelter.json b/data/json/mapgen/animalshelter.json index b687d960f15a6..0e8a317ae1f9c 100644 --- a/data/json/mapgen/animalshelter.json +++ b/data/json/mapgen/animalshelter.json @@ -9,7 +9,8 @@ "type": "item_group", "subtype": "distribution", "entries": [ - { "item": "bandages", "prob": 50 }, + { "item": "bandages", "prob": 25 }, + { "item": "adhesive_bandages", "prob": 25 }, { "item": "saline", "prob": 20 }, { "item": "vitamins", "prob": 15 }, { "item": "calcium_tablet", "prob": 15 }, @@ -183,8 +184,7 @@ " ": "t_pavement", ",": "t_pavement_y", "g": "t_wall_glass", - "%": "t_console_broken", - "*": "t_shrub", + "*": "t_region_shrub", "+": "t_door_c", "-": "t_wall_b", ".": "t_floor", @@ -193,8 +193,8 @@ "3": "t_privacy_fencegate_c", "O": "t_window", "^": "t_chaingate_c", - "'": "t_dirt", - "G": "t_grass", + "'": "t_region_groundcover_barren", + "G": "t_region_groundcover", "M": "t_door_metal_pickable", "i": "t_door_locked_interior", "l": "t_linoleum_white", @@ -203,14 +203,15 @@ "s": "t_linoleum_white", "t": "t_linoleum_white", "F": "t_linoleum_white", - "f": "t_dirt", - "R": "t_dirt", - "Q": "t_dirt", + "f": "t_region_groundcover_barren", + "R": "t_region_groundcover_barren", + "Q": "t_region_groundcover_barren", "4": "t_gutter_downspout", "<": "t_ladder_up", "~": "t_sidewalk" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "?": "f_sofa", "Q": "f_trashcan", diff --git a/data/json/mapgen/bank.json b/data/json/mapgen/bank.json index eeeda76784284..4afd3879ba5a6 100644 --- a/data/json/mapgen/bank.json +++ b/data/json/mapgen/bank.json @@ -33,15 +33,14 @@ " " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt", "t_shrub" ], + " ": [ [ "t_region_groundcover_urban", 10 ], "t_region_shrub_decorative" ], "#": "t_wall_w", "$": "t_metal_floor", - "%": [ "t_door_c", "t_door_c", "t_door_locked_interior" ], - "*": [ "t_door_c", "t_door_c", "t_door_c", "t_door_locked_interior" ], + "%": [ [ "t_door_c", 2 ], "t_door_locked_interior" ], + "*": [ [ "t_door_c", 3 ], "t_door_locked_interior" ], "+": "t_door_c", "-": "t_window", ".": "t_floor", - "6": "t_console", "A": "t_atm", "G": "t_door_glass_c", "M": "t_door_metal_locked", @@ -53,6 +52,7 @@ "w": "t_window_alarm" }, "furniture": { + "6": "f_console", "$": "f_safe_l", "C": "f_chair", "T": "f_table", @@ -168,19 +168,17 @@ "########4 " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", "_": "t_metal_floor", - "|": [ "t_door_c", "t_wall_w", "t_wall_w", "t_wall_w", "t_wall_w", "t_wall_w", "t_wall_w", "t_wall_w", "t_wall_w" ], + "|": [ "t_door_c", [ "t_wall_w", 7 ] ], "I": "t_wall_w", "#": "t_brick_wall", "$": "t_metal_floor", - "%": [ "t_door_c", "t_door_c", "t_door_locked_interior" ], - "*": [ "t_door_c", "t_door_c", "t_door_c", "t_door_locked_interior" ], + "%": [ [ "t_door_c", 2 ], "t_door_locked_interior" ], + "*": [ [ "t_door_c", 3 ], "t_door_locked_interior" ], "+": "t_door_c", "-": "t_window", - "x": "t_console_broken", ".": "t_floor", - "6": "t_console", "A": "t_atm", "G": "t_door_glass_c", "M": "t_door_metal_locked", @@ -194,6 +192,8 @@ "w": "t_window_alarm" }, "furniture": { + "x": "f_console_broken", + "6": "f_console", "a": "f_armchair", "D": "f_sofa", "o": "f_bookcase", diff --git a/data/json/mapgen/bar.json b/data/json/mapgen/bar.json index 9dd8bbc7ff3c9..5dac3ab2e5d15 100644 --- a/data/json/mapgen/bar.json +++ b/data/json/mapgen/bar.json @@ -45,7 +45,6 @@ ",": "t_pavement_y", "-": "t_wall_g", ".": "t_floor", - "@": "t_console_broken", "D": "t_door_locked", "c": "t_linoleum_gray", "d": "t_pavement", @@ -60,6 +59,7 @@ "|": "t_wall_g" }, "furniture": { + "@": "f_console_broken", "#": "f_table", "&": "f_fridge", "B": "f_bench", @@ -195,7 +195,7 @@ "terrain": { "_": "t_pavement", "~": "t_sidewalk", - " ": [ "t_grass", "t_grass", "t_dirt", "t_shrub", "t_grass", "t_dirt" ], + " ": [ [ "t_region_groundcover_urban", 10 ], "t_region_shrub" ], "&": "t_linoleum_gray", "'": "t_window_domestic", "+": "t_door_c", @@ -203,7 +203,6 @@ "-": "t_wall_b", ".": "t_floor", "u": "t_floor", - "@": "t_console_broken", "D": "t_door_locked", "c": "t_linoleum_gray", "d": "t_pavement", @@ -222,6 +221,7 @@ "!": "t_brick_wall" }, "furniture": { + "@": "f_console_broken", "#": "f_table", "$": "f_glass_fridge", "&": "f_fridge", diff --git a/data/json/mapgen/basecamps/primitive_field.json b/data/json/mapgen/basecamps/primitive_field.json index 11b00664b0a4d..546283b93947d 100644 --- a/data/json/mapgen/basecamps/primitive_field.json +++ b/data/json/mapgen/basecamps/primitive_field.json @@ -1405,7 +1405,7 @@ "method": "json", "object": { "set": [ - { "point": "terrain", "id": "t_machinery_old", "x": 5, "y": 12 }, + { "point": "furniture", "id": "f_machinery_old", "x": 5, "y": 12 }, { "point": "furniture", "id": "f_wood_keg", "x": 14, "y": 12 }, { "point": "terrain", "id": "t_dirt", "x": 18, "y": 16 }, { "point": "furniture", "id": "f_kiln_empty", "x": 19, "y": 16 }, diff --git a/data/json/mapgen/basement/basement_bionic.json b/data/json/mapgen/basement/basement_bionic.json index 729e4d713465f..c89d9178d2f22 100644 --- a/data/json/mapgen/basement/basement_bionic.json +++ b/data/json/mapgen/basement/basement_bionic.json @@ -37,8 +37,8 @@ "furniture": { "}": "f_pinball_machine", "*": "f_shower", - "!": "f_ergometer", - "@": "f_treadmill", + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "@": [ "f_treadmill", "f_treadmill_mechanical" ], "^": "f_exercise", "%": "f_floor_canvas", "C": "f_cupboard", @@ -113,8 +113,8 @@ "furniture": { "}": "f_pinball_machine", "*": "f_shower", - "!": "f_ergometer", - "@": "f_treadmill", + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "@": [ "f_treadmill", "f_treadmill_mechanical" ], "^": "f_exercise", "%": "f_floor_canvas", "C": "f_cupboard", diff --git a/data/json/mapgen/basement/basement_chem.json b/data/json/mapgen/basement/basement_chem.json index 2d03a8496316c..f92fe66b0c711 100644 --- a/data/json/mapgen/basement/basement_chem.json +++ b/data/json/mapgen/basement/basement_chem.json @@ -46,7 +46,6 @@ "E": "t_linoleum_gray", "i": "t_linoleum_gray", "H": "t_linoleum_gray", - "4": "t_machinery_old", "R": "t_linoleum_gray", "?": "t_linoleum_gray", "h": "t_linoleum_gray", @@ -55,6 +54,7 @@ }, "liquids": { "E": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, "furniture": { + "4": "f_machinery_old", "T": "f_workbench", "c": "f_counter", "h": "f_chair", @@ -147,7 +147,7 @@ "n": "t_linoleum_white", "H": "t_linoleum_white", "T": "t_linoleum_white", - "8": "t_console_broken" + "8": "t_linoleum_white" }, "liquids": { "E": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, "furniture": { @@ -169,7 +169,8 @@ "f": "f_filing_cabinet", "5": "f_server", "b": "f_lab_bench", - "D": "f_fume_hood" + "D": "f_fume_hood", + "8": "f_console_broken" }, "items": { "U": [ diff --git a/data/json/mapgen/basement/basement_lab_stairs.json b/data/json/mapgen/basement/basement_lab_stairs.json index 737cd0c70ad70..c96167458cd9c 100644 --- a/data/json/mapgen/basement/basement_lab_stairs.json +++ b/data/json/mapgen/basement/basement_lab_stairs.json @@ -40,10 +40,10 @@ ",": "t_rock_floor", "6": "t_card_science", "7": "t_rock_floor", - "C": "t_centrifuge", "<": "t_stairs_up", ">": "t_stairs_down" }, + "furniture": { "C": "f_centrifuge" }, "mapping": { "c": { "items": { "item": "chem_lab", "chance": 30 } }, "d": { "items": { "item": "office", "chance": 30 } } }, "monster": { "7": { "monster": "mon_turret_rifle" } }, "place_nested": [ diff --git a/data/json/mapgen/bridges.json b/data/json/mapgen/bridges.json new file mode 100644 index 0000000000000..726f5d1c3fbb2 --- /dev/null +++ b/data/json/mapgen/bridges.json @@ -0,0 +1,182 @@ +[ + { + "type": "palette", + "id": "bridge_ground_palette", + "terrain": { + "s": "t_water_moving_sh", + "~": "t_water_moving_dp", + ".": "t_pavement_bg_dp", + ":": "t_pavement_y_bg_dp", + "_": "t_sidewalk_bg_dp", + "=": "t_guardrail_bg_dp", + "u": "t_ramp_up_low", + "U": "t_ramp_up_high", + "d": "t_ramp_down_high", + "D": "t_ramp_down_low", + "W": "t_sidewalk_ramp_down_high", + ">": "t_sidewalk_ramp_down_low", + "<": "t_sidewalk_ramp_up_high", + "w": "t_sidewalk_ramp_up_low", + "#": "t_concrete_wall" + } + }, + { + "type": "palette", + "id": "bridge_road_palette", + "terrain": { + " ": "t_open_air", + ".": "t_pavement_hw_air", + ":": "t_pavement_y_hw_air", + "_": "t_sidewalk_hw_air", + "=": "t_guardrail_hw_air", + "U": "t_ramp_up_high", + "d": "t_ramp_down_high", + "D": "t_ramp_down_low", + "W": "t_sidewalk_ramp_down_high", + ">": "t_sidewalk_ramp_down_low", + "<": "t_sidewalk_ramp_up_high", + "w": "t_sidewalk_ramp_up_low", + "#": "t_concrete_wall" + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "bridge" ], + "object": { + "fill_ter": "t_water_moving_dp", + "rows": [ + "~~~~~~~~s######s~~~~~~~~", + "~~~~~~~~ss####ss~~~~~~~~", + "~~~~~~~~~ss##ss~~~~~~~~~", + "~~~~~~~~~~ssss~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~ssss~~~~~~~~~~", + "~~~~~~~~~ss##ss~~~~~~~~~", + "~~~~~~~~ss####ss~~~~~~~~", + "~~~~~~~~s######s~~~~~~~~" + ], + "palettes": [ "bridge_ground_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "bridge_road" ], + "object": { + "fill_ter": "t_open_air", + "rows": [ + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= " + ], + "palettes": [ "bridge_road_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "bridgehead_ground" ], + "object": { + "fill_ter": "t_water_moving_dp", + "rows": [ + "ss=_................_=ss", + "ss=_.......::......._=ss", + "ss=_.......::......._=ss", + "ss=_.......::......._=ss", + "ss=_................_=ss", + "ss=wuuuuuuuuuuuuuuuuw=ss", + "ss=DDDDDDDDDDDDDDDD>= ", + " =WddddddddddddddddW= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_................_= ", + " =_.......::......._= ", + " =_.......::......._= ", + " =_.......::......._= " + ], + "palettes": [ "bridge_road_palette" ] + } + } +] diff --git a/data/json/mapgen/bus_station.json b/data/json/mapgen/bus_station.json index d5fddf6d9b327..7306918e52662 100644 --- a/data/json/mapgen/bus_station.json +++ b/data/json/mapgen/bus_station.json @@ -35,21 +35,14 @@ "terrain": { " ": "t_floor", "+": "t_door_c", - ".": [ [ "t_dirt", 5 ], [ "t_grass", 16 ], [ "t_grass_long", 5 ] ], + ".": "t_region_groundcover_urban", ",": [ - [ "t_grass_long", 35 ], - [ "t_grass", 20 ], - [ "t_shrub", 20 ], - [ "t_shrub_rose", 20 ], - [ "t_shrub_lilac", 20 ], - [ "t_tree_young", 20 ], - [ "t_grass_tall", 20 ], - [ "t_grass_long", 20 ], - [ "t_underbrush", 20 ], - [ "t_shrub_hydrangea", 20 ], - [ "t_shrub_raspberry", 20 ] + [ "t_region_groundcover", 35 ], + [ "t_region_groundcover_forest", 20 ], + [ "t_region_shrub_decorative", 20 ], + [ "t_region_shrub_fruit", 10 ] ], - ";": [ [ "t_tree", 5 ], [ "t_tree_willow", 3 ], [ "t_tree_birch", 3 ], [ "t_tree_maple", 3 ], [ "t_tree_pine", 5 ] ], + ";": "t_region_tree_shade", "w": "t_window", "_": "t_pavement", "y": "t_pavement_y", @@ -64,12 +57,13 @@ "T": "t_linoleum_white", "F": "t_linoleum_white", "l": "t_linoleum_white", - "x": "t_console_broken", + "x": "t_linoleum_white", "i": "t_ladder_up", "I": "t_column", "f": "t_chainfence" }, "furniture": { + "x": "f_console_broken", "c": "f_counter", "S": "f_sink", "B": "f_bench", diff --git a/data/json/mapgen/butcher.json b/data/json/mapgen/butcher.json index 97e152a42b57e..0744d84e5efac 100644 --- a/data/json/mapgen/butcher.json +++ b/data/json/mapgen/butcher.json @@ -32,24 +32,24 @@ " " ], "terrain": { - " ": [ "t_dirt", [ "t_grass", 3 ] ], + " ": "t_region_groundcover_urban", ".": "t_floor", "a": "t_wall_w", "b": "t_sidewalk", "d": "t_wall_glass", "e": "t_door_c", "g": "t_dirt", - "j": "t_console_broken", "m": "t_dirt", "<": "t_stairs_up", "4": "t_gutter_downspout", - "o": "t_shrub" + "o": "t_region_shrub" }, "furniture": { "f": "f_table", "g": "f_dumpster", "h": "f_counter", "i": "f_fridge", + "j": "f_console_broken", "k": "f_rack", "l": "f_trashcan", "m": "f_trashcan", @@ -236,18 +236,18 @@ " " ], "terrain": { - " ": [ "t_dirt", [ "t_grass", 3 ] ], + " ": "t_region_groundcover", ".": "t_floor", "a": "t_wall_w", "b": "t_sidewalk", "d": "t_wall_glass", "e": "t_door_c", - "g": "t_dirt", + "g": "t_region_groundcover_barren", "<": "t_stairs_up", - "4": "t_gutter_downspout", - "j": "t_console_broken" + "4": "t_gutter_downspout" }, "furniture": { + "j": "f_console_broken", "c": "f_chair", "f": "f_table", "g": "f_dumpster", @@ -436,19 +436,19 @@ " " ], "terrain": { - " ": [ "t_dirt", [ "t_grass", 3 ] ], + " ": "t_region_groundcover", ".": "t_floor", "a": "t_wall_w", "b": "t_sidewalk", "d": "t_wall_glass", "e": "t_door_c", - "g": "t_dirt", - "j": "t_console_broken", + "g": "t_region_groundcover_barren", "o": "t_door_o", "<": "t_ladder_up", "4": "t_gutter_downspout" }, "furniture": { + "j": "f_console_broken", "c": "f_chair", "f": "f_table", "g": "f_dumpster", diff --git a/data/json/mapgen/cathedral.json b/data/json/mapgen/cathedral.json index 301b925fbd0cb..cab83defac573 100644 --- a/data/json/mapgen/cathedral.json +++ b/data/json/mapgen/cathedral.json @@ -146,10 +146,11 @@ "u": "t_floor", "v": "t_floor", "w": [ "t_window_stained_red", "t_window_stained_blue", "t_window_stained_green" ], - "x": "t_console_broken", + "x": "t_floor", "|": "t_wall" }, "furniture": { + "x": "f_console_broken", "7": "f_rack", "8": "f_desk", "B": "f_brazier", diff --git a/data/json/mapgen/cave.json b/data/json/mapgen/cave.json index 8b09d6ae0adc1..66f115201986e 100644 --- a/data/json/mapgen/cave.json +++ b/data/json/mapgen/cave.json @@ -576,8 +576,15 @@ "............ ....F.7J G.", "............>..........." ], - "terrain": { ".": "t_rock", " ": "t_rock_floor", ">": "t_slope_up", "7": "t_console_broken" }, - "furniture": { "f": "f_firering", "c": "f_camp_chair", "C": "f_crate_o", "W": "f_crate_c", "T": "f_tourist_table" }, + "terrain": { ".": "t_rock", " ": "t_rock_floor", ">": "t_slope_up" }, + "furniture": { + "f": "f_firering", + "c": "f_camp_chair", + "C": "f_crate_o", + "W": "f_crate_c", + "T": "f_tourist_table", + "7": "f_console_broken" + }, "traps": { "F": "tr_rollmat", "2": "tr_crossbow", diff --git a/data/json/mapgen/city_blocks/urban_14_dense_house_mart_food.json b/data/json/mapgen/city_blocks/urban_14_dense_house_mart_food.json index 236f7a1fcc508..9fa7b68530de2 100644 --- a/data/json/mapgen/city_blocks/urban_14_dense_house_mart_food.json +++ b/data/json/mapgen/city_blocks/urban_14_dense_house_mart_food.json @@ -53,7 +53,12 @@ ">": "t_stairs_down", "-": "t_thconc_floor" }, - "furniture": { "!": "f_counter", "]": "f_treadmill", ")": "f_exercise", "}": "f_ergometer" }, + "furniture": { + "!": "f_counter", + "]": [ "f_treadmill", "f_treadmill_mechanical" ], + ")": "f_exercise", + "}": [ "f_ergometer", "f_ergometer_mechanical" ] + }, "vendingmachines": { "[": { "item_group": "vending_drink" }, "(": { "item_group": "vending_food" } }, "set": [ { "point": "trap", "id": "tr_rollmat", "x": [ 9, 11 ], "y": 11 }, diff --git a/data/json/mapgen/collapsed_tower.json b/data/json/mapgen/collapsed_tower.json index 2ed4e08a0e50d..7c197925c8fbe 100644 --- a/data/json/mapgen/collapsed_tower.json +++ b/data/json/mapgen/collapsed_tower.json @@ -2,11 +2,23 @@ { "name": "GROUP_COLLAPSED_TOWER", "type": "monstergroup", - "default": "mon_null", + "default": "mon_zombie", "monsters": [ - { "monster": "mon_zombie_gasbag_immobile", "freq": 150, "cost_multiplier": 1 }, - { "monster": "mon_zombie", "freq": 200, "cost_multiplier": 7, "pack_size": [ 3, 5 ] }, - { "monster": "mon_zombie_gasbag_crawler", "freq": 150, "cost_multiplier": 7, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zombie_gasbag_immobile", "freq": 150, "cost_multiplier": 1, "pack_size": [ 1, 4 ] }, + { "monster": "mon_zombie_gasbag_crawler", "freq": 150, "cost_multiplier": 3, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zombie_scissorlimbs", "freq": 50, "cost_multiplier": 9, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zombie_gasbag_impaler", "freq": 50, "cost_multiplier": 6, "pack_size": [ 1, 4 ] } + ] + }, + { + "name": "GROUP_COLLAPSED_TOWER_BASEMENT", + "type": "monstergroup", + "default": "mon_zombie_gasbag_immobile", + "monsters": [ + { "monster": "mon_zombie_hanging_innards", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_zombie_giant_heart", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_zombie_gasbag_crawler", "freq": 150, "cost_multiplier": 3, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zombie_scissorlimbs", "freq": 50, "cost_multiplier": 9, "pack_size": [ 1, 2 ] }, { "monster": "mon_zombie_gasbag_impaler", "freq": 50, "cost_multiplier": 6, "pack_size": [ 1, 4 ] } ] }, @@ -46,9 +58,9 @@ ".||||||||#|l l| ||66 | | |-c----c-| | z~~ ###### zTz |s", "....s.. |--- ---|#|||66 ||#| #|#||| zz~~~ zzz 1s", "....|.. |### #||| B B | |l ll ll ll|l| ~~~ 1s", - "....s..||-- --||||| | |l ll ll l|####rHr z~~ >????> zzz 1s", + "....s..||-- --||||| | |l ll ll l|####rHr z~~ c????c zzz 1s", "....s..||B666B 46B || B w |## | #|?rrr ##~~ rrrrrr s", - ". |||||| 666 6B ||||| w #|###llll l#|||r###zT~~ Hr>>rH |", + ". |||||| 666 6B ||||| w #|###llll l#|||r###zT~~ HrccrH |", ".. ### B B 666|| | ##|||||--| ##|?r|||||#~~~ ||||s", ".. |||# B B B B||| | |##| ###| ## - |||||###### ## |s", ".... |# B B 666 || | w C || ~ ||||||666666 ||| |s", @@ -65,9 +77,9 @@ "..|||z|C | C| B B |||||||||||| |CCC||```3 >|| ||CCC CCC|s", "....s CB |||| CCC CC||#D | C||||| |#```3 |#||||C C B|s", ".... CC 4 CCC||B 4##||##3 ##|||#|#```||||||#3 ||#|####### 1s", - ".... |||--22-||||||||||| ## ||||||||||||||| ||| ||||||||||||||s", - "....szzzzz|||zzzzzzz|||##| z## |||z||z|###zzzz1111 ||##zzzzzzzzzzs", - "...##.......||......||.... ##...........|||.##......|||||.............", + ".... |||--22-||||||||||| ## |||||||||||||||||||||||||||||||||||s", + "....szzzzz|||zzzzzzz|||##| z## |||z||z|###||zz1111|||##zzzzzzzzzzs", + "...##.......||......||.... ##...........||||||......|||||.............", ".#..sssssssssssssssssssssss 3sssssssssssssssssssssssss||sssssssssssssss" ], "set": [ @@ -164,10 +176,10 @@ { "point": "bash", "x": [ 48, 74 ], "y": [ 24, 47 ], "repeat": [ 50, 100 ] } ], "palettes": [ "collapsed_tower" ], - "furniture": { "R": "f_rack" }, + "furniture": { "C": "f_machinery_electronic", "x": "f_machinery_heavy", "R": "f_rack" }, "terrain": { - "C": "t_machinery_electronic", - "x": "t_machinery_heavy", + "|": "t_concrete_wall_flesh", + " ": "t_thconc_floor_flesh", "?": "t_nanofab", "r": "t_metal_floor", "/": "t_nanofab_body", @@ -183,14 +195,14 @@ { "item": "cleaning", "x": [ 15, 15 ], "y": [ 21, 22 ], "chance": 60 } ], "place_monster": [ { "monster": "mon_talon_m202a1", "x": [ 12, 13 ], "y": [ 20, 23 ] } ], - "monster": { " ": { "monster": "mon_zombie_living_wall", "chance": 20 } }, + "monster": { " ": { "monster": "mon_zombie_living_wall", "chance": 10 } }, "place_monsters": [ - { "monster": "GROUP_COLLAPSED_TOWER", "x": [ 0, 23 ], "y": [ 0, 15 ], "density": 2.5 }, - { "monster": "GROUP_COLLAPSED_TOWER", "x": [ 24, 47 ], "y": [ 0, 23 ], "density": 2.5 }, - { "monster": "GROUP_COLLAPSED_TOWER", "x": [ 48, 71 ], "y": [ 0, 23 ], "density": 2.5 }, - { "monster": "GROUP_COLLAPSED_TOWER", "x": [ 0, 23 ], "y": [ 37, 47 ], "density": 2.5 }, - { "monster": "GROUP_COLLAPSED_TOWER", "x": [ 24, 47 ], "y": [ 24, 47 ], "density": 2.5 }, - { "monster": "GROUP_COLLAPSED_TOWER", "x": [ 48, 71 ], "y": [ 24, 47 ], "density": 2.5 } + { "monster": "GROUP_COLLAPSED_TOWER_BASEMENT", "x": [ 0, 23 ], "y": [ 0, 15 ], "density": 2.5 }, + { "monster": "GROUP_COLLAPSED_TOWER_BASEMENT", "x": [ 24, 47 ], "y": [ 0, 23 ], "density": 2.5 }, + { "monster": "GROUP_COLLAPSED_TOWER_BASEMENT", "x": [ 48, 71 ], "y": [ 0, 23 ], "density": 2.5 }, + { "monster": "GROUP_COLLAPSED_TOWER_BASEMENT", "x": [ 0, 23 ], "y": [ 37, 47 ], "density": 2.5 }, + { "monster": "GROUP_COLLAPSED_TOWER_BASEMENT", "x": [ 24, 47 ], "y": [ 24, 47 ], "density": 2.5 }, + { "monster": "GROUP_COLLAPSED_TOWER_BASEMENT", "x": [ 48, 71 ], "y": [ 24, 47 ], "density": 2.5 } ] } } diff --git a/data/json/mapgen/cs_internet_cafe.json b/data/json/mapgen/cs_internet_cafe.json index 51acdbc665084..3e95a54b9bbac 100644 --- a/data/json/mapgen/cs_internet_cafe.json +++ b/data/json/mapgen/cs_internet_cafe.json @@ -63,11 +63,10 @@ "...4...................." ], "terrain": { - ".": [ [ "t_grass", 5 ], "t_dirt" ], + ".": "t_region_groundcover_urban", ",": "t_floor", "|": "t_wall_w", "s": "t_sidewalk", - "P": "t_console_broken", "D": "t_door_c", "g": "t_wall_glass_alarm", "G": "t_door_glass_c", @@ -75,7 +74,15 @@ "4": "t_gutter_downspout", "A": "t_atm" }, - "furniture": { "c": "f_displaycase", "t": "f_toilet", "h": "f_chair", "V": "f_vending_c", "S": "f_sink", "L": "f_locker" }, + "furniture": { + "P": "f_console_broken", + "c": "f_displaycase", + "t": "f_toilet", + "h": "f_chair", + "V": "f_vending_c", + "S": "f_sink", + "L": "f_locker" + }, "toilets": { "t": { "//": "no values needed here" } }, "items": { "c": { "item": "ic_merch", "chance": 20 }, @@ -132,13 +139,12 @@ ">": "t_stairs_down", "#": "t_wall_w", ",": "t_thconc_floor", - "k": "t_generator_broken", - "P": "t_console_broken", "D": "t_door_locked", "g": "t_wall_glass_alarm", "&": "t_flat_roof", "=": "t_flat_roof" }, + "furniture": { "P": "f_console_broken", "k": "f_generator_broken" }, "place_loot": [ { "item": "television", "x": 14, "y": 9, "chance": 100 }, { "item": "stepladder", "x": 5, "y": 10, "chance": 100 } ], "items": { "c": { "item": "electronics", "chance": 40 }, diff --git a/data/json/mapgen/dojo.json b/data/json/mapgen/dojo.json index 0ff2a0941d1d0..8f3ea4d45fdd9 100644 --- a/data/json/mapgen/dojo.json +++ b/data/json/mapgen/dojo.json @@ -105,10 +105,13 @@ "#": "t_wall_b", "*": "t_thconc_floor", "S": "t_thconc_floor", - "+": "t_door_c", - "x": [ "t_machinery_light", "t_machinery_heavy", "t_machinery_old", "t_machinery_electronic" ] + "x": "t_thconc_floor", + "+": "t_door_c" + }, + "furniture": { + "S": "f_filing_cabinet", + "x": [ "f_machinery_light", "f_machinery_heavy", "f_machinery_old", "f_machinery_electronic" ] }, - "furniture": { "S": "f_filing_cabinet" }, "items": { "t": { "item": "office_paper", "chance": 25, "repeat": [ 2, 4 ] } }, "place_nested": [ { diff --git a/data/json/mapgen/dollar_store.json b/data/json/mapgen/dollar_store.json index 7a82b5db2a19e..f3a04d3a9cb89 100644 --- a/data/json/mapgen/dollar_store.json +++ b/data/json/mapgen/dollar_store.json @@ -35,13 +35,12 @@ "terrain": { "+": "t_reinforced_door_glass_c", "-": "t_wall_glass", - ".": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], + ".": "t_region_groundcover_urban", "P": "t_wall_glass", "_": "t_floor", - "d": "t_dirt", - "p": "t_grass", + "d": "t_region_groundcover_urban", + "p": "t_region_groundcover_urban", "|": "t_wall_wood", - "X": "t_console_broken", "s": "t_sidewalk", "U": "t_sidewalk", "4": "t_gutter_downspout", @@ -56,7 +55,8 @@ "I": "f_desk", "S": "f_filing_cabinet", "U": "f_dumpster", - "p": [ "f_datura", "f_bluebell", "f_mutpoppy", "f_dahlia", "f_flower_tulip", "f_chamomile", "f_flower_spurge", "f_lily" ] + "X": "f_console_broken", + "p": "f_region_flower" }, "toilets": { "T": { } }, "items": { @@ -185,43 +185,18 @@ "+": "t_reinforced_door_glass_c", "-": "t_wall_glass_alarm", ".": "t_floor", - "_": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "p": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "d": "t_dirt", + "_": "t_region_groundcover_urban", + "p": "t_region_groundcover_urban", + "d": "t_region_groundcover_urban", "s": "t_sidewalk", "|": "t_adobe_brick_wall", - "X": "t_console_broken", "U": "t_sidewalk", "4": "t_gutter_downspout", "<": "t_ladder_up", - "9": [ - "t_tree_blackjack", - "t_tree_walnut", - "t_tree_chestnut", - "t_tree_beech", - "t_tree_hazelnut", - "t_tree_cottonwood", - "t_tree", - "t_tree_elm", - "t_tree_dead", - "t_tree_apple", - "t_tree_pear", - "t_tree_cherry", - "t_tree_peach", - "t_tree_apricot", - "t_tree_plum", - "t_tree_mulberry", - "t_tree_elderberry", - "t_tree_pine", - "t_tree_birch", - "t_tree_willow", - "t_tree_maple", - "t_tree_hickory", - "t_tree_almond", - "t_tree_pecan" - ] + "9": "t_region_tree" }, "furniture": { + "X": "f_console_broken", "#": "f_counter", "l": "f_stool", "{": "f_rack", diff --git a/data/json/mapgen/field_football.json b/data/json/mapgen/field_football.json index 5e587a0706506..931f5d5ed57f6 100644 --- a/data/json/mapgen/field_football.json +++ b/data/json/mapgen/field_football.json @@ -12,7 +12,8 @@ [ "towel_soiled", 20 ], [ "heatpack", 40 ], [ "heatpack_used", 60 ], - [ "bandages", 40 ], + [ "bandages", 20 ], + [ "adhesive_bandages", 20 ], [ "mouthpiece", 40 ], [ "football", 60 ], [ "football_armor", 60 ], diff --git a/data/json/mapgen/fire_station.json b/data/json/mapgen/fire_station.json index cc655746c8104..ec74ee6d6b0b4 100644 --- a/data/json/mapgen/fire_station.json +++ b/data/json/mapgen/fire_station.json @@ -38,17 +38,17 @@ "+": "t_door_c", ",": "t_pavement_y", "-": "t_brick_wall", - ".": "t_grass", + ".": "t_region_groundcover_urban", "L": "t_door_locked", "M": "t_door_metal_locked", "O": "t_window", "_": "t_pavement", "w": "t_gates_control_brick", - "x": "t_console_broken", "|": "t_brick_wall", "4": "t_gutter_downspout" }, "furniture": { + "x": "f_console_broken", "#": "f_counter", ":": "f_dresser", "@": "f_bed", @@ -172,13 +172,12 @@ "+": "t_door_metal_locked", ".": "t_scrap_floor", "6": "t_gates_control_brick", - "C": "t_console_broken", "D": "t_door_metal_c", "P": "t_pavement_y", - "S": "t_shrub_rose", + "S": "t_region_shrub_decorative", "T": "t_thconc_floor", - "_": "t_grass", - "a": "t_shrub_lilac", + "_": "t_region_groundcover_urban", + "a": "t_region_shrub_decorative", "d": "t_door_c", "e": "t_thconc_floor", "h": "t_curtains", @@ -193,9 +192,10 @@ "<": "t_ladder_up" }, "furniture": { + "C": "f_console_broken", "#": "f_table", "&": "f_sink", - "5": "f_ergometer", + "5": [ "f_ergometer", "f_ergometer_mechanical" ], "B": "f_bookcase", "E": "f_exercise", "F": "f_fridge", diff --git a/data/json/mapgen/garage.json b/data/json/mapgen/garage.json index 0b8dfc194b2c7..d89a575d2f5ba 100644 --- a/data/json/mapgen/garage.json +++ b/data/json/mapgen/garage.json @@ -33,21 +33,20 @@ " " ], "terrain": { - " ": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt", "t_shrub" ], + " ": [ [ "t_region_groundcover_urban", 10 ], "t_region_shrub" ], "E": "t_pavement", "U": "t_pavement", "$": "t_door_glass_c", "+": "t_door_c", "-": "t_brick_wall", ".": "t_thconc_floor", - "6": "t_console_broken", ":": "t_window", "=": "t_door_metal_locked", "A": "t_m_frame", "H": "t_wall_glass", "e": "t_gates_mech_control", "|": "t_brick_wall", - "W": "t_chainfence_h", + "W": "t_chainfence", "^": "t_chaingate_c", "M": "t_metal_floor", "#": "t_grate", @@ -55,6 +54,7 @@ "<": "t_ladder_up" }, "furniture": { + "6": "f_console_broken", "A": "f_air_conditioner", "L": "f_locker", "b": "f_bench", @@ -158,24 +158,24 @@ " " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], - "~": [ "t_dirt", "t_pavement", "t_pavement", "t_pavement", "t_pavement", "t_pavement", "t_pavement" ], - "_": [ "t_dirt", "t_sidewalk", "t_sidewalk", "t_sidewalk", "t_sidewalk", "t_sidewalk", "t_sidewalk" ], - "*": [ "t_tree_pine", "t_tree", "t_shrub", "t_tree_young" ], + " ": "t_region_groundcover", + "~": [ "t_region_groundcover_barren", [ "t_pavement", 6 ] ], + "_": [ "t_region_groundcover_barren", [ "t_sidewalk", 6 ] ], + "*": [ [ "t_region_tree_shade", 3 ], "t_region_shrub" ], "J": "t_water_pump", "D": "t_door_locked", "+": "t_door_c", "w": "t_wall_log", "U": "t_brick_wall", ".": "t_floor", - "6": "t_console_broken", ":": "t_window", - "W": "t_chainfence_h", + "W": "t_chainfence", "^": "t_chaingate_c", - "z": "t_dirt", + "z": "t_region_groundcover_barren", "4": "t_gutter_downspout" }, "furniture": { + "6": "f_console_broken", "L": "f_locker", "c": "f_counter", "s": "f_sink", @@ -269,7 +269,7 @@ " " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt", "t_shrub", "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", "E": "t_pavement", "X": "t_sidewalk", "U": "t_sidewalk", @@ -278,7 +278,6 @@ "O": "t_door_locked", "-": "t_wall_b", ".": "t_thconc_floor", - "6": "t_console_broken", ":": "t_window", "=": "t_door_metal_locked", "A": "t_m_frame", @@ -294,6 +293,7 @@ }, "toilets": { "&": { } }, "furniture": { + "6": "f_console_broken", "A": "f_air_conditioner", "L": "f_locker", "T": "f_rack", @@ -366,9 +366,14 @@ "W": "t_window_domestic", "*": "t_chainfence", "8": "t_chaingate_c", - "x": [ "t_machinery_light", "t_machinery_heavy", "t_machinery_old", "t_machinery_electronic" ] + "x": "t_thconc_floor" + }, + "furniture": { + "I": "f_desk", + "h": "f_chair", + "f": "f_filing_cabinet", + "x": [ "f_machinery_light", "f_machinery_heavy", "f_machinery_old", "f_machinery_electronic" ] }, - "furniture": { "I": "f_desk", "h": "f_chair", "f": "f_filing_cabinet" }, "items": { "I": { "item": "office", "chance": 30 }, "f": { "item": "office_paper", "chance": 30 }, diff --git a/data/json/mapgen/garage_gas.json b/data/json/mapgen/garage_gas.json index dc52df76a0989..cf875fbab7f7b 100644 --- a/data/json/mapgen/garage_gas.json +++ b/data/json/mapgen/garage_gas.json @@ -42,9 +42,8 @@ "+": "t_door_c", "-": "t_wall_w", "|": "t_wall_w", - ".": [ [ "t_grass", 3 ], [ "t_dirt", 3 ], "t_grass_long" ], + ".": "t_region_groundcover_urban", " ": "t_thconc_floor", - "6": "t_console_broken", "=": "t_door_metal_locked", "I": "t_column", "[": "t_door_glass_c", @@ -58,6 +57,7 @@ "w": "t_window" }, "furniture": { + "6": "f_console_broken", "P": "f_indoor_plant", "D": "f_trashcan", "R": "f_trashcan", diff --git a/data/json/mapgen/gardening_store.json b/data/json/mapgen/gardening_store.json index 1a3180380d4dd..edd0b8db75b55 100644 --- a/data/json/mapgen/gardening_store.json +++ b/data/json/mapgen/gardening_store.json @@ -37,21 +37,20 @@ "+": "t_door_glass_c", ",": "t_pavement_y", "-": "t_wall_g", - ".": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "Z": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "1": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "2": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "3": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "5": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "Q": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "B": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "p": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ] ], - "b": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], + ".": "t_region_groundcover_urban", + "Z": "t_region_groundcover_urban", + "1": "t_region_groundcover_urban", + "2": "t_region_groundcover_urban", + "3": "t_region_groundcover_urban", + "5": "t_region_groundcover_urban", + "Q": "t_region_groundcover_urban", + "B": "t_region_groundcover_urban", + "p": "t_region_groundcover_urban", + "b": "t_region_groundcover_urban", "O": "t_window", "_": "t_pavement", "r": "t_floor", "|": "t_wall_g", - "?": "t_console_broken", "^": "t_chaingate_l", "%": "t_chainfence", "*": [ "t_door_locked", "t_door_c" ], @@ -60,6 +59,7 @@ }, "toilets": { "&": { } }, "furniture": { + "?": "f_console_broken", "#": "f_counter", "$": "f_counter_gate_c", "r": "f_rack", diff --git a/data/json/mapgen/gunsmith.json b/data/json/mapgen/gunsmith.json index 1a2c1e49e77b7..8745781a4cbf4 100644 --- a/data/json/mapgen/gunsmith.json +++ b/data/json/mapgen/gunsmith.json @@ -38,7 +38,7 @@ ], "terrain": { "#": "t_floor", - "%": "t_shrub", + "%": "t_region_shrub", "+": "t_door_metal_pickable", ",": "t_pavement_y", "-": "t_wall_w", @@ -52,12 +52,12 @@ "d": "t_pavement", "s": "t_sidewalk", "w": "t_window_bars_alarm", - "x": "t_console_broken", "|": "t_wall_w", "<": "t_stairs_up", "4": "t_gutter_downspout" }, "furniture": { + "x": "f_console_broken", "#": "f_counter", "C": "f_sofa", "E": "f_desk", diff --git a/data/json/mapgen/gym.json b/data/json/mapgen/gym.json index 0bf565cf27fb2..47336aeb21b99 100644 --- a/data/json/mapgen/gym.json +++ b/data/json/mapgen/gym.json @@ -47,10 +47,10 @@ "4": "t_gutter_downspout" }, "furniture": { - "!": "f_ergometer", + "!": [ "f_ergometer", "f_ergometer_mechanical" ], "#": "f_counter", "*": "f_shower", - "@": "f_treadmill", + "@": [ "f_treadmill", "f_treadmill_mechanical" ], "O": "f_locker", "V": "f_exercise", "a": "f_stool", @@ -176,13 +176,13 @@ "<": "t_stairs_up" }, "furniture": { - "!": "f_ergometer", + "!": [ "f_ergometer", "f_ergometer_mechanical" ], "{": "f_bigmirror", "#": "f_counter", "H": "f_vending_c", "&": "f_counter", "*": "f_shower", - "@": "f_treadmill", + "@": [ "f_treadmill", "f_treadmill_mechanical" ], "O": "f_locker", "V": "f_exercise", "C": "f_bench", diff --git a/data/json/mapgen/hazardous_waste_sarcophagus.json b/data/json/mapgen/hazardous_waste_sarcophagus.json index 12532ead88c59..bca07090420ad 100644 --- a/data/json/mapgen/hazardous_waste_sarcophagus.json +++ b/data/json/mapgen/hazardous_waste_sarcophagus.json @@ -55,16 +55,9 @@ " ffffffffffffffffffffffffffffffffffffffffffffff ", " " ], + "fill_ter": "t_linoleum_white", "terrain": { - " ": [ - [ "t_grass", 20 ], - [ "t_grass_dead", 3 ], - [ "t_grass_tall", 5 ], - [ "t_grass_long", 3 ], - [ "t_dirt", 5 ], - [ "t_shrub", 2 ], - [ "t_tree", 1 ] - ], + " ": [ [ "t_region_groundcover", 40 ], [ "t_region_shrub", 2 ], [ "t_region_tree", 1 ] ], "f": "t_chainfence", "|": "t_wall", "-": "t_wall", @@ -77,34 +70,12 @@ ",": "t_sidewalk", ":": "t_pavement", ";": "t_pavement_y", - "1": "t_floor", - "2": "t_floor", - "3": "t_floor", - "4": "t_floor", - "5": "t_console", - "6": "t_console_broken", - "7": "t_floor", - "8": "t_floor", - "9": "t_floor", - "&": "t_floor", "$": "t_sewage", - ".": "t_floor", - "a": "t_floor", - "b": "t_floor", - "r": "t_floor", - "F": "t_floor", - "c": "t_floor", - "C": "t_floor", - "d": "t_floor", - "l": "t_floor", - "p": "t_floor", - "A": "t_floor", "P": "t_sewage_pipe", "S": "t_sewage_pump", "G": "t_grate", "E": "t_elevator", "e": "t_elevator_control_off", - "s": "t_floor", "v": "t_dirt", "V": "t_vat", "L": "t_door_metal_locked", @@ -117,6 +88,8 @@ "2": "f_rack_coat", "3": "f_server", "4": "f_utility_shelf", + "5": "f_console", + "6": "f_console_broken", "7": "f_locker", "8": "f_utility_shelf", "9": "f_utility_shelf", @@ -238,20 +211,9 @@ "####################### ## ####################", "################################################" ], + "fill_ter": "t_metal_floor", "terrain": { " ": "t_rock_floor", - ".": "t_metal_floor", - "&": "t_metal_floor", - "a": "t_metal_floor", - "l": "t_metal_floor", - "s": "t_metal_floor", - "r": "t_metal_floor", - "c": "t_metal_floor", - "C": "t_metal_floor", - "d": "t_metal_floor", - "8": "t_metal_floor", - "9": "t_metal_floor", - "F": "t_metal_floor", "|": "t_concrete_wall", "-": "t_concrete_wall", "+": "t_door_metal_c", @@ -262,7 +224,6 @@ "%": "t_reinforced_glass", "E": "t_elevator", "e": "t_elevator_control_off", - "5": "t_console", "W": "t_water_dispenser", "~": [ [ "t_sewage", 55 ], [ "t_dirtfloor", 25 ], [ "t_dirtmound", 20 ] ] }, @@ -273,6 +234,7 @@ "c": "f_counter", "C": "f_chair", "l": "f_locker", + "5": "f_console", "8": "f_utility_shelf", "9": "f_utility_shelf", "a": "f_air_conditioner", diff --git a/data/json/mapgen/homeimprovement.json b/data/json/mapgen/homeimprovement.json index 916ce683426e3..f9117684e7520 100644 --- a/data/json/mapgen/homeimprovement.json +++ b/data/json/mapgen/homeimprovement.json @@ -40,11 +40,11 @@ "O": "t_window", "r": "t_carpet_red", "|": "t_wall_r", - "%": "t_console_broken", "4": "t_gutter_downspout", "<": "t_ladder_up" }, "furniture": { + "%": "f_console_broken", "A": "f_stool", "3": "f_bookcase", "U": [ "f_dumpster", "f_recycle_bin" ], diff --git a/data/json/mapgen/homeimprovement_superstore_new.json b/data/json/mapgen/homeimprovement_superstore_new.json index 9d43fc0088a3e..b565dcfddea11 100644 --- a/data/json/mapgen/homeimprovement_superstore_new.json +++ b/data/json/mapgen/homeimprovement_superstore_new.json @@ -217,10 +217,10 @@ ">": "t_stairs_down", "<": "t_stairs_up", "$": "t_atm", - "&": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], - "B": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], - " ": [ "t_grass_long", "t_grass_long", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_dirt", "t_shrub" ], - "/": [ "t_tree", "t_tree_young", "t_shrub" ], + "&": "t_region_groundcover_urban", + "B": "t_region_groundcover_urban", + " ": [ [ "t_region_groundcover_urban", 10 ], "t_region_shrub" ], + "/": [ [ "t_region_tree", 2 ], "t_region_shrub" ], "0": "t_grass_golf", "a": "t_sandmound", "A": "t_claymound", @@ -235,7 +235,6 @@ "F": "t_chaingate_c", "#": "t_door_metal_locked", "g": "t_gates_mech_control", - "x": "t_console_broken", "!": "t_door_glass_c", "+": "t_door_c", "%": "t_door_locked_interior", @@ -278,6 +277,7 @@ "Z": "t_glass_roof" }, "furniture": { + "x": "f_console_broken", "V": "f_vending_c", "C": "f_chair", "T": "f_table", @@ -316,12 +316,12 @@ "U": "f_sofa", "q": "f_bookcase", "B": "f_bench", - "&": [ "f_dahlia", "f_dandelion", "f_lily", "f_flower_tulip", "f_bluebell" ], + "&": "f_region_flower", "M": "f_fema_groundsheet", "{": "f_canvas_door", "}": "f_canvas_wall", "H": "f_camp_chair", - "X": [ "f_crate_c", "f_crate_c", "f_crate_c", "f_crate_o" ], + "X": [ [ "f_crate_c", 3 ], "f_crate_o" ], "D": "f_dumpster", "O": "f_air_conditioner", "j": "f_standing_tank", diff --git a/data/json/mapgen/homeless_shelter.json b/data/json/mapgen/homeless_shelter.json index 339384bafe6bf..a50321d4b4f47 100644 --- a/data/json/mapgen/homeless_shelter.json +++ b/data/json/mapgen/homeless_shelter.json @@ -5,25 +5,8 @@ "terrain": { "*": "t_open_air", "~": "t_open_air_rooved", - ".": [ [ "t_grass_long", 200 ], [ "t_grass", 600 ], [ "t_dirt", 200 ], [ "t_shrub", 1 ] ], - ",": [ - [ "t_grass_long", 75 ], - [ "t_grass", 50 ], - [ "t_shrub", 20 ], - [ "t_shrub_rose", 20 ], - [ "t_shrub_lilac", 20 ], - [ "t_tree_young", 20 ], - [ "t_grass_tall", 20 ], - [ "t_grass_long", 20 ], - [ "t_underbrush", 20 ], - [ "t_shrub_hydrangea", 20 ], - [ "t_shrub_raspberry", 20 ], - [ "t_tree", 10 ], - [ "t_tree_willow", 2 ], - [ "t_tree_birch", 2 ], - [ "t_tree_maple", 2 ], - [ "t_tree_pine", 2 ] - ], + ".": [ [ "t_region_groundcover_urban", 1000 ], [ "t_region_shrub", 1 ] ], + ",": [ [ "t_region_groundcover_urban", 125 ], [ "t_region_shrub", 120 ], [ "t_region_tree_shade", 40 ] ], "-": "t_door_locked_interior", "<": "t_stairs_down", "+": "t_door_c", @@ -39,7 +22,6 @@ "L": "t_thconc_floor", "R": "t_thconc_floor", "s": "t_concrete", - "x": "t_console_broken", "|": "t_brick_wall", "#": "t_ponywall", "=": "t_reinforced_glass", @@ -54,6 +36,7 @@ "n": "t_dirtmound" }, "furniture": { + "x": "f_console_broken", "3": "f_bench", "B": "f_bench", "S": "f_sink", diff --git a/data/json/mapgen/hotel_tower.json b/data/json/mapgen/hotel_tower.json index 43b1d7277c3e8..d3d7a731af066 100644 --- a/data/json/mapgen/hotel_tower.json +++ b/data/json/mapgen/hotel_tower.json @@ -76,8 +76,8 @@ " s''''%c..BB|c..BB|o..BB|c.LBB|t.........t|BB..c|BB..c|BB..o|BB..o%''''s" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { "V": "t_pavement", "w": "t_window_domestic", "x": "t_console_broken" }, - "furniture": { "D": "f_desk" }, + "terrain": { "V": "t_pavement", "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -130,8 +130,8 @@ "******%c..BB|c..BB|o..BBXc.LBB|t.........t|BB..cXBB..c|BB..o|BB..o%*****" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { "w": "t_window_domestic", "x": "t_console_broken" }, - "furniture": { "D": "f_desk" }, + "terrain": { "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -180,8 +180,8 @@ "******%c..BB|c..BB|o..BB|c.LBB|t.........t|BB..c|BB..c|BB..o|BB..o%*****" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { "w": "t_window_domestic", "x": "t_console_broken" }, - "furniture": { "D": "f_desk" }, + "terrain": { "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -230,8 +230,8 @@ "******%c..BB|c..BB|o..BB|c.LBB|t.........t|BB..c|BB..c|BB..o|BB..o%*****" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { "w": "t_window_domestic", "x": "t_console_broken" }, - "furniture": { "D": "f_desk" }, + "terrain": { "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -526,10 +526,9 @@ "_": "t_thconc_floor", "+": "t_door_metal_c", "D": "t_chaingate_l", - "%": "t_chainfence", - "H": "t_generator_broken" + "%": "t_chainfence" }, - "furniture": { "Y": "f_standing_tank", "6": "f_water_heater", "7": "f_roof_turbine_vent" }, + "furniture": { "Y": "f_standing_tank", "H": "f_generator_broken", "6": "f_water_heater", "7": "f_roof_turbine_vent" }, "liquids": { "6": { "liquid": "water_clean", "amount": [ 0, 100 ] }, "Y": { "liquid": "water_clean", "amount": [ 100, 1000 ] } }, "place_monsters": [ { "monster": "GROUP_ROOF_ZOMBIE", "x": [ 7, 23 ], "y": [ 0, 22 ], "repeat": 2 }, @@ -622,8 +621,8 @@ "%c.LBB|t.........t|BB..c" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { "+": [ "t_door_c", "t_door_c", "t_door_o" ], "w": "t_window_domestic", "x": "t_console_broken" }, - "furniture": { "D": "f_desk" }, + "terrain": { "+": [ [ "t_door_c", 2 ], "t_door_o" ], "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -668,8 +667,8 @@ "|c.LBB|t.........t|BB..c" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { "+": [ "t_door_c", "t_door_c", "t_door_o" ], "w": "t_window_domestic", "x": "t_console_broken" }, - "furniture": { "D": "f_desk" }, + "terrain": { "+": [ [ "t_door_c", 2 ], "t_door_o" ], "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -714,14 +713,8 @@ "|c.LBB|h.........h|BB..c" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { - "+": [ "t_door_c", "t_door_c", "t_door_o" ], - "G": "t_door_glass_c", - "w": "t_window_domestic", - "V": "t_pavement", - "x": "t_console_broken" - }, - "furniture": { "D": "f_desk" }, + "terrain": { "+": [ "t_door_c", "t_door_c", "t_door_o" ], "G": "t_door_glass_c", "w": "t_window_domestic", "V": "t_pavement" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, @@ -767,13 +760,8 @@ "|c.LBB|t.........t|BB..c" ], "palettes": [ "hotel_tower_palette.json" ], - "terrain": { - "+": [ "t_door_c", "t_door_c", "t_door_o" ], - "G": "t_door_glass_c", - "w": "t_window_domestic", - "x": "t_console_broken" - }, - "furniture": { "D": "f_desk" }, + "terrain": { "+": [ "t_door_c", "t_door_c", "t_door_o" ], "G": "t_door_glass_c", "w": "t_window_domestic" }, + "furniture": { "D": "f_desk", "x": "f_console_broken" }, "items": { "B": { "item": "bed", "chance": 50 }, "L": { "item": "hotel_luggage", "chance": 100 }, diff --git a/data/json/mapgen/house/house15.json b/data/json/mapgen/house/house15.json index ee74d8d46bb55..952d3f72e4d93 100644 --- a/data/json/mapgen/house/house15.json +++ b/data/json/mapgen/house/house15.json @@ -34,7 +34,7 @@ ], "palettes": [ "standard_domestic_palette" ], "terrain": { "%": "t_region_shrub_fruit", "!": "t_region_groundcover_urban", "'": "t_concrete" }, - "furniture": { "!": "f_bluebell", "$": "f_treadmill" }, + "furniture": { "!": "f_bluebell", "$": [ "f_treadmill", "f_treadmill_mechanical" ] }, "place_loot": [ { "group": "livingroom", "x": [ 7, 16 ], "y": [ 7, 9 ], "chance": 90, "repeat": [ 1, 6 ] } ], "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 1, 22 ], "y": [ 2, 21 ], "chance": 5 } ] } diff --git a/data/json/mapgen/house/house_garage_prepper.json b/data/json/mapgen/house/house_garage_prepper.json index df3d8db13d2a7..8f1e3891895ea 100644 --- a/data/json/mapgen/house/house_garage_prepper.json +++ b/data/json/mapgen/house/house_garage_prepper.json @@ -60,11 +60,10 @@ "-": "t_linoleum_gray", "$": "t_window_boarded", "/": "t_window_reinforced", - ";": "t_console_broken", ",": "t_door_boarded", "(": "t_door_metal_pickable" }, - "furniture": { "!": "f_region_flower", "{": "f_table", "}": "f_chair", ")": "f_locker" }, + "furniture": { "!": "f_region_flower", ";": "f_console_broken", "{": "f_table", "}": "f_chair", ")": "f_locker" }, "set": [ { "point": "trap", "id": "tr_beartrap", "x": [ 10, 11 ], "y": 2, "repeat": [ 1, 2 ] }, { "point": "trap", "id": "tr_beartrap", "x": 2, "y": [ 7, 8 ], "repeat": [ 1, 2 ] }, diff --git a/data/json/mapgen/irradiator_1.json b/data/json/mapgen/irradiator_1.json index 331d2f6c71f4c..f858cc3a3486a 100644 --- a/data/json/mapgen/irradiator_1.json +++ b/data/json/mapgen/irradiator_1.json @@ -168,20 +168,7 @@ "[[[[L__________________LssssssssssssssssssssssssL__________________L[[[[" ], "terrain": { - "*": [ - "t_grass", - "t_grass", - "t_dirt", - "t_shrub_rose", - "t_shrub_lilac", - "t_tree_young", - "t_shrub_hydrangea", - "t_grass_long", - "t_woodchips", - "t_moss", - "t_grass_long", - "t_grass_dead" - ], + "*": [ [ "t_region_groundcover_forest", 2 ], "t_region_shrub_decorative" ], "'": [ "t_fence_barbed" ], "X": [ "t_strconc_wall" ], "+": [ "t_door_c" ], @@ -198,34 +185,32 @@ "f": [ "t_chainfence_h" ], "s": [ "t_sidewalk" ], "w": [ "t_window" ], - "x": [ "t_console_broken" ], "|": [ "t_strconc_wall" ], "U": [ "t_water_pool" ], "R": [ "t_reinforced_glass_shutter_open" ], "m": [ "t_oil_circ_brkr_s", "t_station_disc", "t_switchgear_s", "t_potential_trans", "t_current_trans", "t_lgtn_arrest" ], - "M": [ "t_machinery_heavy" ], "e": [ "t_gates_mech_control" ], "#": [ "t_sidewalk" ], - "P": [ "t_sewage_pump", "t_sewage_pipe", "t_sewage_pipe", "t_sewage_pipe" ], + "P": [ "t_sewage_pump", [ "t_sewage_pipe", 3 ] ], "Y": [ "t_door_metal_locked" ], "y": [ "t_door_metal_o" ], "N": [ "t_door_metal_locked" ], "%": [ "t_grate" ], - "/": [ "t_plut_generator" ], "}": [ "t_ladder_up" ], ")": [ "t_reinforced_glass" ], "!": [ "t_thconc_floor" ], - "0": [ "t_console" ], "1": [ "t_floor_red" ], "2": [ "t_floor_green" ], "3": [ "t_rad_platform" ], - "4": [ "t_card_industrial" ], - "5": [ "t_console" ], - "6": [ "t_console" ], - "7": [ "t_console" ] + "4": [ "t_card_industrial" ] }, "furniture": { "#": [ "f_bench" ], + "/": [ "f_compact_ASRG_containment" ], + "0": [ "f_console" ], + "5": [ "f_console" ], + "6": [ "f_console" ], + "7": [ "f_console" ], "S": [ "f_locker" ], "A": [ "f_locker" ], "j": [ "f_locker" ], @@ -236,10 +221,12 @@ "d": [ "f_desk" ], "g": [ "f_shower" ], "h": [ "f_chair" ], + "M": [ "f_machinery_heavy" ], "o": [ "f_sofa" ], "r": [ "f_rack" ], "t": [ "f_table" ], "Q": [ "f_air_filter" ], + "x": [ "f_console_broken" ], "Z": [ "f_water_purifier" ], "B": [ "f_bed", "f_dresser", "f_glass_cabinet" ], "<": [ "f_sink" ], diff --git a/data/json/mapgen/jewel_store.json b/data/json/mapgen/jewel_store.json index 0530214443a86..5dfe77f11e1ce 100644 --- a/data/json/mapgen/jewel_store.json +++ b/data/json/mapgen/jewel_store.json @@ -42,7 +42,7 @@ "+": "t_door_glass_c", ",": "t_pavement_y", "-": "t_wall_b", - ".": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt", "t_shrub" ], + ".": [ "t_region_groundcover_urban", "t_region_shrub" ], "5": "t_chainfence_h", "8": "t_chainfence_v", "F": "t_sidewalk", @@ -50,13 +50,13 @@ "_": "t_pavement", "h": "t_wall_glass_alarm", "v": "t_wall_glass_alarm", - "?": "t_console_broken", "4": "t_gutter_downspout", "|": "t_wall_b" }, "furniture": { "#": "f_counter", "%": "f_counter", + "?": "f_console_broken", "G": "f_desk", "T": "f_safe_l", "c": "f_chair", diff --git a/data/json/mapgen/lab/lab_common.json b/data/json/mapgen/lab/lab_common.json index 6ccc77eb54867..6159618dff094 100644 --- a/data/json/mapgen/lab/lab_common.json +++ b/data/json/mapgen/lab/lab_common.json @@ -3,6 +3,8 @@ "type": "palette", "id": "lab_palette", "furniture": { + "6": "f_console", + "x": "f_console_broken", "b": "f_bed", "l": "f_locker", "X": [ "f_cardboard_box", "f_crate_c" ], @@ -21,8 +23,6 @@ "^": "f_rubble_rock" }, "terrain": { - "6": "t_console", - "x": "t_console_broken", "g": "t_reinforced_glass", "G": "t_reinforced_door_glass_lab_c", ".": "t_thconc_floor", diff --git a/data/json/mapgen/lab/lab_floorplan_cross.json b/data/json/mapgen/lab/lab_floorplan_cross.json index 82c5d3af0d7d8..7fcdba5700e0e 100644 --- a/data/json/mapgen/lab/lab_floorplan_cross.json +++ b/data/json/mapgen/lab/lab_floorplan_cross.json @@ -166,18 +166,8 @@ "-----------MM----------|" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "terrain": { - "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ], - "!": [ - "t_thconc_floor", - "t_thconc_floor", - "t_thconc_floor", - "t_thconc_floor", - "t_console_broken", - "t_generator_broken", - "t_centrifuge" - ] - }, + "terrain": { "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ] }, + "furniture": { "!": [ [ "f_null", 4 ], "f_console_broken", "f_generator_broken", "f_centrifuge" ] }, "place_nested": [ { "chunks": [ "lab_spawn_7x7" ], diff --git a/data/json/mapgen/lab/lab_floorplans.json b/data/json/mapgen/lab/lab_floorplans.json index 7bd70ed17d36d..62b4a723ebeba 100644 --- a/data/json/mapgen/lab/lab_floorplans.json +++ b/data/json/mapgen/lab/lab_floorplans.json @@ -141,10 +141,9 @@ "c...c|.rrr...|-|X.ccc.X|" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "f": "f_null" }, + "furniture": { "f": "f_null", "P": "f_generator_broken" }, "terrain": { "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ], - "P": "t_generator_broken", "F": "t_chainfence_h", "f": "t_chainfence_v", "H": "t_chaingate_c", @@ -204,11 +203,8 @@ "..............l|X.ccc.X|" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "terrain": { - "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ], - "=": "t_conveyor", - "%": "t_machinery_heavy" - }, + "terrain": { "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ], "=": "t_conveyor" }, + "furniture": { "%": "f_machinery_heavy" }, "mapping": { "c": { "items": [ { "item": "chem_lab", "chance": 20 }, { "item": "tools_science", "chance": 20 } ] } }, "place_nested": [ { "chunks": [ "lab_spawn_9x9_wall_sw" ], "x": 13, "y": 1 }, @@ -254,12 +250,8 @@ "rrr.....!.....l|-------|" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "f": "f_null" }, - "terrain": { - "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ], - "!": [ "t_thconc_floor", "t_thconc_floor", "t_console_broken", "t_generator_broken" ], - "C": "t_centrifuge" - }, + "furniture": { "!": [ [ "f_null", 2 ], "f_console_broken", "f_generator_broken" ], "C": "f_centrifuge", "f": "f_null" }, + "terrain": { "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ] }, "mapping": { "c": { "items": [ { "item": "chem_lab", "chance": 10 }, { "item": "tools_science", "chance": 10 } ] }, "r": { "items": [ { "item": "cleaning", "chance": 30 } ] } @@ -533,13 +525,13 @@ "........................" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "?": "f_autodoc", "/": "f_autodoc_couch" }, + "furniture": { "?": "f_autodoc", "/": "f_autodoc_couch", "7": "f_console", "C": "f_centrifuge" }, "terrain": { ",": "t_floor_blue", - "C": "t_centrifuge", + "C": "t_floor_blue", "?": "t_floor_blue", "/": "t_floor_blue", - "7": "t_console", + "7": "t_floor_blue", "r": "t_floor_blue" }, "place_loot": [ { "item": "anesthetic_kit", "x": 15, "y": 11, "ammo": 100 } ], @@ -613,12 +605,12 @@ ], "palettes": [ "lab_palette" ], "terrain": { - "C": "t_centrifuge", + "C": "t_floor", "?": [ "t_concrete_wall", "t_concrete_wall", "t_door_glass_frosted_lab_c" ], "7": "t_floor", "8": "t_floor" }, - "furniture": { "7": "f_autodoc", "8": "f_autodoc_couch" }, + "furniture": { "C": "f_centrifuge", "7": "f_autodoc", "8": "f_autodoc_couch" }, "items": { "b": { "item": "hospital_bed", "chance": 33 }, "l": { "item": "surgery", "chance": 50 }, @@ -683,7 +675,8 @@ "........................" ], "palettes": [ "lab_palette" ], - "terrain": { "C": "t_centrifuge", "7": "t_console", ",": "t_floor_blue" }, + "furniture": { "7": "f_console", "C": "f_centrifuge" }, + "terrain": { "C": "t_floor_blue", "7": "t_floor_blue", ",": "t_floor_blue" }, "mapping": { "c": { "items": [ { "item": "office", "chance": 30 }, { "item": "tools_science", "chance": 15 } ] }, "l": { "items": [ { "item": "science", "chance": 60 } ] } @@ -749,13 +742,12 @@ ".......|.........|......" ], "palettes": [ "lab_palette" ], - "furniture": { "S": "f_null", "^": "f_indoor_plant", "f": "f_null" }, + "furniture": { "S": "f_null", "^": "f_indoor_plant", "P": "f_generator_broken", "f": "f_null" }, "terrain": { "F": "t_chainfence_h", "f": "t_chainfence_v", "H": "t_chaingate_c", "&": "t_radio_tower", - "P": "t_generator_broken", "S": "t_sewage_pump", "p": "t_sewage_pipe", "C": "t_gates_control_concrete_lab", @@ -829,15 +821,8 @@ ".........|....|---------" ], "palettes": [ "lab_palette", "lab_loot_home_office" ], - "furniture": { "^": "f_indoor_plant" }, - "terrain": { - "E": "t_elevator", - "e": "t_elevator_control_off", - "w": "t_water_sh", - "W": "t_water_dp", - "=": "t_door_lab_c", - "C": "t_centrifuge" - }, + "furniture": { "^": "f_indoor_plant", "C": "f_centrifuge" }, + "terrain": { "E": "t_elevator", "e": "t_elevator_control_off", "w": "t_water_sh", "W": "t_water_dp", "=": "t_door_lab_c" }, "mapping": { "t": { "items": [ { "item": "vending_food_items", "chance": 20 } ] } }, "place_loot": [ { "group": "everyday_corpse", "x": 17, "y": 15 }, @@ -938,7 +923,7 @@ ], "palettes": [ "lab_palette", "lab_loot_home_office" ], "furniture": { "F": "f_sofa", "B": "f_bathtub", "C": "f_counter", "O": "f_oven", "V": "f_table" }, - "terrain": { "w": "t_window_domestic", "`": "t_grass", "+": "t_door_lab_c" }, + "terrain": { "w": "t_window_domestic", "`": "t_grass_golf", "+": "t_door_lab_c" }, "mapping": { "t": { "items": [ { "item": "livingroom", "chance": 20 } ] }, "F": { "items": [ { "item": "livingroom", "chance": 5 } ] }, diff --git a/data/json/mapgen/lab/lab_floorplans_1side.json b/data/json/mapgen/lab/lab_floorplans_1side.json index 361515eb3e588..aba5a9e3042e7 100644 --- a/data/json/mapgen/lab/lab_floorplans_1side.json +++ b/data/json/mapgen/lab/lab_floorplans_1side.json @@ -166,7 +166,7 @@ }, { "monster": [ "mon_zombie_soldier" ], "x": [ 1, 21 ], "y": [ 1, 16 ], "pack_size": [ 1, 4 ], "chance": 40 } ], - "terrain": { "7": "t_console" }, + "furniture": { "7": "f_console" }, "mapping": { "l": { "items": [ @@ -254,8 +254,7 @@ { "monster": "mon_zombie_grabber", "x": [ 1, 5 ], "y": [ 12, 15 ] }, { "monster": "mon_zombie_scientist", "x": [ 11, 12 ], "y": [ 5, 10 ], "pack_size": [ 1, 2 ], "chance": 50 } ], - "furniture": { "^": "f_indoor_plant" }, - "terrain": { "7": "t_console", "C": "t_centrifuge" }, + "furniture": { "^": "f_indoor_plant", "7": "f_console", "C": "f_centrifuge" }, "mapping": { "X": { "items": [ { "item": "softdrugs", "chance": 40 }, { "item": "harddrugs", "chance": 30 } ] }, "r": { "items": [ { "item": "softdrugs", "chance": 40 }, { "item": "harddrugs", "chance": 30 } ] }, diff --git a/data/json/mapgen/lab/lab_floorplans_finale1level.json b/data/json/mapgen/lab/lab_floorplans_finale1level.json index ec5402e4a6b58..969856ef5d252 100644 --- a/data/json/mapgen/lab/lab_floorplans_finale1level.json +++ b/data/json/mapgen/lab/lab_floorplans_finale1level.json @@ -35,13 +35,13 @@ "........................" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "?": "f_autodoc", "/": "f_autodoc_couch" }, + "furniture": { "7": "f_console", "C": "f_centrifuge", "?": "f_autodoc", "/": "f_autodoc_couch" }, "terrain": { ",": "t_floor_blue", - "C": "t_centrifuge", + "C": "t_floor_blue", "?": "t_floor_blue", "/": "t_floor_blue", - "7": "t_console", + "7": "t_floor_blue", "r": "t_floor_blue" }, "place_loot": [ @@ -119,16 +119,8 @@ "......g..........g......" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "R": "f_rack" }, - "terrain": { - "C": "t_machinery_electronic", - "x": "t_machinery_heavy", - "?": "t_nanofab", - "r": "t_metal_floor", - "/": "t_nanofab_body", - "Y": "t_thconc_floor_olight", - "p": "t_metal_floor" - }, + "furniture": { "C": "f_machinery_electronic", "x": "f_machinery_heavy", "R": "f_rack" }, + "terrain": { "?": "t_nanofab", "r": "t_metal_floor", "/": "t_nanofab_body", "Y": "t_thconc_floor_olight", "p": "t_metal_floor" }, "mapping": { "r": { "item": { "item": "standard_template_construct" } }, "R": { "item": { "item": "nanomaterial" } } }, "place_monster": [ { "monster": "mon_secubot", "x": [ 1, 4 ], "y": [ 20, 22 ], "chance": 90 }, @@ -174,9 +166,9 @@ ".......................-" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "R": "f_rack", "D": "f_desk" }, + "furniture": { "C": "f_machinery_electronic", "R": "f_rack", "D": "f_desk" }, "fields": { "Q": { "field": "fd_fatigue", "intensity": 3 } }, - "terrain": { "C": "t_machinery_electronic", "r": "t_metal_floor", "Y": "t_thconc_floor_olight", "p": "t_metal_floor" }, + "terrain": { "r": "t_metal_floor", "Y": "t_thconc_floor_olight", "p": "t_metal_floor" }, "mapping": { "R": { "item": [ { "item": "dimensional_anchor" }, { "item": "phase_immersion_suit" } ] }, "D": { @@ -231,8 +223,8 @@ "........................" ], "palettes": [ "lab_palette", "lab_loot_research" ], - "furniture": { "V": "f_standing_tank" }, - "terrain": { ",": "t_floor_blue", "V": "t_floor_blue", "C": "t_centrifuge" }, + "furniture": { "V": "f_standing_tank", "C": "f_centrifuge" }, + "terrain": { ",": "t_floor_blue", "V": "t_floor_blue", "C": "t_floor_blue" }, "mapping": { "c": { "items": [ { "item": "mut_lab", "chance": 50 } ] } }, "computers": { "6": { diff --git a/data/json/mapgen/lab/lab_rooms.json b/data/json/mapgen/lab/lab_rooms.json index 99b271c604cec..00eb30d2923bf 100644 --- a/data/json/mapgen/lab/lab_rooms.json +++ b/data/json/mapgen/lab/lab_rooms.json @@ -267,7 +267,7 @@ "........." ], "palettes": [ "lab_palette" ], - "terrain": { "C": [ "t_centrifuge" ] } + "furniture": { "C": [ "f_centrifuge" ] } } }, { @@ -732,14 +732,15 @@ "object": { "mapgensize": [ 1, 1 ], "rows": [ "A" ], - "terrain": { + "terrain": { "A": "t_thconc_floor" }, + "furniture": { "A": [ - "t_machinery_heavy", - "t_machinery_heavy", - "t_machinery_electronic", - "t_machinery_light", - "t_centrifuge", - "t_console_broken" + "f_machinery_heavy", + "f_machinery_heavy", + "f_machinery_electronic", + "f_machinery_light", + "f_centrifuge", + "f_console_broken" ] } } @@ -986,7 +987,11 @@ ], "palettes": [ "lab_palette" ], "terrain": { "%": "t_thconc_floor" }, - "furniture": { "%": "f_treadmill", "5": [ "f_ergometer", "f_exercise" ], "`": "f_canvas_floor" }, + "furniture": { + "%": [ "f_treadmill", "f_treadmill_mechanical" ], + "5": [ "f_ergometer", "f_ergometer_mechanical", "f_exercise" ], + "`": "f_canvas_floor" + }, "items": { ".": { "item": "clutter_gym", "chance": 3 }, "l": { "item": "locker_gym", "chance": 30 }, diff --git a/data/json/mapgen/lab/lab_surface/lab_surface_big_z-1.json b/data/json/mapgen/lab/lab_surface/lab_surface_big_z-1.json index f838ba32b222c..1114307de4eaf 100644 --- a/data/json/mapgen/lab/lab_surface/lab_surface_big_z-1.json +++ b/data/json/mapgen/lab/lab_surface/lab_surface_big_z-1.json @@ -174,8 +174,7 @@ "*": "t_thconc_floor_olight", "e": "t_elevator", "m": "t_door_metal_c", - "w": "t_gates_control_brick", - "x": "t_console_broken" + "w": "t_gates_control_brick" }, "furniture": { "&": "f_trashcan", @@ -186,7 +185,8 @@ "f": "f_fridge", "l": "f_locker", "s": "f_stool", - "U": "f_utility_shelf" + "U": "f_utility_shelf", + "x": "f_console_broken" }, "items": { "d": { "item": "office", "chance": 60, "repeat": [ 2, 6 ] }, diff --git a/data/json/mapgen/lab/lab_surface/lab_surface_nested.json b/data/json/mapgen/lab/lab_surface/lab_surface_nested.json index 375238fd34f78..da5be15a3e112 100644 --- a/data/json/mapgen/lab/lab_surface/lab_surface_nested.json +++ b/data/json/mapgen/lab/lab_surface/lab_surface_nested.json @@ -1161,7 +1161,7 @@ "A": "t_strconc_floor", "c": "t_strconc_floor", "C": "t_strconc_floor", - "m": "t_machinery_heavy", + "m": "t_strconc_floor", "P": "t_sewage_pipe", "t": "t_strconc_floor", "S": "t_strconc_floor", @@ -1171,6 +1171,7 @@ "furniture": { "A": "f_air_filter", "C": "f_air_compressor", + "m": "f_machinery_heavy", "t": "f_standing_tank", "S": "f_standing_tank", "U": "f_utility_shelf", @@ -1224,7 +1225,7 @@ "D": "t_strconc_floor", "F": "t_strconc_floor", "L": "t_strconc_floor", - "m": "t_machinery_heavy", + "m": "t_strconc_floor", "R": "t_strconc_floor", "T": "t_strconc_floor", "u": "t_strconc_floor", @@ -1237,6 +1238,7 @@ "D": "f_drill_press", "F": "f_home_furnace", "L": "f_heavy_lathe", + "m": "f_machinery_heavy", "R": "f_router", "T": "f_tablesaw", "u": "f_utility_shelf", @@ -1873,19 +1875,34 @@ "type": "mapgen", "method": "json", "nested_mapgen_id": "surface_sub_hall_clutter", - "object": { "mapgensize": [ 1, 1 ], "rows": [ "X" ], "terrain": { "X": "t_strconc_floor" }, "furniture": { "X": "f_IV_pole" } } + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "X" ], + "terrain": { "X": "t_strconc_floor" }, + "furniture": { "X": [ "f_IV_pole", "f_desk", "f_counter" ] } + } }, { "type": "mapgen", "method": "json", "nested_mapgen_id": "surface_sub_hall_clutter", - "object": { "mapgensize": [ 1, 1 ], "rows": [ "X" ], "terrain": { "X": "t_strconc_floor" }, "furniture": { "X": "f_autoclave" } } + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "X" ], + "terrain": { "X": "t_strconc_floor" }, + "furniture": { "X": [ "f_autoclave", "f_console_broken", "f_centrifuge" ] } + } }, { "type": "mapgen", "method": "json", "nested_mapgen_id": "surface_sub_hall_clutter", - "object": { "mapgensize": [ 1, 1 ], "rows": [ "X" ], "terrain": { "X": "t_machinery_old" } } + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "X" ], + "terrain": { "X": "t_strconc_floor" }, + "furniture": { "X": [ "f_machinery_old", "f_machinery_light", "f_machinery_electronic" ] } + } }, { "type": "mapgen", diff --git a/data/json/mapgen/lab/lab_trains.json b/data/json/mapgen/lab/lab_trains.json index 64df9439a6449..4e863d34c528f 100644 --- a/data/json/mapgen/lab/lab_trains.json +++ b/data/json/mapgen/lab/lab_trains.json @@ -44,14 +44,8 @@ "failures": [ { "action": "damage" }, { "action": "alarm" }, { "action": "manhacks" } ] } }, - "terrain": { - "=": "t_chaingate_c", - "_": "t_chainfence_h", - "8": "t_potential_trans", - "P": "t_generator_broken", - "!": "t_sewage_pump", - "p": "t_sewage_pipe" - }, + "terrain": { "=": "t_chaingate_c", "_": "t_chainfence_h", "8": "t_potential_trans", "!": "t_sewage_pump", "p": "t_sewage_pipe" }, + "furniture": { "P": "f_generator_broken" }, "place_nested": [ { "chunks": [ "lab_train_subway_east" ], "x": 0, "y": 0, "neighbors": { "east": [ "subway" ] } }, { "chunks": [ "lab_train_subway_west" ], "x": 0, "y": 0, "neighbors": { "west": [ "subway" ] } }, diff --git a/data/json/mapgen/lab_subway_vent_shaft.json b/data/json/mapgen/lab_subway_vent_shaft.json index 32bb9e09bf2a2..548e622f1546a 100644 --- a/data/json/mapgen/lab_subway_vent_shaft.json +++ b/data/json/mapgen/lab_subway_vent_shaft.json @@ -4,7 +4,7 @@ "id": "lab_subway_vent_shaft", "terrain": { "2": "t_door_metal_c", - "%": "t_machinery_heavy", + "%": "t_metal_floor_no_roof", "-": "t_wall_metal", "3": "t_chaingate_c", ",": "t_region_groundcover_urban", @@ -15,10 +15,11 @@ "~": "t_water_pool_shallow", "<": "t_ladder_up", ">": "t_ladder_down", - "u": "t_chainfence_h", - "U": "t_chainfence_v", + "u": "t_chainfence", + "U": "t_chainfence", "#": "t_rock" - } + }, + "furniture": { "%": "f_machinery_heavy" } }, { "type": "mapgen", diff --git a/data/json/mapgen/lake_buildings/lighthouse.json b/data/json/mapgen/lake_buildings/lighthouse.json index 4e2a78c11c610..4f3c71aa72f79 100644 --- a/data/json/mapgen/lake_buildings/lighthouse.json +++ b/data/json/mapgen/lake_buildings/lighthouse.json @@ -336,12 +336,10 @@ "<": "t_wood_stairs_up", "Q": "t_open_air_rooved", ">": "t_wood_stairs_down", - "x": "t_generator_broken", - "y": "t_machinery_old", "#": "t_wall_wood", "0": "t_laminated_glass" }, - "furniture": { "M": [ "f_crate_c", "f_cardboard_box" ] }, + "furniture": { "M": [ "f_crate_c", "f_cardboard_box" ], "x": "f_generator_broken", "y": "f_machinery_old" }, "items": { "M": [ { "item": "fishing_items", "chance": 30, "repeat": [ 1, 2 ] }, @@ -393,11 +391,11 @@ "<": "t_wood_stairs_up", ">": "t_wood_stairs_down", "0": "t_laminated_glass", - "y": "t_machinery_old", "#": "t_grate", "+": "t_laminated_door_glass_c", "Q": "t_open_air_rooved" - } + }, + "furniture": { "y": "f_machinery_old" } } }, { diff --git a/data/json/mapgen/lan_center.json b/data/json/mapgen/lan_center.json index e5fd19f5c1abb..e4974ae70772a 100644 --- a/data/json/mapgen/lan_center.json +++ b/data/json/mapgen/lan_center.json @@ -35,44 +35,19 @@ "terrain": { "+": "t_reinforced_door_glass_c", ".": "t_floor", - "6": "t_console", - "_": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt", "t_shrub" ], - "a": "t_console_broken", - "d": "t_grass_long", + "_": [ [ "t_region_groundcover_urban", 8 ], "t_region_shrub_decorative" ], + "d": "t_region_groundcover", "s": "t_sidewalk", "w": "t_window", "|": "t_wall_w", "4": "t_gutter_downspout", "=": "t_door_locked", "U": "t_sidewalk", - "9": [ - "t_tree_blackjack", - "t_tree_walnut", - "t_tree_chestnut", - "t_tree_beech", - "t_tree_hazelnut", - "t_tree_cottonwood", - "t_tree", - "t_tree_elm", - "t_tree_dead", - "t_tree_apple", - "t_tree_pear", - "t_tree_cherry", - "t_tree_peach", - "t_tree_apricot", - "t_tree_plum", - "t_tree_mulberry", - "t_tree_elderberry", - "t_tree_pine", - "t_tree_birch", - "t_tree_willow", - "t_tree_maple", - "t_tree_hickory", - "t_tree_almond", - "t_tree_pecan" - ] + "9": [ "t_region_tree_shade", "t_region_tree_fruit" ] }, "furniture": { + "6": "f_console", + "a": "f_console_broken", "#": "f_table", "&": "f_trashcan", "C": "f_counter", @@ -85,7 +60,7 @@ "I": "f_desk", "S": "f_filing_cabinet", "U": [ "f_dumpster", "f_recycle_bin" ], - "d": [ "f_datura", "f_bluebell", "f_mutpoppy", "f_dahlia", "f_flower_tulip", "f_chamomile", "f_flower_spurge", "f_lily" ], + "d": "f_region_weed", "y": [ "f_indoor_plant_y", "f_indoor_plant" ], "R": "f_sink", "@": "f_sofa" @@ -189,10 +164,9 @@ "+": "t_reinforced_door_glass_c", "-": "t_wall_glass", ".": "t_floor", - "6": "t_console", "D": "t_door_c", "P": "t_wall_glass", - "_": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt", "t_shrub" ], + "_": [ [ "t_region_groundcover_urban", 8 ], "t_region_shrub_decorative" ], "d": "t_dirt", "p": "t_pavement", "s": "t_sidewalk", @@ -200,6 +174,7 @@ "4": "t_gutter_downspout" }, "furniture": { + "6": "f_console", "#": "f_table", "&": "f_trashcan", "C": "f_counter", diff --git a/data/json/mapgen/laundromat.json b/data/json/mapgen/laundromat.json index bd45dfd7d684c..10b291f557d46 100644 --- a/data/json/mapgen/laundromat.json +++ b/data/json/mapgen/laundromat.json @@ -39,7 +39,6 @@ ".": "t_linoleum_white", "=": "t_wall_glass", "A": "t_atm", - "C": "t_console_broken", "[": "t_door_glass_c", "_": "t_pavement", "l": "t_linoleum_gray", @@ -56,6 +55,7 @@ "&": "f_trashcan", "6": "f_arcade_machine", "B": "f_stool", + "C": "f_console_broken", "D": "f_dryer", "S": "f_sink", "T": "f_toilet", @@ -165,7 +165,7 @@ "sss4sssssssssss||||||||s" ], "terrain": { - " ": [ "t_grass", "t_grass", "t_dirt", "t_grass", "t_shrub", "t_tree_young" ], + " ": [ [ "t_region_groundcover_urban", 5 ], "t_region_shrub" ], "P": "t_floor", "p": "t_floor", ",": "t_floor", @@ -175,7 +175,6 @@ ".": "t_linoleum_white", "=": "t_wall_glass", "A": "t_atm", - "C": "t_console_broken", "[": "t_door_glass_c", "_": "t_pavement", "-": "t_pavement_y", @@ -183,10 +182,11 @@ "d": "t_sidewalk", "s": "t_sidewalk", "|": "t_wall_w", - "H": "t_grass", + "H": "t_region_groundcover_urban", "4": "t_gutter_downspout" }, "furniture": { + "C": "f_console_broken", "#": "f_counter", "}": "f_bookcase", "P": "f_desk", diff --git a/data/json/mapgen/mall/mall_second_floor.json b/data/json/mapgen/mall/mall_second_floor.json index 6681f69e49b1a..66da84c6b67a1 100644 --- a/data/json/mapgen/mall/mall_second_floor.json +++ b/data/json/mapgen/mall/mall_second_floor.json @@ -1144,7 +1144,14 @@ "S": "t_thconc_floor", "I": "t_thconc_floor" }, - "furniture": { "%": "f_counter", "*": "f_crate_c", "!": "f_beaded_door", "p": "f_desk", "]": "f_ergometer", "0": "f_exercise" }, + "furniture": { + "%": "f_counter", + "*": "f_crate_c", + "!": "f_beaded_door", + "p": "f_desk", + "]": [ "f_ergometer", "f_ergometer_mechanical" ], + "0": "f_exercise" + }, "items": { "K": { "item": "pottery", "chance": 30, "repeat": [ 2, 4 ] }, "J": { "item": "office", "chance": 20 }, @@ -1220,8 +1227,8 @@ "I": "t_thconc_floor" }, "furniture": { - "*": "f_treadmill", - "]": "f_ergometer", + "*": [ "f_treadmill", "f_treadmill_mechanical" ], + "]": [ "f_ergometer", "f_ergometer_mechanical" ], "!": "f_exercise", "&": "f_counter", "%": "f_shower", diff --git a/data/json/mapgen/megastore.json b/data/json/mapgen/megastore.json index 9bf37dfb18ade..73610490cbb8d 100644 --- a/data/json/mapgen/megastore.json +++ b/data/json/mapgen/megastore.json @@ -10,7 +10,7 @@ "^": "t_glass_roof", "1": "t_metal_railing", "%": "t_grate", - ",": "t_grass", + ",": "t_region_groundcover_urban", "-": "t_concrete_wall", "|": "t_concrete_wall", "+": "t_door_glass_c", @@ -23,10 +23,10 @@ "W": "t_sidewalk", "<": "t_stairs_up", ">": "t_stairs_down", - "6": "t_console_broken", "Y": "t_switchgear_s" }, "furniture": { + "6": "f_console_broken", "a": "f_armchair", "A": "f_sofa", "b": "f_bookcase", @@ -1989,7 +1989,7 @@ ], "rotation": 1, "palettes": [ "megastore" ], - "terrain": { "%": "t_machinery_heavy" } + "furniture": { "%": "f_machinery_heavy" } } }, { @@ -2256,6 +2256,7 @@ ], "rotation": 0, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ @@ -2308,6 +2309,7 @@ ], "rotation": 0, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ @@ -2360,6 +2362,7 @@ ], "rotation": 1, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ @@ -2412,6 +2415,7 @@ ], "rotation": 3, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 1, 22 ], "y": [ 1, 22 ] }, { "monster": "GROUP_SCHOOL", "x": [ 1, 22 ], "y": [ 1, 22 ], "chance": 20 } @@ -2467,6 +2471,7 @@ ], "rotation": [ 0, 3 ], "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ [ "null", 5 ], [ "roof_2x2_infrastructure", 20 ], [ "roof_2x2_infrastructure_2", 20 ], [ "roof_2x2_utilities", 20 ] ], @@ -2512,6 +2517,7 @@ ], "rotation": 1, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ @@ -2563,6 +2569,7 @@ ], "rotation": 3, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ [ "null", 5 ], [ "roof_2x2_infrastructure", 80 ], [ "roof_2x2_infrastructure_2", 40 ], [ "roof_2x2_utilities", 40 ] ], @@ -2608,6 +2615,7 @@ ], "rotation": 2, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ @@ -2659,6 +2667,7 @@ ], "rotation": 2, "palettes": [ "megastore" ], + "terrain": { " ": "t_flat_roof" }, "place_nested": [ { "chunks": [ [ "null", 5 ], [ "roof_2x2_infrastructure", 80 ], [ "roof_2x2_infrastructure_2", 40 ], [ "roof_2x2_utilities", 40 ] ], diff --git a/data/json/mapgen/microlab/microlab_connector.json b/data/json/mapgen/microlab/microlab_connector.json index ea60aae01867b..180fe707cc3b6 100644 --- a/data/json/mapgen/microlab/microlab_connector.json +++ b/data/json/mapgen/microlab/microlab_connector.json @@ -227,7 +227,8 @@ " |||||| |||||||||||" ], "palettes": [ "microlab" ], - "terrain": { "p": "t_sewage_pipe", "w": "t_water_pool_shallow", "%": "t_machinery_heavy", "S": "t_sewage_pump" }, + "terrain": { "p": "t_sewage_pipe", "w": "t_water_pool_shallow", "S": "t_sewage_pump" }, + "furniture": { "%": "f_machinery_heavy" }, "items": { "l": { "item": "sewage_plant", "chance": 75 } } } }, diff --git a/data/json/mapgen/microlab/microlab_edge_room_connector.json b/data/json/mapgen/microlab/microlab_edge_room_connector.json new file mode 100644 index 0000000000000..53085fbbaa153 --- /dev/null +++ b/data/json/mapgen/microlab/microlab_edge_room_connector.json @@ -0,0 +1,38 @@ +[ + { + "type": "mapgen", + "om_terrain": [ [ "microlab_generic_edge_room_connector" ] ], + "method": "json", + "object": { + "fill_ter": "t_strconc_floor", + "rows": [ + "|||||| PP PP PP ||||||", + " c|##| PP PP PP |##| ", + " 6|||| PP |||| PP ||||F ", + " F|XX= PP h PP =XX|F ", + " F|XX= PP |dd| PP =XX|F ", + "|||XX= PPPPPPPPPP =XX||2", + " F|XX= PPPPPPPPPP =XX|F ", + " F|XX======[[======XX|F ", + " F|XXXXXX=YPPY=XXXXXX|F ", + " |XXXXXX=YPPY=XXXXXX|F ", + "|||||||====[[====||||||2", + " 2YPPPPPPPPPPY2 ", + " 2YPPPPPPPPPPY2 ", + "||| |||===[[===||||2((|", + "cc= |XXX= PP =XXX|c ", + " [ |XXX= PP =XXX|c c ", + " = |XXX= PP =XXX|c c ", + "cc= |XXX= PP =XXX|c ", + "||| |XXX=YPPY=XXX||||||", + " c| ||||||PP||||||FFFFF", + " c| 2 c ", + " c| 2 c ", + " c|22|||||| ||||||c c ", + " |FFFF| |FFFF| " + ], + "palettes": [ "microlab" ], + "terrain": { "X": "t_region_shrub_decorative", "P": "t_carpet_concrete_red" } + } + } +] diff --git a/data/json/mapgen/microlab/microlab_reactor.json b/data/json/mapgen/microlab/microlab_reactor.json new file mode 100644 index 0000000000000..c68075f8e6209 --- /dev/null +++ b/data/json/mapgen/microlab/microlab_reactor.json @@ -0,0 +1,84 @@ +[ + { + "type": "mapgen", + "om_terrain": [ "microlab_reactor" ], + "method": "json", + "object": { + "fill_ter": "t_strconc_floor", + "rows": [ + "########################", + "########################", + "#######----------#######", + "######--````````--######", + "####---``````````---####", + "###--````gggggg````--###", + "###-`````ggAAgg`````-###", + "###-`````ggAAgg`````-###", + "###-`````gggggg`````-###", + "###-````````ggg`````-###", + "###--```````>g>````--###", + "####-((((((- --####", + "####-d6 6d -YYY --#####", + "####-Yh hY - --#----#", + "####- -222--##- ~-#", + "####- 6-YYY ----2--#", + "####- h6- -l b l-#", + "####- ^ 6-G55--l b l-#", + "####- ------ 2 l-#", + "####- ------(22(-------#", + "####- -- --######", + "####- 2 -######", + "####--- --#####", + "#####| |#####" + ], + "set": [ + { "square": "radiation", "amount": 1000, "x": 6, "y": 2, "x2": 17, "y2": 10 }, + { "square": "radiation", "amount": 1000, "x": 3, "y": 4, "x2": 20, "y2": 10 }, + { "square": "radiation", "amount": 100, "x": 11, "y": 11, "x2": 18, "y2": 13 }, + { "square": "radiation", "amount": 10000, "x": 9, "y": 5, "x2": 14, "y2": 8 } + ], + "palettes": [ "microlab" ], + "items": { "d": { "item": "cop_armory", "chance": 5 }, "l": { "item": "decontamination_room", "chance": 70 } }, + "terrain": { "-": "t_wall_metal", "`": "t_hole", "#": "t_rock", "G": "t_card_science", "g": "t_bridge", "A": "t_plut_generator" } + } + }, + { + "type": "mapgen", + "om_terrain": [ "microlab_reactor_b" ], + "method": "json", + "object": { + "rows": [ + "########################", + "########################", + "#######----------#######", + "######--wwwwwwww--######", + "####---wwwwwwwwww---####", + "###--wwww-gggg-wwww--###", + "###-wwwwwggAAggwwwww-###", + "###-wwwwwggAAggwwwww-###", + "###-wwwww-gggg-wwwww-###", + "###-wwwwwwwwgggwwwww-###", + "###--wwwwwww": "t_stairs_down", "<": "t_stairs_up", - "X": "t_card_military", - "x": "t_console_broken" + "X": "t_card_military" }, "furniture": { "d": "f_desk", @@ -146,7 +129,8 @@ "S": "f_sink", "6": "f_shower", "b": "f_bookcase", - "1": "f_speaker_cabinet" + "1": "f_speaker_cabinet", + "x": "f_console_broken" }, "items": { "r": { "item": "trash_cart", "chance": 50, "repeat": 2 }, @@ -227,16 +211,18 @@ "0": "t_reinforced_glass_shutter", "^": "t_elevator_control_off", "$": "t_elevator", - "x": "t_console_broken", + "%": "t_floor", + "x": "t_floor", "+": "t_door_metal_locked", "?": "t_door_metal_c_peep", "=": "t_door_locked", ">": "t_stairs_down", "<": "t_stairs_up", - "%": "t_machinery_electronic", "X": "t_card_military" }, "furniture": { + "%": "f_machinery_electronic", + "x": "f_console_broken", "d": "f_desk", "c": "f_chair", "a": "f_air_conditioner", @@ -323,7 +309,7 @@ "5": "t_floor", "6": "t_floor", "a": "t_floor", - "g": "t_generator_broken", + "g": "t_floor", "h": "t_switchgear_s", "i": "t_station_disc", "j": "t_current_trans", @@ -331,16 +317,24 @@ "0": "t_reinforced_glass_shutter_open", "^": "t_elevator_control_off", "$": "t_elevator", - "x": "t_console_broken", + "x": "t_floor", "+": "t_door_metal_locked", "?": "t_door_metal_c_peep", - "%": "t_machinery_electronic", + "%": "t_floor", ">": "t_stairs_down", "<": "t_stairs_up", "X": "t_mdoor_frame", "Y": "t_card_military" }, - "furniture": { "a": "f_air_conditioner", "5": "f_utility_shelf", "6": "f_locker", "4": "f_speaker_cabinet" }, + "furniture": { + "g": "f_generator_broken", + "%": "f_machinery_electronic", + "a": "f_air_conditioner", + "x": "f_console_broken", + "5": "f_utility_shelf", + "6": "f_locker", + "4": "f_speaker_cabinet" + }, "items": { "5": { "item": "radiation_meds", "chance": 60, "repeat": 2 }, "6": { "item": "radiation_equipment", "chance": 60 } }, "place_graffiti": [ { @@ -499,10 +493,17 @@ "Y": "t_card_military", "^": "t_elevator_control_off", "$": "t_elevator", - "x": "t_console_broken", - "%": "t_machinery_electronic" + "x": "t_rock_floor", + "%": "t_rock_floor" + }, + "furniture": { + "x": "f_console_broken", + "%": "f_machinery_electronic", + "1": "f_speaker_cabinet", + "4": "f_speaker_cabinet", + "a": "f_air_conditioner", + "c": "f_chair" }, - "furniture": { "1": "f_speaker_cabinet", "4": "f_speaker_cabinet", "a": "f_air_conditioner", "c": "f_chair" }, "computers": { "6": { "name": "Missile Controls", diff --git a/data/json/mapgen/movie_theater.json b/data/json/mapgen/movie_theater.json index 828860f9074b9..a12c43c19c6b2 100644 --- a/data/json/mapgen/movie_theater.json +++ b/data/json/mapgen/movie_theater.json @@ -248,16 +248,20 @@ "+": "t_door_metal_c", "D": "t_chaingate_l", "%": "t_chainfence", - "H": "t_generator_broken", "&": "t_flat_roof", "A": "t_flat_roof", ":": "t_flat_roof", "Y": "t_flat_roof", "X": "t_flat_roof", - "=": "t_flat_roof", - "p": "t_machinery_old" + "=": "t_flat_roof" + }, + "furniture": { + "H": "f_generator_broken", + "Y": "f_standing_tank", + "6": "f_water_heater", + "7": "f_roof_turbine_vent", + "p": "f_machinery_old" }, - "furniture": { "Y": "f_standing_tank", "6": "f_water_heater", "7": "f_roof_turbine_vent" }, "items": { "C": { "item": "snacks", "chance": 30, "repeat": [ 6, 12 ] } } } } diff --git a/data/json/mapgen/nested/basement_nested.json b/data/json/mapgen/nested/basement_nested.json index eed3e4d43c684..f00bf35ad6a8b 100644 --- a/data/json/mapgen/nested/basement_nested.json +++ b/data/json/mapgen/nested/basement_nested.json @@ -2760,7 +2760,13 @@ "O": "t_carpet_purple", "=": "t_carpet_purple" }, - "furniture": { "!": "f_ergometer", "@": "f_treadmill", "V": "f_exercise", "c": "f_bench", "B": "f_bigmirror" }, + "furniture": { + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "@": [ "f_treadmill", "f_treadmill_mechanical" ], + "V": "f_exercise", + "c": "f_bench", + "B": "f_bigmirror" + }, "traps": { "=": "tr_rollmat" }, "nested": { "1": { "chunks": [ [ "5x5_sauna_N", 30 ], [ "5x5_pool", 10 ], [ "5x5_gym_N", 60 ] ] } } } @@ -2791,7 +2797,13 @@ "O": "t_carpet_green", "=": "t_carpet_green" }, - "furniture": { "!": "f_ergometer", "@": "f_treadmill", "V": "f_exercise", "c": "f_bench", "B": "f_bigmirror" }, + "furniture": { + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "@": [ "f_treadmill", "f_treadmill_mechanical" ], + "V": "f_exercise", + "c": "f_bench", + "B": "f_bigmirror" + }, "traps": { "=": "tr_rollmat" }, "nested": { "1": { "chunks": [ [ "5x5_sauna_S", 30 ], [ "5x5_pool", 10 ], [ "5x5_gym_S", 60 ] ] } } } @@ -2822,7 +2834,13 @@ "O": "t_carpet_yellow", "=": "t_carpet_yellow" }, - "furniture": { "!": "f_ergometer", "@": "f_treadmill", "V": "f_exercise", "c": "f_bench", "B": "f_bigmirror" }, + "furniture": { + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "@": [ "f_treadmill", "f_treadmill_mechanical" ], + "V": "f_exercise", + "c": "f_bench", + "B": "f_bigmirror" + }, "traps": { "=": "tr_rollmat" }, "nested": { "1": { "chunks": [ [ "5x5_sauna_E", 30 ], [ "5x5_pool", 10 ], [ "5x5_gym_E", 60 ] ] } } } @@ -2853,7 +2871,13 @@ "O": "t_carpet_red", "=": "t_carpet_red" }, - "furniture": { "!": "f_ergometer", "@": "f_treadmill", "V": "f_exercise", "c": "f_bench", "B": "f_bigmirror" }, + "furniture": { + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "@": [ "f_treadmill", "f_treadmill_mechanical" ], + "V": "f_exercise", + "c": "f_bench", + "B": "f_bigmirror" + }, "traps": { "=": "tr_rollmat" }, "nested": { "1": { "chunks": [ [ "5x5_sauna_W", 30 ], [ "5x5_pool", 10 ], [ "5x5_gym_W", 60 ] ] } } } diff --git a/data/json/mapgen/nested/retail_nested.json b/data/json/mapgen/nested/retail_nested.json index 48f3c48b02fe2..ea74288305067 100644 --- a/data/json/mapgen/nested/retail_nested.json +++ b/data/json/mapgen/nested/retail_nested.json @@ -18,8 +18,9 @@ " A ", " VVV " ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "H": "f_table", "G": "f_table", @@ -88,8 +89,9 @@ " A ", " VVV " ], - "terrain": { " ": "t_floor", "L": "t_carpet_yellow", ".": "t_carpet_yellow", "?": "t_console_broken" }, + "terrain": { " ": "t_floor", "L": "t_carpet_yellow", ".": "t_carpet_yellow", "?": "t_carpet_yellow" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "H": "f_table", "G": "f_table", @@ -156,9 +158,10 @@ "A": "t_linoleum_white", "y": "t_linoleum_white", "Y": "t_linoleum_white", - "?": "t_console_broken" + "?": "t_linoleum_white" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "H": "f_table", "G": "f_table", @@ -225,9 +228,10 @@ "H": "t_carpet_green", "L": "t_carpet_green", ".": "t_carpet_green", - "?": "t_console_broken" + "?": "t_carpet_green" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "H": "f_table", "G": "f_displaycase", @@ -290,8 +294,9 @@ " A ", "y MMMM Y" ], - "terrain": { " ": "t_floor", "G": "t_carpet_red", "L": "t_carpet_red", ".": "t_carpet_red", "?": "t_console_broken" }, + "terrain": { " ": "t_floor", "G": "t_carpet_red", "L": "t_carpet_red", ".": "t_carpet_red", "?": "t_carpet_red" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "H": "f_table", "G": "f_displaycase", @@ -360,9 +365,10 @@ "L": "t_carpet_yellow", "B": "t_carpet_yellow", ".": "t_carpet_yellow", - "?": "t_console_broken" + "?": "t_carpet_yellow" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "B": "f_table", "H": "f_displaycase", @@ -447,9 +453,10 @@ "A": "t_linoleum_gray", "s": "t_linoleum_gray", "i": "t_linoleum_gray", - "?": "t_console_broken" + "?": "t_linoleum_gray" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "i": "f_oven", "s": "f_sink", @@ -520,8 +527,9 @@ " C QQVV ", "|| |||||" ], - "terrain": { " ": "t_floor", "?": "t_console_broken", "|": "t_brick_wall" }, + "terrain": { " ": "t_floor", "?": "t_floor", "|": "t_brick_wall" }, "furniture": { + "?": "f_console_broken", "A": "f_stool", "B": "f_counter", "C": "f_table", @@ -623,8 +631,9 @@ " b LLL ", "|| |||||" ], - "terrain": { " ": "t_floor", "?": "t_console_broken", "|": "t_brick_wall" }, + "terrain": { " ": "t_floor", "?": "t_floor", "|": "t_brick_wall" }, "furniture": { + "?": "f_console_broken", "A": "f_stool", "B": "f_counter", "C": "f_table", @@ -721,8 +730,16 @@ " ", "bb C" ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, - "furniture": { "A": "f_stool", "B": "f_workbench", "C": "f_rack_wood", "d": "f_mannequin", "e": "f_mannequin", "b": "f_bench" }, + "terrain": { " ": "t_floor", "?": "t_floor" }, + "furniture": { + "?": "f_console_broken", + "A": "f_stool", + "B": "f_workbench", + "C": "f_rack_wood", + "d": "f_mannequin", + "e": "f_mannequin", + "b": "f_bench" + }, "items": { "C": [ { "item": "SUS_tailoring_materials", "chance": 30, "repeat": [ 1, 2 ] } ], "d": [ { "item": "SUS_mannequin_formal_mens", "chance": 30 } ], @@ -752,8 +769,9 @@ " b LLL ", "|| |||||" ], - "terrain": { " ": "t_floor", "?": "t_console_broken", "|": "t_brick_wall" }, + "terrain": { " ": "t_floor", "?": "t_floor", "|": "t_brick_wall" }, "furniture": { + "?": "f_console_broken", "A": "f_stool", "B": "f_counter", "C": "f_table", @@ -843,8 +861,16 @@ "A ", "BB C" ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, - "furniture": { "A": "f_stool", "B": "f_workbench", "C": "f_rack_wood", "d": "f_mannequin", "e": "f_mannequin", "b": "f_bench" }, + "terrain": { " ": "t_floor", "?": "t_floor" }, + "furniture": { + "?": "f_console_broken", + "A": "f_stool", + "B": "f_workbench", + "C": "f_rack_wood", + "d": "f_mannequin", + "e": "f_mannequin", + "b": "f_bench" + }, "items": { "C": [ { "item": "SUS_tailoring_materials", "chance": 10, "repeat": [ 1, 2 ] }, @@ -881,8 +907,9 @@ " b QQQ ", "|| |||||" ], - "terrain": { " ": "t_floor", "?": "t_console_broken", "|": "t_brick_wall" }, + "terrain": { " ": "t_floor", "?": "t_floor", "|": "t_brick_wall" }, "furniture": { + "?": "f_console_broken", "A": "f_stool", "B": "f_counter", "C": "f_table", @@ -967,8 +994,16 @@ "A ", "BB C" ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, - "furniture": { "A": "f_stool", "B": "f_workbench", "C": "f_rack_wood", "d": "f_mannequin", "e": "f_mannequin", "b": "f_bench" }, + "terrain": { " ": "t_floor", "?": "t_floor" }, + "furniture": { + "?": "f_console_broken", + "A": "f_stool", + "B": "f_workbench", + "C": "f_rack_wood", + "d": "f_mannequin", + "e": "f_mannequin", + "b": "f_bench" + }, "items": { "C": [ { "item": "SUS_tailoring_materials", "chance": 10, "repeat": [ 1, 2 ] }, @@ -997,8 +1032,9 @@ "B zz", "Cyz " ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor", "?": "t_floor" }, "furniture": { + "?": "f_console_broken", "A": "f_chair", "B": "f_desk", "C": "f_rack", @@ -1032,8 +1068,9 @@ " zz", "CDF " ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor", "?": "t_floor" }, "furniture": { + "?": "f_console_broken", "A": "f_chair", "B": "f_desk", "C": "f_rack", @@ -1067,8 +1104,9 @@ "G ", "ybb " ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor", "?": "t_floor" }, "furniture": { + "?": "f_console_broken", "G": "f_locker", "b": "f_bench", "d": "f_filing_cabinet", @@ -1096,14 +1134,15 @@ "G ", "y C " ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor" }, "furniture": { "C": "f_rack", "G": "f_sofa", "d": "f_filing_cabinet", "D": "f_vending_c", "F": "f_vending_c", - "y": [ "f_indoor_plant", "f_indoor_plant_y" ] + "y": [ "f_indoor_plant", "f_indoor_plant_y" ], + "?": "f_console_broken" }, "vendingmachines": { "D": { "item_group": "vending_drink" }, "F": { "item_group": "vending_food" } }, "items": { @@ -1126,8 +1165,9 @@ "BA ", "y GC" ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor" }, "furniture": { + "?": "f_console_broken", "A": "f_chair", "B": "f_desk", "C": "f_rack", @@ -1158,7 +1198,7 @@ "G b ", "yz CC" ], - "terrain": { " ": "t_floor", "?": "t_console_broken" }, + "terrain": { " ": "t_floor" }, "furniture": { "A": "f_chair", "B": "f_desk", @@ -1170,7 +1210,8 @@ "D": "f_vending_c", "F": "f_vending_c", "y": [ "f_indoor_plant", "f_indoor_plant_y" ], - "z": [ [ "f_cardboard_box", 5 ], "f_crate_c" ] + "z": [ [ "f_cardboard_box", 5 ], "f_crate_c" ], + "?": "f_console_broken" }, "vendingmachines": { "D": { "item_group": "vending_drink" }, "F": { "item_group": "vending_food" } }, "items": { @@ -1259,8 +1300,9 @@ "F * | ", "YPPQQSY| |j " ], - "terrain": { "?": "t_console_broken", "|": "t_brick_wall", "*": "t_door_c" }, + "terrain": { "|": "t_brick_wall", "*": "t_door_c" }, "furniture": { + "?": "f_console_broken", "L": "f_table", "H": "f_chair", "G": "f_sofa", diff --git a/data/json/mapgen/nested/shelter_nested.json b/data/json/mapgen/nested/shelter_nested.json index 382fffc85f165..61821048e0dc4 100644 --- a/data/json/mapgen/nested/shelter_nested.json +++ b/data/json/mapgen/nested/shelter_nested.json @@ -32,7 +32,7 @@ " " ], "terrain": { " ": "t_null" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan", "6": "f_console" }, "computers": { "6": { "name": "Evac shelter computer", @@ -81,10 +81,17 @@ "terrain": { ":": [ "t_window_frame", "t_window_no_curtains" ], "+": [ "t_door_c", "t_door_b" ], - "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ], - "x": "t_console_broken" + "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ] + }, + "furniture": { + "b": "f_bench", + "c": "f_cupboard", + "l": "f_locker", + "S": "f_sink", + "%": "f_trashcan", + "6": "f_console", + "x": "f_console_broken" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, "computers": { "6": { "name": "Evac shelter computer", @@ -143,10 +150,16 @@ "terrain": { ":": [ "t_window_frame", "t_window_no_curtains" ], "+": [ "t_door_c", "t_door_b" ], - "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ], - "6": "t_console_broken" + "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ] + }, + "furniture": { + "b": "f_bench", + "c": "f_cupboard", + "l": [ [ "f_locker", 2 ], "f_wreckage" ], + "S": "f_sink", + "%": "f_trashcan", + "6": "f_console_broken" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": [ [ "f_locker", 2 ], "f_wreckage" ], "S": "f_sink", "%": "f_trashcan" }, "items": { "l": { "item": "shelter_supplies", "chance": 40 }, "c": [ { "item": "trash", "chance": 1 }, { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 10 } ], @@ -189,7 +202,7 @@ " " ], "terrain": { " ": "t_null" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan", "6": "f_console" }, "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 70 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } }, "computers": { "6": { @@ -236,12 +249,19 @@ " |||||:||+|:||||| " ], "terrain": { - "x": "t_console_broken", ":": [ "t_window_frame", "t_window" ], "+": [ "t_door_c", "t_door_b" ], "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ] }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "furniture": { + "x": "f_console_broken", + "b": "f_bench", + "c": "f_cupboard", + "l": "f_locker", + "S": "f_sink", + "%": "f_trashcan", + "6": "f_console" + }, "computers": { "6": { "name": "Evac shelter computer", @@ -296,10 +316,16 @@ "terrain": { ":": [ "t_window_frame", "t_window" ], "+": [ "t_door_c", "t_door_b" ], - "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ], - "6": "t_console_broken" + "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ] + }, + "furniture": { + "b": "f_bench", + "c": "f_cupboard", + "l": [ [ "f_locker", 2 ], "f_wreckage" ], + "S": "f_sink", + "%": "f_trashcan", + "6": "f_console_broken" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": [ [ "f_locker", 2 ], "f_wreckage" ], "S": "f_sink", "%": "f_trashcan" }, "items": { "l": { "item": "shelter_supplies", "chance": 40 }, "c": [ { "item": "trash", "chance": 1 }, { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 10 } ], @@ -342,7 +368,7 @@ " " ], "terrain": { " ": "t_null" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan", "6": "f_console" }, "computers": { "6": { "name": "Evac shelter computer", @@ -392,10 +418,17 @@ ":": [ "t_window_frame", "t_window_no_curtains" ], "+": [ "t_door_c", "t_door_b" ], "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ], - "*": "t_ladder_up", - "x": "t_console_broken" + "*": "t_ladder_up" + }, + "furniture": { + "b": "f_bench", + "c": "f_cupboard", + "l": "f_locker", + "S": "f_sink", + "%": "f_trashcan", + "6": "f_console", + "x": "f_console_broken" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, "computers": { "6": { "name": "Evac shelter computer", @@ -455,11 +488,17 @@ ":": [ "t_window_frame", "t_window" ], "+": [ "t_door_c", "t_door_b" ], "=": [ "t_door_b", "t_door_locked_interior", "t_door_c", "t_door_o" ], - "*": "t_ladder_up", - "6": [ "t_console", "t_console_broken" ], - "x": "t_console_broken" + "*": "t_ladder_up" + }, + "furniture": { + "b": "f_bench", + "c": "f_cupboard", + "l": [ [ "f_locker", 2 ], "f_wreckage" ], + "S": "f_sink", + "%": "f_trashcan", + "6": [ "f_console", "f_console_broken" ], + "x": "f_console_broken" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": [ [ "f_locker", 2 ], "f_wreckage" ], "S": "f_sink", "%": "f_trashcan" }, "items": { "l": { "item": "shelter_supplies", "chance": 40 }, "c": [ { "item": "trash", "chance": 1 }, { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 10 } ], diff --git a/data/json/mapgen/office_cubical.json b/data/json/mapgen/office_cubical.json index 336462507c51a..8b03ed245c8b8 100644 --- a/data/json/mapgen/office_cubical.json +++ b/data/json/mapgen/office_cubical.json @@ -33,14 +33,13 @@ "ssssssssssssssssssssssss" ], "terrain": { - " ": [ "t_grass", "t_grass", "t_dirt" ], - "$": "t_shrub", + " ": "t_region_groundcover_urban", + "$": "t_region_shrub_decorative", "+": "t_door_c", "-": "t_wall_w", "D": "t_door_locked", "s": "t_sidewalk", "w": "t_window", - "x": "t_console_broken", "|": "t_wall_w", "4": "t_gutter_downspout" }, @@ -55,7 +54,8 @@ "l": "f_locker", "n": "f_safe_l", "o": "f_bookcase", - "t": "f_table" + "t": "f_table", + "x": "f_console_broken" }, "vendingmachines": { "V": { } }, "toilets": { "T": { } }, @@ -163,15 +163,14 @@ " ##############ssssssss" ], "terrain": { - " ": [ "t_grass", "t_grass", "t_dirt" ], - "$": "t_shrub", + " ": "t_region_groundcover_urban", + "$": "t_region_shrub_decorative", "+": "t_door_c", "-": "t_wall_w", "D": "t_door_locked", "s": "t_sidewalk", "W": "t_window_domestic", "w": "t_window", - "x": "t_console_broken", "|": "t_wall_w", "#": "t_brick_wall", "R": "t_sidewalk", @@ -192,7 +191,8 @@ "l": "f_locker", "n": "f_safe_l", "o": "f_bookcase", - "t": "f_table" + "t": "f_table", + "x": "f_console_broken" }, "vendingmachines": { "V": { } }, "toilets": { "T": { } }, diff --git a/data/json/mapgen/outpost.json b/data/json/mapgen/outpost.json index eb38a164cfa65..d0bc4089fb65e 100644 --- a/data/json/mapgen/outpost.json +++ b/data/json/mapgen/outpost.json @@ -31,31 +31,17 @@ "|x xx x|", "|----------++----------|" ], + "fill_ter": "t_thconc_floor", "terrain": { - " ": [ "t_grass_dead", "t_grass", "t_grass_long", "t_dirt", "t_grass_tall" ], - "x": [ "t_grass_dead", "t_grass", "t_grass_long", "t_dirt", "t_grass_tall" ], - ".": "t_floor", - "!": "t_floor", - "&": "t_floor", - "1": "t_floor", - "l": "t_floor", - "c": "t_floor", - "t": "t_floor", - "r": "t_floor", - "L": "t_floor", - "b": "t_floor", - "S": "t_floor", - "T": "t_floor", - "C": "t_floor", - "X": "t_floor", + " ": "t_region_groundcover", + "x": "t_region_groundcover", "-": "t_chainfence", "|": "t_chainfence", "/": "t_concrete_wall", "+": "t_chaingate_l", "*": "t_door_c", "=": "t_door_locked", - ";": "t_door_metal_c", - "p": "t_plut_generator" + ";": "t_door_metal_c" }, "furniture": { "t": "f_table", @@ -69,7 +55,8 @@ "l": "f_locker", "L": "f_locker", "b": "f_bunkbed", - "T": "f_trashcan" + "T": "f_trashcan", + "p": "f_compact_ASRG_containment" }, "items": { "b": { "item": "army_bed", "chance": 60 }, @@ -191,33 +178,17 @@ "|x xx x|", "|----------++----------|" ], + "fill_ter": "t_thconc_floor", "terrain": { - " ": [ "t_grass_dead", "t_grass", "t_grass_long", "t_dirt", "t_grass_tall" ], - "x": [ "t_grass_dead", "t_grass", "t_grass_long", "t_dirt", "t_grass_tall" ], - ".": "t_floor", - "!": "t_floor", - "&": "t_floor", - "1": "t_floor", - "l": "t_floor", - "c": "t_floor", - "d": "t_floor", - "t": "t_floor", - "r": "t_floor", - "f": "t_floor", - "L": "t_floor", - "b": "t_floor", - "S": "t_floor", - "T": "t_floor", - "C": "t_floor", - "X": "t_floor", + " ": "t_region_groundcover", + "x": "t_region_groundcover", "-": "t_chainfence", "|": "t_chainfence", "/": "t_concrete_wall", "+": "t_chaingate_l", "*": "t_door_c", "=": "t_door_locked", - ";": "t_door_metal_c", - "p": "t_plut_generator" + ";": "t_door_metal_c" }, "furniture": { "t": "f_table", @@ -233,7 +204,8 @@ "b": "f_bunkbed", "d": "f_desk", "f": "f_fridge", - "T": "f_trashcan" + "T": "f_trashcan", + "p": "f_compact_ASRG_containment" }, "items": { "b": { "item": "army_bed", "chance": 60 }, diff --git a/data/json/mapgen/parking_garage.json b/data/json/mapgen/parking_garage.json index e9d743f0882c8..a46fdb514db2d 100644 --- a/data/json/mapgen/parking_garage.json +++ b/data/json/mapgen/parking_garage.json @@ -15,7 +15,7 @@ "'": "t_strconc_floor", "+": "t_door_c", "!": "t_door_metal_locked", - ".": [ [ "t_dirt", 5 ], [ "t_grass", 10 ], [ "t_grass_long", 7 ], [ "t_shrub", 1 ] ], + ".": [ [ "t_region_groundcover_urban", 25 ], [ "t_region_shrub", 1 ] ], "w": "t_window", "W": "t_reinforced_glass", "_": "t_pavement", @@ -31,7 +31,6 @@ "D": "t_strconc_floor", "c": "t_linoleum_white", "r": "t_linoleum_white", - "x": "t_console_broken", ">": "t_stairs_down", "<": "t_stairs_up", "I": "t_column", @@ -39,11 +38,19 @@ "g": "t_chaingate_l", "#": "t_rock", "*": "t_open_air", - "E": "t_elevator", - "@": "t_generator_broken", - "&": "t_machinery_heavy" + "E": "t_elevator" + }, + "furniture": { + "x": "f_console_broken", + "@": "f_generator_broken", + "&": "f_machinery_heavy", + "c": "f_counter", + "d": "f_desk", + "D": "f_dumpster", + "h": "f_chair", + "F": "f_filing_cabinet", + "%": "f_solar_unit" }, - "furniture": { "c": "f_counter", "d": "f_desk", "D": "f_dumpster", "h": "f_chair", "F": "f_filing_cabinet", "%": "f_solar_unit" }, "items": { "D": { "item": "office", "chance": 45, "repeat": [ 1, 2 ] }, "Y": { "item": "jackets", "chance": 55, "repeat": [ 1, 6 ] }, diff --git a/data/json/mapgen/pawn_shop.json b/data/json/mapgen/pawn_shop.json index 40bfe2f43a618..10a7e694ed484 100644 --- a/data/json/mapgen/pawn_shop.json +++ b/data/json/mapgen/pawn_shop.json @@ -33,7 +33,7 @@ "..............'U": "t_stairs_down", - "A": "t_metal_floor", "C": "t_dirtmound", "~": "t_water_sh" }, - "furniture": { "#": "f_wreckage", "A": "f_safe_l" }, + "furniture": { "#": "f_wreckage", "6": "f_machinery_light", "e": "f_machinery_heavy", "r": "f_console_broken", "A": "f_safe_l" }, "place_loot": [ { "group": "guns_pistol_rare", "x": 0, "y": 9, "chance": 70, "ammo": 95, "magazine": 100 } ], "place_monsters": [ { "monster": "GROUP_RAZORCLAW", "x": [ 2, 21 ], "y": [ 2, 21 ], "density": 0.4 } ] } @@ -141,19 +125,22 @@ "........................", "........................" ], + "fill_ter": "t_metal_floor", "terrain": { " ": "t_metal_floor", - "#": "t_metal_floor", "+": "t_door_metal_c", "-": "t_wall_metal", ".": "t_rock", - "6": "t_machinery_light", "C": "t_dirtmound", - "R": "t_plut_generator", - "e": "t_machinery_heavy", "~": "t_water_sh" }, - "furniture": { "#": "f_wreckage" }, + "furniture": { + "6": "f_machinery_light", + "e": "f_machinery_heavy", + "r": "f_console_broken", + "R": "f_compact_ASRG_containment", + "#": "f_wreckage" + }, "items": { "C": { "item": "razorclaw_nest", "chance": 80 } }, "place_monsters": [ { "monster": "GROUP_RAZORCLAW", "x": [ 12, 21 ], "y": [ 9, 13 ], "density": 0.2 } ], "place_monster": [ { "monster": "mon_alpha_razorclaw", "x": 13, "y": 11 } ] @@ -190,21 +177,24 @@ "........................", "........................" ], + "fill_ter": "t_metal_floor", "terrain": { " ": "t_metal_floor", - "#": "t_metal_floor", "+": "t_door_metal_c", "-": "t_wall_metal", ".": "t_rock", - "6": "t_machinery_light", - "9": "t_metal_floor", "<": "t_stairs_up", - "A": "t_metal_floor", "C": "t_dirtmound", - "e": "t_machinery_heavy", "~": "t_water_sh" }, - "furniture": { "#": "f_wreckage", "9": "f_locker", "A": "f_standing_tank" }, + "furniture": { + "6": "f_machinery_light", + "e": "f_machinery_heavy", + "r": "f_console_broken", + "9": "f_locker", + "A": "f_standing_tank", + "#": "f_wreckage" + }, "items": { "9": { "item": "hardware_plumbing", "chance": 90 }, "C": { "item": "razorclaw_nest", "chance": 70 } }, "place_monsters": [ { "monster": "GROUP_RAZORCLAW", "x": [ 0, 9 ], "y": [ 9, 13 ], "density": 0.05 } ] } diff --git a/data/json/mapgen/robofachq_static.json b/data/json/mapgen/robofachq_static.json index 3c7ca357af165..f46a4463a6431 100644 --- a/data/json/mapgen/robofachq_static.json +++ b/data/json/mapgen/robofachq_static.json @@ -121,13 +121,13 @@ "fill_ter": "t_thconc_floor", "rows": [ "############################################| |############################################", - "########|||||||||||||||||||||||||#|||||||||||||22|||############################################", + "########|||||||||||||||||||||||||#|||||||||||||55|||############################################", "########|k ht|A h ^|#|lll|lllll| YY |############################################", "########|i k k htth ht| Cd6ddC |#|bYb|bYbYb|T YY T|########||||||||############################", "########|k o k htth ht| CCCCCC |#|b b|b b b|| YY ||######||=A6666A=||##########################", "########| W ^|^ h ^|#|l l|l l l| YY |######|,=Y Y=,|##########################", "########|FFFF| htth ?||||[[||||||l l|l l l|T YY T|######|,= htth =,|##########################", - "########|||||| htth ?||^^ ^^|| |||22||||||||||,= htth =,|##########################", + "########|||||| htth ?||^^ ^^|| |||55||||||||||,= htth =,|##########################", "########|ffff| 2 YY 2Y bbb bbbb| |L | i|,= htth =,|##########################", "########| |^??t t??^| ,, ||||||||||||| |LY2 Y;|,= htth =,|##########################", "###||||||hd ||||||||||| ,, 2 r r r| d( Y b|||||2||,= htth =,|##########################", @@ -179,11 +179,10 @@ "E": "t_elevator_control", "Y": "t_thconc_floor_olight", "#": "t_rock", - "6": "t_console", "R": "t_railing", "W": "t_water_dispenser" }, - "furniture": { ":": "f_server", "K": "f_counter", "H": "f_armchair", "L": "f_locker", "f": "f_filing_cabinet" }, + "furniture": { "6": "f_console", ":": "f_server", "K": "f_counter", "H": "f_armchair", "L": "f_locker", "f": "f_filing_cabinet" }, "item": { "A": { "item": "american_flag" } }, "items": { "F": { "item": "fridge", "chance": 80 }, @@ -211,7 +210,7 @@ { "item": "lab_bookshelves", "chance": 55, "repeat": [ 1, 3 ] } ] }, - "monster": { "T": { "monster": "mon_turret_rifle" } }, + "monster": { "T": { "monster": "mon_robofac_laserturret_mk1" } }, "npcs": { "G": { "class": "hub_security" }, "Q": { "class": "hub_security_head" } } } }, @@ -284,18 +283,18 @@ "E": "t_elevator_control", "Y": "t_thconc_floor_olight", "#": "t_rock", - "6": "t_console", "R": "t_railing", "W": "t_water_dispenser" }, "furniture": { + "6": "f_console", "K": "f_counter", "M": "f_counter", "S": "f_table", "A": "f_canvas_wall", "%": "f_canvas_door", - "E": "f_ergometer", - "T": "f_treadmill", + "E": [ "f_ergometer", "f_ergometer_mechanical" ], + "T": [ "f_treadmill", "f_treadmill_mechanical" ], "X": "f_exercise" }, "sealed_item": { @@ -401,23 +400,23 @@ "E": "t_elevator_control", "Y": "t_thconc_floor_olight", "#": "t_rock", - "6": "t_console", "R": "t_railing", - "9": "t_conveyor", - "7": "t_machinery_light", - "8": "t_machinery_heavy", - "&": "t_machinery_electronic" + "9": "t_conveyor" }, "furniture": { + "6": "f_console", "K": "f_counter", "S": "f_table", "A": "f_canvas_wall", "%": "f_canvas_door", "H": "f_armchair", "M": "f_server", - "E": "f_ergometer", - "T": "f_treadmill", - "X": "f_exercise" + "E": [ "f_ergometer", "f_ergometer_mechanical" ], + "T": [ "f_treadmill", "f_treadmill_mechanical" ], + "X": "f_exercise", + "7": "f_machinery_light", + "8": "f_machinery_heavy", + "&": "f_machinery_electronic" }, "items": { "S": [ @@ -450,19 +449,19 @@ "##############################################||5555||tt tt|####################################", "#####################################||||||||||^ ^| h h|####################################", "#####################################|rrrrrrrr|^ ^| |####################################", - "#####################################|r r|| ||||2|||####################################", + "#####################################|r r||T T||||2|||####################################", "#####################################|r YY 2 (t r|####################################", "#####################################|||||||||| YY (thY r|####################################", - "#####################################|bbbbbbbb| YY (t Y r|####################################", + "#####################################|bbbbbbbb| YY (tGY r|####################################", "#####################################|Y Y2 ( r|####################################", "#####################################| llllll ||2222||||2|||####################################", - "#####################################|2||||||2|^ Y^|####################################", + "#####################################|2||||||2|^ G Y^|####################################", "#####################################| ~| |~ |^ Y^|####################################", "#####################################| i| |i |^ Y^|####################################", "#####################################||||||||||| ||||||||####################################", "#####################################|lll 2 ^|##########################################", "#####################################|^ ( YY ^|##########################################", - "#####################################| d ( YY ^|##########################################", + "#####################################| dG ( YY ^|##########################################", "#####################################|^hdh ( ^|##########################################", "#####################################|||||||| ||||##########################################" ], @@ -472,7 +471,9 @@ "l": [ { "item": "NC_ROBOFAC_FIELD_RESEARCHER_worn", "chance": 50 }, { "item": "NC_ROBOFAC_SCIENTIST_worn", "chance": 50 } ], "i": { "item": "cleaning", "chance": 50 }, "B": [ { "item": "textbooks", "chance": 50 }, { "item": "manuals", "chance": 50 } ] - } + }, + "monster": { "T": { "monster": "mon_robofac_laserturret_mk1" } }, + "npcs": { "G": { "class": "hub_security" } } } }, { @@ -535,15 +536,8 @@ "################################################################################################" ], "palettes": [ "robofachq" ], - "terrain": { - "-": "t_wall_metal", - "e": "t_elevator", - "E": "t_elevator_control", - "Y": "t_thconc_floor_olight", - "#": "t_rock", - "6": "t_console" - }, - "furniture": { ":": "f_server", "K": "f_counter" }, + "terrain": { "-": "t_wall_metal", "e": "t_elevator", "E": "t_elevator_control", "Y": "t_thconc_floor_olight", "#": "t_rock" }, + "furniture": { "6": "f_console", ":": "f_server", "K": "f_counter" }, "items": { "r": [ { "item": "electronics", "chance": 75, "repeat": [ 1, 5 ] } ] } } }, @@ -613,9 +607,9 @@ "w": "t_water_pool_shallow", "E": "t_elevator_control", "Y": "t_thconc_floor_olight", - "#": "t_rock", - "6": "t_console" + "#": "t_rock" }, + "furniture": { "6": "f_console" }, "items": { "B": [ { "item": "magazines", "chance": 75, "repeat": [ 1, 5 ] }, diff --git a/data/json/mapgen/s_bookstore.json b/data/json/mapgen/s_bookstore.json index 625a11737e3a7..6db5302096468 100644 --- a/data/json/mapgen/s_bookstore.json +++ b/data/json/mapgen/s_bookstore.json @@ -33,13 +33,10 @@ "************************" ], "terrain": { - "#": "t_floor", - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_dirt", 2 ], [ "t_grass_long", 4 ] ], - "^": [ "t_tree_walnut", "t_tree_chestnut", "t_tree_beech", "t_tree", "t_tree_hazelnut" ], + "*": "t_region_groundcover_urban", + "^": "t_region_tree_nut", "+": "t_door_c", "-": "t_wall_w", - ".": "t_floor", ":": "t_door_glass_c", "O": "t_window", "|": "t_wall_w", @@ -48,6 +45,7 @@ "~": "t_sidewalk" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "T": "f_table", "]": "f_rack", @@ -253,8 +251,7 @@ ], "terrain": { "#": "t_floor", - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_dirt", 2 ], [ "t_grass_long", 4 ] ], + "*": "t_region_groundcover_urban", "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", @@ -262,11 +259,12 @@ "=": "t_wall_glass", ">": "t_stairs_up", "O": "t_window", - "q": "t_grass", + "q": "t_region_groundcover_urban", "|": "t_wall_w", "~": "t_sidewalk" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "T": "f_table", "[": "f_rack", @@ -459,21 +457,21 @@ "************************" ], "terrain": { - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_dirt", 2 ], [ "t_grass_long", 4 ] ], + "*": "t_region_groundcover_urban", "+": [ "t_door_c", "t_door_locked" ], "-": "t_wall_w", ".": "t_floor", "O": "t_window", "S": "t_sidewalk", - "^": [ "t_tree_walnut", "t_tree_chestnut", "t_tree_beech", "t_tree", "t_tree_hazelnut" ], - "o": "t_dirt", - "q": "t_dirt", + "^": "t_region_tree_nut", + "o": "t_region_groundcover_barren", + "q": "t_region_groundcover_barren", "|": "t_wall_w", "4": "t_gutter_downspout", "~": "t_sidewalk" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "S": "f_statue", "T": "f_table", diff --git a/data/json/mapgen/s_clothing.json b/data/json/mapgen/s_clothing.json index f4957f0029398..62a1328d97d8a 100644 --- a/data/json/mapgen/s_clothing.json +++ b/data/json/mapgen/s_clothing.json @@ -300,8 +300,7 @@ "**********~~~***********" ], "terrain": { - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], + "*": "t_region_groundcover_urban", "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", @@ -316,6 +315,7 @@ }, "sealed_item": { "1": { "item": { "item": "seed_rose" }, "furniture": "f_planter_harvest" } }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "&": "f_counter_gate_c", "@": "f_mannequin", @@ -575,9 +575,8 @@ "************************" ], "terrain": { - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt" ], - "&": "t_grass", + "*": "t_region_groundcover_urban", + "&": "t_region_groundcover_urban", "+": "t_door_c", "-": "t_brick_wall", ".": "t_floor", @@ -588,15 +587,16 @@ "H": "t_sidewalk", "O": "t_window", "T": "t_sidewalk", - "^": "t_tree", - "r": "t_grass", - "z": "t_shrub", + "^": "t_region_tree", + "r": "t_region_groundcover_urban", + "z": "t_region_shrub", "|": "t_brick_wall", "~": "t_sidewalk", - "R": "t_grass", + "R": "t_region_groundcover_urban", "4": "t_gutter_downspout" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "@": "f_mannequin", "H": "f_chair", @@ -608,7 +608,7 @@ "d": "f_desk", "f": "f_indoor_plant", "h": "f_chair", - "r": [ "f_datura", "f_bluebell", "f_mutpoppy", "f_dahlia", "f_flower_tulip", "f_chamomile", "f_flower_spurge", "f_lily" ], + "r": "f_region_flower", "s": "f_sink", "u": "f_trashcan", "y": "f_indoor_plant_y" diff --git a/data/json/mapgen/s_coffee.json b/data/json/mapgen/s_coffee.json index 6b005ff91ba5b..b90cd4db017f5 100644 --- a/data/json/mapgen/s_coffee.json +++ b/data/json/mapgen/s_coffee.json @@ -45,8 +45,8 @@ "%": "t_linoleum_white", "+": "t_door_c", ",": "t_pavement_y", - ".": "t_grass", - "/": "t_dirt", + ".": "t_region_groundcover_urban", + "/": "t_region_groundcover_barren", "3": [ "t_door_locked", "t_door_locked_alarm" ], ";": "t_linoleum_white", "=": "t_linoleum_white", @@ -56,7 +56,7 @@ "G": "t_linoleum_white", "I": "t_door_locked_interior", "L": "t_linoleum_white", - "M": "t_dirt", + "M": "t_region_groundcover_barren", "O": "t_window", "S": "t_sidewalk", "U": "t_linoleum_white", @@ -68,8 +68,7 @@ "f": "t_linoleum_white", "l": "t_linoleum_white", "w": "t_linoleum_white", - "x": "t_console_broken", - "z": "t_shrub", + "z": "t_region_shrub_decorative", "{": "t_door_glass_c", "|": "t_wall_b", "<": "t_stairs_up", @@ -77,6 +76,7 @@ "T": "t_tree_coffee" }, "furniture": { + "x": "f_console_broken", "#": "f_counter", "%": "f_trashcan", "/": "f_bluebell", @@ -91,11 +91,11 @@ "F": "f_fridge", "G": "f_oven", "L": "f_locker", - "M": "f_dahlia", + "M": "f_region_flower", "U": "f_sink", "X": "f_rack", "^": "f_indoor_plant", - "b": "f_dandelion", + "b": "f_region_weed", "f": "f_glass_fridge", "l": "f_rack", "r": "f_rack" @@ -219,7 +219,7 @@ { "line": "terrain", "id": "t_concrete", "x": 18, "x2": 18, "y": 6, "y2": 4 } ], "terrain": { - "#": "t_shrub", + "#": "t_region_shrub", "%": "t_wall_glass", "+": "t_door_glass_c", ",": "t_pavement_y", @@ -241,11 +241,11 @@ "p": "t_concrete", "r": "t_linoleum_white", "s": "t_sidewalk", - "x": "t_console_broken", "4": "t_gutter_downspout", "|": "t_wall_b" }, "furniture": { + "x": "f_console_broken", "&": "f_trashcan", "H": "f_chair", "O": "f_oven", @@ -330,53 +330,10 @@ }, { "method": "json", + "om_terrain": "s_restaurant_coffee_2", + "type": "mapgen", + "weight": 100, "object": { - "fill_ter": "t_floor", - "furniture": { - "#": "f_chair", - "&": "f_trashcan", - "+": "f_null", - "-": "f_null", - ".": "f_null", - "D": "f_null", - "S": "f_null", - "T": "f_toilet", - "^": "f_indoor_plant", - "_": "f_null", - "a": "f_sink", - "b": "f_null", - "c": "f_counter", - "d": "f_dumpster", - "l": "f_locker", - "o": "f_oven", - "p": "f_null", - "r": "f_rack", - "s": "f_null", - "t": "f_table", - "u": "f_null", - "v": "f_vending_o", - "w": "f_null", - "{": "f_fridge", - "|": "f_null" - }, - "place_items": [ - { "chance": 80, "repeat": [ 1, 8 ], "item": "coffee_freezer", "x": [ 3, 4 ], "y": 4 }, - { "chance": 70, "repeat": [ 1, 8 ], "item": "coffee_display_2", "x": 7, "y": 13 }, - { "chance": 70, "repeat": [ 1, 8 ], "item": "coffee_display_2", "x": 6, "y": 11 }, - { "chance": 75, "repeat": [ 1, 8 ], "item": "coffee_condiments", "x": [ 5, 6 ], "y": 12 }, - { "chance": 75, "repeat": [ 1, 8 ], "item": "coffee_condiments", "x": 6, "y": 9 }, - { "chance": 35, "item": "clothing_work_torso", "x": [ 7, 9 ], "y": 20 }, - { "chance": 40, "item": "coffee_trash", "x": 5, "y": 15 }, - { "chance": 75, "repeat": [ 1, 3 ], "item": "kitchen_nonfood", "x": 5, "y": [ 13, 14 ] }, - { "chance": 35, "item": "coffee_dishes", "x": 6, "y": 8 }, - { "chance": 50, "item": "fast_trash", "x": [ 15, 16 ], "y": 19 }, - { "chance": 65, "repeat": [ 1, 3 ], "item": "coffee_newsstand", "x": 15, "y": 6 } - ], - "place_monsters": [ - { "chance": 4, "density": 1, "monster": "GROUP_ZOMBIE", "x": 8, "y": 10 }, - { "chance": 3, "density": 1, "monster": "GROUP_ZOMBIE_FAT_BASE", "x": 17, "y": 11 } - ], - "place_toilets": [ { "x": 20, "y": 17 } ], "rows": [ "______________sss_______", "______u__u____sss_______", @@ -390,7 +347,7 @@ "__|...c.............^|u_", "__|...c..............|__", "__|...c..............|_u", - "__|...c......#.......|__", + "__|...x......#.......|__", "_u|..c|.....#t#......|u_", "__|..c|......#....|D||__", "__|..&|...........|..|__", @@ -403,39 +360,58 @@ "_____u_____ppppppppp____", "________________________" ], + "fill_ter": "t_floor", + "furniture": { + "#": "f_chair", + "&": "f_trashcan", + "T": "f_toilet", + "^": "f_indoor_plant", + "a": "f_sink", + "c": "f_counter", + "d": "f_dumpster", + "l": "f_locker", + "o": "f_oven", + "r": "f_rack", + "t": "f_table", + "v": "f_vending_o", + "{": "f_fridge", + "x": "f_console_broken" + }, "terrain": { - "#": "t_floor", - "&": "t_floor", "+": "t_door_glass_c", "-": "t_wall_glass", - ".": "t_floor", "D": "t_door_c", - "S": "t_shrub", - "T": "t_floor", - "^": "t_floor", - "_": "t_grass", - "a": "t_floor", + "S": "t_region_shrub_decorative", + "_": "t_region_groundcover_urban", "b": "t_door_metal_pickable", - "c": "t_floor", "d": "t_pavement", - "l": "t_floor", - "o": "t_floor", "p": "t_pavement", - "r": "t_floor", "s": "t_sidewalk", - "t": "t_floor", - "u": "t_underbrush", - "v": "t_floor", + "u": "t_region_shrub", "w": "t_window_boarded_noglass", - "{": "t_floor", "4": "t_gutter_downspout", "<": "t_ladder_up", "|": "t_wall_b" - } - }, - "om_terrain": "s_restaurant_coffee_2", - "type": "mapgen", - "weight": 100 + }, + "place_items": [ + { "chance": 80, "repeat": [ 1, 8 ], "item": "coffee_freezer", "x": [ 3, 4 ], "y": 4 }, + { "chance": 70, "repeat": [ 1, 8 ], "item": "coffee_display_2", "x": 7, "y": 13 }, + { "chance": 70, "repeat": [ 1, 8 ], "item": "coffee_display_2", "x": 6, "y": 11 }, + { "chance": 75, "repeat": [ 1, 8 ], "item": "coffee_condiments", "x": [ 5, 6 ], "y": 12 }, + { "chance": 75, "repeat": [ 1, 8 ], "item": "coffee_condiments", "x": 6, "y": 9 }, + { "chance": 35, "item": "clothing_work_torso", "x": [ 7, 9 ], "y": 20 }, + { "chance": 40, "item": "coffee_trash", "x": 5, "y": 15 }, + { "chance": 75, "repeat": [ 1, 3 ], "item": "kitchen_nonfood", "x": 5, "y": [ 13, 14 ] }, + { "chance": 35, "item": "coffee_dishes", "x": 6, "y": 8 }, + { "chance": 50, "item": "fast_trash", "x": [ 15, 16 ], "y": 19 }, + { "chance": 65, "repeat": [ 1, 3 ], "item": "coffee_newsstand", "x": 15, "y": 6 } + ], + "place_monsters": [ + { "chance": 4, "density": 1, "monster": "GROUP_ZOMBIE", "x": 8, "y": 10 }, + { "chance": 3, "density": 1, "monster": "GROUP_ZOMBIE_FAT_BASE", "x": 17, "y": 11 } + ], + "place_toilets": [ { "x": 20, "y": 17 } ] + } }, { "type": "mapgen", diff --git a/data/json/mapgen/s_electronics.json b/data/json/mapgen/s_electronics.json index 2c001e497d48e..6709748753588 100644 --- a/data/json/mapgen/s_electronics.json +++ b/data/json/mapgen/s_electronics.json @@ -34,7 +34,7 @@ "________________________" ], "terrain": { - "%": "t_shrub", + "%": "t_region_shrub_decorative", "+": "t_door_metal_pickable", ",": "t_pavement_y", "-": "t_wall_w", @@ -50,8 +50,7 @@ "_": "t_pavement", "d": "t_pavement", "s": "t_sidewalk", - "x": "t_console_broken", - "z": "t_shrub", + "z": "t_region_shrub_decorative", "|": "t_wall_w", "4": "t_gutter_downspout", "<": "t_ladder_up" @@ -70,6 +69,7 @@ "r": "f_rack", "t": "f_trashcan", "w": "f_washer", + "x": "f_console_broken", "y": "f_dryer" }, "toilets": { "T": { } }, @@ -190,42 +190,17 @@ " xUUxxxxxxx " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", ".": "t_floor", - "p": "t_grass", - "J": "t_grass", + "p": "t_region_groundcover_urban", + "J": "t_region_groundcover_urban", "+": "t_door_c", "-": "t_brick_wall", ":": "t_window", "|": "t_brick_wall", "U": "t_sidewalk", "x": "t_sidewalk", - "9": [ - "t_tree_blackjack", - "t_tree_walnut", - "t_tree_chestnut", - "t_tree_beech", - "t_tree_hazelnut", - "t_tree_cottonwood", - "t_tree", - "t_tree_elm", - "t_tree_dead", - "t_tree_apple", - "t_tree_pear", - "t_tree_cherry", - "t_tree_peach", - "t_tree_apricot", - "t_tree_plum", - "t_tree_mulberry", - "t_tree_elderberry", - "t_tree_pine", - "t_tree_birch", - "t_tree_willow", - "t_tree_maple", - "t_tree_hickory", - "t_tree_almond", - "t_tree_pecan" - ], + "9": "t_region_tree", "<": "t_ladder_up", "4": "t_gutter_downspout" }, @@ -247,7 +222,7 @@ "F": "f_filing_cabinet", "@": "f_sofa", "G": "f_workbench", - "p": [ "f_datura", "f_bluebell", "f_mutpoppy", "f_dahlia", "f_flower_tulip", "f_chamomile", "f_flower_spurge", "f_lily" ] + "p": "f_region_flower" }, "toilets": { "&": { } }, "items": { diff --git a/data/json/mapgen/s_gas.json b/data/json/mapgen/s_gas.json index 92bcc43661a40..ffb483c32a023 100644 --- a/data/json/mapgen/s_gas.json +++ b/data/json/mapgen/s_gas.json @@ -32,7 +32,7 @@ "...s9s...........s9s....", "........................" ], - "place_terrain": [ { "ter": "t_gas_tank", "x": 2, "y": 3 }, { "ter": "t_diesel_tank", "x": 4, "y": 3 } ], + "place_furniture": [ { "furn": "f_gas_tank", "x": 2, "y": 3 }, { "furn": "f_diesel_tank", "x": 4, "y": 3 } ], "terrain": { "&": "t_atm", "+": "t_chaingate_l", diff --git a/data/json/mapgen/s_grocery.json b/data/json/mapgen/s_grocery.json index a618880db0e21..6db55cc9a2e08 100644 --- a/data/json/mapgen/s_grocery.json +++ b/data/json/mapgen/s_grocery.json @@ -31,14 +31,12 @@ "___L***+**************|_", "___|------------------|_" ], + "fill_ter": "t_linoleum_white", "terrain": { " ": "t_linoleum_white", - "#": "t_linoleum_white", - "%": "t_console_broken", "*": "t_floor", "+": "t_door_c", "-": "t_wall_w", - "7": "t_linoleum_white", "=": "t_wall_glass", "A": "t_atm", "C": "t_floor", @@ -50,19 +48,15 @@ "W": "t_chainfence_h", "[": "t_door_glass_c", "]": "t_floor", - "^": "t_linoleum_white", "_": "t_pavement", - "b": "t_linoleum_white", - "f": "t_linoleum_white", "l": "t_linoleum_gray", - "r": "t_linoleum_white", "s": "t_sidewalk", - "t": "t_linoleum_white", - "w": "t_chainfence_v", + "w": "t_chainfence", "4": "t_gutter_downspout", "|": "t_wall_w" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "7": "f_bookcase", "C": "f_crate_c", @@ -213,7 +207,7 @@ " " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", diff --git a/data/json/mapgen/s_gun.json b/data/json/mapgen/s_gun.json index 9450d5c3f17b3..53ce1d2d7fd8e 100644 --- a/data/json/mapgen/s_gun.json +++ b/data/json/mapgen/s_gun.json @@ -37,7 +37,7 @@ { "ter": "t_door_metal_pickable", "x": [ 7, 14 ], "y": 14 } ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", "*": "t_pavement_y", "+": "t_door_metal_pickable", "-": "t_wall_w", @@ -51,12 +51,12 @@ "l": "t_thconc_floor", "|": "t_wall_w", "D": "t_door_c", - "?": "t_console_broken", "<": "t_ladder_up", "4": "t_gutter_downspout" }, "toilets": { "&": { } }, "furniture": { + "?": "f_console_broken", "#": "f_counter", "H": "f_counter", "S": "f_stool", @@ -233,19 +233,18 @@ "+": "t_door_metal_pickable", ".": "t_floor", "5": "t_window_bars_alarm", - ";": "t_floor", - "@": "t_shrub", + "@": "t_region_shrub_decorative", "A": "t_atm", "D": "t_door_c", "L": "t_door_metal_locked", "_": "t_pavement", "s": "t_sidewalk", "|": "t_wall_w", - "?": "t_console_broken", "<": "t_ladder_up", "4": "t_gutter_downspout" }, "furniture": { + "?": "f_console_broken", "#": "f_counter", "a": "f_stool", "E": "f_desk", @@ -377,7 +376,7 @@ "+": "t_door_metal_pickable", ".": "t_floor", "5": "t_window_bars_alarm", - "@": "t_shrub", + "@": "t_region_shrub_decorative", "A": "t_atm", "C": "t_door_frame", "D": "t_door_o", @@ -386,7 +385,7 @@ "p": "t_door_metal_o", "s": "t_sidewalk", "|": "t_wall_w", - "x": "t_dirt", + "x": "t_region_groundcover_barren", "<": "t_ladder_up", "4": "t_gutter_downspout" }, @@ -475,22 +474,22 @@ ".d-------------------.d." ], "terrain": { - "#": "t_dirt", + "#": "t_region_groundcover_barren", "+": "t_door_metal_pickable", "-": "t_brick_wall", - ".": "t_grass", - "S": "t_grass", - "T": "t_dirt", + ".": "t_region_groundcover_urban", + "S": "t_region_groundcover_urban", + "T": "t_region_groundcover_barren", "W": "t_wall_w", "_": "t_floor", "a": "t_wall_r", - "b": "t_dirt", - "d": "t_dirt", + "b": "t_region_groundcover_barren", + "d": "t_region_groundcover_barren", "e": "t_window_boarded", "f": "t_door_boarded", "g": "t_door_c", "s": "t_sidewalk", - "u": "t_underbrush", + "u": "t_region_shrub", "w": "t_wall_b", "|": "t_wall_w", "4": "t_gutter_downspout" diff --git a/data/json/mapgen/s_hardware.json b/data/json/mapgen/s_hardware.json index b0c7b87b0108f..566a6c880cc66 100644 --- a/data/json/mapgen/s_hardware.json +++ b/data/json/mapgen/s_hardware.json @@ -33,8 +33,7 @@ "************************" ], "terrain": { - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt", "t_shrub" ], + "*": [ [ "t_region_groundcover_urban", 8 ], "t_region_shrub" ], "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", @@ -47,6 +46,7 @@ "4": "t_gutter_downspout" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "@": "f_locker", "[": "f_bookcase", @@ -159,11 +159,11 @@ ], "terrain": { "#": "t_wall_w", - "'": [ "t_grass", "t_grass", "t_dirt" ], + "'": "t_region_groundcover_urban", "+": "t_door_glass_c", "-": "t_wall_glass", ".": "t_floor", - "D": "t_dirt", + "D": "t_region_groundcover_barren", "=": "t_door_c", "H": "t_pavement", "M": "t_pavement", @@ -175,7 +175,6 @@ "W": "t_chainfence_h", "_": "t_floor", "p": "t_pavement", - "r": "t_console_broken", "w": "t_chainfence_v", "|": "t_chaingate_c", "~": "t_sidewalk", @@ -188,6 +187,7 @@ "M": { "item": { "item": "seed_flower" }, "furniture": "f_planter_harvest" } }, "furniture": { + "r": "f_console_broken", "D": "f_dumpster", "H": "f_warehouse_shelf", "P": "f_rack", @@ -308,8 +308,7 @@ "************************" ], "terrain": { - "%": "t_console_broken", - "*": "t_grass", + "*": "t_region_groundcover_urban", "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", @@ -325,6 +324,7 @@ "4": "t_gutter_downspout" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "]": "f_rack", "l": "f_stool", @@ -442,8 +442,7 @@ "************************" ], "terrain": { - "%": "t_console_broken", - "*": [ [ "t_grass", 5 ], [ "t_grass_long", 2 ], "t_dirt", "t_shrub" ], + "*": [ [ "t_region_groundcover_urban", 8 ], "t_region_shrub" ], "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", @@ -457,6 +456,7 @@ }, "toilets": { "&": { } }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "[": "f_table", "]": "f_rack", diff --git a/data/json/mapgen/s_lightindustry.json b/data/json/mapgen/s_lightindustry.json index 99ab2feebc1fb..80220576c1964 100644 --- a/data/json/mapgen/s_lightindustry.json +++ b/data/json/mapgen/s_lightindustry.json @@ -130,13 +130,17 @@ "c": "t_gates_mech_control", "d": "t_chainfence_h", "&": "t_chaingate_l", - "5": "t_machinery_electronic", - "6": "t_machinery_light", - "7": "t_machinery_heavy", - "8": "t_machinery_old", + "5": "t_thconc_floor", + "6": "t_thconc_floor", + "7": "t_thconc_floor", + "8": "t_thconc_floor", "^": "t_gutter_downspout" }, "furniture": { + "5": "f_machinery_electronic", + "6": "f_machinery_light", + "7": "f_machinery_heavy", + "8": "f_machinery_old", "k": "f_sink", "l": "f_oven", "m": "f_fridge", diff --git a/data/json/mapgen/school_1.json b/data/json/mapgen/school_1.json index 1db692e90a8c4..69311fb9338c0 100644 --- a/data/json/mapgen/school_1.json +++ b/data/json/mapgen/school_1.json @@ -405,17 +405,10 @@ "*": "t_open_air", "~": "t_open_air_rooved", "H": "t_glass_railing", - " ": [ [ "t_dirt", 5 ], [ "t_grass", 16 ], [ "t_grass_long", 5 ] ], - "b": "t_dirt", - "$": [ - [ "t_underbrush", 10 ], - [ "t_shrub", 32 ], - [ "t_grass_tall", 10 ], - [ "t_shrub_lilac", 2 ], - [ "t_shrub_hydrangea", 2 ], - [ "t_shrub_rose", 1 ] - ], - ";": [ [ "t_tree", 10 ], [ "t_tree_willow", 3 ], [ "t_tree_birch", 3 ], [ "t_tree_maple", 3 ], [ "t_tree_pine", 5 ] ], + " ": "t_region_groundcover_urban", + "b": "t_region_groundcover_barren", + "$": "t_region_shrub_decorative", + ";": "t_region_tree_shade", "+": "t_door_c", "i": "t_linoleum_gray", "e": "t_linoleum_gray", @@ -434,7 +427,6 @@ "f": "t_chainfence_h", "s": "t_sidewalk", "w": "t_window", - "x": "t_console_broken", "|": "t_wall_y", "I": "t_column", ",": "t_floor_waxed", @@ -461,6 +453,7 @@ "j": "t_sewage_pipe" }, "furniture": { + "x": "f_console_broken", "%": "f_curtain", "@": "f_bed", "#": "f_bench", diff --git a/data/json/mapgen/sewage_treatment.json b/data/json/mapgen/sewage_treatment.json index f52478065c5da..722c050b1335a 100644 --- a/data/json/mapgen/sewage_treatment.json +++ b/data/json/mapgen/sewage_treatment.json @@ -3,8 +3,8 @@ "type": "palette", "id": "sewage_treatment_palette", "terrain": { - " ": [ "t_dirt", "t_grass" ], - "?": "t_shrub", + " ": "t_region_groundcover", + "?": "t_region_shrub", ")": "t_water_pool_shallow", ".": "t_pavement", "_": "t_sidewalk", @@ -30,25 +30,26 @@ "b": "t_door_metal_pickable", "e": "t_door_metal_locked", "D": "t_door_glass_c", - "6": "t_console_broken", "+": "t_door_c", ",": "t_floor", "M": "t_metal_floor", "<": "t_ladder_up", ">": "t_stairs_down", - "%": "t_machinery_heavy", - "$": "t_machinery_light", + "%": "t_thconc_floor", + "$": "t_thconc_floor", "{": "t_thconc_floor", "R": "t_thconc_floor", "J": "t_current_trans", "U": "t_sai_box", - "G": "t_generator_broken", "F": "t_potential_trans", "7": "t_metal_floor", "4": "t_metal_floor", "g": "t_metal_floor", - "Y": "t_switchgear_s" - } + "Y": "t_switchgear_s", + "G": "t_thconc_floor", + "6": "t_thconc_floor" + }, + "furniture": { "%": "f_machinery_heavy", "$": "f_machinery_light", "G": "f_generator_broken", "6": "f_console_broken" } }, { "type": "palette", @@ -86,7 +87,6 @@ "H": "t_sconc_wall", "2": "t_sewage_pipe", "U": "t_sai_box", - "G": "t_generator_broken", "Y": "t_switchgear_s", "&": "t_sewage_pump", "-": "t_wall_glass", @@ -94,11 +94,19 @@ "a": "t_railing_v", "|": "t_chainfence", "C": "t_chaingate_l", - "$": "t_machinery_light", - "@": "t_machinery_heavy", - "v": "t_machinery_old", + "$": "t_thconc_floor", + "@": "t_thconc_floor", + "v": "t_thconc_floor", "+": "t_door_c", - "6": "t_console_broken" + "G": "t_thconc_floor", + "6": "t_thconc_floor" + }, + "furniture": { + "$": "f_machinery_light", + "@": "f_machinery_heavy", + "v": "f_machinery_old", + "G": "f_generator_broken", + "6": "f_console_broken" } }, { diff --git a/data/json/mapgen/sports_store.json b/data/json/mapgen/sports_store.json index 35be3e5075581..ffaa665dc4d73 100644 --- a/data/json/mapgen/sports_store.json +++ b/data/json/mapgen/sports_store.json @@ -48,8 +48,8 @@ "furniture": { "#": "f_counter", "h": "f_stool", - "t": "f_treadmill", - "e": "f_ergometer", + "t": [ "f_treadmill", "f_treadmill_mechanical" ], + "e": [ "f_ergometer", "f_ergometer_mechanical" ], "p": "f_floor_canvas", "m": "f_exercise", "%": "f_sink", diff --git a/data/json/mapgen/stadium_football.json b/data/json/mapgen/stadium_football.json index 9d3c32abad4ee..357b6b079dbce 100644 --- a/data/json/mapgen/stadium_football.json +++ b/data/json/mapgen/stadium_football.json @@ -1011,10 +1011,10 @@ "+": "f_null", "-": "f_null", ".": "f_null", - "5": "f_ergometer", + "5": [ "f_ergometer", "f_ergometer_mechanical" ], "C": "f_counter", "D": "f_null", - "L": "f_treadmill", + "L": [ "f_treadmill", "f_treadmill_mechanical" ], "S": "f_sink", "T": "f_trashcan", "_": "f_null", diff --git a/data/json/mapgen/station_radio.json b/data/json/mapgen/station_radio.json index dda7f03f22037..50170cb0560f6 100644 --- a/data/json/mapgen/station_radio.json +++ b/data/json/mapgen/station_radio.json @@ -34,7 +34,7 @@ " " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", "+": "t_door_c", "=": "t_door_locked_alarm", "D": "t_door_locked", @@ -46,7 +46,6 @@ "_": "t_pavement", "&": "t_radio_tower", "s": "t_sidewalk", - "x": "t_console_broken", "F": "t_chainfence", "f": "t_chainfence", "G": "t_chaingate_l", @@ -54,6 +53,7 @@ "<": "t_ladder_up" }, "furniture": { + "x": "f_console_broken", "o": "f_bookcase", "d": "f_desk", "h": "f_chair", @@ -177,7 +177,7 @@ "ss " ], "terrain": { - " ": [ "t_grass", "t_grass", "t_grass", "t_dirt" ], + " ": "t_region_groundcover_urban", "+": "t_door_c", "=": "t_door_locked_alarm", "D": "t_door_locked", @@ -190,7 +190,6 @@ "R": "t_pavement", "&": "t_radio_tower", "s": "t_sidewalk", - "x": "t_console_broken", "F": "t_chainfence", "f": "t_chainfence", "G": "t_chaingate_l", @@ -199,6 +198,7 @@ "<": "t_ladder_up" }, "furniture": { + "x": "f_console_broken", "o": "f_bookcase", "d": "f_desk", "h": "f_chair", diff --git a/data/json/mapgen/store/s_camping.json b/data/json/mapgen/store/s_camping.json index ae12955f8ec7b..ecfe2d116fdcc 100644 --- a/data/json/mapgen/store/s_camping.json +++ b/data/json/mapgen/store/s_camping.json @@ -53,17 +53,11 @@ "k": "t_thconc_floor", "s": "t_linoleum_gray", "t": "t_linoleum_gray", - "u": "t_console_broken", "v": "t_pavement", "w": "t_pavement", "x": "t_pavement", "K": "t_pavement", "G": "t_pavement", - "y": "t_linoleum_gray", - "z": "t_linoleum_gray", - "A": "t_linoleum_gray", - "B": "t_linoleum_gray", - "M": "t_linoleum_gray", ";": "t_gutter_downspout" }, "furniture": { @@ -81,6 +75,7 @@ "s": "f_rack", "ƃ": "f_counter_gate_c", "t": "f_counter", + "u": "f_console_broken", "v": "f_groundsheet", "w": "f_canvas_wall", "x": "f_canvas_door", diff --git a/data/json/mapgen/store/s_diner.json b/data/json/mapgen/store/s_diner.json index 640d3bac0d122..2353caf4115aa 100644 --- a/data/json/mapgen/store/s_diner.json +++ b/data/json/mapgen/store/s_diner.json @@ -54,7 +54,6 @@ "j": "t_thconc_floor", "k": "t_thconc_floor", "m": "t_thconc_floor", - "n": "t_console_broken", "o": "t_thconc_floor", "p": "t_thconc_floor", "q": "t_thconc_floor", @@ -65,6 +64,7 @@ "<": "t_stairs_up" }, "furniture": { + "n": "f_console_broken", "e": "f_counter", "f": "f_table", "F": "f_table", diff --git a/data/json/mapgen/store/s_games.json b/data/json/mapgen/store/s_games.json index 18b62a01b3670..88192a8e45720 100644 --- a/data/json/mapgen/store/s_games.json +++ b/data/json/mapgen/store/s_games.json @@ -41,23 +41,17 @@ ".": "t_region_groundcover_urban", "f": "t_sidewalk", "g": "t_pavement_y", - "h": "t_carpet_purple", - "i": "t_carpet_purple", - "j": "t_console_broken", - "k": "t_carpet_purple", - "l": "t_carpet_purple", "n": "t_pavement", - "Y": "t_carpet_purple", ";": "t_linoleum_gray", "q": "t_linoleum_gray", "r": "t_linoleum_gray", "m": "t_linoleum_gray", - "s": "t_carpet_purple", "9": "t_gutter_downspout" }, "furniture": { "h": "f_rack_wood", "i": "f_counter", + "j": "f_console_broken", "ƃ": "f_counter_gate_c", "k": "f_table", "A": "f_stool", diff --git a/data/json/mapgen/store/s_gunstore.json b/data/json/mapgen/store/s_gunstore.json index d05cf70c65472..9dc1074866321 100644 --- a/data/json/mapgen/store/s_gunstore.json +++ b/data/json/mapgen/store/s_gunstore.json @@ -50,7 +50,6 @@ "o": "t_thconc_floor", "t": "t_thconc_floor", "^": "t_thconc_floor", - "l": "t_console_broken", "x": "t_thconc_floor", "w": "t_pavement", "_": "t_pavement", @@ -60,6 +59,7 @@ "furniture": { "j": "f_rack", "k": "f_counter", + "l": "f_console_broken", "m": "f_displaycase", "n": "f_table", "o": "f_locker", diff --git a/data/json/mapgen/store/s_hunting.json b/data/json/mapgen/store/s_hunting.json index 1194c0e643d01..c61ab25f56376 100644 --- a/data/json/mapgen/store/s_hunting.json +++ b/data/json/mapgen/store/s_hunting.json @@ -33,7 +33,7 @@ "........4..............." ], "terrain": { - ".": [ "t_grass", "t_grass", "t_grass", "t_grass", "t_dirt" ], + ".": "t_region_groundcover", " ": "t_floor", ",": "t_thconc_floor", "y": "t_thconc_floor", @@ -48,16 +48,16 @@ "|": "t_wall_w", "-": "t_wall_w", "~": "t_window_bars_alarm", - "C": "t_console_broken", "4": "t_gutter_downspout" }, "furniture": { + "C": "f_console_broken", "#": "f_counter", "%": "f_sink", "R": "f_rack", "r": "f_warehouse_shelf", - "O": [ "f_crate_c", "f_crate_c", "f_crate_c", "f_crate_o" ], - "o": [ "f_crate_c", "f_crate_c", "f_crate_c", "f_crate_o" ], + "O": [ [ "f_crate_c", 3 ], "f_crate_o" ], + "o": [ [ "f_crate_c", 3 ], "f_crate_o" ], "X": "f_safe_l", "x": "f_safe_l", "B": "f_bulletin", diff --git a/data/json/mapgen/teashop.json b/data/json/mapgen/teashop.json index 7653f3aabdaaf..1723904573bf1 100644 --- a/data/json/mapgen/teashop.json +++ b/data/json/mapgen/teashop.json @@ -33,9 +33,9 @@ "........................" ], "set": [ - { "point": "furniture", "id": "f_mutpoppy", "x": [ 0, 23 ], "y": [ 21, 23 ], "repeat": [ 4, 9 ] }, - { "point": "terrain", "id": "t_shrub", "x": [ 0, 23 ], "y": [ 21, 23 ], "repeat": [ 4, 9 ] }, - { "point": "furniture", "id": "f_chamomile", "x": [ 0, 23 ], "y": [ 21, 23 ], "repeat": [ 4, 9 ] } + { "point": "furniture", "id": "f_region_weed", "x": [ 0, 23 ], "y": [ 21, 23 ], "repeat": [ 4, 9 ] }, + { "point": "terrain", "id": "t_region_shrub_fruit", "x": [ 0, 23 ], "y": [ 21, 23 ], "repeat": [ 4, 9 ] }, + { "point": "furniture", "id": "f_region_flower", "x": [ 0, 23 ], "y": [ 21, 23 ], "repeat": [ 4, 9 ] } ], "terrain": { "#": "t_floor", @@ -43,33 +43,27 @@ "+": "t_door_c", ",": "t_floor", "-": "t_wall_w", - ".": [ "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_dirt" ], - "1": "t_grass", - "2": "t_grass", - "3": "t_grass", - "6": "t_console_broken", + ".": "t_region_groundcover_urban", + "1": "t_region_groundcover_urban", + "2": "t_region_groundcover_urban", + "3": "t_region_groundcover_urban", "C": "t_sidewalk", - "F": "t_floor", - "K": "t_floor", "O": "t_window_domestic", "S": "t_sidewalk", "T": "t_sidewalk", "_": "t_pavement", - "c": "t_floor", "o": "t_window", - "t": "t_floor", - "v": "t_floor", - "z": "t_shrub", - "{": "t_floor", + "z": "t_region_shrub_decorative", "4": "t_gutter_downspout", "|": "t_wall_w" }, "furniture": { + "6": "f_console_broken", "#": "f_counter", "&": "f_dumpster", - "1": "f_dandelion", - "2": "f_dahlia", - "3": "f_bluebell", + "1": "f_region_weed", + "2": "f_region_flower", + "3": [ "f_region_weed", "f_region_flower" ], "C": "f_chair", "F": "f_fridge", "K": "f_sink", @@ -198,48 +192,41 @@ ], "terrain": { "#": "t_linoleum_gray", - "&": "t_floor", "D": "t_door_locked", "+": "t_door_c", ";": "t_linoleum_gray", ",": "t_floor", - ".": [ "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_dirt" ], - "T": [ "t_tree", "t_tree_young", "t_shrub", "t_grass", "t_grass", "t_dirt" ], - "z": "t_shrub", - "@": "t_grass", - "1": "t_grass", - "2": "t_grass", - "3": "t_grass", - "4": "t_grass", - "^": "t_grass", - "6": "t_console_broken", - "C": "t_floor", + ".": "t_region_groundcover_urban", + "T": [ [ "t_region_groundcover_urban", 3 ], [ "t_region_tree_shade", 2 ], "t_region_shrub_decorative" ], + "z": "t_region_shrub_fruit", + "@": "t_region_groundcover_urban", + "1": "t_region_groundcover_urban", + "2": "t_region_groundcover_urban", + "3": "t_region_groundcover_urban", + "4": "t_region_groundcover_urban", + "^": "t_region_groundcover_urban", "F": "t_linoleum_gray", "K": "t_linoleum_gray", "O": "t_window_domestic", "S": "t_sidewalk", - "$": "t_floor", "_": "t_pavement", - "c": "t_floor", "o": "t_window", - "Y": "t_floor", - "t": "t_floor", - "{": "t_floor", "|": "t_wall_g", "w": "t_wall_log", - "W": "t_railing_v", + "W": "t_railing", "Q": "t_fencegate_c", "<": "t_stairs_up", - "q": "t_fence_v" + "q": "t_fence" }, "furniture": { + "6": "f_console_broken", "#": "f_counter", "Y": "f_rack_coat", "&": "f_trashcan", - "1": "f_dandelion", - "2": "f_dahlia", - "3": "f_bluebell", - "4": "f_lily", + "1": "f_region_weed", + "2": "f_region_flower", + "3": "f_region_flower", + "4": "f_region_flower", "@": "f_statue", "F": "f_fridge", "K": "f_sink", diff --git a/data/json/mapgen/town_hall.json b/data/json/mapgen/town_hall.json index 2bcbdca22308b..8c7b8a19d5ad7 100644 --- a/data/json/mapgen/town_hall.json +++ b/data/json/mapgen/town_hall.json @@ -5,8 +5,8 @@ "terrain": { "*": "t_open_air", "~": "t_open_air_rooved", - ".": [ "t_grass_long", "t_grass", "t_grass", "t_dirt", "t_grass_long", "t_grass", "t_grass", "t_dirt", "t_shrub" ], - ",": [ "t_grass_long", "t_grass_long", "t_grass_long", "t_grass", "t_tree_young", "t_tree", "t_shrub", "t_dirt" ], + ".": [ [ "t_region_groundcover_urban", 10 ], "t_region_shrub_decorative" ], + ",": [ [ "t_region_groundcover_urban", 10 ], "t_region_shrub_decorative", "t_region_shrub_fruit", "t_region_tree_shade" ], "-": "t_door_locked_interior", "<": "t_stairs_down", "+": "t_door_c", @@ -26,7 +26,6 @@ "O": "t_linoleum_white", "u": "t_linoleum_white", "s": "t_sidewalk", - "x": "t_console_broken", "|": "t_brick_wall", "!": "t_door_glass_c", "=": "t_wall_glass", @@ -34,6 +33,7 @@ "v": "t_window" }, "furniture": { + "x": "f_console_broken", "3": "f_bench", "B": "f_bench", "S": "f_sink", diff --git a/data/json/mapgen/veterinarian.json b/data/json/mapgen/veterinarian.json index b0c48efca595c..c396400784283 100644 --- a/data/json/mapgen/veterinarian.json +++ b/data/json/mapgen/veterinarian.json @@ -34,8 +34,7 @@ ], "terrain": { " ": "t_pavement", - "%": "t_console_broken", - "*": "t_shrub", + "*": "t_region_shrub", "+": "t_door_c", ",": "t_pavement_y", "-": "t_wall_w", @@ -47,7 +46,7 @@ "O": "t_window", "R": "t_linoleum_white", "^": "t_chaingate_c", - "i": [ "t_door_locked_interior", "t_door_locked_interior", "t_door_c" ], + "i": [ [ "t_door_locked_interior", 2 ], "t_door_c" ], "l": "t_linoleum_white", "s": "t_linoleum_white", "t": "t_linoleum_white", @@ -56,6 +55,7 @@ "4": "t_gutter_downspout" }, "furniture": { + "%": "f_console_broken", "#": "f_counter", "$": "f_safe_l", "?": "f_counter", diff --git a/data/json/mapgen/ws_fire_lookout_tower.json b/data/json/mapgen/ws_fire_lookout_tower.json index 1b96b3890ebba..cf73c759cc1d3 100644 --- a/data/json/mapgen/ws_fire_lookout_tower.json +++ b/data/json/mapgen/ws_fire_lookout_tower.json @@ -272,6 +272,7 @@ "om_terrain": [ "ws_fire_lookout_tower_f2" ], "weight": 1000, "object": { + "fill_ter": "t_flat_roof", "rows": [ "........................", "........................", @@ -302,17 +303,15 @@ ".": "t_open_air", ",": "t_flat_roof", "X": "t_wall_log", - "|": "t_railing_v", - "-": "t_railing_h", - "g": "t_generator_broken", + "|": "t_railing", + "-": "t_railing", "D": "t_door_c", "+": "t_floor", ">": "t_ladder_down", "f": "t_flat_roof", - "s": "t_flat_roof", - "h": "t_flat_roof" + "s": "t_flat_roof" }, - "furniture": { "h": "f_chair" }, + "furniture": { "g": "f_generator_broken", "h": "f_chair" }, "items": { "s": { "item": "flt_loot_vehicle", "chance": 50 }, "f": { "item": "trash_forest", "chance": 80 } }, "place_monsters": [ { "monster": "GROUP_ZOMBIE_FIRELOOKOUTTOWER", "x": 12, "y": 9 }, diff --git a/data/json/mapgen_palettes/abandoned_barn_p.json b/data/json/mapgen_palettes/abandoned_barn_p.json index a54fbd37524f5..3bbc8a940c997 100644 --- a/data/json/mapgen_palettes/abandoned_barn_p.json +++ b/data/json/mapgen_palettes/abandoned_barn_p.json @@ -30,11 +30,9 @@ "d": "t_region_groundcover_barren", "D": "t_door_boarded_damaged", "f": "t_region_groundcover", - "g": "t_generator_broken", "h": "t_dirtfloor", "I": "t_dirtfloor", "L": [ "t_covered_well", [ "t_water_pump", 2 ] ], - "m": "t_machinery_old", "M": "t_milking_machine", "n": "t_dirtfloor", "N": "t_dirtfloor", @@ -68,9 +66,11 @@ "c": "f_clay_kiln", "C": "f_crate_o", "f": "f_region_weed", + "g": "f_generator_broken", "h": "f_hay", "I": "f_stool", "!": "f_canvas_door_o", + "m": "f_machinery_old", "n": "f_canvas_floor", "N": "f_canvas_wall", "r": "f_rubble", diff --git a/data/json/mapgen_palettes/acidia_camp_palette.json b/data/json/mapgen_palettes/acidia_camp_palette.json index 4154eadb46866..017bd587ee107 100644 --- a/data/json/mapgen_palettes/acidia_camp_palette.json +++ b/data/json/mapgen_palettes/acidia_camp_palette.json @@ -36,7 +36,7 @@ "Q": "t_dirtfloor", "r": "t_dirtfloor", "S": "t_pit_spiked", - "T": "t_machinery_old", + "T": "t_dirtfloor", "t": "t_dirtfloor", "U": "t_pit", "u": "t_dirtfloor", @@ -47,6 +47,7 @@ "Z": "t_radio_controls" }, "furniture": { + "T": "f_machinery_old", "$": "f_crate_o", "(": "f_bench", ")": "f_standing_tank", diff --git a/data/json/mapgen_palettes/airliner_palette.json b/data/json/mapgen_palettes/airliner_palette.json index 39ba607e694ec..c9b9428afdd08 100644 --- a/data/json/mapgen_palettes/airliner_palette.json +++ b/data/json/mapgen_palettes/airliner_palette.json @@ -22,11 +22,18 @@ "D": "t_door_metal_locked", "g": "t_reinforced_glass", "s": "t_reinforced_glass_shutter", - "x": "t_console_broken", ">": "t_slope_down", "<": "t_slope_up" }, - "furniture": { "a": "f_seat_airplane", "c": "f_counter", "f": "f_fridge", "l": "f_locker", "S": "f_sink", "*": "f_wreckage" }, + "furniture": { + "a": "f_seat_airplane", + "c": "f_counter", + "f": "f_fridge", + "l": "f_locker", + "S": "f_sink", + "x": "f_console_broken", + "*": "f_wreckage" + }, "toilets": { "T": { } } } ] diff --git a/data/json/mapgen_palettes/apartment.json b/data/json/mapgen_palettes/apartment.json index ff2fcc03e34a6..4845d89ed1b7d 100644 --- a/data/json/mapgen_palettes/apartment.json +++ b/data/json/mapgen_palettes/apartment.json @@ -15,7 +15,6 @@ "W": "t_window", "s": "t_sidewalk", "w": [ [ "t_window_domestic", 3 ], "t_curtains" ], - "x": "t_console_broken", "|": "t_wall", "z": "t_flat_roof", "(": "t_flat_roof", @@ -41,8 +40,8 @@ "<": "t_stairs_up", ">": "t_stairs_down", "*": "t_open_air", - "K": "t_generator_broken", - "M": "t_machinery_heavy" + "K": "t_thconc_floor", + "M": "t_thconc_floor" }, "furniture": { "a": "f_small_satelitte_dish", @@ -57,6 +56,8 @@ "h": [ [ "f_chair", 2 ], "f_null" ], "I": "f_floor_lamp", "j": "f_trashcan", + "K": "f_generator_broken", + "M": "f_machinery_heavy", "l": [ [ "f_stool", 2 ], "f_null" ], "n": "f_table", "o": "f_bookcase", @@ -67,6 +68,7 @@ "S": "f_sink", "t": "f_table", "u": "f_cupboard", + "x": "f_console_broken", "X": [ [ "f_wardrobe", 2 ], "f_dresser" ], "Y": "f_rack_coat", "1": "f_cupboard", @@ -135,8 +137,7 @@ "p": "t_region_groundcover_urban", "s": "t_sidewalk", "w": "t_window", - "X": "t_door_locked", - "x": "t_console_broken" + "X": "t_door_locked" }, "furniture": { "A": "f_armchair", @@ -157,6 +158,7 @@ "t": "f_table", "T": "f_toilet", "u": "f_cupboard", + "x": "f_console_broken", "Y": "f_rack_coat", "1": "f_cupboard", "2": "f_cupboard", diff --git a/data/json/mapgen_palettes/basement.json b/data/json/mapgen_palettes/basement.json index 1fc892a70d705..96afa11f774aa 100644 --- a/data/json/mapgen_palettes/basement.json +++ b/data/json/mapgen_palettes/basement.json @@ -136,13 +136,13 @@ "*": "t_door_c", "^": "t_door_locked_interior", "5": "t_card_military", - "6": "t_console_broken", "<": "t_stairs_up", "M": "t_wall_metal", "|": "t_reinforced_glass", "/": "t_door_curtain_c", "W": "t_water_dispenser" }, + "furniture": { "6": "f_console_broken" }, "toilets": { "&": { } } }, { diff --git a/data/json/mapgen_palettes/bike_shop_palette.json b/data/json/mapgen_palettes/bike_shop_palette.json index c4561b91a1f0d..1299cc7fb3816 100644 --- a/data/json/mapgen_palettes/bike_shop_palette.json +++ b/data/json/mapgen_palettes/bike_shop_palette.json @@ -15,7 +15,6 @@ ";": "t_door_locked", "&": "t_floor", "^": "t_floor", - "%": "t_console_broken", "@": "t_sidewalk", "C": "t_floor", "D": "t_floor", @@ -50,6 +49,7 @@ "t": "f_table", "q": "f_stool", "B": "f_bench", + "%": "f_console_broken", "&": "f_trashcan", "@": "f_dumpster", "^": "f_indoor_plant" diff --git a/data/json/mapgen_palettes/cground.json b/data/json/mapgen_palettes/cground.json index 2e1b0c1f5c936..102d3586a44a5 100644 --- a/data/json/mapgen_palettes/cground.json +++ b/data/json/mapgen_palettes/cground.json @@ -16,7 +16,6 @@ "i": "t_pit_shallow", "v": "t_window_domestic", "+": "t_door_c", - "X": "t_console_broken", "H": "t_privacy_fence", "m": "t_privacy_fencegate_c", "F": "t_region_tree_evergreen", @@ -43,6 +42,7 @@ "'": "t_concrete" }, "furniture": { + "X": "f_console_broken", "g": "f_bulletin", "i": "f_firering", "b": "f_bench", diff --git a/data/json/mapgen_palettes/church.json b/data/json/mapgen_palettes/church.json index 53a79df26191e..79408cdd92ded 100644 --- a/data/json/mapgen_palettes/church.json +++ b/data/json/mapgen_palettes/church.json @@ -7,13 +7,12 @@ "+": "t_door_c", "-": "t_wall_w", ".": "t_floor", - "6": "t_console", "=": "t_door_locked_alarm", "D": "t_door_locked", "O": "t_column", "S": "t_floor", "T": "t_floor", - "^": "t_shrub", + "^": "t_region_shrub", "c": "t_floor", "b": "t_floor", "d": "t_floor", @@ -27,6 +26,7 @@ "|": "t_wall_w" }, "furniture": { + "6": "f_console", "#": "f_bench", "S": "f_sink", "T": "f_toilet", diff --git a/data/json/mapgen_palettes/city_block_palette.json b/data/json/mapgen_palettes/city_block_palette.json index 4b98c51e29f9c..2cb098e966a74 100644 --- a/data/json/mapgen_palettes/city_block_palette.json +++ b/data/json/mapgen_palettes/city_block_palette.json @@ -3,6 +3,7 @@ "type": "palette", "id": "city_block_foundation_palette", "furniture": { + "?": "f_console_broken", "A": "f_stool", "B": "f_beaded_door", "D": "f_chair", @@ -68,7 +69,6 @@ "M": "t_region_shrub_decorative", "S": "t_ladder_down", "V": "t_ladder_up", - "?": "t_console_broken", "$": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ] }, "toilets": { "t": { } }, diff --git a/data/json/mapgen_palettes/clothes_store_palette.json b/data/json/mapgen_palettes/clothes_store_palette.json index e11f54c1922ff..3fff3c5b628e0 100644 --- a/data/json/mapgen_palettes/clothes_store_palette.json +++ b/data/json/mapgen_palettes/clothes_store_palette.json @@ -2,8 +2,9 @@ { "type": "palette", "id": "clothes_store_palette", - "terrain": { "%": "t_console_broken", "p": "t_region_groundcover_urban" }, + "terrain": { "p": "t_region_groundcover_urban" }, "furniture": { + "%": "f_console_broken", "c": "f_counter", "C": "f_armchair", "s": "f_stool", @@ -58,14 +59,9 @@ { "type": "palette", "id": "tailor_palette", - "terrain": { - "%": "t_console_broken", - ";": "t_door_locked", - "0": "t_window_alarm", - "z": "t_region_shrub_decorative", - "p": "t_region_groundcover_urban" - }, + "terrain": { ";": "t_door_locked", "0": "t_window_alarm", "z": "t_region_shrub_decorative", "p": "t_region_groundcover_urban" }, "furniture": { + "%": "f_console_broken", "c": "f_counter", "R": "f_clothing_rail", "s": "f_stool", @@ -99,7 +95,6 @@ "type": "palette", "id": "furs_palette", "terrain": { - "%": "t_console_broken", ";": "t_door_locked", "i": "t_door_locked_interior", "0": "t_window_alarm", @@ -107,6 +102,7 @@ "p": "t_region_groundcover_urban" }, "furniture": { + "%": "f_console_broken", "c": "f_displaycase", "s": "f_stool", "d": "f_desk", diff --git a/data/json/mapgen_palettes/collapsed_tower.json b/data/json/mapgen_palettes/collapsed_tower.json index 00c7b558f2c69..a31f5b11e171a 100644 --- a/data/json/mapgen_palettes/collapsed_tower.json +++ b/data/json/mapgen_palettes/collapsed_tower.json @@ -39,7 +39,7 @@ ":": "f_dresser", ";": "f_toilet", "=": "f_fireplace", - ">": "f_counter", + "c": "f_counter", "?": "f_sofa", "@": "f_bed", "A": "f_sink", diff --git a/data/json/mapgen_palettes/electronic_palette.json b/data/json/mapgen_palettes/electronic_palette.json index bbf5b8f690ebd..1bf23f1517665 100644 --- a/data/json/mapgen_palettes/electronic_palette.json +++ b/data/json/mapgen_palettes/electronic_palette.json @@ -17,7 +17,6 @@ "W": "t_wall_glass", "w": "t_window", "s": "t_sidewalk", - "x": "t_console_broken", "f": "t_chainfence_v", "g": "t_chaingate_c", "<": "t_stairs_up", @@ -26,6 +25,7 @@ "(": "t_pavement" }, "furniture": { + "x": "f_console_broken", "n": "f_displaycase", "1": "f_rack", "2": "f_rack", diff --git a/data/json/mapgen_palettes/fema.json b/data/json/mapgen_palettes/fema.json index 76cad836ff1e0..c2b9e0c85b9e8 100644 --- a/data/json/mapgen_palettes/fema.json +++ b/data/json/mapgen_palettes/fema.json @@ -7,7 +7,7 @@ "/": "t_region_groundcover_barren", "!": "t_region_groundcover_barren", "_": "t_region_groundcover_barren", - "'": "t_plut_generator", + "'": "t_floor", "?": "t_floor", "#": "t_pit_corpsed", "-": "t_wall", @@ -27,10 +27,11 @@ "P": "t_water_pump", "s": "t_floor", "w": [ "t_window_domestic", "t_curtains", "t_curtains" ], - "6": "t_console_broken", - "7": "t_centrifuge" + "6": "t_floor", + "7": "t_floor" }, "furniture": { + "'": "f_generator_broken", "=": "f_canvas_wall", ",": "f_fema_groundsheet", "*": "f_canvas_door", @@ -57,7 +58,9 @@ "U": "f_cupboard", "W": "f_woodstove", "x": "f_crate_o", - "X": "f_crate_c" + "X": "f_crate_c", + "6": "f_console_broken", + "7": "f_centrifuge" }, "toilets": { "&": { "amount": [ 0, 50 ] } }, "items": { diff --git a/data/json/mapgen_palettes/helipad.json b/data/json/mapgen_palettes/helipad.json index 2897a2a5c4449..1ef56488c24ce 100644 --- a/data/json/mapgen_palettes/helipad.json +++ b/data/json/mapgen_palettes/helipad.json @@ -31,10 +31,7 @@ "M": "t_door_metal_locked", ",": "t_concrete_y", "o": "t_sidewalk", - "?": "t_console_broken", - "g": "t_generator_broken", "P": "t_water_pump", - "5": "t_machinery_light", "6": "t_bulk_tank", "I": "t_thconc_y", "U": "t_metal_floor", @@ -47,6 +44,9 @@ "L": "f_locker", "4": "f_locker", "c": "f_chair", + "?": "f_console_broken", + "g": "f_generator_broken", + "5": "f_machinery_light", "s": "f_chair", "l": "f_utility_shelf", "d": "f_desk", diff --git a/data/json/mapgen_palettes/hospital.json b/data/json/mapgen_palettes/hospital.json index 66180a0603779..1a2b0c2981703 100644 --- a/data/json/mapgen_palettes/hospital.json +++ b/data/json/mapgen_palettes/hospital.json @@ -33,9 +33,9 @@ "`": "t_thconc_floor", "+": "t_door_c", "!": "t_door_locked_interior", - "*": "t_centrifuge", - "6": "t_console", - "7": "t_console", + "*": "t_floor", + "6": "t_floor", + "7": "t_floor", "S": "t_floor", "2": "t_floor", "8": "t_floor", @@ -44,6 +44,9 @@ "?": "t_floor" }, "furniture": { + "*": "f_centrifuge", + "6": "f_console", + "7": "f_console", "b": "f_bench", "c": "f_chair", "B": "f_bed", diff --git a/data/json/mapgen_palettes/hotel_tower_palette.json b/data/json/mapgen_palettes/hotel_tower_palette.json index 6a0b5d0f93b39..2a55e64166211 100644 --- a/data/json/mapgen_palettes/hotel_tower_palette.json +++ b/data/json/mapgen_palettes/hotel_tower_palette.json @@ -18,7 +18,7 @@ "S": "f_sink", "&": "f_toilet", "b": "f_bathtub", - "E": [ "f_exercise", "f_ergometer", "f_treadmill" ], + "E": [ "f_exercise", "f_ergometer", "f_ergometer_mechanical", "f_treadmill", "f_treadmill_mechanical" ], "e": "f_fridge", "l": "f_locker", "W": "f_washer", diff --git a/data/json/mapgen_palettes/house_general_palette.json b/data/json/mapgen_palettes/house_general_palette.json index d5906dfd9d8e3..0078a6b98f6a0 100644 --- a/data/json/mapgen_palettes/house_general_palette.json +++ b/data/json/mapgen_palettes/house_general_palette.json @@ -212,7 +212,7 @@ "u": "t_thconc_floor", "X": "t_thconc_floor" }, - "furniture": { "c": "f_exercise", "u": "f_ergometer", "X": "f_punching_bag" }, + "furniture": { "c": "f_exercise", "u": [ "f_ergometer", "f_ergometer_mechanical" ], "X": "f_punching_bag" }, "monsters": { "!": [ { "monster": "GROUP_ROACH", "chance": 70 }, { "monster": "GROUP_ZOMBIE", "chance": 100 } ], ".": [ { "monster": "GROUP_ROACH", "chance": 80 }, { "monster": "GROUP_ZOMBIE", "chance": 60 } ] diff --git a/data/json/mapgen_palettes/house_w_palette.json b/data/json/mapgen_palettes/house_w_palette.json index 1cf6d42e0ae3b..33995323b4b21 100644 --- a/data/json/mapgen_palettes/house_w_palette.json +++ b/data/json/mapgen_palettes/house_w_palette.json @@ -50,7 +50,8 @@ "w": "f_rack_wood", "x": "f_entertainment_center", "y": [ "f_indoor_plant", "f_indoor_plant_y" ], - "z": [ [ "f_cardboard_box", 5 ], "f_crate_c" ] + "z": [ [ "f_cardboard_box", 5 ], "f_crate_c" ], + "?": "f_console_broken" }, "terrain": { ".": "t_linoleum_gray", @@ -69,8 +70,7 @@ "6": "t_carpet_red", "7": "t_carpet_green", "8": "t_carpet_purple", - "9": "t_carpet_yellow", - "?": "t_console_broken" + "9": "t_carpet_yellow" }, "toilets": { "t": { } }, "liquids": { "g": { "liquid": "water_clean", "amount": [ 0, 100 ] } } diff --git a/data/json/mapgen_palettes/junkyard_palette.json b/data/json/mapgen_palettes/junkyard_palette.json index 42d2d3ea8d659..850f72c3f0ff7 100644 --- a/data/json/mapgen_palettes/junkyard_palette.json +++ b/data/json/mapgen_palettes/junkyard_palette.json @@ -3,7 +3,7 @@ "type": "palette", "id": "junkyard_palette", "terrain": { - ".": [ [ "t_pavement", 22 ], "t_region_groundcover_urban" ], + ".": [ [ "t_pavement", 22 ], "t_region_groundcover" ], "g": "t_region_groundcover_urban", "_": [ [ "t_region_groundcover_barren", 5 ], "t_region_groundcover_urban" ], "|": "t_fence_barbed", @@ -26,10 +26,10 @@ "d": "t_door_metal_locked", "m": "t_metal_floor", "9": "t_wall_wood", - "x": "t_console_broken", "4": "t_gutter_downspout" }, "furniture": { + "x": "f_console_broken", "#": "f_straw_bed", "N": "f_ladder", "B": "f_bench", diff --git a/data/json/mapgen_palettes/lab_surface_palette.json b/data/json/mapgen_palettes/lab_surface_palette.json index 0899f163e29b1..7e8a208be2faa 100644 --- a/data/json/mapgen_palettes/lab_surface_palette.json +++ b/data/json/mapgen_palettes/lab_surface_palette.json @@ -24,7 +24,6 @@ "m": "t_door_metal_c", "M": "t_door_metal_locked", "w": "t_gates_control_brick", - "x": "t_console_broken", "]": "t_sidewalk", "*": "t_region_shrub_decorative", "?": [ "t_region_shrub_decorative", "t_region_tree_shade" ], @@ -52,7 +51,8 @@ "S": "f_sink", "s": "f_stool", "t": "f_table", - "U": "f_utility_shelf" + "U": "f_utility_shelf", + "x": "f_console_broken" }, "toilets": { "T": { } }, "vendingmachines": { "D": { "item_group": "vending_drink" }, "F": { "item_group": "vending_food" } } @@ -79,7 +79,6 @@ "m": "t_door_metal_c", "M": "t_door_metal_locked", "p": "t_sewage_pipe", - "x": "t_console_broken", "]": "t_sidewalk", "*": "t_region_shrub_decorative", "<": "t_stairs_up", @@ -111,7 +110,8 @@ "S": "f_sink", "s": "f_stool", "t": "f_table", - "v": "f_vent_pipe" + "v": "f_vent_pipe", + "x": "f_console_broken" }, "toilets": { "T": { } }, "vendingmachines": { "D": { "item_group": "vending_drink" }, "F": { "item_group": "vending_food" } } @@ -129,9 +129,7 @@ "-": "t_door_glass_frosted_c", "=": "t_door_glass_frosted_lab_c", ":": "t_reinforced_glass", - "m": "t_door_metal_c", - "o": "t_centrifuge", - "x": "t_console_broken" + "m": "t_door_metal_c" }, "furniture": { "&": "f_trashcan", @@ -165,7 +163,9 @@ "S": "f_sink", "t": "f_table", "U": "f_utility_shelf", - "v": "f_ventilator" + "v": "f_ventilator", + "o": "f_centrifuge", + "x": "f_console_broken" } } ] diff --git a/data/json/mapgen_palettes/library_palette.json b/data/json/mapgen_palettes/library_palette.json index d42db01ea9ebf..974b5b11c6486 100644 --- a/data/json/mapgen_palettes/library_palette.json +++ b/data/json/mapgen_palettes/library_palette.json @@ -2,8 +2,9 @@ { "type": "palette", "id": "library_palette", - "terrain": { "%": "t_console_broken", "p": "t_region_groundcover_urban", ";": "t_door_locked", "5": "t_region_tree_evergreen" }, + "terrain": { "p": "t_region_groundcover_urban", ";": "t_door_locked", "5": "t_region_tree_evergreen" }, "furniture": { + "%": "f_console_broken", "c": "f_counter", "d": "f_desk", "[": "f_table", diff --git a/data/json/mapgen_palettes/lmoe.json b/data/json/mapgen_palettes/lmoe.json index 28bc0f7a493ad..6a48164868480 100644 --- a/data/json/mapgen_palettes/lmoe.json +++ b/data/json/mapgen_palettes/lmoe.json @@ -16,7 +16,6 @@ ":": "t_secretdoor_metal_c", ";": "t_secretdoor_metal_o", "~": "t_water_pump", - "G": "t_generator_broken", "t": "t_metal_floor" }, "furniture": { @@ -28,10 +27,11 @@ "C": "f_cupboard", "d": "f_dresser", "D": "f_desk", - "e": "f_ergometer", + "e": "f_ergometer_mechanical", "E": "f_exercise", "F": "f_fridge", "f": "f_sofa", + "G": "f_generator_broken", "h": "f_chair", "H": "f_water_heater", "K": "f_sink", diff --git a/data/json/mapgen_palettes/lumberyard.json b/data/json/mapgen_palettes/lumberyard.json index 73b3aa7dfcf2d..4a82f4eb5ffc8 100644 --- a/data/json/mapgen_palettes/lumberyard.json +++ b/data/json/mapgen_palettes/lumberyard.json @@ -15,13 +15,10 @@ ";": "t_door_metal_locked", ".": "t_thconc_floor", "6": "t_gates_mech_control", - "@": "t_machinery_heavy", - "G": "t_generator_broken", "=": "t_conveyor", "+": "t_door_c", "!": "t_door_locked_interior", - "X": "t_console_broken", - "v": "t_chainfence_v", + "v": "t_chainfence", "V": "t_chaingate_l", "x": "t_thconc_floor", "z": "t_flat_roof", @@ -33,13 +30,16 @@ ",": "t_thconc_floor" }, "furniture": { + "@": "f_machinery_heavy", "B": "f_bandsaw", + "G": "f_generator_broken", "J": "f_jointer", "M": "f_mitresaw", "P": "f_planer", "R": "f_router", "T": "f_tablesaw", "U": "f_utility_shelf", + "X": "f_console_broken", "p": "f_drill_press", "i": "f_filing_cabinet", "&": "f_trashcan", diff --git a/data/json/mapgen_palettes/mall_palette.json b/data/json/mapgen_palettes/mall_palette.json index 6cb70de570762..fe628abd119b6 100644 --- a/data/json/mapgen_palettes/mall_palette.json +++ b/data/json/mapgen_palettes/mall_palette.json @@ -1,153 +1,4 @@ [ - { - "type": "palette", - "id": "mall_palette", - "furniture": { - "?": "f_sofa", - "!": "f_rack", - "@": "f_bed", - "$": "f_counter", - "%": "f_indoor_plant", - "^": "f_indoor_plant", - "&": "f_bench", - "*": "f_chair", - "(": "f_rack", - ")": "f_dahlia", - "~": "f_counter", - "8": "f_table", - "9": "f_table", - "B": "f_bookcase", - "D": "f_trashcan", - "F": "f_arcade_machine", - "G": "f_trashcan", - "I": "f_arcade_machine", - "J": "f_counter", - "K": "f_locker", - "L": "f_locker", - "M": "f_trashcan", - "N": "f_chair", - "O": "f_oven", - "P": "f_indoor_plant", - "Q": "f_indoor_plant", - "R": "f_table", - "S": "f_sink", - "U": "f_bench", - "W": "f_washer", - "X": "f_safe_l", - "Y": "f_dryer", - "b": "f_bench", - "c": "f_counter", - "d": "f_desk", - "e": "f_fridge", - "f": "f_glass_fridge", - "g": "f_chair", - "h": "f_chair", - "i": "f_bench", - "j": "f_fridge", - "k": "f_chair", - "l": "f_vending_c", - "m": "f_vending_c", - "n": "f_table", - "o": "f_vending_c", - "q": "f_counter", - "r": "f_rack", - "t": "f_toilet", - "u": "f_rack", - "v": "f_pinball_machine", - "x": "f_pinball_machine", - "y": "f_indoor_plant", - "z": [ [ "f_cardboard_box", 5 ], "f_crate_c" ] - }, - "terrain": { - "#": "t_shrub", - "!": "t_linoleum_gray_no_roof", - "$": "t_linoleum_white_no_roof", - "%": "t_carpet_green", - "^": "t_linoleum_white_no_roof", - "&": "t_linoleum_white_no_roof", - "*": "t_carpet_green", - "(": "t_linoleum_white_no_roof", - ")": "t_region_groundcover_urban", - "~": "t_carpet_green", - "+": "t_door_c", - ",": "t_pavement_y", - "-": "t_brick_wall", - ".": "t_region_groundcover_urban", - "1": "t_linoleum_white", - "2": "t_linoleum_gray", - "3": "t_carpet_red", - "4": "t_carpet_green", - "5": "t_door_gray_c", - "6": "t_console_broken", - "7": "t_gates_mech_control", - "8": "t_sidewalk", - "9": "t_linoleum_white_no_roof", - "0": "t_door_red_c", - ":": "t_door_locked_interior", - ";": "t_door_locked", - "=": "t_door_metal_locked", - "?": "t_floor", - "@": "t_floor", - "A": "t_railing_h", - "B": "t_floor", - "C": "t_concrete", - "D": "t_floor", - "E": "t_elevator", - "F": "t_floor", - "G": "t_carpet_red", - "H": "t_laminated_glass", - "J": "t_carpet_red", - "I": "t_carpet_red", - "K": "t_carpet_red", - "L": "t_floor", - "M": "t_linoleum_gray_no_roof", - "N": "t_linoleum_white_no_roof", - "O": "t_floor", - "P": "t_floor", - "Q": "t_carpet_red", - "R": "t_linoleum_gray_no_roof", - "S": "t_floor", - "T": "t_tree", - "U": "t_sidewalk", - "V": "t_laminated_glass", - "W": "t_floor", - "X": "t_floor", - "Y": "t_floor", - "Z": "t_laminated_door_glass_c", - "[": "t_laminated_door_glass_c", - "]": "t_laminated_door_glass_o", - "_": "t_pavement", - "a": "t_railing_v", - "b": "t_floor", - "c": "t_floor", - "d": "t_floor", - "e": "t_floor", - "f": "t_floor", - "g": "t_carpet_red", - "h": "t_floor", - "i": "t_linoleum_gray_no_roof", - "j": "t_carpet_red", - "k": "t_linoleum_gray_no_roof", - "l": "t_floor", - "m": "t_carpet_red", - "n": "t_floor", - "o": "t_linoleum_gray_no_roof", - "p": "t_column", - "q": "t_linoleum_gray_no_roof", - "r": "t_floor", - "s": "t_sidewalk", - "t": "t_floor", - "u": "t_carpet_red", - "v": "t_carpet_red", - "w": "t_water_pool_shallow_outdoors", - "x": "t_floor", - "y": "t_linoleum_gray_no_roof", - "<": "t_stairs_up", - "z": "t_floor", - "|": "t_brick_wall" - }, - "toilets": { "t": { } } - }, { "type": "palette", "id": "mall_palette_2", @@ -205,6 +56,8 @@ "ȝ": "f_dryer", "Ʃ": "f_entertainment_center", "y": [ "f_indoor_plant", "f_indoor_plant_y" ], + "x": [ "f_machinery_light", "f_machinery_heavy", "f_machinery_old", "f_machinery_electronic" ], + "?": "f_console_broken", "z": [ [ "f_cardboard_box", 5 ], "f_crate_c" ] }, "terrain": { @@ -237,14 +90,12 @@ "+": "t_laminated_door_glass_c", "=": [ "t_door_c", "t_door_locked" ], "p": "t_column", - "x": [ "t_machinery_light", "t_machinery_heavy", "t_machinery_old", "t_machinery_electronic" ], "2": "t_wall_g", "5": "t_wall_wood", - "6": "t_carpet_red", - "7": "t_carpet_green", - "8": "t_carpet_purple", - "9": "t_carpet_yellow", - "?": "t_console_broken", + "6": "t_carpet_concrete_red", + "7": "t_carpet_concrete_green", + "8": "t_carpet_concrete_purple", + "9": "t_carpet_concrete_yellow", "§": "t_water_pool_shallow_outdoors" }, "toilets": { "t": { } } diff --git a/data/json/mapgen_palettes/mansion.json b/data/json/mapgen_palettes/mansion.json index 38d71fed78598..1475ec0f43184 100644 --- a/data/json/mapgen_palettes/mansion.json +++ b/data/json/mapgen_palettes/mansion.json @@ -16,6 +16,7 @@ "7": "f_indoor_plant", "8": "f_indoor_plant_y", "9": "f_indoor_plant_y", + "&": "f_console_broken", "?": "f_fireplace", "@": "f_statue", "A": "f_armchair", @@ -24,8 +25,8 @@ "D": "f_desk", "F": "f_fridge", "G": "f_dryer", - "H": "f_treadmill", - "I": "f_ergometer", + "H": [ "f_treadmill", "f_treadmill_mechanical" ], + "I": [ "f_ergometer", "f_ergometer_mechanical" ], "J": "f_bathtub", "K": [ [ "f_cardboard_box", 5 ], "f_crate_c", "f_crate_o" ], "L": [ [ "f_cardboard_box", 5 ], "f_crate_c", "f_crate_o" ], @@ -46,8 +47,8 @@ "e": "f_pool_table", "f": "f_fridge", "g": "f_dryer", - "h": "f_treadmill", - "i": "f_ergometer", + "h": [ "f_treadmill", "f_treadmill_mechanical" ], + "i": [ "f_ergometer", "f_ergometer_mechanical" ], "j": "f_shower", "l": "f_bookcase", "m": "f_locker", @@ -65,7 +66,6 @@ }, "terrain": { "%": "t_door_locked_interior", - "&": "t_console_broken", "!": "t_region_groundcover_urban", ")": "t_carpet_concrete_red", "+": "t_door_c", @@ -117,14 +117,8 @@ { "type": "palette", "id": "mansion_palette_basement", - "terrain": { - "#": "t_rock", - "*": "t_machinery_old", - "?": "t_generator_broken", - "X": "t_brick_wall", - "]": "t_sewage_pipe", - "p": "t_sewage_pump" - } + "terrain": { "#": "t_rock", "X": "t_brick_wall", "]": "t_sewage_pipe", "p": "t_sewage_pump" }, + "furniture": { "*": "f_machinery_old", "?": "f_generator_broken" } }, { "type": "palette", diff --git a/data/json/mapgen_palettes/microlab.json b/data/json/mapgen_palettes/microlab.json index e60bcc3cc3e90..12dfcdb76288c 100644 --- a/data/json/mapgen_palettes/microlab.json +++ b/data/json/mapgen_palettes/microlab.json @@ -9,7 +9,6 @@ "2": "t_door_glass_frosted_lab_c", "4": "t_door_metal_pickable", "5": "t_door_metal_locked", - "6": "t_console_broken", "[": "t_door_glass_c", "-": "t_wall_metal", "y": "t_pavement_y", @@ -27,6 +26,7 @@ "&": "f_toilet", "~": "f_shower", "@": "f_bed", + "6": "f_console_broken", "a": "f_armchair", "k": "f_cupboard", "D": "f_dresser", diff --git a/data/json/mapgen_palettes/military/mil_base_palette.json b/data/json/mapgen_palettes/military/mil_base_palette.json index b77256f8be1e3..c52531a943cbe 100644 --- a/data/json/mapgen_palettes/military/mil_base_palette.json +++ b/data/json/mapgen_palettes/military/mil_base_palette.json @@ -48,15 +48,11 @@ "&": "t_grate", "e": "t_gates_mech_control", "5": "t_card_military", - "*": "t_gas_tank", + "*": "t_pavement", "%": "t_pit_corpsed", "8": "t_wall_metal", "9": "t_metal_floor", - "J": "t_generator_broken", - "p": "t_plut_generator", "Z": "t_radio_tower", - "'": "t_console_broken", - "0": "t_console", "@": "t_rock", "~": "t_gutter_downspout" }, @@ -66,6 +62,7 @@ "#": "f_desk", "[": "f_table", ":": "f_table", + "*": "f_gas_tank", "h": "f_chair", "$": "f_filing_cabinet", "`": "f_shredder", @@ -73,6 +70,10 @@ "c": "f_counter", "S": "f_sink", "o": "f_oven", + "J": "f_generator_broken", + "p": "f_compact_ASRG_containment", + "'": "f_console_broken", + "0": "f_console", "t": "f_trashcan", "Y": "f_rack_coat", "O": "f_bookcase", @@ -96,7 +97,7 @@ "L": "f_shower", "6": "f_water_heater", "7": "f_standing_tank", - "H": "f_standing_tank", + "H": "f_diesel_tank", "j": "f_home_furnace", "q": "f_drill_press", "Q": "f_bandsaw", diff --git a/data/json/mapgen_palettes/movie_theater_palette.json b/data/json/mapgen_palettes/movie_theater_palette.json index 87e6569e2813e..cc02ca2b802fc 100644 --- a/data/json/mapgen_palettes/movie_theater_palette.json +++ b/data/json/mapgen_palettes/movie_theater_palette.json @@ -27,7 +27,8 @@ "o": "f_oven", "r": "f_rack", "F": "f_vending_c", - "v": "f_vending_c" + "v": "f_vending_c", + "Z": "f_console_broken" }, "terrain": { "$": "t_carpet_green", @@ -50,7 +51,6 @@ "d": "t_door_c", "a": "t_atm", "w": "t_window", - "Z": "t_console_broken", "-": "t_railing_h", "R": "t_railing_h", "<": "t_ladder_up" diff --git a/data/json/mapgen_palettes/necropolis/necropolis_a.json b/data/json/mapgen_palettes/necropolis/necropolis_a.json index a2bc5a0120f70..303b01e515f4b 100644 --- a/data/json/mapgen_palettes/necropolis/necropolis_a.json +++ b/data/json/mapgen_palettes/necropolis/necropolis_a.json @@ -6,6 +6,8 @@ ")": "f_wreckage", "?": "f_sofa", "@": "f_bed", + "1": "f_generator_broken", + "6": "f_console_broken", "B": "f_bathtub", "C": "f_region_weed", "D": "f_trashcan", @@ -49,12 +51,12 @@ ",": "t_pavement_y", "-": "t_wall", ".": "t_region_groundcover_urban", - "1": "t_generator_broken", + "1": "t_thconc_floor", "2": "t_sewage_pipe", "3": "t_recycler", "4": "t_water_pump", "5": "t_slide", - "6": "t_console_broken", + "6": "t_thconc_floor", "7": "t_chainfence_h", "8": "t_chainfence_v", "9": "t_chaingate_l", diff --git a/data/json/mapgen_palettes/necropolis/necropolis_b1.json b/data/json/mapgen_palettes/necropolis/necropolis_b1.json index 6f7a3e82a7bc5..e26983d1de3fc 100644 --- a/data/json/mapgen_palettes/necropolis/necropolis_b1.json +++ b/data/json/mapgen_palettes/necropolis/necropolis_b1.json @@ -6,6 +6,7 @@ ")": "f_wreckage", "?": "f_sofa", "@": "f_bed", + "6": "f_console_broken", "D": "f_trashcan", "L": "f_locker", "S": "f_sink", @@ -37,9 +38,8 @@ "3": "t_sewage", "4": "t_water_pump", "5": "t_water_sh", - "6": "t_console_broken", - "7": "t_chainfence_h", - "8": "t_chainfence_v", + "7": "t_chainfence", + "8": "t_chainfence", "9": "t_chaingate_l", ";": "t_metal_floor", "<": "t_stairs_up", diff --git a/data/json/mapgen_palettes/necropolis/necropolis_b2.json b/data/json/mapgen_palettes/necropolis/necropolis_b2.json index 623867b26765b..b00668ee624ee 100644 --- a/data/json/mapgen_palettes/necropolis/necropolis_b2.json +++ b/data/json/mapgen_palettes/necropolis/necropolis_b2.json @@ -5,10 +5,16 @@ "furniture": { "?": "f_sofa", "@": "f_bed", + "$": "f_machinery_light", + "%": "f_machinery_heavy", + "(": "f_machinery_old", + "1": "f_generator_broken", + "_": "f_machinery_electronic", + "6": "f_console_broken", "B": "f_bathtub", - "C": "f_treadmill", + "C": [ "f_treadmill", "f_treadmill_mechanical" ], "D": "f_trashcan", - "J": "f_ergometer", + "J": [ "f_ergometer", "f_ergometer_mechanical" ], "L": "f_locker", "N": "f_robotic_arm", "O": "f_oven", @@ -35,9 +41,9 @@ " ": "t_metal_floor", "!": "t_bars", "#": "t_ladder_up", - "$": "t_machinery_light", - "%": "t_machinery_heavy", - "(": "t_machinery_old", + "$": "t_metal_floor", + "%": "t_metal_floor", + "(": "t_metal_floor", "*": "t_door_bar_locked", "+": "t_door_metal_c", ",": "t_pavement_y", @@ -45,14 +51,14 @@ ".": "t_rock", "/": "t_rock_floor", "0": "t_conveyor", - "1": "t_generator_broken", + "1": "t_metal_floor", "2": "t_sewage_pipe", "3": "t_sewage", "4": "t_water_pump", "5": "t_gates_control_metal", - "6": "t_console_broken", - "7": "t_chainfence_h", - "8": "t_chainfence_v", + "6": "t_metal_floor", + "7": "t_chainfence", + "8": "t_chainfence", "9": "t_chaingate_l", ":": "t_door_locked", ";": "t_metal_floor", @@ -85,8 +91,8 @@ "Z": "t_metal_floor", "[": "t_door_glass_c", "^": "t_underbrush", - "_": "t_machinery_electronic", - "a": "t_railing_v", + "_": "t_metal_floor", + "a": "t_railing", "b": "t_dirtfloor", "c": "t_metal_floor", "d": "t_metal_floor", diff --git a/data/json/mapgen_palettes/necropolis/necropolis_b3.json b/data/json/mapgen_palettes/necropolis/necropolis_b3.json index 1a28f41637278..2d1d612ed3279 100644 --- a/data/json/mapgen_palettes/necropolis/necropolis_b3.json +++ b/data/json/mapgen_palettes/necropolis/necropolis_b3.json @@ -5,10 +5,16 @@ "furniture": { "?": "f_sofa", "@": "f_bed", + "$": "f_machinery_light", + "%": "f_machinery_heavy", + "(": "f_machinery_old", + "1": "f_generator_broken", + "_": "f_machinery_electronic", + "6": "f_console_broken", "B": "f_bathtub", - "C": "f_treadmill", + "C": [ "f_treadmill", "f_treadmill_mechanical" ], "D": "f_trashcan", - "J": "f_ergometer", + "J": [ "f_ergometer", "f_ergometer_mechanical" ], "L": "f_locker", "N": "f_robotic_arm", "O": "f_oven", @@ -36,9 +42,9 @@ " ": "t_metal_floor", "!": "t_bars", "#": "t_ladder_up", - "$": "t_machinery_light", - "%": "t_machinery_heavy", - "(": "t_machinery_old", + "$": "t_metal_floor", + "%": "t_metal_floor", + "(": "t_metal_floor", "*": "t_door_bar_locked", "+": "t_door_metal_c", ",": "t_pavement_y", @@ -46,14 +52,14 @@ ".": "t_rock", "/": "t_rock_floor", "0": "t_conveyor", - "1": "t_generator_broken", + "1": "t_metal_floor", "2": "t_potential_trans", "3": "t_sewage", "4": "t_water_pump", "5": "t_gates_control_metal", - "6": "t_console_broken", + "6": "t_metal_floor", "7": "t_backboard", - "8": "t_chainfence_v", + "8": "t_chainfence", "9": "t_chaingate_l", ":": "t_door_locked", ";": "t_metal_floor", @@ -86,7 +92,7 @@ "Z": "t_metal_floor", "[": "t_door_glass_c", "^": "t_underbrush", - "_": "t_machinery_electronic", + "_": "t_metal_floor", "a": "t_railing_v", "b": "t_dirtfloor", "c": "t_metal_floor", diff --git a/data/json/mapgen_palettes/office.json b/data/json/mapgen_palettes/office.json index 6deaba4d80ed2..05995b369c9cc 100644 --- a/data/json/mapgen_palettes/office.json +++ b/data/json/mapgen_palettes/office.json @@ -23,7 +23,6 @@ "C": "t_linoleum_white", "y": "t_linoleum_white", " ": "t_region_groundcover_urban", - "x": "t_console_broken", ",": "t_pavement_y", "_": "t_pavement", "%": [ [ "t_region_shrub_decorative", 16 ], [ "t_region_groundcover_forest", 5 ] ], @@ -46,9 +45,7 @@ "2": "t_gutter_east", "3": "t_gutter_south", "4": "t_gutter_west", - "5": "t_gutter_drop", - "X": "t_generator_broken", - "N": "t_machinery_heavy" + "5": "t_gutter_drop" }, "furniture": { "?": "f_sofa", @@ -72,6 +69,9 @@ "a": "f_trashcan", "F": "f_filing_cabinet", "Q": "f_safe_l", + "x": "f_console_broken", + "X": "f_generator_broken", + "N": "f_machinery_heavy", "y": "f_locker", "B": "f_bulletin", "6": "f_cellphone_booster", diff --git a/data/json/mapgen_palettes/office_doctor.json b/data/json/mapgen_palettes/office_doctor.json index f76a559975113..591848cdd532e 100644 --- a/data/json/mapgen_palettes/office_doctor.json +++ b/data/json/mapgen_palettes/office_doctor.json @@ -7,14 +7,11 @@ "!": "t_door_locked_interior", "#": "t_wall_w", "$": "t_floor", - "%": "t_console_broken", "&": "t_floor", "+": "t_door_c", ".": "t_floor", "0": "t_window_alarm", "D": "t_floor", - "5": "t_console", - "6": "t_console", "9": "t_window_domestic", ":": "t_door_glass_c", ";": "t_door_locked", @@ -50,6 +47,9 @@ "furniture": { "$": "f_safe_l", "&": "f_toilet", + "%": "f_console_broken", + "5": "f_console", + "6": "f_console", "B": "f_bed", "C": "f_locker", "H": "f_locker", diff --git a/data/json/mapgen_palettes/prison.json b/data/json/mapgen_palettes/prison.json index 88118407be03f..44dce938d3699 100644 --- a/data/json/mapgen_palettes/prison.json +++ b/data/json/mapgen_palettes/prison.json @@ -40,7 +40,6 @@ "s": "t_sidewalk", "t": "t_floor", "w": "t_window", - "x": "t_console_broken", "y": "t_floor", "z": "t_floor", "|": "t_concrete_wall" @@ -64,6 +63,7 @@ "o": "f_bookcase", "r": "f_rack", "t": "f_table", + "x": "f_console_broken", "z": "f_rack" }, "toilets": { "T": { } }, diff --git a/data/json/mapgen_palettes/private_resort.json b/data/json/mapgen_palettes/private_resort.json index 39d90a1e3ec47..effeb1fe942e4 100644 --- a/data/json/mapgen_palettes/private_resort.json +++ b/data/json/mapgen_palettes/private_resort.json @@ -3,6 +3,7 @@ "type": "palette", "id": "p_resort_palette_main_floor", "furniture": { + "&": "f_console_broken", "f": "f_glass_fridge", "B": "f_workbench", "]": "f_fridge", @@ -72,7 +73,6 @@ "P": "t_concrete", "U": "t_water_pool", "m": "t_metal_floor", - "&": "t_console_broken", "p": "t_door_c_peep", "8": "t_door_curtain_c", "n": "t_carpet_green", @@ -189,6 +189,10 @@ "type": "palette", "id": "p_resort_palette_basement", "furniture": { + "&": "f_console_broken", + "1": "f_generator_broken", + "2": "f_machinery_light", + "3": "f_machinery_heavy", "L": "f_locker", "S": "f_utility_shelf", "f": "f_glass_fridge", @@ -212,10 +216,6 @@ "V": "t_bars", "0": "t_ballistic_glass", "l": "t_door_metal_locked", - "&": "t_console_broken", - "1": "t_generator_broken", - "2": "t_machinery_light", - "3": "t_machinery_heavy", "?": "t_secretdoor_metal_c", ",": "t_metal_floor", "m": "t_wall_metal", @@ -233,6 +233,7 @@ "(": "f_small_satelitte_dish", "s": "f_solar_unit", "H": "f_chimney", + "l": "f_machinery_light", "v": "f_roof_turbine_vent" }, "terrain": { @@ -241,8 +242,7 @@ ">": "t_stairs_down", "r": "t_guardrail", "#": "t_sai_box_damaged", - "I": "t_lgtn_arrest", - "l": "t_machinery_light" + "I": "t_lgtn_arrest" } } ] diff --git a/data/json/mapgen_palettes/refugee_center.json b/data/json/mapgen_palettes/refugee_center.json index cefb285301468..15e312bae19ee 100644 --- a/data/json/mapgen_palettes/refugee_center.json +++ b/data/json/mapgen_palettes/refugee_center.json @@ -13,7 +13,6 @@ "0": "t_door_locked_interior", "1": "t_reinforced_glass_shutter", "2": "t_utility_light", - "6": "t_console_broken", "!": "t_fence_barbed", "=": "t_door_metal_locked", ">": "t_stairs_down", @@ -27,6 +26,7 @@ "}": "t_sidewalk" }, "furniture": { + "6": "f_console_broken", ")": "f_wreckage", "@": "f_bed", "D": "f_trashcan", diff --git a/data/json/mapgen_palettes/robofachq.json b/data/json/mapgen_palettes/robofachq.json index 9055efc84710d..a56fc15e5cdf0 100644 --- a/data/json/mapgen_palettes/robofachq.json +++ b/data/json/mapgen_palettes/robofachq.json @@ -9,7 +9,6 @@ "2": "t_door_metal_c", "4": "t_door_metal_pickable", "5": "t_door_metal_locked", - "6": "t_console_broken", "[": "t_door_glass_c", "-": "t_wall", "|": "t_concrete_wall", @@ -28,11 +27,12 @@ ">": "t_stairs_down", "0": "t_window_empty", ":": "t_window_domestic", - "u": "t_chainfence_h", - "U": "t_chainfence_v", + "u": "t_chainfence", + "U": "t_chainfence", "#": "t_rock" }, "furniture": { + "6": "f_console_broken", "&": "f_toilet", "~": "f_shower", "@": "f_bed", diff --git a/data/json/mapgen_palettes/shelter.json b/data/json/mapgen_palettes/shelter.json index f3bb04936e2eb..d0790f5f21591 100644 --- a/data/json/mapgen_palettes/shelter.json +++ b/data/json/mapgen_palettes/shelter.json @@ -11,18 +11,24 @@ "+": "t_door_c", "-": "t_wall_w", "_": "t_linoleum_white", - "6": "t_console", ":": "t_window_domestic", ">": "t_stairs_down", "<": "t_stairs_up", - "x": "t_console_broken", "|": "t_wall_w", ";": "t_concrete_wall", "*": "t_ladder_up", "=": "t_door_locked_interior", "4": "t_gutter_downspout" }, - "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "furniture": { + "6": "f_console", + "x": "f_console_broken", + "b": "f_bench", + "c": "f_cupboard", + "l": "f_locker", + "S": "f_sink", + "%": "f_trashcan" + }, "toilets": { "T": { } }, "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 80 }, diff --git a/data/json/mapgen_palettes/steel_mill_palette.json b/data/json/mapgen_palettes/steel_mill_palette.json index d98d6042f5163..981ad62d7f47b 100644 --- a/data/json/mapgen_palettes/steel_mill_palette.json +++ b/data/json/mapgen_palettes/steel_mill_palette.json @@ -24,10 +24,6 @@ ">": "t_stairs_down", "/": "t_ladder_up", "I": "t_ladder_down", - "c": "t_console_broken", - "m": "t_machinery_light", - "M": "t_machinery_heavy", - "E": "t_machinery_electronic", "8": "t_bulk_tank", "^": "t_railroad_rubble", "X": "t_railroad_track", @@ -43,13 +39,17 @@ ";": "t_gates_control_concrete", "a": "t_open_air_rooved", "r": "t_metal_flat_roof", - "g": "t_generator_broken", "G": "t_grate", "2": "t_sai_box", "5": "t_switchgear_l", "`": "t_thconc_y" }, "furniture": { + "c": "f_console_broken", + "m": "f_machinery_light", + "M": "f_machinery_heavy", + "E": "f_machinery_electronic", + "g": "f_generator_broken", "h": "f_chair", "T": "f_table", "A": "f_air_conditioner", diff --git a/data/json/monster_factions.json b/data/json/monster_factions.json index 510b9501d9a28..5614331a49660 100644 --- a/data/json/monster_factions.json +++ b/data/json/monster_factions.json @@ -54,6 +54,12 @@ "name": "jabberwock", "by_mood": [ "jabberwock" ] }, + { + "type": "MONSTER_FACTION", + "name": "robofac", + "neutral": [ "cop_bot", "defense_bot", "utility_bot", "animal" ], + "hate": [ "zombie", "fungus", "cult", "triffid", "nether" ] + }, { "type": "MONSTER_FACTION", "name": "bot", diff --git a/data/json/monsterdrops/zombie_cop.json b/data/json/monsterdrops/zombie_cop.json index 8ef549093c7b1..27039dd5a3528 100644 --- a/data/json/monsterdrops/zombie_cop.json +++ b/data/json/monsterdrops/zombie_cop.json @@ -30,7 +30,8 @@ [ "1st_aid", 30 ], [ "armor_riot", 20 ], [ "airhorn", 5 ], - [ "bandages", 20 ], + [ "bandages", 10 ], + [ "adhesive_bandages", 10 ], [ "tacvest", 5 ], [ "heavy_flashlight", 35 ], [ "holster", 25 ], @@ -113,7 +114,10 @@ "id": "swat_zombie_gear", "subtype": "collection", "entries": [ - { "collection": [ { "item": "bandages", "prob": 60 }, { "item": "1st_aid", "prob": 20 } ], "prob": 25 }, + { + "collection": [ { "item": "adhesive_bandages", "prob": 30 }, { "item": "bandages", "prob": 30 }, { "item": "1st_aid", "prob": 20 } ], + "prob": 25 + }, { "collection": [ { "item": "swat_armor", "prob": 50 }, { "item": "kevlar", "prob": 25 }, { "item": "tacvest", "prob": 5 } ], "prob": 75 diff --git a/data/json/monstergroups/wilderness.json b/data/json/monstergroups/wilderness.json index 11f4dcfd889a1..cadd5f84e44fb 100644 --- a/data/json/monstergroups/wilderness.json +++ b/data/json/monstergroups/wilderness.json @@ -131,6 +131,10 @@ { "monster": "mon_crow", "freq": 25, "cost_multiplier": 0, "pack_size": [ 1, 14 ], "conditions": [ "DAY" ] }, { "monster": "mon_deer", "freq": 4, "cost_multiplier": 2, "pack_size": [ 1, 5 ] }, { "monster": "mon_deer", "freq": 16, "cost_multiplier": 2, "pack_size": [ 1, 5 ], "conditions": [ "DAY" ] }, + { "monster": "mon_zeer", "freq": 4, "cost_multiplier": 10, "pack_size": [ 1, 5 ], "starts": 72 }, + { "monster": "mon_zeer", "freq": 4, "cost_multiplier": 10, "pack_size": [ 1, 5 ], "starts": 168 }, + { "monster": "mon_zeer", "freq": 4, "cost_multiplier": 10, "pack_size": [ 1, 5 ], "starts": 672 }, + { "monster": "mon_zeer", "freq": 4, "cost_multiplier": 10, "pack_size": [ 1, 5 ], "starts": 2160 }, { "monster": "mon_dog", "freq": 3, "cost_multiplier": 25, "pack_size": [ 1, 6 ] }, { "monster": "mon_dog", @@ -725,6 +729,14 @@ { "monster": "mon_zolf", "freq": 2, "cost_multiplier": 2, "starts": 168, "pack_size": [ 1, 4 ] }, { "monster": "mon_zolf", "freq": 2, "cost_multiplier": 2, "starts": 672, "pack_size": [ 1, 4 ] }, { "monster": "mon_zolf", "freq": 2, "cost_multiplier": 2, "starts": 2160, "pack_size": [ 1, 4 ] }, + { + "monster": "mon_zombie_horse", + "freq": 2, + "cost_multiplier": 15, + "ends": 2000, + "conditions": [ "DAWN", "SPRING", "SUMMER", "AUTUMN" ], + "pack_size": [ 1, 4 ] + }, { "monster": "mon_groundhog", "freq": 30, diff --git a/data/json/monstergroups/zanimal_upgrades.json b/data/json/monstergroups/zanimal_upgrades.json index 8ed879c184ece..63728e8f84c79 100644 --- a/data/json/monstergroups/zanimal_upgrades.json +++ b/data/json/monstergroups/zanimal_upgrades.json @@ -1,4 +1,24 @@ [ + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_DOG_UPGRADE", + "default": "mon_dog_skeleton", + "//": "No bionics or fungal", + "monsters": [ + { "monster": "mon_dog_skeleton", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_dog_zombie_brute", "freq": 45, "cost_multiplier": 2 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOLF_UPGRADE", + "default": "mon_wolf_skeleton", + "//": "No bionics or fungal", + "monsters": [ + { "monster": "mon_wolf_skeleton", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_dog_zombie_brute", "freq": 45, "cost_multiplier": 2 } + ] + }, { "type": "monstergroup", "name": "GROUP_ZOMBEAR_UPGRADE", diff --git a/data/json/monstergroups/zombies.json b/data/json/monstergroups/zombies.json index 251c75fcd26c7..a4b77da6f149e 100644 --- a/data/json/monstergroups/zombies.json +++ b/data/json/monstergroups/zombies.json @@ -10,6 +10,9 @@ { "monster": "mon_zombie_fat", "freq": 50, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_rot", "freq": 50, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_runner", "freq": 20, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, + { "monster": "mon_feral_human_pipe", "freq": 40, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "mon_feral_human_crowbar", "freq": 40, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "mon_feral_human_axe", "freq": 20, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, { "monster": "mon_zombie_crawler", "freq": 25, "cost_multiplier": 1 }, { "monster": "mon_zombie_brainless", "freq": 25, "cost_multiplier": 1 }, { "monster": "mon_zombie_dog", "freq": 25, "cost_multiplier": 1, "pack_size": [ 2, 3 ] } @@ -58,6 +61,9 @@ { "monster": "mon_zombie_fat", "freq": 50, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_rot", "freq": 50, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_runner", "freq": 20, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, + { "monster": "mon_feral_human_pipe", "freq": 20, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "mon_feral_human_crowbar", "freq": 20, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "mon_feral_human_axe", "freq": 10, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, { "monster": "mon_zombie_crawler", "freq": 25, "cost_multiplier": 1 }, { "monster": "mon_zombie_brainless", "freq": 25, "cost_multiplier": 1 } ] @@ -105,6 +111,9 @@ { "monster": "mon_beekeeper", "freq": 1, "cost_multiplier": 5 }, { "monster": "mon_zombie_technician", "freq": 1, "cost_multiplier": 12 }, { "monster": "mon_zombie_runner", "freq": 20, "cost_multiplier": 5, "pack_size": [ 1, 4 ] }, + { "monster": "mon_feral_human_pipe", "freq": 4, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "mon_feral_human_crowbar", "freq": 4, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "mon_feral_human_axe", "freq": 2, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, { "monster": "mon_zombie_brainless", "freq": 65, "cost_multiplier": 1 } ] }, @@ -119,6 +128,9 @@ { "monster": "mon_zombie_rot", "freq": 60, "cost_multiplier": 0 }, { "monster": "mon_zombie_dog", "freq": 50, "cost_multiplier": 0 }, { "monster": "mon_zombie_crawler", "freq": 30, "cost_multiplier": 0 }, + { "monster": "mon_feral_human_pipe", "freq": 40, "cost_multiplier": 0 }, + { "monster": "mon_feral_human_crowbar", "freq": 40, "cost_multiplier": 0 }, + { "monster": "mon_feral_human_axe", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie_brainless", "freq": 30, "cost_multiplier": 0 } ] }, @@ -475,6 +487,9 @@ { "monster": "mon_zombie", "freq": 1, "cost_multiplier": 7, "pack_size": [ 5, 10 ] }, { "monster": "mon_zombie", "freq": 1, "cost_multiplier": 13, "pack_size": [ 15, 20 ] }, { "monster": "mon_zombie", "freq": 1, "cost_multiplier": 20, "pack_size": [ 25, 30 ] }, + { "monster": "mon_feral_human_pipe", "freq": 4, "cost_multiplier": 1, "pack_size": [ 5, 9 ] }, + { "monster": "mon_feral_human_crowbar", "freq": 4, "cost_multiplier": 1, "pack_size": [ 4, 7 ] }, + { "monster": "mon_feral_human_axe", "freq": 2, "cost_multiplier": 2, "pack_size": [ 2, 4 ] }, { "monster": "mon_zombie", "freq": 75, "cost_multiplier": 2 }, { "monster": "mon_zombie_fat", "freq": 75, "cost_multiplier": 2 }, { "monster": "mon_zombie_fat", "freq": 3, "cost_multiplier": 7, "pack_size": [ 3, 5 ] }, @@ -561,6 +576,16 @@ { "monster": "mon_zombie", "freq": 40, "cost_multiplier": 1 } ] }, + { + "name": "FERAL_HUMANS", + "type": "monstergroup", + "default": "mon_feral_human_pipe", + "monsters": [ + { "monster": "mon_feral_human_pipe", "freq": 100, "cost_multiplier": 1, "pack_size": [ 3, 8 ] }, + { "monster": "mon_feral_human_crowbar", "freq": 40, "cost_multiplier": 1, "pack_size": [ 2, 6 ] }, + { "monster": "mon_feral_human_axe", "freq": 20, "cost_multiplier": 2, "pack_size": [ 1, 4 ] } + ] + }, { "type": "monstergroup", "name": "DUMP_ZOMBIES", diff --git a/data/json/monsters/cyborgs.json b/data/json/monsters/cyborgs.json index c344640b827d5..c611f0502f100 100644 --- a/data/json/monsters/cyborgs.json +++ b/data/json/monsters/cyborgs.json @@ -206,7 +206,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", diff --git a/data/json/monsters/feral_humans.json b/data/json/monsters/feral_humans.json new file mode 100644 index 0000000000000..ed39a82bac961 --- /dev/null +++ b/data/json/monsters/feral_humans.json @@ -0,0 +1,77 @@ +[ + { + "id": "mon_feral_human_pipe", + "type": "MONSTER", + "name": { "str": "feral human" }, + "description": "Pupils dilated and what remains to be seen of the iris and sclera are bloodshot. It still breathes but the zombies treat it like one of them.", + "default_faction": "zombie", + "looks_like": "chud", + "bodytype": "human", + "species": [ "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 100, + "material": [ "flesh" ], + "symbol": "@", + "color": "magenta", + "aggression": 30, + "morale": 100, + "melee_skill": 2, + "melee_dice": 1, + "melee_dice_sides": 3, + "melee_cut": 0, + "dodge": 1, + "harvest": "human", + "vision_day": 30, + "vision_night": 3, + "starting_ammo": { "rock": 6 }, + "special_attacks": [ + { + "type": "gun", + "cooldown": 5, + "move_cost": 150, + "gun_type": "feral_human_thrown_rock", + "fake_skills": [ [ "gun", 2 ], [ "throw", 2 ] ], + "fake_dex": 6, + "fake_per": 6, + "require_targeting_player": false, + "ranges": [ [ 2, 5, "DEFAULT" ] ], + "description": "They throw a loose brick at you!" + } + ], + "death_drops": "default_zombie_clothes", + "death_function": [ "NORMAL" ], + "zombify_into": "mon_zombie", + "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT" ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "HUMAN", "CAN_OPEN_DOORS", "PATH_AVOID_DANGER_2" ] + }, + { + "id": "mon_feral_human_crowbar", + "type": "MONSTER", + "copy-from": "mon_feral_human_pipe", + "melee_dice": 2, + "melee_dice_sides": 6, + "special_attacks": [ + { + "type": "gun", + "cooldown": 5, + "move_cost": 150, + "gun_type": "feral_human_thrown_rock", + "fake_skills": [ [ "gun", 2 ], [ "thrown", 2 ] ], + "fake_dex": 6, + "fake_per": 6, + "require_targeting_player": false, + "ranges": [ [ 2, 5, "DEFAULT" ] ], + "description": "They throw a loose brick at you!" + } + ] + }, + { + "id": "mon_feral_human_axe", + "type": "MONSTER", + "copy-from": "mon_feral_human_pipe", + "melee_dice": 3, + "melee_dice_sides": 8 + } +] diff --git a/data/json/monsters/fungus.json b/data/json/monsters/fungus.json index 7c19762afc1a9..d59b3102350e7 100644 --- a/data/json/monsters/fungus.json +++ b/data/json/monsters/fungus.json @@ -449,7 +449,6 @@ "WARM", "BASHES", "DESTROYS", - "BLEED", "POISON", "ATTACKMON", "NO_BREATHE", diff --git a/data/json/monsters/mammal.json b/data/json/monsters/mammal.json index 520375c618e54..bb559d79c4962 100644 --- a/data/json/monsters/mammal.json +++ b/data/json/monsters/mammal.json @@ -98,7 +98,7 @@ "//": "220 days gestation period, the mother and cubs remain together for 16-17 months.", "baby_flags": [ "SPRING" ], "special_attacks": [ [ "EAT_FOOD", 20 ] ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "BLEED", "BASHES", "ATTACKMON" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "BASHES", "ATTACKMON" ] }, { "id": "mon_beaver", @@ -194,7 +194,7 @@ "upgrades": { "age_grow": 38, "into": "mon_boar_wild" }, "biosignature": { "biosig_item": "feces_manure", "biosig_timer": 7 }, "special_attacks": [ [ "EAT_FOOD", 40 ] ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, { "id": "mon_boar_wild", @@ -232,7 +232,7 @@ "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], "special_attacks": [ [ "EAT_FOOD", 20 ] ], - "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, { "id": "mon_bobcat", @@ -563,18 +563,7 @@ "death_function": [ "NORMAL" ], "zombify_into": "mon_zougar", "harvest": "mammal_fur", - "flags": [ - "SEES", - "HEARS", - "GOODHEARING", - "SMELLS", - "ANIMAL", - "PATH_AVOID_DANGER_1", - "WARM", - "HIT_AND_RUN", - "KEENNOSE", - "BLEED" - ] + "flags": [ "SEES", "HEARS", "GOODHEARING", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE" ] }, { "id": "mon_tiger", @@ -660,6 +649,7 @@ "placate_triggers": [ "PLAYER_WEAK" ], "death_drops": { "subtype": "collection", "groups": [ [ "cow", 25 ] ], "//": "25% chance of an item from group cow" }, "death_function": [ "NORMAL" ], + "zombify_into": "mon_zow", "harvest": "mammal_large_leather", "reproduction": { "baby_monster": "mon_cow_calf", "baby_count": 1, "baby_timer": 343 }, "baby_flags": [ "SPRING", "SUMMER", "AUTUMN" ], @@ -708,7 +698,7 @@ "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], "harvest": "mammal_fur", - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE" ] }, { "id": "mon_coyote_wolf", @@ -740,7 +730,7 @@ "fear_triggers": [ "SOUND" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, { "id": "mon_deer_fawn", @@ -802,6 +792,7 @@ "path_settings": { "max_dist": 10 }, "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], + "zombify_into": "mon_zeer", "reproduction": { "baby_monster": "mon_deer_fawn", "baby_count": 1, "baby_timer": 330 }, "//": " 201 days gestation period. The fawn will stay with its mother for approximately one year, suckling for three to four months.", "biosignature": { "biosig_item": "feces_manure", "biosig_timer": 12 }, @@ -1609,7 +1600,7 @@ "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE" ] }, { "id": "mon_fox_red", @@ -1640,7 +1631,7 @@ "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE" ] }, { "id": "mon_groundhog", @@ -1724,6 +1715,7 @@ "harvest": "mammal_large_leather", "biosignature": { "biosig_item": "feces_manure", "biosig_timer": 2 }, "special_attacks": [ [ "EAT_CROP", 60 ] ], + "zombify_into": "mon_zombie_horse", "flags": [ "SEES", "HEARS", @@ -1790,7 +1782,7 @@ "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "HIT_AND_RUN", "KEENNOSE" ] }, { "id": "mon_moose", @@ -1828,7 +1820,7 @@ "harvest": "mammal_large_leather", "biosignature": { "biosig_item": "feces_manure", "biosig_timer": 8 }, "special_attacks": [ [ "EAT_CROP", 60 ] ], - "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "BLEED", "ATTACKMON" ] + "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "ATTACKMON" ] }, { "id": "mon_muskrat", @@ -1894,7 +1886,7 @@ "death_function": [ "NORMAL" ], "regenerates": 10, "regen_morale": true, - "flags": [ "ATTACKMON", "BLEED", "BORES", "CAN_DIG", "HEARS", "KEENNOSE", "PATH_AVOID_DANGER_1", "SMELLS", "WARM" ], + "flags": [ "ATTACKMON", "BORES", "CAN_DIG", "HEARS", "KEENNOSE", "PATH_AVOID_DANGER_1", "SMELLS", "WARM" ], "//": "Reinsert GOODHEARING when z-level tunneling is possible." }, { @@ -1924,7 +1916,7 @@ "anger_triggers": [ "FRIEND_ATTACKED", "HURT" ], "fear_triggers": [ "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "CLIMBS", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "CLIMBS", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, { "id": "mon_otter", @@ -1985,18 +1977,7 @@ "upgrades": { "age_grow": 38, "into": "mon_pig" }, "biosignature": { "biosig_item": "feces_manure", "biosig_timer": 7 }, "special_attacks": [ [ "EAT_FOOD", 40 ] ], - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "ANIMAL", - "PATH_AVOID_DANGER_1", - "CATTLEFODDER", - "PET_WONT_FOLLOW", - "WARM", - "KEENNOSE", - "BLEED" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "CATTLEFODDER", "PET_WONT_FOLLOW", "WARM", "KEENNOSE" ] }, { "id": "mon_pig", @@ -2033,7 +2014,7 @@ "death_function": [ "NORMAL" ], "zombify_into": "mon_zombie_pig", "special_attacks": [ [ "EAT_FOOD", 20 ] ], - "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, { "id": "mon_rabbit", @@ -2088,7 +2069,7 @@ "vision_night": 5, "anger_triggers": [ "FRIEND_ATTACKED", "HURT" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "CLIMBS", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "CLIMBS", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, { "id": "mon_rat_king", @@ -2334,6 +2315,6 @@ "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], "zombify_into": "mon_zolf", - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE", "BLEED" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] } ] diff --git a/data/json/monsters/marloss.json b/data/json/monsters/marloss.json index 4bddf7ba93bd9..66d143afd1c05 100644 --- a/data/json/monsters/marloss.json +++ b/data/json/monsters/marloss.json @@ -28,7 +28,7 @@ "death_drops": "marloss_zealot_death_drops", "death_function": [ "NORMAL" ], "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT" ], - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "BLEED", "HUMAN", "POISON" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "HUMAN", "POISON" ] }, { "id": "mon_marloss_zealot_m", @@ -59,6 +59,6 @@ "death_drops": "marloss_zealot_death_drops", "death_function": [ "NORMAL" ], "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT" ], - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "BLEED", "HUMAN", "POISON" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "HUMAN", "POISON" ] } ] diff --git a/data/json/monsters/mutant.json b/data/json/monsters/mutant.json index ef2b4324a06c2..8c2021c1ed02d 100644 --- a/data/json/monsters/mutant.json +++ b/data/json/monsters/mutant.json @@ -75,7 +75,7 @@ "upgrades": { "half_life": 50, "into": "mon_mutant_evolved" }, "regenerates": 1, "regen_morale": true, - "flags": [ "SEES", "HEARS", "SMELLS", "KEENNOSE", "WARM", "BLEED", "BASHES", "PATH_AVOID_DANGER_2" ] + "flags": [ "SEES", "HEARS", "SMELLS", "KEENNOSE", "WARM", "BASHES", "PATH_AVOID_DANGER_2" ] }, { "id": "mon_mutant_evolved", @@ -120,7 +120,6 @@ "SMELLS", "KEENNOSE", "WARM", - "BLEED", "BASHES", "PATH_AVOID_DANGER_2", "PUSH_MON", diff --git a/data/json/monsters/nether.json b/data/json/monsters/nether.json index e72c2c62a1886..980cf66a2df5d 100644 --- a/data/json/monsters/nether.json +++ b/data/json/monsters/nether.json @@ -112,7 +112,7 @@ "special_attacks": [ [ "FEAR_PARALYZE", 0 ], { "type": "bite", "cooldown": 5 } ], "death_drops": "default_zombie_clothes", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BLEED", "IMMOBILE", "GUILT", "POISON", "REVIVES", "FILTHY" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "IMMOBILE", "GUILT", "POISON", "REVIVES", "FILTHY" ] }, { "id": "mon_breather", @@ -212,7 +212,7 @@ "special_attacks": [ [ "scratch", 15 ] ], "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "BLEED", "HUMAN", "POISON", "REVIVES", "FILTHY" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "HUMAN", "POISON", "REVIVES", "FILTHY" ] }, { "id": "mon_dog_thing", @@ -295,7 +295,7 @@ "special_attacks": [ [ "FEAR_PARALYZE", 0 ], { "type": "bite", "cooldown": 5 } ], "death_drops": "default_zombie_clothes", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BLEED", "HARDTOSHOOT", "ATTACKMON", "HUMAN", "POISON", "REVIVES", "FILTHY" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "HARDTOSHOOT", "ATTACKMON", "HUMAN", "POISON", "REVIVES", "FILTHY" ] }, { "id": "mon_flying_polyp", @@ -458,7 +458,7 @@ "armor_bullet": 2, "harvest": "human", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "BLEED", "HUMAN", "REVIVES", "CLIMBS", "FILTHY" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "HUMAN", "REVIVES", "CLIMBS", "FILTHY" ] }, { "id": "mon_hound_tindalos", diff --git a/data/json/monsters/reptile_amphibian.json b/data/json/monsters/reptile_amphibian.json index 58a786ae707ca..1de35f4832edc 100644 --- a/data/json/monsters/reptile_amphibian.json +++ b/data/json/monsters/reptile_amphibian.json @@ -76,7 +76,7 @@ "fear_triggers": [ "FIRE", "HURT" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "GOODHEARING", "SMELLS", "KEENNOSE", "PATH_AVOID_DANGER_1", "ANIMAL", "BLEED", "ATTACKMON", "SWIMS" ] + "flags": [ "SEES", "HEARS", "GOODHEARING", "SMELLS", "KEENNOSE", "PATH_AVOID_DANGER_1", "ANIMAL", "ATTACKMON", "SWIMS" ] }, { "id": "mon_rattlesnake", diff --git a/data/json/monsters/robofac_robots.json b/data/json/monsters/robofac_robots.json new file mode 100644 index 0000000000000..b369d63535236 --- /dev/null +++ b/data/json/monsters/robofac_robots.json @@ -0,0 +1,36 @@ +[ + { + "id": "mon_robofac_laserturret_mk1", + "type": "MONSTER", + "name": { "str": "prototype laser turret" }, + "description": "This appears to be a very experimental automated tower. Plating-less and seemingly half-built, it's little more than an oversized laser emitter and a camera, both welded to a swiveling platform.", + "default_faction": "robofac", + "species": [ "ROBOT" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 30, + "speed": 100, + "material": [ "steel" ], + "symbol": "2", + "color": "white", + "aggression": 100, + "morale": 100, + "armor_bash": 2, + "armor_cut": 5, + "armor_bullet": 2, + "vision_day": 50, + "special_attacks": [ + { + "type": "gun", + "cooldown": 1, + "gun_type": "v29", + "fake_skills": [ [ "gun", 4 ], [ "pistol", 4 ] ], + "ranges": [ [ 0, 30, "DEFAULT" ] ] + } + ], + "special_when_hit": [ "RETURN_FIRE", 100 ], + "death_drops": { }, + "death_function": [ "BROKEN" ], + "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "COLDPROOF", "IMMOBILE", "NO_BREATHE" ] + } +] diff --git a/data/json/monsters/zanimal_upgrade.json b/data/json/monsters/zanimal_upgrade.json index 2ae29edc219cd..ba24c12fc39bc 100644 --- a/data/json/monsters/zanimal_upgrade.json +++ b/data/json/monsters/zanimal_upgrade.json @@ -1,4 +1,132 @@ [ + { + "id": "mon_dog_skeleton", + "type": "MONSTER", + "name": { "str": "skeletal dog" }, + "description": "This once-canine has shed all of its skin, revealing a carapace of fused bones and ribs. Devoid entirely of flesh, this walking suit of bone seems to be controlled by a net of veins and sinews which pulse with glistening black goo.", + "default_faction": "zombie", + "bodytype": "dog", + "species": [ "ZOMBIE" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 12, + "speed": 100, + "material": [ "bone" ], + "symbol": "d", + "color": "white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 1, + "melee_dice_sides": 9, + "melee_cut": 6, + "dodge": 3, + "armor_cut": 15, + "armor_bullet": 12, + "armor_stab": 30, + "armor_acid": 3, + "vision_night": 3, + "harvest": "mr_bones", + "special_attacks": [ { "type": "bite", "cooldown": 5 } ], + "upgrades": { "half_life": 15, "into": "mon_dog_skeleton_brute" }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "NO_BREATHE", "HARDTOSHOOT", "REVIVES", "POISON", "FILTHY" ] + }, + { + "id": "mon_dog_zombie_brute", + "type": "MONSTER", + "name": { "str": "barghest" }, + "copy-from": "mon_dog_zombie_rot", + "description": "Huge swollen zombie dog, smeared black with slime. Its teeth are longer and its broad back is rippling with muscles and oozing wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { "half_life": 21, "into": "mon_dog_zombie_hulk" }, + "special_attacks": [ [ "SMASH", 30 ], { "type": "bite", "cooldown": 2, "accuracy": 4, "no_infection_chance": 12 } ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_VEH" ] } + }, + { + "id": "mon_dog_zombie_hulk", + "type": "MONSTER", + "name": { "str": "hulking horror" }, + "copy-from": "mon_dog_zombie_brute", + "description": "A four-legged canine body now grotesquely swollen, with arms as wide as a trash can and massive exposed teeth.", + "diff": 5, + "volume": "440 L", + "weight": "100 kg", + "color": "white_magenta", + "proportional": { "hp": 4, "speed": 1.25 }, + "relative": { "melee_skill": 1, "melee_dice": 1, "melee_cut": -2 }, + "armor_bash": 8, + "armor_cut": 12, + "armor_bullet": 10, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 20 ], { "type": "bite", "cooldown": 2, "accuracy": 4, "no_infection_chance": 12 } ], + "extend": { "flags": [ "DESTROYS" ] } + }, + { + "id": "mon_dog_skeleton_brute", + "type": "MONSTER", + "copy-from": "mon_dog_skeleton", + "name": { "str": "boneplate wolf" }, + "description": "This is a four legged creature covered in fused bony plates, shaped somewhat like a dog or wolf. Joints and cracks around its body ooze with black goo.", + "volume": "46 L", + "weight": "60 kg", + "hp": 70, + "relative": { "melee_dice": -1, "melee_dice_sides": 2, "melee_cut": 6 }, + "armor_cut": 30, + "armor_bullet": 24, + "armor_bash": 12, + "armor_acid": 1, + "special_attacks": [ + [ "SMASH", 45 ], + { "id": "scratch", "damage_max_instance": [ { "damage_type": "cut", "amount": 15, "armor_multiplier": 0.6 } ] } + ], + "upgrades": { "half_life": 12, "into": "mon_skeleton_hulk" } + }, + { + "id": "mon_wolf_skeleton", + "type": "MONSTER", + "name": { "str": "skeletal wolf" }, + "description": "This once-canine has shed all of its skin, revealing a carapace of fused bones and ribs. Devoid entirely of flesh, this walking suit of bone seems to be controlled by a net of veins and sinews which pulse with glistening black goo.", + "looks_like": "mon_dog_skeleton", + "default_faction": "zombie", + "bodytype": "dog", + "species": [ "ZOMBIE" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 18, + "speed": 100, + "material": [ "bone" ], + "symbol": "d", + "color": "white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 3, + "melee_dice_sides": 7, + "melee_cut": 8, + "dodge": 4, + "armor_cut": 15, + "armor_bullet": 12, + "armor_stab": 30, + "armor_acid": 3, + "vision_night": 3, + "harvest": "mr_bones", + "special_attacks": [ { "type": "bite", "cooldown": 5 } ], + "upgrades": { "half_life": 15, "into": "mon_dog_skeleton_brute" }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "NO_BREATHE", "HARDTOSHOOT", "REVIVES", "POISON", "FILTHY" ] + }, { "id": "mon_zougar_hunter", "type": "MONSTER", @@ -44,7 +172,7 @@ "vision_day": 10, "harvest": "mr_bones", "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], - "flags": [ "SEES", "HEARS", "BLEED", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] + "flags": [ "SEES", "HEARS", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] }, { "id": "mon_zougar_shady", @@ -166,7 +294,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", diff --git a/data/json/monsters/zed-animal.json b/data/json/monsters/zed-animal.json index 5a26d8b249761..7567cf917171e 100644 --- a/data/json/monsters/zed-animal.json +++ b/data/json/monsters/zed-animal.json @@ -57,41 +57,9 @@ "harvest": "zombie", "special_attacks": [ { "type": "bite", "cooldown": 5 } ], "death_function": [ "NORMAL" ], - "upgrades": { "half_life": 28, "into": "mon_dog_skeleton" }, + "upgrades": { "half_life": 28, "into_group": "GROUP_ZOMBIE_DOG_UPGRADE" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] }, - { - "id": "mon_dog_skeleton", - "type": "MONSTER", - "name": { "str": "skeletal dog" }, - "description": "This once-canine has shed all of its skin, revealing a carapace of fused bones and ribs. Devoid entirely of flesh, this walking suit of bone seems to be controlled by a net of veins and sinews which pulse with glistening black goo.", - "default_faction": "zombie", - "bodytype": "dog", - "species": [ "ZOMBIE" ], - "volume": "30000 ml", - "weight": "40750 g", - "hp": 12, - "speed": 100, - "material": [ "bone" ], - "symbol": "d", - "color": "white", - "aggression": 100, - "morale": 100, - "melee_skill": 4, - "melee_dice": 1, - "melee_dice_sides": 9, - "melee_cut": 6, - "dodge": 3, - "armor_cut": 15, - "armor_bullet": 12, - "armor_stab": 30, - "armor_acid": 3, - "vision_night": 3, - "harvest": "mr_bones", - "special_attacks": [ { "type": "bite", "cooldown": 5 } ], - "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "NO_BREATHE", "HARDTOSHOOT", "REVIVES", "POISON", "FILTHY" ] - }, { "id": "mon_dog_zombie_cop", "type": "MONSTER", @@ -124,6 +92,7 @@ "special_attacks": [ { "type": "bite", "cooldown": 5 } ], "death_drops": { "subtype": "collection", "groups": [ [ "dog_cop", 40 ] ], "//": "40% chance of an item from group dog_cop" }, "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 28, "into_group": "GROUP_ZOMBIE_DOG_UPGRADE" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { @@ -154,6 +123,7 @@ "harvest": "zombie", "special_attacks": [ { "type": "bite", "cooldown": 2, "accuracy": 4, "no_infection_chance": 12 } ], "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 28, "into": "mon_dog_zombie_brute" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { @@ -185,6 +155,7 @@ "anger_triggers": [ "PLAYER_CLOSE", "HURT" ], "fear_triggers": [ "FIRE" ], "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 28, "into_group": "GROUP_ZOLF_UPGRADE" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "KEENNOSE", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] }, { @@ -252,20 +223,7 @@ "anger_triggers": [ "PLAYER_WEAK", "PLAYER_CLOSE" ], "fear_triggers": [ "FIRE" ], "death_function": [ "NORMAL" ], - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "KEENNOSE", - "BLEED", - "BASHES", - "POISON", - "NO_BREATHE", - "REVIVES", - "FILTHY" - ], + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "KEENNOSE", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "1d8->2d5, minor bonus over 1d9" }, { @@ -380,6 +338,37 @@ "FILTHY" ] }, + { + "id": "mon_zombie_horse", + "type": "MONSTER", + "name": { "str": "zombie horse" }, + "description": "From the looks of this zombie horse's ghastly features, with its protruding ribs, whitish skull, and empty eyes, the exposed part of the internal organs shows a seemingly lifeless color, and the black body fluid drips slowly. The new strength makes the horse no longer dependent on its muscles, but it can still pursue the enemy quickly.", + "default_faction": "zombie", + "bodytype": "horse", + "categories": [ "CLASSIC" ], + "species": [ "ZOMBIE" ], + "volume": "85200 ml", + "weight": "125 kg", + "hp": 70, + "speed": 215, + "material": [ "flesh" ], + "symbol": "V", + "color": "black", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 3, + "melee_dice_sides": 6, + "melee_cut": 6, + "armor_bash": 5, + "armor_cut": 1, + "vision_day": 30, + "vision_night": 3, + "harvest": "zombie_leather", + "anger_triggers": [ "PLAYER_CLOSE", "PLAYER_WEAK" ], + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "SMELLS", "BASHES", "NO_BREATHE", "REVIVES", "BONES", "FAT" ] + }, { "id": "mon_ziger", "type": "MONSTER", @@ -394,6 +383,69 @@ "melee_dice": 3, "dodge": 0 }, + { + "id": "mon_zow", + "type": "MONSTER", + "name": { "str": "zombie cow" }, + "description": "Once a placid cow, this leathery horror stumbles and shudders, its pulsing black eyes scanning for prey beneath wicked horns. It is big and heavy and murderous.", + "looks_like": "mon_cow", + "default_faction": "zombie", + "bodytype": "dog", + "categories": [ "CLASSIC" ], + "species": [ "ZOMBIE" ], + "volume": "680 L", + "weight": "680 kg", + "hp": 166, + "speed": 104, + "material": [ "flesh" ], + "symbol": "Z", + "color": "green", + "aggression": 100, + "morale": 100, + "melee_skill": 6, + "melee_dice": 2, + "melee_dice_sides": 10, + "melee_cut": 6, + "armor_bash": 3, + "armor_cut": 3, + "vision_day": 30, + "vision_night": 3, + "anger_triggers": [ "PLAYER_CLOSE", "PLAYER_WEAK" ], + "death_drops": { "subtype": "collection", "groups": [ [ "cow", 25 ] ], "//": "25% chance of an item from group cow" }, + "death_function": [ "NORMAL" ], + "harvest": "zombie_leather", + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] + }, + { + "id": "mon_zeer", + "type": "MONSTER", + "name": { "str": "woodland wight" }, + "looks_like": "mon_deer", + "description": "Pale, stumbling white-tailed deer with blackened eyes and drooling slime down its neck. Its legs twist and bend in strange, haphazard directions, but with unnatural strength and speed. Preys on coyotes, wolves, and giant spider mutants.", + "default_faction": "zombie", + "bodytype": "horse", + "categories": [ "CLASSIC" ], + "species": [ "ZOMBIE" ], + "volume": "87 L", + "weight": "87 kg", + "hp": 100, + "speed": 240, + "material": [ "flesh" ], + "symbol": "Z", + "color": "green", + "aggression": 100, + "morale": 100, + "melee_skill": 3, + "melee_dice": 3, + "melee_dice_sides": 3, + "melee_cut": 0, + "armor_bash": 1, + "armor_cut": 3, + "vision_night": 15, + "death_function": [ "NORMAL" ], + "harvest": "zombie_leather", + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] + }, { "id": "mon_zpider_mass", "type": "MONSTER", diff --git a/data/json/monsters/zed-classic.json b/data/json/monsters/zed-classic.json index 8929931397370..6a01e0fd201c7 100644 --- a/data/json/monsters/zed-classic.json +++ b/data/json/monsters/zed-classic.json @@ -84,7 +84,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -133,7 +132,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -168,20 +166,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BASHES", - "GRABS", - "POISON", - "BLEED", - "NO_BREATHE", - "REVIVES", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "GRABS", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] }, { "id": "mon_zombie_dancer", @@ -257,7 +242,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -305,7 +289,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "ACIDPROOF", "NO_BREATHE", "REVIVES", @@ -352,7 +335,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "ACIDPROOF", "NO_BREATHE", "REVIVES", @@ -398,7 +380,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -447,7 +428,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -496,7 +476,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", diff --git a/data/json/monsters/zed_burned.json b/data/json/monsters/zed_burned.json index 4fc32bd66fa36..a5e022bafe5b7 100644 --- a/data/json/monsters/zed_burned.json +++ b/data/json/monsters/zed_burned.json @@ -79,7 +79,7 @@ "special_attacks": [ [ "SMASH", 30 ], [ "GRAB", 7 ] ], "death_function": [ "SMOKEBURST", "NORMAL" ], "upgrades": { "half_life": 21, "into_group": "GROUP_ZOMBIE_BRUTE" }, - "flags": [ "SEES", "HEARS", "STUMBLES", "POISON", "BLEED", "NO_BREATHE", "REVIVES", "REVIVES_HEALTHY", "NO_NECRO", "FILTHY" ] + "flags": [ "SEES", "HEARS", "STUMBLES", "POISON", "NO_BREATHE", "REVIVES", "REVIVES_HEALTHY", "NO_NECRO", "FILTHY" ] }, { "id": "mon_zombie_scorched", @@ -113,6 +113,6 @@ "special_attacks": [ [ "GRAB", 7 ] ], "death_function": [ "SMOKEBURST", "NORMAL" ], "upgrades": { "half_life": 14, "into_group": "GROUP_ZOMBIE_UPGRADE" }, - "flags": [ "SEES", "HEARS", "STUMBLES", "POISON", "BLEED", "NO_BREATHE", "REVIVES", "REVIVES_HEALTHY", "NO_NECRO", "FILTHY" ] + "flags": [ "SEES", "HEARS", "STUMBLES", "POISON", "NO_BREATHE", "REVIVES", "REVIVES_HEALTHY", "NO_NECRO", "FILTHY" ] } ] diff --git a/data/json/monsters/zed_children.json b/data/json/monsters/zed_children.json index 417479d652eca..0fa1c8af14176 100644 --- a/data/json/monsters/zed_children.json +++ b/data/json/monsters/zed_children.json @@ -28,7 +28,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "BLEED", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, { @@ -66,20 +66,7 @@ "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", "upgrades": { "half_life": 14, "into_group": "GROUP_CHILD_ZOMBIE_UPGRADE" }, - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BASHES", - "BLEED", - "POISON", - "GUILT", - "NO_BREATHE", - "REVIVES", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "GUILT", "NO_BREATHE", "REVIVES", "FILTHY" ] }, { "id": "mon_zombie_creepy", @@ -110,20 +97,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BLEED", - "BASHES", - "POISON", - "NO_BREATHE", - "REVIVES", - "CLIMBS", - "FILTHY" - ], + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "CLIMBS", "FILTHY" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, { @@ -156,20 +130,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BLEED", - "GUILT", - "BASHES", - "POISON", - "NO_BREATHE", - "REVIVES", - "FILTHY" - ], + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "GUILT", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "GUILT because it still looks enough like a child to evoke pity" }, { @@ -202,7 +163,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "BOOMER" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ "SEES", "HEARS", "STUMBLES", "WARM", "BLEED", "GUILT", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], + "flags": [ "SEES", "HEARS", "STUMBLES", "WARM", "GUILT", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "GUILT because it still looks enough like a child to evoke pity" }, { @@ -234,20 +195,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BLEED", - "BASHES", - "POISON", - "NO_BREATHE", - "REVIVES", - "CLIMBS", - "FILTHY" - ], + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "CLIMBS", "FILTHY" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, { @@ -282,20 +230,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BLEED", - "GUILT", - "POISON", - "NO_BREATHE", - "REVIVES", - "HARDTOSHOOT", - "FILTHY" - ], + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "GUILT", "POISON", "NO_BREATHE", "REVIVES", "HARDTOSHOOT", "FILTHY" ], "//": "GUILT because it still looks enough like a child to evoke pity" } ] diff --git a/data/json/monsters/zed_fusion.json b/data/json/monsters/zed_fusion.json index 57bcf155d19ae..3017c635850da 100644 --- a/data/json/monsters/zed_fusion.json +++ b/data/json/monsters/zed_fusion.json @@ -211,6 +211,92 @@ "death_function": [ "GAS" ], "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "POISON", "CLIMBS", "NO_BREATHE", "CLIMBS", "HARDTOSHOOT" ] }, + { + "id": "mon_zombie_scissorlimbs", + "type": "MONSTER", + "name": { "str": "scissorlimbs" }, + "description": " A nightmarish spider of gore stands tall among the ruins, and keeps silent watch of the blighted landscape. Its spindly limbs of bone slip between the rubble with otherworldly speed.", + "default_faction": "zombie", + "bodytype": "spider", + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 5, + "volume": "122500 ml", + "weight": "81500 g", + "hp": 10, + "speed": 250, + "material": [ "flesh" ], + "symbol": "M", + "color": "red_yellow", + "aggression": 100, + "morale": 100, + "melee_skill": 5, + "melee_dice": 5, + "melee_dice_sides": 2, + "melee_cut": 12, + "armor_bash": 2, + "armor_cut": 10, + "armor_bullet": 10, + "vision_day": 1, + "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 3, "allow_no_target": true }, [ "scratch", 5 ] ], + "death_function": [ "GAS" ], + "flags": [ "SEES", "HEARS", "GOODHEARING", "WARM", "POISON", "CLIMBS", "NO_BREATHE", "CLIMBS", "HARDTOSHOOT" ] + }, + { + "id": "mon_zombie_hanging_innards", + "type": "MONSTER", + "name": { "str": "hanging innards" }, + "description": "Great snakes of flesh hang from the ceiling above, madly thrashing and reaching about.", + "default_faction": "zombie", + "bodytype": "spider", + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 5, + "volume": "122500 ml", + "weight": "81500 g", + "hp": 200, + "speed": 110, + "material": [ "flesh" ], + "symbol": "S", + "color": "magenta_red", + "aggression": 100, + "morale": 100, + "melee_skill": 5, + "melee_dice": 5, + "melee_dice_sides": 2, + "armor_bash": 6, + "armor_cut": 10, + "armor_bullet": 6, + "vision_day": 2, + "vision_night": 2, + "harvest": "exempt", + "special_attacks": [ [ "RANGED_PULL", 20 ], [ "SMASH", 20 ] ], + "death_function": [ "GAS" ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "POISON", "CLIMBS", "NO_BREATHE", "IMMOBILE" ] + }, + { + "id": "mon_zombie_giant_heart", + "type": "MONSTER", + "name": { "str": "spasming lump" }, + "description": "A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic and desperate manner.", + "default_faction": "zombie", + "volume": "875000 ml", + "weight": "200 kg", + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 1, + "hp": 3, + "speed": 100, + "material": [ "flesh" ], + "symbol": "O", + "color": "red_yellow", + "morale": 10, + "vision_day": 60, + "vision_night": 60, + "armor_bash": 50, + "armor_cut": 25, + "armor_bullet": 20, + "harvest": "exempt", + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "SMELLS", "IMMOBILE", "WARM", "POISON", "IMMOBILE", "NO_BREATHE", "FILTHY" ] + }, { "id": "mon_zombie_living_wall", "type": "MONSTER", diff --git a/data/json/monsters/zed_lab.json b/data/json/monsters/zed_lab.json index df7ebd490479c..1f2870184ddcb 100644 --- a/data/json/monsters/zed_lab.json +++ b/data/json/monsters/zed_lab.json @@ -40,7 +40,6 @@ "WARM", "BASHES", "POISON", - "BLEED", "ACIDPROOF", "NO_BREATHE", "REVIVES", @@ -94,7 +93,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", diff --git a/data/json/monsters/zed_misc.json b/data/json/monsters/zed_misc.json index 1b2d09f287f2b..80a6225190837 100644 --- a/data/json/monsters/zed_misc.json +++ b/data/json/monsters/zed_misc.json @@ -52,7 +52,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "GRABS", "NO_BREATHE", "REVIVES", @@ -99,7 +98,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NOHEAD", "NO_BREATHE", "REVIVES", @@ -294,7 +292,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NOHEAD", "NO_BREATHE", "REVIVES", @@ -341,7 +338,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "GRABS", "NO_BREATHE", "REVIVES", @@ -387,7 +383,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -478,7 +473,7 @@ { "id": "mon_zombie_hunter", "type": "MONSTER", - "name": { "str": "feral hunter" }, + "name": { "str": "zombie hunter" }, "description": "This once-human body is barely recognizable, scrambling about on all fours, its nails and teeth both sharpened into dangerous looking spikes.", "default_faction": "zombie", "bodytype": "human", @@ -545,7 +540,7 @@ "special_attacks": [ [ "JACKSON", 0 ] ], "death_drops": "jackson_drops", "death_function": [ "JACKSON" ], - "flags": [ "SEES", "SMELLS", "WARM", "BASHES", "BLEED", "NO_BREATHE", "POISON", "FILTHY" ] + "flags": [ "SEES", "SMELLS", "WARM", "BASHES", "NO_BREATHE", "POISON", "FILTHY" ] }, { "id": "mon_zombie_mancroc", @@ -600,7 +595,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "GRABS", "NO_BREATHE", "REVIVES", @@ -719,7 +713,7 @@ { "id": "mon_zombie_runner", "type": "MONSTER", - "name": { "str": "feral runner" }, + "name": { "str": "zombie runner" }, "description": "This recently-risen body moves quickly, darting its head back and forth and gnawing at its hands.", "default_faction": "zombie", "bodytype": "human", @@ -758,7 +752,7 @@ { "id": "mon_zombie_predator", "type": "MONSTER", - "name": { "str": "feral predator" }, + "name": { "str": "zombie predator" }, "description": "With its joints in odd places and angles, this humanoid creature prowls across the landscape with surprising speed. Its teeth and arms are sharpened into fine points, and black ooze seeps out from cuts between its muscles.", "default_faction": "zombie", "bodytype": "human", @@ -867,7 +861,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -905,18 +898,7 @@ "fear_triggers": [ "FIRE" ], "death_drops": { "groups": [ [ "shia_stuff", 1 ] ] }, "death_function": [ "NORMAL" ], - "flags": [ - "SEES", - "HEARS", - "WARM", - "BASHES", - "POISON", - "BLEED", - "NO_BREATHE", - "PATH_AVOID_DANGER_2", - "PRIORITIZE_TARGETS", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "WARM", "BASHES", "POISON", "NO_BREATHE", "PATH_AVOID_DANGER_2", "PRIORITIZE_TARGETS", "FILTHY" ] }, { "id": "mon_zombie_shrieker", @@ -1005,7 +987,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NOHEAD", "NO_BREATHE", "REVIVES", @@ -1096,7 +1077,6 @@ "GROUP_BASH", "POISON", "NO_BREATHE", - "BLEED", "SWIMS", "REVIVES", "PUSH_MON", @@ -1176,7 +1156,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", diff --git a/data/json/monsters/zed_skeletal.json b/data/json/monsters/zed_skeletal.json index 1697ea2ef040f..77a8ee3ac6e01 100644 --- a/data/json/monsters/zed_skeletal.json +++ b/data/json/monsters/zed_skeletal.json @@ -32,7 +32,7 @@ "upgrades": { "half_life": 15, "into": "mon_skeleton_brute" }, "death_drops": "default_zombie_clothes", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "BLEED", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] + "flags": [ "SEES", "HEARS", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] }, { "//": "Skelly brute gaps the evolution between normal and the juggernaut.", @@ -71,7 +71,7 @@ "upgrades": { "half_life": 12, "into": "mon_skeleton_hulk" }, "death_drops": "default_zombie_clothes", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "BLEED", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] + "flags": [ "SEES", "HEARS", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] }, { "id": "mon_skeleton_electric", @@ -107,7 +107,7 @@ "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 }, [ "SHOCKSTORM", 25 ] ], "death_drops": "default_zombie_clothes", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "BLEED", "ELECTRIC", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] + "flags": [ "SEES", "HEARS", "ELECTRIC", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] }, { "id": "mon_skeleton_hulk", @@ -153,7 +153,6 @@ "WARM", "BASHES", "DESTROYS", - "BLEED", "POISON", "ATTACKMON", "NO_BREATHE", diff --git a/data/json/monsters/zed_soldiers.json b/data/json/monsters/zed_soldiers.json index 7fb87a0d44c9a..494d95ec2a56f 100644 --- a/data/json/monsters/zed_soldiers.json +++ b/data/json/monsters/zed_soldiers.json @@ -33,20 +33,7 @@ "death_function": [ "NORMAL" ], "upgrades": { "half_life": 28, "into_group": "GROUP_SOLDIER_UPGRADE" }, "burn_into": "mon_zombie_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "WARM", - "BASHES", - "GROUP_BASH", - "POISON", - "BLEED", - "NO_BREATHE", - "REVIVES", - "PUSH_MON", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { "id": "mon_zombie_soldier_blackops_1", @@ -88,20 +75,7 @@ "death_function": [ "NORMAL" ], "upgrades": { "half_life": 38, "into": "mon_zombie_soldier_blackops_2" }, "burn_into": "mon_zombie_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "WARM", - "BASHES", - "GROUP_BASH", - "POISON", - "BLEED", - "NO_BREATHE", - "REVIVES", - "PUSH_MON", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { "id": "mon_zombie_soldier_blackops_2", @@ -133,7 +107,6 @@ "looks_like": "mon_zombie_soldier", "diff": 20, "relative": { "hp": 20, "speed": 10, "melee_skill": 1, "vision_day": 10, "vision_night": 10 }, - "delete": { "flags": [ "BLEED" ] }, "extend": { "special_attacks": [ [ "ACID_BARF", 10 ], @@ -163,7 +136,6 @@ "looks_like": "mon_zombie_soldier", "diff": 20, "relative": { "hp": 40, "speed": -10, "melee_skill": 2, "armor_bash": 5 }, - "delete": { "flags": [ "BLEED" ] }, "extend": { "special_attacks": [ [ "ACID_BARF", 5 ], @@ -222,20 +194,7 @@ "death_function": [ "NORMAL" ], "upgrades": { "half_life": 42, "into": "mon_zombie_kevlar_2" }, "burn_into": "mon_zombie_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "WARM", - "BASHES", - "GROUP_BASH", - "POISON", - "BLEED", - "NO_BREATHE", - "REVIVES", - "PUSH_MON", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { "id": "mon_zombie_kevlar_2", @@ -274,20 +233,7 @@ "death_drops": "mon_zombie_kevlar_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "WARM", - "BASHES", - "GROUP_BASH", - "POISON", - "BLEED", - "NO_BREATHE", - "REVIVES", - "PUSH_MON", - "FILTHY" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { "id": "mon_zombie_military_pilot", @@ -330,7 +276,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -382,7 +327,6 @@ "POISON", "NO_BREATHE", "REVIVES", - "BLEED", "PUSH_MON", "DRIPS_NAPALM", "FILTHY" @@ -421,7 +365,7 @@ "death_drops": "mon_zombie_armored_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "BLEED", "NO_BREATHE", "REVIVES", "FILTHY" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] }, { "id": "mon_zombie_bio_op", @@ -466,7 +410,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "ACIDPROOF", "ELECTRIC", "NO_BREATHE", diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index ba20dc4af3b40..f0c243de08e19 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -701,7 +701,8 @@ "type": "mutation", "id": "CANNIBAL", "name": { "str": "Cannibal" }, - "points": 1, + "points": 3, + "//": "Feral humans vastly increase the cannibal meat supply, therefore this trait needs to increase in cost.", "description": "For your whole life you've been forbidden from indulging in your peculiar tastes. Now the world's ended, and you'll be damned if anyone is going to tell you that you can't eat people.", "starting_trait": true, "valid": false, @@ -6374,17 +6375,6 @@ "purifiable": false, "profession": true }, - { - "type": "mutation", - "id": "PROF_HELI_PILOT", - "name": "Helicopter Pilot", - "points": 0, - "description": "You are a trained helicopter pilot. This makes you one of the few living people who can operate a helicopter after the Cataclysm.", - "valid": false, - "purifiable": false, - "profession": true, - "cancels": [ "WAYFARER" ] - }, { "type": "mutation", "id": "PROF_SWAT", @@ -6838,8 +6828,7 @@ "points": -8, "description": "Whether from personal choice or childhood trauma, traveling with vehicles is off-limits to you, even if your life depended on it.", "starting_trait": true, - "valid": false, - "cancels": [ "PROF_HELI_PILOT" ] + "valid": false }, { "type": "mutation", diff --git a/data/json/npcs/NC_DOCTOR.json b/data/json/npcs/NC_DOCTOR.json index 1ddddeb50d826..1125717aa3620 100644 --- a/data/json/npcs/NC_DOCTOR.json +++ b/data/json/npcs/NC_DOCTOR.json @@ -81,7 +81,8 @@ "id": "NC_DOCTOR_misc", "subtype": "distribution", "entries": [ - { "item": "bandages", "prob": 50 }, + { "item": "bandages", "prob": 30 }, + { "item": "adhesive_bandages", "prob": 30 }, { "item": "cotton_ball", "prob": 50 }, { "item": "1st_aid", "prob": 35 }, { "item": "saline", "prob": 25 }, diff --git a/data/json/npcs/NC_SOLDIER.json b/data/json/npcs/NC_SOLDIER.json index 4abb8d3099882..2f50c50526697 100644 --- a/data/json/npcs/NC_SOLDIER.json +++ b/data/json/npcs/NC_SOLDIER.json @@ -168,7 +168,7 @@ { "item": "mre_chickenpesto_box", "prob": 45 }, { "item": "mre_southwestbeef_box", "prob": 45 }, { "item": "mre_hotdog_box", "prob": 45 }, - { "item": "1st_aid", "prob": 35 }, + { "item": "ifak", "prob": 35 }, { "item": "saline", "prob": 10 }, { "item": "con_milk", "prob": 10 }, { "item": "sports_drink", "prob": 40 }, diff --git a/data/json/npcs/TALK_TEST.json b/data/json/npcs/TALK_TEST.json index 93cdab41ac3b3..6c23dd217571c 100644 --- a/data/json/npcs/TALK_TEST.json +++ b/data/json/npcs/TALK_TEST.json @@ -605,6 +605,31 @@ } ] }, + { + "type": "talk_topic", + "id": "TALK_TEST_VARS_TIME", + "dynamic_line": "This is a test conversation that shouldn't appear in the game.", + "responses": [ + { "text": "This is a basic test response.", "topic": "TALK_DONE" }, + { + "text": "This is a u_add_var time test response.", + "topic": "TALK_DONE", + "effect": { "u_add_var": "test", "type": "test", "context": "var_time_test", "time": true }, + "condition": { "not": { "u_has_var": "test", "type": "test", "context": "var_time_test", "time": true } } + }, + { + "text": "This is a npc_add_var time test response.", + "topic": "TALK_DONE", + "effect": { "npc_add_var": "test", "type": "test", "context": "var_time_test", "time": true }, + "condition": { "not": { "u_has_var": "test", "type": "test", "context": "var_time_test", "time": true } } + }, + { + "text": "This is a u_compare_var time test response for > 3_days.", + "topic": "TALK_DONE", + "condition": { "u_compare_time_since_var": "test", "type": "test", "context": "var_time_test", "op": ">", "time": "3 days" } + } + ] + }, { "type": "talk_topic", "id": "TALK_TEST_ADJUST_VARS", diff --git a/data/json/npcs/factions.json b/data/json/npcs/factions.json index ab58aa84435c4..a02e7fa68c8f8 100644 --- a/data/json/npcs/factions.json +++ b/data/json/npcs/factions.json @@ -54,6 +54,7 @@ "type": "faction", "id": "robofac", "name": "Hub 01", + "mon_faction": "robofac", "likes_u": -200, "respects_u": 0, "known_by_u": false, diff --git a/data/json/npcs/items_generic.json b/data/json/npcs/items_generic.json index ce2dfede61614..674dfc10f1654 100644 --- a/data/json/npcs/items_generic.json +++ b/data/json/npcs/items_generic.json @@ -364,7 +364,8 @@ [ "backpack", 5 ], [ "bacon", 2 ], [ "banana", 1 ], - [ "bandages", 25 ], + [ "bandages", 20 ], + [ "adhesive_bandages", 20 ], [ "barrel_ported", 1 ], [ "baseball", 1 ], [ "bat", 5 ], diff --git a/data/json/npcs/tacoma_ranch/NPC_ranch_nurse.json b/data/json/npcs/tacoma_ranch/NPC_ranch_nurse.json index b20c25c6d1cf6..22683ad1b3de2 100644 --- a/data/json/npcs/tacoma_ranch/NPC_ranch_nurse.json +++ b/data/json/npcs/tacoma_ranch/NPC_ranch_nurse.json @@ -36,9 +36,11 @@ "repeat_responses": { "for_item": [ "1st_aid", + "ifak", "antibiotics", "aspirin", "bandages", + "adhesive_bandages", "bfipowder", "chem_hydrogen_peroxide", "codeine", diff --git a/data/json/npcs/tacoma_ranch/NPC_ranch_scavenger.json b/data/json/npcs/tacoma_ranch/NPC_ranch_scavenger.json index d55784f1dbd87..d3ea627c516e5 100644 --- a/data/json/npcs/tacoma_ranch/NPC_ranch_scavenger.json +++ b/data/json/npcs/tacoma_ranch/NPC_ranch_scavenger.json @@ -49,7 +49,7 @@ "goal": "MGOAL_FIND_ITEM", "difficulty": 5, "value": 50000, - "item": "spear_knife", + "item": "spear_knife_superior", "count": 12, "origins": [ "ORIGIN_SECONDARY" ], "followup": "MISSION_RANCH_SCAVENGER_2", diff --git a/data/json/npcs/tacoma_ranch/mission_mapgen_tacoma_commune.json b/data/json/npcs/tacoma_ranch/mission_mapgen_tacoma_commune.json index ebe45aa9e9f71..abc144cef0d05 100644 --- a/data/json/npcs/tacoma_ranch/mission_mapgen_tacoma_commune.json +++ b/data/json/npcs/tacoma_ranch/mission_mapgen_tacoma_commune.json @@ -815,15 +815,8 @@ "W.......rW ", "WWW....WWW " ], - "terrain": { - "r": "t_dirtfloor", - "W": "t_wall_log", - ".": "t_dirtfloor", - "c": "t_conveyor", - "m": "t_machinery_old", - "M": "t_machinery_heavy" - }, - "furniture": { "r": "f_rack" }, + "terrain": { "r": "t_dirtfloor", "W": "t_wall_log", ".": "t_dirtfloor", "m": "t_dirtfloor", "M": "t_dirtfloor", "c": "t_conveyor" }, + "furniture": { "m": "f_machinery_old", "M": "f_machinery_heavy", "r": "f_rack" }, "place_item": [ { "item": "log", "x": 3, "y": 0 }, { "item": "log", "x": 3, "y": 1 }, diff --git a/data/json/obsolete.json b/data/json/obsolete.json index 41c9ecc8981cb..411006155d94f 100644 --- a/data/json/obsolete.json +++ b/data/json/obsolete.json @@ -24,7 +24,7 @@ "blackpowder_tolerance": 60, "clip_size": 1, "loudness": 25, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "built_in_mods": [ "combination_gun_shotgun_pipe" ], "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ], "valid_mod_locations": [ @@ -83,7 +83,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "1000 ml", + "barrel_volume": "1000 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], @@ -121,7 +121,7 @@ "durability": 6, "blackpowder_tolerance": 60, "reload": 200, - "barrel_length": "500 ml", + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "accessories", 4 ], [ "barrel", 1 ], @@ -231,7 +231,7 @@ "loudness": 25, "clip_size": 1, "reload": 200, - "barrel_length": "1000 ml", + "barrel_volume": "1000 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], @@ -1231,5 +1231,429 @@ "install": { "skills": [ [ "mechanics", 5 ], [ "electronics", 5 ] ] }, "removal": { "skills": [ [ "mechanics", 3 ] ] } } + }, + { + "type": "terrain", + "id": "t_gas_tank", + "name": "fuel tank", + "description": "A tank filled with gasoline.", + "looks_like": "f_gas_tank", + "symbol": "Q", + "color": "brown_red", + "move_cost": 0, + "coverage": 50 + }, + { + "type": "terrain", + "id": "t_gas_tank_smashed", + "name": "broken fuel tank", + "description": "A broken tank which was filled with gasoline.", + "looks_like": "f_gas_tank_smashed", + "symbol": "Q", + "color": "light_red", + "move_cost": 0, + "coverage": 50 + }, + { + "type": "terrain", + "id": "t_diesel_tank", + "name": "fuel tank", + "description": "A tank filled with diesel.", + "looks_like": "f_diesel_tank", + "symbol": "Q", + "color": "brown_red", + "move_cost": 0, + "coverage": 50 + }, + { + "type": "terrain", + "id": "t_diesel_tank_smashed", + "name": "broken diesel tank", + "description": "A broken tank which was filled with diesel.", + "looks_like": "f_diesel_tank_smashed", + "symbol": "Q", + "color": "light_red", + "move_cost": 0, + "coverage": 50 + }, + { + "type": "terrain", + "id": "t_centrifuge", + "name": "centrifuge", + "description": "This is a centrifuge, a liquid separating device with an automated analyzer unit. It could be used to analyze a medical fluid sample, such as blood, if a test tube was placed in it.", + "symbol": "{", + "color": "magenta", + "move_cost": 0, + "coverage": 30, + "flags": [ "TRANSPARENT", "PERMEABLE" ], + "bash": { + "str_min": 3, + "str_max": 45, + "sound": "crunch!", + "sound_fail": "whack!", + "ter_set": "t_rock_floor", + "items": [ + { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, + { "item": "circuit", "count": [ 1, 6 ], "prob": 50 }, + { "item": "scrap", "count": [ 2, 5 ] }, + { "item": "steel_chunk", "count": [ 0, 3 ] }, + { "item": "sheet_metal", "count": [ 1, 3 ] }, + { "item": "cable", "charges": [ 1, 15 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_plut_generator", + "name": "plutonium generator", + "description": "This imposing apparatus harnesses the power of the atom. Refined nuclear fuel is 'burned' to provide nearly limitless electrical power. It's not doing much good here though. Perhaps it could be salvaged for other purposes.", + "symbol": "0", + "color": "light_green", + "looks_like": "f_machinery_electronic", + "move_cost": 0, + "flags": [ "TRANSPARENT", "NOITEM", "SEALED", "REDUCE_SCENT", "PERMEABLE" ], + "bash": { + "str_min": 50, + "str_max": 400, + "explosive": 25, + "ter_set": "t_concrete", + "sound": "metal screeching!", + "sound_fail": "clang!", + "items": [ + { "item": "scrap", "count": [ 4, 16 ] }, + { "item": "steel_chunk", "count": [ 1, 6 ] }, + { "item": "plutonium", "charges": [ 0, 3 ] }, + { "item": "lead", "charges": [ 12, 18 ] } + ] + }, + "deconstruct": { + "ter_set": "t_concrete", + "items": [ + { "item": "RAM", "count": [ 4, 8 ] }, + { "item": "cable", "charges": [ 8, 16 ] }, + { "item": "small_lcd_screen", "count": [ 2, 4 ] }, + { "item": "large_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 12, 24 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 4, 8 ] }, + { "item": "amplifier", "count": [ 3, 6 ] }, + { "item": "plutonium", "charges": [ 2, 8 ] }, + { "item": "scrap", "count": [ 8, 16 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_machinery_light", + "name": "light machinery", + "description": "Assorted light machinery. You could scavenge it for parts.", + "symbol": "$", + "color": "dark_gray", + "move_cost": 10, + "coverage": 65, + "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "FLAMMABLE", "PLACE_ITEM" ], + "deconstruct": { + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": [ 1, 3 ] }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 40 }, + { "item": "cu_pipe", "prob": 40 }, + { "item": "scrap", "count": [ 1, 4 ] }, + { "item": "hose", "count": 1 }, + { "item": "steel_chunk", "count": [ 1, 5 ] }, + { "item": "bearing", "charges": [ 4, 12 ] }, + { "item": "frame", "prob": 50 }, + { "item": "motor", "prob": 50 } + ] + }, + "bash": { + "str_min": 16, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": 2, "prob": 40 }, + { "item": "chain", "prob": 20 }, + { "item": "cu_pipe", "prob": 10 }, + { "item": "scrap", "count": [ 3, 8 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "bearing", "charges": [ 2, 8 ] }, + { "item": "frame", "prob": 20 }, + { "item": "motor", "prob": 10 } + ] + } + }, + { + "type": "terrain", + "id": "t_machinery_heavy", + "name": "heavy machinery", + "description": "Assorted heavy machinery. You could scavenge it for parts.", + "symbol": "%", + "color": "light_gray", + "move_cost": 0, + "coverage": 75, + "flags": [ "BASHABLE", "CONTAINER", "SEALED", "PLACE_ITEM" ], + "deconstruct": { + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": [ 1, 3 ] }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 60 }, + { "item": "cu_pipe", "prob": 20 }, + { "item": "steel_lump", "count": [ 1, 2 ] }, + { "item": "hose", "count": 1 }, + { "item": "sheet_metal", "count": [ 1, 3 ] }, + { "item": "steel_chunk", "count": [ 1, 3 ] }, + { "item": "bearing", "charges": [ 4, 12 ] }, + { "item": "frame", "prob": 60 }, + { "item": "motor", "prob": 30 }, + { "item": "metal_tank", "prob": 30 }, + { "item": "motor_large", "prob": 10 } + ] + }, + "bash": { + "str_min": 18, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": 1 }, + { "item": "chain", "prob": 20 }, + { "item": "steel_lump", "count": 1 }, + { "item": "scrap", "count": [ 1, 5 ] }, + { "item": "sheet_metal", "count": 2 }, + { "item": "steel_chunk", "count": [ 1, 2 ] }, + { "item": "bearing", "charges": [ 2, 8 ] }, + { "item": "frame", "prob": 30 }, + { "item": "motor", "prob": 10 }, + { "item": "metal_tank", "prob": 20 }, + { "item": "motor_large", "prob": 5 } + ] + } + }, + { + "type": "terrain", + "id": "t_machinery_old", + "name": "old machinery", + "description": "Assorted old machinery. You could scavenge it for parts.", + "symbol": "&", + "color": "brown", + "move_cost": 4, + "coverage": 55, + "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "FLAMMABLE", "PLACE_ITEM" ], + "deconstruct": { + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 40 }, + { "item": "cu_pipe", "prob": 60 }, + { "item": "scrap", "count": [ 1, 3 ] }, + { "item": "hose", "count": 1 }, + { "item": "steel_chunk", "count": [ 1, 3 ] }, + { "item": "bearing", "charges": [ 1, 5 ] }, + { "item": "frame", "prob": 30 }, + { "item": "motor", "prob": 30 }, + { "item": "splinter", "count": 3, "prob": 30 }, + { "item": "2x4", "count": [ 1, 4 ] }, + { "item": "nail", "charges": [ 3, 10 ] } + ] + }, + "bash": { + "str_min": 10, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": 1 }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "chain", "prob": 20 }, + { "item": "cu_pipe", "prob": 10 }, + { "item": "scrap", "count": [ 1, 5 ] }, + { "item": "steel_chunk", "count": [ 1, 2 ] }, + { "item": "motor", "prob": 10 }, + { "item": "splinter", "count": [ 4, 8 ] }, + { "item": "2x4", "count": 2 }, + { "item": "nail", "charges": [ 2, 5 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_machinery_electronic", + "name": "electronic machinery", + "description": "Assorted electronic machinery. You could scavenge it for parts.", + "symbol": "$", + "color": "yellow", + "move_cost": 8, + "coverage": 55, + "flags": [ "TRANSPARENT", "BASHABLE", "CONTAINER", "SEALED", "FLAMMABLE", "PLACE_ITEM" ], + "deconstruct": { + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "count": [ 1, 3 ] }, + { "item": "pipe", "count": [ 1, 2 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "bearing", "charges": [ 2, 6 ] }, + { "item": "motor", "prob": 40 }, + { "item": "processor", "count": 1 }, + { "item": "RAM", "count": [ 1, 4 ] }, + { "item": "cable", "charges": [ 1, 4 ] }, + { "item": "small_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 5, 10 ] }, + { "item": "circuit", "count": [ 3, 8 ] }, + { "item": "power_supply", "count": [ 1, 3 ] }, + { "item": "amplifier", "count": [ 1, 3 ] }, + { "item": "plastic_chunk", "count": [ 2, 8 ] }, + { "item": "scrap", "count": [ 1, 5 ] } + ] + }, + "bash": { + "str_min": 10, + "str_max": 80, + "sound": "clang!", + "sound_fail": "ting.", + "ter_set": "t_rock_floor", + "items": [ + { "item": "wire", "prob": 40 }, + { "item": "pipe", "prob": 40 }, + { "item": "steel_chunk", "prob": 40 }, + { "item": "bearing", "charges": [ 2, 4 ] }, + { "item": "motor", "prob": 10 }, + { "item": "processor", "prob": 40 }, + { "item": "RAM", "count": [ 1, 2 ] }, + { "item": "cable", "charges": [ 1, 2 ] }, + { "item": "small_lcd_screen", "prob": 40 }, + { "item": "e_scrap", "count": [ 3, 8 ] }, + { "item": "circuit", "count": [ 1, 3 ] }, + { "item": "power_supply", "prob": 40 }, + { "item": "amplifier", "prob": 40 }, + { "item": "plastic_chunk", "count": [ 2, 8 ] }, + { "item": "scrap", "count": [ 3, 8 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_console_broken", + "name": "broken console", + "description": "This is a standalone computer terminal. It doesn't seem to be working. It's the broken screen and shattered circuit boards that's telling you that.", + "symbol": "6", + "color": "light_gray", + "move_cost": 0, + "coverage": 50, + "roof": "t_flat_roof", + "flags": [ "TRANSPARENT", "NOITEM", "INDOORS", "SHORT", "PERMEABLE" ], + "deconstruct": { + "ter_set": "t_floor", + "items": [ + { "item": "processor", "count": [ 1, 2 ] }, + { "item": "RAM", "count": [ 4, 8 ] }, + { "item": "cable", "charges": [ 4, 6 ] }, + { "item": "large_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 10, 16 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 2, 4 ] }, + { "item": "amplifier", "count": [ 2, 4 ] }, + { "item": "plastic_chunk", "count": [ 10, 12 ] }, + { "item": "scrap", "count": [ 6, 8 ] } + ] + }, + "bash": { + "str_min": 16, + "str_max": 150, + "sound": "crunch!", + "sound_fail": "whack!", + "ter_set": "t_floor", + "items": [ + { "item": "processor", "prob": 25 }, + { "item": "RAM", "count": [ 0, 2 ], "prob": 50 }, + { "item": "cable", "charges": [ 1, 2 ], "prob": 50 }, + { "item": "large_lcd_screen", "prob": 25 }, + { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, + { "item": "circuit", "count": [ 0, 2 ], "prob": 50 }, + { "item": "power_supply", "prob": 25 }, + { "item": "amplifier", "prob": 25 }, + { "item": "plastic_chunk", "count": [ 4, 10 ], "prob": 50 }, + { "item": "scrap", "count": [ 2, 6 ], "prob": 50 } + ] + } + }, + { + "type": "terrain", + "id": "t_console", + "name": "computer console", + "description": "This is a standalone computer terminal. It can be used to view contents and perform any allowed functions. It might even be possible to hack it, given the skills.", + "symbol": "6", + "color": "blue", + "move_cost": 0, + "coverage": 50, + "light_emitted": 10, + "roof": "t_flat_roof", + "flags": [ "TRANSPARENT", "CONSOLE", "NOITEM", "INDOORS", "SHORT", "PERMEABLE" ], + "deconstruct": { + "ter_set": "t_floor", + "items": [ + { "item": "processor", "count": [ 1, 2 ] }, + { "item": "RAM", "count": [ 4, 8 ] }, + { "item": "cable", "charges": [ 4, 6 ] }, + { "item": "large_lcd_screen", "count": 1 }, + { "item": "e_scrap", "count": [ 10, 16 ] }, + { "item": "circuit", "count": [ 6, 10 ] }, + { "item": "power_supply", "count": [ 2, 4 ] }, + { "item": "amplifier", "count": [ 2, 4 ] }, + { "item": "plastic_chunk", "count": [ 10, 12 ] }, + { "item": "scrap", "count": [ 6, 8 ] } + ] + }, + "bash": { + "str_min": 8, + "str_max": 150, + "sound": "crunch!", + "sound_fail": "whack!", + "ter_set": "t_console_broken", + "items": [ + { "item": "processor", "prob": 25 }, + { "item": "RAM", "count": [ 0, 2 ], "prob": 50 }, + { "item": "cable", "charges": [ 1, 2 ], "prob": 50 }, + { "item": "large_lcd_screen", "prob": 25 }, + { "item": "e_scrap", "count": [ 1, 4 ], "prob": 50 }, + { "item": "circuit", "count": [ 0, 2 ], "prob": 50 }, + { "item": "power_supply", "prob": 25 }, + { "item": "amplifier", "prob": 25 }, + { "item": "plastic_chunk", "count": [ 4, 10 ], "prob": 50 }, + { "item": "scrap", "count": [ 2, 6 ], "prob": 50 } + ] + } + }, + { + "type": "terrain", + "id": "t_generator_broken", + "name": "broken generator", + "description": "This generator is broken and will not help you produce usable electricity.", + "symbol": "&", + "color": "light_gray", + "looks_like": "f_machinery_old", + "move_cost": 0, + "coverage": 30, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT", "MOUNTABLE", "PERMEABLE" ], + "bash": { + "str_min": 20, + "str_max": 150, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_pavement", + "items": [ + { "item": "steel_lump", "prob": 50 }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "scrap", "count": [ 3, 7 ] } + ] + } } ] diff --git a/data/json/obsolete_terrains.json b/data/json/obsolete_terrains.json index 27f16350b7ec6..e87ea95d62cce 100644 --- a/data/json/obsolete_terrains.json +++ b/data/json/obsolete_terrains.json @@ -2,315 +2,23 @@ { "type": "obsolete_terrain", "terrains": [ - "apartments_con_tower_1", - "apartments_con_tower_1_entrance", - "apartments_mod_tower_1", - "apartments_mod_tower_1_entrance", - "bridge_ew", - "bridge_ns", - "public_works", - "public_works_entrance", - "hdwr_large_entrance", - "hdwr_large_SW", - "hdwr_large_NW", - "hdwr_large_NE", - "hdwr_large_backroom", - "hdwr_large_loadingbay", - "cemetery_4square_00", - "cemetery_4square_10", - "cemetery_4square_01", - "cemetery_4square_11", - "loffice_tower_1", - "loffice_tower_2", - "loffice_tower_3", - "loffice_tower_4", - "loffice_tower_5", - "loffice_tower_6", - "loffice_tower_7", - "loffice_tower_8", - "loffice_tower_9", - "loffice_tower_10", - "loffice_tower_11", - "loffice_tower_12", - "loffice_tower_13", - "loffice_tower_14", - "loffice_tower_15", - "loffice_tower_16", - "school_1", - "school_2", - "school_3", - "school_4", - "school_5", - "school_6", - "school_7", - "school_8", - "school_9", - "prison_1", - "prison_2", - "prison_3", - "prison_4", - "prison_5", - "prison_6", - "prison_7", - "prison_8", - "prison_9", - "prison_b_entrance", - "prison_b", - "hospital_entrance", - "hospital", - "cathedral_1_entrance", - "cathedral_1", - "cathedral_b_entrance", - "cathedral_b", - "hotel_tower_1_1", - "hotel_tower_1_2", - "hotel_tower_1_3", - "hotel_tower_1_4", - "hotel_tower_1_5", - "hotel_tower_1_6", - "hotel_tower_1_7", - "hotel_tower_1_8", - "hotel_tower_1_9", - "hotel_tower_b_1", - "hotel_tower_b_2", - "hotel_tower_b_3", - "bunker", - "farm", - "farm_field", - "subway_station", - "mansion", - "mansion_entrance", - "ranch_camp_1", - "ranch_camp_2", - "ranch_camp_3", - "ranch_camp_4", - "ranch_camp_5", - "ranch_camp_6", - "ranch_camp_7", - "ranch_camp_8", - "ranch_camp_9", - "ranch_camp_10", - "ranch_camp_11", - "ranch_camp_12", - "ranch_camp_13", - "ranch_camp_14", - "ranch_camp_15", - "ranch_camp_16", - "ranch_camp_17", - "ranch_camp_18", - "ranch_camp_19", - "ranch_camp_20", - "ranch_camp_21", - "ranch_camp_22", - "ranch_camp_23", - "ranch_camp_24", - "ranch_camp_25", - "ranch_camp_26", - "ranch_camp_27", - "ranch_camp_28", - "ranch_camp_29", - "ranch_camp_30", - "ranch_camp_31", - "ranch_camp_32", - "ranch_camp_33", - "ranch_camp_34", - "ranch_camp_35", - "ranch_camp_36", - "ranch_camp_37", - "ranch_camp_38", - "ranch_camp_39", - "ranch_camp_40", - "ranch_camp_41", - "ranch_camp_42", - "ranch_camp_43", - "ranch_camp_44", - "ranch_camp_45", - "ranch_camp_46", - "ranch_camp_47", - "ranch_camp_48", - "ranch_camp_49", - "ranch_camp_50", - "ranch_camp_51", - "ranch_camp_52", - "ranch_camp_53", - "ranch_camp_54", - "ranch_camp_55", - "ranch_camp_56", - "ranch_camp_57", - "ranch_camp_58", - "ranch_camp_59", - "ranch_camp_60", - "ranch_camp_61", - "ranch_camp_62", - "ranch_camp_63", - "ranch_camp_64", - "ranch_camp_65", - "ranch_camp_66", - "ranch_camp_67", - "ranch_camp_68", - "ranch_camp_69", - "ranch_camp_70", - "ranch_camp_71", - "ranch_camp_72", - "ranch_camp_73", - "ranch_camp_74", - "ranch_camp_75", - "ranch_camp_76", - "ranch_camp_77", - "ranch_camp_78", - "ranch_camp_79", - "ranch_camp_80", - "ranch_camp_81", - "ranch_camp_57_roof", - "ranch_camp_65_roof", - "ranch_camp_66_roof", - "ranch_camp_67_roof", - "ranch_camp_68_roof", - "ranch_camp_74_roof", - "ranch_camp_75_roof", - "ranch_camp_57_silo", - "ranch_camp_57_silocap", - "bandit_cabin", - "bandit_camp_1", - "bandit_camp_2", - "bandit_camp_3", - "bandit_camp_4", - "bandit_garage_1", - "bandit_garage_2", - "cabin", - "cabin_strange", - "cabin_strange_b", - "campsite", - "campsite_a", - "campsite_cabin_incomplete", - "campsite_field_biker", - "campsite_field_biker_destroyed", - "haz_sar", - "haz_sar_entrance", - "haz_sar_b1", - "haz_sar_entrance_b1", - "hunter_shack", - "basement_bionic", - "lmoe", - "lmoe_roof", - "lmoe_under", - "lmoe_under_empty", - "magic_basement", - "outpost", - "park", - "pond_field", - "pond_forest", - "pond_swamp", - "pool", - "pwr_large_entrance", - "pwr_large_2", - "pwr_large_3", - "pwr_large_4", - "pwr_sub_s", - "radio_tower", - "robofachq_ai_a0", - "robofachq_ai_a1", - "robofachq_ai_a2", - "robofachq_ai_a3", - "robofachq_ai_b0", - "robofachq_ai_b1", - "robofachq_ai_b2", - "robofachq_ai_b3", - "robofachq_aiutl_a0", - "robofachq_aiutl_a1", - "robofachq_aiutl_a2", - "robofachq_aiutl_a3", - "robofachq_aiutl_b0", - "robofachq_aiutl_b1", - "robofachq_aiutl_b2", - "robofachq_aiutl_b3", - "robofachq_hab_a0", - "robofachq_hab_a1", - "robofachq_hab_a2", - "robofachq_hab_a3", - "robofachq_hab_b0", - "robofachq_hab_b1", - "robofachq_hab_b2", - "robofachq_hab_b3", - "robofachq_roof_a0", - "robofachq_roof_a1", - "robofachq_roof_a2", - "robofachq_roof_a3", - "robofachq_surface_a0", - "robofachq_surface_a1", - "robofachq_surface_a2", - "robofachq_surface_a3", - "robofachq_surface_b0", - "robofachq_surface_b1", - "robofachq_surface_b2", - "robofachq_surface_b3", - "robofachq_surface_parking", - "robofachq_surface_entrance", - "robofachq_surface_car_entrance", - "sai", - "shelter", - "shelter_1", - "shelter_2", - "shelter_roof", - "shelter_roof_1", - "shelter_roof_2", - "shelter_under", - "shipwreck_river_1", - "shipwreck_river_2", - "shipwreck_river_3", - "shipwreck_river_4", - "toxic_dump", - "orchard_tree_apple", - "orchard_stall", - "orchard_processing", - "sewage_treatment", - "sewage_treatment_hub", - "sewage_treatment_under", - "dairy_farm_NW", - "dairy_farm_NE", - "dairy_farm_SW", - "dairy_farm_SE", - "megastore", - "megastore_entrance", - "haz_sar_entrance", - "haz_sar", - "haz_sar_entrance_b1", - "haz_sar_b1", - "haz_sar_entrance_north", - "haz_sar_north", - "haz_sar_entrance_b1_north", - "haz_sar_b1_north", - "haz_sar_entrance_east", - "haz_sar_east", - "haz_sar_entrance_b1_east", - "haz_sar_b1_east", - "haz_sar_entrance_south", - "haz_sar_south", - "haz_sar_entrance_b1_south", - "haz_sar_b1_south", - "haz_sar_entrance_west", - "haz_sar_west", - "haz_sar_entrance_b1_west", - "haz_sar_b1_west", - "house_base", - "house_base_north", - "house_base_south", - "house_base_east", - "house_base_west", "mass_grave_north", "mass_grave_south", "mass_grave_east", "mass_grave_west", - "house", - "house_north", - "house_south", - "house_east", - "house_west", - "rural_house", - "rural_house_north", - "rural_house_south", - "rural_house_east", - "rural_house_west" + "bridge_north", + "bridge_east", + "bridge_south", + "bridge_west", + "fema", + "fema_entrance", + "fema_1_3", + "fema_2_1", + "fema_2_2", + "fema_2_3", + "fema_3_1", + "fema_3_2", + "fema_3_3" ] } ] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 1661462bcfcc2..cf1b46c120bae 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -4509,8 +4509,8 @@ { "point": [ 4, 0, -4 ], "overmap": "microlab_generic_edge" }, { "point": [ 5, 0, -4 ], "overmap": "microlab_generic_edge" }, { "point": [ 6, 0, -4 ], "overmap": "microlab_rock_border" }, - { "point": [ -1, 1, -4 ], "overmap": "microlab_rock_border" }, - { "point": [ 0, 1, -4 ], "overmap": "microlab_generic_edge" }, + { "point": [ -1, 1, -4 ], "overmap": "microlab_reactor_west" }, + { "point": [ 0, 1, -4 ], "overmap": "microlab_generic_edge_room_connector_west" }, { "point": [ 1, 1, -4 ], "overmap": "microlab_generic" }, { "point": [ 2, 1, -4 ], "overmap": "microlab_generic" }, { "point": [ 3, 1, -4 ], "overmap": "microlab_generic_hallway_start_south" }, @@ -4541,7 +4541,8 @@ { "point": [ 4, 4, -4 ], "overmap": "microlab_rock_border" }, { "point": [ 5, 4, -4 ], "overmap": "microlab_rock_border" }, { "point": [ 6, 4, -4 ], "overmap": "microlab_rock_border" }, - { "point": [ 3, 4, -5 ], "overmap": "microlab_generic_isolated_elevator_pit_north" } + { "point": [ 3, 4, -5 ], "overmap": "microlab_generic_isolated_elevator_pit_north" }, + { "point": [ -1, 1, -5 ], "overmap": "microlab_reactor_b_west" } ], "locations": [ "wilderness" ], "city_distance": [ 3, -1 ], diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_microlab.json b/data/json/overmap/overmap_terrain/overmap_terrain_microlab.json index c4b7d67100c19..ed96bee77eab9 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_microlab.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_microlab.json @@ -62,6 +62,7 @@ "microlab_generic_firebreak", "microlab_generic_hallway", "microlab_generic_stairs_down", + "microlab_generic_edge_room_connector", "microlab_generic_isolated_stairs_odd", "microlab_generic_isolated_stairs_even", "microlab_generic_isolated_stairs_up", @@ -73,6 +74,15 @@ "see_cost": 5, "flags": [ "RISK_HIGH", "SOURCE_CHEMISTRY", "SOURCE_MEDICINE" ] }, + { + "type": "overmap_terrain", + "id": [ "microlab_reactor", "microlab_reactor_b" ], + "name": "science lab reactor", + "sym": "L", + "color": "light_red", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, { "type": "overmap_terrain", "id": "microlab_generic_surface", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_transportation.json b/data/json/overmap/overmap_terrain/overmap_terrain_transportation.json index eb7a6f94d496e..ad2842be6c13a 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_transportation.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_transportation.json @@ -62,16 +62,41 @@ }, { "type": "overmap_terrain", - "id": "bridge", + "abstract": "generic_bridge", "copy-from": "generic_transportation", "name": "bridge", "sym": "│", "color": "white", - "see_cost": 2, - "extras": "bridge", - "mapgen": [ { "method": "builtin", "name": "bridge" } ], + "see_cost": 2 + }, + { + "type": "overmap_terrain", + "id": "bridge", + "copy-from": "generic_bridge", + "color": "blue", "flags": [ "RIVER" ] }, + { + "type": "overmap_terrain", + "id": "bridge_road", + "copy-from": "generic_bridge", + "name": "bridge (overpass)" + }, + { + "type": "overmap_terrain", + "id": "bridgehead_ground", + "copy-from": "generic_bridge", + "name": "bridgehead (ground)", + "sym": "v", + "extras": "bridgehead_ground" + }, + { + "type": "overmap_terrain", + "id": "bridgehead_ramp", + "copy-from": "generic_bridge", + "name": "bridgehead (ramp)", + "sym": "^" + }, { "type": "overmap_terrain", "id": [ "roadstop", "roadstop_roof" ], diff --git a/data/json/player_activities.json b/data/json/player_activities.json index 9db49f5ac2afa..f66090b8e2350 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -866,5 +866,33 @@ "activity_level": "NO_EXERCISE", "verb": "consuming", "based_on": "time" + }, + { + "id": "ACT_WORKOUT_HARD", + "type": "activity_type", + "activity_level": "EXTRA_EXERCISE", + "verb": { "ctxt": "training", "str": "working out" }, + "based_on": "time" + }, + { + "id": "ACT_WORKOUT_ACTIVE", + "type": "activity_type", + "activity_level": "ACTIVE_EXERCISE", + "verb": { "ctxt": "training", "str": "working out" }, + "based_on": "time" + }, + { + "id": "ACT_WORKOUT_MODERATE", + "type": "activity_type", + "activity_level": "MODERATE_EXERCISE", + "verb": { "ctxt": "training", "str": "working out" }, + "based_on": "time" + }, + { + "id": "ACT_WORKOUT_LIGHT", + "type": "activity_type", + "activity_level": "LIGHT_EXERCISE", + "verb": { "ctxt": "training", "str": "working out" }, + "based_on": "time" } ] diff --git a/data/json/professions.json b/data/json/professions.json index b895a804c7a01..42dc0b75fc90e 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -901,6 +901,7 @@ "wristwatch", "water_clean", "bandages", + "adhesive_bandages", "aspirin", "1st_aid", "stethoscope" @@ -997,6 +998,7 @@ "coat_lab", "water_clean", "bandages", + "adhesive_bandages", "aspirin", "grahmcrackers", "stethoscope" @@ -1121,7 +1123,7 @@ "description": "You got your pilot's license, and earned a living ferrying businessmen and tourists around. The Cataclysm has grounded you for now, but the sky still calls to you…", "points": 4, "skills": [ { "level": 4, "name": "driving" }, { "level": 1, "name": "speech" }, { "level": 3, "name": "mechanics" } ], - "traits": [ "PROF_HELI_PILOT" ], + "proficiencies": [ "prof_helicopter_pilot" ], "items": { "both": { "items": [ "pants_cargo", "socks", "polo_shirt", "boots", "wristwatch", "fancy_sunglasses" ], @@ -1162,7 +1164,22 @@ "description": "Everyone is dead? Oh well, it doesn't matter; it's not like you got along with people much anyway. Your beloved cats are all the friends you need!", "points": 5, "skills": [ { "level": 1, "name": "survival" }, { "level": 1, "name": "cooking" }, { "level": 1, "name": "tailor" } ], - "pets": [ { "name": "mon_cat", "amount": 30 } ], + "pets": [ + { "name": "mon_cat", "amount": 5 }, + { "name": "mon_cat_tabby", "amount": 4 }, + { "name": "mon_cat_longhair", "amount": 3 }, + { "name": "mon_cat_persian", "amount": 3 }, + { "name": "mon_cat_siamese", "amount": 3 }, + { "name": "mon_cat_calico", "amount": 2 }, + { "name": "mon_cat_maine_coon", "amount": 2 }, + { "name": "mon_cat_devon_rex", "amount": 2 }, + { "name": "mon_cat_bengal", "amount": 1 }, + { "name": "mon_cat_sphynx", "amount": 1 }, + { "name": "mon_cat_chonker_kitten", "amount": 1 }, + { "name": "mon_cat_longhair_kitten", "amount": 1 }, + { "name": "mon_cat_calico_kitten", "amount": 1 }, + { "name": "mon_cat_tabby_kitten", "amount": 1 } + ], "items": { "both": { "items": [ "jeans", "longshirt", "socks", "coat_winter", "boots_winter", "knit_scarf", "pockknife", "water_clean", "wristwatch" ], @@ -2233,6 +2250,7 @@ "description": "You ran into trouble coming out of class at your community college's metalsmithing program, but despite the havoc you've managed to keep ahold of some of the equipment you were carrying.", "points": 1, "skills": [ { "level": 4, "name": "fabrication" } ], + "proficiencies": [ "prof_blacksmithing" ], "items": { "both": { "items": [ "jeans", "socks", "boots", "tank_top", "apron_leather", "fire_gauntlets", "wristwatch", "hammer" ], @@ -3125,6 +3143,7 @@ { "level": 2, "name": "chemistry" }, { "level": 3, "name": "cooking" } ], + "proficiencies": [ "prof_knapping" ], "items": { "both": { "items": [ @@ -4092,7 +4111,7 @@ { "level": 3, "name": "mechanics" }, { "level": 3, "name": "gun" } ], - "traits": [ "PROF_HELI_PILOT" ], + "proficiencies": [ "prof_helicopter_pilot" ], "items": { "both": { "items": [ diff --git a/data/json/proficiencies/misc.json b/data/json/proficiencies/misc.json new file mode 100644 index 0000000000000..5e1c79be5479d --- /dev/null +++ b/data/json/proficiencies/misc.json @@ -0,0 +1,17 @@ +[ + { + "type": "proficiency", + "id": "prof_knapping", + "name": { "str": "Knapping" } + }, + { + "type": "proficiency", + "id": "prof_blacksmithing", + "name": { "str": "Blacksmithing" } + }, + { + "type": "proficiency", + "id": "prof_helicopter_pilot", + "name": { "str": "Helicopter Piloting" } + } +] diff --git a/data/json/recipes/armor/head.json b/data/json/recipes/armor/head.json index 200771e9c45fb..a8d29aa576dd5 100644 --- a/data/json/recipes/armor/head.json +++ b/data/json/recipes/armor/head.json @@ -1017,12 +1017,13 @@ "category": "CC_ARMOR", "subcategory": "CSC_ARMOR_HEAD", "skill_used": "fabrication", - "time": "6 m", + "time": "5 m", "autolearn": true, + "reversible": true, "components": [ [ [ "hat_hard", 1 ], [ "helmet_bike", 1 ] ], [ [ "flashlight", 1 ] ], - [ [ "cordage", 1, "LIST" ], [ "duct_tape", 10 ], [ "medical_tape", 20 ] ] + [ [ "rag", 2 ], [ "leather", 2 ], [ "cordage", 1, "LIST" ], [ "duct_tape", 10 ], [ "medical_tape", 20 ] ] ] }, { diff --git a/data/json/recipes/armor/pets_horse.json b/data/json/recipes/armor/pets_horse.json index 2fb9e1057eb80..343944527e500 100644 --- a/data/json/recipes/armor/pets_horse.json +++ b/data/json/recipes/armor/pets_horse.json @@ -77,6 +77,8 @@ [ "wax", 6 ], [ "tallow", 24 ], [ "mutant_tallow", 24 ], + [ "human_tallow", 24 ], + [ "demihuman_tallow", 24 ], [ "tallow_tainted", 24 ], [ "vinegar", 30 ], [ "pine_bough", 60 ] diff --git a/data/json/recipes/armor/storage.json b/data/json/recipes/armor/storage.json index c91e914ba261e..6ce5d2eeb6df9 100644 --- a/data/json/recipes/armor/storage.json +++ b/data/json/recipes/armor/storage.json @@ -346,7 +346,7 @@ "time": "36 s", "reversible": true, "autolearn": true, - "components": [ [ [ "raw_leather", 6 ], [ "raw_hleather", 6 ], [ "raw_fur", 6 ], [ "raw_hfur", 6 ] ] ], + "components": [ [ [ "raw_leather", 6 ], [ "raw_hleather", 6 ], [ "raw_demihumanleather", 6 ], [ "raw_fur", 6 ], [ "raw_hfur", 6 ] ] ], "flags": [ "BLIND_EASY" ] }, { diff --git a/data/json/recipes/chem/fuel.json b/data/json/recipes/chem/fuel.json index ae77278af0984..0ed8983868f12 100644 --- a/data/json/recipes/chem/fuel.json +++ b/data/json/recipes/chem/fuel.json @@ -66,7 +66,6 @@ [ "edible_tallow_lard", 8, "LIST" ], [ "tallow_tainted", 8 ], [ "any_fat", 16, "LIST" ], - [ "fat_tainted", 16 ], [ "lamp_oil", 1000 ], [ "motor_oil", 1000 ] ] @@ -93,7 +92,7 @@ [ "cooking_oil", 16 ], [ "cooking_oil2", 16 ], [ "any_fat", 6, "LIST" ], - [ "fat_tainted", 6 ] + [ "ghee", 16 ] ] ], "//": "Making lamp oil from (tainted) fat directly is less efficient than using lard/tallow, but allows processing of spoilt fats. See #29770", diff --git a/data/json/recipes/chem/mutagens.json b/data/json/recipes/chem/mutagens.json index 5cafd8da8cfe9..b3d139ee8e677 100644 --- a/data/json/recipes/chem/mutagens.json +++ b/data/json/recipes/chem/mutagens.json @@ -269,7 +269,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_animal", 5 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ], [ "meat_scrap", 30 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { @@ -299,7 +299,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_animal", 6 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ], [ "meat_scrap", 30 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { @@ -329,7 +329,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_animal", 6 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 1 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 1 ], [ "meat_scrap", 10 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { @@ -359,7 +359,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_animal", 6 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ], [ "meat_scrap", 30 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { @@ -389,7 +389,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_animal", 6 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ], [ "meat_scrap", 30 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { @@ -419,7 +419,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_animal", 6 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ], [ "meat_scrap", 30 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { @@ -543,7 +543,7 @@ "batch_time_factors": [ 80, 20 ], "book_learn": [ [ "recipe_maiar", 6 ] ], "using": [ [ "mutagen_production_standard", 25 ] ], - "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], + "components": [ [ [ "mutagen", 1 ] ], [ [ "meat", 3 ], [ "meat_scrap", 30 ] ], [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] ], "flags": [ "SECRET" ] }, { diff --git a/data/json/recipes/food/baking.json b/data/json/recipes/food/baking.json index 6a55087e0f570..37f03ea498baf 100644 --- a/data/json/recipes/food/baking.json +++ b/data/json/recipes/food/baking.json @@ -15,9 +15,9 @@ "components": [ [ [ "flour", 4 ] ], [ [ "yeast", 2 ] ], - [ [ "apple_cider", 2 ], [ "apple", 2 ] ], - [ [ "pumpkin", 2 ] ], - [ [ "sugar", 4 ] ], + [ [ "apple_cider", 2 ], [ "apple", 2 ], [ "irradiated_apple", 2 ] ], + [ [ "pumpkin", 2 ], [ "irradiated_pumpkin", 2 ] ], + [ [ "sugar", 4 ], [ "artificial_sweetener", 4 ] ], [ [ "powder_eggs", 2 ], [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], [ [ "any_butter_or_oil", 2, "LIST" ] ], [ [ "salt", 2 ] ], diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index 004c61edfb773..bae81e2bef4d4 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -15,9 +15,9 @@ "components": [ [ [ "flour", 40 ] ], [ [ "yeast", 2 ] ], - [ [ "milk", 2 ], [ "milk_raw", 2 ] ], - [ [ "pumpkin", 2 ] ], - [ [ "sugar", 4 ] ], + [ [ "milk_standard_raw", 2, "LIST" ] ], + [ [ "pumpkin", 2 ], [ "irradiated_pumpkin", 2 ] ], + [ [ "sugar", 4 ], [ "artificial_sweetener", 4 ] ], [ [ "powder_eggs", 2 ], [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], [ [ "any_butter_or_oil", 2, "LIST" ] ], [ [ "salt", 2 ] ] diff --git a/data/json/recipes/food/brewing.json b/data/json/recipes/food/brewing.json index 450837636adda..013e218daeffa 100644 --- a/data/json/recipes/food/brewing.json +++ b/data/json/recipes/food/brewing.json @@ -27,10 +27,7 @@ "batch_time_factors": [ 50, 4 ], "book_learn": [ [ "survival_book", 3 ], [ "textbook_survival", 3 ], [ "manual_survival", 3 ], [ "dairy_book", 3 ] ], "using": [ [ "milk_standard", 15 ] ], - "components": [ - [ [ "vinegar", 3 ] ], - [ [ "wild_herbs", 40 ], [ "stomach_large", 1 ], [ "hstomach_large", 1 ], [ "stomach", 2 ], [ "hstomach", 2 ] ] - ] + "components": [ [ [ "vinegar", 3 ] ], [ [ "wild_herbs", 40 ], [ "meat_stomach", 1, "LIST" ] ] ] }, { "type": "recipe", diff --git a/data/json/recipes/food/canned.json b/data/json/recipes/food/canned.json index dce8b0130e2bd..7c88cc18b716e 100644 --- a/data/json/recipes/food/canned.json +++ b/data/json/recipes/food/canned.json @@ -15,11 +15,7 @@ "result_mult": 2, "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 100, "LIST" ] ], [ [ "pot_canning", -1 ] ] ], - "components": [ - [ [ "water", 11 ], [ "water_clean", 11 ] ], - [ [ "jar_glass", 1 ] ], - [ [ "offal", 2 ], [ "liver", 5 ], [ "sweetbread", 5 ], [ "kidney", 5 ] ] - ] + "components": [ [ [ "water", 11 ], [ "water_clean", 11 ] ], [ [ "jar_glass", 1 ] ], [ [ "meat_offal", 2, "LIST" ] ] ] }, { "result": "offal_canned", @@ -43,7 +39,7 @@ [ [ "canister_empty", 1 ], [ "can_food", 1 ] ], [ [ "scrap", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ], - [ [ "offal", 1 ], [ "liver", 3 ], [ "sweetbread", 3 ], [ "kidney", 3 ] ] + [ [ "meat_offal", 1, "LIST" ] ] ] }, { @@ -64,7 +60,7 @@ "components": [ [ [ "water", 1 ], [ "water_clean", 1 ], [ "salt_water", 1 ], [ "saline", 5 ] ], [ [ "jar_glass", 1 ] ], - [ [ "offal", 2 ], [ "liver", 5 ], [ "sweetbread", 5 ], [ "kidney", 5 ] ], + [ [ "meat_offal", 2, "LIST" ] ], [ [ "vinegar", 1 ] ] ] }, @@ -86,7 +82,7 @@ "components": [ [ [ "water", 11 ], [ "water_clean", 11 ] ], [ [ "jar_glass", 1 ] ], - [ [ "meat", 1 ], [ "fish", 1 ] ], + [ [ "meat_red_raw", 1, "LIST" ], [ "fish", 1 ] ], [ [ "veggy", 1 ], [ "veggy_wild", 1 ] ] ] }, @@ -113,7 +109,7 @@ [ [ "can_medium", 1 ] ], [ [ "scrap", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ], - [ [ "meat", 1 ], [ "fish", 1 ] ], + [ [ "meat_red_raw", 1, "LIST" ], [ "fish", 1 ] ], [ [ "veggy", 1 ], [ "veggy_wild", 1 ] ] ] }, @@ -136,7 +132,7 @@ "components": [ [ [ "water", 16 ], [ "water_clean", 16 ] ], [ [ "jar_3l_glass", 1 ] ], - [ [ "meat", 6 ], [ "fish", 6 ] ], + [ [ "meat_red_raw", 6, "LIST" ], [ "fish", 6 ] ], [ [ "veggy", 6 ], [ "veggy_wild", 6 ] ] ] }, @@ -156,7 +152,7 @@ "result_mult": 2, "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 100, "LIST" ] ], [ [ "pot_canning", -1 ] ] ], - "components": [ [ [ "water", 11 ], [ "water_clean", 11 ] ], [ [ "jar_glass", 1 ] ], [ [ "meat", 4 ], [ "fish", 4 ] ] ] + "components": [ [ [ "water", 11 ], [ "water_clean", 11 ] ], [ [ "jar_glass", 1 ] ], [ [ "meat_red_raw", 4, "LIST" ], [ "fish", 4 ] ] ] }, { "type": "recipe", @@ -181,7 +177,7 @@ [ [ "canister_empty", 1 ], [ "can_food", 1 ] ], [ [ "scrap", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ], - [ [ "meat", 2 ], [ "fish", 2 ] ] + [ [ "meat_red_raw", 2, "LIST" ], [ "fish", 2 ] ] ] }, { @@ -200,7 +196,11 @@ "batch_time_factors": [ 83, 5 ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 200, "LIST" ] ], [ [ "pot_canning", -1 ] ] ], - "components": [ [ [ "water", 16 ], [ "water_clean", 16 ] ], [ [ "jar_3l_glass", 1 ] ], [ [ "meat", 24 ], [ "fish", 24 ] ] ] + "components": [ + [ [ "water", 16 ], [ "water_clean", 16 ] ], + [ [ "jar_3l_glass", 1 ] ], + [ [ "meat_red_raw", 24, "LIST" ], [ "fish", 24 ] ] + ] }, { "type": "recipe", @@ -938,11 +938,7 @@ "container": "jar_3l_glass_sealed", "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 200, "LIST" ] ], [ [ "pot_canning", -1 ] ] ], - "components": [ - [ [ "water", 16 ], [ "water_clean", 16 ] ], - [ [ "jar_3l_glass", 1 ] ], - [ [ "offal", 12 ], [ "liver", 30 ], [ "sweetbread", 30 ], [ "kidney", 30 ] ] - ] + "components": [ [ [ "water", 16 ], [ "water_clean", 16 ] ], [ [ "jar_3l_glass", 1 ] ], [ [ "meat_offal", 12, "LIST" ] ] ] }, { "type": "recipe", diff --git a/data/json/recipes/food/frozen.json b/data/json/recipes/food/frozen.json index 8889cfa1c251a..d4a8c999cc749 100644 --- a/data/json/recipes/food/frozen.json +++ b/data/json/recipes/food/frozen.json @@ -144,7 +144,7 @@ "components": [ [ [ "icecream", 1 ], [ "icecream_artificial", 1 ] ], [ [ "chocolate", 1 ], [ "candy", 1 ], [ "candy2", 1 ], [ "candy3", 1 ], [ "maple_candy", 1 ], [ "syrup", 1 ] ], - [ [ "sugar", 5 ] ] + [ [ "sugar", 5 ], [ "artificial_sweetener", 5 ] ] ] }, { diff --git a/data/json/recipes/food/offal_dishes.json b/data/json/recipes/food/offal_dishes.json index 8915083ef24af..7df9508df6a26 100644 --- a/data/json/recipes/food/offal_dishes.json +++ b/data/json/recipes/food/offal_dishes.json @@ -20,7 +20,7 @@ "result": "lung_cooked", "qualities": [ { "id": "COOK", "level": 1 } ], "tools": [ [ [ "surface_heat", 7, "LIST" ] ] ], - "components": [ [ [ "lung", 1 ] ] ] + "components": [ [ [ "meat_lung", 1, "LIST" ] ] ] }, { "type": "recipe", @@ -129,7 +129,7 @@ "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 100, "LIST" ] ] ], "components": [ - [ [ "small_stomach_boiled", 2 ], [ "stomach_boiled", 1 ] ], + [ [ "meat_stomach_boiled", 1, "LIST" ] ], [ [ "water", 4 ], [ "water_clean", 4 ] ], [ [ "veggy_any", 2, "LIST" ], @@ -182,7 +182,7 @@ "tools": [ [ [ "surface_heat", 75, "LIST" ] ], [ [ "rock_quern", -1 ], [ "clay_quern", -1 ], [ "food_processor", 20 ] ] ], "components": [ [ [ "liver", 8 ] ], - [ [ "edible_fat", 2, "LIST" ], [ "lard", 2 ], [ "mutant_lard", 2 ] ], + [ [ "edible_fat", 2, "LIST" ], [ "edible_lard", 2, "LIST" ] ], [ [ "powder_eggs", 10 ], [ "eggs_bird", 2, "LIST" ] ], [ [ "onion", 1 ], [ "irradiated_onion", 1 ] ], [ [ "flour", 2 ] ], @@ -231,7 +231,7 @@ [ [ "salt", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "mustard", 1 ] ], - [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "tomato", 1 ] ] + [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "tomato", 1 ], [ "irradiated_tomato", 1 ] ] ] }, { @@ -307,7 +307,7 @@ "qualities": [ { "id": "COOK", "level": 3 }, { "id": "CUT", "level": 1 } ], "tools": [ [ [ "surface_heat", 50, "LIST" ] ] ], "components": [ - [ [ "lung", 4 ] ], + [ [ "meat_lung", 4, "LIST" ] ], [ [ "flour", 4 ] ], [ [ "onion", 1 ], [ "irradiated_onion", 1 ] ], [ [ "cooking_oil", 1 ], [ "cooking_oil2", 1 ] ], @@ -315,7 +315,7 @@ [ [ "pepper", 6 ] ], [ [ "worthy_wine", 3, "LIST" ] ], [ [ "garlic_clove", 1 ] ], - [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "tomato", 1 ] ] + [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "tomato", 1 ], [ "irradiated_tomato", 1 ] ] ] }, { @@ -332,17 +332,17 @@ "qualities": [ { "id": "COOK", "level": 3 }, { "id": "CUT", "level": 1 } ], "tools": [ [ [ "surface_heat", 50, "LIST" ] ] ], "components": [ - [ [ "lung", 4 ] ], + [ [ "meat_lung", 4, "LIST" ] ], [ [ "kidney", 4 ] ], [ [ "brain", 4 ] ], [ [ "onion", 3 ], [ "irradiated_onion", 3 ] ], [ [ "any_butter", 4, "LIST" ] ], [ [ "salt", 6 ] ], [ [ "mustard", 3 ] ], - [ [ "sugar_standard", 3, "LIST" ] ], + [ [ "sugar_standard", 3, "LIST" ], [ "artificial_sweetener", 42 ] ], [ [ "worthy_wine", 3, "LIST" ] ], [ [ "batter", 4, "LIST" ] ], - [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "tomato", 1 ] ] + [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "tomato", 1 ], [ "irradiated_tomato", 1 ] ] ] }, { @@ -385,7 +385,12 @@ "book_learn": [ [ "offalcooking", 3 ] ], "qualities": [ { "id": "COOK", "level": 2 }, { "id": "CUT_FINE", "level": 1 } ], "tools": [ [ [ "funnel", -1 ] ] ], - "components": [ [ [ "stomach", 2 ], [ "stomach_large", 1 ] ], [ [ "salt", 20 ] ], [ [ "water", 2 ] ], [ [ "bag_plastic", 1 ] ] ] + "components": [ + [ [ "meat_stomach", 1, "LIST" ] ], + [ [ "salt", 20 ] ], + [ [ "water", 2 ], [ "water_clean", 2 ] ], + [ [ "bag_plastic", 1 ] ] + ] }, { "type": "recipe", diff --git a/data/json/recipes/food/other.json b/data/json/recipes/food/other.json new file mode 100644 index 0000000000000..669fae5381065 --- /dev/null +++ b/data/json/recipes/food/other.json @@ -0,0 +1,17 @@ +[ + { + "type": "recipe", + "result": "molasses", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 3, + "time": "50 m", + "batch_time_factors": [ 20, 1 ], + "charges": 1, + "autolearn": true, + "qualities": [ { "id": "BOIL", "level": 2 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ [ [ "beet_syrup", 6 ] ] ] + } +] diff --git a/data/json/recipes/other/containers.json b/data/json/recipes/other/containers.json index 309bd51aa766e..eedc8d6b5dc44 100644 --- a/data/json/recipes/other/containers.json +++ b/data/json/recipes/other/containers.json @@ -91,7 +91,7 @@ "tools": [ [ [ "water_boiling_heat", 3, "LIST" ] ] ], "components": [ [ [ "water", 5 ], [ "water_clean", 5 ] ], - [ [ "stomach", 1 ], [ "hstomach", 1 ], [ "demihuman_stomach", 1 ] ], + [ [ "meat_stomach_small", 1, "LIST" ] ], [ [ "cordage_short", 2, "LIST" ], [ "filament", 100, "LIST" ] ] ] }, @@ -109,7 +109,7 @@ "tools": [ [ [ "water_boiling_heat", 4, "LIST" ] ] ], "components": [ [ [ "water", 8 ], [ "water_clean", 8 ] ], - [ [ "stomach_large", 1 ], [ "hstomach_large", 1 ], [ "demihuman_stomach_large", 1 ] ], + [ [ "meat_stomach_large", 1, "LIST" ] ], [ [ "cordage_short", 3, "LIST" ], [ "filament", 150, "LIST" ] ] ] }, diff --git a/data/json/recipes/other/medical.json b/data/json/recipes/other/medical.json index e3ca6e2b9ec27..fae569ecd4be0 100644 --- a/data/json/recipes/other/medical.json +++ b/data/json/recipes/other/medical.json @@ -51,6 +51,47 @@ "tools": [ [ [ "water_boiling_heat", 9, "LIST" ] ] ], "components": [ [ [ "bandages_makeshift", 3 ] ], [ [ "water_clean", 3 ], [ "water", 3 ] ] ] }, + { + "result": "adhesive_bandages", + "type": "recipe", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MEDICAL", + "skill_used": "firstaid", + "difficulty": 1, + "time": "5 m", + "batch_time_factors": [ 50, 2 ], + "autolearn": true, + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "medical_gauze", 5 ] ], [ [ "duct_tape", 20 ], [ "medical_tape", 10 ] ] ] + }, + { + "result": "tourniquet_upper", + "type": "recipe", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MEDICAL", + "skill_used": "firstaid", + "difficulty": 1, + "time": "1 m", + "autolearn": true, + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ + [ + [ "leather_belt", 1 ], + [ "hose", 1 ], + [ "rope_6", 1 ], + [ "cordage_6", 1 ], + [ "vine_6", 1 ], + [ "rope_makeshift_6", 1 ], + [ "towel", 1 ], + [ "blanket", 1 ], + [ "bandana", 1 ], + [ "cable", 1 ], + [ "wire", 1 ], + [ "tie_skinny", 1 ] + ], + [ [ "stick", 1 ], [ "cu_pipe", 1 ] ] + ] + }, { "result": "disinfectant", "type": "recipe", diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index f783464cbbb6d..94344672a5659 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -622,6 +622,26 @@ [ [ "steel_chunk", 12 ] ] ] }, + { + "result": "broken_robofac_laserturret_mk1", + "type": "uncraft", + "skill_used": "electronics", + "difficulty": 6, + "time": "3 h", + "using": [ [ "soldering_standard", 10 ] ], + "qualities": [ { "id": "SCREW", "level": 1 } ], + "components": [ + [ [ "ai_module", 1 ] ], + [ [ "gun_module", 1 ] ], + [ [ "targeting_module", 1 ] ], + [ [ "identification_module", 1 ] ], + [ [ "sensor_module", 1 ] ], + [ [ "medium_storage_battery", 1 ] ], + [ [ "power_supply", 1 ] ], + [ [ "robot_controls", 1 ] ], + [ [ "turret_chassis", 1 ] ] + ] + }, { "result": "broken_eyebot", "type": "uncraft", @@ -3525,12 +3545,31 @@ [ [ "aspirin", 10 ] ], [ [ "disinfectant", 10 ] ], [ [ "saline", 5 ] ], - [ [ "bandages", 6 ] ], + [ [ "adhesive_bandages", 6 ] ], + [ [ "bandages", 3 ] ], [ [ "medical_gauze", 6 ] ], [ [ "booklet_firstaid", 1 ] ] ], "flags": [ "BLIND_EASY", "UNCRAFT_LIQUIDS_CONTAINED" ] }, + { + "result": "ifak", + "type": "uncraft", + "time": "6 s", + "components": [ + [ [ "medical_tape", 20 ] ], + [ [ "tourniquet_upper", 1 ] ], + [ [ "disinfectant", 5 ] ], + [ [ "quikclot", 5 ] ], + [ [ "bandages", 9 ] ], + [ [ "medical_gauze", 3 ] ], + [ [ "adhesive_bandages", 3 ] ], + [ [ "pur_tablets", 3 ] ], + [ [ "gloves_medical", 1 ] ], + [ [ "scissors", 1 ] ] + ], + "flags": [ "BLIND_EASY", "UNCRAFT_LIQUIDS_CONTAINED" ] + }, { "result": "survival_kit", "type": "uncraft", @@ -3749,6 +3788,26 @@ "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "rag", 25 ] ], [ [ "element", 5 ] ], [ [ "cable", 5 ] ] ] }, + { + "result": "wearable_light", + "type": "uncraft", + "skill_used": "fabrication", + "time": "30 s", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "flashlight", 1 ] ], [ [ "rag", 2 ] ] ] + }, + { + "result": "miner_hat", + "type": "uncraft", + "skill_used": "fabrication", + "time": "30 s", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ + [ [ "hat_hard", 1 ], [ "helmet_bike", 1 ] ], + [ [ "flashlight", 1 ] ], + [ [ "rag", 2 ], [ "leather", 2 ], [ "cordage", 1, "LIST" ], [ "duct_tape", 10 ], [ "medical_tape", 20 ] ] + ] + }, { "result": "adobe_pallet_done", "type": "uncraft", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 5ca27e103297e..10e1058db472e 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -48,7 +48,7 @@ "skill_used": "cooking", "time": "5 m", "autolearn": true, - "batch_time_factors": [ 80, 4 ], + "batch_time_factors": [ 20, 1 ], "qualities": [ { "id": "BOIL", "level": 1 } ], "tools": [ [ [ "water_boiling_heat", 3, "LIST" ] ] ], "components": [ [ [ "water", 1 ] ] ] @@ -4330,7 +4330,7 @@ [ [ "bread_sandwich", 2, "LIST" ] ], [ [ "spinach", 1 ] ], [ [ "cooking_oil", 1 ] ], - [ [ "lemon", 1 ] ], + [ [ "lemon", 1 ], [ "irradiated_lemon", 1 ] ], [ [ "vinegar", 1 ] ], [ [ "scrambled_eggs", 1 ], [ "boiled_egg", 1 ] ] ] @@ -5503,16 +5503,9 @@ "tools": [ [ [ "surface_heat", 5, "LIST" ] ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], - [ - [ "stomach", 1 ], - [ "stomach_large", 1 ], - [ "hstomach", 1 ], - [ "hstomach_large", 1 ], - [ "demihuman_stomach", 1 ], - [ "demihuman_stomach_large", 1 ] - ], - [ [ "offal", 1 ], [ "liver", 2 ], [ "lung", 2 ], [ "kidney", 2 ] ], - [ [ "oatmeal", 2 ], [ "buckwheat", 1 ] ] + [ [ "meat_stomach_small", 1, "LIST" ] ], + [ [ "meat_offal", 1, "LIST" ] ], + [ [ "oatmeal", 16 ], [ "buckwheat", 1 ] ] ] }, { @@ -5533,16 +5526,9 @@ "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], "components": [ [ [ "water", 2 ], [ "water_clean", 2 ] ], - [ - [ "stomach", 2 ], - [ "stomach_large", 1 ], - [ "hstomach", 2 ], - [ "hstomach_large", 1 ], - [ "demihuman_stomach", 2 ], - [ "demihuman_stomach_large", 1 ] - ], - [ [ "offal", 2 ], [ "liver", 4 ], [ "lung", 4 ], [ "kidney", 4 ] ], - [ [ "oatmeal", 4 ], [ "buckwheat", 1 ] ] + [ [ "meat_stomach_large", 1, "LIST" ] ], + [ [ "meat_offal", 2, "LIST" ] ], + [ [ "oatmeal", 32 ], [ "buckwheat", 2 ] ] ] }, { @@ -5780,7 +5766,7 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "food_processor", 20 ] ] ], - "components": [ [ [ "bone", 1 ] ] ] + "components": [ [ [ "bone", 1 ], [ "bone_human", 1 ] ] ] }, { "result": "meal_bone_tainted", @@ -5916,7 +5902,7 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "food_processor", 20 ] ] ], - "components": [ [ [ "chitin_piece", 1 ], [ "acidchitin_piece", 1 ] ] ] + "components": [ [ [ "chitin_piece", 1 ], [ "acidchitin_piece", 1 ], [ "endochitin", 1 ] ] ] }, { "result": "chilly-p", @@ -5946,8 +5932,8 @@ "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 1 } ], "tools": [ [ [ "char_smoker", 10 ] ] ], "components": [ - [ [ "offal", 4 ], [ "meat_nofish", 2, "LIST" ], [ "brain", 10 ] ], - [ [ "stomach", 2 ], [ "stomach_large", 1 ] ], + [ [ "offal", 4 ], [ "mutant_bug_organs", 4 ], [ "meat_nofish", 2, "LIST" ], [ "brain", 10 ] ], + [ [ "meat_stomach", 1, "LIST" ] ], [ [ "salt_water", 4 ], [ "saline", 8 ], @@ -5990,8 +5976,8 @@ "batch_time_factors": [ 50, 3 ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 1 } ], "components": [ - [ [ "offal", 4 ], [ "meat_nofish", 2, "LIST" ], [ "brain", 10 ] ], - [ [ "stomach", 2 ], [ "stomach_large", 1 ] ], + [ [ "offal", 4 ], [ "mutant_bug_organs", 4 ], [ "meat_nofish", 2, "LIST" ], [ "brain", 10 ] ], + [ [ "meat_stomach", 1, "LIST" ] ], [ [ "salt_water", 4 ], [ "saline", 8 ], @@ -6292,7 +6278,7 @@ "//": "Making the very first starter is a lot more finnicky than splitting it once it's mature.", "autolearn": true, "qualities": [ { "id": "CONTAIN", "level": 1 } ], - "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "jar_glass", 1 ] ], [ [ "flour", 4 ] ] ] + "components": [ [ [ "water_clean", 1 ] ], [ [ "jar_glass", 1 ] ], [ [ "flour", 4 ] ] ] }, { "type": "recipe", @@ -6305,7 +6291,7 @@ "result_mult": 2, "autolearn": true, "qualities": [ { "id": "CONTAIN", "level": 1 } ], - "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "jar_glass", 1 ] ], [ [ "flour", 4 ] ], [ [ "sourdough_starter", 1 ] ] ] + "components": [ [ [ "water_clean", 1 ] ], [ [ "jar_glass", 1 ] ], [ [ "flour", 4 ] ], [ [ "sourdough_starter", 1 ] ] ] }, { "type": "recipe", @@ -6320,7 +6306,13 @@ "autolearn": true, "qualities": [ { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], - "components": [ [ [ "flour", 10 ] ], [ [ "sourdough_starter", 1 ] ], [ [ "water", 3 ], [ "water_clean", 3 ] ] ] + "//": "The single water_clean here is for feeding the new starter.", + "components": [ + [ [ "flour", 10 ] ], + [ [ "sourdough_starter", 1 ] ], + [ [ "water", 2 ], [ "water_clean", 2 ] ], + [ [ "water_clean", 1 ] ] + ] }, { "type": "recipe", @@ -6537,7 +6529,7 @@ "components": [ [ [ "horseradish_root", 1 ] ], [ [ "salt", 1 ], [ "seasoning_salt", 1 ] ], - [ [ "sugar", 4 ] ], + [ [ "sugar", 4 ], [ "artificial_sweetener", 4 ] ], [ [ "water_clean", 1 ] ] ] }, @@ -6584,7 +6576,7 @@ [ [ "mustard_powder", 20 ] ], [ [ "salt", 2 ], [ "seasoning_salt", 2 ] ], [ [ "vinegar", 1 ] ], - [ [ "sugar", 1 ] ], + [ [ "sugar", 1 ], [ "artificial_sweetener", 1 ] ], [ [ "water_clean", 1 ] ] ] }, diff --git a/data/json/recipes/recipe_medsandchemicals.json b/data/json/recipes/recipe_medsandchemicals.json index 17261fd56247b..a9fe058d18c81 100644 --- a/data/json/recipes/recipe_medsandchemicals.json +++ b/data/json/recipes/recipe_medsandchemicals.json @@ -227,7 +227,11 @@ [ "isherwood_herbal_remedies", 2 ] ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], - "components": [ [ [ "meal_bone", 1 ] ], [ [ "dry_fruit", 1 ], [ "sugar", 45 ] ], [ [ "water_clean", 1 ] ] ] + "components": [ + [ [ "meal_bone", 1 ] ], + [ [ "dry_fruit", 1 ], [ "sugar", 45 ], [ "artificial_sweetener", 45 ] ], + [ [ "water_clean", 1 ] ] + ] }, { "type": "recipe", diff --git a/data/json/recipes/recipe_obsolete.json b/data/json/recipes/recipe_obsolete.json index 1cb21d004dbb5..2d9f696a4e43d 100644 --- a/data/json/recipes/recipe_obsolete.json +++ b/data/json/recipes/recipe_obsolete.json @@ -2499,5 +2499,10 @@ "type": "recipe", "result": "bone_plate", "obsolete": true + }, + { + "type": "recipe", + "result": "slam_shotgun", + "obsolete": true } ] diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index a91bade313322..60147c164d97d 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -274,7 +274,7 @@ "batch_time_factors": [ 83, 3 ], "flags": [ "BLIND_EASY" ], "tools": [ [ [ "rock_quern", -1 ], [ "clay_quern", -1 ] ] ], - "components": [ [ [ "chitin_piece", 1 ], [ "acidchitin_piece", 1 ] ] ] + "components": [ [ [ "chitin_piece", 1 ], [ "acidchitin_piece", 1 ], [ "endochitin", 1 ] ] ] }, { "type": "recipe", @@ -290,7 +290,7 @@ "batch_time_factors": [ 83, 3 ], "flags": [ "BLIND_EASY" ], "tools": [ [ [ "mortar_pestle", -1 ] ] ], - "components": [ [ [ "chitin_piece", 1 ] ] ] + "components": [ [ [ "chitin_piece", 1 ], [ "acidchitin_piece", 1 ], [ "endochitin", 1 ] ] ] }, { "type": "recipe", @@ -452,7 +452,7 @@ "subcategory": "CSC_OTHER_TOOLS", "skill_used": "fabrication", "difficulty": 1, - "time": "20 m", + "time": "5 m", "reversible": true, "autolearn": true, "qualities": [ { "id": "CUT", "level": 1 } ], @@ -491,6 +491,7 @@ "difficulty": 2, "time": "25 m", "autolearn": true, + "reversible": true, "using": [ [ "soldering_standard", 10 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "SCREW", "level": 1 } ], "components": [ @@ -776,6 +777,7 @@ "difficulty": 3, "time": "1 h", "autolearn": true, + "proficiencies": [ { "proficiency": "prof_knapping", "required": true } ], "book_learn": [ [ "mag_survival", 1 ], [ "atomic_survival", 1 ], [ "textbook_carpentry", 2 ] ], "qualities": [ { "id": "HAMMER", "level": 1 } ], "components": [ @@ -1582,7 +1584,7 @@ "decomp_learn": 2, "autolearn": true, "using": [ [ "cordage", 1 ] ], - "components": [ [ [ "shotgun_d", 1 ] ], [ [ "shot_00", 2 ], [ "shot_slug", 2 ], [ "shot_flechette", 2 ] ] ] + "components": [ [ [ "slamfire_shotgun_d", 1 ] ], [ [ "shot_00", 2 ], [ "shot_slug", 2 ], [ "shot_flechette", 2 ] ] ] }, { "type": "recipe", @@ -3106,12 +3108,12 @@ "category": "CC_OTHER", "subcategory": "CSC_OTHER_TOOLS", "skill_used": "fabrication", - "difficulty": 3, - "time": "30 m", + "difficulty": 1, + "autolearn": true, + "time": "2 m", "reversible": true, "book_learn": [ [ "mag_survival", 4 ], [ "atomic_survival", 3 ], [ "textbook_survival", 2 ] ], - "qualities": [ { "id": "HAMMER", "level": 1 } ], - "components": [ [ [ "rope_superior", 1, "LIST" ] ], [ [ "scrap", 4 ] ] ] + "components": [ [ [ "rope_superior", 1, "LIST" ] ], [ [ "grip_hook", 4 ] ] ] }, { "type": "recipe", @@ -3656,7 +3658,7 @@ "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "salt_water", 1 ], [ "saline", 2 ], [ "salt", 2 ] ], - [ [ "raw_leather", 1 ], [ "raw_tainted_leather", 1 ], [ "raw_hleather", 1 ] ] + [ [ "raw_leather", 1 ], [ "raw_tainted_leather", 1 ], [ "raw_hleather", 1 ], [ "raw_demihumanleather", 1 ] ] ] }, { @@ -4326,7 +4328,7 @@ "time": "1 m", "autolearn": true, "reversible": true, - "components": [ [ [ "2x4", 10 ] ], [ [ "rope_6", 1 ] ] ], + "components": [ [ [ "2x4", 10 ] ], [ [ "rope_any_short", 1, "LIST" ] ] ], "flags": [ "BLIND_EASY" ] }, { @@ -4338,7 +4340,19 @@ "time": "1 m", "autolearn": true, "reversible": true, - "components": [ [ [ "stick", 10 ] ], [ [ "rope_6", 1 ] ] ], + "components": [ [ [ "stick", 10 ] ], [ [ "rope_any_short", 1, "LIST" ] ] ], + "flags": [ "BLIND_EASY" ] + }, + { + "result": "bundle_branch_long", + "type": "recipe", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "reversible": true, + "components": [ [ [ "stick_long", 5 ] ], [ [ "rope_any_short", 2, "LIST" ] ] ], "flags": [ "BLIND_EASY" ] }, { @@ -4609,5 +4623,33 @@ "autolearn": true, "tools": [ [ [ "tongs", -1 ] ], [ [ "crucible", -1 ], [ "crucible_clay", -1 ] ], [ [ "sheet_metal", -1 ] ], [ [ "forge", 75 ] ] ], "components": [ [ [ "plastic_chunk", 200 ] ] ] + }, + { + "type": "recipe", + "result": "funnel_separation", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_TOOLS", + "skill_used": "fabrication", + "difficulty": 7, + "time": "1 h", + "book_learn": [ [ "glassblowing_book", 5 ] ], + "qualities": [ { "id": "CHISEL", "level": 3 } ], + "tools": [ [ [ "tongs", -1 ] ], [ [ "pipe", -1 ] ], [ [ "crucible", -1 ], [ "crucible_clay", -1 ] ], [ [ "forge", 75 ] ] ], + "components": [ + [ [ "glass_shard", 3 ], [ "pipe_glass", 1 ], [ "flask_glass", 3 ], [ "test_tube", 6 ], [ "marble", 75 ] ], + [ [ "stopcock", 1 ] ] + ] + }, + { + "type": "recipe", + "result": "stopcock", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_OTHER", + "skill_used": "fabrication", + "difficulty": 4, + "time": "30 m", + "autolearn": true, + "tools": [ [ [ "mold_plastic", -1 ] ], [ [ "surface_heat", 5, "LIST" ] ] ], + "components": [ [ [ "plastic_chunk", 1 ] ] ] } ] diff --git a/data/json/recipes/recipe_vehicle.json b/data/json/recipes/recipe_vehicle.json index e75d6d4b01894..85624474a32ac 100644 --- a/data/json/recipes/recipe_vehicle.json +++ b/data/json/recipes/recipe_vehicle.json @@ -651,6 +651,7 @@ "skill_used": "fabrication", "difficulty": 1, "time": "45 m", + "proficiencies": [ { "proficiency": "prof_blacksmithing", "time_multiplier": 10.0 } ], "reversible": true, "autolearn": true, "using": [ [ "steel_standard", 20 ] ], @@ -668,6 +669,7 @@ "skill_used": "fabrication", "difficulty": 1, "time": "1 h 30 m", + "proficiencies": [ { "proficiency": "prof_blacksmithing", "time_multiplier": 10.0 } ], "reversible": true, "autolearn": true, "qualities": [ { "id": "GLARE", "level": 2 } ], diff --git a/data/json/recipes/weapon/ranged.json b/data/json/recipes/weapon/ranged.json index cdf1df3b28f6e..ac8a885227af8 100644 --- a/data/json/recipes/weapon/ranged.json +++ b/data/json/recipes/weapon/ranged.json @@ -260,13 +260,13 @@ }, { "type": "recipe", - "result": "slam_shotgun", + "result": "slamfire_shotgun", "category": "CC_WEAPON", "subcategory": "CSC_WEAPON_RANGED", "skill_used": "mechanics", "skills_required": [ [ "gun", 1 ] ], "difficulty": 1, - "time": "2 h", + "time": "4 h", "autolearn": true, "book_learn": [ [ "manual_shotgun", 1 ] ], "qualities": [ @@ -274,7 +274,7 @@ { "id": "GLARE", "level": 2 }, { "id": "HAMMER", "level": 2 }, { "id": "FILE", "level": 1 }, - { "id": "WELD", "level": 2 } + { "id": "WELD", "level": 1 } ], "tools": [ [ @@ -301,5 +301,193 @@ ] ], "components": [ [ [ "pipe", 2 ] ], [ [ "nail", 1 ] ], [ [ "scrap", 3 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun", + "id_suffix": "without_welding", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "time": "2 h", + "autolearn": true, + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "DRILL", "level": 2 } + ], + "tools": [ + [ + [ "shot_00", -1 ], + [ "shot_bird", -1 ], + [ "shot_dragon", -1 ], + [ "shot_flechette", -1 ], + [ "shot_slug", -1 ], + [ "shot_scrap", -1 ], + [ "shot_he", -1 ], + [ "shot_beanbag", -1 ], + [ "reloaded_shot_00", -1 ], + [ "reloaded_shot_bird", -1 ], + [ "reloaded_shot_dragon", -1 ], + [ "reloaded_shot_flechette", -1 ], + [ "reloaded_shot_slug", -1 ], + [ "bp_shot_00", -1 ], + [ "bp_shot_bird", -1 ], + [ "bp_shot_dragon", -1 ], + [ "bp_shot_flechette", -1 ], + [ "bp_shot_slug", -1 ], + [ "bp_shot_scrap", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "pipe", 2 ] ], [ [ "nail", 1 ] ], [ [ "pipe_fittings", 1 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "id_suffix": "with_tape", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "time": "1 h", + "autolearn": true, + "components": [ [ [ "four_winds_shotgun", 2 ] ], [ [ "duct_tape", 100 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "difficulty": 2, + "time": "6 h", + "autolearn": true, + "book_learn": [ [ "manual_shotgun", 1 ] ], + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "GLARE", "level": 2 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WELD", "level": 1 } + ], + "tools": [ + [ + [ "shot_00", -1 ], + [ "shot_bird", -1 ], + [ "shot_dragon", -1 ], + [ "shot_flechette", -1 ], + [ "shot_slug", -1 ], + [ "shot_scrap", -1 ], + [ "shot_he", -1 ], + [ "shot_beanbag", -1 ], + [ "reloaded_shot_00", -1 ], + [ "reloaded_shot_bird", -1 ], + [ "reloaded_shot_dragon", -1 ], + [ "reloaded_shot_flechette", -1 ], + [ "reloaded_shot_slug", -1 ], + [ "bp_shot_00", -1 ], + [ "bp_shot_bird", -1 ], + [ "bp_shot_dragon", -1 ], + [ "bp_shot_flechette", -1 ], + [ "bp_shot_slug", -1 ], + [ "bp_shot_scrap", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "pipe", 4 ] ], [ [ "nail", 2 ] ], [ [ "scrap", 6 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "id_suffix": "welded_together", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "difficulty": 2, + "time": "6 h", + "autolearn": true, + "book_learn": [ [ "manual_shotgun", 1 ] ], + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "GLARE", "level": 2 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WELD", "level": 1 } + ], + "tools": [ + [ + [ "shot_00", -1 ], + [ "shot_bird", -1 ], + [ "shot_dragon", -1 ], + [ "shot_flechette", -1 ], + [ "shot_slug", -1 ], + [ "shot_scrap", -1 ], + [ "shot_he", -1 ], + [ "shot_beanbag", -1 ], + [ "reloaded_shot_00", -1 ], + [ "reloaded_shot_bird", -1 ], + [ "reloaded_shot_dragon", -1 ], + [ "reloaded_shot_flechette", -1 ], + [ "reloaded_shot_slug", -1 ], + [ "bp_shot_00", -1 ], + [ "bp_shot_bird", -1 ], + [ "bp_shot_dragon", -1 ], + [ "bp_shot_flechette", -1 ], + [ "bp_shot_slug", -1 ], + [ "bp_shot_scrap", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "four_winds_shotgun", 2 ] ], [ [ "scrap", 1 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "id_suffix": "bolted_and_welded", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "time": "2 h", + "autolearn": true, + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "DRILL", "level": 2 }, + { "id": "WELD", "level": 1 } + ], + "tools": [ + [ + [ "shot_00", -1 ], + [ "shot_bird", -1 ], + [ "shot_dragon", -1 ], + [ "shot_flechette", -1 ], + [ "shot_slug", -1 ], + [ "shot_scrap", -1 ], + [ "shot_he", -1 ], + [ "shot_beanbag", -1 ], + [ "reloaded_shot_00", -1 ], + [ "reloaded_shot_bird", -1 ], + [ "reloaded_shot_dragon", -1 ], + [ "reloaded_shot_flechette", -1 ], + [ "reloaded_shot_slug", -1 ], + [ "bp_shot_00", -1 ], + [ "bp_shot_bird", -1 ], + [ "bp_shot_dragon", -1 ], + [ "bp_shot_flechette", -1 ], + [ "bp_shot_slug", -1 ], + [ "bp_shot_scrap", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "pipe", 4 ] ], [ [ "nail", 2 ] ], [ [ "pipe_fittings", 2 ] ], [ [ "scrap", 3 ] ] ] } ] diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index 4d45cca7a5304..3b0ec60531d91 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -499,8 +499,8 @@ "mx_prison_bus": 15 } }, + "bridgehead_ground": { "chance": 5, "extras": { "mx_minefield": 100 } }, "road_nesw_manhole": { "chance": 20, "extras": { "mx_city_trap": 100 } }, - "bridge": { "chance": 5, "extras": { "mx_minefield": 100 } }, "build": { "chance": 90, "extras": { @@ -918,7 +918,22 @@ "base_acid": 0.0, "base_wind": 3.4, "base_wind_distrib_peaks": 80, - "base_wind_season_variation": 50 + "base_wind_season_variation": 50, + "weather_types": [ + "clear", + "sunny", + "cloudy", + "light_drizzle", + "drizzle", + "rain", + "thunder", + "lightning", + "acid_drizzle", + "acid_rain", + "flurries", + "snowing", + "snowstorm" + ] }, "overmap_feature_flag_settings": { "clear_blacklist": false, "blacklist": [ ], "clear_whitelist": false, "whitelist": [ ] } } diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 832f913805a87..c1e103dddfc8f 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -167,13 +167,22 @@ "id": "meat_offal", "type": "requirement", "//": "Anything you might consider offal or intestines.", - "components": [ [ [ "lung", 4 ], [ "liver", 4 ], [ "kidney", 4 ], [ "sweetbread", 4 ], [ "offal", 1 ] ] ] + "components": [ + [ + [ "meat_lung", 4, "LIST" ], + [ "liver", 4 ], + [ "kidney", 4 ], + [ "sweetbread", 4 ], + [ "offal", 1 ], + [ "mutant_bug_organs", 1 ] + ] + ] }, { "id": "meat_raw_steak", "type": "requirement", "//": "An unbroken slab of raw meat. For when scraps just aren't good enough.", - "components": [ [ [ "meat", 1 ], [ "mutant_meat", 1 ], [ "human_flesh", 1 ], [ "mutant_human_flesh", 1 ] ] ] + "components": [ [ [ "meat", 1 ], [ "mutant_meat", 1 ], [ "human_flesh", 1 ], [ "mutant_human_flesh", 1 ], [ "demihuman_flesh", 1 ] ] ] }, { "id": "meat_red_raw", @@ -187,6 +196,51 @@ "//": "Anything you might consider raw 'red' meat. About 250mL of meat.", "components": [ [ [ "meat_red_raw", 1, "LIST" ], [ "rehydrated_meat", 1 ], [ "meat_canned", 1 ] ] ] }, + { + "id": "meat_lung", + "type": "requirement", + "//": "Anything you might consider raw lung. About 250mL of lungs.", + "components": [ [ [ "lung", 1 ], [ "mutant_bug_lungs", 1 ] ] ] + }, + { + "id": "meat_stomach", + "type": "requirement", + "//": "Anything you might consider a raw stomach. About 500mL of stomachs.", + "components": [ [ [ "meat_stomach_small", 2, "LIST" ], [ "meat_stomach_large", 1, "LIST" ] ] ] + }, + { + "id": "meat_stomach_cooked", + "type": "requirement", + "//": "Anything you might consider a cooked stomach. About 500mL of stomachs.", + "components": [ [ [ "meat_stomach_small", 2, "LIST" ], [ "meat_stomach_large", 1, "LIST" ] ] ] + }, + { + "id": "meat_stomach_boiled", + "type": "requirement", + "//": "Anything you might consider a boiled stomach. About 500mL of stomachs.", + "components": [ + [ + [ "small_stomach_boiled", 2 ], + [ "stomach_boiled", 1 ], + [ "small_hstomach_boiled", 2 ], + [ "hstomach_boiled", 1 ], + [ "small_demihuman_stomach_boiled", 2 ], + [ "demihuman_stomach_boiled", 1 ] + ] + ] + }, + { + "id": "meat_stomach_large", + "type": "requirement", + "//": "Anything you might consider a small raw stomach.", + "components": [ [ [ "stomach_large", 1 ], [ "hstomach_large", 1 ], [ "demihuman_stomach_large", 1 ] ] ] + }, + { + "id": "meat_stomach_small", + "type": "requirement", + "//": "Anything you might consider a small raw stomach.", + "components": [ [ [ "stomach", 1 ], [ "hstomach", 1 ], [ "demihuman_stomach", 1 ] ] ] + }, { "id": "meat_nofish", "type": "requirement", @@ -196,7 +250,7 @@ [ "meat_red", 1, "LIST" ], [ "liver", 5 ], [ "kidney", 5 ], - [ "lung", 5 ], + [ "meat_lung", 5, "LIST" ], [ "sweetbread", 5 ], [ "bacon", 4 ], [ "lunchmeat", 5 ], @@ -223,6 +277,7 @@ [ "mutant_meat_scrap_cooked", 10 ], [ "human_cooked", 1 ], [ "mutant_human_cooked", 1 ], + [ "demihuman_cooked", 1 ], [ "meat_pickled", 1 ], [ "meat_smoked", 1 ], [ "meat_salted", 1 ], @@ -398,19 +453,27 @@ "id": "any_fat", "type": "requirement", "//": "Any type of raw fat.", - "components": [ [ [ "fat", 1 ], [ "mutant_fat", 1 ], [ "fat_tainted", 1 ], [ "edible_fat", 1, "LIST" ], [ "fat_tainted", 1 ] ] ] + "components": [ [ [ "edible_fat", 1, "LIST" ], [ "fat_tainted", 1 ] ] ] }, { "id": "edible_fat", "type": "requirement", "//": "Any type of edible raw fat.", - "components": [ [ [ "fat", 1 ], [ "mutant_fat", 1 ], [ "human_fat", 1 ], [ "mutant_human_fat", 1 ] ] ] + "components": [ [ [ "fat", 1 ], [ "mutant_fat", 1 ], [ "human_fat", 1 ], [ "mutant_human_fat", 1 ], [ "demihuman_fat", 1 ] ] ] }, { "id": "edible_tallow", "type": "requirement", "//": "Any type of edible tallow.", - "components": [ [ [ "tallow", 1 ], [ "mutant_tallow", 1 ], [ "human_tallow", 1 ], [ "mutant_human_tallow", 1 ] ] ] + "components": [ + [ + [ "tallow", 1 ], + [ "mutant_tallow", 1 ], + [ "human_tallow", 1 ], + [ "mutant_human_tallow", 1 ], + [ "demihuman_tallow", 1 ] + ] + ] }, { "id": "any_tallow", @@ -422,7 +485,7 @@ "id": "edible_lard", "type": "requirement", "//": "Lard that is safe for consumption.", - "components": [ [ [ "lard", 1 ], [ "mutant_lard", 1 ], [ "human_lard", 1 ], [ "mutant_human_lard", 1 ] ] ] + "components": [ [ [ "lard", 1 ], [ "mutant_lard", 1 ], [ "human_lard", 1 ], [ "mutant_human_lard", 1 ], [ "demihuman_lard", 1 ] ] ] }, { "id": "edible_tallow_lard", diff --git a/data/json/requirements/materials.json b/data/json/requirements/materials.json index fee059bafc45a..61c2947ef1a2f 100644 --- a/data/json/requirements/materials.json +++ b/data/json/requirements/materials.json @@ -119,6 +119,12 @@ "//": "Materials used for lashing, when choice of makeshift rope is sensible, per 216 g/180 cm of rope.", "components": [ [ [ "rope_6", 1 ], [ "vine_6", 1 ], [ "rope_makeshift_6", 1 ] ] ] }, + { + "id": "rope_any_short", + "type": "requirement", + "//": "Materials used for lashing, when any rope or wire is sensible, per 216 g/180 cm of rope.", + "components": [ [ [ "rope_6", 1 ], [ "vine_6", 1 ], [ "rope_makeshift_6", 1 ], [ "wire", 1 ] ] ] + }, { "id": "rope_superior", "type": "requirement", diff --git a/data/json/scenarios.json b/data/json/scenarios.json index 1c4a7b522cf01..b976718303e29 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -195,7 +195,7 @@ "sloc_cemetery" ], "professions": [ "svictim", "tweaker" ], - "flags": [ "FIRE_START", "INFECTED", "BAD_DAY", "CHALLENGE", "CITY_START" ] + "flags": [ "FIRE_START", "INFECTED", "BAD_DAY", "CHALLENGE", "CITY_START", "LONE_START" ] }, { "type": "scenario", diff --git a/data/json/snippets/fliers.json b/data/json/snippets/fliers.json index 54ca6acac2266..f4cd2afd3ed6a 100644 --- a/data/json/snippets/fliers.json +++ b/data/json/snippets/fliers.json @@ -2,7 +2,6 @@ { "type": "snippet", "category": "flier", - "//": "Missing flier_ 27, 29, 30", "text": [ { "id": "flier_1", @@ -108,10 +107,22 @@ "id": "flier_26", "text": "This is an advertisement for Rivtech brand ammunition. It shows a picture of an armored steel plate with a gaping hole blasted through the middle. Sitting beside the plate is a block of brightly colored caseless ammunition. The caption reads: \"Rivtech 8x40mm caseless. Nothing else comes close.\"" }, + { + "id": "flier_27", + "text": "This is an advertisement for SUDS Laundromat. It shows words surrounded by bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! 50% off on all washers and driers!\"" + }, { "id": "flier_28", "text": "This is a propaganda poster showing the Northrop Dispatch's military variant. It depicts the iconic dark green, arachnoid dispatch, standing before a fence and facing away from the camera as blurring machines rush forward from its back towards black silhouettes menacing on the horizon. It reads: \"WE ARE HERE TO PROTECT YOU.\"" }, + { + "id": "flier_29", + "text": "This is an advertisement for Iron Gym. It shows pictures of people performing various exercises such as running, yoga and weight lifting. It reads: \"I lift things up and put them down!\"" + }, + { + "id": "flier_30", + "text": "This is an advertisement for Space Time Inc. It has pictures of astronauts floating around a spaceship with the Moon in the background. It reads: \"Own your own piece of the Moon! For only $29.99 a month, you can have prime real estate amongst the stars!\"" + }, { "id": "flier_31", "text": "This is a public notice from the Centers for Disease Control. Its message, repeated in several languages, reads: \"BOIL WATER ADVISORY. An unidentified agent has contaminated local groundwater. It is highly infectious and can cause erratic and violent behavior. Boil all water, and isolate any loved ones showing concerning symptoms. Visit www.cdc.gov/cdda-advisory for more information.\"" diff --git a/data/json/test_regions.json b/data/json/test_regions.json index d46d4f3782a68..6d606d5fdea3e 100644 --- a/data/json/test_regions.json +++ b/data/json/test_regions.json @@ -127,7 +127,27 @@ "s_lot": 6 } }, - "weather": { "base_temperature": 8.0, "base_humidity": 40.0, "base_pressure": 1015.0, "base_acid": 0.0 }, + "weather": { + "base_temperature": 8.0, + "base_humidity": 40.0, + "base_pressure": 1015.0, + "base_acid": 0.0, + "weather_types": [ + "clear", + "sunny", + "cloudy", + "light_drizzle", + "drizzle", + "rain", + "thunder", + "lightning", + "acid_drizzle", + "acid_rain", + "flurries", + "snowing", + "snowstorm" + ] + }, "overmap_feature_flag_settings": { "clear_blacklist": false, "blacklist": [ ], "clear_whitelist": false, "whitelist": [ ] } }, { @@ -180,8 +200,6 @@ ",": "t_pavement_y", "_": "t_pavement", "r": "t_floor", - "6": "t_console", - "x": "t_console_broken", "^": "t_floor", ".": "t_floor", "-": "t_wall", @@ -201,6 +219,8 @@ "s": "t_sidewalk" }, "furniture": { + "6": "f_console", + "x": "f_console_broken", "d": "f_dumpster", "O": "f_oven", "r": "f_rack", diff --git a/data/json/traps.json b/data/json/traps.json index 3e3d2d7d46e11..7a547c334bcee 100644 --- a/data/json/traps.json +++ b/data/json/traps.json @@ -265,7 +265,7 @@ "avoidance": 5, "difficulty": 6, "action": "shotgun", - "drops": [ "string_36", "shotgun_d", { "item": "shot_00", "quantity": 2, "charges": 1 } ], + "drops": [ "string_36", "slamfire_shotgun_d", { "item": "shot_00", "quantity": 2, "charges": 1 } ], "vehicle_data": { "chance": 70, "damage": 300, @@ -287,7 +287,7 @@ "avoidance": 5, "difficulty": 6, "action": "shotgun", - "drops": [ "string_36", "shotgun_d", { "item": "shot_00", "quantity": 1, "charges": 1 } ], + "drops": [ "string_36", "slamfire_shotgun_d", { "item": "shot_00", "quantity": 1, "charges": 1 } ], "vehicle_data": { "chance": 70, "damage": 300, @@ -296,7 +296,7 @@ "sound_type": "fire_gun", "sound_variant": "shotgun_d", "remove_trap": true, - "spawn_items": [ "shotgun_d", "string_6" ] + "spawn_items": [ "slamfire_shotgun_d", "string_6" ] } }, { @@ -310,7 +310,7 @@ "avoidance": 5, "difficulty": 6, "action": "shotgun", - "drops": [ "string_36", "shotgun_s", { "item": "shot_00", "quantity": 1, "charges": 1 } ], + "drops": [ "string_36", "slamfire_shotgun", { "item": "shot_00", "quantity": 1, "charges": 1 } ], "vehicle_data": { "chance": 70, "damage": 300, @@ -319,7 +319,7 @@ "sound_type": "fire_gun", "sound_variant": "shotgun_s", "remove_trap": true, - "spawn_items": [ "shotgun_s", "string_6" ] + "spawn_items": [ "four_winds_shotgun", "string_6" ] } }, { diff --git a/data/json/vehicle_groups.json b/data/json/vehicle_groups.json index 2d85139ae9b96..ba344589253dc 100644 --- a/data/json/vehicle_groups.json +++ b/data/json/vehicle_groups.json @@ -13,6 +13,7 @@ [ "suv_electric", 200 ], [ "suv_electric", 120 ], [ "car_mini", 400 ], + [ "car_hybrid", 500 ], [ "beetle", 500 ], [ "bicycle", 800 ], [ "bicycle_dirt", 200 ], @@ -97,7 +98,8 @@ [ "cube_van", 500 ], [ "cube_van_cheap", 500 ], [ "hippie_van", 500 ], - [ "4x4_car", 500 ] + [ "4x4_car", 500 ], + [ "car_hybrid", 500 ] ] }, { @@ -113,6 +115,7 @@ [ "car_anmlcmpt", 250 ], [ "car_hatch", 1000 ], [ "electric_car", 500 ], + [ "car_hybrid", 500 ], [ "car_sports", 1000 ], [ "car_sports_electric", 300 ], [ "pickup", 600 ], @@ -159,6 +162,7 @@ [ "car_hatch", 500 ], [ "car_mini", 250 ], [ "electric_car", 500 ], + [ "car_hybrid", 400 ], [ "beetle", 300 ], [ "car_sports", 100 ], [ "car_sports_electric", 50 ], @@ -225,6 +229,7 @@ [ "car_anmlcmpt", 100 ], [ "car_hatch", 500 ], [ "electric_car", 750 ], + [ "car_hybrid", 500 ], [ "hippie_van", 750 ], [ "golf_cart", 300 ], [ "scooter", 300 ], @@ -327,6 +332,7 @@ [ "car_hatch", 750 ], [ "car_chassis", 2000 ], [ "electric_car", 400 ], + [ "car_hybrid", 400 ], [ "car_sports", 400 ], [ "car_sports_electric", 100 ], [ "car_racing_electric", 5 ], @@ -350,6 +356,7 @@ [ "car_sports", 200 ], [ "suv", 400 ], [ "car_mini", 250 ], + [ "car_hybrid", 200 ], [ "rv", 250 ], [ "meth_lab", 50 ], [ "beetle", 400 ], @@ -369,6 +376,7 @@ [ "car_hatch", 475 ], [ "car_anmlcmpt", 150 ], [ "electric_car", 100 ], + [ "car_hybrid", 100 ], [ "suv", 800 ], [ "suv_electric", 100 ], [ "suv_electric_rack", 100 ], @@ -392,6 +400,7 @@ [ "suv", 400 ], [ "rv", 200 ], [ "car_sports", 300 ], + [ "car_hybrid", 200 ], [ "cube_van_cheap", 200 ], [ "pickup", 500 ], [ "hippie_van", 300 ] @@ -409,6 +418,7 @@ [ "car_hatch", 500 ], [ "car_anmlcmpt", 150 ], [ "electric_car", 750 ], + [ "car_hybrid", 500 ], [ "hippie_van", 750 ], [ "motorcycle", 500 ], [ "superbike", 50 ], @@ -570,6 +580,7 @@ [ "car", 2000 ], [ "car_hatch", 1000 ], [ "electric_car", 500 ], + [ "car_hybrid", 500 ], [ "suv", 800 ], [ "suv_electric", 200 ], [ "car_mini", 400 ], @@ -600,6 +611,7 @@ [ "4x4_car", 200 ], [ "car_sports_electric", 100 ], [ "car_mini", 375 ], + [ "car_hybrid", 200 ], [ "beetle", 750 ], [ "car", 1500 ], [ "car_hatch", 750 ], @@ -630,6 +642,7 @@ [ "car", 1000 ], [ "car_hatch", 500 ], [ "electric_car", 500 ], + [ "car_hybrid", 400 ], [ "suv", 800 ], [ "suv_electric", 200 ], [ "car_mini", 400 ], @@ -666,6 +679,7 @@ [ "car", 2000 ], [ "car_hatch", 1000 ], [ "electric_car", 500 ], + [ "car_hybrid", 400 ], [ "suv", 800 ], [ "suv_electric", 200 ], [ "car_mini", 400 ], @@ -692,6 +706,7 @@ [ "car", 2000 ], [ "car_hatch", 1000 ], [ "electric_car", 500 ], + [ "car_hybrid", 400 ], [ "car_mini", 250 ], [ "suv", 800 ], [ "suv_electric", 200 ], @@ -711,6 +726,7 @@ "vehicles": [ [ "car", 500 ], [ "electric_car", 100 ], + [ "car_hybrid", 100 ], [ "car_sports", 300 ], [ "car_sports_electric", 300 ], [ "suv", 500 ], diff --git a/data/json/vehicleparts/vehicle_parts.json b/data/json/vehicleparts/vehicle_parts.json index ad3972da7ed0f..78eda76c26d9c 100644 --- a/data/json/vehicleparts/vehicle_parts.json +++ b/data/json/vehicleparts/vehicle_parts.json @@ -1872,6 +1872,35 @@ "flags": [ "ON_CONTROLS", "SECURITY", "FOLDABLE", "ENABLED_DRAINS_EPOWER" ], "breaks_into": "ig_vp_device" }, + { + "type": "vehicle_part", + "id": "smart_engine_controller", + "name": { "str": "smart engine controller" }, + "symbol": "'", + "color": "light_gray", + "broken_symbol": "'", + "broken_color": "red", + "damage_modifier": 10, + "durability": 35, + "description": "Electronic module that automatically switches combustion and electric engines on and off minimizing fuel consumption and optimizing power output and battery charge rate. Must be turned on to work. Simplified ruleset: 1. When throttling, maximize acceleration. 2. Keep battery at 90%. 3. Minimize fuel consumption.", + "epower": -25, + "folded_volume": 1, + "item": "processor", + "requirements": { + "install": { + "skills": [ [ "mechanics", 4 ], [ "electronics", 4 ] ], + "time": "5 m", + "qualities": [ { "id": "SCREW_FINE", "level": 1 } ] + }, + "removal": { + "skills": [ [ "mechanics", 4 ], [ "electronics", 4 ] ], + "time": "5 m", + "qualities": [ { "id": "SCREW_FINE", "level": 1 } ] + } + }, + "flags": [ "ON_CONTROLS", "FOLDABLE", "ENABLED_DRAINS_EPOWER", "SMART_ENGINE_CONTROLLER" ], + "breaks_into": "ig_vp_device" + }, { "type": "vehicle_part", "id": "seatbelt_heavyduty", diff --git a/data/json/vehicleparts/vp_flags.json b/data/json/vehicleparts/vp_flags.json index 50299b7a1a5d6..34b5a82490319 100644 --- a/data/json/vehicleparts/vp_flags.json +++ b/data/json/vehicleparts/vp_flags.json @@ -54,6 +54,12 @@ "context": [ "vehicle_part" ], "info": "With a seat or saddle, you drive from here. You can 'e'xamine the tile to access the controls, or use the vehicle control key (default '^')." }, + { + "id": "SMART_ENGINE_CONTROLLER", + "type": "json_flag", + "context": [ "vehicle_part" ], + "info": "When active, turns engines on and off automatically." + }, { "id": "COVERED", "type": "json_flag", diff --git a/data/json/vehicles/cars.json b/data/json/vehicles/cars.json index b7965cc0d8f3f..e0467dd473ae0 100644 --- a/data/json/vehicles/cars.json +++ b/data/json/vehicles/cars.json @@ -467,6 +467,62 @@ { "x": -3, "y": 2, "parts": [ "wheel_mount_medium", "wheel" ] } ] }, + { + "id": "car_hybrid", + "type": "vehicle", + "name": "Hybrid Car", + "blueprint": [ + [ "o-++-o" ], + [ "+=##'|" ], + [ "+=##'|" ], + [ "o-++-o" ] + ], + "parts": [ + { "x": 0, "y": 0, "part": "frame_vertical_2" }, + { "x": 0, "y": 0, "parts": [ "reclining_seat", "seatbelt" ] }, + { + "x": 0, + "y": 0, + "parts": [ "controls", "dashboard", "vehicle_clock", "smart_engine_controller", "stereo", "horn_car", "vehicle_alarm" ] + }, + { "x": 0, "y": 0, "part": "roof" }, + { "x": 0, "y": 1, "parts": [ "frame_vertical_2", "reclining_seat", "seatbelt", "roof" ] }, + { "x": 0, "y": -1, "parts": [ "frame_vertical", "door" ] }, + { "x": 0, "y": 2, "parts": [ "frame_vertical", "door" ] }, + { "x": -1, "y": 0, "parts": [ "frame_vertical_2", "seat", "seatbelt", "roof" ] }, + { "x": -1, "y": 1, "parts": [ "frame_vertical_2", "seat", "seatbelt", "roof" ] }, + { "x": -1, "y": -1, "parts": [ "frame_vertical", "door" ] }, + { "x": -1, "y": 2, "parts": [ "frame_vertical", "door" ] }, + { "x": 1, "y": 0, "parts": [ "frame_horizontal", "windshield" ] }, + { "x": 1, "y": 1, "parts": [ "frame_horizontal", "windshield" ] }, + { "x": 1, "y": -1, "parts": [ "frame_vertical", "windshield" ] }, + { "x": 1, "y": 2, "parts": [ "frame_vertical", "windshield" ] }, + { "x": 2, "y": 0, "parts": [ "frame_horizontal", "halfboard_horizontal" ] }, + { "x": 2, "y": 0, "parts": [ "engine_inline4", "alternator_truck" ] }, + { "x": 2, "y": 1, "parts": [ "frame_horizontal", "engine_electric", "halfboard_horizontal" ] }, + { "x": 2, "y": -1, "parts": [ "frame_nw", "halfboard_nw", "headlight" ] }, + { "x": 2, "y": -1, "parts": [ "wheel_mount_medium_steerable", "wheel" ] }, + { "x": 2, "y": 2, "parts": [ "frame_ne", "halfboard_ne", "headlight" ] }, + { "x": 2, "y": 2, "parts": [ "wheel_mount_medium_steerable", "wheel" ] }, + { "x": -2, "y": 0, "parts": [ "frame_vertical", "medium_storage_battery", "trunk", "muffler", "roof" ] }, + { "x": -2, "y": 1, "parts": [ "frame_vertical", "medium_storage_battery", "trunk", "roof" ] }, + { "x": -2, "y": -1, "parts": [ "frame_vertical", "halfboard_vertical", "tank" ] }, + { "x": -2, "y": 2, "parts": [ "frame_vertical", "halfboard_vertical" ] }, + { "x": -3, "y": -1, "parts": [ "frame_horizontal", "halfboard_sw", "wheel_mount_medium", "wheel" ] }, + { "x": -3, "y": 0, "parts": [ "frame_horizontal", "door_trunk" ] }, + { "x": -3, "y": 1, "parts": [ "frame_horizontal", "door_trunk" ] }, + { "x": -3, "y": 2, "parts": [ "frame_horizontal", "halfboard_se", "wheel_mount_medium", "wheel" ] } + ], + "items": [ + { "x": 0, "y": 0, "chance": 14, "item_groups": [ "car_misc" ] }, + { "x": 0, "y": 0, "chance": 5, "item_groups": [ "snacks" ] }, + { "x": 0, "y": 1, "chance": 8, "item_groups": [ "car_misc" ] }, + { "x": 0, "y": 1, "chance": 2, "item_groups": [ "fast_food" ] }, + { "x": -2, "y": 0, "chance": 11, "item_groups": [ "car_kit" ] }, + { "x": -2, "y": 1, "chance": 15, "item_groups": [ "car_kit" ] }, + { "x": -2, "y": 1, "chance": 15, "items": [ "jack_small", "wheel" ] } + ] + }, { "id": "car_mini", "type": "vehicle", diff --git a/data/json/vehicles/emergency.json b/data/json/vehicles/emergency.json index cfc02a7289754..a6028b961397f 100644 --- a/data/json/vehicles/emergency.json +++ b/data/json/vehicles/emergency.json @@ -151,6 +151,7 @@ { "x": -2, "y": 0, "chance": 25, "item_groups": [ "ambulance_equipment" ] }, { "x": -3, "y": 0, "chance": 15, "items": [ "bandages" ] }, { "x": -3, "y": 0, "chance": 15, "items": [ "1st_aid" ] }, + { "x": -3, "y": 0, "chance": 15, "items": [ "ifak" ] }, { "x": -3, "y": 0, "chance": 5, "items": [ "adrenaline_injector" ] }, { "x": -3, "y": 0, "chance": 5, "items": [ "oxycodone" ] }, { "x": -3, "y": 0, "chance": 5, "items": [ "tramadol" ] }, diff --git a/data/json/vehicles/helicopters.json b/data/json/vehicles/helicopters.json index f9769e43c3c80..cc3a99e7c62c9 100644 --- a/data/json/vehicles/helicopters.json +++ b/data/json/vehicles/helicopters.json @@ -421,7 +421,7 @@ "items": [ { "x": -1, "y": 0, "chance": 100, "items": [ "1st_aid" ] }, { "x": -1, "y": 0, "chance": 100, "items": [ "mag_firstaid" ] }, - { "x": -1, "y": 2, "chance": 100, "items": [ "1st_aid" ] }, + { "x": -1, "y": 2, "chance": 100, "items": [ "ifak" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "gloves_medical" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "ampoule" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "rx12_injector" ] }, @@ -597,7 +597,7 @@ { "x": -2, "y": 0, "chance": 100, "items": [ "bone_human" ] }, { "x": -1, "y": 0, "chance": 100, "items": [ "1st_aid" ] }, { "x": -1, "y": 0, "chance": 100, "items": [ "mag_firstaid" ] }, - { "x": -1, "y": 2, "chance": 100, "items": [ "1st_aid" ] }, + { "x": -1, "y": 2, "chance": 100, "items": [ "ifak" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "gloves_medical" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "ampoule" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "rx12_injector" ] }, @@ -781,7 +781,7 @@ "items": [ { "x": -1, "y": 0, "chance": 100, "items": [ "mag_firstaid" ] }, { "x": -1, "y": 0, "chance": 100, "items": [ "1st_aid" ] }, - { "x": -1, "y": 2, "chance": 100, "items": [ "1st_aid" ] }, + { "x": -1, "y": 2, "chance": 100, "items": [ "ifak" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "gloves_medical" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "ampoule" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "rx12_injector" ] }, @@ -895,7 +895,7 @@ { "x": -2, "y": 2, "chance": 100, "items": [ "bone_human" ] }, { "x": -1, "y": 0, "chance": 100, "items": [ "mag_firstaid" ] }, { "x": -1, "y": 0, "chance": 100, "items": [ "1st_aid" ] }, - { "x": -1, "y": 2, "chance": 100, "items": [ "1st_aid" ] }, + { "x": -1, "y": 2, "chance": 100, "items": [ "ifak" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "gloves_medical" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "ampoule" ] }, { "x": -1, "y": 2, "chance": 100, "items": [ "rx12_injector" ] }, @@ -1090,7 +1090,7 @@ { "x": -1, "y": -1, "chance": 5, "items": [ "mre_chicken_box" ] }, { "x": -1, "y": -1, "chance": 10, "items": [ "canteen" ] }, { "x": -1, "y": -1, "chance": 10, "items": [ "light_plus_battery_cell" ] }, - { "x": -1, "y": -1, "chance": 10, "items": [ "1st_aid" ] }, + { "x": -1, "y": -1, "chance": 10, "items": [ "ifak" ] }, { "x": -1, "y": -1, "chance": 10, "items": [ "mag_fieldrepair" ] }, { "x": -1, "y": -1, "chance": 15, "items": [ "e_scrap" ] }, { "x": -1, "y": -1, "chance": 7, "items": [ "screwdriver" ] }, @@ -1241,7 +1241,7 @@ { "x": -1, "y": -1, "chance": 7, "items": [ "mre_chicken_box" ] }, { "x": -1, "y": -1, "chance": 10, "items": [ "canteen" ] }, { "x": -1, "y": -1, "chance": 10, "items": [ "light_plus_battery_cell" ] }, - { "x": -1, "y": -1, "chance": 10, "items": [ "1st_aid" ] }, + { "x": -1, "y": -1, "chance": 10, "items": [ "ifak" ] }, { "x": -1, "y": -1, "chance": 7, "items": [ "mag_fieldrepair" ] }, { "x": -1, "y": -1, "chance": 15, "items": [ "e_scrap" ] }, { "x": -1, "y": -1, "chance": 7, "items": [ "screwdriver" ] }, @@ -1387,7 +1387,7 @@ { "x": -1, "y": 1, "chance": 7, "items": [ "mre_chicken_box" ] }, { "x": -1, "y": 1, "chance": 10, "items": [ "canteen" ] }, { "x": -1, "y": 1, "chance": 10, "items": [ "light_plus_battery_cell" ] }, - { "x": -1, "y": 1, "chance": 10, "items": [ "1st_aid" ] }, + { "x": -1, "y": 1, "chance": 10, "items": [ "ifak" ] }, { "x": -1, "y": 1, "chance": 7, "items": [ "mag_fieldrepair" ] }, { "x": -1, "y": 1, "chance": 15, "items": [ "e_scrap" ] }, { "x": -1, "y": 1, "chance": 7, "items": [ "screwdriver" ] }, @@ -2359,7 +2359,7 @@ { "x": -4, "y": -1, "chance": 7, "ammo": 80, "items": [ "mp3" ] }, { "x": -2, "y": -1, "chance": 7, "items": [ "aspirin" ] }, { "x": -2, "y": -1, "chance": 7, "items": [ "bandages" ] }, - { "x": -2, "y": -1, "chance": 10, "items": [ "1st_aid" ] }, + { "x": -2, "y": -1, "chance": 10, "items": [ "ifak" ] }, { "x": -2, "y": 1, "chance": 7, "items": [ "screwdriver" ] }, { "x": -2, "y": 1, "chance": 10, "items": [ "mag_fieldrepair" ] }, { "x": -2, "y": 1, "chance": 7, "items": [ "wrench" ] }, @@ -2933,7 +2933,7 @@ { "x": -3, "y": 0, "chance": 7, "items": [ "knife_combat" ] }, { "x": -1, "y": 0, "chance": 7, "items": [ "aspirin" ] }, { "x": -1, "y": 0, "chance": 7, "items": [ "bandages" ] }, - { "x": -1, "y": 0, "chance": 10, "items": [ "1st_aid" ] }, + { "x": -1, "y": 0, "chance": 10, "items": [ "ifak" ] }, { "x": -1, "y": 0, "chance": 10, "items": [ "pocket_firstaid" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "screwdriver" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "wrench" ] }, @@ -3130,7 +3130,7 @@ { "x": -3, "y": 0, "chance": 7, "items": [ "knife_combat" ] }, { "x": -1, "y": 0, "chance": 7, "items": [ "aspirin" ] }, { "x": -1, "y": 0, "chance": 7, "items": [ "bandages" ] }, - { "x": -1, "y": 0, "chance": 10, "items": [ "1st_aid" ] }, + { "x": -1, "y": 0, "chance": 10, "items": [ "ifak" ] }, { "x": -1, "y": 0, "chance": 10, "items": [ "pocket_firstaid" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "screwdriver" ] }, { "x": -1, "y": 2, "chance": 7, "items": [ "wrench" ] }, diff --git a/data/json/vitamin.json b/data/json/vitamin.json index 369b4d945b566..fe8e36e0acf72 100644 --- a/data/json/vitamin.json +++ b/data/json/vitamin.json @@ -75,5 +75,29 @@ "rate": "4 h", "flags": [ "NO_DISPLAY" ], "disease_excess": [ [ 10, 19 ], [ 20, 29 ], [ 30, 40 ] ] + }, + { + "id": "blood", + "type": "vitamin", + "vit_type": "counter", + "name": { "str": "Blood" }, + "deficiency": "hypovolemia", + "min": -50000, + "max": 0, + "rate": "-6 s", + "flags": [ "NO_DISPLAY" ], + "disease": [ [ -5000, -7500 ], [ -7510, -15000 ], [ -15010, -20000 ], [ -20010, -50000 ] ] + }, + { + "id": "redcells", + "type": "vitamin", + "vit_type": "counter", + "name": { "str": "Red Blood Cells" }, + "deficiency": "redcells_anemia", + "min": -50000, + "max": 0, + "rate": "-12 s", + "flags": [ "NO_DISPLAY" ], + "disease": [ [ -7510, -20000 ], [ -20010, -35000 ], [ -35010, -50000 ] ] } ] diff --git a/data/json/weather_type.json b/data/json/weather_type.json new file mode 100644 index 0000000000000..72e79533d3b44 --- /dev/null +++ b/data/json/weather_type.json @@ -0,0 +1,332 @@ +[ + { + "id": "null", + "type": "weather_type", + "name": "NULL Weather - BUG", + "color": "c_magenta", + "map_color": "c_magenta_red", + "glyph": "0", + "ranged_penalty": 0, + "sight_penalty": 0.0, + "light_modifier": 0, + "sound_attn": 0, + "dangerous": false, + "precip": "none", + "rains": false, + "acidic": false, + "sun_intensity": "normal" + }, + { + "id": "clear", + "type": "weather_type", + "name": "Clear", + "color": "c_cyan", + "map_color": "c_yellow_white", + "glyph": " ", + "ranged_penalty": 0, + "sight_penalty": 1.0, + "light_modifier": 0, + "sound_attn": 0, + "dangerous": false, + "precip": "none", + "rains": false, + "acidic": false, + "sun_intensity": "normal" + }, + { + "id": "sunny", + "type": "weather_type", + "name": "Sunny", + "color": "c_light_cyan", + "map_color": "c_yellow_white", + "glyph": "*", + "ranged_penalty": 0, + "sight_penalty": 1.0, + "light_modifier": 2, + "sound_attn": 0, + "dangerous": false, + "precip": "none", + "rains": false, + "acidic": false, + "sun_intensity": "high", + "requirements": { "pressure_min": 1020, "humidity_max": 70, "time": "day" } + }, + { + "id": "cloudy", + "type": "weather_type", + "name": "Cloudy", + "color": "c_light_gray", + "map_color": "c_dark_gray_white", + "glyph": "~", + "ranged_penalty": 0, + "sight_penalty": 1.0, + "light_modifier": -20, + "sound_attn": 0, + "dangerous": false, + "precip": "none", + "rains": false, + "acidic": false, + "sun_intensity": "light", + "requirements": { "pressure_max": 1010, "humidity_min": 40 } + }, + { + "id": "light_drizzle", + "type": "weather_type", + "name": "Light Drizzle", + "color": "c_light_blue", + "map_color": "h_light_blue", + "glyph": ".", + "ranged_penalty": 0, + "sight_penalty": 1.01, + "light_modifier": -10, + "sound_attn": 0, + "dangerous": false, + "precip": "very_light", + "rains": true, + "acidic": false, + "tiles_animation": "weather_rain_drop", + "weather_animation": { "factor": 0.01, "color": "c_light_blue", "glyph": "," }, + "sound_category": "drizzle", + "sun_intensity": "light", + "requirements": { "pressure_max": 1003, "humidity_min": 96, "humidity_and_pressure": false, "required_weathers": [ "cloudy" ] } + }, + { + "id": "drizzle", + "type": "weather_type", + "name": "Drizzle", + "color": "c_light_blue", + "map_color": "h_light_blue", + "glyph": ".", + "ranged_penalty": 1, + "sight_penalty": 1.03, + "light_modifier": -20, + "sound_attn": 1, + "dangerous": false, + "precip": "light", + "rains": true, + "acidic": false, + "tiles_animation": "weather_rain_drop", + "weather_animation": { "factor": 0.01, "color": "c_light_blue", "glyph": "." }, + "sound_category": "drizzle", + "sun_intensity": "light", + "requirements": { "pressure_max": 1000, "humidity_min": 97, "humidity_and_pressure": false, "required_weathers": [ "light_drizzle" ] } + }, + { + "id": "rain", + "type": "weather_type", + "name": "Rain", + "color": "c_blue", + "map_color": "h_blue", + "glyph": "o", + "ranged_penalty": 3, + "sight_penalty": 1.1, + "light_modifier": -30, + "sound_attn": 4, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "tiles_animation": "weather_rain_drop", + "weather_animation": { "factor": 0.02, "color": "c_light_blue", "glyph": "," }, + "sound_category": "rainy", + "sun_intensity": "light", + "requirements": { + "pressure_max": 993, + "humidity_min": 98, + "humidity_and_pressure": false, + "required_weathers": [ "light_drizzle", "drizzle" ] + } + }, + { + "id": "thunder", + "type": "weather_type", + "name": "Thunder Storm", + "color": "c_dark_gray", + "map_color": "i_blue", + "glyph": "%", + "ranged_penalty": 4, + "sight_penalty": 1.2, + "light_modifier": -40, + "sound_attn": 8, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "effects": [ + { + "one_in_chance": 50, + "must_be_outside": false, + "sound_message": "You hear a distant rumble of thunder.", + "sound_effect": "thunder_far" + } + ], + "tiles_animation": "weather_rain_drop", + "weather_animation": { "factor": 0.02, "color": "c_light_blue", "glyph": "." }, + "sound_category": "thunder", + "sun_intensity": "none", + "requirements": { "pressure_max": 996, "required_weathers": [ "rain" ] } + }, + { + "id": "lightning", + "type": "weather_type", + "name": "Lightning Storm", + "color": "c_yellow", + "map_color": "h_yellow", + "glyph": "%", + "ranged_penalty": 4, + "sight_penalty": 1.25, + "light_modifier": -45, + "sound_attn": 8, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "effects": [ + { + "one_in_chance": 50, + "must_be_outside": false, + "sound_message": "You hear a distant rumble of thunder.", + "sound_effect": "thunder_far" + }, + { + "one_in_chance": 600, + "must_be_outside": false, + "message": "A flash of lightning illuminates your surroundings!.", + "sound_effect": "thunder_near", + "lightning": true + } + ], + "tiles_animation": "weather_rain_drop", + "weather_animation": { "factor": 0.04, "color": "c_light_blue", "glyph": "," }, + "sound_category": "thunder", + "sun_intensity": "none", + "requirements": { "pressure_max": 990, "required_weathers": [ "thunder" ] } + }, + { + "id": "acid_drizzle", + "type": "weather_type", + "name": "Acidic Drizzle", + "color": "c_light_green", + "map_color": "c_yellow_green", + "glyph": ".", + "ranged_penalty": 2, + "sight_penalty": 1.03, + "light_modifier": -20, + "sound_attn": 1, + "dangerous": true, + "precip": "light", + "rains": true, + "acidic": true, + "effects": [ + { + "time_between": "3 minutes", + "must_be_outside": true, + "message": "The acid rain stings, but is mostly harmless for now…", + "rain_proof": true, + "pain_max": 10, + "pain": 1 + } + ], + "tiles_animation": "weather_acid_drop", + "weather_animation": { "factor": 0.01, "color": "c_light_green", "glyph": "." }, + "sound_category": "drizzle", + "sun_intensity": "normal", + "requirements": { "acidic": true, "required_weathers": [ "drizzle" ] } + }, + { + "id": "acid_rain", + "type": "weather_type", + "name": "Acid Rain", + "color": "c_green", + "map_color": "c_yellow_green", + "glyph": "o", + "ranged_penalty": 4, + "sight_penalty": 1.1, + "light_modifier": -30, + "sound_attn": 4, + "dangerous": true, + "precip": "heavy", + "rains": true, + "acidic": true, + "effects": [ + { + "time_between": "2 seconds", + "must_be_outside": true, + "message": "The acid rain burns!", + "rain_proof": true, + "pain_max": 100, + "pain": 3 + } + ], + "tiles_animation": "weather_acid_drop", + "weather_animation": { "factor": 0.02, "color": "c_light_green", "glyph": "," }, + "sound_category": "rainy", + "sun_intensity": "none", + "requirements": { "acidic": true, "required_weathers": [ "rain" ] } + }, + { + "id": "flurries", + "type": "weather_type", + "name": "Flurries", + "color": "c_white", + "map_color": "c_dark_gray_cyan", + "glyph": ".", + "ranged_penalty": 2, + "sight_penalty": 1.12, + "light_modifier": -15, + "sound_attn": 2, + "dangerous": false, + "precip": "light", + "rains": false, + "acidic": false, + "tiles_animation": "weather_snowflake", + "weather_animation": { "factor": 0.01, "color": "c_white", "glyph": "." }, + "sound_category": "flurries", + "sun_intensity": "light", + "requirements": { "temperature_max": 33, "required_weathers": [ "drizzle" ] } + }, + { + "id": "snowing", + "type": "weather_type", + "name": "Snowing", + "color": "c_white", + "map_color": "c_dark_gray_cyan", + "glyph": "*", + "ranged_penalty": 4, + "sight_penalty": 1.3, + "light_modifier": -20, + "sound_attn": 4, + "dangerous": false, + "precip": "heavy", + "rains": false, + "acidic": false, + "effects": [ { "must_be_outside": true, "wet": 10 } ], + "tiles_animation": "weather_snowflake", + "weather_animation": { "factor": 0.02, "color": "c_white", "glyph": "," }, + "sound_category": "snow", + "sun_intensity": "light", + "requirements": { "temperature_max": 33, "required_weathers": [ "rain", "thunder", "lightning" ] } + }, + { + "id": "snowstorm", + "type": "weather_type", + "name": "Snowstorm", + "color": "c_white", + "map_color": "c_white_cyan", + "glyph": "%", + "ranged_penalty": 6, + "sight_penalty": 1.2, + "light_modifier": -30, + "sound_attn": 6, + "dangerous": false, + "precip": "heavy", + "rains": false, + "acidic": false, + "effects": [ { "must_be_outside": true, "wet": 40 } ], + "tiles_animation": "weather_snowflake", + "weather_animation": { "factor": 0.04, "color": "c_white", "glyph": "*" }, + "sound_category": "snowstorm", + "sun_intensity": "none", + "requirements": { "temperature_max": 33, "windpower_min": 15, "required_weathers": [ "thunder", "lightning" ] } + } +] diff --git a/data/legacy/1/obsolete.json b/data/legacy/1/obsolete.json index ae5e8e6bda3fd..d42cc839b842f 100644 --- a/data/legacy/1/obsolete.json +++ b/data/legacy/1/obsolete.json @@ -8,8 +8,8 @@ "color": "yellow", "description": "Conical Ball .22 is a variety of .22 ammunition with a very small propellant charge and generally lacks gunpowder. The end result is a subsonic round. It is nearly silent, but is so weak as to be nearly useless. This one has been handmade using an intact casing.", "material": [ "steel", "powder" ], - "volume": 1, - "weight": 3, + "volume": "250 ml", + "weight": "3 g", "bashing": 1, "ammo_type": "22", "casing": "22_casing", @@ -30,8 +30,8 @@ "color": "yellow", "description": "Rat-shot is extremely weak ammunition, designed for killing rats, snakes, or other small vermin while being unable to damage walls. It has an extremely short range and is unable to injure all but the smallest creatures. This one has been handmade using an intact casing.", "material": [ "steel", "powder" ], - "volume": 1, - "weight": 3, + "volume": "250 ml", + "weight": "3 g", "bashing": 1, "ammo_type": "22", "casing": "22_casing", @@ -52,8 +52,8 @@ "color": "red", "description": "A hand-reloaded beanbag round for shotguns, not deadly but designed to disable.", "material": [ "plastic", "powder" ], - "volume": 1, - "weight": 46, + "volume": "250 ml", + "weight": "46 g", "ammo_type": "shot", "casing": "shot_hull", "damage": 8, @@ -72,8 +72,8 @@ "description": "A homemade, rechargeable power cell built from salvaged electronics. With enough electronics skill, you could attach it to an electric-powered device to provide it with energy. The power cell is not compatible with standard batteries; it must be re-energized via a special recharging station.", "price": 2000, "material": [ "plastic", "aluminum" ], - "weight": 142, - "volume": 1, + "weight": "142 g", + "volume": "250 ml", "to_hit": -2, "category": "spare_parts" }, @@ -82,7 +82,7 @@ "id": "brew_bum_wine", "name": "cheap wine must", "description": "Unfermented grape wine. A hearty mix of pressed grapes, with some added brandy to fortify it.", - "weight": 46, + "weight": "46 g", "color": "red", "container": "jug_plastic", "flags": [ "TRADER_AVOID" ], @@ -92,7 +92,7 @@ "fun": -15, "price": 0, "material": [ "fruit", "water" ], - "volume": 1, + "volume": "250 ml", "charges": 7, "phase": "liquid", "comestible_type": "DRINK", @@ -110,8 +110,8 @@ "flags": [ "RELOAD_ONE", "NEVER_JAMS", "RELOAD_EJECT" ], "skill": "shotgun", "ammo": [ "shot" ], - "weight": 1814, - "volume": 4, + "weight": "1814 g", + "volume": "1 L", "bashing": 12, "to_hit": -1, "ranged_damage": 4, @@ -146,8 +146,8 @@ "flags": [ "RELOAD_ONE", "NEVER_JAMS", "RELOAD_EJECT" ], "skill": "shotgun", "ammo": [ "shot" ], - "weight": 1133, - "volume": 6, + "weight": "1133 g", + "volume": "1500 ml", "bashing": 12, "to_hit": -1, "ranged_damage": 1, @@ -166,12 +166,12 @@ "name": "spare magazine", "description": "A spare magazine you can keep on hand to make reloads faster, but must itself be reloaded before it can be used again.", "location": "accessories", - "weight": 330, + "weight": "330 g", "color": "light_gray", "symbol": ":", "material": [ "steel", "plastic" ], "mod_targets": [ "pistol", "shotgun", "smg", "rifle" ], - "volume": 1, + "volume": "250 ml", "price": 5000 }, { @@ -181,13 +181,13 @@ "clip_size_modifier": 50, "description": "Increases the ammunition capacity of your firearm by 50%.", "location": "magazine", - "weight": 495, + "weight": "495 g", "to_hit": -1, "color": "light_gray", "symbol": ":", "material": [ "steel", "plastic" ], "mod_targets": [ "pistol", "shotgun", "smg", "rifle" ], - "volume": 1, + "volume": "250 ml", "price": 5600 }, { @@ -197,12 +197,12 @@ "clip_size_modifier": 100, "description": "Completely doubles the ammunition capacity of your firearm.", "location": "magazine", - "weight": 660, + "weight": "660 g", "color": "light_gray", "symbol": ":", "material": [ "steel", "plastic" ], "mod_targets": [ "shotgun", "smg", "rifle", "pistol" ], - "volume": 2, + "volume": "500 ml", "price": 7200 }, { @@ -215,8 +215,8 @@ "description": "10 plastic bags, folded smooth and wrapped tightly together with a string.", "price": 500, "material": [ "plastic" ], - "weight": 10, - "volume": 1, + "weight": "10 g", + "volume": "250 ml", "to_hit": 1 }, { @@ -227,13 +227,13 @@ "dispersion_modifier": 90, "damage_modifier": 6, "description": "This is a complete conversion kit, designed to turn a rifle into a powerful battle rifle. It reduces accuracy, and increases noise and recoil, but also increases damage and fire rate.", - "weight": 589, + "weight": "589 g", "color": "magenta", "symbol": ":", "material": [ "steel" ], "mod_targets": [ "rifle" ], - "volume": 2, - "integral_volume": 0, + "volume": "500 ml", + "integral_volume": "0 L", "burst_modifier": 4, "recoil_modifier": 60, "price": 68000, @@ -248,13 +248,13 @@ "dispersion_modifier": -150, "damage_modifier": 8, "description": "This is a complete conversion kit, designed to turn a rifle into a deadly sniper rifle. It removes any automatic fire capabilities but also increases accuracy and damage.", - "weight": 589, + "weight": "589 g", "color": "green", "symbol": ":", "material": [ "steel" ], "mod_targets": [ "rifle" ], - "volume": 2, - "integral_volume": 0, + "volume": "500 ml", + "integral_volume": "0 L", "burst_modifier": -99, "price": 66000, "min_skills": [ [ "gun", 8 ] ], @@ -270,8 +270,8 @@ "description": "A large block of semi-processed coal.", "price": 60000, "material": [ "stone" ], - "weight": 13840, - "volume": 72, + "weight": "13840 g", + "volume": "18 L", "bashing": 8, "to_hit": -5 }, @@ -285,8 +285,8 @@ "color": "dark_gray", "description": "These are smaller pieces of charcoal used in smaller heating devices.", "material": [ "wood" ], - "volume": 1, - "weight": 22, + "volume": "250 ml", + "weight": "22 g", "phase": "solid", "ammo_type": "charcoal", "count": 10, @@ -302,8 +302,8 @@ "color": "dark_gray", "description": "These are smaller pieces of coal used in smaller heating devices.", "material": [ "wood" ], - "volume": 1, - "weight": 22, + "volume": "250 ml", + "weight": "22 g", "ammo_type": "charcoal", "count": 10, "stack_size": 20 @@ -317,8 +317,8 @@ "color": "white", "description": "Also known as a flight, this item provides aerodynamic stabilization of arrows. You'll need to put these on your arrows to make them functional.", "material": [ "paper" ], - "volume": 1, - "weight": 1, + "volume": "250 ml", + "weight": "1 g", "bashing": 1, "ammo_type": "components", "count": 10, @@ -328,7 +328,7 @@ "type": "ARMOR", "id": "helmet_netting", "name": "helmet netting", - "weight": 25, + "weight": "25 g", "color": "green", "covers": [ "HEAD" ], "to_hit": -1, @@ -337,7 +337,7 @@ "flags": [ "OVERSIZE", "BELTED", "WATER_FRIENDLY" ], "price": 2000, "material": [ "cotton" ], - "volume": 0, + "volume": "0 L", "coverage": 12, "material_thickness": 1 }, @@ -350,8 +350,8 @@ "category": "other", "description": "A small metal tank for holding gas or liquids. Useful for crafting.", "price": 6000, - "weight": 3200, - "volume": 45, + "weight": "3200 g", + "volume": "11250 ml", "bashing": 5, "to_hit": -3, "material": [ "steel" ] @@ -367,8 +367,8 @@ "material": [ "steel", "plastic" ], "flags": [ "CHARGE", "NO_UNLOAD", "NEVER_JAMS", "NO_UNLOAD" ], "skill": "rifle", - "weight": 1814, - "volume": 13, + "weight": "1814 g", + "volume": "3250 ml", "bashing": 8, "to_hit": -1, "dispersion": 10, @@ -396,8 +396,8 @@ "color": "yellow", "description": "A single capacitor charged with current to be used by a laser weapon or similar armament.", "material": [ "steel" ], - "volume": 1, - "weight": 5 + "volume": "250 ml", + "weight": "5 g" }, { "id": "inhaler_stimgas", @@ -405,8 +405,8 @@ "comestible_type": "MED", "name": "stimgas inhaler", "description": "A powerful stimulant with no risk of addiction.", - "weight": 10, - "volume": 1, + "weight": "10 g", + "volume": "250 ml", "price": 750, "charges": 25, "material": [ "plastic" ], @@ -422,8 +422,8 @@ "comestible_type": "MED", "name": "sewagas inhaler", "description": "A powerful hallucinogen with low risk of addiction.", - "weight": 10, - "volume": 1, + "weight": "10 g", + "volume": "250 ml", "price": 500, "charges": 25, "material": [ "plastic" ], @@ -451,8 +451,8 @@ "flags": [ "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON" ], "skill": "archery", "ammo": [ "dart" ], - "weight": 440, - "volume": 4, + "weight": "440 g", + "volume": "1 L", "bashing": 8, "to_hit": -2, "dispersion": 75, @@ -470,8 +470,8 @@ "color": "yellow", "description": "A handful of darts, useful as ammunition for blowguns.", "material": [ "wood" ], - "volume": 1, - "weight": 1, + "volume": "250 ml", + "weight": "1 g", "ammo_type": "dart", "damage": 1, "range": 30, @@ -490,8 +490,8 @@ "description": "An electrode plate from a lead-acid battery.", "price": 10, "material": [ "steel" ], - "weight": 400, - "volume": 1, + "weight": "400 g", + "volume": "250 ml", "bashing": 4, "to_hit": -2 }, @@ -501,8 +501,8 @@ "name": "active nail bomb", "description": "This is an active nail bomb, likely to explode any second now. Better throw it!", "category": "weapons", - "weight": 290, - "volume": 2, + "weight": "290 g", + "volume": "500 ml", "price": 0, "material": [ "steel", "plastic" ], "symbol": "*", @@ -528,8 +528,8 @@ "name": "forged sword", "description": "A common short sword, forged from several pieces of steel. The pointy end is the dangerous one.", "material": [ "steel" ], - "volume": 8, - "weight": 700, + "volume": "2 L", + "weight": "700 g", "bashing": 4, "cutting": 14, "to_hit": 2, @@ -546,8 +546,8 @@ "category": "other", "material": [ "wood" ], "flags": [ "NO_SALVAGE", "TRADER_AVOID" ], - "weight": 6, - "volume": 0, + "weight": "6 g", + "volume": "0 L", "to_hit": -5, "qualities": [ [ "COOK", 1 ] ] }, diff --git a/data/legacy/3/crazy.json b/data/legacy/3/crazy.json index c1b2cef436118..4ddad28328f6f 100644 --- a/data/legacy/3/crazy.json +++ b/data/legacy/3/crazy.json @@ -9,8 +9,8 @@ "category": "weapons", "name": "Granade", "description": "Attached to this grenade is a name tag with the name Kevin written on it. Does not seem to work like a grenade, handle with care.", - "weight": 180, - "volume": 1, + "weight": "180 g", + "volume": "250 ml", "price": 40000, "to_hit": -1, "bashing": 6, @@ -25,8 +25,8 @@ "category": "weapons", "name": "active Granade", "description": "Attached to this grenade is a name tag with the name Kevin written on it. Does not seem to work like a grenade, handle with care. Better throw it!", - "weight": 180, - "volume": 1, + "weight": "180 g", + "volume": "250 ml", "price": 0, "to_hit": -1, "bashing": 6, diff --git a/data/legacy/4/boots.json b/data/legacy/4/boots.json index 368d17a085ae2..36d9718eb42b8 100644 --- a/data/legacy/4/boots.json +++ b/data/legacy/4/boots.json @@ -4,8 +4,8 @@ "type": "ARMOR", "name": { "str": "pair of boots", "str_pl": "pairs of boots" }, "description": "Tough leather boots. Very durable.", - "weight": 1060, - "volume": 10, + "weight": "1060 g", + "volume": "2500 ml", "price": 10000, "to_hit": -1, "bashing": 1, @@ -43,8 +43,8 @@ "category": "armor", "name": { "str": "pair of bone armor boots", "str_pl": "pairs of bone armor boots" }, "description": "Leather boots armored with reinforcements made from bone. Light and strong.", - "weight": 1824, - "volume": 17, + "weight": "1824 g", + "volume": "4250 ml", "price": 13500, "to_hit": -1, "bashing": 4, @@ -82,8 +82,8 @@ "category": "armor", "name": { "str": "pair of turnout boots", "str_pl": "pairs of turnout boots" }, "description": "A pair of steel-toed rubber boots, the sort worn by firefighters. Highly resistant to heat and flame, they provide excellent protection from injury.", - "weight": 1930, - "volume": 14, + "weight": "1930 g", + "volume": "3500 ml", "price": 13000, "to_hit": 2, "material": [ "plastic", "nomex" ], @@ -120,8 +120,8 @@ "category": "armor", "name": { "str": "pair of chitinous boots", "str_pl": "pairs of chitinous boots" }, "description": "Boots made from the exoskeletons of insects. Light and durable.", - "weight": 1620, - "volume": 17, + "weight": "1620 g", + "volume": "4250 ml", "price": 13500, "to_hit": -1, "bashing": 4, @@ -159,8 +159,8 @@ "category": "armor", "name": { "str": "pair of combat boots", "str_pl": "pairs of combat boots" }, "description": "Modern reinforced tactical combat boots. Very durable.", - "weight": 1060, - "volume": 8, + "weight": "1060 g", + "volume": "2 L", "price": 7000, "to_hit": -1, "bashing": 1, @@ -198,8 +198,8 @@ "category": "armor", "name": { "str": "pair of survivor fireboots", "str_pl": "pairs of survivor fireboots" }, "description": "A pair of customized, Kevlar armored Nomex boots, modified to provide maximum protection from harm and the elements, even when knee-deep in the dead.", - "weight": 1980, - "volume": 12, + "weight": "1980 g", + "volume": "3 L", "price": 24000, "to_hit": -1, "bashing": 1, @@ -236,8 +236,8 @@ "type": "ARMOR", "name": { "str": "pair of fur boots", "str_pl": "pairs of fur boots" }, "description": "Boots lined with fur for warmth.", - "weight": 1890, - "volume": 18, + "weight": "1890 g", + "volume": "4500 ml", "price": 14000, "to_hit": -1, "bashing": 1, @@ -275,8 +275,8 @@ "category": "armor", "name": { "str": "pair of survivor wetsuit boots", "str_pl": "pairs of survivor wetsuit boots" }, "description": "A pair of customized, Kevlar armored neoprene boots, modified to provide maximum protection from harm and the elements, even when knee-deep in the dead.", - "weight": 1180, - "volume": 6, + "weight": "1180 g", + "volume": "1500 ml", "price": 24000, "to_hit": -1, "bashing": 1, @@ -313,8 +313,8 @@ "type": "ARMOR", "name": { "str": "pair of hiking boots", "str_pl": "pairs of hiking boots" }, "description": "Tough yet light leather boots. Durable and comfortable.", - "weight": 960, - "volume": 8, + "weight": "960 g", + "volume": "2 L", "price": 14000, "to_hit": -1, "bashing": 1, @@ -352,8 +352,8 @@ "category": "armor", "name": { "str": "pair of heavy survivor boots", "str_pl": "pairs of heavy survivor boots" }, "description": "A pair of customized Kevlar boots, heavily armored with steel and modified to provide maximum protection from harm, even when knee-deep in the dead.", - "weight": 1610, - "volume": 12, + "weight": "1610 g", + "volume": "3 L", "price": 24000, "to_hit": -1, "bashing": 1, @@ -391,8 +391,8 @@ "category": "armor", "name": { "str": "pair of leather armor boots", "str_pl": "pairs of leather armor boots" }, "description": "Thick leather boots made specifically to protect the feet. Light and tough.", - "weight": 902, - "volume": 8, + "weight": "902 g", + "volume": "2 L", "price": 12500, "to_hit": -1, "bashing": 4, @@ -430,8 +430,8 @@ "category": "armor", "name": { "str": "pair of light survivor boots", "str_pl": "pairs of light survivor boots" }, "description": "A pair of customized, Kevlar armored cloth boots, modified to provide maximum protection from harm, even when knee-deep in the dead.", - "weight": 1120, - "volume": 8, + "weight": "1120 g", + "volume": "2 L", "price": 24000, "to_hit": -1, "bashing": 1, @@ -469,8 +469,8 @@ "category": "armor", "name": { "str": "pair of armored boots", "str_pl": "pairs of armored boots" }, "description": "An extremely heavy set of armor plated boots.", - "weight": 1890, - "volume": 13, + "weight": "1890 g", + "volume": "3250 ml", "price": 50000, "to_hit": -2, "bashing": 7, @@ -507,8 +507,8 @@ "type": "ARMOR", "name": { "str": "pair of rubber boots", "str_pl": "pairs of rubber boots" }, "description": "A pair of rubber boots, often used while cleaning with caustic materials.", - "weight": 980, - "volume": 14, + "weight": "980 g", + "volume": "3500 ml", "price": 8000, "to_hit": 2, "material": [ "plastic" ], @@ -544,8 +544,8 @@ "type": "ARMOR", "name": { "str": "pair of steeltoed boots", "str_pl": "pairs of steeltoed boots" }, "description": "Leather boots with a steel toe. Extremely durable.", - "weight": 1320, - "volume": 12, + "weight": "1320 g", + "volume": "3 L", "price": 12000, "to_hit": -1, "bashing": 4, @@ -583,8 +583,8 @@ "category": "armor", "name": { "str": "pair of survivor boots", "str_pl": "pairs of survivor boots" }, "description": "A pair of customized leather boots, armored with Kevlar and modified to provide maximum protection from harm, even when knee-deep in the dead.", - "weight": 1330, - "volume": 10, + "weight": "1330 g", + "volume": "2500 ml", "price": 24000, "to_hit": -1, "bashing": 1, @@ -621,8 +621,8 @@ "type": "ARMOR", "name": { "str": "pair of western boots", "str_pl": "pairs of western boots" }, "description": "Stiff leather boots with intricate embroidery and one-inch heels. They look good, but aren't made for running.", - "weight": 1060, - "volume": 10, + "weight": "1060 g", + "volume": "2500 ml", "price": 15000, "to_hit": -1, "bashing": 1, @@ -659,8 +659,8 @@ "type": "ARMOR", "name": { "str": "pair of winter boots", "str_pl": "pairs of winter boots" }, "description": "Cumbersome boots designed for warmth.", - "weight": 1640, - "volume": 14, + "weight": "1640 g", + "volume": "3500 ml", "price": 7000, "to_hit": -1, "material": [ "wool", "plastic" ], @@ -697,8 +697,8 @@ "category": "armor", "name": { "str": "pair of winter survivor boots", "str_pl": "pairs of winter survivor boots" }, "description": "A pair of customized, Kevlar armored fur boots, modified to provide maximum protection from harm and the elements, even when knee-deep in the dead.", - "weight": 1760, - "volume": 14, + "weight": "1760 g", + "volume": "3500 ml", "price": 24000, "to_hit": -1, "bashing": 1, @@ -736,8 +736,8 @@ "category": "armor", "name": { "str": "pair of XL survivor boots", "str_pl": "pairs of XL survivor boots" }, "description": "A massive pair of customized leather boots, armored with Kevlar and modified to provide maximum protection from harm and the elements, even when knee-deep in the dead.", - "weight": 2460, - "volume": 20, + "weight": "2460 g", + "volume": "5 L", "price": 24000, "to_hit": -1, "bashing": 1, @@ -774,8 +774,8 @@ "type": "ARMOR", "name": { "str": "pair of knee-high boots", "str_pl": "pairs of knee-high boots" }, "description": "Very long leather boots that cover the lower legs. Difficult to wear but extremely durable.", - "weight": 1520, - "volume": 15, + "weight": "1520 g", + "volume": "3750 ml", "price": 8000, "to_hit": -1, "bashing": 1, @@ -812,8 +812,8 @@ "type": "ARMOR", "name": { "str": "pair of rollerblades", "str_pl": "pairs of rollerblades" }, "description": "A pair of inline skates. Very fast on flat floors, but they make it hard to move on rough terrain, or to dodge effectively.", - "weight": 1640, - "volume": 15, + "weight": "1640 g", + "volume": "3750 ml", "price": 8500, "to_hit": -2, "material": [ "plastic", "cotton" ], @@ -849,8 +849,8 @@ "type": "ARMOR", "name": { "str": "pair of rollerskates", "str_pl": "pairs of rollerskates" }, "description": "An old-fashioned pair of leather rollerskates with steel frames. While quite fast on flat floors, they make it difficult to move on rough terrain.", - "weight": 2720, - "volume": 12, + "weight": "2720 g", + "volume": "3 L", "price": 8500, "to_hit": -2, "bashing": 6, diff --git a/data/legacy/5/vehicle_parts.json b/data/legacy/5/vehicle_parts.json index 924fe9d2faf1c..63ba8bcd2170f 100644 --- a/data/legacy/5/vehicle_parts.json +++ b/data/legacy/5/vehicle_parts.json @@ -4,12 +4,12 @@ "id": "v_curtain_item", "name": { "str": "vehicle curtain" }, "description": "A rod, a few metal rings, and a large piece of cloth with some strings attached for securely fastening the edges.", - "weight": 2200, + "weight": "2200 g", "to_hit": -4, "color": "white", "symbol": "\"", "material": [ "cotton", "steel" ], - "volume": 20, + "volume": "5 L", "bashing": 1, "category": "veh_parts", "price": 3500 diff --git a/data/mods/Aftershock/items/comestibles.json b/data/mods/Aftershock/items/comestibles.json index 127bf14320281..635e8bb42b274 100644 --- a/data/mods/Aftershock/items/comestibles.json +++ b/data/mods/Aftershock/items/comestibles.json @@ -12,7 +12,7 @@ "quench": -5, "description": "A crumbly white pill half the size of your thumb, packed with vitamins and calories. Provides a whole day's nutrition in portable form, but it's a little hard to keep down, thanks to the rancid taste and chalky texture.", "price": 10000, - "volume": 0, + "volume": "0 L", "charges": 5, "looks_like": "vitamins", "fun": -8, diff --git a/data/mods/Aftershock/items/tools.json b/data/mods/Aftershock/items/tools.json index fe119be50a8da..8597032339992 100644 --- a/data/mods/Aftershock/items/tools.json +++ b/data/mods/Aftershock/items/tools.json @@ -221,21 +221,11 @@ "name": { "str": "UPS", "str_pl": "UPS's" }, "description": "This is a unified power supply, or UPS. It is a device developed jointly by military and scientific interests for use in combat and the field. The UPS is designed to power armor and some guns, but drains batteries quickly. It can be worn around to either leg for ease of access, and it's been waterproofed to protect the delicate electronics. Has it's own custom battery, with higher capacity and rechargeable, but not removeable", "coverage": 5, - "ammo": "battery", - "initial_charges": 1000, - "max_charges": 1500, + "ammo": [ "battery" ], "encumbrance": 2, "covers": [ "LEG_EITHER" ], - "flags": [ "RECHARGE", "WAIST", "FRAGILE", "OVERSIZE", "WATERPROOF", "IS_UPS", "NO_RELOAD", "NO_UNLOAD" ], - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ ] - } - ] + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1500 } } ], + "flags": [ "RECHARGE", "WAIST", "FRAGILE", "OVERSIZE", "WATERPROOF", "IS_UPS" ] }, { "id": "adv_UPS_off", diff --git a/data/mods/Aftershock/mobs/uplifted_monsters.json b/data/mods/Aftershock/mobs/uplifted_monsters.json index 8d0191fae4d28..792161a8afd45 100644 --- a/data/mods/Aftershock/mobs/uplifted_monsters.json +++ b/data/mods/Aftershock/mobs/uplifted_monsters.json @@ -54,7 +54,7 @@ "harvest": "demihuman_large_fur", "reproduction": { "baby_monster": "mon_uplifted_bear_cub", "baby_count": 1, "baby_timer": 700 }, "baby_flags": [ "SPRING" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "BLEED", "BASHES", "ATTACKMON" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "BASHES", "ATTACKMON" ] }, { "id": "mon_uplifted_bear_cub", diff --git a/data/mods/Aftershock/mobs/zombies.json b/data/mods/Aftershock/mobs/zombies.json index 8309ab58850d5..f794db9288ba9 100644 --- a/data/mods/Aftershock/mobs/zombies.json +++ b/data/mods/Aftershock/mobs/zombies.json @@ -31,7 +31,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -77,7 +76,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -129,7 +127,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -174,7 +171,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", diff --git a/data/mods/BlazeIndustries/items/vehicle/blaze_gun.json b/data/mods/BlazeIndustries/items/vehicle/blaze_gun.json new file mode 100644 index 0000000000000..9430546f27c10 --- /dev/null +++ b/data/mods/BlazeIndustries/items/vehicle/blaze_gun.json @@ -0,0 +1,85 @@ +[ + { + "id": "blaze_marlin_9a", + "looks_like": "ar15", + "type": "GUN", + "reload_noise_volume": 10, + "name": { "str_sp": "modified Marlin 39A" }, + "description": "A Marlin 39A, modified for use in a vehicle turret.", + "weight": "2948 g", + "volume": "2500 ml", + "price": 23000, + "price_postapoc": 2000, + "to_hit": -1, + "bashing": 12, + "material": [ "iron", "wood" ], + "symbol": "(", + "color": "brown", + "ammo": [ "22" ], + "skill": "rifle", + "ranged_damage": { "damage_type": "bullet", "amount": 5 }, + "dispersion": 90, + "durability": 8, + "blackpowder_tolerance": 56, + "clip_size": 19, + "valid_mod_locations": [ + [ "accessories", 4 ], + [ "barrel", 1 ], + [ "bore", 1 ], + [ "brass catcher", 1 ], + [ "grip", 1 ], + [ "mechanism", 4 ], + [ "muzzle", 1 ], + [ "rail", 1 ], + [ "sights", 1 ], + [ "sling", 1 ], + [ "stock", 1 ], + [ "underbarrel", 1 ] + ], + "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ], + "flags": [ "RELOAD_ONE" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "22": 19 } } ] + }, + { + "id": "blaze_sks", + "looks_like": "ar15", + "type": "GUN", + "reload_noise_volume": 10, + "name": { "str": "modified SKS" }, + "description": "An SKS, modified to be suitable for use in a vehicle turret.", + "weight": "3850 g", + "volume": "2838 ml", + "longest_side": "103 cm", + "price": 38000, + "price_postapoc": 3500, + "to_hit": -1, + "bashing": 12, + "material": [ "steel", "wood" ], + "symbol": "(", + "color": "brown", + "ammo": [ "762" ], + "skill": "rifle", + "ranged_damage": { "damage_type": "bullet", "amount": 1 }, + "dispersion": 90, + "durability": 8, + "clip_size": 10, + "barrel_volume": "500 ml", + "built_in_mods": [ "inter_bayonet" ], + "valid_mod_locations": [ + [ "accessories", 4 ], + [ "barrel", 1 ], + [ "bore", 1 ], + [ "brass catcher", 1 ], + [ "grip", 1 ], + [ "mechanism", 4 ], + [ "muzzle", 1 ], + [ "rail", 1 ], + [ "sights", 1 ], + [ "sling", 1 ], + [ "stock", 1 ], + [ "underbarrel", 1 ] + ], + "flags": [ "RELOAD_ONE", "NEVER_JAMS" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "762": 10 } } ] + } +] diff --git a/data/mods/BlazeIndustries/recipes/blaze_gun_recipes.json b/data/mods/BlazeIndustries/recipes/blaze_gun_recipes.json new file mode 100644 index 0000000000000..9e9ca36c76dcd --- /dev/null +++ b/data/mods/BlazeIndustries/recipes/blaze_gun_recipes.json @@ -0,0 +1,26 @@ +[ + { + "result": "blaze_sks", + "type": "recipe", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "mechanics", + "difficulty": 2, + "time": "20 m", + "autolearn": true, + "qualities": [ { "id": "HAMMER", "level": 2 }, { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sks", 1 ] ] ] + }, + { + "result": "blaze_marlin_9a", + "type": "recipe", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "mechanics", + "difficulty": 2, + "time": "20 m", + "autolearn": true, + "qualities": [ { "id": "HAMMER", "level": 2 }, { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "marlin_9a", 1 ] ] ] + } +] diff --git a/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json b/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json index 7a80bf31e28e4..cb7e6e71e2feb 100644 --- a/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json +++ b/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json @@ -366,8 +366,8 @@ "copy-from": "turret", "type": "vehicle_part", "name": { "str": "mounted Marlin 39A" }, - "item": "marlin_9a", - "breaks_into": [ { "item": "marlin_9a", "prob": 50 } ], + "item": "blaze_marlin_9a", + "breaks_into": [ { "item": "blaze_marlin_9a", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, { @@ -614,8 +614,8 @@ "copy-from": "turret", "type": "vehicle_part", "name": { "str": "mounted SKS" }, - "item": "sks", - "breaks_into": [ { "item": "sks", "prob": 50 } ], + "item": "blaze_sks", + "breaks_into": [ { "item": "blaze_sks", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, { diff --git a/data/mods/CRT_EXPANSION/items/crt_gunmods.json b/data/mods/CRT_EXPANSION/items/crt_gunmods.json index 5934e0ffedf7c..605911a93c984 100644 --- a/data/mods/CRT_EXPANSION/items/crt_gunmods.json +++ b/data/mods/CRT_EXPANSION/items/crt_gunmods.json @@ -23,7 +23,7 @@ "name": "CQB SI shotgun", "description": "The integrated underbarrel shotgun of this gun which holds a single shot. It's irremovable.", "weight": "2600 g", - "volume": 0, + "volume": "0 L", "price": 95000, "to_hit": -1, "material": [ "steel" ], @@ -43,7 +43,7 @@ "description": ", A military-grade stock which folds reducing the guns volume. The weight and the pivoting hook which latches onto your forearm allows for greater stability. ", "weight": "500 g", "volume": "125 ml", - "integral_volume": 0, + "integral_volume": "0 L", "price": 42000, "material": [ "plastic", "steel" ], "symbol": ":", @@ -74,7 +74,7 @@ "description": "A compact flashlight which is mounted to the side of your weapon, not powerful, but good enough for tight hallways.", "weight": "250 g", "volume": "125 ml", - "integral_volume": 0, + "integral_volume": "0 L", "price": 42000, "material": [ "plastic", "steel" ], "symbol": ":", @@ -102,7 +102,7 @@ "description": "A compact flashlight which is attached to the side of your weapon, not powerful, but good enough for tight hallways.", "weight": "250 g", "volume": "125 ml", - "integral_volume": 0, + "integral_volume": "0 L", "price": 42000, "material": [ "plastic", "steel" ], "symbol": ":", diff --git a/data/mods/CRT_EXPANSION/items/crt_makeshift_survival.json b/data/mods/CRT_EXPANSION/items/crt_makeshift_survival.json index 1c5364d238df6..7e1a56be307c2 100644 --- a/data/mods/CRT_EXPANSION/items/crt_makeshift_survival.json +++ b/data/mods/CRT_EXPANSION/items/crt_makeshift_survival.json @@ -5,8 +5,8 @@ "category": "armor", "name": "plant fiber tunic", "description": "A loose garment cobbled together from a collection of plant bundles and wound together by makeshift cordage", - "weight": 1520, - "volume": 23, + "weight": "1520 g", + "volume": "5750 ml", "price": 0, "to_hit": -5, "material": [ "dry_plant" ], @@ -25,8 +25,8 @@ "category": "armor", "name": "plant fiber bracelet", "description": "A bracelet wound together by makeshift cordage. Has some cool looking pebbles. ", - "weight": 1520, - "volume": 23, + "weight": "1520 g", + "volume": "5750 ml", "price": 0, "to_hit": -5, "material": [ "dry_plant" ], diff --git a/data/mods/CRT_EXPANSION/monsters/crt_monster.json b/data/mods/CRT_EXPANSION/monsters/crt_monster.json index 32bf1fb739c10..05269cca0bbd4 100644 --- a/data/mods/CRT_EXPANSION/monsters/crt_monster.json +++ b/data/mods/CRT_EXPANSION/monsters/crt_monster.json @@ -35,7 +35,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -78,7 +77,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -117,7 +115,7 @@ "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "death_drops": "mon_zombie_cop_death_drops", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "BLEED", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] + "flags": [ "SEES", "HEARS", "REVIVES", "NO_BREATHE", "POISON", "FILTHY" ] }, { "id": "mon_leaper", @@ -203,7 +201,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "BLEED", "FILTHY" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { "id": "mon_pack", @@ -233,20 +231,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "WARM", - "BLEED", - "BASHES", - "POISON", - "NO_BREATHE", - "REVIVES", - "CLIMBS", - "FILTHY", - "SWARMS" - ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "CLIMBS", "FILTHY", "SWARMS" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, { @@ -292,7 +277,6 @@ "NO_BREATHE", "REVIVES", "PUSH_MON", - "BLEED", "FILTHY" ] } diff --git a/data/mods/CRT_EXPANSION/monsters/monster.json b/data/mods/CRT_EXPANSION/monsters/monster.json index 8169eee163789..d3f189c90b4db 100644 --- a/data/mods/CRT_EXPANSION/monsters/monster.json +++ b/data/mods/CRT_EXPANSION/monsters/monster.json @@ -27,7 +27,7 @@ "harvest": "zombie", "special_attacks": [ [ "TENTACLE", 2 ], [ "scratch", 10 ] ], "death_function": [ "NORMAL" ], - "flags": [ "HEARS", "GOODHEARING", "WARM", "CLIMBS", "NOHEAD", "POISON", "BLEED", "NO_BREATHE" ] + "flags": [ "HEARS", "GOODHEARING", "WARM", "CLIMBS", "NOHEAD", "POISON", "NO_BREATHE" ] }, { "id": "mon_dullahan", @@ -56,6 +56,6 @@ "harvest": "zombie", "special_attacks": [ [ "TENTACLE", 7 ], [ "scratch", 8 ] ], "death_function": [ "NORMAL" ], - "flags": [ "WARM", "CLIMBS", "NOHEAD", "POISON", "BLEED", "NO_BREATHE" ] + "flags": [ "WARM", "CLIMBS", "NOHEAD", "POISON", "NO_BREATHE" ] } ] diff --git a/data/mods/CRT_EXPANSION/scenarios/crt_classes.json b/data/mods/CRT_EXPANSION/scenarios/crt_classes.json index 86520b79a1d60..4939fe02f2188 100644 --- a/data/mods/CRT_EXPANSION/scenarios/crt_classes.json +++ b/data/mods/CRT_EXPANSION/scenarios/crt_classes.json @@ -183,7 +183,7 @@ "mre_veggy_box", "crt_la_boots", "two_way_radio", - "1st_aid", + "ifak", "bandages", "crt_backpack", "UPS_off" diff --git a/data/mods/CrazyCataclysm/crazy_monsters.json b/data/mods/CrazyCataclysm/crazy_monsters.json index efbbd93694aa7..57808d7c97670 100644 --- a/data/mods/CrazyCataclysm/crazy_monsters.json +++ b/data/mods/CrazyCataclysm/crazy_monsters.json @@ -42,7 +42,7 @@ "vision_night": 3, "death_drops": "skeltal_drops", "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "BLEED", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "FILTHY" ], + "flags": [ "SEES", "HEARS", "HARDTOSHOOT", "REVIVES", "NO_BREATHE", "FILTHY" ], "harvest": "mr_bones", "special_attacks": [ [ "DOOT", 50 ] ] }, @@ -111,7 +111,6 @@ "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", - "BLEED", "BASHES", "ATTACKMON", "FIREPROOF", diff --git a/data/mods/Dark-Skies-Above/monsters/wild_aliens/alien_fauna.json b/data/mods/Dark-Skies-Above/monsters/wild_aliens/alien_fauna.json index 26fe1c9488859..cdd09651e361f 100644 --- a/data/mods/Dark-Skies-Above/monsters/wild_aliens/alien_fauna.json +++ b/data/mods/Dark-Skies-Above/monsters/wild_aliens/alien_fauna.json @@ -122,7 +122,6 @@ "KEENNOSE", "PATH_AVOID_DANGER_1", "ANIMAL", - "BLEED", "PET_WONT_FOLLOW", "PET_MOUNTABLE", "CATTLEFODDER" @@ -170,7 +169,6 @@ "PATH_AVOID_DANGER_1", "GROUP_MORALE", "ANIMAL", - "BLEED", "ATTACKMON", "SWIMS" ] diff --git a/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json b/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json index a455b09e196b9..b90862c2dcd0d 100644 --- a/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json +++ b/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json @@ -30,7 +30,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "upgrades": { "half_life": 21, "into_group": "DKS_GROUP_STRAY_UPGRADE" }, - "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "POISON", "BLEED", "FILTHY", "BASHES", "GROUP_BASH", "PUSH_MON", "REVIVES" ] + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "POISON", "FILTHY", "BASHES", "GROUP_BASH", "PUSH_MON", "REVIVES" ] }, { "id": "dks_mon_stray_cop", @@ -68,20 +68,7 @@ "death_drops": "mon_zombie_cop_death_drops", "upgrades": { "half_life": 60, "into": "dks_mon_crystal_baby" }, "death_function": [ "NORMAL" ], - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "STUMBLES", - "WARM", - "BASHES", - "GROUP_BASH", - "POISON", - "BLEED", - "PUSH_MON", - "FILTHY", - "REVIVES" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "GROUP_BASH", "POISON", "PUSH_MON", "FILTHY", "REVIVES" ] }, { "id": "dks_mon_stray_soldier", @@ -121,7 +108,7 @@ "death_drops": "mon_zombie_soldier_death_drops", "death_function": [ "NORMAL" ], "upgrades": { "half_life": 60, "into": "dks_mon_crystal_baby" }, - "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "BLEED", "PUSH_MON", "FILTHY", "REVIVES" ] + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "PUSH_MON", "FILTHY", "REVIVES" ] }, { "id": "dks_mon_stray_fireman", @@ -166,7 +153,6 @@ "BASHES", "GROUP_BASH", "POISON", - "BLEED", "NO_BREATHE", "REVIVES", "PUSH_MON", @@ -207,20 +193,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "upgrades": { "half_life": 21, "into": "dks_mon_stray_eater" }, - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "BASHES", - "GROUP_BASH", - "PUSH_MON", - "STUMBLES", - "WARM", - "POISON", - "BLEED", - "FILTHY", - "REVIVES" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "BASHES", "GROUP_BASH", "PUSH_MON", "STUMBLES", "WARM", "POISON", "FILTHY", "REVIVES" ] }, { "id": "dks_mon_stray_eater", @@ -466,7 +439,6 @@ "PUSH_MON", "PATH_AVOID_FIRE", "FILTHY", - "BLEED", "REVIVES" ] }, @@ -521,7 +493,6 @@ "PATH_AVOID_FALL", "PATH_AVOID_FIRE", "FILTHY", - "BLEED", "REVIVES" ] }, @@ -577,7 +548,6 @@ "PUSH_MON", "PATH_AVOID_DANGER_1", "FILTHY", - "BLEED", "REVIVES" ] }, @@ -772,20 +742,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_children_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "upgrades": { "half_life": 50, "into": "dks_mon_stray_wretch" }, - "flags": [ - "SEES", - "HEARS", - "SMELLS", - "BASHES", - "GROUP_BASH", - "STUMBLES", - "WARM", - "BLEED", - "GUILT", - "POISON", - "FILTHY", - "REVIVES" - ] + "flags": [ "SEES", "HEARS", "SMELLS", "BASHES", "GROUP_BASH", "STUMBLES", "WARM", "GUILT", "POISON", "FILTHY", "REVIVES" ] }, { "id": "dks_mon_stray_wretch_burnt", @@ -823,7 +780,6 @@ "SMELLS", "KEENNOSE", "BASHES", - "BLEED", "WARM", "POISON", "HIT_AND_RUN", @@ -876,7 +832,6 @@ "HEARS", "SMELLS", "KEENNOSE", - "BLEED", "WARM", "POISON", "CLIMBS", @@ -927,7 +882,6 @@ "SMELLS", "KEENNOSE", "ELECTRIC", - "BLEED", "WARM", "POISON", "CLIMBS", @@ -973,7 +927,6 @@ "SMELLS", "KEENNOSE", "ELECTRIC", - "BLEED", "HARDTOSHOOT", "WARM", "POISON", @@ -1064,7 +1017,6 @@ "HEARS", "SMELLS", "KEENNOSE", - "BLEED", "ELECTRIC", "WARM", "POISON", @@ -1278,7 +1230,7 @@ "special_attacks": [ [ "BOOMER_GLOW", 20 ], [ "STRETCH_ATTACK", 20 ], [ "LONGSWIPE", 20 ] ], "special_when_hit": [ "ZAPBACK", 100 ], "death_function": [ "BOOMER_GLOW", "DISINTEGRATE" ], - "flags": [ "SEES", "IMMOBILE", "NOGIB", "ELECTRIC", "BLEED", "WARM", "NO_BREATHE", "NOHEAD", "ARTHROPOD_BLOOD" ] + "flags": [ "SEES", "IMMOBILE", "NOGIB", "ELECTRIC", "WARM", "NO_BREATHE", "NOHEAD", "ARTHROPOD_BLOOD" ] }, { "id": "dks_mon_crystal_mite", diff --git a/data/mods/DinoMod/egg.json b/data/mods/DinoMod/egg.json index 615beeec8dfc8..851bf76b47ecc 100644 --- a/data/mods/DinoMod/egg.json +++ b/data/mods/DinoMod/egg.json @@ -3,7 +3,7 @@ "type": "COMESTIBLE", "id": "egg_dino", "name": "dinosaur egg", - "weight": 75, + "weight": "75 g", "color": "green", "spoils_in": "4 days", "comestible_type": "FOOD", @@ -14,7 +14,7 @@ "description": "Pale, football-shaped egg laid by a dinosaur.", "price": 500, "material": [ "egg" ], - "volume": 1, + "volume": "250 ml", "stack_size": 4, "fun": -6, "flags": [ "FREEZERBURN" ], diff --git a/data/mods/DinoMod/monstergroups/dinosaur.json b/data/mods/DinoMod/monstergroups/dinosaur.json index 63c0568c8586f..d1543cede0246 100644 --- a/data/mods/DinoMod/monstergroups/dinosaur.json +++ b/data/mods/DinoMod/monstergroups/dinosaur.json @@ -85,19 +85,87 @@ "name": "GROUP_DINOSAUR_ZOMBIE", "default": "mon_null", "monsters": [ - { "monster": "mon_zeinonychus", "freq": 3, "cost_multiplier": 30, "starts": 72, "pack_size": [ 2, 3 ] }, + { "monster": "mon_zallimimus", "freq": 50, "cost_multiplier": 10, "starts": 72, "pack_size": [ 4, 8 ] }, + { "monster": "mon_zachycephalosaurus", "freq": 25, "cost_multiplier": 10, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zamptosaurus", "freq": 100, "cost_multiplier": 10, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zpinosaurus", "freq": 1, "cost_multiplier": 90, "starts": 72 }, { "monster": "mon_zyrannosaurus", "freq": 1, "cost_multiplier": 80, "starts": 72 }, - { "monster": "mon_zpinosaurus", "freq": 1, "cost_multiplier": 90, "starts": 72 } + { "monster": "mon_zalbertosaurus", "freq": 4, "cost_multiplier": 70, "starts": 72 }, + { "monster": "mon_zriceratops", "freq": 3, "cost_multiplier": 60, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_ztegosaurus", "freq": 5, "cost_multiplier": 40, "starts": 72, "pack_size": [ 2, 4 ] }, + { "monster": "mon_zankylosaurus", "freq": 5, "cost_multiplier": 40, "starts": 72 }, + { "monster": "mon_zapatosaurus", "freq": 5, "cost_multiplier": 50, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zeratosaurus", "freq": 1, "cost_multiplier": 60, "starts": 72 }, + { "monster": "mon_zallosaurus", "freq": 8, "cost_multiplier": 60, "starts": 72 }, + { "monster": "mon_zeinonychus", "freq": 3, "cost_multiplier": 30, "starts": 72, "pack_size": [ 2, 3 ] }, + { "monster": "mon_zutahraptor", "freq": 5, "cost_multiplier": 60, "starts": 72 }, + { "monster": "mon_zarasaurolophus", "freq": 3, "cost_multiplier": 20, "starts": 72, "pack_size": [ 2, 4 ] }, + { "monster": "mon_zimorphodon", "freq": 50, "cost_multiplier": 10, "starts": 72, "pack_size": [ 2, 4 ] }, + { "monster": "mon_zilophosaurus", "freq": 1, "cost_multiplier": 20, "starts": 72, "pack_size": [ 1, 2 ] } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_zpinosaurus_UPGRADE", + "default": "mon_zpinosaurus_brute", + "monsters": [ + { "monster": "mon_zpinosaurus_shady", "freq": 15, "cost_multiplier": 5 }, + { "monster": "mon_zpinosaurus_brute", "freq": 23, "cost_multiplier": 5 } ] }, { "type": "monstergroup", "name": "GROUP_zyrannosaurus_UPGRADE", "default": "mon_syrannosaurus", - "//": "No dogs, humans, bionics, or profession-types", "monsters": [ { "monster": "mon_syrannosaurus", "freq": 45, "cost_multiplier": 5 }, - { "monster": "mon_zyrannosaurus_shady", "freq": 15, "cost_multiplier": 5 } + { "monster": "mon_zyrannosaurus_shady", "freq": 15, "cost_multiplier": 5 }, + { "monster": "mon_zyrannosaurus_brute", "freq": 23, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_zalbertosaurus_UPGRADE", + "default": "mon_salbertosaurus", + "monsters": [ + { "monster": "mon_salbertosaurus", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_zalbertosaurus_brute", "freq": 23, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_zeratosaurus_UPGRADE", + "default": "mon_seratosaurus", + "monsters": [ + { "monster": "mon_seratosaurus", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_zeratosaurus_brute", "freq": 23, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_zallosaurus_UPGRADE", + "default": "mon_sallosaurus", + "monsters": [ + { "monster": "mon_sallosaurus", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_zallosaurus_brute", "freq": 23, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_zeinonychus_UPGRADE", + "default": "mon_zeinonychus_brute", + "monsters": [ + { "monster": "mon_zeinonychus_shady", "freq": 15, "cost_multiplier": 5 }, + { "monster": "mon_zeinonychus_brute", "freq": 23, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_zutahraptor_UPGRADE", + "default": "mon_sutahraptor", + "monsters": [ + { "monster": "mon_sutahraptor", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_zutahraptor_brute", "freq": 23, "cost_multiplier": 5 } ] }, { @@ -105,9 +173,23 @@ "name": "GROUP_ZOMBIE", "default": "mon_zombie", "monsters": [ - { "monster": "mon_zeinonychus", "freq": 3, "cost_multiplier": 30, "starts": 72, "pack_size": [ 2, 3 ] }, + { "monster": "mon_zallimimus", "freq": 5, "cost_multiplier": 10, "starts": 72, "pack_size": [ 4, 8 ] }, + { "monster": "mon_zachycephalosaurus", "freq": 3, "cost_multiplier": 10, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zamptosaurus", "freq": 10, "cost_multiplier": 10, "starts": 72, "pack_size": [ 1, 2 ] }, { "monster": "mon_zpinosaurus", "freq": 1, "cost_multiplier": 90, "starts": 72 }, - { "monster": "mon_zyrannosaurus", "freq": 1, "cost_multiplier": 80, "starts": 72 } + { "monster": "mon_zyrannosaurus", "freq": 1, "cost_multiplier": 80, "starts": 72 }, + { "monster": "mon_zalbertosaurus", "freq": 4, "cost_multiplier": 70, "starts": 72 }, + { "monster": "mon_zriceratops", "freq": 3, "cost_multiplier": 60, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_ztegosaurus", "freq": 5, "cost_multiplier": 40, "starts": 72, "pack_size": [ 2, 4 ] }, + { "monster": "mon_zankylosaurus", "freq": 5, "cost_multiplier": 40, "starts": 72 }, + { "monster": "mon_zapatosaurus", "freq": 5, "cost_multiplier": 50, "starts": 72, "pack_size": [ 1, 2 ] }, + { "monster": "mon_zeratosaurus", "freq": 1, "cost_multiplier": 60, "starts": 72 }, + { "monster": "mon_zallosaurus", "freq": 8, "cost_multiplier": 60, "starts": 72 }, + { "monster": "mon_zeinonychus", "freq": 3, "cost_multiplier": 30, "starts": 72, "pack_size": [ 2, 3 ] }, + { "monster": "mon_zutahraptor", "freq": 5, "cost_multiplier": 60, "starts": 72 }, + { "monster": "mon_zarasaurolophus", "freq": 3, "cost_multiplier": 20, "starts": 72, "pack_size": [ 2, 4 ] }, + { "monster": "mon_zimorphodon", "freq": 5, "cost_multiplier": 10, "starts": 72, "pack_size": [ 2, 4 ] }, + { "monster": "mon_zilophosaurus", "freq": 1, "cost_multiplier": 20, "starts": 72, "pack_size": [ 1, 2 ] } ] } ] diff --git a/data/mods/DinoMod/monsters/dinosaur.json b/data/mods/DinoMod/monsters/dinosaur.json index 31c3d55a1f949..4c861b0a7b85f 100644 --- a/data/mods/DinoMod/monsters/dinosaur.json +++ b/data/mods/DinoMod/monsters/dinosaur.json @@ -42,7 +42,6 @@ "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", - "BLEED", "WARM", "SWIMS", "CATFOOD", @@ -223,19 +222,7 @@ "reproduction": { "baby_egg": "egg_spinosaurus", "baby_count": 3, "baby_timer": 24 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ - "SEES", - "SMELLS", - "HEARS", - "ANIMAL", - "PATH_AVOID_DANGER_1", - "BASHES", - "DESTROYS", - "BLEED", - "ATTACKMON", - "WARM", - "SWIMS" - ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "DESTROYS", "ATTACKMON", "WARM", "SWIMS" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], @@ -271,7 +258,7 @@ "reproduction": { "baby_egg": "egg_tyrannosaurus", "baby_count": 3, "baby_timer": 24 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "DESTROYS", "BLEED", "ATTACKMON", "WARM" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "DESTROYS", "ATTACKMON", "WARM" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], @@ -308,7 +295,7 @@ "reproduction": { "baby_egg": "egg_albertosaurus", "baby_count": 3, "baby_timer": 24 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "BLEED", "ATTACKMON", "WARM" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "ATTACKMON", "WARM" ], "special_attacks": [ [ "GRAB", 7 ], [ "LUNGE", 5 ] ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], @@ -543,7 +530,7 @@ "reproduction": { "baby_egg": "egg_ceratosaurus", "baby_count": 3, "baby_timer": 24 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "BLEED", "ATTACKMON", "WARM", "SWIMS" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "ATTACKMON", "WARM", "SWIMS" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], @@ -579,7 +566,7 @@ "reproduction": { "baby_egg": "egg_allosaurus", "baby_count": 3, "baby_timer": 24 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "BLEED", "ATTACKMON", "WARM" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "ATTACKMON", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], @@ -652,7 +639,7 @@ "reproduction": { "baby_egg": "egg_velociraptor", "baby_count": 3, "baby_timer": 18 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", "BLEED", "WARM", "CLIMBS" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", "WARM", "CLIMBS" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], @@ -697,7 +684,6 @@ "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", - "BLEED", "ATTACKMON", "WARM", "CLIMBS", @@ -739,7 +725,6 @@ "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", - "BLEED", "ATTACKMON", "WARM", "CLIMBS", @@ -782,7 +767,7 @@ "reproduction": { "baby_egg": "egg_utahraptor", "baby_count": 3, "baby_timer": 18 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", "BLEED", "ATTACKMON", "WARM", "CLIMBS" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", "ATTACKMON", "WARM", "CLIMBS" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], @@ -853,7 +838,7 @@ "reproduction": { "baby_egg": "egg_dimorphodon", "baby_count": 3, "baby_timer": 24 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "FLIES", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "BLEED" ], + "flags": [ "SEES", "SMELLS", "HEARS", "FLIES", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1" ], "harvest": "animal_noskin", "fear_triggers": [ "PLAYER_CLOSE", "FIRE", "FRIEND_DIED" ], "placate_triggers": [ "MEAT" ], @@ -868,7 +853,7 @@ "symbol": "D", "color": "magenta_green", "volume": "400000 ml", - "weight": 400000, + "weight": "400 kg", "material": [ "flesh" ], "aggression": 10, "morale": 30, @@ -888,7 +873,7 @@ "reproduction": { "baby_egg": "egg_dilophosaurus", "baby_count": 3, "baby_timer": 18 }, "baby_flags": [ "SPRING", "SUMMER" ], "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", "BLEED", "WARM" ], + "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "KEENNOSE", "WARM" ], "harvest": "mammal_leather", "anger_triggers": [ "PLAYER_WEAK", "HURT" ], "placate_triggers": [ "MEAT" ], diff --git a/data/mods/DinoMod/monsters/fungus.json b/data/mods/DinoMod/monsters/fungus.json index 551957b6e7f0c..122d5d67bff80 100644 --- a/data/mods/DinoMod/monsters/fungus.json +++ b/data/mods/DinoMod/monsters/fungus.json @@ -18,7 +18,7 @@ "vision_day": 5, "vision_night": 5, "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], - "upgrades": { "into": "mon_zpinosaurus_fungus" }, + "upgrades": { }, "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM", "SWIMS" ] }, { @@ -40,7 +40,7 @@ "vision_day": 5, "vision_night": 5, "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], - "upgrades": { "half_life": 1400000, "into_group": "GROUP_zyrannosaurus_UPGRADE" }, + "upgrades": { }, "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM" ] }, { @@ -62,7 +62,7 @@ "vision_day": 5, "vision_night": 5, "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], - "upgrades": { "into": "mon_zeinonychus_fungus" }, + "upgrades": { }, "flags": [ "SEES", "SMELLS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] } ] diff --git a/data/mods/DinoMod/monsters/zed-dinosaur.json b/data/mods/DinoMod/monsters/zed-dinosaur.json index 6789cf645a720..effe0b13ee955 100644 --- a/data/mods/DinoMod/monsters/zed-dinosaur.json +++ b/data/mods/DinoMod/monsters/zed-dinosaur.json @@ -26,6 +26,7 @@ "death_function": [ "NORMAL" ], "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "description": "The shuffling corpse of a medium-sized bipedal dinosaur covered with tattered feathers and black putrid liquid.", + "upgrades": { "half_life": 14, "into": "mon_zallimimus_brute" }, "flags": [ "SEES", "SMELLS", "HEARS", "POISON", "STUMBLES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ], "vision_night": 3, "harvest": "zed_dino_feather_leather", @@ -57,6 +58,7 @@ "death_function": [ "NORMAL" ], "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "description": "The shuffling corpse of a medium-sized bipedal dinosaur covered with tattered feathers and black putrid liquid. It looks like a reptilian ostrich with a round hard-looking domed head.", + "upgrades": { "half_life": 14, "into": "mon_zachycephalosaurus_brute" }, "flags": [ "SEES", "SMELLS", "HEARS", "POISON", "STUMBLES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ], "vision_night": 3, "harvest": "zed_dino_feather_leather", @@ -89,6 +91,7 @@ "death_function": [ "NORMAL" ], "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "description": "The shuffling corpse of a large feathered bipedal dinosaur with strong legs, broad shoulders and a pointed beak. Its tattered feathers are stained with black, sticky liquid.", + "upgrades": { "half_life": 14, "into": "mon_zamptosaurus_brute" }, "flags": [ "SEES", "SMELLS", "HEARS", "POISON", "STUMBLES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM", "BASHES" ], "vision_night": 3, "harvest": "zed_dino_feather_leather", @@ -120,7 +123,7 @@ "death_function": [ "NORMAL" ], "description": "Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing black eyes, and a tattered sail on its back.", "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], - "upgrades": { "half_life": 14, "into": "mon_zpinosaurus_shady" }, + "upgrades": { "half_life": 14, "into_group": "GROUP_zpinosaurus_UPGRADE" }, "flags": [ "SEES", "SMELLS", @@ -129,7 +132,6 @@ "STUMBLES", "BASHES", "DESTROYS", - "BLEED", "NO_BREATHE", "REVIVES", "FILTHY", @@ -140,33 +142,6 @@ "harvest": "zed_dino_feather_leather", "categories": [ "DINOSAUR", "CLASSIC" ] }, - { - "type": "MONSTER", - "id": "mon_zpinosaurus_shady", - "name": { "str": "Spinosaurus shady zombie" }, - "copy-from": "mon_zpinosaurus", - "color": "light_gray", - "description": "An uncanny shadow envelops this dinosaur. You can make out the outline of a huge bipedal dinosaur with a tattered sail. The head is long and narrow with a V-shaped snout.", - "flags": [ - "SEES", - "SMELLS", - "HEARS", - "POISON", - "STUMBLES", - "BASHES", - "DESTROYS", - "BLEED", - "NO_BREATHE", - "REVIVES", - "FILTHY", - "WARM", - "SWIMS", - "NIGHT_INVISIBILITY" - ], - "vision_day": 3, - "vision_night": 30, - "categories": [ "DINOSAUR" ] - }, { "type": "MONSTER", "id": "mon_zyrannosaurus", @@ -194,74 +169,11 @@ "description": "Massive piles of ragged, stinking flesh lifting enormous teeth.", "special_attacks": [ [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "upgrades": { "half_life": 14, "into_group": "GROUP_zyrannosaurus_UPGRADE" }, - "flags": [ - "SEES", - "SMELLS", - "HEARS", - "POISON", - "STUMBLES", - "BASHES", - "DESTROYS", - "BLEED", - "NO_BREATHE", - "REVIVES", - "FILTHY", - "WARM" - ], + "flags": [ "SEES", "SMELLS", "HEARS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ], "vision_night": 3, "harvest": "zed_dino_feather_leather", "categories": [ "DINOSAUR", "CLASSIC" ] }, - { - "type": "MONSTER", - "id": "mon_zyrannosaurus_shady", - "name": { "str": "Shady Z-Rex" }, - "copy-from": "mon_zyrannosaurus", - "color": "light_gray", - "description": "An uncanny shadow envelops this dinosaur. You can make out the outline of a huge bipedal dinosaur with feathery edges. The head looks big, lots of big teeth would fit in it.", - "flags": [ - "SEES", - "SMELLS", - "HEARS", - "POISON", - "STUMBLES", - "BASHES", - "DESTROYS", - "BLEED", - "NO_BREATHE", - "REVIVES", - "FILTHY", - "WARM", - "NIGHT_INVISIBILITY" - ], - "vision_day": 3, - "vision_night": 30, - "categories": [ "DINOSAUR" ] - }, - { - "type": "MONSTER", - "id": "mon_syrannosaurus", - "name": { "str": "S-Rex", "str_pl": "S-Rexes" }, - "copy-from": "mon_zyrannosaurus", - "color": "white", - "material": [ "bone" ], - "speed": 35, - "melee_skill": 13, - "melee_dice": 4, - "melee_dice_sides": 12, - "melee_cut": 20, - "armor_bash": 0, - "armor_cut": 30, - "armor_bullet": 30, - "armor_stab": 30, - "armor_acid": 3, - "vision_day": 30, - "hp": 200, - "description": "Monstrous columns of dense bone lifting enormous sharp pointed teeth dripping with black goo.", - "flags": [ "SEES", "HEARS", "POISON", "HARDTOSHOOT", "BLEED", "NO_BREATHE", "REVIVES", "FILTHY" ], - "harvest": "mr_bones", - "categories": [ "DINOSAUR" ] - }, { "type": "MONSTER", "id": "mon_zalbertosaurus", @@ -275,7 +187,8 @@ "armor_bullet": 3, "hp": 330, "special_attacks": [ { "type": "bite", "cooldown": 5 }, [ "GRAB", 7 ], [ "scratch", 20 ], [ "LUNGE", 5 ] ], - "description": "Massive jaws drooling black liquid lifted over grasping claws by a huge shuffling dinosaur corpse." + "description": "Massive jaws drooling black liquid lifted over grasping claws by a huge shuffling dinosaur corpse.", + "upgrades": { "half_life": 14, "into_group": "GROUP_zalbertosaurus_UPGRADE" } }, { "type": "MONSTER", @@ -295,7 +208,8 @@ "armor_cut": 5, "armor_bullet": 3, "hp": 250, - "description": "A massive shambling rhino-like dinosaur corpse with a bony crest from which three wicked looking horns emerge. Its black eyes ooze like tears." + "description": "A massive shambling rhino-like dinosaur corpse with a bony crest from which three wicked looking horns emerge. Its black eyes ooze like tears.", + "upgrades": { "half_life": 14, "into": "mon_zriceratops_brute" } }, { "type": "MONSTER", @@ -315,7 +229,8 @@ "armor_cut": 4, "armor_bullet": 2, "hp": 250, - "description": "A large shambling quadruped dinosaur corpse dragging with the weight of the plates on its back, waving a much livelier looking spiked tail." + "description": "A large shambling quadruped dinosaur corpse dragging with the weight of the plates on its back, waving a much livelier looking spiked tail.", + "upgrades": { "half_life": 14, "into": "mon_ztegosaurus_brute" } }, { "type": "MONSTER", @@ -335,7 +250,8 @@ "armor_cut": 7, "armor_bullet": 4, "hp": 200, - "description": "The shuffling corpse of what looks like a giant armadillo with peeling armored plates and black, glistening eyes. Its tail ends in a massive spiked club of bone." + "description": "The shuffling corpse of what looks like a giant armadillo with peeling armored plates and black, glistening eyes. Its tail ends in a massive spiked club of bone.", + "upgrades": { "half_life": 14, "into": "mon_zankylosaurus_brute" } }, { "type": "MONSTER", @@ -358,7 +274,8 @@ { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, [ "SMASH", 30 ] ], - "description": "Massive, long-necked, four-legged dinosaur corpse with a long, whip-like tail. The head is upright and the neck looks like it would still make a good strong club." + "description": "Massive, long-necked, four-legged dinosaur corpse with a long, whip-like tail. The head is upright and the neck looks like it would still make a good strong club.", + "upgrades": { "half_life": 14, "into": "mon_zapatosaurus_brute" } }, { "type": "MONSTER", @@ -378,20 +295,8 @@ "armor_bullet": 2, "hp": 115, "description": "This zombie is enormous, scaly, studded with bony spikes, and it moves with horrible speed. Its colorful horns are worn and wet with filth and its bright scales and bone spikes have taken a beating.", - "flags": [ - "SEES", - "SMELLS", - "HEARS", - "BASHES", - "BLEED", - "POISON", - "STUMBLES", - "NO_BREATHE", - "REVIVES", - "FILTHY", - "WARM", - "SWIMS" - ] + "upgrades": { "half_life": 14, "into_group": "GROUP_zeratosaurus_UPGRADE" }, + "flags": [ "SEES", "SMELLS", "HEARS", "BASHES", "POISON", "STUMBLES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM", "SWIMS" ] }, { "type": "MONSTER", @@ -411,7 +316,8 @@ "armor_bullet": 2, "hp": 200, "description": "The shambling corpse of a large predatory bipedal dinosaur, with tiger-like stripes on its broad, scaled back.", - "flags": [ "SEES", "SMELLS", "HEARS", "POISON", "STUMBLES", "BASHES", "BLEED", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ] + "upgrades": { "half_life": 14, "into_group": "GROUP_zallosaurus_UPGRADE" }, + "flags": [ "SEES", "SMELLS", "HEARS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ] }, { "type": "MONSTER", @@ -444,38 +350,13 @@ { "type": "bite", "cooldown": 5 } ], "description": "The shuffling corpse of a medium-sized bipedal dinosaur covered with tattered feathers and black putrid liquid. Both feet brandish a large sickle-like claw.", - "upgrades": { "half_life": 14, "into": "mon_zeinonychus_shady" }, - "flags": [ "SEES", "SMELLS", "HEARS", "KEENNOSE", "BLEED", "POISON", "STUMBLES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ], + "upgrades": { "half_life": 14, "into_group": "GROUP_zeinonychus_UPGRADE" }, + "flags": [ "SEES", "SMELLS", "HEARS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "REVIVES", "FILTHY", "WARM" ], "vision_day": 30, "vision_night": 10, "harvest": "zed_dino_feather_leather", "categories": [ "DINOSAUR", "CLASSIC" ] }, - { - "type": "MONSTER", - "id": "mon_zeinonychus_shady", - "name": { "str": "Deinonychus shady zombie" }, - "copy-from": "mon_zeinonychus", - "color": "light_gray", - "description": "An uncanny shadow envelops this dinosaur. You can make out the outline of a medium-sized bipedal dinosaur with feathery edges. Both feet brandish a large sickle-like claw.", - "flags": [ - "SEES", - "SMELLS", - "HEARS", - "KEENNOSE", - "BLEED", - "POISON", - "STUMBLES", - "NO_BREATHE", - "REVIVES", - "FILTHY", - "WARM", - "NIGHT_INVISIBILITY" - ], - "vision_day": 3, - "vision_night": 40, - "categories": [ "DINOSAUR" ] - }, { "type": "MONSTER", "id": "mon_zutahraptor", @@ -493,7 +374,8 @@ "armor_cut": 4, "armor_bullet": 2, "hp": 170, - "description": "The swaying, hopping corpse of a large bipedal dinosaur with feathered arms, a long tail, and long sharp scythe-like claws." + "description": "The swaying, hopping corpse of a large bipedal dinosaur with feathered arms, a long tail, and long sharp scythe-like claws.", + "upgrades": { "half_life": 14, "into_group": "GROUP_zutahraptor_UPGRADE" } }, { "type": "MONSTER", @@ -513,7 +395,8 @@ "armor_cut": 7, "armor_bullet": 4, "hp": 500, - "description": "A huge mottled dinosaur with a blunt head crest, dead and walking, eyes vacant and swollen." + "description": "A huge mottled dinosaur with a blunt head crest, dead and walking, eyes vacant and swollen.", + "upgrades": { "half_life": 14, "into": "mon_zarasaurolophus_brute" } }, { "type": "MONSTER", @@ -533,7 +416,8 @@ "armor_cut": 4, "armor_bullet": 1, "hp": 50, - "description": "The raggedly flying corpse of a feathered reptile over three feet long, with short wings and a big colorful beak." + "description": "The raggedly flying corpse of a feathered reptile over three feet long, with short wings and a big colorful beak.", + "upgrades": { "half_life": 14, "into": "mon_zimorphodon_brute" } }, { "type": "MONSTER", @@ -552,6 +436,7 @@ "armor_cut": 4, "armor_bullet": 2, "hp": 200, - "description": "The shuffling corpse of a medium dinosaur with sharp teeth and two prominent bony crests on its head with ragged strips of ripped flesh hanging down like a frill." + "description": "The shuffling corpse of a medium dinosaur with sharp teeth and two prominent bony crests on its head with ragged strips of ripped flesh hanging down like a frill.", + "upgrades": { "half_life": 14, "into": "mon_zilophosaurus_brute" } } ] diff --git a/data/mods/DinoMod/monsters/zinosaur_upgrade.json b/data/mods/DinoMod/monsters/zinosaur_upgrade.json new file mode 100644 index 0000000000000..0ec03170a5bf2 --- /dev/null +++ b/data/mods/DinoMod/monsters/zinosaur_upgrade.json @@ -0,0 +1,596 @@ +[ + { + "type": "MONSTER", + "id": "mon_zallimimus_brute", + "name": { "str": "Gruesome Gallimimus" }, + "copy-from": "mon_zallimimus", + "description": "The shuffling corpse of a medium-sized bipedal dinosaur covered with tattered feathers and black putrid liquid. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zachycephalosaurus_brute", + "name": { "str": "Skull Breaker" }, + "copy-from": "mon_zachycephalosaurus", + "description": "The shuffling corpse of a medium-sized bipedal dinosaur covered with tattered feathers and black putrid liquid. Its round, hard-looking domed head sits on a body bulging with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zamptosaurus_brute", + "name": { "str": "Crusher Camp" }, + "copy-from": "mon_zamptosaurus", + "description": "The shuffling corpse of a large feathered bipedal dinosaur with grossly bulging legs, massive hulking shoulders and a vicious pointed beak. Its tattered feathers are stained with black, sticky liquid.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zpinosaurus_brute", + "name": { "str": "Spino Sledge" }, + "copy-from": "mon_zpinosaurus", + "description": "Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing black eyes, and a tattered sail on its back. Its body is even bigger than normal, bulging with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zyrannosaurus_brute", + "name": { "str": "Rage Rex" }, + "copy-from": "mon_zyrannosaurus", + "description": "Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zalbertosaurus_brute", + "name": { "str": "Alberta Anvil" }, + "copy-from": "mon_zalbertosaurus", + "description": "Massive jaws and grabbing claws lifting by a body bulging with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ], [ "GRAB", 7 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zriceratops_brute", + "name": { "str": "Triceratruck" }, + "copy-from": "mon_zriceratops", + "description": "A massive shambling rhino-like dinosaur corpse with a bony crest from which three wicked looking horns emerge. Its black eyes ooze like tears. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_ztegosaurus_brute", + "name": { "str": "Stegosaurus Sledge" }, + "copy-from": "mon_ztegosaurus", + "description": "A large shambling quadruped dinosaur corpse with plates on its back, waving a spiked tail. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zankylosaurus_brute", + "name": { "str": "Dino Tank" }, + "copy-from": "mon_zankylosaurus", + "description": "Heavily armored zombie dinosaur. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zapatosaurus_brute", + "name": { "str": "Zombie Dreadnought" }, + "copy-from": "mon_zapatosaurus", + "description": "Massive, long-necked, four-legged dinosaur corpse with a long, whip-like tail. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zeratosaurus_brute", + "name": { "str": "Draco Titan" }, + "copy-from": "mon_zeratosaurus", + "description": "This zombie is enormous, scaly, studded with bony spikes, and it moves with horrible speed. Its colorful horns and bone spikes sit on a body bulging with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zallosaurus_brute", + "name": { "str": "Allosaurus Avalanche" }, + "copy-from": "mon_zallosaurus", + "description": "The shambling corpse of a large predatory bipedal dinosaur. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zeinonychus_brute", + "name": { "str": "Deino Destroyer" }, + "copy-from": "mon_zeinonychus", + "description": "The shuffling corpse of a medium-sized bipedal dinosaur covered with tattered feathers and black putrid liquid. Both feet brandish a large sickle-like claw. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zutahraptor_brute", + "name": { "str": "Utah Hoodoo" }, + "copy-from": "mon_zutahraptor", + "description": "The swaying, hopping corpse of a large bipedal dinosaur with feathered arms, a long tail, and long sharp scythe-like claws. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zarasaurolophus_brute", + "name": { "str": "Parasaur Punch" }, + "copy-from": "mon_zarasaurolophus", + "description": "A huge mottled dinosaur with a blunt head crest, dead and walking, eyes vacant and swollen. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zimorphodon_brute", + "name": { "str": "Winged Horror" }, + "copy-from": "mon_zimorphodon", + "description": "The flying corpse of a feathered reptile over three feet long, with short wings and a big colorful beak. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zilophosaurus_brute", + "name": { "str": "Crested Crusher" }, + "copy-from": "mon_zilophosaurus", + "description": "The shuffling corpse of a medium dinosaur with sharp teeth and two prominent bony crests on its head with ragged strips of ripped flesh hanging down like a frill. Its entire body bulges with distended muscles and swollen, festering wounds.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "upgrades": { }, + "special_attacks": [ [ "SMASH", 30 ] ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_MON", "PUSH_VEH" ] }, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zpinosaurus_shady", + "name": { "str": "Spinosaurus shady zombie" }, + "copy-from": "mon_zpinosaurus", + "color": "light_gray", + "description": "An uncanny shadow envelops this dinosaur. You can make out the outline of a huge bipedal dinosaur with a tattered sail. The head is long and narrow with a V-shaped snout.", + "upgrades": { }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "POISON", + "STUMBLES", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "REVIVES", + "FILTHY", + "WARM", + "SWIMS", + "NIGHT_INVISIBILITY" + ], + "vision_day": 3, + "vision_night": 30, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zyrannosaurus_shady", + "name": { "str": "Shady Z-Rex" }, + "copy-from": "mon_zyrannosaurus", + "color": "light_gray", + "description": "An uncanny shadow envelops this dinosaur. You can make out the outline of a huge bipedal dinosaur with feathery edges. The head looks big, lots of big teeth would fit in it.", + "upgrades": { }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "POISON", + "STUMBLES", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "REVIVES", + "FILTHY", + "WARM", + "NIGHT_INVISIBILITY" + ], + "vision_day": 3, + "vision_night": 30, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_zeinonychus_shady", + "name": { "str": "Deinonychus shady zombie" }, + "copy-from": "mon_zeinonychus", + "color": "light_gray", + "description": "An uncanny shadow envelops this dinosaur. You can make out the outline of a medium-sized bipedal dinosaur with feathery edges. Both feet brandish a large sickle-like claw.", + "upgrades": { }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "KEENNOSE", + "POISON", + "STUMBLES", + "NO_BREATHE", + "REVIVES", + "FILTHY", + "WARM", + "NIGHT_INVISIBILITY" + ], + "vision_day": 3, + "vision_night": 40, + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_syrannosaurus", + "name": { "str": "S-Rex", "str_pl": "S-Rexes" }, + "copy-from": "mon_zyrannosaurus", + "color": "white", + "material": [ "bone" ], + "armor_bash": 0, + "description": "Monstrous columns of dense bone lifting enormous sharp pointed teeth dripping with black goo.", + "proportional": { "hp": 0.4, "speed": 0.875 }, + "relative": { + "melee_dice": 9, + "melee_dice_sides": 5, + "melee_cut": 7, + "armor_cut": 22, + "armor_bullet": 30, + "armor_stab": 30, + "armor_acid": 3, + "vision_day": -20 + }, + "upgrades": { }, + "extend": { "flags": [ "HARDTOSHOOT" ] }, + "harvest": "mr_bones", + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_salbertosaurus", + "name": { "str": "Skeletal Albertosaurus" }, + "copy-from": "mon_zalbertosaurus", + "color": "white", + "material": [ "bone" ], + "armor_bash": 0, + "description": "Monstrous columns of dense bone lifting sharp pointed teeth dripping with black goo. Skeletal claws reach ahead.", + "proportional": { "hp": 0.4, "speed": 0.875 }, + "relative": { + "melee_dice": 9, + "melee_dice_sides": 5, + "melee_cut": 7, + "armor_cut": 22, + "armor_bullet": 30, + "armor_stab": 30, + "armor_acid": 3, + "vision_day": -20 + }, + "upgrades": { }, + "extend": { "flags": [ "HARDTOSHOOT" ] }, + "harvest": "mr_bones", + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_seratosaurus", + "name": { "str": "Bone Dragon" }, + "copy-from": "mon_zeratosaurus", + "color": "white", + "material": [ "bone" ], + "armor_bash": 0, + "description": "Monstrous columns of dense bone lifting sharp pointed teeth dripping with black goo. Spikes and colorful horns jut out to complete the effect.", + "proportional": { "hp": 0.4, "speed": 0.875 }, + "relative": { + "melee_dice": 9, + "melee_dice_sides": 5, + "melee_cut": 7, + "armor_cut": 22, + "armor_bullet": 30, + "armor_stab": 30, + "armor_acid": 3, + "vision_day": -20 + }, + "upgrades": { }, + "extend": { "flags": [ "HARDTOSHOOT" ] }, + "harvest": "mr_bones", + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_sallosaurus", + "name": { "str": "Skeletal allosaurus" }, + "copy-from": "mon_zallosaurus", + "color": "white", + "material": [ "bone" ], + "armor_bash": 0, + "description": "Monstrous columns of dense bone lifting sharp pointed teeth dripping with black goo.", + "proportional": { "hp": 0.4, "speed": 0.875 }, + "relative": { + "melee_dice": 9, + "melee_dice_sides": 5, + "melee_cut": 7, + "armor_cut": 22, + "armor_bullet": 30, + "armor_stab": 30, + "armor_acid": 3, + "vision_day": -20 + }, + "upgrades": { }, + "extend": { "flags": [ "HARDTOSHOOT" ] }, + "harvest": "mr_bones", + "categories": [ "DINOSAUR" ] + }, + { + "type": "MONSTER", + "id": "mon_sutahraptor", + "name": { "str": "Utah Bones" }, + "copy-from": "mon_zutahraptor", + "color": "white", + "material": [ "bone" ], + "armor_bash": 0, + "description": "Monstrous columns of dense bone lifting sharp pointed teeth dripping with black goo. There is a long tail and long sharp scythe-like claws", + "proportional": { "hp": 0.4, "speed": 0.875 }, + "relative": { + "melee_dice": 9, + "melee_dice_sides": 5, + "melee_cut": 7, + "armor_cut": 22, + "armor_bullet": 30, + "armor_stab": 30, + "armor_acid": 3, + "vision_day": -20 + }, + "upgrades": { }, + "extend": { "flags": [ "HARDTOSHOOT" ] }, + "harvest": "mr_bones", + "categories": [ "DINOSAUR" ] + } +] diff --git a/data/mods/Fuji_Structures/worldgen/gas/s_gas_b21.json b/data/mods/Fuji_Structures/worldgen/gas/s_gas_b21.json index 7e3544246d05f..d73f21557f905 100644 --- a/data/mods/Fuji_Structures/worldgen/gas/s_gas_b21.json +++ b/data/mods/Fuji_Structures/worldgen/gas/s_gas_b21.json @@ -67,7 +67,7 @@ "i": "f_locker", "j": "f_bench", "k": "f_locker", - "l": "f_treadmill", + "l": [ "f_treadmill", "f_treadmill_mechanical" ], "m": "f_shower", "n": "f_toilet", "p": "f_sink", diff --git a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json index a3bb83542b657..398eaa75f7b0e 100644 --- a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json +++ b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json @@ -306,5 +306,15 @@ ], "type": "MIGRATION", "replace": "shot_pump" + }, + { + "id": "slamfire_shotgun", + "type": "MIGRATION", + "replace": "slamfire_shotgun" + }, + { + "id": "slamfire_shotgun_d", + "type": "MIGRATION", + "replace": "slamfire_shotgun_d" } ] diff --git a/data/mods/Generic_Guns/firearms/pistol_magnum.json b/data/mods/Generic_Guns/firearms/pistol_magnum.json index f1079f276cb95..1b935c3138296 100644 --- a/data/mods/Generic_Guns/firearms/pistol_magnum.json +++ b/data/mods/Generic_Guns/firearms/pistol_magnum.json @@ -44,7 +44,7 @@ "durability": 6, "blackpowder_tolerance": 60, "loudness": 25, - "barrel_length": 1, + "barrel_volume": "250 ml", "valid_mod_locations": [ [ "accessories", 2 ], [ "muzzle", 1 ], diff --git a/data/mods/Generic_Guns/firearms/shot.json b/data/mods/Generic_Guns/firearms/shot.json index 85f7ddeea8119..d566b22c79a9a 100644 --- a/data/mods/Generic_Guns/firearms/shot.json +++ b/data/mods/Generic_Guns/firearms/shot.json @@ -50,25 +50,19 @@ "ammo": [ "ammo_shot" ] }, { - "id": "slam_shotgun", - "copy-from": "slam_shotgun", + "id": "slamfire_shotgun", + "copy-from": "slamfire_shotgun", "type": "GUN", - "name": { "str": "slam-fire shotgun" }, + "name": { "str": "slam-fire pipe shotgun" }, "description": "A crude shotgun, composed of two thick steel pipes, an end cap and a nail. The lack of sights make this weapon only useful at point-blank range.", - "weight": "3629 g", - "volume": "2264 ml", - "looks_like": "pipe", - "price": 8500, - "price_postapoc": 1000, - "bashing": 8, - "material": [ "steel" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 960, - "durability": 4, - "clip_size": 1, - "modes": [ [ "DEFAULT", "single", 1 ] ], - "valid_mod_locations": [ [ "sling", 1 ], [ "sights mount", 1 ], [ "underbarrel mount", 1 ] ], - "flags": [ "RELOAD_EJECT" ], - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "shot": 1 } } ] + "ammo": [ "ammo_shot" ] + }, + { + "id": "slamfire_shotgun_d", + "copy-from": "slamfire_shotgun_d", + "type": "GUN", + "name": { "str": "double slam-fire pipe shotgun" }, + "description": "A crude shotgun, composed of two thick steel pipes, an end cap and a nail. The lack of sights make this weapon only useful at point-blank range.", + "ammo": [ "ammo_shot" ] } ] diff --git a/data/mods/Generic_Guns/magazines/grenade.json b/data/mods/Generic_Guns/magazines/grenade.json index 13d8f2c655acd..d5fc0146d0af8 100644 --- a/data/mods/Generic_Guns/magazines/grenade.json +++ b/data/mods/Generic_Guns/magazines/grenade.json @@ -4,7 +4,7 @@ "type": "MAGAZINE", "name": { "str": "grenade machine gun belt" }, "description": "An ammo belt consisting of metal linkages which separate from the belt upon firing. This one holds grenade cartridges and is too bulky to be worn like other ammo belts.", - "volume": 0, + "volume": "0 L", "price": 0, "material": [ "steel" ], "symbol": "#", diff --git a/data/mods/Generic_Guns/obsolete.json b/data/mods/Generic_Guns/obsolete.json index 452cccd75d252..69beceb33f2fb 100644 --- a/data/mods/Generic_Guns/obsolete.json +++ b/data/mods/Generic_Guns/obsolete.json @@ -43,5 +43,10 @@ "type": "recipe", "result": "rifle_pipe_rifle", "obsolete": true + }, + { + "type": "recipe", + "result": "slam_shotgun", + "obsolete": true } ] diff --git a/data/mods/Generic_Guns/recipes/recipes_firearms_single.json b/data/mods/Generic_Guns/recipes/recipes_firearms_single.json index 1c2998dfd75bc..b2914a75b4556 100644 --- a/data/mods/Generic_Guns/recipes/recipes_firearms_single.json +++ b/data/mods/Generic_Guns/recipes/recipes_firearms_single.json @@ -125,7 +125,7 @@ }, { "type": "recipe", - "result": "slam_shotgun", + "result": "slamfire_shotgun", "category": "CC_WEAPON", "subcategory": "CSC_WEAPON_RANGED", "skill_used": "mechanics", @@ -139,14 +139,13 @@ { "id": "GLARE", "level": 2 }, { "id": "HAMMER", "level": 2 }, { "id": "FILE", "level": 1 }, - { "id": "WELD", "level": 2 } + { "id": "WELD", "level": 1 } ], "tools": [ [ [ "shot_buck", -1 ], [ "shot_fowl", -1 ], [ "shot_pyro", -1 ], - [ "shot_dart", -1 ], [ "shot_foster", -1 ], [ "shot_bean", -1 ], [ "reloaded_shot_buck", -1 ], @@ -165,5 +164,158 @@ ] ], "components": [ [ [ "pipe", 2 ] ], [ [ "nail", 1 ] ], [ [ "scrap", 3 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun", + "id_suffix": "without_welding", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "time": "1 h", + "autolearn": true, + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "DRILL", "level": 2 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WRENCH", "level": 1 } + ], + "tools": [ + [ + [ "shot_buck", -1 ], + [ "shot_fowl", -1 ], + [ "shot_pyro", -1 ], + [ "shot_foster", -1 ], + [ "shot_bean", -1 ], + [ "reloaded_shot_buck", -1 ], + [ "reloaded_shot_fowl", -1 ], + [ "reloaded_shot_pyro", -1 ], + [ "reloaded_shot_dart", -1 ], + [ "reloaded_shot_foster", -1 ], + [ "reloaded_shot_junk", -1 ], + [ "bp_shot_buck", -1 ], + [ "bp_shot_fowl", -1 ], + [ "bp_shot_pyro", -1 ], + [ "bp_shot_dart", -1 ], + [ "bp_shot_foster", -1 ], + [ "bp_shot_junk", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "pipe", 2 ] ], [ [ "nail", 1 ] ], [ [ "pipe_fittings", 1 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "difficulty": 2, + "time": "2 h", + "autolearn": true, + "book_learn": [ [ "manual_shotgun", 1 ] ], + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "GLARE", "level": 2 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WELD", "level": 1 } + ], + "tools": [ + [ + [ "shot_buck", -1 ], + [ "shot_fowl", -1 ], + [ "shot_pyro", -1 ], + [ "shot_foster", -1 ], + [ "shot_bean", -1 ], + [ "reloaded_shot_buck", -1 ], + [ "reloaded_shot_fowl", -1 ], + [ "reloaded_shot_pyro", -1 ], + [ "reloaded_shot_dart", -1 ], + [ "reloaded_shot_foster", -1 ], + [ "reloaded_shot_junk", -1 ], + [ "bp_shot_buck", -1 ], + [ "bp_shot_fowl", -1 ], + [ "bp_shot_pyro", -1 ], + [ "bp_shot_dart", -1 ], + [ "bp_shot_foster", -1 ], + [ "bp_shot_junk", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "pipe", 4 ] ], [ [ "nail", 2 ] ], [ [ "scrap", 5 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "id_suffix": "welded_and_bolted", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "difficulty": 2, + "time": "2 h", + "autolearn": true, + "book_learn": [ [ "manual_shotgun", 1 ] ], + "qualities": [ + { "id": "SAW_M", "level": 1 }, + { "id": "GLARE", "level": 2 }, + { "id": "HAMMER", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "WELD", "level": 1 } + ], + "tools": [ + [ + [ "shot_buck", -1 ], + [ "shot_fowl", -1 ], + [ "shot_pyro", -1 ], + [ "shot_foster", -1 ], + [ "shot_bean", -1 ], + [ "reloaded_shot_buck", -1 ], + [ "reloaded_shot_fowl", -1 ], + [ "reloaded_shot_pyro", -1 ], + [ "reloaded_shot_dart", -1 ], + [ "reloaded_shot_foster", -1 ], + [ "reloaded_shot_junk", -1 ], + [ "bp_shot_buck", -1 ], + [ "bp_shot_fowl", -1 ], + [ "bp_shot_pyro", -1 ], + [ "bp_shot_dart", -1 ], + [ "bp_shot_foster", -1 ], + [ "bp_shot_junk", -1 ], + [ "shot_hull", -1 ] + ] + ], + "components": [ [ [ "pipe", 4 ] ], [ [ "nail", 2 ] ], [ [ "pipe_fittings", 2 ] ], [ [ "scrap", 2 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "id_suffix": "welded_together", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "difficulty": 1, + "time": "2 h", + "autolearn": true, + "qualities": [ { "id": "WELD", "level": 1 } ], + "components": [ [ [ "slamfire_shotgun", 2 ] ], [ [ "scrap", 2 ] ] ] + }, + { + "type": "recipe", + "result": "slamfire_shotgun_d", + "id_suffix": "taped_together", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ [ "gun", 1 ] ], + "time": "1 h", + "autolearn": true, + "components": [ [ [ "slamfire_shotgun", 2 ] ], [ [ "duct_tape", 100 ] ] ] } ] diff --git a/data/mods/Magiclysm/items/alchemy_items.json b/data/mods/Magiclysm/items/alchemy_items.json index 1ea8c222106b0..9345100f06711 100644 --- a/data/mods/Magiclysm/items/alchemy_items.json +++ b/data/mods/Magiclysm/items/alchemy_items.json @@ -119,7 +119,7 @@ "description": "The powdered remains of a will-o-wisps's physical form. It seems to still possess an otherworldly glow.", "material": [ "powder" ], "weight": "5 g", - "volume": 1 + "volume": "250 ml" }, { "id": "glow_light", @@ -165,7 +165,7 @@ "description": "The great plates from behind a bulette's head have always been prized for use in shield and armor making.", "material": [ "arcane_skin" ], "weight": "30 kg", - "volume": 12 + "volume": "3 L" }, { "id": "bulette_pearl", @@ -176,7 +176,7 @@ "description": "As a bulette burrows through the earth its gills collect minute amounts of precious metals and gems which slowly aggregate into lustrous gemstones prized for their beauty and power.", "material": [ "stone" ], "weight": "120 g", - "volume": 1 + "volume": "250 ml" }, { "id": "dragon_essence", diff --git a/data/mods/Magiclysm/items/books_lore.json b/data/mods/Magiclysm/items/books_lore.json index d7920c471160f..33b24e508593e 100644 --- a/data/mods/Magiclysm/items/books_lore.json +++ b/data/mods/Magiclysm/items/books_lore.json @@ -43,7 +43,7 @@ "name": "old photo", "description": "A photo of a jovial, old wizard, he seems to be dancing with a coat rack in this basement. There is a stack of suitcases in the background.", "weight": "1 g", - "volume": 0, + "volume": "0 L", "price": 800, "material": [ "paper" ], "symbol": "*", diff --git a/data/mods/Magiclysm/items/enchanted_gunmods.json b/data/mods/Magiclysm/items/enchanted_gunmods.json index 3ac8615b79ec5..073a736aab194 100644 --- a/data/mods/Magiclysm/items/enchanted_gunmods.json +++ b/data/mods/Magiclysm/items/enchanted_gunmods.json @@ -29,7 +29,7 @@ "description": "A small visible-light laser using light shown through a mana crystal that mounts on a firearm's accessory rail to enhance ease and speed of target acquisition. Aside from increased weight, there are no drawbacks. You can rotate the attachment rail to fit under the barrel.", "weight": "108 g", "volume": "250 ml", - "integral_volume": 0, + "integral_volume": "0 L", "price": 36000, "material": [ "plastic", "steel" ], "symbol": ":", @@ -48,7 +48,7 @@ "description": "A small visible-light laser using light shown through a mana crystal that mounts on a firearm's accessory rail to enhance ease and speed of target acquisition. Aside from increased weight, there are no drawbacks. You can rotate the attachment rail to fit on the rail.", "weight": "108 g", "volume": "250 ml", - "integral_volume": 0, + "integral_volume": "0 L", "price": 36000, "material": [ "plastic", "steel" ], "symbol": ":", @@ -68,7 +68,7 @@ "description": "Adds a blue dot optic made from crystallized mana to the top of your gun, replacing the iron sights. Increases accuracy and weight.", "weight": "270 g", "volume": "250 ml", - "integral_volume": 0, + "integral_volume": "0 L", "price": 68000, "material": [ "plastic", "steel" ], "symbol": ":", diff --git a/data/mods/Magiclysm/items/enchanted_misc.json b/data/mods/Magiclysm/items/enchanted_misc.json index a31fd6860ca07..39b097220230a 100644 --- a/data/mods/Magiclysm/items/enchanted_misc.json +++ b/data/mods/Magiclysm/items/enchanted_misc.json @@ -53,7 +53,7 @@ "name": { "str": "skeleton key of opening", "str_pl": "skeleton keys of opening" }, "description": "A small gold skeleton key. You can activate it to unlock locked things.", "weight": "20 g", - "volume": 0, + "volume": "0 L", "price": 500000, "material": [ "gold" ], "symbol": "[", diff --git a/data/mods/Magiclysm/items/enchanted_ranged.json b/data/mods/Magiclysm/items/enchanted_ranged.json index 9669ff05c6055..31119a80b097f 100644 --- a/data/mods/Magiclysm/items/enchanted_ranged.json +++ b/data/mods/Magiclysm/items/enchanted_ranged.json @@ -85,7 +85,7 @@ "modes": [ [ "DEFAULT", "single", 1 ] ], "ammo": [ "shot" ], "reload": 200, - "barrel_length": 2, + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "mechanism", 1 ] ], "reload_noise": "chuk chuk.", "flags": [ "RELOAD_ONE", "PUMP_ACTION", "DURABLE_MELEE", "SHEATH_SWORD" ], diff --git a/data/mods/Magiclysm/items/enchanted_rings.json b/data/mods/Magiclysm/items/enchanted_rings.json index 09ec19b12640e..0cdac26a70129 100644 --- a/data/mods/Magiclysm/items/enchanted_rings.json +++ b/data/mods/Magiclysm/items/enchanted_rings.json @@ -5,7 +5,7 @@ "name": "copper magic ring", "description": "A generic copper magic ring.", "weight": "4 g", - "volume": 0, + "volume": "0 L", "price": 5000, "material": [ "copper" ], "symbol": "[", @@ -21,7 +21,7 @@ "name": "magic ring", "description": "A generic silver magic ring.", "weight": "5 g", - "volume": 0, + "volume": "0 L", "price": 5000, "material": [ "silver" ], "symbol": "[", @@ -37,7 +37,7 @@ "name": "magic ring", "description": "A generic gold magic ring.", "weight": "9 g", - "volume": 0, + "volume": "0 L", "price": 5000, "material": [ "gold" ], "symbol": "[", @@ -53,7 +53,7 @@ "name": "magic ring", "description": "A generic platinum magic ring.", "weight": "11 g", - "volume": 0, + "volume": "0 L", "price": 5000, "material": [ "platinum" ], "symbol": "[", diff --git a/data/mods/Magiclysm/items/enchanted_unarmed.json b/data/mods/Magiclysm/items/enchanted_unarmed.json index 6daa637744fae..6434e14d8b5cf 100644 --- a/data/mods/Magiclysm/items/enchanted_unarmed.json +++ b/data/mods/Magiclysm/items/enchanted_unarmed.json @@ -88,7 +88,7 @@ "range": -8, "modes": [ [ "DEFAULT", "single", 1 ], [ "DOUBLE", "double", 2 ] ], "reload": 200, - "barrel_length": 2, + "barrel_volume": "500 ml", "valid_mod_locations": [ [ "mechanism", 1 ] ], "flags": [ "UNARMED_WEAPON", "DURABLE_MELEE", "NEVER_JAMS", "RELOAD_EJECT", "RELOAD_ONE" ], "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ], diff --git a/data/mods/Magiclysm/items/enchanted_wands.json b/data/mods/Magiclysm/items/enchanted_wands.json index 95deaa50f545f..1288ad08863eb 100644 --- a/data/mods/Magiclysm/items/enchanted_wands.json +++ b/data/mods/Magiclysm/items/enchanted_wands.json @@ -36,9 +36,8 @@ "material": [ "wood" ], "symbol": "|", "color": "brown", - "flags": [ "BELT_CLIP", "NONCONDUCTIVE" ], - "initial_charges": 20, - "max_charges": 20, + "flags": [ "BELT_CLIP", "NONCONDUCTIVE", "NO_UNLOAD", "NO_RELOAD" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "holster": true, "ammo_restriction": { "crystallized_mana": 20 } } ], "charges_per_use": 1 }, { diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index 6d3c6a06a4757..2cc6e97e9f495 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -83,8 +83,8 @@ "category": "tools", "name": "magic light", "description": "A small magical light that you can read by.", - "weight": 0, - "volume": 0, + "weight": "0 kg", + "volume": "0 L", "price": 0, "symbol": ",", "color": "light_green", @@ -234,8 +234,8 @@ "type": "ARMOR", "name": { "str": "flesh pouch", "str_pl": "flesh pouches" }, "description": "A large pouch of tough flesh on your back, filled with tiny tentacles that grasp and hold anything you place inside. It shifts and adjusts itself to minimize encumbrance.", - "weight": 0, - "volume": 0, + "weight": "0 kg", + "volume": "0 L", "price": 0, "material": [ "flesh" ], "symbol": "[", diff --git a/data/mods/Magiclysm/items/weapons.json b/data/mods/Magiclysm/items/weapons.json index c8f7f6817b412..4fc8c67375c52 100644 --- a/data/mods/Magiclysm/items/weapons.json +++ b/data/mods/Magiclysm/items/weapons.json @@ -38,7 +38,7 @@ "description": "This weapon measures about 3 feet in length and is fletched like an arrow for better accuracy. The business end of the javelin has wicked-looking barbs which could cause significant bleeding.", "weight": "2500 g", "volume": "2830 ml", - "flags": [ "SPEAR", "SHEATH_SPEAR", "JAVELIN", "TRADER_AVOID", "BLEED", "NO_REPAIR" ] + "flags": [ "SPEAR", "SHEATH_SPEAR", "JAVELIN", "TRADER_AVOID", "NO_REPAIR" ] }, { "id": "lizardfolk_javelin_gun", diff --git a/data/mods/Magiclysm/martialarts.json b/data/mods/Magiclysm/martialarts.json index f62196d17e1a4..d404b96f8de55 100644 --- a/data/mods/Magiclysm/martialarts.json +++ b/data/mods/Magiclysm/martialarts.json @@ -58,6 +58,8 @@ "cudgel_plus_two", "rapier_plus_one", "rapier_plus_two", + "estoc_plus_one", + "estoc_plus_two", "cavalry_sabre_plus_one", "cavalry_sabre_plus_two", "broadsword_plus_one", diff --git a/data/mods/Magiclysm/monsters/goblin.json b/data/mods/Magiclysm/monsters/goblin.json index 0a0798d1653b1..8d4c275c9ba4a 100644 --- a/data/mods/Magiclysm/monsters/goblin.json +++ b/data/mods/Magiclysm/monsters/goblin.json @@ -35,7 +35,7 @@ ] }, "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "WARM", "BASHES", "BLEED", "FILTHY", "PATH_AVOID_DANGER_2" ] + "flags": [ "SEES", "HEARS", "WARM", "BASHES", "FILTHY", "PATH_AVOID_DANGER_2" ] }, { "type": "MONSTER", diff --git a/data/mods/Magiclysm/monsters/monsters.json b/data/mods/Magiclysm/monsters/monsters.json index cb98c88e4abd0..2a15957aab636 100644 --- a/data/mods/Magiclysm/monsters/monsters.json +++ b/data/mods/Magiclysm/monsters/monsters.json @@ -248,7 +248,7 @@ "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "bite", "cooldown": 30 }, [ "GRAB", 15 ], [ "scratch", 15 ], [ "slam", 10 ], [ "SMASH", 30 ] ], "regenerates": 1, - "flags": [ "SEES", "SMELLS", "KEENNOSE", "PATH_AVOID_DANGER_1", "WARM", "GRABS", "BLEED", "FLAMMABLE" ] + "flags": [ "SEES", "SMELLS", "KEENNOSE", "PATH_AVOID_DANGER_1", "WARM", "GRABS", "FLAMMABLE" ] }, { "id": "mon_stirge", diff --git a/data/mods/Magiclysm/professions.json b/data/mods/Magiclysm/professions.json index 0f460566c65d1..cd898e0b6809a 100644 --- a/data/mods/Magiclysm/professions.json +++ b/data/mods/Magiclysm/professions.json @@ -271,6 +271,7 @@ "boots", "wristwatch", "holy_symbol", + "mbag", "priest_beginner", "whiskey", "whiskey", diff --git a/data/mods/Magiclysm/worldgen/magic_academy.json b/data/mods/Magiclysm/worldgen/magic_academy.json index 5fe37bae294f2..124cc479cd113 100644 --- a/data/mods/Magiclysm/worldgen/magic_academy.json +++ b/data/mods/Magiclysm/worldgen/magic_academy.json @@ -115,7 +115,13 @@ "palettes": [ "standard_domestic_palette" ], "traps": { "=": "tr_rollmat" }, "terrain": { " ": "t_thconc_floor", "`": "t_rock", "]": "t_door_glass_green_c", "#": "t_rock_blue", "~": "t_water_pool" }, - "furniture": { ")": "f_beaded_door", "}": "f_huge_mana_crystal", "!": "f_ergometer", "$": "f_treadmill", "%": "f_exercise" }, + "furniture": { + ")": "f_beaded_door", + "}": "f_huge_mana_crystal", + "!": [ "f_ergometer", "f_ergometer_mechanical" ], + "$": [ "f_treadmill", "f_treadmill_mechanical" ], + "%": "f_exercise" + }, "place_loot": [ { "item": "television", "x": 8, "y": 1, "chance": 100 }, { "item": "stereo", "x": 7, "y": 1, "chance": 100 } ], "items": { "q": [ diff --git a/data/mods/More_Locations/bandit_tower/bandit_tower_2trc_04.json b/data/mods/More_Locations/bandit_tower/bandit_tower_2trc_04.json index e3b27dfb5eadd..4dcb0b10af242 100644 --- a/data/mods/More_Locations/bandit_tower/bandit_tower_2trc_04.json +++ b/data/mods/More_Locations/bandit_tower/bandit_tower_2trc_04.json @@ -36,7 +36,7 @@ "rotation": 1, "palettes": [ "tri_tower", "upper_level", "bandit_tower_stuff" ], "terrain": { "5": "t_pavement", "8": "t_bridge", "y": "t_wall_wood" }, - "furniture": { "Y": "f_exercise", "J": "f_treadmill" }, + "furniture": { "Y": "f_exercise", "J": [ "f_treadmill", "f_treadmill_mechanical" ] }, "items": { "l": { "item": "sports", "chance": 20 }, "x": { "item": "allsporting", "chance": 20 } }, "npcs": { "@": { "class": "thug" } } } diff --git a/data/mods/More_Locations/tpalettes.json b/data/mods/More_Locations/tpalettes.json index 064bb40945c8f..d1257d5566d95 100644 --- a/data/mods/More_Locations/tpalettes.json +++ b/data/mods/More_Locations/tpalettes.json @@ -120,7 +120,7 @@ "P": "f_piano", "W": "f_wardrobe", "Y": "f_statue", - "Z": [ "f_treadmill", "f_exercise" ] + "Z": [ "f_treadmill", "f_treadmill_mechanical", "f_exercise" ] }, "items": { "$": { "item": "art", "chance": 75 }, @@ -642,7 +642,7 @@ "3": "f_dryer", "5": "f_pool_table", "7": "f_exercise", - "8": "f_treadmill", + "8": [ "f_treadmill", "f_treadmill_mechanical" ], "9": "f_pinball_machine", "0": "f_arcade_machine" } diff --git a/data/mods/My_Sweet_Cataclysm/sweet_med.json b/data/mods/My_Sweet_Cataclysm/sweet_med.json index 8880438c139a3..61543fc42d57f 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_med.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_med.json @@ -14,6 +14,6 @@ "charges": 3, "stack_size": 9, "flags": [ "NO_INGEST", "CANT_HEAL_EVERYONE" ], - "use_action": { "type": "heal", "bandages_power": 15, "bleed": 1, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 15, "bleed": 30, "move_cost": 300 } } ] diff --git a/data/mods/National_Guard_Camp/palettes/national_guard_camp.json b/data/mods/National_Guard_Camp/palettes/national_guard_camp.json index cc2263d43e805..eb4d7b3a4d59e 100644 --- a/data/mods/National_Guard_Camp/palettes/national_guard_camp.json +++ b/data/mods/National_Guard_Camp/palettes/national_guard_camp.json @@ -32,7 +32,7 @@ "t": "f_toilet", "u": "f_shower", "v": "f_oven", - "y": "f_treadmill" + "y": [ "f_treadmill", "f_treadmill_mechanical" ] }, "terrain": { " ": "t_thconc_floor", diff --git a/data/mods/National_Guard_Camp/palettes/national_guard_camp_b.json b/data/mods/National_Guard_Camp/palettes/national_guard_camp_b.json index e9e81b21b3ff2..83d7b77b4e9a8 100644 --- a/data/mods/National_Guard_Camp/palettes/national_guard_camp_b.json +++ b/data/mods/National_Guard_Camp/palettes/national_guard_camp_b.json @@ -31,7 +31,7 @@ "t": "f_toilet", "u": "f_shower", "v": "f_oven", - "y": "f_treadmill", + "y": [ "f_treadmill", "f_treadmill_mechanical" ], "z": "f_trashcan" }, "terrain": { diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index 0da4fd0a1ea26..7e90ae2473225 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -33,7 +33,7 @@ "material": [ "cotton" ], "symbol": ",", "color": "white", - "use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 0.5, "limb_power": 0 }, "WASH_HARD_ITEMS" ], + "use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 5, "limb_power": 0 }, "WASH_HARD_ITEMS" ], "flags": [ "NO_SALVAGE" ] }, { @@ -96,6 +96,7 @@ { "holster": true, "min_item_volume": "50 ml", + "max_item_length": "60 cm", "max_contains_volume": "1500 ml", "max_contains_weight": "1000 g", "moves": 50, @@ -104,6 +105,7 @@ { "holster": true, "min_item_volume": "50 ml", + "max_item_length": "60 cm", "max_contains_volume": "1500 ml", "max_contains_weight": "1000 g", "moves": 50, @@ -112,6 +114,7 @@ { "holster": true, "min_item_volume": "50 ml", + "max_item_length": "60 cm", "max_contains_volume": "1500 ml", "max_contains_weight": "1000 g", "moves": 50, @@ -120,6 +123,7 @@ { "holster": true, "min_item_volume": "50 ml", + "max_item_length": "60 cm", "max_contains_volume": "1500 ml", "max_contains_weight": "1000 g", "moves": 50, @@ -277,7 +281,7 @@ "holster": true, "max_contains_volume": "20 L", "max_contains_weight": "20 kg", - "item_restriction": [ "test_battery_disposable", "test_battery_rechargeable" ] + "item_restriction": [ "test_battery_disposable", "test_battery_rechargable" ] } ] }, @@ -1215,5 +1219,89 @@ "price": 0, "price_postapoc": 0, "fun": -20 + }, + { + "id": "test_swat_armor", + "repairs_like": "survivor_suit", + "type": "ARMOR", + "category": "armor", + "name": { "str": "SWAT armor" }, + "//": "This is well within the pricing structure I found for ballistic vest, shins, and LBE. LEO gear ain't cheap.", + "description": "A suit of black bulletproof armor with lots of pockets. The word SWAT is emblazoned across the back.", + "weight": "7800 g", + "volume": "13 L", + "price": 285000, + "price_postapoc": 2000, + "to_hit": -3, + "bashing": 6, + "material": [ "kevlar_layered", "cotton" ], + "symbol": "[", + "looks_like": "touring_suit", + "color": "dark_gray", + "armor_portion_data": [ { "covers": [ "torso", "LEGS", "ARMS" ], "coverage": 95, "encumbrance": [ 12, 25 ] } ], + "pocket_data": [ + { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, + { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, + { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "3 kg", "moves": 120 }, + { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "3 kg", "moves": 120 } + ], + "warmth": 35, + "material_thickness": 11, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 4, + "flags": [ "POCKETS", "STURDY" ] + }, + { + "id": "test_pants_fur", + "type": "ARMOR", + "name": { "str_sp": "fur pants" }, + "description": "A hefty pair of fur-lined pants.", + "weight": "920 g", + "volume": "4 L", + "price": 20000, + "price_postapoc": 100, + "to_hit": 1, + "material": [ "cotton", "fur" ], + "symbol": "[", + "looks_like": "pants", + "color": "brown", + "covers": [ "LEGS" ], + "coverage": 95, + "encumbrance": 16, + "max_encumbrance": 20, + "pocket_data": [ + { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, + { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, + { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, + { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + ], + "warmth": 80, + "material_thickness": 3, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 3, + "flags": [ "VARSIZE", "POCKETS" ] + }, + { + "id": "test_pants_faux_fur", + "type": "ARMOR", + "copy-from": "test_pants_fur", + "name": { "str_sp": "faux fur pants" }, + "description": "A pair of long cotton pants lined with warm imitation fur.", + "material": [ "faux_fur", "cotton" ], + "covers": [ "LEGS" ], + "warmth": 70 + }, + { + "id": "test_portion_faux_fur_pants_suit", + "type": "ARMOR", + "copy-from": "test_pants_fur", + "name": { "str_sp": "faux fur pants suit test thing" }, + "description": "A TEST OBJECT SHOULD NOT BE IN GAME", + "material": [ "faux_fur", "cotton" ], + "armor_portion_data": [ + { "covers": [ "torso", "leg_r", "arm_r" ], "coverage": 100, "encumbrance": [ 10, 25 ] }, + { "covers": [ "arm_l", "leg_l", "head" ], "coverage": 50, "encumbrance": 5 } + ], + "warmth": 5 } ] diff --git a/data/mods/Urban_Development/building_jsons/urban_20_duplex.json b/data/mods/Urban_Development/building_jsons/urban_20_duplex.json index ab03813b0dcf8..95e6333f27ef2 100644 --- a/data/mods/Urban_Development/building_jsons/urban_20_duplex.json +++ b/data/mods/Urban_Development/building_jsons/urban_20_duplex.json @@ -78,7 +78,7 @@ ], "palettes": [ "acidia_residential_commercial_palette" ], "terrain": { "7": "t_strconc_floor" }, - "furniture": { "7": "f_treadmill" }, + "furniture": { "7": [ "f_treadmill", "f_treadmill_mechanical" ] }, "items": { "'": { "item": "cleaning", "chance": 2 }, "D": { "item": "allclothes", "chance": 60 }, diff --git a/data/mods/Urban_Development/building_jsons/urban_33_hotel.json b/data/mods/Urban_Development/building_jsons/urban_33_hotel.json index e42a6a3a02bfa..9173d3810cf80 100644 --- a/data/mods/Urban_Development/building_jsons/urban_33_hotel.json +++ b/data/mods/Urban_Development/building_jsons/urban_33_hotel.json @@ -515,7 +515,7 @@ ], "palettes": [ "acidia_commercial_palette" ], "terrain": { " ": "t_linoleum_white", "!": "t_linoleum_white", "2": "t_linoleum_white" }, - "furniture": { "!": "f_ergometer", "2": "f_treadmill" }, + "furniture": { "!": [ "f_ergometer", "f_ergometer_mechanical" ], "2": [ "f_treadmill", "f_treadmill_mechanical" ] }, "items": { " ": { "item": "traveler", "chance": 1 }, "3": { "item": "traveler", "chance": 1 } }, "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 11 ], "y": [ 1, 18 ], "density": 0.4 } ] } diff --git a/data/mods/desert_region/desert_mammal.json b/data/mods/desert_region/desert_mammal.json index 828f178611574..53b6e8189a7ba 100644 --- a/data/mods/desert_region/desert_mammal.json +++ b/data/mods/desert_region/desert_mammal.json @@ -38,7 +38,6 @@ "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", - "BLEED", "PUSH_MON", "DESTROYS", "CATTLEFODDER", diff --git a/data/mods/desert_region/desert_monsters.json b/data/mods/desert_region/desert_monsters.json index bce4b7ea0cdd7..17685e7e77f94 100644 --- a/data/mods/desert_region/desert_monsters.json +++ b/data/mods/desert_region/desert_monsters.json @@ -57,7 +57,7 @@ "special_attacks": [ [ "FUNGUS", 200 ], [ "SMASH", 15 ], [ "FUNGUS_BRISTLE", 20 ], [ "FUNGUS_BIG_BLOSSOM", 30 ] ], "extend": { "flags": [ "POISON", "NO_BREATHE" ] }, "delete": { - "flags": [ "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "BLEED", "CATTLEFODDER", "GROUP_MORALE", "GOODHEARING", "SWARMS" ] + "flags": [ "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "CATTLEFODDER", "GROUP_MORALE", "GOODHEARING", "SWARMS" ] } }, { diff --git a/data/mods/desert_region/desert_regional_map_settings.json b/data/mods/desert_region/desert_regional_map_settings.json index d292d51678de5..d23a5d52b67a9 100644 --- a/data/mods/desert_region/desert_regional_map_settings.json +++ b/data/mods/desert_region/desert_regional_map_settings.json @@ -709,7 +709,22 @@ "spring_humidity_manual_mod": 10, "summer_humidity_manual_mod": 0, "autumn_humidity_manual_mod": 10, - "winter_humidity_manual_mod": 15 + "winter_humidity_manual_mod": 15, + "weather_types": [ + "clear", + "sunny", + "cloudy", + "light_drizzle", + "drizzle", + "rain", + "thunder", + "lightning", + "acid_drizzle", + "acid_rain", + "flurries", + "snowing", + "snowstorm" + ] }, "overmap_feature_flag_settings": { "clear_blacklist": false, "blacklist": [ ], "clear_whitelist": false, "whitelist": [ ] } } diff --git a/data/mods/rural_biome/rural_regional_map_settings.json b/data/mods/rural_biome/rural_regional_map_settings.json index c254c1cc0fbc3..32519ed5125c8 100644 --- a/data/mods/rural_biome/rural_regional_map_settings.json +++ b/data/mods/rural_biome/rural_regional_map_settings.json @@ -608,7 +608,22 @@ "base_acid": 0.0, "base_wind": 3.4, "base_wind_distrib_peaks": 80, - "base_wind_season_variation": 50 + "base_wind_season_variation": 50, + "weather_types": [ + "clear", + "sunny", + "cloudy", + "light_drizzle", + "drizzle", + "rain", + "thunder", + "lightning", + "acid_drizzle", + "acid_rain", + "flurries", + "snowing", + "snowstorm" + ] }, "overmap_feature_flag_settings": { "clear_blacklist": false, diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 5a0d798c2df3e..5c022b87163ae 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -1855,6 +1855,12 @@ "id": "sleep", "bindings": [ { "input_method": "keyboard", "key": "$" } ] }, + { + "type": "keybinding", + "name": "Workout", + "category": "DEFAULTMODE", + "id": "workout" + }, { "type": "keybinding", "name": "Control Vehicle", diff --git a/data/raw/keybindings/vehicle.json b/data/raw/keybindings/vehicle.json index f3cc5141bceb2..433cefb64acbc 100644 --- a/data/raw/keybindings/vehicle.json +++ b/data/raw/keybindings/vehicle.json @@ -223,6 +223,13 @@ "name": "Toggle tracking", "bindings": [ { "input_method": "keyboard", "key": "K" } ] }, + { + "id": "TOGGLE_SMART_ENGINE_CONTROLLER", + "type": "keybinding", + "category": "VEHICLE", + "name": "Toggle smart engine controller", + "bindings": [ { "input_method": "keyboard", "key": "Y" } ] + }, { "id": "TURRET_FIRE_MODE", "type": "keybinding", diff --git a/doc/ARTIFACTS.md b/doc/ARTIFACTS.md new file mode 100644 index 0000000000000..f5beaa44006a3 --- /dev/null +++ b/doc/ARTIFACTS.md @@ -0,0 +1,61 @@ +# Artifacts + +## Introduction + +An "artifact" is a special game item with unique "magic" effects. It uses a base item id and enhances it with further abilities. + +## Generation + +The procedural generation of artifacts is defined in Json. The object looks like the following: +```json +{ + "type": "relic_procgen_data", + "id": "cult", + "passive_add_procgen_values": [ + { + "weight": 100, + "min_value": -1, + "max_value": 1, + "type": "STRENGTH", + "increment": 1, + "power_per_increment": 250 + } + ], + "passive_mult_procgen_values": [ + { + "weight": 100, + "min_value": -1.5, + "max_value": 1.5, + "type": "STRENGTH", + "increment": 0.1, + "power_per_increment": 250 + } + ], + "type_weights": [ { "weight": 100, "value": "passive_enchantment_add" } ], + "items": [ { "weight": 100, "item": "spoon" } ] + } +``` + +### passive_add_procgen_values and passive_mult_procgen_values + +As the names suggest, these are *passive* benefits/penalties to having the artifact (ie. always present without activating the artifact's abilities). **Add** values add or subtract from existing scores, and **mult** values multiply them. These are entered as a list of possible 'abilities' the artifact could get. It does not by default get all these abilities, rather when it spawns it selects from the list provided. + +- **weight:** the weight of this value in the list, to be chosen randomly +- **min_value:** the minimum possible value for this value type. for add must be an integer, for mult it can be a float +- **max_value:** the maximum possible value for this value type. for add must be an integer, for mult it can be a float +- **type:** the type of enchantment value. see MAGIC.md for detailed documentation on enchantment values +- **increment:** the increment that is used for the power multiplier +- **power_per_increment:** the power value per increment + +### type_weights +This determines the relative weight of the 'add' and 'mult' types. When generated, an artifact first decides if it is going to apply an 'add' or a 'mult' ability based on the type_weights of each. Then it uses the weights of the entries under the selected type to pick an ability. This continues cycling until the artifact reaches the defined power level. Possible values right now that are functional are: +- passive_enchantment_add +- passive_enchantment_mult + +This must be included in a dataset or it could cause a crash. + +### items +This provides a list of possible items that this artifact can spawn as, if it appears randomly in a hard-coded map extra. + +## Power Level +An artifact's power level is a summation of its attributes. For example, each point of strength addition in the above object, the artifact is a +250 power, so an artifact with +2 strength would have a power level of 500. similarly, if an artifact had a strength multiplier of 0.8, it would have a power level of -500. diff --git a/doc/COMPILING/COMPILING-VS-VCPKG.md b/doc/COMPILING/COMPILING-VS-VCPKG.md index 376386d76bd08..7a52ec15f119b 100644 --- a/doc/COMPILING/COMPILING-VS-VCPKG.md +++ b/doc/COMPILING/COMPILING-VS-VCPKG.md @@ -29,7 +29,7 @@ cd vcpkg .\vcpkg integrate install ``` -4. Install (or upgrade) neccessary packages with following command line: +4. (Optionally) Install (or upgrade) necessary packages with following command line: #### install 64 bit dependencies: @@ -61,7 +61,7 @@ git clone https://github.com/CleverRaven/Cataclysm-DDA.git cd Cataclysm-DDA ``` -2. Open the provided solution (`msvc-full-features\Cataclysm-vcpkg-static.sln`) in `Visual Studio`, select configuration (`Release` or `Debug`) and platform (`x64` or `x86`) and build it. +2. Open the provided solution (`msvc-full-features\Cataclysm-vcpkg-static.sln`) in `Visual Studio`, select configuration (`Release` or `Debug`) and platform (`x64` or `x86`) and build it. All necessary dependencies will be built and cached for future use by vcpkg automatically. **Note**: This will compile release version with Sound, Tiles and Localization support (language files won't be automatically compiled). diff --git a/doc/DEVELOPER_FAQ.md b/doc/DEVELOPER_FAQ.md index d043f579b3247..b98bcfac9af30 100644 --- a/doc/DEVELOPER_FAQ.md +++ b/doc/DEVELOPER_FAQ.md @@ -46,7 +46,7 @@ The comments given in source code to structure `struct overmap_special` explain 1. Edit `data/json/bionics.json` and add your bionic near similar types. See `JSON_INFO.md` for a more in-depth review of the individual fields. 2. If you want the bionic to be available in the game world as an item, add it to `item_groups.json`, and add a bionic item to `data/json/items/bionics.json`. 3. Manually code in effects into the appropriate files, for activated bionics edit the `player::activate_bionic` function in `bionics.cpp`. -4. For bionic ranged weapons add the bionic weapon counterparts to `ranged.json`, give them the `NO_AMMO` and `BIO_WEAPON` flags. +4. For bionic ranged weapons add the bionic weapon counterparts to `ranged.json`, give them the `NO_AMMO` and `BIONIC_WEAPON` flags. 5. For bionic close combat weapons add the bionic weapon to `data/json/items/melee.json` give them `NON_STUCK`, `NO_UNWIELD` at least. ## How armor protection is calculated diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index c12ac74a150b0..c586b27509bfc 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -596,6 +596,8 @@ List of known flags, used in both `terrain.json` and `furniture.json`. - ```UNSTABLE``` Walking here cause the bouldering effect on the character. - ```USABLE_FIRE``` This terrain or furniture counts as a nearby fire for crafting. - ```WALL``` This terrain is an upright obstacle. Used for fungal conversion, and also implies `CONNECT_TO_WALL`. +- ```WORKOUT_LEGS``` This furniture is for training your legs. Needed for checks like `is_limb_broken()`. +- ```WORKOUT_ARMS``` This furniture is for training your arms. Needed for checks like `is_limb_broken()`. ### Examine Actions @@ -629,7 +631,6 @@ List of known flags, used in both `terrain.json` and `furniture.json`. - ```shrub_wildveggies``` Pick a wild veggies shrub. - ```slot_machine``` Gamble. - ```toilet``` Either drink or get water out of the toilet. -- ```trap``` Interact with a trap. - ```water_source``` Drink or get water from a water source. ### Fungal Conversions Only @@ -812,7 +813,7 @@ List of known flags, used in both `terrain.json` and `furniture.json`. - ```MESSY``` Creates more mess when pulping - ```NO_CVD``` Item can never be used with a CVD machine - ```NO_RELOAD``` Item can never be reloaded (even if has a valid ammo type). -- ```NO_UNWIELD``` Cannot unwield this item. +- ```NO_UNWIELD``` Cannot unwield this item. Fake weapons and tools produced by bionics should have this flag. Such items support unwield as a special case. - ```POLEARM``` Item is clumsy up close and does 70% of normal damage against adjacent targets. Should be paired with REACH_ATTACK. Simple reach piercing weapons like spears should not get this flag. - ```REACH_ATTACK``` Allows to perform reach attack. - ```SHEATH_KNIFE``` Item can be sheathed in a knife sheath, it applicable to small/medium knives (with volume not bigger than 2) @@ -911,7 +912,6 @@ Multiple death functions can be used. Not all combinations make sense. - ```BASHES``` Bashes down doors. - ```BILE_BLOOD``` Makes monster bleed bile. - ```BIRDFOOD``` Becomes friendly / tamed with bird food. -- ```BLEED``` Causes the player to bleed. - ```BONES``` May produce bones and sinews when butchered. - ```BORES``` Tunnels through just about anything (15x bash multiplier: dark wyrms' bash skill 12->180) - ```CAN_DIG``` Can dig _and_ walk. diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 138b3ed9092ba..912ebcf3bf586 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -43,6 +43,8 @@ Use the `Home` key to return to the top. - [`cbms`](#-cbms-) - [`traits`](#-traits-) + [Recipes](#recipes) + - [Recipe components](#recipe-components) + - [Overlapping recipe component requirements](#overlapping-recipe-component-requirements) + [Constructions](#constructions) + [Scent Types](#scent_types) + [Scores, Achievements, and Conducts](#scores-achievements-and-conducts) @@ -288,6 +290,7 @@ See below for specifics on the various items ## `data/json/requirements/` + Standard components and tools for crafting | Filename | Description @@ -300,6 +303,42 @@ Standard components and tools for crafting | uncraft.json | common results of taking stuff apart | vehicle.json | tools to work on vehicles +Recipe requirements are JSON objects with `"type": "requirement"`. They allow re-using common +groups of recipe ingredients, or alternative ingredients. For example, the `bread_sandwich` +requirement includes several alternative breads you could make a sandwich with: + +```json +{ + "id": "bread_sandwich", + "type": "requirement", + "//": "Bread appropriate for sandwiches.", + "components": [ + [ + [ "flatbread", 1 ], + [ "bread", 1 ], + [ "cornbread", 1 ], + [ "wastebread", 1 ], + [ "sourdough_bread", 1 ], + [ "biscuit", 1 ], + [ "brioche", 1 ] + ] + ] +} +``` + +This lets you simplify the "components" of sandwich recipes that could work with any of those breads, ex. + +```json +{ + "type": "recipe", + "result": "sandwich_honey", + "components": [ [ [ "bread_sandwich", 2, "LIST" ] ], [ [ "honeycomb", 1 ], [ "honey_bottled", 1 ] ] ], + "//": "..." +} +``` + +See the [Recipe components](#recipe-components) section for how to use the "components" syntax. + ## `data/json/vehicles/` @@ -395,7 +434,7 @@ This section describes each json file and their contents. Each json has their ow | Identifier | Description |--- |--- | id | Unique ID. Must be one continuous word, use underscores if necessary. -| picture | Array of string, each entry is a line of an ascii picture and must be at most 42 columns long. +| picture | Array of string, each entry is a line of an ascii picture and must be at most 41 columns long. ```C++ { @@ -442,6 +481,7 @@ This section describes each json file and their contents. Each json has their ow | squeamish_penalty | (_optional_) Mood effect of wearing filthy clothing on this part. (default: `0`) | stat_hp_mods | (_optional_) Values modifiying hp_max of this part following this formula: `hp_max += int_mod*int_max + dex_mod*dex_max + str_mod*str_max + per_mod*per_max + health_mod*get_healthy()` with X_max being the unmodifed value of the X stat and get_healthy() being the hidden health stat of the character. | bionic_slots | (_optional_) How many bionic slots does this part have. +| is_limb | (_optional_) Is this bodypart a limb. (default: `false`) ```C++ { @@ -885,6 +925,17 @@ Example: ] ``` +#### `proficiencies` + +(optional, array of proficiency ids) + +List of starting proficiency ids. + +Example: +```json +"proficiencies": [ "prof_knapping" ] +``` + Mods can modify this list (requires `"edit-mode": "modify"`, see example) via "add:skills" and "remove:skills", removing requires only the skill id. Example: ```C++ { @@ -973,7 +1024,7 @@ player will start with this as a nearby vehicle. A list of flags. TODO: document those flags here. -- ```NO_BONUS_ITEMS``` Prevent bonus items (such as inhalers with the ASTHMA trait) from being given to this profession +- `NO_BONUS_ITEMS` Prevent bonus items (such as inhalers with the ASTHMA trait) from being given to this profession Mods can modify this via `add:flags` and `remove:flags`. @@ -995,6 +1046,8 @@ Mods can modify this via `add:traits` and `remove:traits`. ### Recipes +Crafting recipes are defined as a JSON object with the following fields: + ```C++ "result": "javelin", // ID of resulting item "category": "CC_WEAPON", // Category of crafting recipe. CC_NONCRAFT used for disassembly recipes @@ -1021,6 +1074,14 @@ Mods can modify this via `add:traits` and `remove:traits`. [ "survival", 1 ], [ "fabrication", 2 ] ], +"proficiencies" : [ // The proficiencies related to this recipe + { + "proficiency": "prof_knapping", // The id of a proficiency + "required": false, // Whether or not you must have the proficiency to craft it. Incompatible with `time_multiplier` + "time_multiplier": 2.0 // The multiplier on time taken to craft this recipe if you do not have this proficiency + "fail_multiplier": 2.5 // The multiplier on failure chance when crafting without this proficiency. Defaults to 2.5. Multiple proficiencies will multiply this value. (if all have the default, it's fail_multiplier ^ n, where n is the number of proficiencies that are lacked) + } +] "batch_time_factors": [25, 15], // Optional factors for batch crafting time reduction. First number specifies maximum crafting time reduction as percentage, and the second number the minimal batch size to reach that number. In this example given batch size of 20 the last 6 crafts will take only 3750 time units. "flags": [ // A set of strings describing boolean features of the recipe "BLIND_EASY", @@ -1035,25 +1096,117 @@ Mods can modify this via `add:traits` and `remove:traits`. [ [ "fire", -1 ] // Charges consumed when tool is used, -1 means no charges are consumed ]], -"components": [ // Equivalent tools or components are surrounded by a single set of brackets -[ - [ "spear_wood", 1 ], // Number of charges/items required - [ "pointy_stick", 1 ] -], -[ - [ "rag", 1 ], - [ "leather", 1 ], - [ "fur", 1 ] -], +"components": [ // Items (or item alternatives) required to craft this recipe + [ + [ "item_a", 5 ] // First ingredient: need 5 of item_a + ], + [ + [ "item_b", 2 ], // Also need 2 of item_b... + [ "item_c", 4 ] // OR 4 of item_c (but do not need both) + ], + [ + // ... any number of other component ingredients (see below) + ] +] +``` + +#### Recipe components + +A recipe's "components" lists all the required items or ingredients needed to craft the finished +item from the recipe. Each ingredient is given as an integer quantity of a specific item id or +requirement id, or as a list of several equivalent item/requirement quantities. + +The syntax of an ingredient in its simplest form is an item id and quantity. Continuing the +"javelin" recipe, let's require a single "spear_wood" item: + +```json +"components": [ + [ [ "spear_wood", 1 ] ] +] +``` + +A single component may also have substitutions; for instance, to allow crafting from one +"spear_wood" *or* one "pointy_stick": + +```json +"components": [ + [ [ "spear_wood", 1 ], [ "pointy_stick", 1 ] ] +] +``` + +Notice that the first example with *only* "spear_wood" was simply the degenerate case - a list of +alternatives with only 1 alternative - which is why it was doubly nested in `[ [ ... ] ]`. + +The javelin would be better with some kind of leather or cloth grip. To require 2 rags, 1 leather, +or 1 fur *in addition to* the wood spear or pointy stick: + +```json +"components": [ + [ [ "spear_wood", 1 ], [ "pointy_stick", 1 ] ], + [ [ "rag", 2 ], [ "leather", 1 ], [ "fur", 1 ] ] +] +``` + +And to bind the grip onto the javelin, some sinew or thread should be required, which can have the +"NO_RECOVER" keyword to indicate they cannot be recovered if the item is deconstructed: + +```json +"components": [ + [ [ "spear_wood", 1 ], [ "pointy_stick", 1 ] ], + [ [ "rag", 2 ], [ "leather", 1 ], [ "fur", 1 ] ], + [ [ "sinew", 20, "NO_RECOVER" ], [ "thread", 20, "NO_RECOVER" ] ] +] +``` + +*Note*: Related to "NO_RECOVER", some items such as "superglue" and "duct_tape" have an +"UNRECOVERABLE" flag on the item itself, indicating they can never be reclaimed when disassembling. +See [JSON_FLAGS.md](JSON_FLAGS.md) for how to use this and other item flags. + +To avoid repeating commonly used sets of ingredient items, instead of an individual item id, +provide the id of a "requirement" type, along with a quantity, and the "LIST" keyword. +Typically these are defined within [`data/json/requirements`](#datajsonrequirements). + +For example if these "grip_patch" and "grip_wrap" requirements were defined: + +```json [ - [ "plant_fibre", 20, false ], // Optional flag for recoverability, default is true. - [ "sinew", 20, false ], - [ "thread", 20, false ], - [ "duct_tape", 20 ] // Certain items are flagged as unrecoverable at the item definition level. + { + "id": "grip_patch", + "type": "requirement", + "components": [ [ [ "rag", 2 ], [ "leather", 1 ], [ "fur", 1 ] ] ] + }, + { + "id": "grip_wrap", + "type": "requirement", + "components": [ [ [ "sinew", 20, "NO_RECOVER" ], [ "thread", 20, "NO_RECOVER" ] ] ] + } +] +``` + +Then javelin recipe components could use 1 grip and 1 wrap, for example: + +```json +"result": "javelin", +"components": [ + [ [ "spear_wood", 1 ], [ "pointy_stick", 1 ] ], + [ [ "grip_patch", 1, "LIST" ] ], + [ [ "grip_wrap", 1, "LIST" ] ] ] +``` + +And other recipes needing two such grips could simply require 2 of each: + +```json +"result": "big_staff", +"components": [ + [ [ "stick_long", 1 ] ], + [ [ "grip_patch", 2, "LIST" ] ], + [ [ "grip_wrap", 2, "LIST" ] ] ] ``` + + #### Overlapping recipe component requirements If recipes have requirements which overlap, this makes it more @@ -1519,7 +1672,7 @@ it is present to help catch errors. "trigger_type": "TIME", // What variable is tracked by this trigger "threshold_low": 20, // Is True if the value is above threshold_low "threshold_high": 2, // Is True if the value is below threshold_high - "msg_on": { "text": "Everything is terrible and this makes you so ANGRY!", "rating": "mixed" } // message displayed when the trigger activates + "msg_on": { "text": "Everything is terrible and this makes you so ANGRY!", "rating": "mixed" } // message displayed when the trigger activates "msg_off": { "text": "Your glow fades." } // message displayed when the trigger deactivates the trait } ] @@ -1539,7 +1692,7 @@ it is present to help catch errors. ### Traps ```C++ - "type": "trap", + "type": "trap", "id": "tr_beartrap", // Unique ID "name": "bear trap", // In-game name displayed "color": "blue", @@ -1548,7 +1701,7 @@ it is present to help catch errors. "avoidance": 7, // 0 to ??, affects avoidance "difficulty": 3, // 0 to ??, difficulty of assembly & disassembly "trap_radius": 1, // 0 to ??, trap radius - "action": "blade", + "action": "blade", "map_regen": "microlab_shifting_hall", // a valid overmap id, for map_regen action traps "benign": true, "always_invisible": true, @@ -1958,7 +2111,7 @@ When adding a new book, please use this color key: A few exceptions to this color key may apply, for example for books that don’t are what they seem to be. Never use `yellow` and `red`, those colors are reserved for sounds and infrared vision. -####CBMs +#### CBMs CBMs can be defined like this: @@ -2079,7 +2232,7 @@ Guns can be defined like this: "reload": 450, // Amount of time to reload, 100 = 1 second = 1 "turn" "built_in_mods": ["m203"], //An array of mods that will be integrated in the weapon using the IRREMOVABLE tag. "default_mods": ["m203"] //An array of mods that will be added to a weapon on spawn. -"barrel_length": "30 mL", // Amount of volume lost when the barrel is sawn. Approximately 250 ml per inch is a decent approximation. +"barrel_volume": "30 mL", // Amount of volume lost when the barrel is sawn. Approximately 250 ml per inch is a decent approximation. "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ] ], // The valid locations for gunmods and the mount of slots for that location. ``` Alternately, every item (book, tool, armor, even food) can be used as gun if it has gun_data: @@ -2575,7 +2728,7 @@ The contents of use_action fields can either be a string indicating a built-in f "limb_power" : 10, // How much hp to restore when healing limbs? Mandatory value "head_power" : 7, // How much hp to restore when healing head? If unset, defaults to 0.8 * limb_power. "torso_power" : 15, // How much hp to restore when healing torso? If unset, defaults to 1.5 * limb_power. - "bleed" : 0.4, // Chance to remove bleed effect. + "bleed" : 4, // How many bleed effect intensity levels can be reduced by it. Base value. "bite" : 0.95, // Chance to remove bite effect. "infect" : 0.1, // Chance to remove infected effect. "move_cost" : 250, // Cost in moves to use the item. diff --git a/doc/MODDING.md b/doc/MODDING.md index 058164b34043f..47e528138edef 100644 --- a/doc/MODDING.md +++ b/doc/MODDING.md @@ -13,6 +13,7 @@ A mod is created by creating a folder within Cataclysm's `data/mods` directory. The modinfo.json file is a file that contains metadata for your mod. Every mod must have a `modinfo.json` file in order for Cataclysm to find it. A barebones `modinfo.json` file looks like this: ````json +[ { "type": "MOD_INFO", "ident": "Mod_ID", @@ -22,6 +23,7 @@ A barebones `modinfo.json` file looks like this: "category": "content", "dependencies": [ "dda" ] } +] ```` The `category` attribute denotes where the mod will appear in the mod selection menu. These are the available categories to choose from, with some examples chosen from mods that existed when this document was written. Pick whichever one applies best to your mod when writing your modinfo file. - `content` - A mod that adds a lot of stuff. Typically reserved for very large mods or complete game overhauls (eg: Core game files, Aftershock) diff --git a/doc/NPCs.md b/doc/NPCs.md index 6248dce2a2aaa..b7c40527e44cc 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -426,7 +426,7 @@ Effect | Description `u_add_trait: trait_string`
`npc_add_trait: trait_string` | Your character or the NPC will gain the trait. `u_lose_effect: effect_string`
`npc_lose_effect: effect_string` | Your character or the NPC will lose the effect if they have it. `u_lose_trait: trait_string`
`npc_lose_trait: trait_string` | Your character or the NPC will lose the trait. -`u_add_var, npc_add_var`: `var_name, type: type_str`, `context: context_str`, `value: value_str` | Your character or the NPC will store `value_str` as a variable that can be later retrieved by `u_has_var` or `npc_has_var`. `npc_add_var` can be used to store arbitrary local variables, and `u_add_var` can be used to store arbitrary "global" variables, and should be used in preference to setting effects. +`u_add_var, npc_add_var`: `var_name, type: type_str`, `context: context_str`, either `value: value_str` or `time: true` | Your character or the NPC will store `value_str` as a variable that can be later retrieved by `u_has_var` or `npc_has_var`. `npc_add_var` can be used to store arbitrary local variables, and `u_add_var` can be used to store arbitrary "global" variables, and should be used in preference to setting effects. If `time` is used instead of `value_str`, then the current turn of the game is stored. `u_lose_var`, `npc_lose_var`: `var_name`, `type: type_str`, `context: context_str` | Your character or the NPC will clear any stored variable that has the same `var_name`, `type_str`, and `context_str`. `u_adjust_var, npc_adjust_var`: `var_name, type: type_str`, `context: context_str`, `adjustment: adjustment_num` | Your character or the NPC will adjust the stored variable by `adjustment_num`. `barber_hair` | Opens a menu allowing the player to choose a new hair style. @@ -554,6 +554,7 @@ Condition | Type | Description `"u_has_any_trait"`
`"npc_has_any_trait"` | array | `true` if the player character or NPC has any trait or mutation in the array. Used to check multiple specific traits. `"u_has_var"`, `"npc_has_var"` | string | `"type": type_str`, `"context": context_str`, and `"value": value_str` are required fields in the same dictionary as `"u_has_var"` or `"npc_has_var"`.
`true` is the player character or NPC has a variable set by `"u_add_var"` or `"npc_add_var"` with the string, `type_str`, `context_str`, and `value_str`. `"u_compare_var"`, `"npc_compare_var"` | dictionary | `"type": type_str`, `"context": context_str`, `"op": op_str`, `"value": value_num` are required fields, referencing a var as in `"u_add_var"` or `"npc_add_var"`.
`true` if the player character or NPC has a stored variable that is true for the provided operator `op_str` (one of `==`, `!=`, `<`, `>`, `<=`, `>=`) and value. +`"u_compare_time_since_var"`, `"npc_compare_time_since_var_"` | dictionary | `"type": type_str`, `"context": context_str`, `"op": op_str`, `"time": time_string` are required fields, referencing a var as in `"u_add_var"` or `"npc_add_var"`.
`true` if the player character or NPC has a stored variable and the current turn and that value (converted to a time point) plus the time_string is true for the provided operator `op_str` (one of `==`, `!=`, `<`, `>`, `<=`, `>=`). *example*: `{ "u_compare_time_since_var": "test", "type": "test", "context": "var_time_test", "op": ">", "time": "3 days" }` returns true if the player character has a "test", "test", "var_time_test" variable and the current turn is greater than that value plus 3 days' worth of turns. `"u_has_strength"`
`"npc_has_strength"` | int | `true` if the player character's or NPC's strength is at least the value of `u_has_strength` or `npc_has_strength`. `"u_has_dexterity"`
`"npc_has_dexterity"` | int | `true` if the player character's or NPC's dexterity is at least the value of `u_has_dexterity` or `npc_has_dexterity`. `"u_has_intelligence"`
`"npc_has_intelligence"` | int | `true` if the player character's or NPC's intelligence is at least the value of `u_has_intelligence` or `npc_has_intelligence`. diff --git a/doc/PROFICIENCY.md b/doc/PROFICIENCY.md new file mode 100644 index 0000000000000..859c401f5b28b --- /dev/null +++ b/doc/PROFICIENCY.md @@ -0,0 +1,19 @@ +# proficiency + +## definition + +```JSON +{ + "id": "prof_knapping", + "type": "proficiency", + "name": { "str": "Knapping" } +}, +``` +### `id` +Mandatory. The id of the proficiency. + +### `type` +Mandatory. Must be `proficiency`. + +### `name` +Mandatory. The name of the proficiency. diff --git a/doc/REGION_SETTINGS.md b/doc/REGION_SETTINGS.md index 4781f29931c00..584f7bb7c913c 100644 --- a/doc/REGION_SETTINGS.md +++ b/doc/REGION_SETTINGS.md @@ -494,6 +494,7 @@ The **weather** section defines the base weather attributes used for the region. | `base_wind` | Base wind for the region in mph units. Roughly the yearly average. | | `base_wind_distrib_peaks` | How high the wind peaks can go. Higher values produce windier days. | | `base_wind_season_variation` | How the wind varies with season. Lower values produce more variation | +| `weather_types` | Ids of the weather types allowed in this region. When choosing weather they will be iterated over in the order they are listed and the last valid entry will be the weather. | ### Example @@ -507,7 +508,23 @@ The **weather** section defines the base weather attributes used for the region. "base_wind": 5.7, "base_wind_distrib_peaks": 30, "base_wind_season_variation": 64, - "base_acid": 0.0 + "base_acid": 0.0, + "weather_types": [ + "clear", + "sunny", + "cloudy", + "light_drizzle", + "drizzle", + "rain", + "thunder", + "lightning", + "acid_drizzle", + "acid_rain", + "flurries", + "snowing", + "snowstorm" + ] + }, } } ``` diff --git a/doc/TRANSLATING.md b/doc/TRANSLATING.md index 85af77c583d2b..5803eaa09144a 100644 --- a/doc/TRANSLATING.md +++ b/doc/TRANSLATING.md @@ -2,6 +2,7 @@ * [Translators](#translators) * [Getting Started](#getting-Started) + * [Glossary](#glossary) * [Grammatical gender](#grammatical-gender) * [Tips](#tips) * [Developers](#developers) @@ -87,6 +88,22 @@ Click on the "Save" button when you are satisfied with your translation. See [Transifex's documentation][3] for more information. +### Glossary + +This glossary is intended to help explain some CDDA-specific terms and their +etymology in order to help translations. + +* **Exodii**: The Exodii are a bunch of humans from another dimension. When + the Blob invaded their world, they managed to acquire enough technology to + open portals of their own, and now they portal to worlds that have been + attacked by the Blob and try to rescue survivors. Exodii is a horrible + mangling of "Exodus" - the word literally means leaving or going out and has + connotations of forced emigration and refugees. The Exodii are the people of + an Exodus. While Exodus is a Latin word and "ii" to indicate a plural is a + Latin thing, but this isn't actually the [correct Latin + plural](https://www.latin-is-simple.com/en/vocabulary/noun/9294/) for this + word. + ### Grammatical gender For NPC dialogue (and potentially other strings) some languages may wish to diff --git a/doc/VITAMIN.md b/doc/VITAMIN.md index 2abcb854a2708..f00cb5d98073b 100644 --- a/doc/VITAMIN.md +++ b/doc/VITAMIN.md @@ -38,7 +38,7 @@ This is some toxic chemical or component. This currently has no effect. This is a drug. This currently has no effect. #### `counter` -This is a counter for something, that is neither a toxin, vitamin, or drug. This currently has no effect. +This is a counter for something, that is neither a toxin, vitamin, or drug. ### `name` What the vitamin shows up as where vitamins are displayed, such as the vitamins display in the item menu. diff --git a/doc/WEATHER_TYPE.md b/doc/WEATHER_TYPE.md new file mode 100644 index 0000000000000..84af9e821ac1c --- /dev/null +++ b/doc/WEATHER_TYPE.md @@ -0,0 +1,167 @@ +## Weather_type + +Each weather type is a type of weather that occurs, its effects and what causes it. The only required entries are null and clear. + + +##Fields + +| Identifier | Description | +| ------------------------------ | --------------------------------------------------------------------- | +| `name` | UI name of weather type. | +| `color` | UI color of weather type. | +| `map_color` | Map color of weather type. | +| `glyph` | Map glyph of weather type. | +| `ranged_penalty` | Penalty to ranged attacks. | +| `sight_penalty` | Penalty to per-square visibility, applied in transparency map. | +| `light_modifier` | modification to ambient light. | +| `sound_attn` | Sound attenuation of a given weather type. | +| `dangerous` | If true, our activity gets interrupted. | +| `precip` | Amount of associated precipitation. Valid values are: none, very_light, light and heavy | +| `rains` | Whether said precipitation falls as rain. | +| `acidic` | Whether said precipitation is acidic. | +| `tiles_animation` | Optional, name of the tiles animation to use | +| `sound_category` | Optional, if playing sound effects what to use. Valid values are: silent, drizzle, rainy, thunder, flurries, + snowstorm and snow. | +| `sun_intensity` | Strength of the sun. Valid values are: none, light, normal, and high | +| `weather_animation` | Optional, Information controlling weather animations. Members: factor, color and glyph | +| `effects` | Array for the effects the weather has. Descibed in detail below +| `requirements` | Optional, is what determines what weather it is. All members are optional. + When checking what weather it is it loops through the entries in order and uses the last one to succeed. | + + `pressure_min` + `pressure_max` + `humidity_min` + `humidity_max` + `temperature_min` + `temperature_max` + `windpower_min` + `windpower_max` + | These are all minimum and maximum values for which the weather will occur. I.e it will only rain if its humid enough | + + `humidity_and_pressure` | if there are pressure and humidity requirements are they both required or just one | + `acidic` | does this require acidic precipitation | + `time` | Valid values are: day, night, and both. | + `required_weathers` | a string array of possible weathers it is at this point in the loop. i.e. rain can only happen if the conditions for clouds light drizzle or drizzle are present | + +### Example + +```json +{ + "id": "lightning", + "type": "weather_type", + "name": "Lightning Storm", + "color": "c_yellow", + "map_color": "h_yellow", + "glyph": "%", + "ranged_penalty": 4, + "sight_penalty": 1.25, + "light_modifier": -45, + "sound_attn": 8, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "effects": [ + { + "one_in_chance": 50, + "must_be_outside":false, + "sound_message": "You hear a distant rumble of thunder.", + "sound_effect": "thunder_far" + }, + { + "one_in_chance": 600, + "must_be_outside":false, + "message": "A flash of lightning illuminates your surroundings!.", + "sound_effect": "thunder_near", + "lightning":true + } + ], + "tiles_animation": "weather_rain_drop", + "weather_animation": { "factor": 0.04, "color": "c_light_blue", "glyph": "," }, + "sound_category": "thunder", + "sun_intensity": "none", + "requirements": { "pressure_max": 990, "required_weathers": [ "thunder" ] } + }, +``` +### Weather_effects + +Things that weather can cause to happen. + +##Fields + +| Identifier | Description | +| ------------------------------ | --------------------------------------------------------------------- | +| `message` | Optional: Message displayed when this effect happens. | +| `sound_message` | Optional: Message describing what you hear, will not display if deaf | +| `sound_effect` | Optional: Name of sound effect to play | +| `sound_message` | Optional: Message describing what you hear for this, will not display if deaf. | +| `must_be_outside` | Whether the effect only happens while you are outside. | +| `one_in_chance` | Optional: The chance of the event occuring is 1 in this value, if blank will always happen. | +| `time_between` | Optional: The time between instances of this effect occuring. If both this and one_in_chance are set will only happen when both are true. | +| `lightning` | Optional: Causes the world be bright at night and supercharge monster electric fields. | +| `rain_proof` | Optional: If rainproof, resistant gear will help against this | +| `pain_max` | Optional: If there is a threshold of pain at which this will stop happening. | +| `pain` | Optional: How much pain this causes. | +| `wet` | Optional: How much wet this causes. | +| `radiation` | Optional: How much radiation this causes. | +| `healthy` | Optional: How much healthy this adds or removes. | +| `effect_id` | Optional: String id of an effect to add. | +| `effect_duration` | Optional: How long the above effect will be added for, defaults to 1 second. | +| `target_part` | Optional: Bodypart that above effect or damage are applied to, if blank affects whole body. | +| `damage` | Optional: Hp bashing damage applied. | +| `spawns` | Optional: Array of spawns to cause. If spawns are selected but are unable to spawn the effect is cancelled. | +| `fields` | Optional: Array of fields to cause. Elements are discussed below | + + optional( weather_effect_jo, was_loaded, "", effect.lightning, false ); + ### Example + +```json + { + "must_be_outside":true, + "radiation":10, + "healthy":1, + "message":"Suddenly a something", + "add_effect":"bite", + "effect_duration":"10 minutes", + "target_part": "arm_l", + "damage":5, + "spawns": + [{ + "max_radius":10, + "min_radius":10, + "target":"mon_zombie_survivor_elite", + "hallucination_count":1, + "real_count":0 +}] +``` + ### spawn_type + +How many and what spawns + +##Fields + +| Identifier | Description | +| ------------------------------ | --------------------------------------------------------------------- | +| `max_radius` | Optional: The furthest away a spawn will happen. | +| `min_radius` | Optional: The closest a spawn will happen. | +| `hallucination_count` | Optional: Number of hallucinations of the target to spawn. | +| `real_count` | Optional: Number of real copies to spawn. | +| `target` | Optional: Monster id of target to spawn. If left blank a nearby monster will be used. | +| `target_range` | Optional: If target is left blank how far away to look for something to copy. | + + ### fields + +Fields to create what kind and where + +##Fields + +| Identifier | Description | +| ------------------------------ | --------------------------------------------------------------------- | +| `type` | The string id of the field. | +| `intensity` | Intensity of the field. | +| `age` | Age of the field. | +| `outdoor_only` | Optional: Defaults to true. If true field will only spawn outdoors. | +| `radius` | Optional: Radius around player the effect will spread, defaults to everywhere. | + + + diff --git a/gfx/UltimateCataclysmDemo/giant.png b/gfx/UltimateCataclysmDemo/giant.png index 45f379069c224..2c8dc0a9b2a3a 100644 Binary files a/gfx/UltimateCataclysmDemo/giant.png and b/gfx/UltimateCataclysmDemo/giant.png differ diff --git a/gfx/UltimateCataclysmDemo/large.png b/gfx/UltimateCataclysmDemo/large.png index f1f3c6402fb19..ee9ab1ca7fff2 100644 Binary files a/gfx/UltimateCataclysmDemo/large.png and b/gfx/UltimateCataclysmDemo/large.png differ diff --git a/gfx/UltimateCataclysmDemo/normal.png b/gfx/UltimateCataclysmDemo/normal.png index 28cf1b0d0ec06..cbc7a756646a4 100644 Binary files a/gfx/UltimateCataclysmDemo/normal.png and b/gfx/UltimateCataclysmDemo/normal.png differ diff --git a/gfx/UltimateCataclysmDemo/tall.png b/gfx/UltimateCataclysmDemo/tall.png index 6414703079b69..3aa0cecd810b7 100644 Binary files a/gfx/UltimateCataclysmDemo/tall.png and b/gfx/UltimateCataclysmDemo/tall.png differ diff --git a/gfx/UltimateCataclysmDemo/tile_config.json b/gfx/UltimateCataclysmDemo/tile_config.json index ffe0c7da8b823..08a580d2482dc 100644 --- a/gfx/UltimateCataclysmDemo/tile_config.json +++ b/gfx/UltimateCataclysmDemo/tile_config.json @@ -1 +1 @@ -{"tile_info": [{"width": 32, "height": 32}], "tiles-new": [{"file": "normal.png", "tiles": [{"id": "f_indoor_plant", "fg": 3}, {"id": "f_indoor_plant_y", "fg": 1}, {"id": ["f_indoor_plant_y_season_autumn", "f_indoor_plant_y_season_winter"], "fg": 2}, {"id": "f_recycle_bin", "fg": 4}, {"id": "f_armchair", "fg": 5}, {"id": "f_wreckage", "fg": 6}, {"id": "f_gunsafe_ml", "fg": 8}, {"id": "f_gunsafe_mj", "fg": 7}, {"id": "f_gun_safe_el", "fg": 9}, {"id": "f_mutpoppy", "fg": 10}, {"id": "f_planter_mature", "multitile": true, "fg": 13, "additional_tiles": [{"id": "center", "fg": 14}, {"id": "corner", "fg": [23, 26, 22, 16]}, {"id": "t_connection", "fg": [19, 18, 25, 15]}, {"id": "edge", "fg": [20, 21]}, {"id": "end_piece", "fg": [17, 12, 11, 24]}, {"id": "unconnected", "fg": 13}]}, {"id": "f_boulder_small", "fg": 27}, {"id": "f_dandelion", "fg": 28}, {"id": "f_planter", "multitile": true, "fg": 37, "additional_tiles": [{"id": "center", "fg": 32}, {"id": "corner", "fg": [42, 36, 39, 35]}, {"id": "t_connection", "fg": [29, 40, 44, 43]}, {"id": "edge", "fg": [41, 38]}, {"id": "end_piece", "fg": [33, 34, 30, 31]}, {"id": "unconnected", "fg": 37}]}, {"id": "f_bathtub", "multitile": true, "fg": 54, "additional_tiles": [{"id": "center", "fg": 55}, {"id": "corner", "fg": [53, 50, 48, 56]}, {"id": "t_connection", "fg": [60, 52, 51, 47]}, {"id": "edge", "fg": [59, 57]}, {"id": "end_piece", "fg": [45, 49, 46, 58]}, {"id": "unconnected", "fg": 54}]}, {"id": "f_sofa", "multitile": true, "fg": 65, "additional_tiles": [{"id": "center", "fg": 66}, {"id": "corner", "fg": [74, 69, 76, 62]}, {"id": "t_connection", "fg": [70, 68, 61, 63]}, {"id": "edge", "fg": [75, 73]}, {"id": "end_piece", "fg": [64, 67, 72, 71]}, {"id": "unconnected", "fg": 65}]}, {"id": "f_alien_anemone", "fg": 78}, {"id": "f_alien_table", "fg": 77}, {"id": "f_filing_cabinet", "fg": 79}, {"id": "f_toilet", "fg": 80}, {"id": "f_ash", "fg": 81}, {"id": "f_desk", "multitile": true, "fg": 82, "additional_tiles": [{"id": "center", "fg": 91}, {"id": "corner", "fg": [87, 84, 92, 86]}, {"id": "t_connection", "fg": [90, 89, 85, 95]}, {"id": "edge", "fg": [96, 83]}, {"id": "end_piece", "fg": [97, 94, 93, 88]}, {"id": "unconnected", "fg": 82}]}, {"id": "f_trashcan", "fg": 98}, {"id": "f_entertainment_center", "fg": 99}, {"id": "f_grave_stone", "fg": [{"weight": 1, "sprite": 100}, {"weight": 1, "sprite": 101}]}, {"id": "f_rubble", "fg": 102}, {"id": "f_rubble_rock", "fg": 103}, {"id": "f_sign", "fg": 104}, {"id": "f_flower_spurge", "fg": 105}, {"id": "f_planter_harvest", "multitile": true, "fg": 117, "additional_tiles": [{"id": "center", "fg": 110}, {"id": "corner", "fg": [115, 120, 111, 118]}, {"id": "t_connection", "fg": [112, 113, 121, 107]}, {"id": "edge", "fg": [106, 108]}, {"id": "end_piece", "fg": [116, 114, 109, 119]}, {"id": "unconnected", "fg": 117}]}, {"id": "f_cardboard_box", "fg": 122}, {"id": "f_datura", "fg": 123}, {"id": "f_planter_seedling", "multitile": true, "fg": 131, "additional_tiles": [{"id": "center", "fg": 132}, {"id": "corner", "fg": [134, 125, 136, 128]}, {"id": "t_connection", "fg": [124, 133, 130, 126]}, {"id": "edge", "fg": [139, 137]}, {"id": "end_piece", "fg": [127, 135, 129, 138]}, {"id": "unconnected", "fg": 131}]}, {"id": "f_table", "multitile": true, "fg": 140, "additional_tiles": [{"id": "center", "fg": 154}, {"id": "corner", "fg": [148, 151, 142, 152]}, {"id": "t_connection", "fg": [141, 147, 144, 153]}, {"id": "edge", "fg": [143, 150]}, {"id": "end_piece", "fg": [146, 149, 155, 145]}, {"id": "unconnected", "fg": 140}]}, {"id": "f_boulder_large", "fg": 156}, {"id": "f_flower_tulip", "fg": [{"weight": 1, "sprite": 158}, {"weight": 2, "sprite": 157}]}, {"id": "f_cupboard", "multitile": true, "fg": 174, "additional_tiles": [{"id": "center", "fg": 173}, {"id": "corner", "fg": [167, 164, 166, 160]}, {"id": "t_connection", "fg": [163, 172, 168, 169]}, {"id": "edge", "fg": [171, 162]}, {"id": "end_piece", "fg": [159, 161, 165, 170]}, {"id": "unconnected", "fg": 174}]}, {"id": "f_bluebell", "fg": [{"weight": 1, "sprite": 175}, {"weight": 2, "sprite": 176}]}, {"id": "f_bed", "multitile": true, "fg": 182, "additional_tiles": [{"id": "center", "fg": 178}, {"id": "corner", "fg": [188, 187, 181, 186]}, {"id": "t_connection", "fg": [190, 185, 191, 189]}, {"id": "edge", "fg": [192, 180]}, {"id": "end_piece", "fg": [177, 183, 179, 184]}, {"id": "unconnected", "fg": 182}]}, {"id": "f_firering", "fg": 193}, {"id": "f_bench", "multitile": true, "fg": 207, "additional_tiles": [{"id": "center", "fg": 200}, {"id": "corner", "fg": [203, 205, 197, 196]}, {"id": "t_connection", "fg": [194, 201, 204, 206]}, {"id": "edge", "fg": [198, 202]}, {"id": "end_piece", "fg": [208, 199, 209, 195]}, {"id": "unconnected", "fg": 207}]}, {"id": "f_mailbox", "fg": 210}, {"id": "f_grave_stone_old", "fg": [{"weight": 1, "sprite": 212}, {"weight": 1, "sprite": 211}]}, {"id": "f_rack_wood", "fg": 213}, {"id": "f_boulder_medium", "fg": 214}, {"id": "f_chamomile", "fg": 215}, {"id": "f_hay", "fg": 216}, {"id": "f_counter", "multitile": true, "fg": 223, "additional_tiles": [{"id": "center", "fg": 219}, {"id": "corner", "fg": [228, 220, 226, 224]}, {"id": "t_connection", "fg": [225, 218, 232, 227]}, {"id": "edge", "fg": [222, 221]}, {"id": "end_piece", "fg": [229, 231, 230, 217]}, {"id": "unconnected", "fg": 223}]}, {"id": "f_air_conditioner", "fg": 233}, {"id": "f_chair", "fg": 234}, {"id": "f_stool", "fg": 235}, {"id": "f_dahlia", "fg": [{"weight": 1, "sprite": 236}, {"weight": 2, "sprite": 237}]}, {"id": ["f_displaycase"], "fg": 238}, {"id": "f_rack", "fg": 239}, {"id": "vp_door_trunk", "fg": 240, "rotates": true, "multitile": true, "additional_tiles": [{"id": "open", "fg": 241}]}, {"id": ["vp_headlight", "vp_headlight_reinforced"], "fg": 242}, {"id": "vp_door", "fg": 243, "rotates": true, "multitile": true, "additional_tiles": [{"id": "open", "fg": 244}]}, {"id": "vp_halfboard_ne", "fg": 248, "rotates": true}, {"id": "vp_halfboard_sw", "fg": 250, "rotates": true}, {"id": "vp_halfboard_se", "fg": 245, "rotates": true}, {"id": "vp_halfboard_cover", "fg": 247, "rotates": true}, {"id": "vp_halfboard_vertical_2", "fg": 252, "rotates": true}, {"id": "vp_halfboard_horizontal_2", "fg": 249, "rotates": true}, {"id": "vp_halfboard_vertical", "fg": 246, "rotates": true}, {"id": "vp_halfboard_nw", "fg": 253, "rotates": true}, {"id": "vp_halfboard_horizontal", "fg": 251, "rotates": true}, {"id": "vp_windshield", "fg": 257, "rotates": true, "multitile": true, "additional_tiles": [{"id": "center", "fg": [254, 258, 255, 256]}, {"id": "edge", "fg": 257}, {"id": "unconnected", "fg": 257}, {"id": "end_piece", "fg": [254, 258, 255, 256]}, {"id": "t_connection", "fg": [254, 258, 255, 256]}, {"id": "corner", "fg": [254, 258, 255, 256]}]}, {"id": "powder_candy", "fg": 259}, {"id": "joint", "fg": 261}, {"id": "joint_lit", "fg": 262}, {"id": "joint_roach", "fg": 260}, {"id": "bag_canvas", "fg": 263}, {"id": "wood_panel", "fg": 264}, {"id": "jar_glass", "fg": 265}, {"id": "shot_hull", "fg": 266}, {"id": "wrench", "fg": 267}, {"id": "needle_bone", "fg": 270}, {"id": "needle_curved", "fg": 268}, {"id": "needle_wood", "fg": 269}, {"id": "pinecone", "fg": 271}, {"id": "ash", "fg": 272}, {"id": "lighter", "fg": [{"weight": 1, "sprite": 273}, {"weight": 1, "sprite": 275}, {"weight": 1, "sprite": 274}]}, {"id": "chips", "fg": 276}, {"id": "rifle_flintlock", "fg": 277}, {"id": "balclava", "fg": 301}, {"id": "beret", "fg": 290}, {"id": "boots", "fg": 317}, {"id": "boxer_briefs", "fg": 296}, {"id": "boxer_shorts", "fg": 282}, {"id": "boy_shorts", "fg": 287}, {"id": "bra", "fg": 309}, {"id": "briefs", "fg": 293}, {"id": "corset", "fg": 306}, {"id": "cowboy_hat", "fg": 318}, {"id": "dress_shoes", "fg": 286}, {"id": "hat_ball", "fg": 300}, {"id": "hat_cotton", "fg": 299}, {"id": "hat_fur", "fg": 303}, {"id": "hat_knit", "fg": 281}, {"id": "hat_noise_cancelling", "fg": 326}, {"id": "helmet_army", "fg": 284}, {"id": "helmet_barbute", "fg": 315}, {"id": "helmet_chitin", "fg": 278}, {"id": "helmet_kabuto", "fg": 314}, {"id": "hoodie", "fg": 313}, {"id": "jeans", "fg": 308}, {"id": "longshirt", "fg": 295}, {"id": "maid_dress", "fg": 280}, {"id": "maid_hat", "fg": 294}, {"id": "mask_dust", "fg": 305}, {"id": "panties", "fg": 291}, {"id": "pants", "fg": 288}, {"id": "pants_cargo", "fg": 302}, {"id": "polo_shirt", "fg": 310}, {"id": "ragpouch", "fg": 324}, {"id": "sneakers", "fg": 283}, {"id": "socks", "fg": 298}, {"id": "stockings", "fg": 289}, {"id": "sweater", "fg": 311}, {"id": "sweatshirt", "fg": 285}, {"id": "tank_top", "fg": 325}, {"id": "tshirt", "fg": 307}, {"id": "turban", "fg": 319}, {"id": "undershirt", "fg": 322}, {"id": "coat_lab", "fg": 321}, {"id": "coat_rain", "fg": 292}, {"id": "sports_bra", "fg": 297}, {"id": "skirt", "fg": 279}, {"id": "jacket_light", "fg": 312}, {"id": "jacket_army", "fg": 323}, {"id": "hat_hard", "fg": 320}, {"id": "striped_pants", "fg": 304}, {"id": "striped_shirt", "fg": 316}, {"id": "", "fg": []}, {"id": "bat_metal", "fg": 327}, {"id": "hacksaw", "fg": 328}, {"id": "crucible_clay", "fg": 329}, {"id": "many_years_old_newspaper", "fg": 334}, {"id": "months_old_newspaper", "fg": 330}, {"id": "newest_newspaper", "fg": 333}, {"id": "one_year_old_newspaper", "fg": 332}, {"id": "weeks_old_newspaper", "fg": 331}, {"id": "pointy_stick", "fg": 343}, {"id": "spear_wood", "fg": 342}, {"id": "spear_spike", "fg": 337}, {"id": "spear_knife", "fg": 340}, {"id": "spear_knife_superior", "fg": 341}, {"id": "spear_pipe", "fg": 335}, {"id": "spear_rebar", "fg": 339}, {"id": "spear_steel", "fg": 336}, {"id": "spear_copper", "fg": 338}, {"id": "hickory_root", "fg": 344}, {"id": "flashlight", "fg": 345}, {"id": "heavy_flashlight", "fg": 346}, {"id": "can_drink", "fg": 347}, {"id": "50_casing", "fg": 348}, {"id": "apple", "fg": 350}, {"id": "banana", "fg": 351}, {"id": "broccoli", "fg": 359}, {"id": "corn", "fg": 362}, {"id": "cucumber", "fg": 355}, {"id": "egg_bird", "fg": 361}, {"id": "grapes", "fg": 349}, {"id": "lemon", "fg": 352}, {"id": "onion", "fg": 360}, {"id": "orange", "fg": 354}, {"id": "pear", "fg": 356}, {"id": "potato", "fg": 353}, {"id": "pumpkin", "fg": 358}, {"id": "tomato", "fg": 357}, {"id": "sewing_kit", "fg": 363}, {"id": "jug_plastic", "fg": 364}, {"id": "pot", "fg": 365}, {"id": "backpack", "fg": 366}, {"id": "cattlefodder", "fg": 367}, {"id": "cup_plastic", "fg": 368}, {"id": "knife_meat_cleaver", "fg": 369}, {"id": "fire_ax", "fg": 370}, {"id": "ax", "fg": 372}, {"id": "hatchet", "fg": 371}, {"id": ["glock_17", "glock_19", "glock_18c", "glock_22", "glock_31"], "fg": 373}, {"id": "straw_pile", "fg": 374}, {"id": "thread", "fg": 375}, {"id": "wheat", "fg": 376}, {"id": "pan", "fg": 377}, {"id": "bottle_glass", "fg": 378}, {"id": "nail", "fg": 379}, {"id": "juniper", "fg": 380}, {"id": "pool_ball", "fg": 381}, {"id": "crowbar", "fg": 382}, {"id": "rag", "fg": 383}, {"id": "id_industrial", "fg": 384}, {"id": "corpse_generic_human", "fg": 385}, {"id": "chainsaw_off", "fg": 386}, {"id": "teapot", "fg": 387}, {"id": "mp5mag", "fg": 388}, {"id": "meat", "fg": 389}, {"id": "cig_butt", "fg": 390}, {"id": "usb_drive", "fg": 391}, {"id": "1st_aid", "fg": 392}, {"id": "welder_crude", "fg": 393}, {"id": "nailbat", "fg": 394}, {"id": "remington_870", "fg": 395}, {"id": "sheet_metal_small", "fg": 396}, {"id": "screwdriver", "fg": 397}, {"id": "primitive_hammer", "fg": 398}, {"id": "steel_lump", "fg": 399}, {"id": "string_6", "fg": 400}, {"id": "saw", "fg": 401}, {"id": "aspirin", "fg": 417}, {"id": "bandages", "fg": 403}, {"id": "syringe", "fg": 409}, {"id": "antibiotics", "fg": 416}, {"id": "weak_antibiotic", "fg": 402}, {"id": "strong_antibiotic", "fg": 410}, {"id": "vitamins", "fg": 407}, {"id": "gummy_vitamins", "fg": 408}, {"id": "calcium_tablet", "fg": 413}, {"id": "oxycodone", "fg": 411}, {"id": "tramadol", "fg": 412}, {"id": "codeine", "fg": 406}, {"id": "prussian_blue", "fg": 405}, {"id": "iodine", "fg": 414}, {"id": "antiparasitic", "fg": 415}, {"id": "antifungal", "fg": 404}, {"id": "can_drink_unsealed", "fg": 418}, {"id": "9mm_casing", "fg": 419}, {"id": "wrapper", "fg": 420}, {"id": "rebar", "fg": 421}, {"id": "glass_shard", "fg": 422}, {"id": "pot_copper", "fg": 423}, {"id": "40mm_casing", "fg": 424}, {"id": "nailboard", "fg": 425}, {"id": "scissors", "fg": 426}, {"id": "ak74", "fg": 427}, {"id": "coffeemaker", "fg": 428}, {"id": "blanket", "fg": 430}, {"id": "down_blanket", "fg": 429}, {"id": "longbow", "fg": 431}, {"id": "pneumatic_shotgun", "fg": 432}, {"id": "thermos", "fg": 433}, {"id": "box_cigarette", "fg": 434}, {"id": "m79", "fg": 435}, {"id": "stick", "fg": 436}, {"id": "steel_chunk", "fg": 437}, {"id": "television", "fg": 438}, {"id": "shovel", "fg": 439}, {"id": "id_science", "fg": 440}, {"id": "cable", "fg": 441}, {"id": "pipe", "fg": 442}, {"id": "bottle_plastic", "fg": 443}, {"id": "fp_loyalty_card", "fg": 444}, {"id": "id_military", "fg": 445}, {"id": "water", "fg": 447}, {"id": "water_clean", "fg": 448}, {"id": "blood", "fg": 446}, {"id": "filter_air", "fg": 449}, {"id": "welder", "fg": 450}, {"id": "broom", "fg": 451}, {"id": "rolling_pin", "fg": 452}, {"id": "makeshift_crowbar", "fg": 453}, {"id": "bat", "fg": 454}, {"id": "wood_sheet", "fg": 455}, {"id": "jar_3l_glass_sealed", "fg": 456}, {"id": "plastic_sheet", "fg": 457}, {"id": "box_large", "fg": 458}, {"id": "knife_vegetable_cleaver", "fg": 459}, {"id": "arming_sword", "fg": 460}, {"id": "crossbow", "fg": 461}, {"id": "pot_canning", "fg": 462}, {"id": "sheet_metal", "fg": 463}, {"id": "brick", "fg": 464}, {"id": "wire", "fg": 465}, {"id": "2x4", "fg": 466}, {"id": ["seed_hops", "seed_blackberries", "seed_blueberries", "coffee_pod", "seed_wheat", "roasted_coffee_bean", "seed_chamomile", "coffee_bean", "seed_celery", "fried_seeds", "seed_buckwheat", "seed_oats", "seed_mushroom_morel", "datura_seed", "seed_mushroom", "seed_rhubarb", "seed_wild_herbs", "seed_raw_dandelion", "seed_veggy_wild", "seed_chili_pepper", "seed_dogbane", "seed_mugwort", "seed_bee_balm", "seed_flower", "seed_sunflower", "seed_thyme", "seed_canola", "seed_pumpkin", "seed_beans", "seed_lentils", "soybean_seed", "marloss_seed", "fungal_seeds", "seed_weed", "seed_potato_raw", "seed_cucumber", "seed_corn", "seed_carrot", "garlic_clove", "seed_cactus", "seed_wildcarrot", "seed_cattail", "seed_chicory", "seed_salsify_raw", "seed_dahlia", "seed_garlic", "seed_broccoli", "seed_onion", "seed_zucchini", "seed_cotton_boll", "seed_tomato", "seed_rose", "seed_lettuce", "seed_cabbage", "seed_sugar_beet", "seed_tobacco", "seed_barley", "seed_grapes", "seed_strawberries", "seed_raspberries", "seed_cranberries", "seed_huckleberries", "seed_mulberries", "seed_elderberries"], "fg": 467}, {"id": "acorns", "fg": 468}, {"id": "slingshot", "fg": 469}, {"id": "bottle_plastic_small", "fg": 470}, {"id": "sharp_rock", "fg": 471}, {"id": "bowl_plastic", "fg": 472}, {"id": "contacts", "fg": 473}, {"id": "matches", "fg": 474}, {"id": "box_small", "fg": 475}, {"id": "plastic_shopping_bag", "fg": 476}, {"id": "pillow", "fg": 478}, {"id": "down_pillow", "fg": 477}, {"id": "mop", "fg": 479}, {"id": "board_trap", "fg": 480}, {"id": "can_food", "fg": 481}, {"id": "scrap", "fg": 482}, {"id": "string_36", "fg": 483}, {"id": "file", "fg": 484}, {"id": "box_medium", "fg": 485}, {"id": "paperback_novel", "fg": 507}, {"id": "novel_adventure", "fg": 507}, {"id": "novel_buddy", "fg": 500}, {"id": "novel_coa", "fg": 489}, {"id": "novel_coa2", "fg": 490}, {"id": "novel_crime", "fg": 493}, {"id": "novel_crime2", "fg": 501}, {"id": "novel_drama", "fg": 497}, {"id": "novel_erotic", "fg": 505}, {"id": "novel_experimental", "fg": 496}, {"id": "novel_fantasy", "fg": 502}, {"id": "novel_horror", "fg": 503}, {"id": "novel_mystery", "fg": 506}, {"id": "novel_pulp", "fg": 494}, {"id": "novel_road", "fg": 491}, {"id": "novel_romance", "fg": 488}, {"id": "novel_samurai", "fg": 486}, {"id": "novel_satire", "fg": 498}, {"id": "novel_scifi", "fg": 510}, {"id": "novel_sports", "fg": 509}, {"id": "novel_spy", "fg": 511}, {"id": "novel_swash", "fg": 499}, {"id": "novel_thriller", "fg": 504}, {"id": "novel_tragedy", "fg": 495}, {"id": "novel_war", "fg": 508}, {"id": "novel_war2", "fg": 492}, {"id": "novel_western", "fg": 487}, {"id": "marble", "fg": 512}, {"id": "withered", "fg": 513}, {"id": "bolt_cf", "fg": 514}, {"id": "bolt_explosive", "fg": 522}, {"id": "bolt_metal", "fg": 517}, {"id": ["bolt_steel", "bolt_steel_bodkin", "bolt_steel_target"], "fg": 521}, {"id": ["bolt_wood", "bolt_crude", "bolt_simple_wood", "bolt_simple_small_game", "bolt_makeshift", "bolt_wood_bodkin", "bolt_wood_small_game"], "fg": 531}, {"id": "arrow_cf", "fg": 520}, {"id": "arrow_exploding", "fg": 515}, {"id": "arrow_field_point_fletched", "fg": 524}, {"id": "arrow_fire_hardened_fletched", "fg": 530}, {"id": "arrow_flammable", "fg": 528}, {"id": "arrow_flamming", "fg": 519}, {"id": "arrow_heavy_fire_hardened_fletched", "fg": 529}, {"id": "arrow_metal", "fg": 523}, {"id": "arrow_metal_sharpened_fletched", "fg": 516}, {"id": "arrow_plastic", "fg": 525}, {"id": "arrow_small_game_fletched", "fg": 526}, {"id": "arrow_wood", "fg": 527}, {"id": "arrow_wood_heavy", "fg": 518}, {"id": "rock", "fg": 532}, {"id": "knife_butcher", "fg": 533}, {"id": "stick_long", "fg": 534}, {"id": "log", "fg": 535}, {"id": "jar_glass_sealed", "fg": 536}, {"id": "jar_3l_glass", "fg": 537}, {"id": "knife_butter", "fg": 538}, {"id": "223_casing", "fg": 539}, {"id": "bwirebat", "fg": 540}, {"id": "bag_plastic", "fg": 541}, {"id": ["rifle_9mm", "rifle_3006", "rifle_45", "rifle_22", "rifle_40", "rifle_44", "rifle_38", "rifle_223"], "fg": 542}, {"id": "pipe_shotgun", "fg": 543}, {"id": "spoon", "fg": 544}, {"id": "hammer", "fg": 545}, {"id": "hickory_nut", "fg": 546}, {"id": "glass_plate", "fg": 547}, {"id": "cash_card", "fg": 548}, {"id": "fork", "fg": 549}, {"id": "splinter", "fg": 550}, {"id": "ar15", "fg": 551}, {"id": "pine_bough", "fg": 552}, {"id": "bag_zipper", "fg": 553}, {"id": "tailors_kit", "fg": 554}, {"id": "sponge", "fg": 555}, {"id": "t_strconc_floor", "multitile": true, "fg": 571, "additional_tiles": [{"id": "center", "fg": 568}, {"id": "corner", "fg": [556, 563, 565, 561]}, {"id": "t_connection", "fg": [557, 562, 566, 559]}, {"id": "edge", "fg": [567, 569]}, {"id": "end_piece", "fg": [570, 558, 564, 560]}, {"id": "unconnected", "fg": 571}]}, {"id": "t_tatami", "fg": [{"weight": 100, "sprite": 573}, {"weight": 100, "sprite": 572}]}, {"id": "t_floor_waxed_y", "multitile": true, "fg": 579, "additional_tiles": [{"id": "center", "fg": 585}, {"id": "corner", "fg": [582, 574, 578, 588]}, {"id": "t_connection", "fg": [580, 576, 587, 575]}, {"id": "edge", "fg": [583, 586]}, {"id": "end_piece", "fg": [584, 577, 581, 589]}, {"id": "unconnected", "fg": 579}]}, {"id": "t_pit_shallow", "fg": 590, "bg": [{"weight": 100, "sprite": 1233}, {"weight": 100, "sprite": 1235}]}, {"id": "t_pit_shallow_season_summer", "fg": 590, "bg": [{"weight": 100, "sprite": 1240}, {"weight": 100, "sprite": 1229}]}, {"id": "t_pit_shallow_season_autumn", "fg": 590, "bg": [{"weight": 100, "sprite": 1234}, {"weight": 100, "sprite": 1228}]}, {"id": "t_rock", "fg": 591}, {"id": "t_railroad_rubble", "fg": 592}, {"id": "t_gravel", "fg": 592}, {"id": "t_railroad_rubble_season_winter", "fg": 643}, {"id": "t_sand", "fg": 593}, {"id": "t_sand_season_winter", "fg": 643}, {"id": "t_floor_resin", "multitile": true, "fg": 596, "additional_tiles": [{"id": "center", "fg": 595}, {"id": "corner", "fg": [601, 608, 602, 598]}, {"id": "t_connection", "fg": [600, 594, 604, 603]}, {"id": "edge", "fg": [609, 597]}, {"id": "end_piece", "fg": [606, 607, 605, 599]}, {"id": "unconnected", "fg": 596}]}, {"id": "t_metal_floor", "multitile": true, "fg": 617, "additional_tiles": [{"id": "center", "fg": 611}, {"id": "corner", "fg": [619, 615, 613, 614]}, {"id": "t_connection", "fg": [625, 620, 622, 624]}, {"id": "edge", "fg": [623, 621]}, {"id": "end_piece", "fg": [610, 616, 612, 618]}, {"id": "unconnected", "fg": 617}]}, {"id": ["t_door_metal_locked", "t_door_metal_pickable"], "fg": 626}, {"id": "t_wall_b", "multitile": true, "fg": 630, "additional_tiles": [{"id": "center", "fg": 628}, {"id": "corner", "fg": [641, 634, 640, 632]}, {"id": "t_connection", "fg": [638, 633, 642, 636]}, {"id": "edge", "fg": [627, 629]}, {"id": "end_piece", "fg": [635, 631, 639, 637]}, {"id": "unconnected", "fg": 630}]}, {"id": "t_floor", "multitile": true, "fg": 655, "additional_tiles": [{"id": "center", "fg": 652}, {"id": "corner", "fg": [657, 654, 650, 658]}, {"id": "t_connection", "fg": [656, 645, 651, 659]}, {"id": "edge", "fg": [647, 648]}, {"id": "end_piece", "fg": [653, 649, 660, 646]}, {"id": "unconnected", "fg": 655}]}, {"id": "t_brick_wall", "multitile": true, "fg": 674, "additional_tiles": [{"id": "center", "fg": 676}, {"id": "corner", "fg": [666, 668, 667, 672]}, {"id": "t_connection", "fg": [662, 670, 673, 675]}, {"id": "edge", "fg": [669, 661]}, {"id": "end_piece", "fg": [664, 665, 671, 663]}, {"id": "unconnected", "fg": 674}]}, {"id": "t_wall_wood", "multitile": true, "fg": 684, "additional_tiles": [{"id": "center", "fg": 680}, {"id": "corner", "fg": [677, 686, 690, 688]}, {"id": "t_connection", "fg": [685, 692, 679, 682]}, {"id": "edge", "fg": [678, 689]}, {"id": "end_piece", "fg": [691, 681, 687, 683]}, {"id": "unconnected", "fg": 684}]}, {"id": ["t_linoleum_white", "t_linoleum_white_no_roof"], "multitile": true, "fg": 696, "additional_tiles": [{"id": "center", "fg": 708}, {"id": "corner", "fg": [703, 702, 693, 707]}, {"id": "t_connection", "fg": [695, 705, 701, 704]}, {"id": "edge", "fg": [706, 700]}, {"id": "end_piece", "fg": [694, 697, 699, 698]}, {"id": "unconnected", "fg": 696}]}, {"id": "t_fungus", "multitile": true, "fg": 721, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 716}, {"id": "corner", "bg": 1233, "fg": [718, 722, 710, 711]}, {"id": "t_connection", "bg": 1233, "fg": [723, 709, 715, 717]}, {"id": "edge", "bg": 1233, "fg": [719, 713]}, {"id": "end_piece", "bg": 1233, "fg": [720, 712, 724, 714]}, {"bg": 1233, "id": "unconnected", "fg": 721}]}, {"id": "t_fungus_season_summer", "multitile": true, "fg": 721, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 716}, {"id": "corner", "bg": 1240, "fg": [718, 722, 710, 711]}, {"id": "t_connection", "bg": 1240, "fg": [723, 709, 715, 717]}, {"id": "edge", "bg": 1240, "fg": [719, 713]}, {"id": "end_piece", "bg": 1240, "fg": [720, 712, 724, 714]}, {"bg": 1240, "id": "unconnected", "fg": 721}]}, {"id": "t_fungus_season_autumn", "multitile": true, "fg": 721, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 716}, {"id": "corner", "bg": 1234, "fg": [718, 722, 710, 711]}, {"id": "t_connection", "bg": 1234, "fg": [723, 709, 715, 717]}, {"id": "edge", "bg": 1234, "fg": [719, 713]}, {"id": "end_piece", "bg": 1234, "fg": [720, 712, 724, 714]}, {"bg": 1234, "id": "unconnected", "fg": 721}]}, {"id": "t_fungus_season_winter", "multitile": true, "fg": 721, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": 716}, {"id": "corner", "bg": 643, "fg": [718, 722, 710, 711]}, {"id": "t_connection", "bg": 643, "fg": [723, 709, 715, 717]}, {"id": "edge", "bg": 643, "fg": [719, 713]}, {"id": "end_piece", "bg": 643, "fg": [720, 712, 724, 714]}, {"bg": 643, "id": "unconnected", "fg": 721}]}, {"id": "t_carpet_red", "multitile": true, "fg": 735, "additional_tiles": [{"id": "center", "fg": 732}, {"id": "corner", "fg": [734, 730, 733, 736]}, {"id": "t_connection", "fg": [727, 731, 726, 737]}, {"id": "edge", "fg": [725, 740]}, {"id": "end_piece", "fg": [738, 739, 729, 728]}, {"id": "unconnected", "fg": 735}]}, {"id": ["t_water_moving_sh", "t_swater_moving_sh"], "multitile": true, "fg": 743, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 742}, {"id": "corner", "bg": 1233, "fg": [754, 741, 745, 747]}, {"id": "t_connection", "bg": 1233, "fg": [756, 748, 746, 755]}, {"id": "edge", "bg": 1233, "fg": [751, 752]}, {"id": "end_piece", "bg": 1233, "fg": [753, 744, 749, 750]}, {"bg": 1233, "id": "unconnected", "fg": 743}]}, {"id": ["t_water_moving_sh_season_summer", "t_swater_moving_sh_season_summer"], "multitile": true, "fg": 743, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 742}, {"id": "corner", "bg": 1240, "fg": [754, 741, 745, 747]}, {"id": "t_connection", "bg": 1240, "fg": [756, 748, 746, 755]}, {"id": "edge", "bg": 1240, "fg": [751, 752]}, {"id": "end_piece", "bg": 1240, "fg": [753, 744, 749, 750]}, {"bg": 1240, "id": "unconnected", "fg": 743}]}, {"id": ["t_water_moving_sh_season_autumn", "t_swater_moving_sh_season_autumn"], "multitile": true, "fg": 743, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 742}, {"id": "corner", "bg": 1234, "fg": [754, 741, 745, 747]}, {"id": "t_connection", "bg": 1234, "fg": [756, 748, 746, 755]}, {"id": "edge", "bg": 1234, "fg": [751, 752]}, {"id": "end_piece", "bg": 1234, "fg": [753, 744, 749, 750]}, {"bg": 1234, "id": "unconnected", "fg": 743}]}, {"id": ["t_water_moving_sh_season_winter", "t_swater_moving_sh_season_winter"], "multitile": true, "fg": 743, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": 742}, {"id": "corner", "bg": 643, "fg": [754, 741, 745, 747]}, {"id": "t_connection", "bg": 643, "fg": [756, 748, 746, 755]}, {"id": "edge", "bg": 643, "fg": [751, 752]}, {"id": "end_piece", "bg": 643, "fg": [753, 744, 749, 750]}, {"bg": 643, "id": "unconnected", "fg": 743}]}, {"id": ["t_window", "t_window_alarm"], "fg": 758}, {"id": "t_window_empty", "fg": 762}, {"id": "t_window_domestic", "fg": 761}, {"id": "t_window_open", "fg": 760}, {"id": "t_window_no_curtains", "fg": 759}, {"id": "t_window_no_curtains_open", "fg": 757}, {"id": "t_fence_wire", "multitile": true, "fg": 771, "additional_tiles": [{"id": "center", "fg": 768}, {"id": "corner", "fg": [772, 769, 775, 777]}, {"id": "t_connection", "fg": [774, 767, 770, 763]}, {"id": "edge", "fg": [776, 773]}, {"id": "end_piece", "fg": [765, 766, 764, 778]}, {"id": "unconnected", "fg": 771}]}, {"id": "t_fence_barbed_season_spring", "multitile": true, "fg": 784, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 781}, {"id": "corner", "bg": 1233, "fg": [780, 793, 791, 794]}, {"id": "t_connection", "bg": 1233, "fg": [786, 782, 788, 789]}, {"id": "edge", "bg": 1233, "fg": [792, 787]}, {"id": "end_piece", "bg": 1233, "fg": [783, 779, 785, 790]}, {"bg": 1233, "id": "unconnected", "fg": 784}]}, {"id": "t_fence_barbed_season_summer", "multitile": true, "fg": 784, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 781}, {"id": "corner", "bg": 1240, "fg": [780, 793, 791, 794]}, {"id": "t_connection", "bg": 1240, "fg": [786, 782, 788, 789]}, {"id": "edge", "bg": 1240, "fg": [792, 787]}, {"id": "end_piece", "bg": 1240, "fg": [783, 779, 785, 790]}, {"bg": 1240, "id": "unconnected", "fg": 784}]}, {"id": "t_fence_barbed_season_autumn", "multitile": true, "fg": 784, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 781}, {"id": "corner", "bg": 1234, "fg": [780, 793, 791, 794]}, {"id": "t_connection", "bg": 1234, "fg": [786, 782, 788, 789]}, {"id": "edge", "bg": 1234, "fg": [792, 787]}, {"id": "end_piece", "bg": 1234, "fg": [783, 779, 785, 790]}, {"bg": 1234, "id": "unconnected", "fg": 784}]}, {"id": "t_fence_barbed_season_winter", "multitile": true, "fg": 784, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": 781}, {"id": "corner", "bg": 643, "fg": [780, 793, 791, 794]}, {"id": "t_connection", "bg": 643, "fg": [786, 782, 788, 789]}, {"id": "edge", "bg": 643, "fg": [792, 787]}, {"id": "end_piece", "bg": 643, "fg": [783, 779, 785, 790]}, {"bg": 643, "id": "unconnected", "fg": 784}]}, {"id": "t_floor_waxed", "multitile": true, "fg": 800, "additional_tiles": [{"id": "center", "fg": 809}, {"id": "corner", "fg": [802, 797, 798, 803]}, {"id": "t_connection", "fg": [807, 796, 806, 799]}, {"id": "edge", "fg": [805, 795]}, {"id": "end_piece", "fg": [808, 804, 801, 810]}, {"id": "unconnected", "fg": 800}]}, {"id": "t_curtains", "fg": 811}, {"id": "t_door_glass_c", "fg": 812}, {"id": ["t_wall_glass", "t_wall_glass_alarm"], "multitile": true, "fg": 814, "additional_tiles": [{"id": "center", "fg": 821}, {"id": "corner", "fg": [828, 825, 816, 831]}, {"id": "t_connection", "fg": [829, 819, 818, 824]}, {"id": "edge", "fg": [813, 817]}, {"id": "end_piece", "fg": [815, 827, 832, 820]}, {"id": "unconnected", "fg": 814}]}, {"id": ["t_sidewalk", "t_sidewalk_bg_dp"], "multitile": true, "fg": 846, "additional_tiles": [{"id": "center", "fg": 833}, {"id": "corner", "fg": [834, 848, 835, 839]}, {"id": "t_connection", "fg": [837, 836, 845, 843]}, {"id": "edge", "fg": [842, 847]}, {"id": "end_piece", "fg": [841, 838, 840, 844]}, {"id": "unconnected", "fg": 846}]}, {"id": "t_sidewalk_season_winter", "fg": 643}, {"id": "t_carpet_purple", "multitile": true, "fg": 855, "additional_tiles": [{"id": "center", "fg": 853}, {"id": "corner", "fg": [858, 860, 849, 852]}, {"id": "t_connection", "fg": [862, 864, 856, 854]}, {"id": "edge", "fg": [861, 863]}, {"id": "end_piece", "fg": [857, 859, 851, 850]}, {"id": "unconnected", "fg": 855}]}, {"id": ["t_shrub_raspberry"], "fg": 865, "bg": 1233}, {"id": ["t_shrub_raspberry_harvested"], "fg": 868, "bg": 1240}, {"id": "t_shrub_raspberry_season_summer", "fg": 867, "bg": 1240}, {"id": "t_shrub_raspberry_season_autumn", "fg": 865, "bg": 1234}, {"id": "t_shrub_raspberry_season_winter", "fg": 866, "bg": 644}, {"id": "t_woodchips", "fg": 869}, {"id": "t_woodchips_season_winter", "fg": 643}, {"id": "t_fence_post_season_spring", "fg": 880, "bg": 1233}, {"id": "t_fence_post_season_summer", "fg": 880, "bg": 1240}, {"id": "t_fence_post_season_autumn", "fg": 880, "bg": 1234}, {"id": "t_fence_post_season_winter", "fg": 880, "bg": 643}, {"id": "t_fence_season_spring", "multitile": true, "fg": 880, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 879}, {"id": "corner", "bg": 1233, "fg": [873, 871, 874, 881]}, {"id": "t_connection", "bg": 1233, "fg": [883, 872, 884, 885]}, {"id": "edge", "bg": 1233, "fg": [882, 886]}, {"id": "end_piece", "bg": 1233, "fg": [877, 876, 887, 875]}, {"bg": 1233, "id": "unconnected", "fg": 880}]}, {"id": "t_fence_season_summer", "multitile": true, "fg": 880, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 879}, {"id": "corner", "bg": 1240, "fg": [873, 871, 874, 881]}, {"id": "t_connection", "bg": 1240, "fg": [883, 872, 884, 885]}, {"id": "edge", "bg": 1240, "fg": [882, 886]}, {"id": "end_piece", "bg": 1240, "fg": [877, 876, 887, 875]}, {"bg": 1240, "id": "unconnected", "fg": 880}]}, {"id": "t_fence_season_autumn", "multitile": true, "fg": 880, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 879}, {"id": "corner", "bg": 1234, "fg": [873, 871, 874, 881]}, {"id": "t_connection", "bg": 1234, "fg": [883, 872, 884, 885]}, {"id": "edge", "bg": 1234, "fg": [882, 886]}, {"id": "end_piece", "bg": 1234, "fg": [877, 876, 887, 875]}, {"bg": 1234, "id": "unconnected", "fg": 880}]}, {"id": "t_fence_season_winter", "multitile": true, "fg": 880, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": 879}, {"id": "corner", "bg": 643, "fg": [873, 871, 874, 881]}, {"id": "t_connection", "bg": 643, "fg": [883, 872, 884, 885]}, {"id": "edge", "bg": 643, "fg": [882, 886]}, {"id": "end_piece", "bg": 643, "fg": [877, 876, 887, 875]}, {"bg": 643, "id": "unconnected", "fg": 880}]}, {"id": "t_fencegate_c_season_spring", "fg": 870, "bg": 1233}, {"id": "t_fencegate_c_season_summer", "fg": 870, "bg": 1240}, {"id": "t_fencegate_c_season_autumn", "fg": 870, "bg": 1234}, {"id": "t_fencegate_c_season_winter", "fg": 870, "bg": 643}, {"id": "t_fencegate_o_season_spring", "fg": 878, "bg": 1233}, {"id": "t_fencegate_o_season_summer", "fg": 878, "bg": 1240}, {"id": "t_fencegate_o_season_autumn", "fg": 878, "bg": 1234}, {"id": "t_fencegate_o_season_winter", "fg": 878, "bg": 643}, {"id": "t_wall_y", "multitile": true, "fg": 902, "additional_tiles": [{"id": "center", "fg": 903}, {"id": "corner", "fg": [896, 900, 895, 889]}, {"id": "t_connection", "fg": [893, 898, 892, 897]}, {"id": "edge", "fg": [894, 899]}, {"id": "end_piece", "fg": [890, 891, 901, 888]}, {"id": "unconnected", "fg": 902}]}, {"id": "t_rdoor_c", "fg": 905}, {"id": "t_rdoor_o", "fg": 906}, {"id": "t_rdoor_b", "fg": 904}, {"id": ["t_gates_mech_control"], "fg": 909, "bg": 939}, {"id": ["t_gates_mech_control_lab"], "fg": 911, "bg": 939}, {"id": ["t_gates_control_concrete"], "fg": 908, "bg": 982}, {"id": ["t_gates_control_concrete_lab"], "fg": 911, "bg": 2374}, {"id": ["t_gates_control_brick"], "fg": 908, "bg": 674}, {"id": ["t_gates_control_brick_lab"], "fg": 911, "bg": 674}, {"id": ["t_gates_control_metal"], "fg": 908, "bg": 2382}, {"id": ["t_gates_control_metal_lab"], "fg": 911, "bg": 2382}, {"id": ["t_elevator_control"], "fg": 907, "bg": 939}, {"id": ["t_elevator_control_off"], "fg": 910, "bg": 939}, {"id": ["t_stump"], "fg": 912, "bg": 1233}, {"id": ["t_stump_season_summer"], "fg": 912, "bg": 1240}, {"id": ["t_stump_season_autumn"], "fg": 912, "bg": 1234}, {"id": "t_stump_season_winter", "fg": 912, "bg": 644}, {"id": ["t_water_moving_dp", "t_swater_moving_dp"], "multitile": true, "fg": 916, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 915}, {"id": "corner", "bg": 1233, "fg": [921, 918, 917, 922]}, {"id": "t_connection", "bg": 1233, "fg": [923, 928, 925, 927]}, {"id": "edge", "bg": 1233, "fg": [920, 919]}, {"id": "end_piece", "bg": 1233, "fg": [924, 913, 914, 926]}, {"bg": 1233, "id": "unconnected", "fg": 916}]}, {"id": ["t_water_moving_dp_season_summer", "t_swater_moving_dp_season_summer"], "multitile": true, "fg": 916, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 915}, {"id": "corner", "bg": 1240, "fg": [921, 918, 917, 922]}, {"id": "t_connection", "bg": 1240, "fg": [923, 928, 925, 927]}, {"id": "edge", "bg": 1240, "fg": [920, 919]}, {"id": "end_piece", "bg": 1240, "fg": [924, 913, 914, 926]}, {"bg": 1240, "id": "unconnected", "fg": 916}]}, {"id": ["t_water_moving_dp_season_autumn", "t_swater_moving_dp_season_autumn"], "multitile": true, "fg": 916, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 915}, {"id": "corner", "bg": 1234, "fg": [921, 918, 917, 922]}, {"id": "t_connection", "bg": 1234, "fg": [923, 928, 925, 927]}, {"id": "edge", "bg": 1234, "fg": [920, 919]}, {"id": "end_piece", "bg": 1234, "fg": [924, 913, 914, 926]}, {"bg": 1234, "id": "unconnected", "fg": 916}]}, {"id": ["t_water_moving_dp_season_winter", "t_swater_moving_dp_season_winter"], "multitile": true, "fg": 916, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": 915}, {"id": "corner", "bg": 643, "fg": [921, 918, 917, 922]}, {"id": "t_connection", "bg": 643, "fg": [923, 928, 925, 927]}, {"id": "edge", "bg": 643, "fg": [920, 919]}, {"id": "end_piece", "bg": 643, "fg": [924, 913, 914, 926]}, {"bg": 643, "id": "unconnected", "fg": 916}]}, {"id": "t_thconc_floor", "multitile": true, "fg": 938, "additional_tiles": [{"id": "center", "fg": 939}, {"id": "corner", "fg": [935, 933, 943, 934]}, {"id": "t_connection", "fg": [940, 936, 929, 937]}, {"id": "edge", "fg": [942, 944]}, {"id": "end_piece", "fg": [932, 931, 941, 930]}, {"id": "unconnected", "fg": 938}]}, {"id": "t_carpet_green", "multitile": true, "fg": 955, "additional_tiles": [{"id": "center", "fg": 950}, {"id": "corner", "fg": [946, 956, 954, 952]}, {"id": "t_connection", "fg": [948, 949, 947, 951]}, {"id": "edge", "fg": [960, 953]}, {"id": "end_piece", "fg": [958, 957, 959, 945]}, {"id": "unconnected", "fg": 955}]}, {"id": "t_door_lab_c", "fg": 962}, {"id": "t_door_lab_o", "fg": 961}, {"id": "t_dirtfloor", "multitile": true, "fg": 977, "additional_tiles": [{"id": "center", "fg": 971}, {"id": "corner", "fg": [972, 976, 969, 975]}, {"id": "t_connection", "fg": [974, 966, 978, 965]}, {"id": "edge", "fg": [968, 973]}, {"id": "end_piece", "fg": [970, 967, 963, 964]}, {"id": "unconnected", "fg": 977}]}, {"id": "t_concrete_wall", "multitile": true, "fg": 982, "additional_tiles": [{"id": "center", "fg": 986}, {"id": "corner", "fg": [994, 985, 993, 984]}, {"id": "t_connection", "fg": [989, 979, 987, 983]}, {"id": "edge", "fg": [992, 981]}, {"id": "end_piece", "fg": [991, 988, 990, 980]}, {"id": "unconnected", "fg": 982}]}, {"id": "t_wall_w", "multitile": true, "fg": 996, "additional_tiles": [{"id": "center", "fg": 1006}, {"id": "corner", "fg": [1010, 1002, 1005, 998]}, {"id": "t_connection", "fg": [997, 1009, 999, 995]}, {"id": "edge", "fg": [1000, 1007]}, {"id": "end_piece", "fg": [1008, 1004, 1001, 1003]}, {"id": "unconnected", "fg": 996}]}, {"id": "t_rock_wall", "multitile": true, "fg": 1011, "additional_tiles": [{"id": "center", "fg": 1020}, {"id": "corner", "fg": [1015, 1023, 1012, 1013]}, {"id": "t_connection", "fg": [1016, 1025, 1026, 1022]}, {"id": "edge", "fg": [1014, 1021]}, {"id": "end_piece", "fg": [1017, 1018, 1019, 1024]}, {"id": "unconnected", "fg": 1011}]}, {"id": "t_rock_floor", "multitile": true, "fg": 1034, "additional_tiles": [{"id": "center", "fg": 1038}, {"id": "corner", "fg": [1036, 1042, 1041, 1040]}, {"id": "t_connection", "fg": [1027, 1032, 1035, 1030]}, {"id": "edge", "fg": [1029, 1028]}, {"id": "end_piece", "fg": [1039, 1037, 1033, 1031]}, {"id": "unconnected", "fg": 1034}]}, {"id": "t_grass_tall", "multitile": true, "fg": 1054, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 1052}, {"id": "corner", "bg": 1233, "fg": [1046, 1050, 1056, 1049]}, {"id": "t_connection", "bg": 1233, "fg": [1048, 1044, 1053, 1057]}, {"id": "edge", "bg": 1233, "fg": [1047, 1045]}, {"id": "end_piece", "bg": 1233, "fg": [1051, 1043, 1055, 1058]}, {"bg": 1233, "id": "unconnected", "fg": 1054}]}, {"id": "t_grass_tall_season_summer", "multitile": true, "fg": 1062, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 1069}, {"id": "corner", "bg": 1240, "fg": [1067, 1071, 1074, 1059]}, {"id": "t_connection", "bg": 1240, "fg": [1066, 1073, 1065, 1070]}, {"id": "edge", "bg": 1240, "fg": [1060, 1072]}, {"id": "end_piece", "bg": 1240, "fg": [1061, 1063, 1064, 1068]}, {"bg": 1240, "id": "unconnected", "fg": 1062}]}, {"id": "t_grass_tall_season_autumn", "multitile": true, "fg": 1088, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 1082}, {"id": "corner", "bg": 1234, "fg": [1075, 1090, 1078, 1080]}, {"id": "t_connection", "bg": 1234, "fg": [1086, 1081, 1083, 1085]}, {"id": "edge", "bg": 1234, "fg": [1076, 1077]}, {"id": "end_piece", "bg": 1234, "fg": [1089, 1087, 1084, 1079]}, {"bg": 1234, "id": "unconnected", "fg": 1088}]}, {"id": "t_grass_tall_season_winter", "fg": 644}, {"id": "f_grass_tall", "multitile": true, "fg": 1054, "additional_tiles": [{"id": "center", "fg": 1052}, {"id": "corner", "fg": [1046, 1050, 1056, 1049]}, {"id": "t_connection", "fg": [1048, 1044, 1053, 1057]}, {"id": "edge", "fg": [1047, 1045]}, {"id": "end_piece", "fg": [1051, 1043, 1055, 1058]}, {"id": "unconnected", "fg": 1054}]}, {"id": "f_grass_tall_summer", "multitile": true, "fg": 1062, "additional_tiles": [{"id": "center", "fg": 1069}, {"id": "corner", "fg": [1067, 1071, 1074, 1059]}, {"id": "t_connection", "fg": [1066, 1073, 1065, 1070]}, {"id": "edge", "fg": [1060, 1072]}, {"id": "end_piece", "fg": [1061, 1063, 1064, 1068]}, {"id": "unconnected", "fg": 1062}]}, {"id": "f_grass_tall_autumn", "multitile": true, "fg": 1088, "additional_tiles": [{"id": "center", "fg": 1082}, {"id": "corner", "fg": [1075, 1090, 1078, 1080]}, {"id": "t_connection", "fg": [1086, 1081, 1083, 1085]}, {"id": "edge", "fg": [1076, 1077]}, {"id": "end_piece", "fg": [1089, 1087, 1084, 1079]}, {"id": "unconnected", "fg": 1088}]}, {"id": "t_grass_long", "multitile": true, "fg": 1096, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 1102}, {"id": "corner", "bg": 1233, "fg": [1097, 1100, 1091, 1095]}, {"id": "t_connection", "bg": 1233, "fg": [1098, 1103, 1092, 1106]}, {"id": "edge", "bg": 1233, "fg": [1104, 1094]}, {"id": "end_piece", "bg": 1233, "fg": [1099, 1093, 1105, 1101]}, {"bg": 1233, "id": "unconnected", "fg": 1096}]}, {"id": "t_grass_long_season_autumn", "multitile": true, "fg": 1122, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 1115}, {"id": "corner", "bg": 1234, "fg": [1114, 1121, 1120, 1117]}, {"id": "t_connection", "bg": 1234, "fg": [1108, 1107, 1112, 1119]}, {"id": "edge", "bg": 1234, "fg": [1110, 1113]}, {"id": "end_piece", "bg": 1234, "fg": [1109, 1116, 1111, 1118]}, {"bg": 1234, "id": "unconnected", "fg": 1122}]}, {"id": "t_grass_long_season_summer", "multitile": true, "fg": 1135, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 1132}, {"id": "corner", "bg": 1240, "fg": [1136, 1129, 1125, 1130]}, {"id": "t_connection", "bg": 1240, "fg": [1128, 1133, 1134, 1127]}, {"id": "edge", "bg": 1240, "fg": [1138, 1126]}, {"id": "end_piece", "bg": 1240, "fg": [1124, 1131, 1137, 1123]}, {"bg": 1240, "id": "unconnected", "fg": 1135}]}, {"id": "t_grass_long_season_winter", "fg": 644}, {"id": "f_grass_long", "multitile": true, "fg": 1096, "additional_tiles": [{"id": "center", "fg": 1102}, {"id": "corner", "fg": [1097, 1100, 1091, 1095]}, {"id": "t_connection", "fg": [1098, 1103, 1092, 1106]}, {"id": "edge", "fg": [1104, 1094]}, {"id": "end_piece", "fg": [1099, 1093, 1105, 1101]}, {"id": "unconnected", "fg": 1096}]}, {"id": ["t_shrub_lilac"], "fg": 1142, "bg": 1233}, {"id": ["t_shrub_lilac_harvested"], "fg": 1139, "bg": 1233}, {"id": "t_shrub_lilac_season_summer", "fg": 1141, "bg": 1240}, {"id": "t_shrub_lilac_season_autumn", "fg": 1139, "bg": 1234}, {"id": "t_shrub_lilac_season_winter", "fg": 1140, "bg": 644}, {"id": "t_elevator", "fg": [{"weight": 100, "sprite": 1143}, {"weight": 100, "sprite": 1144}]}, {"id": "t_moss", "fg": 1145}, {"id": "t_moss_season_winter", "fg": 644}, {"id": "t_scrap_floor", "multitile": true, "fg": 1155, "additional_tiles": [{"id": "center", "fg": 1152}, {"id": "corner", "fg": [1150, 1157, 1146, 1161]}, {"id": "t_connection", "fg": [1149, 1160, 1148, 1151]}, {"id": "edge", "fg": [1159, 1153]}, {"id": "end_piece", "fg": [1156, 1147, 1158, 1154]}, {"id": "unconnected", "fg": 1155}]}, {"id": "t_grass_dead", "multitile": true, "fg": 1176, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 1172}, {"id": "corner", "bg": 1233, "fg": [1177, 1168, 1169, 1164]}, {"id": "t_connection", "bg": 1233, "fg": [1171, 1166, 1174, 1165]}, {"id": "edge", "bg": 1233, "fg": [1163, 1170]}, {"id": "end_piece", "bg": 1233, "fg": [1175, 1162, 1167, 1173]}, {"bg": 1233, "id": "unconnected", "fg": 1176}]}, {"id": "t_grass_dead_season_summer", "multitile": true, "fg": 1176, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 1172}, {"id": "corner", "bg": 1240, "fg": [1177, 1168, 1169, 1164]}, {"id": "t_connection", "bg": 1240, "fg": [1171, 1166, 1174, 1165]}, {"id": "edge", "bg": 1240, "fg": [1163, 1170]}, {"id": "end_piece", "bg": 1240, "fg": [1175, 1162, 1167, 1173]}, {"bg": 1240, "id": "unconnected", "fg": 1176}]}, {"id": "t_grass_dead_season_autumn", "multitile": true, "fg": 1176, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 1172}, {"id": "corner", "bg": 1234, "fg": [1177, 1168, 1169, 1164]}, {"id": "t_connection", "bg": 1234, "fg": [1171, 1166, 1174, 1165]}, {"id": "edge", "bg": 1234, "fg": [1163, 1170]}, {"id": "end_piece", "bg": 1234, "fg": [1175, 1162, 1167, 1173]}, {"bg": 1234, "id": "unconnected", "fg": 1176}]}, {"id": "t_grass_dead_season_winter", "fg": 643}, {"id": ["t_water_sh", "t_swater_sh"], "multitile": true, "fg": 1190, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": [{"weight": 1, "sprite": 1186}, {"weight": 1, "sprite": 1193}, {"weight": 1, "sprite": 1188}]}, {"id": "corner", "bg": 1233, "fg": [1181, 1184, 1195, 1192]}, {"id": "t_connection", "bg": 1233, "fg": [1182, 1187, 1191, 1194]}, {"id": "edge", "bg": 1233, "fg": [1180, 1183]}, {"id": "end_piece", "bg": 1233, "fg": [1179, 1185, 1178, 1189]}, {"bg": 1233, "id": "unconnected", "fg": 1190}]}, {"id": ["t_water_sh_season_summer", "t_swater_sh_season_summer"], "multitile": true, "fg": 1190, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": [{"weight": 1, "sprite": 1186}, {"weight": 1, "sprite": 1193}, {"weight": 1, "sprite": 1188}]}, {"id": "corner", "bg": 1240, "fg": [1181, 1184, 1195, 1192]}, {"id": "t_connection", "bg": 1240, "fg": [1182, 1187, 1191, 1194]}, {"id": "edge", "bg": 1240, "fg": [1180, 1183]}, {"id": "end_piece", "bg": 1240, "fg": [1179, 1185, 1178, 1189]}, {"bg": 1240, "id": "unconnected", "fg": 1190}]}, {"id": ["t_water_sh_season_autumn", "t_swater_sh_season_autumn"], "multitile": true, "fg": 1190, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": [{"weight": 1, "sprite": 1186}, {"weight": 1, "sprite": 1193}, {"weight": 1, "sprite": 1188}]}, {"id": "corner", "bg": 1234, "fg": [1181, 1184, 1195, 1192]}, {"id": "t_connection", "bg": 1234, "fg": [1182, 1187, 1191, 1194]}, {"id": "edge", "bg": 1234, "fg": [1180, 1183]}, {"id": "end_piece", "bg": 1234, "fg": [1179, 1185, 1178, 1189]}, {"bg": 1234, "id": "unconnected", "fg": 1190}]}, {"id": ["t_water_sh_season_winter", "t_swater_sh_season_winter"], "multitile": true, "fg": 1190, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": [{"weight": 1, "sprite": 1186}, {"weight": 1, "sprite": 1193}, {"weight": 1, "sprite": 1188}]}, {"id": "corner", "bg": 643, "fg": [1181, 1184, 1195, 1192]}, {"id": "t_connection", "bg": 643, "fg": [1182, 1187, 1191, 1194]}, {"id": "edge", "bg": 643, "fg": [1180, 1183]}, {"id": "end_piece", "bg": 643, "fg": [1179, 1185, 1178, 1189]}, {"bg": 643, "id": "unconnected", "fg": 1190}]}, {"id": "t_reinforced_glass", "multitile": true, "fg": 1207, "additional_tiles": [{"id": "center", "fg": 1198}, {"id": "corner", "fg": [1211, 1206, 1201, 1205]}, {"id": "t_connection", "fg": [1208, 1209, 1200, 1204]}, {"id": "edge", "fg": [1197, 1210]}, {"id": "end_piece", "fg": [1203, 1202, 1196, 1199]}, {"id": "unconnected", "fg": 1207}]}, {"id": "t_carpet_yellow", "multitile": true, "fg": 1213, "additional_tiles": [{"id": "center", "fg": 1226}, {"id": "corner", "fg": [1212, 1221, 1224, 1217]}, {"id": "t_connection", "fg": [1227, 1215, 1214, 1220]}, {"id": "edge", "fg": [1219, 1225]}, {"id": "end_piece", "fg": [1223, 1222, 1218, 1216]}, {"id": "unconnected", "fg": 1213}]}, {"id": "t_dirt", "fg": [{"weight": 100, "sprite": 1233}, {"weight": 70, "sprite": 1235}, {"weight": 30, "sprite": 1239}, {"weight": 30, "sprite": 1230}, {"weight": 10, "sprite": 1237}, {"weight": 20, "sprite": 1231}, {"weight": 20, "sprite": 1232}, {"weight": 10, "sprite": 1236}, {"weight": 10, "sprite": 1238}], "bg": [{"weight": 100, "sprite": 1233}, {"weight": 200, "sprite": 1235}]}, {"id": "t_dirt_season_summer", "fg": [{"weight": 100, "sprite": 1240}, {"weight": 100, "sprite": 1229}, {"weight": 30, "sprite": 1239}, {"weight": 30, "sprite": 1230}, {"weight": 10, "sprite": 1237}, {"weight": 12, "sprite": 1231}, {"weight": 12, "sprite": 1232}, {"weight": 7, "sprite": 1236}, {"weight": 6, "sprite": 1238}], "bg": [{"weight": 100, "sprite": 1240}, {"weight": 100, "sprite": 1229}]}, {"id": "t_dirt_season_autumn", "fg": [{"weight": 100, "sprite": 1234}, {"weight": 100, "sprite": 1228}, {"weight": 30, "sprite": 1239}, {"weight": 30, "sprite": 1230}, {"weight": 10, "sprite": 1237}, {"weight": 6, "sprite": 1231}, {"weight": 6, "sprite": 1232}, {"weight": 6, "sprite": 1236}, {"weight": 4, "sprite": 1238}], "bg": [{"weight": 100, "sprite": 1234}, {"weight": 100, "sprite": 1228}]}, {"id": "t_dirt_season_winter", "fg": 643}, {"id": "t_door_metal_c_peep", "fg": 1241}, {"id": "t_shrub", "fg": 1242, "bg": 1233}, {"id": "t_shrub_season_summer", "fg": 1242, "bg": 1240}, {"id": "t_shrub_season_autumn", "fg": 1242, "bg": 1234}, {"id": "t_shrub_season_winter", "fg": 1243, "bg": 644}, {"id": "t_pit", "fg": 1244, "bg": [{"weight": 100, "sprite": 1233}, {"weight": 100, "sprite": 1235}]}, {"id": "t_pit_season_summer", "fg": 1244, "bg": [{"weight": 100, "sprite": 1240}, {"weight": 100, "sprite": 1229}]}, {"id": "t_pit_season_autumn", "fg": 1244, "bg": [{"weight": 100, "sprite": 1234}, {"weight": 100, "sprite": 1228}]}, {"id": "t_door_c", "fg": 1245}, {"id": "t_door_locked", "fg": 1247}, {"id": "t_door_o", "fg": 1246}, {"id": "t_door_b", "fg": 1248}, {"id": "t_scrap_wall", "multitile": true, "fg": 1263, "additional_tiles": [{"id": "center", "fg": 1260}, {"id": "corner", "fg": [1250, 1264, 1262, 1265]}, {"id": "t_connection", "fg": [1255, 1258, 1254, 1252]}, {"id": "edge", "fg": [1253, 1257]}, {"id": "end_piece", "fg": [1259, 1251, 1249, 1256]}, {"id": "unconnected", "fg": 1263}]}, {"id": "t_clay", "multitile": true, "fg": 1270, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": 1277}, {"id": "corner", "bg": 1233, "fg": [1272, 1267, 1269, 1278]}, {"id": "t_connection", "bg": 1233, "fg": [1280, 1279, 1271, 1275]}, {"id": "edge", "bg": 1233, "fg": [1266, 1268]}, {"id": "end_piece", "bg": 1233, "fg": [1276, 1281, 1274, 1273]}, {"bg": 1233, "id": "unconnected", "fg": 1270}]}, {"id": "t_clay_season_summer", "multitile": true, "fg": 1270, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 1277}, {"id": "corner", "bg": 1240, "fg": [1272, 1267, 1269, 1278]}, {"id": "t_connection", "bg": 1240, "fg": [1280, 1279, 1271, 1275]}, {"id": "edge", "bg": 1240, "fg": [1266, 1268]}, {"id": "end_piece", "bg": 1240, "fg": [1276, 1281, 1274, 1273]}, {"bg": 1240, "id": "unconnected", "fg": 1270}]}, {"id": "t_clay_season_autumn", "multitile": true, "fg": 1270, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 1277}, {"id": "corner", "bg": 1234, "fg": [1272, 1267, 1269, 1278]}, {"id": "t_connection", "bg": 1234, "fg": [1280, 1279, 1271, 1275]}, {"id": "edge", "bg": 1234, "fg": [1266, 1268]}, {"id": "end_piece", "bg": 1234, "fg": [1276, 1281, 1274, 1273]}, {"bg": 1234, "id": "unconnected", "fg": 1270}]}, {"id": "t_clay_season_winter", "fg": 643}, {"id": ["t_shrub_hydrangea"], "fg": 1284, "bg": 1233}, {"id": ["t_shrub_hydrangea_harvested"], "fg": 1285, "bg": 1233}, {"id": "t_shrub_hydrangea_season_summer", "fg": 1282, "bg": 1240}, {"id": "t_shrub_hydrangea_season_autumn", "fg": 1284, "bg": 1234}, {"id": "t_shrub_hydrangea_season_winter", "fg": 1283, "bg": 644}, {"id": "t_bars", "fg": 1286}, {"id": ["t_shrub_grape"], "fg": 1290, "bg": 1233}, {"id": ["t_shrub_grape_harvested"], "fg": 1287, "bg": 1240}, {"id": "t_shrub_grape_season_summer", "fg": 1289, "bg": 1240}, {"id": "t_shrub_grape_season_autumn", "fg": 1290, "bg": 1234}, {"id": "t_shrub_grape_season_winter", "fg": 1288, "bg": 644}, {"id": "t_door_glass_o", "fg": 1291}, {"id": ["t_shrub_rose"], "fg": 1294, "bg": 1233}, {"id": "t_shrub_rose_season_summer", "fg": 1294, "bg": 1240}, {"id": "t_shrub_rose_harvested", "fg": 1294, "bg": 1234}, {"id": "t_shrub_rose_season_autumn", "fg": 1292, "bg": 1234}, {"id": "t_shrub_rose_season_winter", "fg": 1293, "bg": 644}, {"id": "t_wall", "multitile": true, "fg": 1307, "additional_tiles": [{"id": "center", "fg": 1302}, {"id": "corner", "fg": [1308, 1300, 1297, 1306]}, {"id": "t_connection", "fg": [1304, 1299, 1310, 1295]}, {"id": "edge", "fg": [1296, 1298]}, {"id": "end_piece", "fg": [1303, 1309, 1305, 1301]}, {"id": "unconnected", "fg": 1307}]}, {"id": "t_wall_p", "multitile": true, "fg": 1320, "additional_tiles": [{"id": "center", "fg": 1325}, {"id": "corner", "fg": [1313, 1316, 1321, 1318]}, {"id": "t_connection", "fg": [1323, 1317, 1319, 1311]}, {"id": "edge", "fg": [1324, 1312]}, {"id": "end_piece", "fg": [1322, 1314, 1326, 1315]}, {"id": "unconnected", "fg": 1320}]}, {"id": "t_wall_log", "multitile": true, "fg": 1334, "bg": 1233, "additional_tiles": [{"id": "center", "fg": 1338}, {"id": "corner", "fg": [1339, 1328, 1342, 1336]}, {"id": "t_connection", "fg": [1333, 1330, 1341, 1332]}, {"id": "edge", "bg": 1233, "fg": [1329, 1331]}, {"id": "end_piece", "bg": 1233, "fg": [1340, 1335, 1337, 1327]}, {"bg": 1233, "id": "unconnected", "fg": 1334}]}, {"id": "t_wall_g", "multitile": true, "fg": 1348, "additional_tiles": [{"id": "center", "fg": 1352}, {"id": "corner", "fg": [1358, 1355, 1349, 1357]}, {"id": "t_connection", "fg": [1353, 1344, 1354, 1350]}, {"id": "edge", "fg": [1345, 1346]}, {"id": "end_piece", "fg": [1356, 1351, 1347, 1343]}, {"id": "unconnected", "fg": 1348}]}, {"id": "t_door_boarded", "fg": 1359}, {"id": "t_door_boarded_damaged", "fg": 1360}, {"id": ["t_water_pool", "t_water_pool_shallow"], "multitile": true, "fg": 1368, "additional_tiles": [{"id": "center", "fg": [{"weight": 1, "sprite": 1186}, {"weight": 1, "sprite": 1193}, {"weight": 1, "sprite": 1188}]}, {"id": "corner", "fg": [1363, 1372, 1371, 1365]}, {"id": "t_connection", "fg": [1367, 1364, 1369, 1373]}, {"id": "edge", "fg": [1370, 1362]}, {"id": "end_piece", "fg": [1374, 1375, 1361, 1366]}, {"id": "unconnected", "fg": 1368}]}, {"id": "t_pavement", "fg": 1376}, {"id": "t_pavement_season_winter", "fg": 643}, {"id": ["t_water_dp", "t_swater_dp"], "multitile": true, "fg": 1384, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": [{"weight": 1, "sprite": 1386}, {"weight": 1, "sprite": 1387}, {"weight": 1, "sprite": 1393}]}, {"id": "corner", "bg": 1233, "fg": [1392, 1377, 1379, 1388]}, {"id": "t_connection", "bg": 1233, "fg": [1381, 1389, 1391, 1380]}, {"id": "edge", "bg": 1233, "fg": [1383, 1394]}, {"id": "end_piece", "bg": 1233, "fg": [1390, 1385, 1382, 1378]}, {"bg": 1233, "id": "unconnected", "fg": 1384}]}, {"id": ["t_water_dp_season_summer", "t_swater_dp_season_summer"], "multitile": true, "fg": 1384, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": [{"weight": 1, "sprite": 1386}, {"weight": 1, "sprite": 1387}, {"weight": 1, "sprite": 1393}]}, {"id": "corner", "bg": 1240, "fg": [1392, 1377, 1379, 1388]}, {"id": "t_connection", "bg": 1240, "fg": [1381, 1389, 1391, 1380]}, {"id": "edge", "bg": 1240, "fg": [1383, 1394]}, {"id": "end_piece", "bg": 1240, "fg": [1390, 1385, 1382, 1378]}, {"bg": 1240, "id": "unconnected", "fg": 1384}]}, {"id": ["t_water_dp_season_autumn", "t_swater_dp_season_autumn"], "multitile": true, "fg": 1384, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": [{"weight": 1, "sprite": 1386}, {"weight": 1, "sprite": 1387}, {"weight": 1, "sprite": 1393}]}, {"id": "corner", "bg": 1234, "fg": [1392, 1377, 1379, 1388]}, {"id": "t_connection", "bg": 1234, "fg": [1381, 1389, 1391, 1380]}, {"id": "edge", "bg": 1234, "fg": [1383, 1394]}, {"id": "end_piece", "bg": 1234, "fg": [1390, 1385, 1382, 1378]}, {"bg": 1234, "id": "unconnected", "fg": 1384}]}, {"id": ["t_water_dp_season_winter", "t_swater_dp_season_winter"], "multitile": true, "fg": 1384, "bg": 643, "additional_tiles": [{"id": "center", "bg": 643, "fg": [{"weight": 1, "sprite": 1386}, {"weight": 1, "sprite": 1387}, {"weight": 1, "sprite": 1393}]}, {"id": "corner", "bg": 643, "fg": [1392, 1377, 1379, 1388]}, {"id": "t_connection", "bg": 643, "fg": [1381, 1389, 1391, 1380]}, {"id": "edge", "bg": 643, "fg": [1383, 1394]}, {"id": "end_piece", "bg": 643, "fg": [1390, 1385, 1382, 1378]}, {"bg": 643, "id": "unconnected", "fg": 1384}]}, {"id": ["t_linoleum_gray", "t_linoluem_gray_no_roof"], "multitile": true, "fg": 1398, "additional_tiles": [{"id": "center", "fg": 1397}, {"id": "corner", "fg": [1406, 1399, 1405, 1401]}, {"id": "t_connection", "fg": [1402, 1396, 1395, 1408]}, {"id": "edge", "fg": [1400, 1407]}, {"id": "end_piece", "fg": [1404, 1409, 1410, 1403]}, {"id": "unconnected", "fg": 1398}]}, {"id": "t_grass", "multitile": true, "fg": 1417, "bg": 1233, "additional_tiles": [{"id": "center", "bg": 1233, "fg": [{"weight": 1, "sprite": 1418}, {"weight": 1, "sprite": 1421}, {"weight": 1, "sprite": 1433}, {"weight": 1, "sprite": 1432}, {"weight": 1, "sprite": 1413}, {"weight": 1, "sprite": 1424}, {"weight": 1, "sprite": 1415}, {"weight": 1, "sprite": 1434}, {"weight": 1, "sprite": 1428}]}, {"id": "corner", "bg": 1233, "fg": [1427, 1420, 1425, 1416]}, {"id": "t_connection", "bg": 1233, "fg": [1412, 1430, 1411, 1431]}, {"id": "edge", "bg": 1233, "fg": [1426, 1414]}, {"id": "end_piece", "bg": 1233, "fg": [1423, 1429, 1419, 1422]}, {"bg": 1233, "id": "unconnected", "fg": 1417}]}, {"id": "t_grass_season_summer", "multitile": true, "fg": 1417, "bg": 1240, "additional_tiles": [{"id": "center", "bg": 1240, "fg": 1460}, {"id": "corner", "bg": 1240, "fg": [1465, 1452, 1454, 1453]}, {"id": "t_connection", "bg": 1240, "fg": [1455, 1457, 1464, 1463]}, {"id": "edge", "bg": 1240, "fg": [1459, 1458]}, {"id": "end_piece", "bg": 1240, "fg": [1451, 1462, 1461, 1456]}, {"bg": 1240, "id": "unconnected", "fg": 1466}]}, {"id": "t_grass_season_autumn", "multitile": true, "fg": 1417, "bg": 1234, "additional_tiles": [{"id": "center", "bg": 1234, "fg": 1444}, {"id": "corner", "bg": 1234, "fg": [1449, 1435, 1450, 1446]}, {"id": "t_connection", "bg": 1234, "fg": [1447, 1438, 1445, 1443]}, {"id": "edge", "bg": 1234, "fg": [1440, 1439]}, {"id": "end_piece", "bg": 1234, "fg": [1442, 1441, 1437, 1448]}, {"bg": 1234, "id": "unconnected", "fg": 1436}]}, {"id": "t_grass_season_winter", "fg": 643}, {"id": "t_stairs_down", "fg": 1467}, {"id": "t_wood_stairs_down", "fg": 1468}, {"id": "t_floor_wax", "multitile": true, "fg": 1478, "additional_tiles": [{"id": "center", "fg": 1481}, {"id": "corner", "fg": [1483, 1470, 1477, 1474]}, {"id": "t_connection", "fg": [1479, 1484, 1471, 1472]}, {"id": "edge", "fg": [1475, 1480]}, {"id": "end_piece", "fg": [1469, 1482, 1473, 1476]}, {"id": "unconnected", "fg": 1478}]}, {"id": "t_wall_r", "multitile": true, "fg": 1485, "additional_tiles": [{"id": "center", "fg": 1492}, {"id": "corner", "fg": [1494, 1493, 1498, 1499]}, {"id": "t_connection", "fg": [1488, 1490, 1491, 1495]}, {"id": "edge", "fg": [1500, 1497]}, {"id": "end_piece", "fg": [1489, 1496, 1487, 1486]}, {"id": "unconnected", "fg": 1485}]}, {"id": "t_concrete", "multitile": true, "fg": 1508, "additional_tiles": [{"id": "center", "fg": 1502}, {"id": "corner", "fg": [1513, 1510, 1501, 1511]}, {"id": "t_connection", "fg": [1509, 1503, 1515, 1505]}, {"id": "edge", "fg": [1507, 1512]}, {"id": "end_piece", "fg": [1506, 1504, 1516, 1514]}, {"id": "unconnected", "fg": 1508}]}, {"id": "t_concrete_season_winter", "fg": 643}, {"id": "t_wall_resin", "multitile": true, "fg": 1525, "additional_tiles": [{"id": "center", "fg": 1532}, {"id": "corner", "fg": [1520, 1531, 1522, 1528]}, {"id": "t_connection", "fg": [1517, 1523, 1519, 1521]}, {"id": "edge", "fg": [1534, 1533]}, {"id": "end_piece", "fg": [1530, 1524, 1526, 1527]}, {"id": "unconnected", "fg": 1525}]}, {"id": "t_resin_hole_c", "fg": 1529}, {"id": "t_resin_hole_o", "fg": 1518}, {"id": "t_ladder_down", "fg": 1535}, {"id": "tr_nailboard", "fg": 1536, "bg": 480}, {"id": "animation_hit", "fg": 1537}, {"id": ["overlay_effects_bleed"], "fg": 1543}, {"id": ["overlay_effects_deaf"], "fg": 1538}, {"id": ["overlay_effects_downed"], "fg": 1545}, {"id": ["overlay_effects_grabbed"], "fg": 1544}, {"id": ["overlay_effects_winded"], "fg": 1542}, {"id": ["overlay_effects_hot"], "fg": 1539}, {"id": ["overlay_effects_cold"], "fg": 1548}, {"id": ["overlay_male_crouch", "overlay_female_crouch"], "fg": 1541}, {"id": ["overlay_male_run", "overlay_female_run"], "fg": 1546}, {"id": ["overlay_hostile_sees_player"], "fg": 1547}, {"id": ["zombie_revival_indicator"], "fg": 1540}, {"id": "cursor", "fg": 1549}, {"id": "highlight", "fg": 1552}, {"id": "highlight_item", "fg": 1553}, {"id": "line_target", "fg": 1550}, {"id": "line_trail", "fg": 1551}, {"id": "animation_line", "fg": 1554}, {"id": "mon_pig", "fg": [{"weight": 8, "sprite": 1557}, {"weight": 3, "sprite": 1556}, {"weight": 1, "sprite": 1555}], "bg": 1581}, {"id": "mon_piglet", "fg": 1558, "bg": 1582}, {"id": "mon_deer_mouse", "fg": 1559, "bg": 1582}, {"id": "mon_locust_nymph", "fg": 1560, "bg": 1582}, {"id": "mon_skittering_plague", "fg": 1561, "bg": 1581}, {"id": "mon_black_rat", "fg": 1562, "bg": 1582}, {"id": "mon_zolf", "fg": 1563, "bg": 1581}, {"id": "mon_dog", "fg": 1564, "bg": 1581}, {"id": "mon_dog_skeleton", "fg": 1568, "bg": 1581}, {"id": "mon_zombie_dog", "fg": [{"weight": 1, "sprite": 1569}, {"weight": 1, "sprite": 1570}], "bg": 1581}, {"id": "mon_dog_beagle", "fg": 1567, "bg": 1582}, {"id": "mon_dog_gshepherd", "fg": 1566, "bg": 1581}, {"id": "mon_dog_boxer", "fg": 1565, "bg": 1581}, {"id": "mon_dog_dachshund", "fg": 1571, "bg": 1581}, {"id": "mon_blob", "fg": 1572, "bg": 1581}, {"id": "mon_squirrel_red", "fg": 1573, "bg": 1582}, {"id": "mon_plague_vector", "fg": 1574, "bg": 1581}, {"id": "mon_blob_small", "fg": [{"weight": 1, "sprite": 1575}, {"weight": 1, "sprite": 1576}], "bg": 1582}, {"id": "mon_dragonfly", "fg": 1577, "bg": 1582}, {"id": "mon_zombie_child", "fg": [{"weight": 1, "sprite": 1578}, {"weight": 1, "sprite": 1579}], "bg": 1582}, {"id": "mon_plague_nymph", "fg": 1580, "bg": 1582}, {"id": "mon_squirrel", "fg": 1583, "bg": 1582}, {"id": "mon_giant_cockroach", "fg": 1584, "bg": 1581}, {"id": "mon_zombie_pig", "fg": 1585, "bg": 1581}, {"id": "mon_rabbit", "fg": 1586, "bg": 1582}, {"id": "mon_zombeaver", "fg": 1587, "bg": 1582}, {"id": "mon_ant", "fg": 1588, "bg": 1581}, {"id": "mon_ant_acid", "fg": 1593, "bg": 1581}, {"id": "corpse_mon_ant", "fg": 1595}, {"id": "corpse_mon_ant_acid", "fg": 1590}, {"id": "mon_ant_larva", "fg": 1589, "bg": 1582}, {"id": "mon_ant_acid_larva", "fg": 1591, "bg": 1582}, {"id": "corpse_mon_ant_larva", "fg": 1592}, {"id": "corpse_mon_ant_acid_larva", "fg": 1594}, {"id": "mon_centipede_giant", "fg": 1596, "bg": 1581}, {"id": "mon_cat", "fg": [{"weight": 1, "sprite": 1597}, {"weight": 1, "sprite": 1598}], "bg": 1582}, {"id": "mon_beaver", "fg": 1599, "bg": 1582}, {"id": "mon_wolf", "fg": 1600, "bg": 1581}, {"id": "mon_otter", "fg": 1601, "bg": 1582}, {"id": "mon_giant_cockroach_nymph", "fg": 1602, "bg": 1582}, {"id": "mon_duck", "fg": 1603, "bg": 1582}, {"id": "mon_mosquito", "fg": 1604, "bg": 1582}, {"id": "mon_locust", "fg": 1605, "bg": 1581}, {"id": "mon_pregnant_giant_cockroach", "fg": 1606, "bg": 1581}, {"id": "mon_dermatik_larva", "fg": 1607, "bg": 1582}, {"id": "mon_bear_cub", "fg": 1608, "bg": 1582}, {"id": "mon_wasp_small", "fg": 1609, "bg": 1582}, {"id": "fd_fire", "fg": 1610}], "//": "range 1 to 1616"}, {"file": "tall.png", "tiles": [{"id": "f_bookcase", "fg": 1617}, {"id": "f_arcade_machine", "fg": 1618}, {"id": "f_floor_lamp", "fg": 1619}, {"id": "f_dryer", "fg": 1620}, {"id": "f_dresser", "fg": 1621}, {"id": "f_crate_c", "fg": 1623}, {"id": "f_crate_o", "fg": 1622}, {"id": "f_alien_tendril", "fg": 1626}, {"id": "f_alien_zapper", "fg": 1627}, {"id": ["f_alien_pod", "f_alien_pod_organ"], "fg": 1624}, {"id": "f_alien_pod_resin", "fg": 1625}, {"id": "f_glass_cabinet", "fg": 1628}, {"id": "f_shower", "fg": 1629}, {"id": "f_standing_tank", "fg": 1630}, {"id": "f_bigmirror", "fg": 1631}, {"id": "f_glass_fridge", "fg": 1632}, {"id": "f_cattails_season_spring", "fg": 1636, "rotates": false}, {"id": "f_cattails_season_summer", "fg": 1634, "rotates": false}, {"id": "f_cattails_season_autumn", "fg": 1635, "rotates": false}, {"id": "f_cattails_season_winter", "fg": 1633, "rotates": false}, {"id": "f_workbench", "fg": 1637}, {"id": "f_dumpster", "multitile": true, "fg": 1640, "additional_tiles": [{"id": "edge", "fg": [1641, 1644]}, {"id": "end_piece", "fg": [1638, 1642, 1643, 1639]}, {"id": "unconnected", "fg": 1640}]}, {"id": "f_washer", "fg": 1645}, {"id": "f_fireplace", "fg": 1646}, {"id": "f_home_furnace", "fg": 1647}, {"id": "f_locker", "fg": 1648}, {"id": "f_statue", "fg": 1649}, {"id": "f_woodstove", "fg": 1650}, {"id": "f_brazier", "fg": 1651}, {"id": "f_birdbath", "fg": 1652}, {"id": "f_rack_coat", "fg": 1653}, {"id": "f_water_heater", "fg": 1654}, {"id": "f_oven", "fg": 1655}, {"id": "player_male", "fg": 1789}, {"id": "npc_male", "fg": 1789}, {"id": "npc_female", "fg": 1790}, {"id": "player_female", "fg": 1790}, {"id": "t_gutter_downspout", "fg": 1656}, {"id": "t_utility_light", "fg": 1657}, {"id": "t_little_column", "fg": 1658, "bg": 1664}, {"id": "t_machinery_heavy", "fg": 1659, "bg": 1664}, {"id": "t_atm", "fg": 1660, "bg": 1664}, {"id": "t_column", "fg": 1661, "bg": 1664}, {"id": "t_machinery_electronic", "fg": 1668, "bg": 1664}, {"id": "t_machinery_old", "fg": 1669, "bg": 1667}, {"id": "t_stairs_up", "fg": 1670}, {"id": "t_wood_stairs_up", "fg": 1671}, {"id": "t_ladder_up", "fg": 1672}, {"id": "overlay_female_mutation_SCALES", "fg": 1673}, {"id": "overlay_male_mutation_SCALES", "fg": 1674}, {"id": "overlay_female_mutation_TAIL_THICK", "fg": 1675}, {"id": "overlay_male_mutation_TAIL_THICK", "fg": 1676}, {"id": "overlay_female_mutation_TALONS", "fg": 1678}, {"id": "overlay_male_mutation_TALONS", "fg": 1677}, {"id": "overlay_female_mutation_BEAK_PECK", "fg": 1679}, {"id": "overlay_male_mutation_BEAK_PECK", "fg": 1680}, {"id": "overlay_female_mutation_BIRD_EYE", "fg": 1681}, {"id": "overlay_male_mutation_BIRD_EYE", "fg": 1682}, {"id": "overlay_female_mutation_LIZ_EYE", "fg": 1683}, {"id": "overlay_male_mutation_LIZ_EYE", "fg": 1684}, {"id": "overlay_female_mutation_MUZZLE_LONG", "fg": 1686}, {"id": "overlay_male_mutation_MUZZLE_LONG", "fg": 1685}, {"id": "overlay_female_mutation_BEAK_HUM", "fg": 1687}, {"id": "overlay_male_mutation_BEAK_HUM", "fg": 1688}, {"id": "overlay_female_mutation_PLANTSKIN", "fg": 1689}, {"id": "overlay_male_mutation_PLANTSKIN", "fg": 1690}, {"id": "overlay_female_mutation_FANGS", "fg": 1692}, {"id": "overlay_male_mutation_FANGS", "fg": 1691}, {"id": "overlay_female_mutation_CHITIN", "fg": 1693}, {"id": "overlay_male_mutation_CHITIN", "fg": 1694}, {"id": "overlay_female_mutation_ARACHNID_ARMS", "fg": 1695}, {"id": "overlay_male_mutation_ARACHNID_ARMS", "fg": 1696}, {"id": "overlay_female_mutation_FEATHERS", "fg": 1697}, {"id": "overlay_male_mutation_FEATHERS", "fg": 1698}, {"id": "overlay_female_mutation_VINES1", "fg": 1699}, {"id": "overlay_male_mutation_VINES1", "fg": 1700}, {"id": "overlay_female_mutation_WINGS_BIRD", "fg": 1702}, {"id": "overlay_male_mutation_WINGS_BIRD", "fg": 1701}, {"id": "overlay_female_mutation_BEAK", "fg": 1704}, {"id": "overlay_male_mutation_BEAK", "fg": 1703}, {"id": "overlay_female_mutation_CHITIN2", "fg": 1705}, {"id": "overlay_male_mutation_CHITIN2", "fg": 1706}, {"id": "overlay_female_mutation_LEAVES", "fg": 1707}, {"id": "overlay_male_mutation_LEAVES", "fg": 1708}, {"id": "overlay_male_mutation_hair_brown_medium", "fg": 1709}, {"id": "overlay_female_mutation_hair_brown_medium", "fg": 1710}, {"id": "overlay_male_mutation_hair_brown_fro", "fg": 1711}, {"id": "overlay_female_mutation_hair_brown_fro", "fg": 1712}, {"id": "overlay_male_mutation_hair_red_mohawk", "fg": 1713}, {"id": "overlay_female_mutation_hair_red_mohawk", "fg": 1714}, {"id": "overlay_male_mutation_hair_brown_mohawk", "fg": 1716}, {"id": "overlay_female_mutation_hair_brown_mohawk", "fg": 1715}, {"id": "overlay_male_mutation_hair_brown_crewcut", "fg": 1718}, {"id": "overlay_female_mutation_hair_brown_crewcut", "fg": 1717}, {"id": "overlay_male_mutation_hair_black_crewcut", "fg": 1720}, {"id": "overlay_female_mutation_hair_black_crewcut", "fg": 1719}, {"id": "overlay_male_mutation_hair_gray_medium", "fg": 1722}, {"id": "overlay_female_mutation_hair_gray_medium", "fg": 1721}, {"id": "overlay_male_mutation_hair_white_crewcut", "fg": 1723}, {"id": "overlay_female_mutation_hair_white_crewcut", "fg": 1724}, {"id": "overlay_male_mutation_hair_red_medium", "fg": 1726}, {"id": "overlay_female_mutation_hair_red_medium", "fg": 1725}, {"id": "overlay_male_mutation_hair_blond_short", "fg": 1728}, {"id": "overlay_female_mutation_hair_blond_short", "fg": 1727}, {"id": "overlay_male_mutation_hair_white_mohawk", "fg": 1730}, {"id": "overlay_female_mutation_hair_white_mohawk", "fg": 1729}, {"id": "overlay_male_mutation_hair_red_crewcut", "fg": 1732}, {"id": "overlay_female_mutation_hair_red_crewcut", "fg": 1731}, {"id": "overlay_male_mutation_hair_red_fro", "fg": 1734}, {"id": "overlay_female_mutation_hair_red_fro", "fg": 1733}, {"id": "overlay_male_mutation_hair_white_medium", "fg": 1735}, {"id": "overlay_female_mutation_hair_white_medium", "fg": 1736}, {"id": "overlay_male_mutation_hair_black_medium", "fg": 1737}, {"id": "overlay_female_mutation_hair_black_medium", "fg": 1738}, {"id": "overlay_male_mutation_hair_blond_medium", "fg": 1740}, {"id": "overlay_female_mutation_hair_blond_medium", "fg": 1739}, {"id": "overlay_male_mutation_hair_black_fro", "fg": 1742}, {"id": "overlay_female_mutation_hair_black_fro", "fg": 1741}, {"id": "overlay_male_mutation_hair_black_mohawk", "fg": 1743}, {"id": "overlay_female_mutation_hair_black_mohawk", "fg": 1744}, {"id": "overlay_male_mutation_hair_gray_mohawk", "fg": 1745}, {"id": "overlay_female_mutation_hair_gray_mohawk", "fg": 1746}, {"id": "overlay_male_mutation_hair_brown_long", "fg": 1748}, {"id": "overlay_female_mutation_hair_brown_long", "fg": 1747}, {"id": "overlay_male_mutation_hair_gray_short", "fg": 1750}, {"id": "overlay_female_mutation_hair_gray_short", "fg": 1749}, {"id": "overlay_male_mutation_hair_white_short", "fg": 1751}, {"id": "overlay_female_mutation_hair_white_short", "fg": 1752}, {"id": "overlay_male_mutation_hair_white_long", "fg": 1753}, {"id": "overlay_female_mutation_hair_white_long", "fg": 1754}, {"id": "overlay_male_mutation_hair_gray_long", "fg": 1756}, {"id": "overlay_female_mutation_hair_gray_long", "fg": 1755}, {"id": "overlay_male_mutation_hair_brown_short", "fg": 1757}, {"id": "overlay_female_mutation_hair_brown_short", "fg": 1758}, {"id": "overlay_male_mutation_hair_gray_crewcut", "fg": 1760}, {"id": "overlay_female_mutation_hair_gray_crewcut", "fg": 1759}, {"id": "overlay_male_mutation_hair_blond_crewcut", "fg": 1762}, {"id": "overlay_female_mutation_hair_blond_crewcut", "fg": 1761}, {"id": "overlay_male_mutation_hair_black_short", "fg": 1763}, {"id": "overlay_female_mutation_hair_black_short", "fg": 1764}, {"id": "overlay_male_mutation_hair_blond_mohawk", "fg": 1766}, {"id": "overlay_female_mutation_hair_blond_mohawk", "fg": 1765}, {"id": "overlay_male_mutation_hair_black_long", "fg": 1768}, {"id": "overlay_female_mutation_hair_black_long", "fg": 1767}, {"id": "overlay_male_mutation_hair_blond_fro", "fg": 1769}, {"id": "overlay_female_mutation_hair_blond_fro", "fg": 1770}, {"id": "overlay_male_mutation_hair_blond_long", "fg": 1772}, {"id": "overlay_female_mutation_hair_blond_long", "fg": 1771}, {"id": "overlay_male_mutation_hair_gray_fro", "fg": 1774}, {"id": "overlay_female_mutation_hair_gray_fro", "fg": 1773}, {"id": "overlay_male_mutation_hair_red_short", "fg": 1776}, {"id": "overlay_female_mutation_hair_red_short", "fg": 1775}, {"id": "overlay_male_mutation_hair_red_long", "fg": 1778}, {"id": "overlay_female_mutation_hair_red_long", "fg": 1777}, {"id": "overlay_male_mutation_hair_white_fro", "fg": 1779}, {"id": "overlay_female_mutation_hair_white_fro", "fg": 1780}, {"id": "overlay_female_mutation_SKIN_LIGHT", "fg": 1782, "bg": 2179}, {"id": "overlay_male_mutation_SKIN_LIGHT", "fg": 1781, "bg": 2179}, {"id": "overlay_female_mutation_SKIN_DARK", "fg": 1784, "bg": 2179}, {"id": "overlay_male_mutation_SKIN_DARK", "fg": 1783, "bg": 2179}, {"id": "overlay_female_mutation_SKIN_TAN", "fg": 1786, "bg": 2179}, {"id": "overlay_male_mutation_SKIN_TAN", "fg": 1785, "bg": 2179}, {"id": "overlay_male_mutation_SKIN_PINK", "fg": 1788, "bg": 2179}, {"id": "overlay_female_mutation_SKIN_PINK", "fg": 1787, "bg": 2179}, {"id": "overlay_male_mutation_SKIN_MEDIUM", "fg": 1789, "bg": 2179}, {"id": "overlay_female_mutation_SKIN_MEDIUM", "fg": 1790, "bg": 2179}, {"id": "overlay_wielded_bag_canvas", "fg": 1791}, {"id": "overlay_female_wielded_wood_panel", "fg": 1793}, {"id": "overlay_male_wielded_wood_panel", "fg": 1792}, {"id": "overlay_wielded_jar_glass", "fg": 1794}, {"id": "overlay_female_wielded_rifle_flintlock", "fg": 1796}, {"id": "overlay_male_wielded_rifle_flintlock", "fg": 1795}, {"id": "overlay_female_wielded_bat_metal", "fg": 1798}, {"id": "overlay_male_wielded_bat_metal", "fg": 1797}, {"id": "overlay_male_wielded_pointy_stick", "fg": 1799}, {"id": "overlay_female_wielded_pointy_stick", "fg": 1804}, {"id": "overlay_male_wielded_spear_wood", "fg": 1814}, {"id": "overlay_female_wielded_spear_wood", "fg": 1813}, {"id": "overlay_male_wielded_spear_spike", "fg": 1808}, {"id": "overlay_female_wielded_spear_spike", "fg": 1815}, {"id": "overlay_male_wielded_spear_knife", "fg": 1811}, {"id": "overlay_female_wielded_spear_knife", "fg": 1812}, {"id": "overlay_male_wielded_spear_knife_superior", "fg": 1801}, {"id": "overlay_female_wielded_spear_knife_superior", "fg": 1816}, {"id": "overlay_male_wielded_spear_rebar", "fg": 1806}, {"id": "overlay_female_wielded_spear_rebar", "fg": 1810}, {"id": "overlay_male_wielded_spear_pipe", "fg": 1807}, {"id": "overlay_female_wielded_spear_pipe", "fg": 1802}, {"id": "overlay_male_wielded_spear_steel", "fg": 1803}, {"id": "overlay_female_wielded_spear_steel", "fg": 1800}, {"id": "overlay_male_wielded_spear_copper", "fg": 1805}, {"id": "overlay_female_wielded_spear_copper", "fg": 1809}, {"id": "overlay_wielded_flashlight", "fg": 1818}, {"id": "overlay_wielded_heavy_flashlight", "fg": 1817}, {"id": "overlay_wielded_jug_plastic", "fg": 1819}, {"id": "overlay_female_wielded_pot", "fg": 1821}, {"id": "overlay_male_wielded_pot", "fg": 1820}, {"id": "overlay_wielded_fire_ax", "fg": 1822}, {"id": "overlay_wielded_ax", "fg": 1823}, {"id": "overlay_wielded_hatchet", "fg": 1824}, {"id": "overlay_wielded_bottle_glass", "fg": 1825}, {"id": "overlay_female_wielded_rag", "fg": 1826}, {"id": "overlay_male_wielded_rag", "fg": 1827}, {"id": "overlay_female_wielded_corpse_generic_human", "fg": 1828}, {"id": "overlay_male_wielded_corpse_generic_human", "fg": 1829}, {"id": "overlay_male_wielded_chainsaw_off", "fg": 1830}, {"id": "overlay_female_wielded_chainsaw_off", "fg": 1831}, {"id": "overlay_female_wielded_teapot", "fg": 1833}, {"id": "overlay_male_wielded_teapot", "fg": 1832}, {"id": "overlay_male_wielded_1st_aid", "fg": 1834}, {"id": "overlay_female_wielded_1st_aid", "fg": 1835}, {"id": "overlay_female_wielded_nailbat", "fg": 1836}, {"id": "overlay_male_wielded_nailbat", "fg": 1837}, {"id": "overlay_male_wielded_primitive_hammer", "fg": 1838}, {"id": "overlay_female_wielded_primitive_hammer", "fg": 1839}, {"id": "overlay_wielded_steel_lump", "fg": 1840}, {"id": "overlay_wielded_antibiotics", "fg": 1841}, {"id": "overlay_wielded_weak_antibiotic", "fg": 1853}, {"id": "overlay_wielded_strong_antibiotic", "fg": 1848}, {"id": "overlay_wielded_calcium_tablet", "fg": 1843}, {"id": "overlay_wielded_vitamins", "fg": 1851}, {"id": "overlay_wielded_gummy_vitamins", "fg": 1842}, {"id": "overlay_wielded_antifungal", "fg": 1849}, {"id": "overlay_wielded_antiparasitic", "fg": 1846}, {"id": "overlay_wielded_iodine", "fg": 1852}, {"id": "overlay_wielded_prussian_blue", "fg": 1850}, {"id": "overlay_wielded_tramadol", "fg": 1845}, {"id": "overlay_wielded_codeine", "fg": 1844}, {"id": "overlay_wielded_oxycodone", "fg": 1847}, {"id": "overlay_wielded_rebar", "fg": 1854}, {"id": "overlay_wielded_steel_glass_shard", "fg": 1855}, {"id": "overlay_male_wielded_pot_copper", "fg": 1857}, {"id": "overlay_female_wielded_pot_copper", "fg": 1856}, {"id": "overlay_female_wielded_nailboard", "fg": 1858}, {"id": "overlay_male_wielded_nailboard", "fg": 1859}, {"id": "overlay_wielded_scissors", "fg": 1860}, {"id": "overlay_female_wielded_ak74", "fg": 1862}, {"id": "overlay_male_wielded_ak74", "fg": 1861}, {"id": "overlay_wielded_coffeemaker", "fg": 1863}, {"id": "overlay_male_wielded_thermos", "fg": 1865}, {"id": "overlay_female_wielded_thermos", "fg": 1864}, {"id": "overlay_female_wielded_stick", "fg": 1866}, {"id": "overlay_male_wielded_stick", "fg": 1867}, {"id": "overlay_wielded_steel_chunk", "fg": 1868}, {"id": "overlay_wielded_pipe", "fg": 1869}, {"id": "overlay_wielded_bottle_plastic", "fg": 1870}, {"id": "overlay_wielded_broom", "fg": 1871}, {"id": "overlay_wielded_sw_619", "fg": 1872}, {"id": "overlay_wielded_rolling_pin", "fg": 1873}, {"id": "overlay_wielded_makeshift_crowbar", "fg": 1874}, {"id": "overlay_female_wielded_bat", "fg": 1876}, {"id": "overlay_male_wielded_bat", "fg": 1875}, {"id": "overlay_male_wielded_wood_sheet", "fg": 1877}, {"id": "overlay_female_wielded_wood_sheet", "fg": 1878}, {"id": "overlay_wielded_jar_3l_glass_sealed", "fg": 1879}, {"id": "overlay_wielded_box_large", "fg": 1880}, {"id": "overlay_wielded_crowbar", "fg": 1884}, {"id": "overlay_male_wielded_screwdriver", "fg": 1885}, {"id": "overlay_female_wielded_screwdriver", "fg": 1881}, {"id": "overlay_wielded_shovel", "fg": 1886}, {"id": "overlay_wielded_wrench", "fg": 1882}, {"id": "overlay_wielded_hammer", "fg": 1883}, {"id": "overlay_wielded_arming_sword", "fg": 1887}, {"id": "overlay_wielded_brick", "fg": 1888}, {"id": "overlay_male_wielded_2x4", "fg": 1889}, {"id": "overlay_female_wielded_2x4", "fg": 1890}, {"id": "overlay_wielded_katana", "fg": 1891}, {"id": "overlay_wielded_bottle_plastic_small", "fg": 1892}, {"id": "overlay_wielded_sharp_rock", "fg": 1893}, {"id": ["overlay_wielded_glock_17", "overlay_wielded_glock_19", "overlay_wielded_glock_18c", "overlay_wielded_glock_22", "overlay_wielded_glock_31"], "fg": 1894}, {"id": "overlay_wielded_box_small", "fg": 1895}, {"id": "overlay_male_wielded_pillow", "fg": 1897}, {"id": "overlay_female_wielded_pillow", "fg": 1898}, {"id": "overlay_male_wielded_down_pillow", "fg": 1899}, {"id": "overlay_female_wielded_down_pillow", "fg": 1896}, {"id": "overlay_wielded_mop", "fg": 1900}, {"id": ["overlay_wielded_corpse_mon_ant", "overlay_wielded_corpse_mon_ant_soldier", "overlay_wielded_corpse_mon_ant_queen"], "fg": 1902}, {"id": ["overlay_wielded_corpse_mon_ant_acid", "overlay_wielded_corpse_mon_ant_acid_soldier", "overlay_wielded_corpse_mon_ant_acid_queen"], "fg": 1904}, {"id": ["overlay_male_wielded_corpse_mon_zombie", "overlay_male_wielded_corpse_mon_zombie_grappler", "overlay_male_wielded_corpse_mon_zombie_biter", "overlay_male_wielded_corpse_mon_zombie_tough", "overlay_male_wielded_corpse_mon_zombie_hunter", "overlay_male_wielded_corpse_mon_zombie_brute", "overlay_male_wielded_corpse_mon_zombie_predator", "overlay_male_wielded_corpse_mon_zombie_necro", "overlay_male_wielded_corpse_mon_zombie_thorny", "overlay_male_wielded_corpse_mon_zombie_smoker", "overlay_male_wielded_corpse_mon_zombie_shady", "overlay_male_wielded_corpse_mon_zombie_master", "overlay_male_wielded_corpse_mon_zombie_acidic", "overlay_male_wielded_corpse_mon_zombie_fat", "overlay_male_wielded_corpse_mon_zombie_corrosive", "overlay_male_wielded_corpse_mon_zombie_screecher", "overlay_male_wielded_corpse_mon_zombie_scientist", "overlay_male_wielded_corpse_mon_zombie_runner", "overlay_male_wielded_corpse_mon_zombie_spitter", "overlay_male_wielded_corpse_mon_zombie_labsecurity", "overlay_male_wielded_corpse_mon_zombie_child", "overlay_male_wielded_corpse_mon_zombie_hulk", "overlay_male_wielded_corpse_mon_zombie_brute_grappler", "overlay_male_wielded_corpse_mon_zombie_brute_ninja", "overlay_male_wielded_corpse_mon_zombie_kevlar_2", "overlay_male_wielded_corpse_mon_zombie_kevlar_1", "overlay_male_wielded_corpse_mon_zombie_hazmat", "overlay_male_wielded_corpse_mon_zombie_electric", "overlay_male_wielded_corpse_mon_zombie_technician", "overlay_male_wielded_corpse_mon_zombie_fungus", "overlay_male_wielded_corpse_mon_zombie_cop", "overlay_male_wielded_corpse_mon_zombie_child_fungus", "overlay_male_wielded_corpse_mon_zombie_swimmer", "overlay_male_wielded_corpse_mon_zombie_mancroc", "overlay_male_wielded_corpse_mon_zombie_soldier", "overlay_male_wielded_corpse_mon_zombie_skull", "overlay_male_wielded_corpse_mon_zombie_brainless", "overlay_male_wielded_corpse_mon_zombie_survivor", "overlay_male_wielded_corpse_mon_zombie_brute_shocker", "overlay_male_wielded_corpse_mon_zombie_soldier_acid_1", "overlay_male_wielded_corpse_mon_zombie_soldier_blackops_2", "overlay_male_wielded_corpse_mon_zombie_soldier_blackops_1", "overlay_male_wielded_corpse_mon_zombie_soldier_acid_2", "overlay_male_wielded_corpse_mon_zombie_shriekling", "overlay_male_wielded_corpse_mon_zombie_ears", "overlay_male_wielded_corpse_mon_zombie_nullfield", "overlay_male_wielded_corpse_mon_zombie_waif", "overlay_male_wielded_corpse_mon_zombie_sproglodyte", "overlay_male_wielded_corpse_mon_zombie_creepy", "overlay_male_wielded_corpse_mon_zombie_anklebiter", "overlay_male_wielded_corpse_mon_zombie_bio_op", "overlay_male_wielded_corpse_mon_zombie_armored", "overlay_male_wielded_corpse_mon_zombie_prisoner", "overlay_male_wielded_corpse_mon_zombie_military_pilot"], "fg": 1901}, {"id": ["overlay_female_wielded_corpse_mon_zombie", "overlay_female_wielded_corpse_mon_zombie_grappler", "overlay_female_wielded_corpse_mon_zombie_biter", "overlay_female_wielded_corpse_mon_zombie_tough", "overlay_female_wielded_corpse_mon_zombie_hunter", "overlay_female_wielded_corpse_mon_zombie_brute", "overlay_female_wielded_corpse_mon_zombie_predator", "overlay_female_wielded_corpse_mon_zombie_necro", "overlay_female_wielded_corpse_mon_zombie_thorny", "overlay_female_wielded_corpse_mon_zombie_smoker", "overlay_female_wielded_corpse_mon_zombie_shady", "overlay_female_wielded_corpse_mon_zombie_master", "overlay_female_wielded_corpse_mon_zombie_acidic", "overlay_female_wielded_corpse_mon_zombie_fat", "overlay_female_wielded_corpse_mon_zombie_corrosive", "overlay_female_wielded_corpse_mon_zombie_screecher", "overlay_female_wielded_corpse_mon_zombie_scientist", "overlay_female_wielded_corpse_mon_zombie_runner", "overlay_female_wielded_corpse_mon_zombie_spitter", "overlay_female_wielded_corpse_mon_zombie_labsecurity", "overlay_female_wielded_corpse_mon_zombie_child", "overlay_female_wielded_corpse_mon_zombie_hulk", "overlay_female_wielded_corpse_mon_zombie_brute_grappler", "overlay_female_wielded_corpse_mon_zombie_brute_ninja", "overlay_female_wielded_corpse_mon_zombie_kevlar_2", "overlay_female_wielded_corpse_mon_zombie_kevlar_1", "overlay_female_wielded_corpse_mon_zombie_hazmat", "overlay_female_wielded_corpse_mon_zombie_electric", "overlay_female_wielded_corpse_mon_zombie_technician", "overlay_female_wielded_corpse_mon_zombie_fungus", "overlay_female_wielded_corpse_mon_zombie_cop", "overlay_female_wielded_corpse_mon_zombie_child_fungus", "overlay_female_wielded_corpse_mon_zombie_swimmer", "overlay_female_wielded_corpse_mon_zombie_mancroc", "overlay_female_wielded_corpse_mon_zombie_soldier", "overlay_female_wielded_corpse_mon_zombie_skull", "overlay_female_wielded_corpse_mon_zombie_brainless", "overlay_female_wielded_corpse_mon_zombie_survivor", "overlay_female_wielded_corpse_mon_zombie_brute_shocker", "overlay_female_wielded_corpse_mon_zombie_soldier_acid_1", "overlay_female_wielded_corpse_mon_zombie_soldier_blackops_2", "overlay_female_wielded_corpse_mon_zombie_soldier_blackops_1", "overlay_female_wielded_corpse_mon_zombie_soldier_acid_2", "overlay_female_wielded_corpse_mon_zombie_shriekling", "overlay_female_wielded_corpse_mon_zombie_ears", "overlay_female_wielded_corpse_mon_zombie_nullfield", "overlay_female_wielded_corpse_mon_zombie_waif", "overlay_female_wielded_corpse_mon_zombie_sproglodyte", "overlay_female_wielded_corpse_mon_zombie_creepy", "overlay_female_wielded_corpse_mon_zombie_anklebiter", "overlay_female_wielded_corpse_mon_zombie_bio_op", "overlay_female_wielded_corpse_mon_zombie_armored", "overlay_female_wielded_corpse_mon_zombie_prisoner", "overlay_female_wielded_corpse_mon_zombie_military_pilot"], "fg": 1903}, {"id": "overlay_wielded_box_medium", "fg": 1905}, {"id": "overlay_wielded_rock", "fg": 1906}, {"id": "overlay_female_wielded_stick_long", "fg": 1907}, {"id": "overlay_male_wielded_stick_long", "fg": 1908}, {"id": "overlay_wielded_log", "fg": 1909}, {"id": "overlay_female_wielded_television", "fg": 1911}, {"id": "overlay_male_wielded_television", "fg": 1910}, {"id": "overlay_wielded_jar_glass_sealed", "fg": 1912}, {"id": "overlay_wielded_jar_3l_glass", "fg": 1913}, {"id": "overlay_female_wielded_bwirebat", "fg": 1914}, {"id": "overlay_male_wielded_bwirebat", "fg": 1915}, {"id": "overlay_wielded_bag_plastic", "fg": 1916}, {"id": "overlay_female_wielded_splinter", "fg": 1918}, {"id": "overlay_male_wielded_splinter", "fg": 1917}, {"id": "overlay_wielded_ar15", "fg": 1919}, {"id": "overlay_female_worn_pants_army", "fg": 1921}, {"id": "overlay_male_worn_pants_army", "fg": 1920}, {"id": "overlay_female_worn_hat_noise_cancelling", "fg": 1923}, {"id": "overlay_male_worn_hat_noise_cancelling", "fg": 1922}, {"id": "overlay_female_worn_striped_pants", "fg": 1924}, {"id": "overlay_male_worn_striped_pants", "fg": 1925}, {"id": "overlay_female_worn_motorbike_pants", "fg": 1927}, {"id": "overlay_male_worn_motorbike_pants", "fg": 1926}, {"id": "overlay_female_worn_beekeeping_hood", "fg": 1928}, {"id": "overlay_male_worn_beekeeping_hood", "fg": 1929}, {"id": "overlay_male_worn_ski_jacket", "fg": 1931}, {"id": "overlay_female_worn_ski_jacket", "fg": 1930}, {"id": "overlay_female_worn_boots_bunker", "fg": 1932}, {"id": "overlay_male_worn_boots_bunker", "fg": 1933}, {"id": "overlay_male_worn_leg_warmers", "fg": 1935}, {"id": "overlay_female_worn_leg_warmers", "fg": 1934}, {"id": "overlay_worn_dress_shoes", "fg": 1936}, {"id": "overlay_male_worn_glasses_bifocal", "fg": 1938}, {"id": "overlay_female_worn_glasses_bifocal", "fg": 1937}, {"id": "overlay_female_worn_glasses_safety", "fg": 1940}, {"id": "overlay_male_worn_glasses_safety", "fg": 1939}, {"id": "overlay_female_worn_ragpouch", "fg": 1941}, {"id": "overlay_male_worn_ragpouch", "fg": 1942}, {"id": "overlay_female_worn_welding_mask_crude_raised", "fg": 1943}, {"id": "overlay_male_worn_welding_mask_crude_raised", "fg": 1944}, {"id": "overlay_male_worn_gloves_leather", "fg": 1946}, {"id": "overlay_female_worn_gloves_leather", "fg": 1945}, {"id": "overlay_female_worn_helmet_army", "fg": 1947}, {"id": "overlay_male_worn_helmet_army", "fg": 1948}, {"id": "overlay_female_worn_pants_faux_fur", "fg": 1949}, {"id": "overlay_male_worn_pants_faux_fur", "fg": 1950}, {"id": "overlay_male_worn_long_glove_white", "fg": 1952}, {"id": "overlay_female_worn_long_glove_white", "fg": 1951}, {"id": "overlay_female_worn_jacket_army", "fg": 1953}, {"id": "overlay_male_worn_jacket_army", "fg": 1954}, {"id": "overlay_female_worn_pants_cargo", "fg": 1955}, {"id": "overlay_male_worn_pants_cargo", "fg": 1956}, {"id": "overlay_female_worn_gloves_work", "fg": 1957}, {"id": "overlay_male_worn_gloves_work", "fg": 1958}, {"id": "overlay_female_worn_geta", "fg": 1959}, {"id": "overlay_male_worn_geta", "fg": 1960}, {"id": "overlay_male_worn_hat_fur", "fg": 1961}, {"id": "overlay_female_worn_hat_fur", "fg": 1962}, {"id": "overlay_female_worn_gloves_wool", "fg": 1964}, {"id": "overlay_male_worn_gloves_wool", "fg": 1963}, {"id": "overlay_male_worn_arm_warmers", "fg": 1965}, {"id": "overlay_female_worn_arm_warmers", "fg": 1966}, {"id": "overlay_female_worn_beret", "fg": 1968}, {"id": "overlay_male_worn_beret", "fg": 1967}, {"id": "overlay_female_worn_boxer_briefs", "fg": 1969}, {"id": "overlay_male_worn_boxer_briefs", "fg": 1970}, {"id": "overlay_male_worn_touring_suit", "fg": 1972}, {"id": "overlay_female_worn_touring_suit", "fg": 1971}, {"id": "overlay_female_worn_pants_checkered", "fg": 1974}, {"id": "overlay_male_worn_pants_checkered", "fg": 1973}, {"id": "overlay_male_worn_turban", "fg": 1975}, {"id": "overlay_female_worn_turban", "fg": 1976}, {"id": "overlay_female_worn_pants_ski", "fg": 1978}, {"id": "overlay_male_worn_pants_ski", "fg": 1977}, {"id": "overlay_female_worn_glasses_bal", "fg": 1979}, {"id": "overlay_male_worn_glasses_bal", "fg": 1980}, {"id": "overlay_male_worn_boots", "fg": 1981}, {"id": "overlay_female_worn_boots", "fg": 1982}, {"id": "overlay_female_worn_corset", "fg": 1984}, {"id": "overlay_male_worn_corset", "fg": 1983}, {"id": "overlay_female_worn_welding_mask", "fg": 1985}, {"id": "overlay_male_worn_welding_mask", "fg": 1986}, {"id": "overlay_female_worn_jacket_flannel", "fg": 1987}, {"id": "overlay_male_worn_jacket_flannel", "fg": 1988}, {"id": "overlay_male_worn_shorts", "fg": 1990}, {"id": "overlay_female_worn_shorts", "fg": 1989}, {"id": "overlay_female_worn_dinosuit", "fg": 1992}, {"id": "overlay_male_worn_dinosuit", "fg": 1991}, {"id": "overlay_male_worn_undershirt", "fg": 1993}, {"id": "overlay_female_worn_boots_combat", "fg": 1994}, {"id": "overlay_male_worn_boots_combat", "fg": 1995}, {"id": "overlay_female_worn_stockings", "fg": 1996}, {"id": "overlay_male_worn_stockings", "fg": 1997}, {"id": "overlay_male_worn_skirt_leather", "fg": 1999}, {"id": "overlay_female_worn_skirt_leather", "fg": 1998}, {"id": "overlay_female_worn_boots_rubber", "fg": 2001}, {"id": "overlay_male_worn_boots_rubber", "fg": 2000}, {"id": "overlay_female_worn_dress_shirt", "fg": 2002}, {"id": "overlay_male_worn_dress_shirt", "fg": 2003}, {"id": "overlay_female_worn_gloves_golf", "fg": 2005}, {"id": "overlay_male_worn_gloves_golf", "fg": 2004}, {"id": "overlay_female_worn_army_top", "fg": 2006}, {"id": "overlay_male_worn_army_top", "fg": 2007}, {"id": "overlay_female_worn_boxer_shorts", "fg": 2009}, {"id": "overlay_male_worn_boxer_shorts", "fg": 2008}, {"id": "overlay_female_worn_helmet_kabuto", "fg": 2010}, {"id": "overlay_male_worn_helmet_kabuto", "fg": 2011}, {"id": "overlay_male_worn_shoes_bowling", "fg": 2012}, {"id": "overlay_female_worn_shoes_bowling", "fg": 2013}, {"id": "overlay_female_worn_gloves_medical", "fg": 2014}, {"id": "overlay_male_worn_gloves_medical", "fg": 2015}, {"id": "overlay_worn_jacket_jean", "fg": 2016}, {"id": "overlay_female_worn_boots_fur", "fg": 2017}, {"id": "overlay_male_worn_boots_fur", "fg": 2018}, {"id": "overlay_male_worn_blanket", "fg": 2021}, {"id": "overlay_female_worn_blanket", "fg": 2020}, {"id": "overlay_male_worn_down_blanket", "fg": 2019}, {"id": "overlay_female_worn_down_blanket", "fg": 2022}, {"id": "overlay_male_worn_cargo_pants", "fg": 2023}, {"id": "overlay_female_worn_panties", "fg": 2024}, {"id": "overlay_male_worn_panties", "fg": 2025}, {"id": "overlay_female_worn_hat_hard", "fg": 2026}, {"id": "overlay_male_worn_hat_hard", "fg": 2027}, {"id": "overlay_male_worn_glasses_eye", "fg": 2029}, {"id": "overlay_female_worn_glasses_eye", "fg": 2028}, {"id": "overlay_female_worn_helmet_chitin", "fg": 2031}, {"id": "overlay_male_worn_helmet_chitin", "fg": 2030}, {"id": "overlay_female_worn_boy_shorts", "fg": 2032}, {"id": "overlay_male_worn_boy_shorts", "fg": 2033}, {"id": "overlay_male_worn_sweatshirt", "fg": 2034}, {"id": "overlay_female_worn_sweatshirt", "fg": 2035}, {"id": "overlay_male_worn_rucksack", "fg": 2037}, {"id": "overlay_female_worn_rucksack", "fg": 2036}, {"id": "overlay_female_worn_sunglasses", "fg": 2039}, {"id": "overlay_male_worn_sunglasses", "fg": 2038}, {"id": "overlay_female_worn_mask_dust", "fg": 2040}, {"id": "overlay_male_worn_mask_dust", "fg": 2041}, {"id": "overlay_male_worn_helmet_motor", "fg": 2043}, {"id": "overlay_female_worn_helmet_motor", "fg": 2042}, {"id": "overlay_female_worn_sweater", "fg": 2044}, {"id": "overlay_male_worn_sweater", "fg": 2045}, {"id": "overlay_female_worn_jacket_light", "fg": 2046}, {"id": "overlay_male_worn_jacket_light", "fg": 2047}, {"id": "overlay_male_worn_skirt", "fg": 2049}, {"id": "overlay_female_worn_skirt", "fg": 2048}, {"id": "overlay_female_worn_striped_shirt", "fg": 2051}, {"id": "overlay_male_worn_striped_shirt", "fg": 2050}, {"id": "overlay_female_worn_hat_ball", "fg": 2053}, {"id": "overlay_male_worn_hat_ball", "fg": 2052}, {"id": "overlay_male_worn_bra", "fg": 2055}, {"id": "overlay_female_worn_bra", "fg": 2054}, {"id": "overlay_male_worn_glove_jackson", "fg": 2057}, {"id": "overlay_female_worn_glove_jackson", "fg": 2056}, {"id": "overlay_male_worn_boots_western", "fg": 2058}, {"id": "overlay_female_worn_boots_western", "fg": 2059}, {"id": "overlay_female_worn_hazmat_suit", "fg": 2060}, {"id": "overlay_male_worn_hazmat_suit", "fg": 2061}, {"id": "overlay_female_worn_scarf", "fg": 2063}, {"id": "overlay_male_worn_scarf", "fg": 2062}, {"id": "overlay_male_worn_kevlar", "fg": 2065}, {"id": "overlay_female_worn_kevlar", "fg": 2064}, {"id": "overlay_female_worn_backpack_leather", "fg": 2066}, {"id": "overlay_male_worn_backpack_leather", "fg": 2067}, {"id": "overlay_female_worn_armor_samurai", "fg": 2069}, {"id": "overlay_male_worn_armor_samurai", "fg": 2068}, {"id": "overlay_female_worn_jumpsuit", "fg": 2071}, {"id": "overlay_male_worn_jumpsuit", "fg": 2070}, {"id": "overlay_female_worn_jeans", "fg": 2072}, {"id": "overlay_male_worn_jeans", "fg": 2073}, {"id": "overlay_female_worn_boots_winter", "fg": 2075}, {"id": "overlay_male_worn_boots_winter", "fg": 2074}, {"id": "overlay_female_worn_shorts_denim", "fg": 2076}, {"id": "overlay_male_worn_shorts_denim", "fg": 2077}, {"id": "overlay_female_worn_gloves_rubber", "fg": 2079}, {"id": "overlay_male_worn_gloves_rubber", "fg": 2078}, {"id": "overlay_male_worn_hat_cotton", "fg": 2080}, {"id": "overlay_female_worn_hat_cotton", "fg": 2081}, {"id": "overlay_male_worn_robofac_jumpsuit", "fg": 2083}, {"id": "overlay_female_worn_robofac_jumpsuit", "fg": 2082}, {"id": "overlay_female_worn_gloves_liner", "fg": 2084}, {"id": "overlay_male_worn_gloves_liner", "fg": 2085}, {"id": "overlay_female_worn_shorts_cargo", "fg": 2087}, {"id": "overlay_male_worn_shorts_cargo", "fg": 2086}, {"id": "overlay_female_worn_coat_lab", "fg": 2089}, {"id": "overlay_male_worn_coat_lab", "fg": 2088}, {"id": "overlay_male_worn_tank_top", "fg": 2091}, {"id": "overlay_female_worn_tank_top", "fg": 2090}, {"id": "overlay_male_worn_socks", "fg": 2093}, {"id": "overlay_female_worn_socks", "fg": 2092}, {"id": "overlay_female_worn_sports_bra", "fg": 2094}, {"id": "overlay_male_worn_sports_bra", "fg": 2095}, {"id": "overlay_male_worn_bunker_coat", "fg": 2097}, {"id": "overlay_female_worn_bunker_coat", "fg": 2096}, {"id": "overlay_female_worn_gloves_winter", "fg": 2098}, {"id": "overlay_male_worn_gloves_winter", "fg": 2099}, {"id": "overlay_female_worn_mittens", "fg": 2101}, {"id": "overlay_male_worn_mittens", "fg": 2100}, {"id": "overlay_female_worn_glasses_reading", "fg": 2103}, {"id": "overlay_male_worn_glasses_reading", "fg": 2102}, {"id": "overlay_female_worn_longshirt", "fg": 2105}, {"id": "overlay_male_worn_longshirt", "fg": 2104}, {"id": "overlay_female_worn_gloves_cut_resistant", "fg": 2106}, {"id": "overlay_male_worn_gloves_cut_resistant", "fg": 2107}, {"id": "overlay_female_worn_pants", "fg": 2109}, {"id": "overlay_male_worn_pants", "fg": 2108}, {"id": "overlay_female_worn_maid_hat", "fg": 2112}, {"id": "overlay_female_worn_maid_dress", "fg": 2111}, {"id": "overlay_male_worn_maid_hat", "fg": 2110}, {"id": "overlay_male_worn_maid_dress", "fg": 2113}, {"id": "overlay_male_worn_bunker_pants", "fg": 2114}, {"id": "overlay_female_worn_bunker_pants", "fg": 2115}, {"id": "overlay_female_worn_helmet_bike", "fg": 2116}, {"id": "overlay_male_worn_helmet_bike", "fg": 2117}, {"id": "overlay_female_worn_pants_leather", "fg": 2118}, {"id": "overlay_male_worn_pants_leather", "fg": 2119}, {"id": "overlay_male_worn_boots_steel", "fg": 2121}, {"id": "overlay_female_worn_boots_steel", "fg": 2120}, {"id": "overlay_female_worn_survivor_suit", "fg": 2123}, {"id": "overlay_male_worn_survivor_suit", "fg": 2122}, {"id": "overlay_female_worn_pants_fur", "fg": 2124}, {"id": "overlay_male_worn_pants_fur", "fg": 2125}, {"id": "overlay_female_worn_gloves_fingerless", "fg": 2127}, {"id": "overlay_male_worn_gloves_fingerless", "fg": 2126}, {"id": "overlay_female_worn_union_suit", "fg": 2128}, {"id": "overlay_male_worn_union_suit", "fg": 2129}, {"id": "overlay_female_worn_sneakers", "fg": 2130}, {"id": "overlay_male_worn_sneakers", "fg": 2131}, {"id": "overlay_male_worn_flip_flops", "fg": 2133}, {"id": "overlay_female_worn_flip_flops", "fg": 2132}, {"id": "overlay_male_worn_tshirt", "fg": 2135}, {"id": "overlay_female_worn_tshirt", "fg": 2134}, {"id": "overlay_female_worn_boots_hiking", "fg": 2136}, {"id": "overlay_male_worn_boots_hiking", "fg": 2137}, {"id": "overlay_female_worn_gloves_fur", "fg": 2139}, {"id": "overlay_male_worn_gloves_fur", "fg": 2138}, {"id": "overlay_male_worn_firehelmet", "fg": 2141}, {"id": "overlay_female_worn_firehelmet", "fg": 2140}, {"id": "overlay_female_worn_welding_mask_raised", "fg": 2143}, {"id": "overlay_male_worn_welding_mask_raised", "fg": 2142}, {"id": "overlay_female_worn_bandana", "fg": 2144}, {"id": "overlay_male_worn_bandana", "fg": 2145}, {"id": "overlay_male_worn_hat_knit", "fg": 2147}, {"id": "overlay_female_worn_hat_knit", "fg": 2146}, {"id": "overlay_female_worn_hoodie", "fg": 2149}, {"id": "overlay_male_worn_hoodie", "fg": 2148}, {"id": "overlay_male_worn_coat_winter", "fg": 2150}, {"id": "overlay_female_worn_coat_winter", "fg": 2151}, {"id": "overlay_female_worn_duster", "fg": 2152}, {"id": "overlay_male_worn_duster", "fg": 2153}, {"id": "overlay_female_worn_glasses_monocle", "fg": 2154}, {"id": "overlay_male_worn_glasses_monocle", "fg": 2155}, {"id": "overlay_male_worn_welding_mask_crude", "fg": 2157}, {"id": "overlay_female_worn_welding_mask_crude", "fg": 2156}, {"id": "overlay_male_worn_balclava", "fg": 2159}, {"id": "overlay_female_worn_balclava", "fg": 2158}, {"id": "overlay_female_worn_motorbike_boots", "fg": 2161}, {"id": "overlay_male_worn_motorbike_boots", "fg": 2160}, {"id": "overlay_female_worn_helmet_barbute", "fg": 2162}, {"id": "overlay_male_worn_helmet_barbute", "fg": 2163}, {"id": "overlay_female_worn_gloves_tactical", "fg": 2165}, {"id": "overlay_male_worn_gloves_tactical", "fg": 2164}, {"id": "overlay_female_worn_jeans_red", "fg": 2167}, {"id": "overlay_male_worn_jeans_red", "fg": 2166}, {"id": "overlay_female_worn_cowboy_hat", "fg": 2168}, {"id": "overlay_male_worn_cowboy_hat", "fg": 2169}, {"id": "overlay_male_worn_sundress", "fg": 2171}, {"id": "overlay_female_worn_sundress", "fg": 2170}, {"id": "overlay_female_worn_coat_rain", "fg": 2172}, {"id": "overlay_male_worn_coat_rain", "fg": 2173}, {"id": "overlay_male_worn_gloves_light", "fg": 2175}, {"id": "overlay_female_worn_gloves_light", "fg": 2174}, {"id": "mon_skeleton", "fg": 2176, "bg": 2179}, {"id": "mon_dermatik", "fg": 2177, "bg": 2179}, {"id": "mon_zombie_brainless", "fg": 2178, "bg": 2179}, {"id": "mon_zombie_soldier", "fg": 2180, "bg": 2179}, {"id": "mon_fungaloid", "fg": 2181, "bg": 2179}, {"id": "mon_zougar", "fg": 2182, "bg": 2179}, {"id": "mon_bee", "fg": 2183, "bg": 2179}, {"id": "mon_zombie_swimmer", "fg": 2184, "bg": 2179}, {"id": "mon_mosquito_giant", "fg": 2185, "bg": 2179}, {"id": "mon_cougar", "fg": 2186, "bg": 2179}, {"id": "mon_dragonfly_giant", "fg": 2187, "bg": 2179}, {"id": "mon_fly", "fg": 2188, "bg": 2179}], "//": "range 1617 to 2192", "sprite_width": 32, "sprite_height": 64, "sprite_offset_x": 0, "sprite_offset_y": -32}, {"file": "large.png", "tiles": [{"id": "f_rotary_clothesline", "fg": 2193}, {"id": "f_fridge", "fg": 2194}, {"id": "t_tree_young", "fg": [{"weight": 100, "sprite": 2204}, {"weight": 100, "sprite": 2202}], "bg": 2195}, {"id": "t_tree_young_season_summer", "fg": [{"weight": 100, "sprite": 2200}, {"weight": 100, "sprite": 2201}], "bg": 2198, "rotates": false}, {"id": "t_tree_young_season_autumn", "fg": [{"weight": 100, "sprite": 2206}, {"weight": 100, "sprite": 2205}], "bg": 2197, "rotates": false}, {"id": "t_tree_young_season_winter", "fg": [{"weight": 100, "sprite": 2203}, {"weight": 100, "sprite": 2199}], "bg": 2196, "rotates": false}, {"id": "mon_zoose", "fg": 2207, "bg": 2233}, {"id": "mon_zombie_acidic", "fg": 2210, "bg": 2231}, {"id": "mon_zombie_corrosive", "fg": 2208, "bg": 2231}, {"id": "mon_zombie_spitter", "fg": 2211, "bg": 2231}, {"id": "corpse_mon_zombie_spitter", "fg": 2209}, {"id": "mon_moose", "fg": [{"weight": 2, "sprite": 2213}, {"weight": 2, "sprite": 2212}], "bg": 2233}, {"id": "mon_zombear", "fg": 2214, "bg": 2232}, {"id": "mon_zombie_grappler", "fg": [{"weight": 1, "sprite": 2216}, {"weight": 1, "sprite": 2215}], "bg": 2231}, {"id": "mon_boomer", "fg": 2217, "bg": 2231}, {"id": "mon_zombie", "fg": [{"weight": 100, "sprite": 2218}, {"weight": 150, "sprite": 2221}, {"weight": 100, "sprite": 2223}, {"weight": 100, "sprite": 2219}, {"weight": 150, "sprite": 2220}], "bg": 2231}, {"id": ["corpse_mon_zombie", "corpse_mon_zombie_grappler", "corpse_mon_zombie_biter", "corpse_mon_zombie_hunter", "corpse_mon_zombie_brute", "corpse_mon_zombie_predator", "corpse_mon_zombie_necro", "corpse_mon_zombie_thorny", "corpse_mon_zombie_smoker", "corpse_mon_zombie_shady", "corpse_mon_zombie_master", "corpse_mon_zombie_acidic", "corpse_mon_zombie_fat", "corpse_mon_zombie_corrosive", "corpse_mon_zombie_screecher", "corpse_mon_zombie_scientist", "corpse_mon_zombie_runner", "corpse_mon_zombie_labsecurity", "corpse_mon_zombie_child", "corpse_mon_zombie_hulk", "corpse_mon_zombie_brute_grappler", "corpse_mon_zombie_brute_ninja", "corpse_mon_zombie_kevlar_2", "corpse_mon_zombie_kevlar_1", "corpse_mon_zombie_hazmat", "corpse_mon_zombie_electric", "corpse_mon_zombie_technician", "corpse_mon_zombie_fungus", "corpse_mon_zombie_cop", "corpse_mon_zombie_child_fungus", "corpse_mon_zombie_swimmer", "corpse_mon_zombie_mancroc", "corpse_mon_zombie_soldier", "corpse_mon_zombie_skull", "corpse_mon_zombie_brainless", "corpse_mon_zombie_survivor", "corpse_mon_zombie_brute_shocker", "corpse_mon_zombie_soldier_acid_1", "corpse_mon_zombie_soldier_blackops_2", "corpse_mon_zombie_soldier_blackops_1", "corpse_mon_zombie_soldier_acid_2", "corpse_mon_zombie_shriekling", "corpse_mon_zombie_ears", "corpse_mon_zombie_nullfield", "corpse_mon_zombie_waif", "corpse_mon_zombie_sproglodyte", "corpse_mon_zombie_creepy", "corpse_mon_zombie_anklebiter", "corpse_mon_zombie_bio_op", "corpse_mon_zombie_armored", "corpse_mon_zombie_prisoner", "corpse_mon_zombie_military_pilot"], "fg": 2222}, {"id": "mon_zombie_smoker", "fg": 2224, "bg": 2231}, {"id": "mon_zombie_necro", "fg": 2225, "bg": 2231}, {"id": "mon_zombie_biter", "fg": 2226, "bg": 2232}, {"id": "mon_zombie_hunter", "fg": 2228, "bg": 2232}, {"id": "mon_zombie_cop", "fg": 2230, "bg": 2231}, {"id": "mon_zombie_labsecurity", "fg": 2229, "bg": 2231}, {"id": "mon_zombie_rot", "fg": 2234, "bg": 2231}, {"id": "mon_zombie_gasbag", "fg": [{"weight": 1, "sprite": 2236}, {"weight": 1, "sprite": 2235}], "bg": 2231}, {"id": "mon_blob_large", "fg": 2237, "bg": 2233}, {"id": "mon_ant_soldier", "fg": 2242, "bg": 2233}, {"id": "mon_ant_acid_soldier", "fg": 2245, "bg": 2233}, {"id": "corpse_mon_ant_soldier", "fg": 2243}, {"id": "corpse_mon_ant_acid_soldier", "fg": 2241}, {"id": "mon_ant_queen", "fg": 2239, "bg": 2233}, {"id": "mon_ant_acid_queen", "fg": 2238, "bg": 2233}, {"id": "corpse_mon_ant_queen", "fg": 2240}, {"id": "corpse_mon_ant_acid_queen", "fg": 2244}, {"id": "mon_zombie_shady", "fg": 2246, "bg": 2231}, {"id": "mon_zombie_crawler", "fg": 2247, "bg": 2231}, {"id": "mon_zombie_fat", "fg": [{"weight": 1, "sprite": 2248}, {"weight": 1, "sprite": 2249}], "bg": 2231}, {"id": "mon_zombie_tough", "fg": 2250, "bg": 2231}, {"id": "corpse_mon_zombie_tough", "fg": 2251}, {"id": "mon_zombie_electric", "fg": [{"weight": 1, "sprite": 2254}, {"weight": 1, "sprite": 2252}], "bg": 2231}, {"id": "mon_zombie_nullfield", "fg": [{"weight": 1, "sprite": 2253}, {"weight": 1, "sprite": 2255}], "bg": 2231}, {"id": "mon_zombie_scientist", "fg": [{"weight": 1, "sprite": 2257}, {"weight": 1, "sprite": 2256}], "bg": 2231}, {"id": "mon_wasp", "fg": 2258, "bg": 2232}, {"id": "mon_zombie_runner", "fg": 2259, "bg": 2231}, {"id": "mon_mi_go", "fg": 2260, "bg": 2232}, {"id": "mon_zombie_brute", "fg": [{"weight": 100, "sprite": 2261}, {"weight": 100, "sprite": 2262}, {"weight": 50, "sprite": 2264}, {"weight": 50, "sprite": 2263}], "bg": 2232}, {"id": "mon_bear", "fg": 2265, "bg": 2232}], "//": "range 2193 to 2272", "sprite_width": 64, "sprite_height": 64, "sprite_offset_x": -16, "sprite_offset_y": -32}, {"file": "huge.png", "tiles": [{"id": "mon_zombie_hulk", "fg": 2273}], "//": "range 2273 to 2288", "sprite_width": 64, "sprite_height": 96, "sprite_offset_x": -16, "sprite_offset_y": -64}, {"file": "giant.png", "tiles": [{"id": "t_tree", "fg": [{"weight": 100, "sprite": 2297}, {"weight": 100, "sprite": 2296}, {"weight": 100, "sprite": 2298}, {"weight": 100, "sprite": 2292}], "bg": 2302}, {"id": "t_tree_season_summer", "fg": [{"weight": 100, "sprite": 2290}, {"weight": 100, "sprite": 2295}, {"weight": 100, "sprite": 2291}, {"weight": 100, "sprite": 2289}], "bg": 2303}, {"id": "t_tree_season_autumn", "fg": [{"weight": 100, "sprite": 2300}, {"weight": 100, "sprite": 2294}, {"weight": 100, "sprite": 2293}, {"weight": 100, "sprite": 2299}], "bg": 2301}, {"id": "t_tree_season_winter", "fg": [{"weight": 100, "sprite": 2306}, {"weight": 100, "sprite": 2307}, {"weight": 100, "sprite": 2305}, {"weight": 100, "sprite": 2308}], "bg": 2304}, {"id": "t_tree_dead", "fg": [{"weight": 100, "sprite": 2306}, {"weight": 100, "sprite": 2307}, {"weight": 100, "sprite": 2305}, {"weight": 100, "sprite": 2308}, {"weight": 100, "sprite": 2611}], "bg": 2302}, {"id": "t_tree_dead_season_summer", "fg": [{"weight": 100, "sprite": 2306}, {"weight": 100, "sprite": 2307}, {"weight": 100, "sprite": 2305}, {"weight": 100, "sprite": 2308}, {"weight": 100, "sprite": 2611}], "bg": 2303}, {"id": "t_tree_dead_season_autumn", "fg": [{"weight": 100, "sprite": 2306}, {"weight": 100, "sprite": 2307}, {"weight": 100, "sprite": 2305}, {"weight": 100, "sprite": 2308}, {"weight": 100, "sprite": 2611}], "bg": 2301}, {"id": "t_tree_dead_season_winter", "fg": [{"weight": 100, "sprite": 2306}, {"weight": 100, "sprite": 2307}, {"weight": 100, "sprite": 2305}, {"weight": 100, "sprite": 2308}, {"weight": 100, "sprite": 2611}], "bg": 2304}, {"id": "t_tree_birch", "fg": [{"weight": 1, "sprite": 2313}, {"weight": 1, "sprite": 2310}], "bg": 2302}, {"id": "t_tree_birch_season_summer", "fg": [{"weight": 1, "sprite": 2313}, {"weight": 1, "sprite": 2310}], "bg": 2303}, {"id": "t_tree_birch_season_winter", "fg": [{"weight": 1, "sprite": 2314}, {"weight": 1, "sprite": 2311}], "bg": 2304}, {"id": "t_tree_birch_season_autumn", "fg": [{"weight": 1, "sprite": 2312}, {"weight": 1, "sprite": 2309}], "bg": 2301}], "//": "range 2289 to 2320", "sprite_width": 96, "sprite_height": 96, "sprite_offset_x": -32, "sprite_offset_y": -64}, {"file": "incomplete.png", "tiles": [{"id": "f_sink", "multitile": true, "fg": 2331, "additional_tiles": [{"id": "center", "fg": 2336}, {"id": "corner", "fg": [2322, 2334, 2326, 2321]}, {"id": "t_connection", "fg": [2328, 2335, 2330, 2325]}, {"id": "edge", "fg": [2329, 2327]}, {"id": "end_piece", "fg": [2333, 2324, 2323, 2332]}, {"id": "unconnected", "fg": 2331}]}, {"id": "toolbox", "fg": 2337}, {"id": "acoustic_guitar", "fg": 2338}, {"id": "rope_6", "fg": 2339}, {"id": "colt_army", "fg": 2340}, {"id": "ref_lighter", "fg": 2341}, {"id": "soap", "fg": 2342}, {"id": "waffleiron", "fg": 2343}, {"id": "bubblewrap", "fg": 2344}, {"id": "soldering_iron", "fg": 2345}, {"id": "stepladder", "fg": 2346}, {"id": "mag_pistol", "fg": 2347}, {"id": "brazier", "fg": 2348}, {"id": "pliers", "fg": 2349}, {"id": "spray_can", "fg": 2350}, {"id": "condom", "fg": 2351}, {"id": "colt_navy", "fg": 2352}, {"id": "hotplate", "fg": 2353}, {"id": "charcoal", "fg": 2354}, {"id": "stanag30", "fg": 2355}, {"id": "keg", "fg": 2356}, {"id": "pitchfork", "fg": 2357}, {"id": "knife_steak", "fg": 2358}, {"id": "wood_beam", "fg": 2359}, {"id": "smart_phone", "fg": 2360}, {"id": "mosin91_30", "fg": 2361}, {"id": "extinguisher", "fg": 2362}, {"id": "hk_mp5", "fg": 2363}, {"id": "sw_610", "fg": 2364}, {"id": "colt_lightning", "fg": 2365}, {"id": "mag_smg", "fg": 2366}, {"id": "duct_tape", "fg": 2367}, {"id": "t_chainfence", "multitile": true, "rotates": false, "fg": 2368, "bg": 1376, "additional_tiles": [{"id": "edge", "bg": 1376, "fg": [2371, 2368]}, {"id": "end_piece", "bg": 1376, "fg": [2371, 2368, 2371, 2368]}, {"bg": 1376, "id": "unconnected", "fg": 2368}]}, {"id": "t_chainfence_season_winter", "multitile": true, "rotates": false, "fg": 2368, "bg": 643, "additional_tiles": [{"id": "edge", "bg": 643, "fg": [2371, 2368]}, {"id": "end_piece", "bg": 643, "fg": [2371, 2368, 2371, 2368]}, {"bg": 643, "id": "unconnected", "fg": 2368}]}, {"id": "t_chaingate_c", "fg": 2372, "bg": 1376}, {"id": "t_chaingate_l", "fg": 2373, "bg": 1376}, {"id": "t_chaingate_o", "fg": 2369, "bg": 1376}, {"id": "t_chainfence_posts", "fg": 2370, "bg": 1376}, {"id": "t_chaingate_c_season_winter", "fg": 2372, "bg": 643}, {"id": "t_chaingate_l_season_winter", "fg": 2373, "bg": 643}, {"id": "t_chaingate_o_season_winter", "fg": 2369, "bg": 643}, {"id": "t_chainfence_posts_season_winter", "fg": 2370, "bg": 643}, {"id": "t_strconc_wall", "fg": 2374}, {"id": "t_splitrail_fence_season_spring", "fg": 2375, "bg": 1233}, {"id": "t_splitrail_fence_season_summer", "fg": 2375, "bg": 1240}, {"id": "t_splitrail_fence_season_autumn", "fg": 2375, "bg": 1234}, {"id": "t_splitrail_fence_season_winter", "fg": 2375, "bg": 643}, {"id": "t_railing", "fg": 2376, "bg": 1233}, {"id": "t_console", "fg": 2377}, {"id": "t_underbrush", "fg": [{"weight": 100, "sprite": 2380}, {"weight": 100, "sprite": 2379}], "bg": 1233}, {"id": "t_underbrush_harvested", "fg": 2378, "bg": 1233}, {"id": "t_underbrush_season_summer", "fg": [{"weight": 100, "sprite": 2380}, {"weight": 100, "sprite": 2379}], "bg": 1240}, {"id": "t_underbrush_harvested_season_summer", "fg": 2378, "bg": 1240}, {"id": "t_underbrush_season_autumn", "fg": [{"weight": 100, "sprite": 2380}, {"weight": 100, "sprite": 2379}], "bg": 1234}, {"id": "t_underbrush_harvested_season_winter", "fg": 2378, "bg": 644}, {"id": "t_underbrush_season_winter", "fg": [{"weight": 100, "sprite": 2380}, {"weight": 100, "sprite": 2379}], "bg": 644}, {"id": ["t_window_boarded", "t_window_boarded_noglass"], "fg": 2381, "bg": 758}, {"id": "t_wall_metal", "fg": 2382}, {"id": ["t_window_reinforced", "t_window_reinforced_noglass"], "fg": 2383, "bg": 758}, {"id": "t_door_metal_o", "fg": 2384}, {"id": "t_window_frame", "fg": 2385}, {"id": "t_pavement_y", "fg": 2386}, {"id": "t_pavement_y_season_winter", "fg": 643}, {"id": "t_dirtmound", "fg": 2387}, {"id": "t_reinforced_glass_shutter", "fg": 2389}, {"id": "t_reinforced_glass_shutter_open", "fg": 2388}, {"id": "t_trunk", "multitile": true, "fg": [2390, 2391], "bg": [{"weight": 100, "sprite": 1233}, {"weight": 100, "sprite": 1235}]}, {"id": "t_trunk_season_summer", "multitile": true, "fg": [2390, 2391], "bg": [{"weight": 100, "sprite": 1240}, {"weight": 100, "sprite": 1229}]}, {"id": "t_trunk_season_autumn", "multitile": true, "fg": [2390, 2391], "bg": [{"weight": 100, "sprite": 1234}, {"weight": 100, "sprite": 1228}]}, {"id": "t_trunk_season_winter", "multitile": true, "fg": [2390, 2391], "bg": 643}, {"id": "t_console_broken", "fg": 2392}, {"id": ["t_junk_palisade", "t_junk_wall"], "fg": [{"weight": 100, "sprite": 2396}, {"weight": 100, "sprite": 2395}, {"weight": 100, "sprite": 2393}, {"weight": 100, "sprite": 2394}]}, {"id": "t_door_metal_c", "fg": 2397}, {"id": "fd_smoke", "fg": 2400}, {"id": "fd_fungal_haze", "fg": 2399}, {"id": "fd_nuke_gas", "fg": 2398}, {"id": "fd_acid", "fg": 2401}, {"id": "fd_blood", "fg": 2403}, {"id": ["fd_blood_insect", "fd_blood_invertebrate"], "fg": 2402}, {"id": "fd_electricity", "fg": [{"weight": 100, "sprite": 2405}, {"weight": 100, "sprite": 2404}]}, {"id": "fd_web", "fg": [{"weight": 100, "sprite": 2407}, {"weight": 100, "sprite": 2406}, {"weight": 25, "sprite": 2408}, {"weight": 25, "sprite": 2409}]}], "//": "range 2321 to 2416"}, {"file": "fillerhoder.png", "tiles": [{"id": "vp_aisle_horizontal", "fg": 2429}, {"id": "vp_aisle_vertical", "fg": 2426}, {"id": "vp_bed", "fg": 2425}, {"id": "vp_folding_seat", "fg": 2455}, {"id": "vp_frame_cover", "fg": 2503}, {"id": "vp_frame_cross", "fg": 2502}, {"id": "vp_frame_handle", "fg": 2583}, {"id": "vp_frame_horizontal", "fg": 2520}, {"id": "vp_frame_horizontal_2", "fg": 2524}, {"id": "vp_frame_ne", "fg": 2481}, {"id": "vp_frame_nw", "fg": 2568}, {"id": "vp_frame_se", "fg": 2478}, {"id": "vp_frame_sw", "fg": 2566}, {"id": "vp_frame_vertical", "fg": 2488}, {"id": "vp_frame_vertical_2", "fg": 2551}, {"id": "vp_frame_wood_cover", "fg": 2588}, {"id": "vp_frame_wood_cross", "fg": 2533}, {"id": "vp_frame_wood_handle", "fg": 2583}, {"id": "vp_frame_wood_horizontal", "fg": 2452}, {"id": "vp_frame_wood_horizontal_2", "fg": 2428}, {"id": "vp_frame_wood_ne", "fg": 2457}, {"id": "vp_frame_wood_nw", "fg": 2511}, {"id": "vp_frame_wood_se", "fg": 2436}, {"id": "vp_frame_wood_sw", "fg": 2464}, {"id": "vp_frame_wood_vertical", "fg": 2439}, {"id": "vp_frame_wood_vertical_2", "fg": 2565}, {"id": "vp_hdboard_horizontal", "fg": 2577}, {"id": "vp_hdboard_ne", "fg": 2419}, {"id": "vp_hdboard_nw", "fg": 2499}, {"id": "vp_hdboard_se", "fg": 2442}, {"id": "vp_hdboard_sw", "fg": 2458}, {"id": "vp_hdboard_vertical", "fg": 2546}, {"id": "vp_hdframe_cover", "fg": 2572}, {"id": "vp_hdframe_cross", "fg": 2532}, {"id": "vp_hdframe_horizontal", "fg": 2527}, {"id": "vp_hdframe_horizontal_2", "fg": 2475}, {"id": "vp_hdframe_ne", "fg": 2578}, {"id": "vp_hdframe_nw", "fg": 2530}, {"id": "vp_hdframe_se", "fg": 2545}, {"id": "vp_hdframe_sw", "fg": 2484}, {"id": "vp_hdframe_vertical", "fg": 2491}, {"id": "vp_hdframe_vertical_2", "fg": 2592}, {"id": "vp_reclining_seat", "fg": 2455}, {"id": "vp_saddle", "fg": 2476}, {"id": "vp_seat", "fg": 2455}, {"id": "vp_washing_machine", "fg": 2493}, {"id": "vp_woodboard_horizontal", "fg": 2548}, {"id": "vp_woodboard_ne", "fg": 2556}, {"id": "vp_woodboard_nw", "fg": 2453}, {"id": "vp_woodboard_se", "fg": 2507}, {"id": "vp_woodboard_sw", "fg": 2571}, {"id": "vp_woodboard_vertical", "fg": 2514}, {"id": "vp_woodhalfboard_horizontal", "fg": 2548}, {"id": "vp_woodhalfboard_horizontal_2", "fg": 2548}, {"id": "vp_woodhalfboard_ne", "fg": 2556}, {"id": "vp_woodhalfboard_nw", "fg": 2453}, {"id": "vp_woodhalfboard_se", "fg": 2507}, {"id": "vp_woodhalfboard_sw", "fg": 2571}, {"id": "vp_woodhalfboard_vertical", "fg": 2514}, {"id": "vp_woodhalfboard_vertical_2", "fg": 2514}, {"id": "vp_basketlg", "fg": 2462}, {"id": "vp_basketsm", "fg": 2462}, {"id": "vp_battery_motorbike", "fg": 2590}, {"id": "vp_blade_horizontal", "fg": 2589}, {"id": "vp_blade_vertical", "fg": 2433}, {"id": "vp_box", "fg": 2531}, {"id": "vp_cargo_space", "fg": 2486, "bg": 2565}, {"id": "vp_chemlab", "fg": 2431}, {"id": "vp_controls", "fg": 2505}, {"id": "vp_craft_rig", "fg": 2431}, {"id": "vp_door_internal", "fg": 2471}, {"id": "vp_door_opaque", "fg": 2501}, {"id": "vp_door_shutter", "fg": 2473}, {"id": "vp_door_sliding", "fg": 2518}, {"id": "vp_engine_1cyl", "fg": 2563}, {"id": "vp_engine_electric", "fg": 2468}, {"id": "vp_engine_electric_large", "fg": 2541}, {"id": "vp_engine_inline4", "fg": 2535}, {"id": "vp_engine_plasma", "fg": 2482}, {"id": "vp_engine_v12", "fg": 2550, "bg": 2553}, {"id": "vp_engine_v6", "fg": 2550}, {"id": "vp_engine_v8", "fg": 2553}, {"id": "vp_engine_vtwin", "fg": 2423}, {"id": "vp_external_gas_tank", "fg": 2420}, {"id": "vp_flamethrower", "fg": 2539}, {"id": "vp_floodlight", "fg": 2418, "bg": 2480}, {"id": "vp_foot_pedals", "fg": 2504}, {"id": "vp_fusion_gun", "fg": 2490}, {"id": "vp_gas_tank", "fg": 2420}, {"id": "vp_gas_tank_small", "fg": 2420}, {"id": "vp_hatch", "fg": 2557}, {"id": "vp_hatch_opaque", "fg": 2585}, {"id": "vp_hddoor", "fg": 2497}, {"id": "vp_hddoor_internal", "fg": 2519}, {"id": "vp_hddoor_opaque", "fg": 2465}, {"id": "vp_hddoor_shutter", "fg": 2448}, {"id": "vp_hddoor_sliding", "fg": 2521}, {"id": "vp_hddoor_trunk", "fg": 2500}, {"id": "vp_hdhatch", "fg": 2515}, {"id": "vp_hdhatch_opaque", "fg": 2479}, {"id": "vp_hdroof", "fg": 2559}, {"id": "vp_hydrogen_tank", "fg": 2522}, {"id": "vp_kitchen_unit", "fg": 2431}, {"id": "vp_laser_gun", "fg": 2490}, {"id": "vp_light_blue", "fg": 2510, "bg": 2573}, {"id": "vp_light_red", "fg": 2510, "bg": 2472}, {"id": "vp_lit_aisle_horizontal", "fg": 2429}, {"id": "vp_lit_aisle_vertical", "fg": 2426}, {"id": "vp_m249", "fg": 2569}, {"id": "vp_minifridge", "fg": 2529}, {"id": "vp_minireactor", "fg": 2454}, {"id": "vp_mounted_browning", "fg": 2569}, {"id": "vp_mounted_mk19", "fg": 2569}, {"id": "vp_muffler", "fg": 2554}, {"id": ["vp_omnicam", "vp_omnomnicam"], "fg": 2526, "bg": 2559}, {"id": "vp_plasma_gun", "fg": 2508}, {"id": "vp_plating_hard", "fg": 2512}, {"id": "vp_plating_military", "fg": 2430}, {"id": "vp_plating_spiked", "fg": 2547}, {"id": "vp_plating_steel", "fg": 2430}, {"id": "vp_plating_superalloy", "fg": 2460}, {"id": "vp_plating_wood", "fg": 2489}, {"id": "vp_recharge_station", "fg": 2590, "bg": 2531}, {"id": "vp_reinforced_solar_panel", "fg": 2564, "bg": 2441}, {"id": "vp_reinforced_solar_panel_v2", "fg": 2564, "bg": 2441}, {"id": "vp_reinforced_windshield", "fg": 2564, "bg": 2509}, {"id": "vp_roof", "fg": 2480}, {"id": "vp_roof_cloth", "fg": 2528}, {"id": "vp_seatbelt", "fg": 2424}, {"id": "vp_seatbelt_heavyduty", "fg": 2424}, {"id": "vp_small_storage_battery", "fg": 2590}, {"id": "vp_solar_panel", "fg": 2441}, {"id": "vp_solar_panel_v2", "fg": 2441}, {"id": "vp_solar_panel_v3", "fg": 2441}, {"id": "vp_spike", "fg": 2456}, {"id": "vp_storage_battery", "fg": 2590}, {"id": "vp_storage_car", "fg": 2590}, {"id": "vp_storage_truck", "fg": 2590}, {"id": "vp_trunk", "fg": 2531}, {"id": "vp_trunk_floor", "fg": 2434}, {"id": "vp_turret_mount", "fg": 2506, "bg": 2559}, {"id": "vp_v_curtain", "fg": 2438}, {"id": "vp_veh_forge", "fg": 2450}, {"id": "vp_veh_table", "fg": 2586}, {"id": "vp_water_tank", "fg": 2470}, {"id": "vp_welding_rig", "fg": 2574}, {"id": "vp_wheel", "fg": 2591}, {"id": "vp_wheel_armor", "fg": 2591}, {"id": "vp_wheel_armor_steerable", "fg": 2591}, {"id": "vp_wheel_bicycle", "fg": 2562}, {"id": "vp_wheel_bicycle_steerable", "fg": 2562}, {"id": "vp_wheel_caster", "fg": 2467}, {"id": "vp_wheel_motorbike", "fg": 2576}, {"id": "vp_wheel_motorbike_steerable", "fg": 2576}, {"id": "vp_wheel_small", "fg": 2421}, {"id": "vp_wheel_small_steerable", "fg": 2421}, {"id": "vp_wheel_steerable", "fg": 2591}, {"id": "vp_wheel_unicycle", "fg": 2562}, {"id": "vp_wheel_wheelchair", "fg": 2562}, {"id": "vp_wheel_wide", "fg": 2451}, {"id": "vp_wheel_wide_steerable", "fg": 2451}, {"id": "alloy_plate", "fg": 2460, "bg": 2498}, {"id": "foot_crank", "fg": 2504, "bg": 2498}, {"id": "frame", "fg": 2533, "bg": 2498}, {"id": "glass_sheet", "fg": 2509, "bg": 2498}, {"id": "hard_plate", "fg": 2512, "bg": 2498}, {"id": "kitchen_unit", "fg": 2431, "bg": 2498}, {"id": "motor", "fg": 2468, "bg": 2498}, {"id": "motor_large", "fg": 2541, "bg": 2498}, {"id": "muffler", "fg": 2554, "bg": 2498}, {"id": "plasma_engine", "fg": 2482, "bg": 2498}, {"id": "saddle", "fg": 2476, "bg": 2498}, {"id": "seat", "fg": 2455, "bg": 2498}, {"id": "solar_panel", "fg": 2441, "bg": 2498}, {"id": "spiked_plate", "fg": 2547, "bg": 2498}, {"id": "steel_plate", "fg": 2430, "bg": 2498}, {"id": "storage_battery", "fg": 2590, "bg": 2498}, {"id": "vehicle_controls", "fg": 2505, "bg": 2498}, {"id": "weldrig", "fg": 2574, "bg": 2498}, {"id": "forge", "fg": 2450, "bg": 2498}, {"id": "1cyl_combustion", "fg": 2563, "bg": 2498}, {"id": "i4_combustion", "fg": 2535, "bg": 2498}, {"id": "v2_combustion", "fg": 2423, "bg": 2498}, {"id": "v6_combustion", "fg": 2550, "bg": 2498}, {"id": "v8_combustion", "fg": 2553, "bg": 2498}, {"id": "vp_board_horizontal", "fg": 2492}, {"id": "vp_board_ne", "fg": 2461}, {"id": "vp_board_nw", "fg": 2579}, {"id": "vp_board_se", "fg": 2440}, {"id": "vp_board_sw", "fg": 2561}, {"id": "vp_board_vertical", "fg": 2549}, {"id": "vp_hdhalfboard_horizontal", "fg": 2417}, {"id": "vp_hdhalfboard_horizontal_2", "fg": 2449}, {"id": "vp_hdhalfboard_ne", "fg": 2587}, {"id": "vp_hdhalfboard_nw", "fg": 2570}, {"id": "vp_hdhalfboard_se", "fg": 2495}, {"id": "vp_hdhalfboard_sw", "fg": 2517}, {"id": "vp_hdhalfboard_vertical", "fg": 2543}, {"id": "vp_hdhalfboard_vertical_2", "fg": 2559}, {"id": "vp_hdstowboard_horizontal", "fg": 2463}, {"id": "vp_hdstowboard_ne", "fg": 2525}, {"id": "vp_hdstowboard_nw", "fg": 2537}, {"id": "vp_hdstowboard_se", "fg": 2427}, {"id": "vp_hdstowboard_sw", "fg": 2575}, {"id": "vp_hdstowboard_vertical", "fg": 2446}, {"id": "vp_stowboard_horizontal", "fg": 2582}, {"id": "vp_stowboard_ne", "fg": 2444}, {"id": "vp_stowboard_nw", "fg": 2513}, {"id": "vp_stowboard_se", "fg": 2560}, {"id": "vp_stowboard_sw", "fg": 2432}, {"id": "vp_stowboard_vertical", "fg": 2477}, {"id": "vp_wing_mirror", "fg": 2445}, {"id": "[vp_xlframe_cover],[vp_fxlframe_cover]", "fg": 2485}, {"id": "[vp_xlframe_cross],[vp_fxlframe_cross]", "fg": 2483}, {"id": "[vp_xlframe_horizontal_2],[vp_fxlframe_horizontal_2]", "fg": 2558}, {"id": "[vp_xlframe_horizontal],[vp_fxlframe_horizontal]", "fg": 2536}, {"id": "[vp_xlframe_ne],[vp_fxlframe_ne]", "fg": 2459}, {"id": "[vp_xlframe_nw],[vp_fxlframe_nw]", "fg": 2447}, {"id": "[vp_xlframe_se],[vp_fxlframe_se]", "fg": 2523}, {"id": "[vp_xlframe_sw],[vp_fxlframe_sw]", "fg": 2580}, {"id": "[vp_xlframe_vertical_2],[vp_fxlframe_vertical_2]", "fg": 2466}, {"id": "[vp_xlframe_vertical],[vp_fxlframe_vertical]", "fg": 2555}, {"id": "[vp_xlhalfboard_horizontal_2],[vp_fxlhalfboard_horizontal_2]", "fg": 2494}, {"id": "[vp_xlhalfboard_horizontal],[vp_fxlhalfboard_horizontal]", "fg": 2567}, {"id": "[vp_xlhalfboard_ne],[vp_fxlhalfboard_ne]", "fg": 2540}, {"id": "[vp_xlhalfboard_nw],[vp_fxlhalfboard_nw]", "fg": 2435}, {"id": "[vp_xlhalfboard_se],[vp_fxlhalfboard_se]", "fg": 2437}, {"id": "[vp_xlhalfboard_sw],[vp_fxlhalfboard_sw", "fg": 2474}, {"id": "[vp_xlhalfboard_vertical_2],[vp_fxlhalfboard_vertical_2]", "fg": 2487}, {"id": "[vp_xlhalfboard_vertical],[vp_fxlhalfboard_vertical]", "fg": 2443}, {"id": "wheel", "fg": 2591, "bg": 2498}, {"id": "wheel_bicycle", "fg": 2562, "bg": 2498}, {"id": "wheel_motorbike", "fg": 2576, "bg": 2498}, {"id": "wheel_small", "fg": 2421, "bg": 2498}, {"id": "wheel_wide", "fg": 2451, "bg": 2498}], "//": "range 2417 to 2608"}, {"file": "opengameartgiant.png", "tiles": [{"id": "t_tree_chestnut", "fg": 2610, "bg": 2302}, {"id": "t_tree_chestnut_season_summer", "fg": 2611, "bg": 2303}, {"id": "t_tree_chestnut_season_autumn", "fg": 2611, "bg": 2301}, {"id": "t_tree_chestnut_season_winter", "fg": 2611, "bg": 2304}, {"id": "t_tree_pine", "fg": 2614, "bg": 2302}, {"id": "t_tree_pine_season_summer", "fg": 2614, "bg": 2303}, {"id": "t_tree_pine_season_autumn", "fg": 2614, "bg": 2301}, {"id": "t_tree_pine_season_winter", "fg": 2614, "bg": 2304}, {"id": "t_tree_deadpine", "fg": 2612, "bg": 2302}, {"id": "t_tree_deadpine_season_summer", "fg": 2612, "bg": 2303}, {"id": "t_tree_deadpine_season_autumn", "fg": 2612, "bg": 2301}, {"id": "t_tree_deadpine_season_winter", "fg": 2612, "bg": 2304}, {"id": "t_tree_hickory", "fg": 2609, "bg": 2302}, {"id": "t_tree_hickory_season_summer", "fg": 2609, "bg": 2303}, {"id": "t_tree_hickory_season_autumn", "fg": 2609, "bg": 2301}, {"id": "t_tree_hickory_season_winter", "fg": 2613, "bg": 2304}, {"id": "t_tree_hickory_dead", "fg": 2613, "bg": 2302}, {"id": "t_tree_hickory_dead_season_summer", "fg": 2613, "bg": 2303}, {"id": "t_tree_hickory_dead_season_autumn", "fg": 2613, "bg": 2301}, {"id": "t_tree_hickory_dead_season_winter", "fg": 2613, "bg": 2304}], "//": "range 2609 to 2624", "sprite_width": 96, "sprite_height": 96, "sprite_offset_x": -32, "sprite_offset_y": -64}, {"file": "fallback.png", "tiles": [], "ascii": [{"offset": 0, "bold": false, "color": "BLACK"}, {"offset": 256, "bold": true, "color": "WHITE"}, {"offset": 512, "bold": false, "color": "WHITE"}, {"offset": 768, "bold": true, "color": "BLACK"}, {"offset": 1024, "bold": false, "color": "RED"}, {"offset": 1280, "bold": false, "color": "GREEN"}, {"offset": 1536, "bold": false, "color": "BLUE"}, {"offset": 1792, "bold": false, "color": "CYAN"}, {"offset": 2048, "bold": false, "color": "MAGENTA"}, {"offset": 2304, "bold": false, "color": "YELLOW"}, {"offset": 2560, "bold": true, "color": "RED"}, {"offset": 2816, "bold": true, "color": "GREEN"}, {"offset": 3072, "bold": true, "color": "BLUE"}, {"offset": 3328, "bold": true, "color": "CYAN"}, {"offset": 3584, "bold": true, "color": "MAGENTA"}, {"offset": 3840, "bold": true, "color": "YELLOW"}]}]} \ No newline at end of file +{"tile_info": [{"width": 32, "height": 32}], "tiles-new": [{"file": "normal.png", "tiles": [{"id": "f_indoor_plant", "fg": 3}, {"id": "f_indoor_plant_y", "fg": 1}, {"id": ["f_indoor_plant_y_season_autumn", "f_indoor_plant_y_season_winter"], "fg": 2}, {"id": "f_recycle_bin", "fg": 4}, {"id": "f_armchair", "fg": 5}, {"id": "f_wreckage", "fg": 6}, {"id": "f_gunsafe_ml", "fg": 8}, {"id": "f_gunsafe_mj", "fg": 7}, {"id": "f_gun_safe_el", "fg": 9}, {"id": "f_mutpoppy", "fg": 10}, {"id": "f_planter_mature", "multitile": true, "fg": 13, "additional_tiles": [{"id": "center", "fg": 14}, {"id": "corner", "fg": [23, 26, 22, 16]}, {"id": "t_connection", "fg": [19, 18, 25, 15]}, {"id": "edge", "fg": [20, 21]}, {"id": "end_piece", "fg": [17, 12, 11, 24]}, {"id": "unconnected", "fg": 13}]}, {"id": "f_boulder_small", "fg": 27}, {"id": "f_dandelion", "fg": 28}, {"id": "f_planter", "multitile": true, "fg": 37, "additional_tiles": [{"id": "center", "fg": 32}, {"id": "corner", "fg": [42, 36, 39, 35]}, {"id": "t_connection", "fg": [29, 40, 44, 43]}, {"id": "edge", "fg": [41, 38]}, {"id": "end_piece", "fg": [33, 34, 30, 31]}, {"id": "unconnected", "fg": 37}]}, {"id": "f_bathtub", "multitile": true, "fg": 54, "additional_tiles": [{"id": "center", "fg": 55}, {"id": "corner", "fg": [53, 50, 48, 56]}, {"id": "t_connection", "fg": [60, 52, 51, 47]}, {"id": "edge", "fg": [59, 57]}, {"id": "end_piece", "fg": [45, 49, 46, 58]}, {"id": "unconnected", "fg": 54}]}, {"id": "f_sofa", "multitile": true, "fg": 65, "additional_tiles": [{"id": "center", "fg": 66}, {"id": "corner", "fg": [74, 69, 76, 62]}, {"id": "t_connection", "fg": [70, 68, 61, 63]}, {"id": "edge", "fg": [75, 73]}, {"id": "end_piece", "fg": [64, 67, 72, 71]}, {"id": "unconnected", "fg": 65}]}, {"id": "f_alien_anemone", "fg": 78}, {"id": "f_alien_table", "fg": 77}, {"id": "f_filing_cabinet", "fg": 79}, {"id": "f_toilet", "fg": 80}, {"id": "f_ash", "fg": 81}, {"id": "f_desk", "multitile": true, "fg": 82, "additional_tiles": [{"id": "center", "fg": 91}, {"id": "corner", "fg": [87, 84, 92, 86]}, {"id": "t_connection", "fg": [90, 89, 85, 95]}, {"id": "edge", "fg": [96, 83]}, {"id": "end_piece", "fg": [97, 94, 93, 88]}, {"id": "unconnected", "fg": 82}]}, {"id": "f_trashcan", "fg": 98}, {"id": "f_entertainment_center", "fg": 99}, {"id": "f_grave_stone", "fg": [{"weight": 1, "sprite": 100}, {"weight": 1, "sprite": 101}]}, {"id": "f_rubble", "fg": 102}, {"id": "f_rubble_rock", "fg": 103}, {"id": "f_sign", "fg": 104}, {"id": "f_flower_spurge", "fg": 105}, {"id": "f_planter_harvest", "multitile": true, "fg": 117, "additional_tiles": [{"id": "center", "fg": 110}, {"id": "corner", "fg": [115, 120, 111, 118]}, {"id": "t_connection", "fg": [112, 113, 121, 107]}, {"id": "edge", "fg": [106, 108]}, {"id": "end_piece", "fg": [116, 114, 109, 119]}, {"id": "unconnected", "fg": 117}]}, {"id": "f_cardboard_box", "fg": 122}, {"id": "f_datura", "fg": 123}, {"id": "f_planter_seedling", "multitile": true, "fg": 131, "additional_tiles": [{"id": "center", "fg": 132}, {"id": "corner", "fg": [134, 125, 136, 128]}, {"id": "t_connection", "fg": [124, 133, 130, 126]}, {"id": "edge", "fg": [139, 137]}, {"id": "end_piece", "fg": [127, 135, 129, 138]}, {"id": "unconnected", "fg": 131}]}, {"id": "f_table", "multitile": true, "fg": 140, "additional_tiles": [{"id": "center", "fg": 154}, {"id": "corner", "fg": [148, 151, 142, 152]}, {"id": "t_connection", "fg": [141, 147, 144, 153]}, {"id": "edge", "fg": [143, 150]}, {"id": "end_piece", "fg": [146, 149, 155, 145]}, {"id": "unconnected", "fg": 140}]}, {"id": "f_boulder_large", "fg": 156}, {"id": "f_flower_tulip", "fg": [{"weight": 1, "sprite": 158}, {"weight": 2, "sprite": 157}]}, {"id": "f_cupboard", "multitile": true, "fg": 174, "additional_tiles": [{"id": "center", "fg": 173}, {"id": "corner", "fg": [167, 164, 166, 160]}, {"id": "t_connection", "fg": [163, 172, 168, 169]}, {"id": "edge", "fg": [171, 162]}, {"id": "end_piece", "fg": [159, 161, 165, 170]}, {"id": "unconnected", "fg": 174}]}, {"id": "f_metal_crate_r", "fg": 175}, {"id": "f_metal_crate_c", "fg": 177}, {"id": "f_metal_crate_o", "fg": 176}, {"id": "f_bluebell", "fg": [{"weight": 1, "sprite": 178}, {"weight": 2, "sprite": 179}]}, {"id": "f_bed", "multitile": true, "fg": 185, "additional_tiles": [{"id": "center", "fg": 181}, {"id": "corner", "fg": [191, 190, 184, 189]}, {"id": "t_connection", "fg": [193, 188, 194, 192]}, {"id": "edge", "fg": [195, 183]}, {"id": "end_piece", "fg": [180, 186, 182, 187]}, {"id": "unconnected", "fg": 185}]}, {"id": "f_firering", "fg": 196}, {"id": "f_bench", "multitile": true, "fg": 210, "additional_tiles": [{"id": "center", "fg": 203}, {"id": "corner", "fg": [206, 208, 200, 199]}, {"id": "t_connection", "fg": [197, 204, 207, 209]}, {"id": "edge", "fg": [201, 205]}, {"id": "end_piece", "fg": [211, 202, 212, 198]}, {"id": "unconnected", "fg": 210}]}, {"id": "f_mailbox", "fg": 213}, {"id": "f_grave_stone_old", "fg": [{"weight": 1, "sprite": 215}, {"weight": 1, "sprite": 214}]}, {"id": "f_rack_wood", "fg": 216}, {"id": "f_boulder_medium", "fg": 217}, {"id": "f_chamomile", "fg": 218}, {"id": "f_hay", "fg": 219}, {"id": "f_counter", "multitile": true, "fg": 226, "additional_tiles": [{"id": "center", "fg": 222}, {"id": "corner", "fg": [231, 223, 229, 227]}, {"id": "t_connection", "fg": [228, 221, 235, 230]}, {"id": "edge", "fg": [225, 224]}, {"id": "end_piece", "fg": [232, 234, 233, 220]}, {"id": "unconnected", "fg": 226}]}, {"id": "f_air_conditioner", "fg": 236}, {"id": "f_chair", "fg": 237}, {"id": "f_stool", "fg": 238}, {"id": "f_dahlia", "fg": [{"weight": 1, "sprite": 239}, {"weight": 2, "sprite": 240}]}, {"id": ["f_displaycase"], "fg": 241}, {"id": "f_rack", "fg": 242}, {"id": "vp_door_trunk", "fg": 243, "rotates": true, "multitile": true, "additional_tiles": [{"id": "open", "fg": 244}]}, {"id": ["vp_headlight", "vp_headlight_reinforced"], "fg": 245}, {"id": "vp_door", "fg": 246, "rotates": true, "multitile": true, "additional_tiles": [{"id": "open", "fg": 247}]}, {"id": "vp_halfboard_ne", "fg": 251, "rotates": true}, {"id": "vp_halfboard_nw", "fg": 256, "rotates": true}, {"id": "vp_halfboard_se", "fg": 248, "rotates": true}, {"id": "vp_halfboard_sw", "fg": 253, "rotates": true}, {"id": "vp_halfboard_vertical", "fg": 249, "rotates": true}, {"id": "vp_halfboard_horizontal_2", "fg": 252, "rotates": true}, {"id": "vp_halfboard_horizontal", "fg": 254, "rotates": true}, {"id": "vp_halfboard_vertical_2", "fg": 255, "rotates": true}, {"id": "vp_halfboard_cover", "fg": 250, "rotates": true}, {"id": "vp_windshield", "fg": 260, "rotates": true, "multitile": true, "additional_tiles": [{"id": "center", "fg": [257, 261, 258, 259]}, {"id": "edge", "fg": 260}, {"id": "unconnected", "fg": 260}, {"id": "end_piece", "fg": [257, 261, 258, 259]}, {"id": "t_connection", "fg": [257, 261, 258, 259]}, {"id": "corner", "fg": [257, 261, 258, 259]}]}, {"id": ["vp_folding_seat", "vp_reclining_seat", "vp_seat"], "fg": 263}, {"id": "vp_saddle", "fg": 262}, {"id": "powder_candy", "fg": 264}, {"id": "joint", "fg": 266}, {"id": "joint_lit", "fg": 267}, {"id": "joint_roach", "fg": 265}, {"id": "bag_canvas", "fg": 268}, {"id": "wood_panel", "fg": 269}, {"id": "jar_glass", "fg": 270}, {"id": "shot_hull", "fg": 271}, {"id": "wrench", "fg": 272}, {"id": "needle_bone", "fg": 275}, {"id": "needle_curved", "fg": 273}, {"id": "needle_wood", "fg": 274}, {"id": "pinecone", "fg": 276}, {"id": "ash", "fg": 277}, {"id": "lighter", "fg": [{"weight": 1, "sprite": 278}, {"weight": 1, "sprite": 280}, {"weight": 1, "sprite": 279}]}, {"id": "chips", "fg": 281}, {"id": "rifle_flintlock", "fg": 282}, {"id": "balclava", "fg": 306}, {"id": "beret", "fg": 295}, {"id": "boots", "fg": 322}, {"id": "boxer_briefs", "fg": 301}, {"id": "boxer_shorts", "fg": 287}, {"id": "boy_shorts", "fg": 292}, {"id": "bra", "fg": 314}, {"id": "briefs", "fg": 298}, {"id": "corset", "fg": 311}, {"id": "cowboy_hat", "fg": 323}, {"id": "dress_shoes", "fg": 291}, {"id": "hat_ball", "fg": 305}, {"id": "hat_cotton", "fg": 304}, {"id": "hat_fur", "fg": 308}, {"id": "hat_knit", "fg": 286}, {"id": "hat_noise_cancelling", "fg": 331}, {"id": "helmet_army", "fg": 289}, {"id": "helmet_barbute", "fg": 320}, {"id": "helmet_chitin", "fg": 283}, {"id": "helmet_kabuto", "fg": 319}, {"id": "hoodie", "fg": 318}, {"id": "jeans", "fg": 313}, {"id": "longshirt", "fg": 300}, {"id": "maid_dress", "fg": 285}, {"id": "maid_hat", "fg": 299}, {"id": "mask_dust", "fg": 310}, {"id": "panties", "fg": 296}, {"id": "pants", "fg": 293}, {"id": "pants_cargo", "fg": 307}, {"id": "polo_shirt", "fg": 315}, {"id": "ragpouch", "fg": 329}, {"id": "sneakers", "fg": 288}, {"id": "socks", "fg": 303}, {"id": "stockings", "fg": 294}, {"id": "sweater", "fg": 316}, {"id": "sweatshirt", "fg": 290}, {"id": "tank_top", "fg": 330}, {"id": "tshirt", "fg": 312}, {"id": "turban", "fg": 324}, {"id": "undershirt", "fg": 327}, {"id": "coat_lab", "fg": 326}, {"id": "coat_rain", "fg": 297}, {"id": "sports_bra", "fg": 302}, {"id": "skirt", "fg": 284}, {"id": "jacket_light", "fg": 317}, {"id": "jacket_army", "fg": 328}, {"id": "hat_hard", "fg": 325}, {"id": "striped_pants", "fg": 309}, {"id": "striped_shirt", "fg": 321}, {"id": "", "fg": []}, {"id": "bat_metal", "fg": 332}, {"id": "hacksaw", "fg": 333}, {"id": "crucible_clay", "fg": 334}, {"id": "many_years_old_newspaper", "fg": 339}, {"id": "months_old_newspaper", "fg": 335}, {"id": "newest_newspaper", "fg": 338}, {"id": "one_year_old_newspaper", "fg": 337}, {"id": "weeks_old_newspaper", "fg": 336}, {"id": "pointy_stick", "fg": 348}, {"id": "spear_wood", "fg": 347}, {"id": "spear_spike", "fg": 342}, {"id": "spear_knife", "fg": 345}, {"id": "spear_knife_superior", "fg": 346}, {"id": "spear_pipe", "fg": 340}, {"id": "spear_rebar", "fg": 344}, {"id": "spear_steel", "fg": 341}, {"id": "spear_copper", "fg": 343}, {"id": "hickory_root", "fg": 349}, {"id": "flashlight", "fg": 350}, {"id": "heavy_flashlight", "fg": 351}, {"id": "can_drink", "fg": 352}, {"id": "50_casing", "fg": 353}, {"id": "apple", "fg": 355}, {"id": "banana", "fg": 356}, {"id": "broccoli", "fg": 364}, {"id": "corn", "fg": 367}, {"id": "cucumber", "fg": 360}, {"id": "egg_bird", "fg": 366}, {"id": "grapes", "fg": 354}, {"id": "lemon", "fg": 357}, {"id": "onion", "fg": 365}, {"id": "orange", "fg": 359}, {"id": "pear", "fg": 361}, {"id": "potato", "fg": 358}, {"id": "pumpkin", "fg": 363}, {"id": "tomato", "fg": 362}, {"id": "sewing_kit", "fg": 368}, {"id": "jug_plastic", "fg": 369}, {"id": "pot", "fg": 370}, {"id": "backpack", "fg": 371}, {"id": "cattlefodder", "fg": 372}, {"id": "cup_plastic", "fg": 373}, {"id": "knife_meat_cleaver", "fg": 374}, {"id": "fire_ax", "fg": 375}, {"id": "ax", "fg": 377}, {"id": "hatchet", "fg": 376}, {"id": ["glock_17", "glock_19", "glock_18c", "glock_22", "glock_31"], "fg": 378}, {"id": "straw_pile", "fg": 379}, {"id": "thread", "fg": 380}, {"id": "wheat", "fg": 381}, {"id": "pan", "fg": 382}, {"id": "bottle_glass", "fg": 383}, {"id": "nail", "fg": 384}, {"id": "juniper", "fg": 385}, {"id": "pool_ball", "fg": 386}, {"id": "crowbar", "fg": 387}, {"id": "rag", "fg": 388}, {"id": "id_industrial", "fg": 389}, {"id": "corpse_generic_human", "fg": 390}, {"id": "chainsaw_off", "fg": 391}, {"id": "teapot", "fg": 392}, {"id": "mp5mag", "fg": 393}, {"id": "meat", "fg": 394}, {"id": "cig_butt", "fg": 395}, {"id": "usb_drive", "fg": 396}, {"id": "1st_aid", "fg": 397}, {"id": "welder_crude", "fg": 398}, {"id": "nailbat", "fg": 399}, {"id": "remington_870", "fg": 400}, {"id": "sheet_metal_small", "fg": 401}, {"id": "screwdriver", "fg": 402}, {"id": "primitive_hammer", "fg": 403}, {"id": "steel_lump", "fg": 404}, {"id": "string_6", "fg": 405}, {"id": "saw", "fg": 406}, {"id": "aspirin", "fg": 422}, {"id": "bandages", "fg": 408}, {"id": "syringe", "fg": 414}, {"id": "antibiotics", "fg": 421}, {"id": "weak_antibiotic", "fg": 407}, {"id": "strong_antibiotic", "fg": 415}, {"id": "vitamins", "fg": 412}, {"id": "gummy_vitamins", "fg": 413}, {"id": "calcium_tablet", "fg": 418}, {"id": "oxycodone", "fg": 416}, {"id": "tramadol", "fg": 417}, {"id": "codeine", "fg": 411}, {"id": "prussian_blue", "fg": 410}, {"id": "iodine", "fg": 419}, {"id": "antiparasitic", "fg": 420}, {"id": "antifungal", "fg": 409}, {"id": "can_drink_unsealed", "fg": 423}, {"id": "9mm_casing", "fg": 424}, {"id": "wrapper", "fg": 425}, {"id": "rebar", "fg": 426}, {"id": "glass_shard", "fg": 427}, {"id": "pot_copper", "fg": 428}, {"id": "40mm_casing", "fg": 429}, {"id": "nailboard", "fg": 430}, {"id": "scissors", "fg": 431}, {"id": "ak74", "fg": 432}, {"id": "coffeemaker", "fg": 433}, {"id": "blanket", "fg": 435}, {"id": "down_blanket", "fg": 434}, {"id": "longbow", "fg": 436}, {"id": "pneumatic_shotgun", "fg": 437}, {"id": "thermos", "fg": 438}, {"id": "box_cigarette", "fg": 439}, {"id": "m79", "fg": 440}, {"id": "stick", "fg": 441}, {"id": "steel_chunk", "fg": 442}, {"id": "television", "fg": 443}, {"id": "shovel", "fg": 444}, {"id": "id_science", "fg": 445}, {"id": "cable", "fg": 446}, {"id": "pipe", "fg": 447}, {"id": "bottle_plastic", "fg": 448}, {"id": "fp_loyalty_card", "fg": 449}, {"id": "id_military", "fg": 450}, {"id": "water", "fg": 452}, {"id": "water_clean", "fg": 453}, {"id": "blood", "fg": 451}, {"id": "filter_air", "fg": 454}, {"id": "welder", "fg": 455}, {"id": "broom", "fg": 456}, {"id": "rolling_pin", "fg": 457}, {"id": "makeshift_crowbar", "fg": 458}, {"id": "bat", "fg": 459}, {"id": "wood_sheet", "fg": 460}, {"id": "jar_3l_glass_sealed", "fg": 461}, {"id": "plastic_sheet", "fg": 462}, {"id": "box_large", "fg": 463}, {"id": "knife_vegetable_cleaver", "fg": 464}, {"id": "arming_sword", "fg": 465}, {"id": "crossbow", "fg": 466}, {"id": "pot_canning", "fg": 467}, {"id": "sheet_metal", "fg": 468}, {"id": "brick", "fg": 469}, {"id": "wire", "fg": 470}, {"id": "2x4", "fg": 471}, {"id": ["seed_hops", "seed_blackberries", "seed_blueberries", "coffee_pod", "seed_wheat", "roasted_coffee_bean", "seed_chamomile", "coffee_bean", "seed_celery", "fried_seeds", "seed_buckwheat", "seed_oats", "seed_mushroom_morel", "datura_seed", "seed_mushroom", "seed_rhubarb", "seed_wild_herbs", "seed_raw_dandelion", "seed_veggy_wild", "seed_chili_pepper", "seed_dogbane", "seed_mugwort", "seed_bee_balm", "seed_flower", "seed_sunflower", "seed_thyme", "seed_canola", "seed_pumpkin", "seed_beans", "seed_lentils", "soybean_seed", "marloss_seed", "fungal_seeds", "seed_weed", "seed_potato_raw", "seed_cucumber", "seed_corn", "seed_carrot", "garlic_clove", "seed_cactus", "seed_wildcarrot", "seed_cattail", "seed_chicory", "seed_salsify_raw", "seed_dahlia", "seed_garlic", "seed_broccoli", "seed_onion", "seed_zucchini", "seed_cotton_boll", "seed_tomato", "seed_rose", "seed_lettuce", "seed_cabbage", "seed_sugar_beet", "seed_tobacco", "seed_barley", "seed_grapes", "seed_strawberries", "seed_raspberries", "seed_cranberries", "seed_huckleberries", "seed_mulberries", "seed_elderberries"], "fg": 472}, {"id": "acorns", "fg": 473}, {"id": "slingshot", "fg": 474}, {"id": "bottle_plastic_small", "fg": 475}, {"id": "sharp_rock", "fg": 476}, {"id": "bowl_plastic", "fg": 477}, {"id": "contacts", "fg": 478}, {"id": "matches", "fg": 479}, {"id": "box_small", "fg": 480}, {"id": "plastic_shopping_bag", "fg": 481}, {"id": "pillow", "fg": 483}, {"id": "down_pillow", "fg": 482}, {"id": "mop", "fg": 484}, {"id": "board_trap", "fg": 485}, {"id": "can_food", "fg": 486}, {"id": "scrap", "fg": 487}, {"id": "string_36", "fg": 488}, {"id": "file", "fg": 489}, {"id": "box_medium", "fg": 490}, {"id": "paperback_novel", "fg": 512}, {"id": "novel_adventure", "fg": 512}, {"id": "novel_buddy", "fg": 505}, {"id": "novel_coa", "fg": 494}, {"id": "novel_coa2", "fg": 495}, {"id": "novel_crime", "fg": 498}, {"id": "novel_crime2", "fg": 506}, {"id": "novel_drama", "fg": 502}, {"id": "novel_erotic", "fg": 510}, {"id": "novel_experimental", "fg": 501}, {"id": "novel_fantasy", "fg": 507}, {"id": "novel_horror", "fg": 508}, {"id": "novel_mystery", "fg": 511}, {"id": "novel_pulp", "fg": 499}, {"id": "novel_road", "fg": 496}, {"id": "novel_romance", "fg": 493}, {"id": "novel_samurai", "fg": 491}, {"id": "novel_satire", "fg": 503}, {"id": "novel_scifi", "fg": 515}, {"id": "novel_sports", "fg": 514}, {"id": "novel_spy", "fg": 516}, {"id": "novel_swash", "fg": 504}, {"id": "novel_thriller", "fg": 509}, {"id": "novel_tragedy", "fg": 500}, {"id": "novel_war", "fg": 513}, {"id": "novel_war2", "fg": 497}, {"id": "novel_western", "fg": 492}, {"id": "marble", "fg": 517}, {"id": "withered", "fg": 518}, {"id": "bolt_cf", "fg": 519}, {"id": "bolt_explosive", "fg": 527}, {"id": "bolt_metal", "fg": 522}, {"id": ["bolt_steel", "bolt_steel_bodkin", "bolt_steel_target"], "fg": 526}, {"id": ["bolt_wood", "bolt_crude", "bolt_simple_wood", "bolt_simple_small_game", "bolt_makeshift", "bolt_wood_bodkin", "bolt_wood_small_game"], "fg": 536}, {"id": "arrow_cf", "fg": 525}, {"id": "arrow_exploding", "fg": 520}, {"id": "arrow_field_point_fletched", "fg": 529}, {"id": "arrow_fire_hardened_fletched", "fg": 535}, {"id": "arrow_flammable", "fg": 533}, {"id": "arrow_flamming", "fg": 524}, {"id": "arrow_heavy_fire_hardened_fletched", "fg": 534}, {"id": "arrow_metal", "fg": 528}, {"id": "arrow_metal_sharpened_fletched", "fg": 521}, {"id": "arrow_plastic", "fg": 530}, {"id": "arrow_small_game_fletched", "fg": 531}, {"id": "arrow_wood", "fg": 532}, {"id": "arrow_wood_heavy", "fg": 523}, {"id": "rock", "fg": 537}, {"id": "knife_butcher", "fg": 538}, {"id": "stick_long", "fg": 539}, {"id": "log", "fg": 540}, {"id": "jar_glass_sealed", "fg": 541}, {"id": "jar_3l_glass", "fg": 542}, {"id": "knife_butter", "fg": 543}, {"id": "223_casing", "fg": 544}, {"id": "bwirebat", "fg": 545}, {"id": "bag_plastic", "fg": 546}, {"id": ["rifle_9mm", "rifle_3006", "rifle_45", "rifle_22", "rifle_40", "rifle_44", "rifle_38", "rifle_223"], "fg": 547}, {"id": "pipe_shotgun", "fg": 548}, {"id": "spoon", "fg": 549}, {"id": "hammer", "fg": 550}, {"id": "hickory_nut", "fg": 551}, {"id": "glass_plate", "fg": 552}, {"id": "cash_card", "fg": 553}, {"id": "fork", "fg": 554}, {"id": "splinter", "fg": 555}, {"id": "ar15", "fg": 556}, {"id": "pine_bough", "fg": 557}, {"id": "bag_zipper", "fg": 558}, {"id": "tailors_kit", "fg": 559}, {"id": "sponge", "fg": 560}, {"id": "t_strconc_floor", "multitile": true, "fg": 576, "additional_tiles": [{"id": "center", "fg": 573}, {"id": "corner", "fg": [561, 568, 570, 566]}, {"id": "t_connection", "fg": [562, 567, 571, 564]}, {"id": "edge", "fg": [572, 574]}, {"id": "end_piece", "fg": [575, 563, 569, 565]}, {"id": "unconnected", "fg": 576}]}, {"id": "t_tatami", "fg": [{"weight": 100, "sprite": 578}, {"weight": 100, "sprite": 577}]}, {"id": "t_floor_waxed_y", "multitile": true, "fg": 584, "additional_tiles": [{"id": "center", "fg": 590}, {"id": "corner", "fg": [587, 579, 583, 593]}, {"id": "t_connection", "fg": [585, 581, 592, 580]}, {"id": "edge", "fg": [588, 591]}, {"id": "end_piece", "fg": [589, 582, 586, 594]}, {"id": "unconnected", "fg": 584}]}, {"id": "t_pit_shallow", "fg": 595, "bg": [{"weight": 100, "sprite": 1312}, {"weight": 100, "sprite": 1315}]}, {"id": "t_pit_shallow_season_summer", "fg": 595, "bg": [{"weight": 100, "sprite": 1326}, {"weight": 100, "sprite": 1306}]}, {"id": "t_pit_shallow_season_autumn", "fg": 595, "bg": [{"weight": 100, "sprite": 1313}, {"weight": 100, "sprite": 1305}]}, {"id": "t_rock", "fg": 596}, {"id": "t_railroad_rubble", "fg": 597}, {"id": "t_gravel", "fg": 597}, {"id": "t_railroad_rubble_season_winter", "fg": 682}, {"id": "t_sand", "fg": 598}, {"id": "t_floor_resin", "multitile": true, "fg": 601, "additional_tiles": [{"id": "center", "fg": 600}, {"id": "corner", "fg": [606, 613, 607, 603]}, {"id": "t_connection", "fg": [605, 599, 609, 608]}, {"id": "edge", "fg": [614, 602]}, {"id": "end_piece", "fg": [611, 612, 610, 604]}, {"id": "unconnected", "fg": 601}]}, {"id": "t_metal_floor", "multitile": true, "fg": 622, "additional_tiles": [{"id": "center", "fg": 616}, {"id": "corner", "fg": [624, 620, 618, 619]}, {"id": "t_connection", "fg": [630, 625, 627, 629]}, {"id": "edge", "fg": [628, 626]}, {"id": "end_piece", "fg": [615, 621, 617, 623]}, {"id": "unconnected", "fg": 622}]}, {"id": ["t_door_metal_locked", "t_door_metal_pickable"], "fg": 631}, {"id": "t_wall_b", "multitile": true, "fg": 635, "additional_tiles": [{"id": "center", "fg": 633}, {"id": "corner", "fg": [646, 639, 645, 637]}, {"id": "t_connection", "fg": [643, 638, 647, 641]}, {"id": "edge", "fg": [632, 634]}, {"id": "end_piece", "fg": [640, 636, 644, 642]}, {"id": "unconnected", "fg": 635}]}, {"id": "t_floor", "multitile": true, "fg": 695, "additional_tiles": [{"id": "center", "fg": 692}, {"id": "corner", "fg": [697, 694, 690, 698]}, {"id": "t_connection", "fg": [696, 685, 691, 699]}, {"id": "edge", "fg": [687, 688]}, {"id": "end_piece", "fg": [693, 689, 700, 686]}, {"id": "unconnected", "fg": 695}]}, {"id": "t_brick_wall", "multitile": true, "fg": 714, "additional_tiles": [{"id": "center", "fg": 716}, {"id": "corner", "fg": [706, 708, 707, 712]}, {"id": "t_connection", "fg": [702, 710, 713, 715]}, {"id": "edge", "fg": [709, 701]}, {"id": "end_piece", "fg": [704, 705, 711, 703]}, {"id": "unconnected", "fg": 714}]}, {"id": "t_wall_wood", "multitile": true, "fg": 724, "additional_tiles": [{"id": "center", "fg": 720}, {"id": "corner", "fg": [717, 726, 730, 728]}, {"id": "t_connection", "fg": [725, 732, 719, 722]}, {"id": "edge", "fg": [718, 729]}, {"id": "end_piece", "fg": [731, 721, 727, 723]}, {"id": "unconnected", "fg": 724}]}, {"id": ["t_linoleum_white", "t_linoleum_white_no_roof"], "multitile": true, "fg": 736, "additional_tiles": [{"id": "center", "fg": 748}, {"id": "corner", "fg": [743, 742, 733, 747]}, {"id": "t_connection", "fg": [735, 745, 741, 744]}, {"id": "edge", "fg": [746, 740]}, {"id": "end_piece", "fg": [734, 737, 739, 738]}, {"id": "unconnected", "fg": 736}]}, {"id": "t_fungus", "multitile": true, "fg": 761, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 756}, {"id": "corner", "bg": 1312, "fg": [758, 762, 750, 751]}, {"id": "t_connection", "bg": 1312, "fg": [763, 749, 755, 757]}, {"id": "edge", "bg": 1312, "fg": [759, 753]}, {"id": "end_piece", "bg": 1312, "fg": [760, 752, 764, 754]}, {"bg": 1312, "id": "unconnected", "fg": 761}]}, {"id": "t_fungus_season_summer", "multitile": true, "fg": 761, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 756}, {"id": "corner", "bg": 1326, "fg": [758, 762, 750, 751]}, {"id": "t_connection", "bg": 1326, "fg": [763, 749, 755, 757]}, {"id": "edge", "bg": 1326, "fg": [759, 753]}, {"id": "end_piece", "bg": 1326, "fg": [760, 752, 764, 754]}, {"bg": 1326, "id": "unconnected", "fg": 761}]}, {"id": "t_fungus_season_autumn", "multitile": true, "fg": 761, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 756}, {"id": "corner", "bg": 1313, "fg": [758, 762, 750, 751]}, {"id": "t_connection", "bg": 1313, "fg": [763, 749, 755, 757]}, {"id": "edge", "bg": 1313, "fg": [759, 753]}, {"id": "end_piece", "bg": 1313, "fg": [760, 752, 764, 754]}, {"bg": 1313, "id": "unconnected", "fg": 761}]}, {"id": "t_fungus_season_winter", "multitile": true, "fg": 761, "bg": 682, "additional_tiles": [{"id": "center", "bg": 682, "fg": 756}, {"id": "corner", "bg": 682, "fg": [758, 762, 750, 751]}, {"id": "t_connection", "bg": 682, "fg": [763, 749, 755, 757]}, {"id": "edge", "bg": 682, "fg": [759, 753]}, {"id": "end_piece", "bg": 682, "fg": [760, 752, 764, 754]}, {"bg": 682, "id": "unconnected", "fg": 761}]}, {"id": "t_carpet_red", "multitile": true, "fg": 775, "additional_tiles": [{"id": "center", "fg": 772}, {"id": "corner", "fg": [774, 770, 773, 776]}, {"id": "t_connection", "fg": [767, 771, 766, 777]}, {"id": "edge", "fg": [765, 780]}, {"id": "end_piece", "fg": [778, 779, 769, 768]}, {"id": "unconnected", "fg": 775}]}, {"id": ["t_water_moving_sh", "t_swater_moving_sh"], "multitile": true, "fg": 785, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": [{"weight": 1, "sprite": 784}, {"weight": 1, "sprite": 789}, {"weight": 1, "sprite": 783}, {"weight": 1, "sprite": 781}]}, {"id": "corner", "bg": 1312, "fg": [797, 782, 787, 790]}, {"id": "t_connection", "bg": 1312, "fg": [799, 791, 788, 798]}, {"id": "edge", "bg": 1312, "fg": [794, 795]}, {"id": "end_piece", "bg": 1312, "fg": [796, 786, 792, 793]}, {"bg": 1312, "id": "unconnected", "fg": 785}]}, {"id": ["t_water_moving_sh_season_summer", "t_swater_moving_sh_season_summer"], "multitile": true, "fg": 785, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": [{"weight": 1, "sprite": 784}, {"weight": 1, "sprite": 789}, {"weight": 1, "sprite": 783}, {"weight": 1, "sprite": 781}]}, {"id": "corner", "bg": 1326, "fg": [797, 782, 787, 790]}, {"id": "t_connection", "bg": 1326, "fg": [799, 791, 788, 798]}, {"id": "edge", "bg": 1326, "fg": [794, 795]}, {"id": "end_piece", "bg": 1326, "fg": [796, 786, 792, 793]}, {"bg": 1326, "id": "unconnected", "fg": 785}]}, {"id": ["t_water_moving_sh_season_autumn", "t_swater_moving_sh_season_autumn"], "multitile": true, "fg": 785, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": [{"weight": 1, "sprite": 784}, {"weight": 1, "sprite": 789}, {"weight": 1, "sprite": 783}, {"weight": 1, "sprite": 781}]}, {"id": "corner", "bg": 1313, "fg": [797, 782, 787, 790]}, {"id": "t_connection", "bg": 1313, "fg": [799, 791, 788, 798]}, {"id": "edge", "bg": 1313, "fg": [794, 795]}, {"id": "end_piece", "bg": 1313, "fg": [796, 786, 792, 793]}, {"bg": 1313, "id": "unconnected", "fg": 785}]}, {"id": ["t_water_moving_sh_season_winter", "t_swater_moving_sh_season_winter"], "multitile": true, "fg": 785, "bg": 1321, "additional_tiles": [{"id": "center", "bg": 1321, "fg": [{"weight": 1, "sprite": 784}, {"weight": 1, "sprite": 789}, {"weight": 1, "sprite": 783}, {"weight": 1, "sprite": 781}]}, {"id": "corner", "bg": 1321, "fg": [797, 782, 787, 790]}, {"id": "t_connection", "bg": 1321, "fg": [799, 791, 788, 798]}, {"id": "edge", "bg": 1321, "fg": [794, 795]}, {"id": "end_piece", "bg": 1321, "fg": [796, 786, 792, 793]}, {"bg": 1321, "id": "unconnected", "fg": 785}]}, {"id": ["t_window", "t_window_alarm"], "fg": 801}, {"id": "t_window_empty", "fg": 805}, {"id": "t_window_domestic", "fg": 804}, {"id": "t_window_open", "fg": 803}, {"id": "t_window_no_curtains", "fg": 802}, {"id": "t_window_no_curtains_open", "fg": 800}, {"id": "t_fence_wire", "multitile": true, "fg": 814, "additional_tiles": [{"id": "center", "fg": 811}, {"id": "corner", "fg": [815, 812, 818, 820]}, {"id": "t_connection", "fg": [817, 810, 813, 806]}, {"id": "edge", "fg": [819, 816]}, {"id": "end_piece", "fg": [808, 809, 807, 821]}, {"id": "unconnected", "fg": 814}]}, {"id": "t_fence_barbed_season_spring", "multitile": true, "fg": 827, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 824}, {"id": "corner", "bg": 1312, "fg": [823, 836, 834, 837]}, {"id": "t_connection", "bg": 1312, "fg": [829, 825, 831, 832]}, {"id": "edge", "bg": 1312, "fg": [835, 830]}, {"id": "end_piece", "bg": 1312, "fg": [826, 822, 828, 833]}, {"bg": 1312, "id": "unconnected", "fg": 827}]}, {"id": "t_fence_barbed_season_summer", "multitile": true, "fg": 827, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 824}, {"id": "corner", "bg": 1326, "fg": [823, 836, 834, 837]}, {"id": "t_connection", "bg": 1326, "fg": [829, 825, 831, 832]}, {"id": "edge", "bg": 1326, "fg": [835, 830]}, {"id": "end_piece", "bg": 1326, "fg": [826, 822, 828, 833]}, {"bg": 1326, "id": "unconnected", "fg": 827}]}, {"id": "t_fence_barbed_season_autumn", "multitile": true, "fg": 827, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 824}, {"id": "corner", "bg": 1313, "fg": [823, 836, 834, 837]}, {"id": "t_connection", "bg": 1313, "fg": [829, 825, 831, 832]}, {"id": "edge", "bg": 1313, "fg": [835, 830]}, {"id": "end_piece", "bg": 1313, "fg": [826, 822, 828, 833]}, {"bg": 1313, "id": "unconnected", "fg": 827}]}, {"id": "t_fence_barbed_season_winter", "multitile": true, "fg": 827, "bg": 682, "additional_tiles": [{"id": "center", "bg": 682, "fg": 824}, {"id": "corner", "bg": 682, "fg": [823, 836, 834, 837]}, {"id": "t_connection", "bg": 682, "fg": [829, 825, 831, 832]}, {"id": "edge", "bg": 682, "fg": [835, 830]}, {"id": "end_piece", "bg": 682, "fg": [826, 822, 828, 833]}, {"bg": 682, "id": "unconnected", "fg": 827}]}, {"id": "t_floor_waxed", "multitile": true, "fg": 843, "additional_tiles": [{"id": "center", "fg": 852}, {"id": "corner", "fg": [845, 840, 841, 846]}, {"id": "t_connection", "fg": [850, 839, 849, 842]}, {"id": "edge", "fg": [848, 838]}, {"id": "end_piece", "fg": [851, 847, 844, 853]}, {"id": "unconnected", "fg": 843}]}, {"id": "t_curtains", "fg": 854}, {"id": "t_door_glass_c", "fg": 855}, {"id": ["t_wall_glass", "t_wall_glass_alarm"], "multitile": true, "fg": 857, "additional_tiles": [{"id": "center", "fg": 864}, {"id": "corner", "fg": [871, 868, 859, 874]}, {"id": "t_connection", "fg": [872, 862, 861, 867]}, {"id": "edge", "fg": [856, 860]}, {"id": "end_piece", "fg": [858, 870, 875, 863]}, {"id": "unconnected", "fg": 857}]}, {"id": ["t_sidewalk", "t_sidewalk_bg_dp"], "multitile": true, "fg": 889, "additional_tiles": [{"id": "center", "fg": 876}, {"id": "corner", "fg": [877, 891, 878, 882]}, {"id": "t_connection", "fg": [880, 879, 888, 886]}, {"id": "edge", "fg": [885, 890]}, {"id": "end_piece", "fg": [884, 881, 883, 887]}, {"id": "unconnected", "fg": 889}]}, {"id": "t_sidewalk_season_winter", "fg": 682}, {"id": "t_carpet_purple", "multitile": true, "fg": 898, "additional_tiles": [{"id": "center", "fg": 896}, {"id": "corner", "fg": [901, 903, 892, 895]}, {"id": "t_connection", "fg": [905, 907, 899, 897]}, {"id": "edge", "fg": [904, 906]}, {"id": "end_piece", "fg": [900, 902, 894, 893]}, {"id": "unconnected", "fg": 898}]}, {"id": ["t_shrub_raspberry"], "fg": 908, "bg": 1312}, {"id": ["t_shrub_raspberry_harvested"], "fg": 911, "bg": 1326}, {"id": "t_shrub_raspberry_season_summer", "fg": 910, "bg": 1326}, {"id": "t_shrub_raspberry_season_autumn", "fg": 908, "bg": 1313}, {"id": "t_shrub_raspberry_season_winter", "fg": 909, "bg": 649}, {"id": "t_woodchips", "fg": 912}, {"id": "t_woodchips_season_winter", "fg": 682}, {"id": "t_fence_post_season_spring", "fg": 923, "bg": 1312}, {"id": "t_fence_post_season_summer", "fg": 923, "bg": 1326}, {"id": "t_fence_post_season_autumn", "fg": 923, "bg": 1313}, {"id": "t_fence_post_season_winter", "fg": 923, "bg": 682}, {"id": "t_fence_season_spring", "multitile": true, "fg": 923, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 922}, {"id": "corner", "bg": 1312, "fg": [916, 914, 917, 924]}, {"id": "t_connection", "bg": 1312, "fg": [926, 915, 927, 928]}, {"id": "edge", "bg": 1312, "fg": [925, 929]}, {"id": "end_piece", "bg": 1312, "fg": [920, 919, 930, 918]}, {"bg": 1312, "id": "unconnected", "fg": 923}]}, {"id": "t_fence_season_summer", "multitile": true, "fg": 923, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 922}, {"id": "corner", "bg": 1326, "fg": [916, 914, 917, 924]}, {"id": "t_connection", "bg": 1326, "fg": [926, 915, 927, 928]}, {"id": "edge", "bg": 1326, "fg": [925, 929]}, {"id": "end_piece", "bg": 1326, "fg": [920, 919, 930, 918]}, {"bg": 1326, "id": "unconnected", "fg": 923}]}, {"id": "t_fence_season_autumn", "multitile": true, "fg": 923, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 922}, {"id": "corner", "bg": 1313, "fg": [916, 914, 917, 924]}, {"id": "t_connection", "bg": 1313, "fg": [926, 915, 927, 928]}, {"id": "edge", "bg": 1313, "fg": [925, 929]}, {"id": "end_piece", "bg": 1313, "fg": [920, 919, 930, 918]}, {"bg": 1313, "id": "unconnected", "fg": 923}]}, {"id": "t_fence_season_winter", "multitile": true, "fg": 923, "bg": 682, "additional_tiles": [{"id": "center", "bg": 682, "fg": 922}, {"id": "corner", "bg": 682, "fg": [916, 914, 917, 924]}, {"id": "t_connection", "bg": 682, "fg": [926, 915, 927, 928]}, {"id": "edge", "bg": 682, "fg": [925, 929]}, {"id": "end_piece", "bg": 682, "fg": [920, 919, 930, 918]}, {"bg": 682, "id": "unconnected", "fg": 923}]}, {"id": "t_fencegate_c_season_spring", "fg": 913, "bg": 1312}, {"id": "t_fencegate_c_season_summer", "fg": 913, "bg": 1326}, {"id": "t_fencegate_c_season_autumn", "fg": 913, "bg": 1313}, {"id": "t_fencegate_c_season_winter", "fg": 913, "bg": 682}, {"id": "t_fencegate_o_season_spring", "fg": 921, "bg": 1312}, {"id": "t_fencegate_o_season_summer", "fg": 921, "bg": 1326}, {"id": "t_fencegate_o_season_autumn", "fg": 921, "bg": 1313}, {"id": "t_fencegate_o_season_winter", "fg": 921, "bg": 682}, {"id": "t_wall_y", "multitile": true, "fg": 945, "additional_tiles": [{"id": "center", "fg": 946}, {"id": "corner", "fg": [939, 943, 938, 932]}, {"id": "t_connection", "fg": [936, 941, 935, 940]}, {"id": "edge", "fg": [937, 942]}, {"id": "end_piece", "fg": [933, 934, 944, 931]}, {"id": "unconnected", "fg": 945}]}, {"id": "t_rdoor_c", "fg": 948}, {"id": "t_rdoor_o", "fg": 949}, {"id": "t_rdoor_b", "fg": 947}, {"id": ["t_gates_mech_control"], "fg": 952, "bg": 983}, {"id": ["t_gates_mech_control_lab"], "fg": 954, "bg": 983}, {"id": ["t_gates_control_concrete"], "fg": 951, "bg": 1026}, {"id": ["t_gates_control_concrete_lab"], "fg": 954, "bg": 2534}, {"id": ["t_gates_control_brick"], "fg": 951, "bg": 714}, {"id": ["t_gates_control_brick_lab"], "fg": 954, "bg": 714}, {"id": ["t_gates_control_metal"], "fg": 951, "bg": 2542}, {"id": ["t_gates_control_metal_lab"], "fg": 954, "bg": 2542}, {"id": ["t_elevator_control"], "fg": 950, "bg": 983}, {"id": ["t_elevator_control_off"], "fg": 953, "bg": 983}, {"id": ["t_stump"], "fg": 955, "bg": 1312}, {"id": ["t_stump_season_summer"], "fg": 955, "bg": 1326}, {"id": ["t_stump_season_autumn"], "fg": 955, "bg": 1313}, {"id": "t_stump_season_winter", "fg": 955, "bg": 649}, {"id": ["t_water_moving_dp", "t_swater_moving_dp"], "multitile": true, "fg": 959, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": [{"weight": 1, "sprite": 958}, {"weight": 1, "sprite": 964}]}, {"id": "corner", "bg": 1312, "fg": [965, 961, 960, 966]}, {"id": "t_connection", "bg": 1312, "fg": [967, 972, 969, 971]}, {"id": "edge", "bg": 1312, "fg": [963, 962]}, {"id": "end_piece", "bg": 1312, "fg": [968, 956, 957, 970]}, {"bg": 1312, "id": "unconnected", "fg": 959}]}, {"id": ["t_water_moving_dp_season_summer", "t_swater_moving_dp_season_summer"], "multitile": true, "fg": 959, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": [{"weight": 1, "sprite": 958}, {"weight": 1, "sprite": 964}]}, {"id": "corner", "bg": 1326, "fg": [965, 961, 960, 966]}, {"id": "t_connection", "bg": 1326, "fg": [967, 972, 969, 971]}, {"id": "edge", "bg": 1326, "fg": [963, 962]}, {"id": "end_piece", "bg": 1326, "fg": [968, 956, 957, 970]}, {"bg": 1326, "id": "unconnected", "fg": 959}]}, {"id": ["t_water_moving_dp_season_autumn", "t_swater_moving_dp_season_autumn"], "multitile": true, "fg": 959, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": [{"weight": 1, "sprite": 958}, {"weight": 1, "sprite": 964}]}, {"id": "corner", "bg": 1313, "fg": [965, 961, 960, 966]}, {"id": "t_connection", "bg": 1313, "fg": [967, 972, 969, 971]}, {"id": "edge", "bg": 1313, "fg": [963, 962]}, {"id": "end_piece", "bg": 1313, "fg": [968, 956, 957, 970]}, {"bg": 1313, "id": "unconnected", "fg": 959}]}, {"id": ["t_water_moving_dp_season_winter", "t_swater_moving_dp_season_winter"], "multitile": true, "fg": 959, "bg": 1321, "additional_tiles": [{"id": "center", "bg": 1321, "fg": [{"weight": 1, "sprite": 958}, {"weight": 1, "sprite": 964}]}, {"id": "corner", "bg": 1321, "fg": [965, 961, 960, 966]}, {"id": "t_connection", "bg": 1321, "fg": [967, 972, 969, 971]}, {"id": "edge", "bg": 1321, "fg": [963, 962]}, {"id": "end_piece", "bg": 1321, "fg": [968, 956, 957, 970]}, {"bg": 1321, "id": "unconnected", "fg": 959}]}, {"id": "t_thconc_floor", "multitile": true, "fg": 982, "additional_tiles": [{"id": "center", "fg": 983}, {"id": "corner", "fg": [979, 977, 987, 978]}, {"id": "t_connection", "fg": [984, 980, 973, 981]}, {"id": "edge", "fg": [986, 988]}, {"id": "end_piece", "fg": [976, 975, 985, 974]}, {"id": "unconnected", "fg": 982}]}, {"id": "t_carpet_green", "multitile": true, "fg": 999, "additional_tiles": [{"id": "center", "fg": 994}, {"id": "corner", "fg": [990, 1000, 998, 996]}, {"id": "t_connection", "fg": [992, 993, 991, 995]}, {"id": "edge", "fg": [1004, 997]}, {"id": "end_piece", "fg": [1002, 1001, 1003, 989]}, {"id": "unconnected", "fg": 999}]}, {"id": "t_door_lab_c", "fg": 1006}, {"id": "t_door_lab_o", "fg": 1005}, {"id": "t_dirtfloor", "multitile": true, "fg": 1021, "additional_tiles": [{"id": "center", "fg": 1015}, {"id": "corner", "fg": [1016, 1020, 1013, 1019]}, {"id": "t_connection", "fg": [1018, 1010, 1022, 1009]}, {"id": "edge", "fg": [1012, 1017]}, {"id": "end_piece", "fg": [1014, 1011, 1007, 1008]}, {"id": "unconnected", "fg": 1021}]}, {"id": "t_concrete_wall", "multitile": true, "fg": 1026, "additional_tiles": [{"id": "center", "fg": 1030}, {"id": "corner", "fg": [1038, 1029, 1037, 1028]}, {"id": "t_connection", "fg": [1033, 1023, 1031, 1027]}, {"id": "edge", "fg": [1036, 1025]}, {"id": "end_piece", "fg": [1035, 1032, 1034, 1024]}, {"id": "unconnected", "fg": 1026}]}, {"id": "t_wall_w", "multitile": true, "fg": 1040, "additional_tiles": [{"id": "center", "fg": 1050}, {"id": "corner", "fg": [1054, 1046, 1049, 1042]}, {"id": "t_connection", "fg": [1041, 1053, 1043, 1039]}, {"id": "edge", "fg": [1044, 1051]}, {"id": "end_piece", "fg": [1052, 1048, 1045, 1047]}, {"id": "unconnected", "fg": 1040}]}, {"id": "t_rock_wall", "multitile": true, "fg": 1055, "additional_tiles": [{"id": "center", "fg": 1064}, {"id": "corner", "fg": [1059, 1067, 1056, 1057]}, {"id": "t_connection", "fg": [1060, 1069, 1070, 1066]}, {"id": "edge", "fg": [1058, 1065]}, {"id": "end_piece", "fg": [1061, 1062, 1063, 1068]}, {"id": "unconnected", "fg": 1055}]}, {"id": "t_rock_floor", "multitile": true, "fg": 1078, "additional_tiles": [{"id": "center", "fg": 1082}, {"id": "corner", "fg": [1080, 1086, 1085, 1084]}, {"id": "t_connection", "fg": [1071, 1076, 1079, 1074]}, {"id": "edge", "fg": [1073, 1072]}, {"id": "end_piece", "fg": [1083, 1081, 1077, 1075]}, {"id": "unconnected", "fg": 1078}]}, {"id": "t_grass_tall", "multitile": true, "fg": 1098, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 1096}, {"id": "corner", "bg": 1312, "fg": [1090, 1094, 1100, 1093]}, {"id": "t_connection", "bg": 1312, "fg": [1092, 1088, 1097, 1101]}, {"id": "edge", "bg": 1312, "fg": [1091, 1089]}, {"id": "end_piece", "bg": 1312, "fg": [1095, 1087, 1099, 1102]}, {"bg": 1312, "id": "unconnected", "fg": 1098}]}, {"id": "t_grass_tall_season_summer", "multitile": true, "fg": 1106, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 1113}, {"id": "corner", "bg": 1326, "fg": [1111, 1115, 1118, 1103]}, {"id": "t_connection", "bg": 1326, "fg": [1110, 1117, 1109, 1114]}, {"id": "edge", "bg": 1326, "fg": [1104, 1116]}, {"id": "end_piece", "bg": 1326, "fg": [1105, 1107, 1108, 1112]}, {"bg": 1326, "id": "unconnected", "fg": 1106}]}, {"id": "t_grass_tall_season_autumn", "multitile": true, "fg": 1132, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 1126}, {"id": "corner", "bg": 1313, "fg": [1119, 1134, 1122, 1124]}, {"id": "t_connection", "bg": 1313, "fg": [1130, 1125, 1127, 1129]}, {"id": "edge", "bg": 1313, "fg": [1120, 1121]}, {"id": "end_piece", "bg": 1313, "fg": [1133, 1131, 1128, 1123]}, {"bg": 1313, "id": "unconnected", "fg": 1132}]}, {"id": "t_grass_tall_season_winter", "fg": 649}, {"id": "f_grass_tall", "multitile": true, "fg": 1098, "additional_tiles": [{"id": "center", "fg": 1096}, {"id": "corner", "fg": [1090, 1094, 1100, 1093]}, {"id": "t_connection", "fg": [1092, 1088, 1097, 1101]}, {"id": "edge", "fg": [1091, 1089]}, {"id": "end_piece", "fg": [1095, 1087, 1099, 1102]}, {"id": "unconnected", "fg": 1098}]}, {"id": "f_grass_tall_summer", "multitile": true, "fg": 1106, "additional_tiles": [{"id": "center", "fg": 1113}, {"id": "corner", "fg": [1111, 1115, 1118, 1103]}, {"id": "t_connection", "fg": [1110, 1117, 1109, 1114]}, {"id": "edge", "fg": [1104, 1116]}, {"id": "end_piece", "fg": [1105, 1107, 1108, 1112]}, {"id": "unconnected", "fg": 1106}]}, {"id": "f_grass_tall_autumn", "multitile": true, "fg": 1132, "additional_tiles": [{"id": "center", "fg": 1126}, {"id": "corner", "fg": [1119, 1134, 1122, 1124]}, {"id": "t_connection", "fg": [1130, 1125, 1127, 1129]}, {"id": "edge", "fg": [1120, 1121]}, {"id": "end_piece", "fg": [1133, 1131, 1128, 1123]}, {"id": "unconnected", "fg": 1132}]}, {"id": "t_grass_long", "multitile": true, "fg": 1140, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 1146}, {"id": "corner", "bg": 1312, "fg": [1141, 1144, 1135, 1139]}, {"id": "t_connection", "bg": 1312, "fg": [1142, 1147, 1136, 1150]}, {"id": "edge", "bg": 1312, "fg": [1148, 1138]}, {"id": "end_piece", "bg": 1312, "fg": [1143, 1137, 1149, 1145]}, {"bg": 1312, "id": "unconnected", "fg": 1140}]}, {"id": "t_grass_long_season_autumn", "multitile": true, "fg": 1166, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 1159}, {"id": "corner", "bg": 1313, "fg": [1158, 1165, 1164, 1161]}, {"id": "t_connection", "bg": 1313, "fg": [1152, 1151, 1156, 1163]}, {"id": "edge", "bg": 1313, "fg": [1154, 1157]}, {"id": "end_piece", "bg": 1313, "fg": [1153, 1160, 1155, 1162]}, {"bg": 1313, "id": "unconnected", "fg": 1166}]}, {"id": "t_grass_long_season_summer", "multitile": true, "fg": 1179, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 1176}, {"id": "corner", "bg": 1326, "fg": [1180, 1173, 1169, 1174]}, {"id": "t_connection", "bg": 1326, "fg": [1172, 1177, 1178, 1171]}, {"id": "edge", "bg": 1326, "fg": [1182, 1170]}, {"id": "end_piece", "bg": 1326, "fg": [1168, 1175, 1181, 1167]}, {"bg": 1326, "id": "unconnected", "fg": 1179}]}, {"id": "t_grass_long_season_winter", "fg": 649}, {"id": "f_grass_long", "multitile": true, "fg": 1140, "additional_tiles": [{"id": "center", "fg": 1146}, {"id": "corner", "fg": [1141, 1144, 1135, 1139]}, {"id": "t_connection", "fg": [1142, 1147, 1136, 1150]}, {"id": "edge", "fg": [1148, 1138]}, {"id": "end_piece", "fg": [1143, 1137, 1149, 1145]}, {"id": "unconnected", "fg": 1140}]}, {"id": "f_grass_long_season_autumn", "multitile": true, "fg": 1166, "additional_tiles": [{"id": "center", "fg": 1159}, {"id": "corner", "fg": [1158, 1165, 1164, 1161]}, {"id": "t_connection", "fg": [1152, 1151, 1156, 1163]}, {"id": "edge", "fg": [1154, 1157]}, {"id": "end_piece", "fg": [1153, 1160, 1155, 1162]}, {"id": "unconnected", "fg": 1166}]}, {"id": "f_grass_long_season_summer", "multitile": true, "fg": 1179, "additional_tiles": [{"id": "center", "fg": 1176}, {"id": "corner", "fg": [1180, 1173, 1169, 1174]}, {"id": "t_connection", "fg": [1172, 1177, 1178, 1171]}, {"id": "edge", "fg": [1182, 1170]}, {"id": "end_piece", "fg": [1168, 1175, 1181, 1167]}, {"id": "unconnected", "fg": 1179}]}, {"id": ["t_shrub_lilac"], "fg": 1186, "bg": 1312}, {"id": ["t_shrub_lilac_harvested"], "fg": 1183, "bg": 1312}, {"id": "t_shrub_lilac_season_summer", "fg": 1185, "bg": 1326}, {"id": "t_shrub_lilac_season_autumn", "fg": 1183, "bg": 1313}, {"id": "t_shrub_lilac_season_winter", "fg": 1184, "bg": 649}, {"id": "t_elevator", "fg": [{"weight": 100, "sprite": 1187}, {"weight": 100, "sprite": 1188}]}, {"id": "t_moss", "fg": 1189}, {"id": "t_moss_season_winter", "fg": 649}, {"id": "t_scrap_floor", "multitile": true, "fg": 1199, "additional_tiles": [{"id": "center", "fg": 1196}, {"id": "corner", "fg": [1194, 1201, 1190, 1205]}, {"id": "t_connection", "fg": [1193, 1204, 1192, 1195]}, {"id": "edge", "fg": [1203, 1197]}, {"id": "end_piece", "fg": [1200, 1191, 1202, 1198]}, {"id": "unconnected", "fg": 1199}]}, {"id": "t_grass_dead", "multitile": true, "fg": 1220, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 1216}, {"id": "corner", "bg": 1312, "fg": [1221, 1212, 1213, 1208]}, {"id": "t_connection", "bg": 1312, "fg": [1215, 1210, 1218, 1209]}, {"id": "edge", "bg": 1312, "fg": [1207, 1214]}, {"id": "end_piece", "bg": 1312, "fg": [1219, 1206, 1211, 1217]}, {"bg": 1312, "id": "unconnected", "fg": 1220}]}, {"id": "t_grass_dead_season_summer", "multitile": true, "fg": 1251, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 1250}, {"id": "corner", "bg": 1326, "fg": [1238, 1239, 1243, 1241]}, {"id": "t_connection", "bg": 1326, "fg": [1249, 1253, 1247, 1252]}, {"id": "edge", "bg": 1326, "fg": [1242, 1248]}, {"id": "end_piece", "bg": 1326, "fg": [1245, 1246, 1244, 1240]}, {"bg": 1326, "id": "unconnected", "fg": 1251}]}, {"id": "t_grass_dead_season_autumn", "multitile": true, "fg": 1223, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 1237}, {"id": "corner", "bg": 1313, "fg": [1227, 1228, 1229, 1235]}, {"id": "t_connection", "bg": 1313, "fg": [1225, 1230, 1231, 1232]}, {"id": "edge", "bg": 1313, "fg": [1222, 1234]}, {"id": "end_piece", "bg": 1313, "fg": [1236, 1226, 1224, 1233]}, {"bg": 1313, "id": "unconnected", "fg": 1223}]}, {"id": "t_grass_dead_season_winter", "multitile": true, "fg": 675, "bg": 1321, "additional_tiles": [{"id": "center", "bg": 1321, "fg": [{"weight": 1, "sprite": 682}, {"weight": 1, "sprite": 674}, {"weight": 1, "sprite": 673}, {"weight": 1, "sprite": 671}]}, {"id": "corner", "bg": 1321, "fg": [678, 677, 684, 669]}, {"id": "t_connection", "bg": 1321, "fg": [668, 680, 681, 679]}, {"id": "edge", "bg": 1321, "fg": [683, 676]}, {"id": "end_piece", "bg": 1321, "fg": [667, 672, 670, 666]}, {"bg": 1321, "id": "unconnected", "fg": 675}]}, {"id": ["t_water_sh", "t_swater_sh"], "multitile": true, "fg": 1267, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": [{"weight": 1, "sprite": 1263}, {"weight": 1, "sprite": 1270}, {"weight": 1, "sprite": 1265}, {"weight": 1, "sprite": 1257}]}, {"id": "corner", "bg": 1312, "fg": [1258, 1261, 1272, 1269]}, {"id": "t_connection", "bg": 1312, "fg": [1259, 1264, 1268, 1271]}, {"id": "edge", "bg": 1312, "fg": [1256, 1260]}, {"id": "end_piece", "bg": 1312, "fg": [1255, 1262, 1254, 1266]}, {"bg": 1312, "id": "unconnected", "fg": 1267}]}, {"id": ["t_water_sh_season_summer", "t_swater_sh_season_summer"], "multitile": true, "fg": 1267, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": [{"weight": 1, "sprite": 1263}, {"weight": 1, "sprite": 1270}, {"weight": 1, "sprite": 1265}]}, {"id": "corner", "bg": 1326, "fg": [1258, 1261, 1272, 1269]}, {"id": "t_connection", "bg": 1326, "fg": [1259, 1264, 1268, 1271]}, {"id": "edge", "bg": 1326, "fg": [1256, 1260]}, {"id": "end_piece", "bg": 1326, "fg": [1255, 1262, 1254, 1266]}, {"bg": 1326, "id": "unconnected", "fg": 1267}]}, {"id": ["t_water_sh_season_autumn", "t_swater_sh_season_autumn"], "multitile": true, "fg": 1267, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": [{"weight": 1, "sprite": 1263}, {"weight": 1, "sprite": 1270}, {"weight": 1, "sprite": 1265}]}, {"id": "corner", "bg": 1313, "fg": [1258, 1261, 1272, 1269]}, {"id": "t_connection", "bg": 1313, "fg": [1259, 1264, 1268, 1271]}, {"id": "edge", "bg": 1313, "fg": [1256, 1260]}, {"id": "end_piece", "bg": 1313, "fg": [1255, 1262, 1254, 1266]}, {"bg": 1313, "id": "unconnected", "fg": 1267}]}, {"id": ["t_water_sh_season_winter", "t_swater_sh_season_winter"], "multitile": true, "fg": 1267, "bg": 682, "additional_tiles": [{"id": "center", "bg": 682, "fg": [{"weight": 1, "sprite": 1263}, {"weight": 1, "sprite": 1270}, {"weight": 1, "sprite": 1265}]}, {"id": "corner", "bg": 682, "fg": [1258, 1261, 1272, 1269]}, {"id": "t_connection", "bg": 682, "fg": [1259, 1264, 1268, 1271]}, {"id": "edge", "bg": 682, "fg": [1256, 1260]}, {"id": "end_piece", "bg": 682, "fg": [1255, 1262, 1254, 1266]}, {"bg": 682, "id": "unconnected", "fg": 1267}]}, {"id": "t_reinforced_glass", "multitile": true, "fg": 1284, "additional_tiles": [{"id": "center", "fg": 1275}, {"id": "corner", "fg": [1288, 1283, 1278, 1282]}, {"id": "t_connection", "fg": [1285, 1286, 1277, 1281]}, {"id": "edge", "fg": [1274, 1287]}, {"id": "end_piece", "fg": [1280, 1279, 1273, 1276]}, {"id": "unconnected", "fg": 1284}]}, {"id": "t_carpet_yellow", "multitile": true, "fg": 1290, "additional_tiles": [{"id": "center", "fg": 1303}, {"id": "corner", "fg": [1289, 1298, 1301, 1294]}, {"id": "t_connection", "fg": [1304, 1292, 1291, 1297]}, {"id": "edge", "fg": [1296, 1302]}, {"id": "end_piece", "fg": [1300, 1299, 1295, 1293]}, {"id": "unconnected", "fg": 1290}]}, {"id": "t_dirt", "bg": [{"weight": 100, "sprite": 1312}, {"weight": 100, "sprite": 1315}, {"weight": 100, "sprite": 1309}, {"weight": 100, "sprite": 1318}]}, {"id": "t_dirt_season_autumn", "bg": [{"weight": 100, "sprite": 1313}, {"weight": 100, "sprite": 1305}, {"weight": 100, "sprite": 1319}, {"weight": 100, "sprite": 1308}]}, {"id": "t_dirt_season_summer", "bg": [{"weight": 100, "sprite": 1326}, {"weight": 100, "sprite": 1306}, {"weight": 100, "sprite": 1314}, {"weight": 100, "sprite": 1327}]}, {"id": "t_dirt_season_winter", "bg": [{"weight": 100, "sprite": 1321}, {"weight": 100, "sprite": 1317}, {"weight": 100, "sprite": 1316}, {"weight": 100, "sprite": 1324}]}, {"id": "t_door_metal_c_peep", "fg": 1328}, {"id": "t_shrub", "fg": 1329, "bg": 1312}, {"id": "t_shrub_season_summer", "fg": 1329, "bg": 1326}, {"id": "t_shrub_season_autumn", "fg": 1329, "bg": 1313}, {"id": "t_shrub_season_winter", "fg": 1330, "bg": 649}, {"id": "t_pit", "fg": 1331, "bg": [{"weight": 100, "sprite": 1312}, {"weight": 100, "sprite": 1315}]}, {"id": "t_pit_season_summer", "fg": 1331, "bg": [{"weight": 100, "sprite": 1326}, {"weight": 100, "sprite": 1306}]}, {"id": "t_pit_season_autumn", "fg": 1331, "bg": [{"weight": 100, "sprite": 1313}, {"weight": 100, "sprite": 1305}]}, {"id": "t_door_c", "fg": 1332}, {"id": "t_door_locked", "fg": 1334}, {"id": "t_door_o", "fg": 1333}, {"id": "t_door_b", "fg": 1335}, {"id": "t_scrap_wall", "multitile": true, "fg": 1350, "additional_tiles": [{"id": "center", "fg": 1347}, {"id": "corner", "fg": [1337, 1351, 1349, 1352]}, {"id": "t_connection", "fg": [1342, 1345, 1341, 1339]}, {"id": "edge", "fg": [1340, 1344]}, {"id": "end_piece", "fg": [1346, 1338, 1336, 1343]}, {"id": "unconnected", "fg": 1350}]}, {"id": "t_clay", "multitile": true, "fg": 1357, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": 1364}, {"id": "corner", "bg": 1312, "fg": [1359, 1354, 1356, 1365]}, {"id": "t_connection", "bg": 1312, "fg": [1367, 1366, 1358, 1362]}, {"id": "edge", "bg": 1312, "fg": [1353, 1355]}, {"id": "end_piece", "bg": 1312, "fg": [1363, 1368, 1361, 1360]}, {"bg": 1312, "id": "unconnected", "fg": 1357}]}, {"id": "t_clay_season_summer", "multitile": true, "fg": 1357, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": 1364}, {"id": "corner", "bg": 1326, "fg": [1359, 1354, 1356, 1365]}, {"id": "t_connection", "bg": 1326, "fg": [1367, 1366, 1358, 1362]}, {"id": "edge", "bg": 1326, "fg": [1353, 1355]}, {"id": "end_piece", "bg": 1326, "fg": [1363, 1368, 1361, 1360]}, {"bg": 1326, "id": "unconnected", "fg": 1357}]}, {"id": "t_clay_season_autumn", "multitile": true, "fg": 1357, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": 1364}, {"id": "corner", "bg": 1313, "fg": [1359, 1354, 1356, 1365]}, {"id": "t_connection", "bg": 1313, "fg": [1367, 1366, 1358, 1362]}, {"id": "edge", "bg": 1313, "fg": [1353, 1355]}, {"id": "end_piece", "bg": 1313, "fg": [1363, 1368, 1361, 1360]}, {"bg": 1313, "id": "unconnected", "fg": 1357}]}, {"id": "t_clay_season_winter", "multitile": true, "fg": 1357, "bg": 1321, "additional_tiles": [{"id": "center", "bg": 1321, "fg": 1364}, {"id": "corner", "bg": 1321, "fg": [1359, 1354, 1356, 1365]}, {"id": "t_connection", "bg": 1321, "fg": [1367, 1366, 1358, 1362]}, {"id": "edge", "bg": 1321, "fg": [1353, 1355]}, {"id": "end_piece", "bg": 1321, "fg": [1363, 1368, 1361, 1360]}, {"bg": 1321, "id": "unconnected", "fg": 1357}]}, {"id": ["t_shrub_hydrangea"], "fg": 1371, "bg": 1312}, {"id": ["t_shrub_hydrangea_harvested"], "fg": 1372, "bg": 1312}, {"id": "t_shrub_hydrangea_season_summer", "fg": 1369, "bg": 1326}, {"id": "t_shrub_hydrangea_season_autumn", "fg": 1371, "bg": 1313}, {"id": "t_shrub_hydrangea_season_winter", "fg": 1370, "bg": 649}, {"id": "t_bars", "fg": 1373}, {"id": ["t_shrub_grape"], "fg": 1377, "bg": 1312}, {"id": ["t_shrub_grape_harvested"], "fg": 1374, "bg": 1326}, {"id": "t_shrub_grape_season_summer", "fg": 1376, "bg": 1326}, {"id": "t_shrub_grape_season_autumn", "fg": 1377, "bg": 1313}, {"id": "t_shrub_grape_season_winter", "fg": 1375, "bg": 649}, {"id": "t_door_glass_o", "fg": 1378}, {"id": ["t_shrub_rose"], "fg": 1381, "bg": 1312}, {"id": "t_shrub_rose_season_summer", "fg": 1381, "bg": 1326}, {"id": "t_shrub_rose_harvested", "fg": 1381, "bg": 1313}, {"id": "t_shrub_rose_season_autumn", "fg": 1379, "bg": 1313}, {"id": "t_shrub_rose_season_winter", "fg": 1380, "bg": 649}, {"id": "t_wall", "multitile": true, "fg": 1394, "additional_tiles": [{"id": "center", "fg": 1389}, {"id": "corner", "fg": [1395, 1387, 1384, 1393]}, {"id": "t_connection", "fg": [1391, 1386, 1397, 1382]}, {"id": "edge", "fg": [1383, 1385]}, {"id": "end_piece", "fg": [1390, 1396, 1392, 1388]}, {"id": "unconnected", "fg": 1394}]}, {"id": "t_wall_p", "multitile": true, "fg": 1407, "additional_tiles": [{"id": "center", "fg": 1412}, {"id": "corner", "fg": [1400, 1403, 1408, 1405]}, {"id": "t_connection", "fg": [1410, 1404, 1406, 1398]}, {"id": "edge", "fg": [1411, 1399]}, {"id": "end_piece", "fg": [1409, 1401, 1413, 1402]}, {"id": "unconnected", "fg": 1407}]}, {"id": "t_wall_log", "multitile": true, "fg": 1421, "bg": 1312, "additional_tiles": [{"id": "center", "fg": 1425}, {"id": "corner", "fg": [1426, 1415, 1429, 1423]}, {"id": "t_connection", "fg": [1420, 1417, 1428, 1419]}, {"id": "edge", "bg": 1312, "fg": [1416, 1418]}, {"id": "end_piece", "bg": 1312, "fg": [1427, 1422, 1424, 1414]}, {"bg": 1312, "id": "unconnected", "fg": 1421}]}, {"id": "t_wall_g", "multitile": true, "fg": 1435, "additional_tiles": [{"id": "center", "fg": 1439}, {"id": "corner", "fg": [1445, 1442, 1436, 1444]}, {"id": "t_connection", "fg": [1440, 1431, 1441, 1437]}, {"id": "edge", "fg": [1432, 1433]}, {"id": "end_piece", "fg": [1443, 1438, 1434, 1430]}, {"id": "unconnected", "fg": 1435}]}, {"id": "t_door_boarded", "fg": 1446}, {"id": "t_door_boarded_damaged", "fg": 1447}, {"id": ["t_water_pool", "t_water_pool_shallow"], "multitile": true, "fg": 1455, "additional_tiles": [{"id": "center", "fg": [{"weight": 1, "sprite": 1263}, {"weight": 1, "sprite": 1270}, {"weight": 1, "sprite": 1265}]}, {"id": "corner", "fg": [1450, 1459, 1458, 1452]}, {"id": "t_connection", "fg": [1454, 1451, 1456, 1460]}, {"id": "edge", "fg": [1457, 1449]}, {"id": "end_piece", "fg": [1461, 1462, 1448, 1453]}, {"id": "unconnected", "fg": 1455}]}, {"id": "t_pavement", "fg": 1463}, {"id": "t_pavement_season_winter", "fg": 682}, {"id": ["t_water_dp", "t_swater_dp"], "multitile": true, "fg": 1471, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": [{"weight": 1, "sprite": 1473}, {"weight": 1, "sprite": 1474}, {"weight": 1, "sprite": 1481}, {"weight": 1, "sprite": 1479}]}, {"id": "corner", "bg": 1312, "fg": [1480, 1464, 1466, 1475]}, {"id": "t_connection", "bg": 1312, "fg": [1468, 1476, 1478, 1467]}, {"id": "edge", "bg": 1312, "fg": [1470, 1482]}, {"id": "end_piece", "bg": 1312, "fg": [1477, 1472, 1469, 1465]}, {"bg": 1312, "id": "unconnected", "fg": 1471}]}, {"id": ["t_water_dp_season_summer", "t_swater_dp_season_summer"], "multitile": true, "fg": 1471, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": [{"weight": 1, "sprite": 1473}, {"weight": 1, "sprite": 1474}, {"weight": 1, "sprite": 1481}]}, {"id": "corner", "bg": 1326, "fg": [1480, 1464, 1466, 1475]}, {"id": "t_connection", "bg": 1326, "fg": [1468, 1476, 1478, 1467]}, {"id": "edge", "bg": 1326, "fg": [1470, 1482]}, {"id": "end_piece", "bg": 1326, "fg": [1477, 1472, 1469, 1465]}, {"bg": 1326, "id": "unconnected", "fg": 1471}]}, {"id": ["t_water_dp_season_autumn", "t_swater_dp_season_autumn"], "multitile": true, "fg": 1471, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": [{"weight": 1, "sprite": 1473}, {"weight": 1, "sprite": 1474}, {"weight": 1, "sprite": 1481}]}, {"id": "corner", "bg": 1313, "fg": [1480, 1464, 1466, 1475]}, {"id": "t_connection", "bg": 1313, "fg": [1468, 1476, 1478, 1467]}, {"id": "edge", "bg": 1313, "fg": [1470, 1482]}, {"id": "end_piece", "bg": 1313, "fg": [1477, 1472, 1469, 1465]}, {"bg": 1313, "id": "unconnected", "fg": 1471}]}, {"id": ["t_water_dp_season_winter", "t_swater_dp_season_winter"], "multitile": true, "fg": 1471, "bg": 682, "additional_tiles": [{"id": "center", "bg": 682, "fg": [{"weight": 1, "sprite": 1473}, {"weight": 1, "sprite": 1474}, {"weight": 1, "sprite": 1481}]}, {"id": "corner", "bg": 682, "fg": [1480, 1464, 1466, 1475]}, {"id": "t_connection", "bg": 682, "fg": [1468, 1476, 1478, 1467]}, {"id": "edge", "bg": 682, "fg": [1470, 1482]}, {"id": "end_piece", "bg": 682, "fg": [1477, 1472, 1469, 1465]}, {"bg": 682, "id": "unconnected", "fg": 1471}]}, {"id": ["t_linoleum_gray", "t_linoluem_gray_no_roof"], "multitile": true, "fg": 1486, "additional_tiles": [{"id": "center", "fg": 1485}, {"id": "corner", "fg": [1494, 1487, 1493, 1489]}, {"id": "t_connection", "fg": [1490, 1484, 1483, 1496]}, {"id": "edge", "fg": [1488, 1495]}, {"id": "end_piece", "fg": [1492, 1497, 1498, 1491]}, {"id": "unconnected", "fg": 1486}]}, {"id": "t_grass", "multitile": true, "fg": 1504, "bg": 1312, "additional_tiles": [{"id": "center", "bg": 1312, "fg": [{"weight": 1, "sprite": 1505}, {"weight": 1, "sprite": 1511}, {"weight": 1, "sprite": 1508}, {"weight": 1, "sprite": 1499}]}, {"id": "corner", "bg": 1312, "fg": [1514, 1507, 1512, 1503]}, {"id": "t_connection", "bg": 1312, "fg": [1501, 1516, 1500, 1517]}, {"id": "edge", "bg": 1312, "fg": [1513, 1502]}, {"id": "end_piece", "bg": 1312, "fg": [1510, 1515, 1506, 1509]}, {"bg": 1312, "id": "unconnected", "fg": 1504}]}, {"id": "t_grass_season_summer", "multitile": true, "fg": 1555, "bg": 1326, "additional_tiles": [{"id": "center", "bg": 1326, "fg": [{"weight": 1, "sprite": 1547}, {"weight": 1, "sprite": 1546}, {"weight": 1, "sprite": 1552}, {"weight": 1, "sprite": 1548}]}, {"id": "corner", "bg": 1326, "fg": [1554, 1538, 1540, 1539]}, {"id": "t_connection", "bg": 1326, "fg": [1541, 1543, 1553, 1551]}, {"id": "edge", "bg": 1326, "fg": [1545, 1544]}, {"id": "end_piece", "bg": 1326, "fg": [1537, 1550, 1549, 1542]}, {"bg": 1326, "id": "unconnected", "fg": 1555}]}, {"id": "t_grass_season_autumn", "multitile": true, "fg": 1519, "bg": 1313, "additional_tiles": [{"id": "center", "bg": 1313, "fg": [{"weight": 1, "sprite": 1528}, {"weight": 1, "sprite": 1532}, {"weight": 1, "sprite": 1527}, {"weight": 1, "sprite": 1535}]}, {"id": "corner", "bg": 1313, "fg": [1534, 1518, 1536, 1530]}, {"id": "t_connection", "bg": 1313, "fg": [1531, 1521, 1529, 1526]}, {"id": "edge", "bg": 1313, "fg": [1523, 1522]}, {"id": "end_piece", "bg": 1313, "fg": [1525, 1524, 1520, 1533]}, {"bg": 1313, "id": "unconnected", "fg": 1519}]}, {"id": "t_grass_season_winter", "multitile": true, "fg": 675, "bg": 1321, "additional_tiles": [{"id": "center", "bg": 1321, "fg": [{"weight": 1, "sprite": 682}, {"weight": 1, "sprite": 674}, {"weight": 1, "sprite": 673}, {"weight": 1, "sprite": 671}]}, {"id": "corner", "bg": 1321, "fg": [678, 677, 684, 669]}, {"id": "t_connection", "bg": 1321, "fg": [668, 680, 681, 679]}, {"id": "edge", "bg": 1321, "fg": [683, 676]}, {"id": "end_piece", "bg": 1321, "fg": [667, 672, 670, 666]}, {"bg": 1321, "id": "unconnected", "fg": 675}]}, {"id": "t_stairs_down", "fg": 1556}, {"id": "t_wood_stairs_down", "fg": 1557}, {"id": "t_floor_wax", "multitile": true, "fg": 1567, "additional_tiles": [{"id": "center", "fg": 1570}, {"id": "corner", "fg": [1572, 1559, 1566, 1563]}, {"id": "t_connection", "fg": [1568, 1573, 1560, 1561]}, {"id": "edge", "fg": [1564, 1569]}, {"id": "end_piece", "fg": [1558, 1571, 1562, 1565]}, {"id": "unconnected", "fg": 1567}]}, {"id": "t_wall_r", "multitile": true, "fg": 1574, "additional_tiles": [{"id": "center", "fg": 1581}, {"id": "corner", "fg": [1583, 1582, 1587, 1588]}, {"id": "t_connection", "fg": [1577, 1579, 1580, 1584]}, {"id": "edge", "fg": [1589, 1586]}, {"id": "end_piece", "fg": [1578, 1585, 1576, 1575]}, {"id": "unconnected", "fg": 1574}]}, {"id": "t_concrete", "multitile": true, "fg": 1597, "additional_tiles": [{"id": "center", "fg": 1591}, {"id": "corner", "fg": [1602, 1599, 1590, 1600]}, {"id": "t_connection", "fg": [1598, 1592, 1604, 1594]}, {"id": "edge", "fg": [1596, 1601]}, {"id": "end_piece", "fg": [1595, 1593, 1605, 1603]}, {"id": "unconnected", "fg": 1597}]}, {"id": "t_concrete_season_winter", "fg": 682}, {"id": "t_wall_resin", "multitile": true, "fg": 1614, "additional_tiles": [{"id": "center", "fg": 1621}, {"id": "corner", "fg": [1609, 1620, 1611, 1617]}, {"id": "t_connection", "fg": [1606, 1612, 1608, 1610]}, {"id": "edge", "fg": [1623, 1622]}, {"id": "end_piece", "fg": [1619, 1613, 1615, 1616]}, {"id": "unconnected", "fg": 1614}]}, {"id": "t_resin_hole_c", "fg": 1618}, {"id": "t_resin_hole_o", "fg": 1607}, {"id": "t_ladder_down", "fg": 1624}, {"id": "tr_nailboard", "fg": 1625, "bg": 485}, {"id": "animation_hit", "fg": 1626}, {"id": ["overlay_effects_bleed"], "fg": 1632}, {"id": ["overlay_effects_deaf"], "fg": 1627}, {"id": ["overlay_effects_downed"], "fg": 1634}, {"id": ["overlay_effects_grabbed"], "fg": 1633}, {"id": ["overlay_effects_winded"], "fg": 1631}, {"id": ["overlay_effects_hot"], "fg": 1628}, {"id": ["overlay_effects_cold"], "fg": 1637}, {"id": ["overlay_male_crouch", "overlay_female_crouch"], "fg": 1630}, {"id": ["overlay_male_run", "overlay_female_run"], "fg": 1635}, {"id": ["overlay_hostile_sees_player"], "fg": 1636}, {"id": ["zombie_revival_indicator"], "fg": 1629}, {"id": "cursor", "fg": 1638}, {"id": "highlight", "fg": 1641}, {"id": "highlight_item", "fg": 1642}, {"id": "line_target", "fg": 1639}, {"id": "line_trail", "fg": 1640}, {"id": "animation_line", "fg": 1643}, {"id": "mon_pig", "fg": [{"weight": 8, "sprite": 1646}, {"weight": 3, "sprite": 1645}, {"weight": 1, "sprite": 1644}], "bg": 1670}, {"id": "mon_piglet", "fg": 1647, "bg": 1671}, {"id": "mon_deer_mouse", "fg": 1648, "bg": 1671}, {"id": "mon_locust_nymph", "fg": 1649, "bg": 1671}, {"id": "mon_skittering_plague", "fg": 1650, "bg": 1670}, {"id": "mon_black_rat", "fg": 1651, "bg": 1671}, {"id": "mon_zolf", "fg": 1652, "bg": 1670}, {"id": "mon_dog", "fg": 1653, "bg": 1670}, {"id": "mon_dog_skeleton", "fg": 1657, "bg": 1670}, {"id": "mon_zombie_dog", "fg": [{"weight": 1, "sprite": 1658}, {"weight": 1, "sprite": 1659}], "bg": 1670}, {"id": "mon_dog_beagle", "fg": 1656, "bg": 1671}, {"id": "mon_dog_gshepherd", "fg": 1655, "bg": 1670}, {"id": "mon_dog_boxer", "fg": 1654, "bg": 1670}, {"id": "mon_dog_dachshund", "fg": 1660, "bg": 1670}, {"id": "mon_blob", "fg": 1661, "bg": 1670}, {"id": "mon_squirrel_red", "fg": 1662, "bg": 1671}, {"id": "mon_plague_vector", "fg": 1663, "bg": 1670}, {"id": "mon_blob_small", "fg": [{"weight": 1, "sprite": 1664}, {"weight": 1, "sprite": 1665}], "bg": 1671}, {"id": "mon_dragonfly", "fg": 1666, "bg": 1671}, {"id": "mon_zombie_child", "fg": [{"weight": 1, "sprite": 1667}, {"weight": 1, "sprite": 1668}], "bg": 1671}, {"id": "mon_plague_nymph", "fg": 1669, "bg": 1671}, {"id": "mon_squirrel", "fg": 1672, "bg": 1671}, {"id": "mon_giant_cockroach", "fg": 1673, "bg": 1670}, {"id": "mon_zombie_pig", "fg": 1674, "bg": 1670}, {"id": "mon_rabbit", "fg": 1675, "bg": 1671}, {"id": "mon_zombeaver", "fg": 1676, "bg": 1671}, {"id": "mon_ant", "fg": 1677, "bg": 1670}, {"id": "mon_ant_acid", "fg": 1682, "bg": 1670}, {"id": "corpse_mon_ant", "fg": 1684}, {"id": "corpse_mon_ant_acid", "fg": 1679}, {"id": "mon_ant_larva", "fg": 1678, "bg": 1671}, {"id": "mon_ant_acid_larva", "fg": 1680, "bg": 1671}, {"id": "corpse_mon_ant_larva", "fg": 1681}, {"id": "corpse_mon_ant_acid_larva", "fg": 1683}, {"id": "mon_centipede_giant", "fg": 1685, "bg": 1670}, {"id": "mon_cat", "fg": [{"weight": 1, "sprite": 1686}, {"weight": 1, "sprite": 1687}], "bg": 1671}, {"id": "mon_beaver", "fg": 1688, "bg": 1671}, {"id": "mon_wolf", "fg": 1689, "bg": 1670}, {"id": "mon_otter", "fg": 1690, "bg": 1671}, {"id": "mon_giant_cockroach_nymph", "fg": 1691, "bg": 1671}, {"id": "mon_duck", "fg": 1692, "bg": 1671}, {"id": "mon_mosquito", "fg": 1693, "bg": 1671}, {"id": "mon_locust", "fg": 1694, "bg": 1670}, {"id": "mon_pregnant_giant_cockroach", "fg": 1695, "bg": 1670}, {"id": "mon_dermatik_larva", "fg": 1696, "bg": 1671}, {"id": "mon_bear_cub", "fg": 1697, "bg": 1671}, {"id": "mon_wasp_small", "fg": 1698, "bg": 1671}, {"id": "fd_fire", "fg": 1699}], "//": "range 1 to 1712"}, {"file": "tall.png", "tiles": [{"id": "f_scrap_antenna", "animated": true, "fg": [{"weight": 15, "sprite": 1718}, {"weight": 15, "sprite": 1719}, {"weight": 15, "sprite": 1714}, {"weight": 15, "sprite": 1713}, {"weight": 15, "sprite": 1716}, {"weight": 15, "sprite": 1715}], "rotates": false}, {"id": "f_bookcase", "fg": 1720}, {"id": "f_arcade_machine", "fg": 1721}, {"id": "f_floor_lamp", "fg": 1722}, {"id": "f_dryer", "fg": 1723}, {"id": "f_dresser", "fg": 1724}, {"id": "f_crate_c", "fg": 1726}, {"id": "f_crate_o", "fg": 1725}, {"id": "f_alien_tendril", "fg": 1729}, {"id": "f_alien_zapper", "fg": 1730}, {"id": ["f_alien_pod", "f_alien_pod_organ"], "fg": 1727}, {"id": "f_alien_pod_resin", "fg": 1728}, {"id": "f_glass_cabinet", "fg": 1731}, {"id": "f_machinery_old", "fg": 1736}, {"id": "f_machinery_electronic", "fg": 1733}, {"id": "f_machinery_heavy", "fg": 1732}, {"id": "f_machinery_light", "fg": [{"weight": 100, "sprite": 1734}, {"weight": 100, "sprite": 1735}]}, {"id": "f_shower", "fg": 1737}, {"id": "f_console", "multitile": true, "fg": 1767, "additional_tiles": [{"id": "center", "fg": 1747}, {"id": "corner", "fg": [1763, 1764, 1756, 1741]}, {"id": "t_connection", "fg": [1743, 1761, 1766, 1765]}, {"id": "edge", "fg": [1762, 1744]}, {"id": "end_piece", "fg": [1760, 1752, 1738, 1749]}, {"id": "unconnected", "fg": 1767}]}, {"id": "f_console_broken", "multitile": true, "fg": 1758, "additional_tiles": [{"id": "center", "fg": 1754}, {"id": "corner", "fg": [1748, 1759, 1745, 1757]}, {"id": "t_connection", "fg": [1755, 1753, 1768, 1769]}, {"id": "edge", "fg": [1750, 1742]}, {"id": "end_piece", "fg": [1739, 1751, 1746, 1740]}, {"id": "unconnected", "fg": 1758}]}, {"id": "f_standing_tank", "fg": 1770}, {"id": "f_bigmirror", "fg": 1771}, {"id": "f_glass_fridge", "fg": 1772}, {"id": "f_cattails_season_spring", "fg": 1776, "rotates": false}, {"id": "f_cattails_season_summer", "fg": 1774, "rotates": false}, {"id": "f_cattails_season_autumn", "fg": 1775, "rotates": false}, {"id": "f_cattails_season_winter", "fg": 1773, "rotates": false}, {"id": "f_workbench", "fg": 1777}, {"id": "f_dumpster", "multitile": true, "fg": 1780, "additional_tiles": [{"id": "edge", "fg": [1781, 1784]}, {"id": "end_piece", "fg": [1778, 1782, 1783, 1779]}, {"id": "unconnected", "fg": 1780}]}, {"id": "f_washer", "fg": 1785}, {"id": "f_fireplace", "fg": 1786}, {"id": "f_home_furnace", "fg": 1787}, {"id": "f_locker", "fg": 1788}, {"id": "f_statue", "fg": 1789}, {"id": "f_woodstove", "fg": 1790}, {"id": "f_brazier", "fg": 1791}, {"id": "f_birdbath", "fg": 1792}, {"id": "f_rack_coat", "fg": 1793}, {"id": "f_water_heater", "fg": 1794}, {"id": "f_oven", "fg": 1795}, {"id": "player_male", "fg": 1930}, {"id": "npc_male", "fg": 1930}, {"id": "npc_female", "fg": 1931}, {"id": "player_female", "fg": 1931}, {"id": "t_gutter_downspout", "fg": 1797}, {"id": "t_utility_light", "fg": 1798}, {"id": "t_little_column", "fg": 1799, "bg": 1805}, {"id": "t_machinery_heavy", "fg": 1800, "bg": 1805}, {"id": "t_atm", "fg": 1801, "bg": 1805}, {"id": "t_column", "fg": 1802, "bg": 1805}, {"id": "t_machinery_electronic", "fg": 1809, "bg": 1805}, {"id": "t_machinery_old", "fg": 1810, "bg": 1808}, {"id": "t_stairs_up", "fg": 1811}, {"id": "t_wood_stairs_up", "fg": 1812}, {"id": "t_ladder_up", "fg": 1813}, {"id": "overlay_female_mutation_SCALES", "fg": 1814}, {"id": "overlay_male_mutation_SCALES", "fg": 1815}, {"id": "overlay_female_mutation_TAIL_THICK", "fg": 1816}, {"id": "overlay_male_mutation_TAIL_THICK", "fg": 1817}, {"id": "overlay_female_mutation_TALONS", "fg": 1819}, {"id": "overlay_male_mutation_TALONS", "fg": 1818}, {"id": "overlay_female_mutation_BEAK_PECK", "fg": 1820}, {"id": "overlay_male_mutation_BEAK_PECK", "fg": 1821}, {"id": "overlay_female_mutation_BIRD_EYE", "fg": 1822}, {"id": "overlay_male_mutation_BIRD_EYE", "fg": 1823}, {"id": "overlay_female_mutation_LIZ_EYE", "fg": 1824}, {"id": "overlay_male_mutation_LIZ_EYE", "fg": 1825}, {"id": "overlay_female_mutation_MUZZLE_LONG", "fg": 1827}, {"id": "overlay_male_mutation_MUZZLE_LONG", "fg": 1826}, {"id": "overlay_female_mutation_BEAK_HUM", "fg": 1828}, {"id": "overlay_male_mutation_BEAK_HUM", "fg": 1829}, {"id": "overlay_female_mutation_PLANTSKIN", "fg": 1830}, {"id": "overlay_male_mutation_PLANTSKIN", "fg": 1831}, {"id": "overlay_female_mutation_FANGS", "fg": 1833}, {"id": "overlay_male_mutation_FANGS", "fg": 1832}, {"id": "overlay_female_mutation_CHITIN", "fg": 1834}, {"id": "overlay_male_mutation_CHITIN", "fg": 1835}, {"id": "overlay_female_mutation_ARACHNID_ARMS", "fg": 1836}, {"id": "overlay_male_mutation_ARACHNID_ARMS", "fg": 1837}, {"id": "overlay_female_mutation_FEATHERS", "fg": 1838}, {"id": "overlay_male_mutation_FEATHERS", "fg": 1839}, {"id": "overlay_female_mutation_VINES1", "fg": 1840}, {"id": "overlay_male_mutation_VINES1", "fg": 1841}, {"id": "overlay_female_mutation_WINGS_BIRD", "fg": 1843}, {"id": "overlay_male_mutation_WINGS_BIRD", "fg": 1842}, {"id": "overlay_female_mutation_BEAK", "fg": 1845}, {"id": "overlay_male_mutation_BEAK", "fg": 1844}, {"id": "overlay_female_mutation_CHITIN2", "fg": 1846}, {"id": "overlay_male_mutation_CHITIN2", "fg": 1847}, {"id": "overlay_female_mutation_LEAVES", "fg": 1848}, {"id": "overlay_male_mutation_LEAVES", "fg": 1849}, {"id": "overlay_male_mutation_hair_brown_medium", "fg": 1850}, {"id": "overlay_female_mutation_hair_brown_medium", "fg": 1851}, {"id": "overlay_male_mutation_hair_brown_fro", "fg": 1852}, {"id": "overlay_female_mutation_hair_brown_fro", "fg": 1853}, {"id": "overlay_male_mutation_hair_red_mohawk", "fg": 1854}, {"id": "overlay_female_mutation_hair_red_mohawk", "fg": 1855}, {"id": "overlay_male_mutation_hair_brown_mohawk", "fg": 1857}, {"id": "overlay_female_mutation_hair_brown_mohawk", "fg": 1856}, {"id": "overlay_male_mutation_hair_brown_crewcut", "fg": 1859}, {"id": "overlay_female_mutation_hair_brown_crewcut", "fg": 1858}, {"id": "overlay_male_mutation_hair_black_crewcut", "fg": 1861}, {"id": "overlay_female_mutation_hair_black_crewcut", "fg": 1860}, {"id": "overlay_male_mutation_hair_gray_medium", "fg": 1863}, {"id": "overlay_female_mutation_hair_gray_medium", "fg": 1862}, {"id": "overlay_male_mutation_hair_white_crewcut", "fg": 1864}, {"id": "overlay_female_mutation_hair_white_crewcut", "fg": 1865}, {"id": "overlay_male_mutation_hair_red_medium", "fg": 1867}, {"id": "overlay_female_mutation_hair_red_medium", "fg": 1866}, {"id": "overlay_male_mutation_hair_blond_short", "fg": 1869}, {"id": "overlay_female_mutation_hair_blond_short", "fg": 1868}, {"id": "overlay_male_mutation_hair_white_mohawk", "fg": 1871}, {"id": "overlay_female_mutation_hair_white_mohawk", "fg": 1870}, {"id": "overlay_male_mutation_hair_red_crewcut", "fg": 1873}, {"id": "overlay_female_mutation_hair_red_crewcut", "fg": 1872}, {"id": "overlay_male_mutation_hair_red_fro", "fg": 1875}, {"id": "overlay_female_mutation_hair_red_fro", "fg": 1874}, {"id": "overlay_male_mutation_hair_white_medium", "fg": 1876}, {"id": "overlay_female_mutation_hair_white_medium", "fg": 1877}, {"id": "overlay_male_mutation_hair_black_medium", "fg": 1878}, {"id": "overlay_female_mutation_hair_black_medium", "fg": 1879}, {"id": "overlay_male_mutation_hair_blond_medium", "fg": 1881}, {"id": "overlay_female_mutation_hair_blond_medium", "fg": 1880}, {"id": "overlay_male_mutation_hair_black_fro", "fg": 1883}, {"id": "overlay_female_mutation_hair_black_fro", "fg": 1882}, {"id": "overlay_male_mutation_hair_black_mohawk", "fg": 1884}, {"id": "overlay_female_mutation_hair_black_mohawk", "fg": 1885}, {"id": "overlay_male_mutation_hair_gray_mohawk", "fg": 1886}, {"id": "overlay_female_mutation_hair_gray_mohawk", "fg": 1887}, {"id": "overlay_male_mutation_hair_brown_long", "fg": 1889}, {"id": "overlay_female_mutation_hair_brown_long", "fg": 1888}, {"id": "overlay_male_mutation_hair_gray_short", "fg": 1891}, {"id": "overlay_female_mutation_hair_gray_short", "fg": 1890}, {"id": "overlay_male_mutation_hair_white_short", "fg": 1892}, {"id": "overlay_female_mutation_hair_white_short", "fg": 1893}, {"id": "overlay_male_mutation_hair_white_long", "fg": 1894}, {"id": "overlay_female_mutation_hair_white_long", "fg": 1895}, {"id": "overlay_male_mutation_hair_gray_long", "fg": 1897}, {"id": "overlay_female_mutation_hair_gray_long", "fg": 1896}, {"id": "overlay_male_mutation_hair_brown_short", "fg": 1898}, {"id": "overlay_female_mutation_hair_brown_short", "fg": 1899}, {"id": "overlay_male_mutation_hair_gray_crewcut", "fg": 1901}, {"id": "overlay_female_mutation_hair_gray_crewcut", "fg": 1900}, {"id": "overlay_male_mutation_hair_blond_crewcut", "fg": 1903}, {"id": "overlay_female_mutation_hair_blond_crewcut", "fg": 1902}, {"id": "overlay_male_mutation_hair_black_short", "fg": 1904}, {"id": "overlay_female_mutation_hair_black_short", "fg": 1905}, {"id": "overlay_male_mutation_hair_blond_mohawk", "fg": 1907}, {"id": "overlay_female_mutation_hair_blond_mohawk", "fg": 1906}, {"id": "overlay_male_mutation_hair_black_long", "fg": 1909}, {"id": "overlay_female_mutation_hair_black_long", "fg": 1908}, {"id": "overlay_male_mutation_hair_blond_fro", "fg": 1910}, {"id": "overlay_female_mutation_hair_blond_fro", "fg": 1911}, {"id": "overlay_male_mutation_hair_blond_long", "fg": 1913}, {"id": "overlay_female_mutation_hair_blond_long", "fg": 1912}, {"id": "overlay_male_mutation_hair_gray_fro", "fg": 1915}, {"id": "overlay_female_mutation_hair_gray_fro", "fg": 1914}, {"id": "overlay_male_mutation_hair_red_short", "fg": 1917}, {"id": "overlay_female_mutation_hair_red_short", "fg": 1916}, {"id": "overlay_male_mutation_hair_red_long", "fg": 1919}, {"id": "overlay_female_mutation_hair_red_long", "fg": 1918}, {"id": "overlay_male_mutation_hair_white_fro", "fg": 1920}, {"id": "overlay_female_mutation_hair_white_fro", "fg": 1921}, {"id": "overlay_female_mutation_SKIN_LIGHT", "fg": 1923, "bg": 1796}, {"id": "overlay_male_mutation_SKIN_LIGHT", "fg": 1922, "bg": 1796}, {"id": "overlay_female_mutation_SKIN_DARK", "fg": 1925, "bg": 1796}, {"id": "overlay_male_mutation_SKIN_DARK", "fg": 1924, "bg": 1796}, {"id": "overlay_female_mutation_SKIN_TAN", "fg": 1927, "bg": 1796}, {"id": "overlay_male_mutation_SKIN_TAN", "fg": 1926, "bg": 1796}, {"id": "overlay_male_mutation_SKIN_PINK", "fg": 1929, "bg": 1796}, {"id": "overlay_female_mutation_SKIN_PINK", "fg": 1928, "bg": 1796}, {"id": "overlay_male_mutation_SKIN_MEDIUM", "fg": 1930, "bg": 1796}, {"id": "overlay_female_mutation_SKIN_MEDIUM", "fg": 1931, "bg": 1796}, {"id": "overlay_wielded_bag_canvas", "fg": 1932}, {"id": "overlay_female_wielded_wood_panel", "fg": 1934}, {"id": "overlay_male_wielded_wood_panel", "fg": 1933}, {"id": "overlay_wielded_jar_glass", "fg": 1935}, {"id": "overlay_female_wielded_rifle_flintlock", "fg": 1937}, {"id": "overlay_male_wielded_rifle_flintlock", "fg": 1936}, {"id": "overlay_female_wielded_bat_metal", "fg": 1939}, {"id": "overlay_male_wielded_bat_metal", "fg": 1938}, {"id": "overlay_male_wielded_pointy_stick", "fg": 1940}, {"id": "overlay_female_wielded_pointy_stick", "fg": 1945}, {"id": "overlay_male_wielded_spear_wood", "fg": 1955}, {"id": "overlay_female_wielded_spear_wood", "fg": 1954}, {"id": "overlay_male_wielded_spear_spike", "fg": 1949}, {"id": "overlay_female_wielded_spear_spike", "fg": 1956}, {"id": "overlay_male_wielded_spear_knife", "fg": 1952}, {"id": "overlay_female_wielded_spear_knife", "fg": 1953}, {"id": "overlay_male_wielded_spear_knife_superior", "fg": 1942}, {"id": "overlay_female_wielded_spear_knife_superior", "fg": 1957}, {"id": "overlay_male_wielded_spear_rebar", "fg": 1947}, {"id": "overlay_female_wielded_spear_rebar", "fg": 1951}, {"id": "overlay_male_wielded_spear_pipe", "fg": 1948}, {"id": "overlay_female_wielded_spear_pipe", "fg": 1943}, {"id": "overlay_male_wielded_spear_steel", "fg": 1944}, {"id": "overlay_female_wielded_spear_steel", "fg": 1941}, {"id": "overlay_male_wielded_spear_copper", "fg": 1946}, {"id": "overlay_female_wielded_spear_copper", "fg": 1950}, {"id": "overlay_wielded_flashlight", "fg": 1959}, {"id": "overlay_wielded_heavy_flashlight", "fg": 1958}, {"id": "overlay_wielded_jug_plastic", "fg": 1960}, {"id": "overlay_female_wielded_pot", "fg": 1962}, {"id": "overlay_male_wielded_pot", "fg": 1961}, {"id": "overlay_wielded_fire_ax", "fg": 1963}, {"id": "overlay_wielded_ax", "fg": 1964}, {"id": "overlay_wielded_hatchet", "fg": 1965}, {"id": "overlay_wielded_bottle_glass", "fg": 1966}, {"id": "overlay_female_wielded_rag", "fg": 1967}, {"id": "overlay_male_wielded_rag", "fg": 1968}, {"id": "overlay_female_wielded_corpse_generic_human", "fg": 1969}, {"id": "overlay_male_wielded_corpse_generic_human", "fg": 1970}, {"id": "overlay_male_wielded_chainsaw_off", "fg": 1971}, {"id": "overlay_female_wielded_chainsaw_off", "fg": 1972}, {"id": "overlay_female_wielded_teapot", "fg": 1974}, {"id": "overlay_male_wielded_teapot", "fg": 1973}, {"id": "overlay_male_wielded_1st_aid", "fg": 1975}, {"id": "overlay_female_wielded_1st_aid", "fg": 1976}, {"id": "overlay_female_wielded_nailbat", "fg": 1977}, {"id": "overlay_male_wielded_nailbat", "fg": 1978}, {"id": "overlay_male_wielded_primitive_hammer", "fg": 1979}, {"id": "overlay_female_wielded_primitive_hammer", "fg": 1980}, {"id": "overlay_wielded_steel_lump", "fg": 1981}, {"id": "overlay_wielded_antibiotics", "fg": 1982}, {"id": "overlay_wielded_weak_antibiotic", "fg": 1994}, {"id": "overlay_wielded_strong_antibiotic", "fg": 1989}, {"id": "overlay_wielded_calcium_tablet", "fg": 1984}, {"id": "overlay_wielded_vitamins", "fg": 1992}, {"id": "overlay_wielded_gummy_vitamins", "fg": 1983}, {"id": "overlay_wielded_antifungal", "fg": 1990}, {"id": "overlay_wielded_antiparasitic", "fg": 1987}, {"id": "overlay_wielded_iodine", "fg": 1993}, {"id": "overlay_wielded_prussian_blue", "fg": 1991}, {"id": "overlay_wielded_tramadol", "fg": 1986}, {"id": "overlay_wielded_codeine", "fg": 1985}, {"id": "overlay_wielded_oxycodone", "fg": 1988}, {"id": "overlay_wielded_rebar", "fg": 1995}, {"id": "overlay_wielded_steel_glass_shard", "fg": 1996}, {"id": "overlay_male_wielded_pot_copper", "fg": 1998}, {"id": "overlay_female_wielded_pot_copper", "fg": 1997}, {"id": "overlay_female_wielded_nailboard", "fg": 1999}, {"id": "overlay_male_wielded_nailboard", "fg": 2000}, {"id": "overlay_wielded_scissors", "fg": 2001}, {"id": "overlay_female_wielded_ak74", "fg": 2003}, {"id": "overlay_male_wielded_ak74", "fg": 2002}, {"id": "overlay_wielded_coffeemaker", "fg": 2004}, {"id": "overlay_male_wielded_thermos", "fg": 2006}, {"id": "overlay_female_wielded_thermos", "fg": 2005}, {"id": "overlay_female_wielded_stick", "fg": 2007}, {"id": "overlay_male_wielded_stick", "fg": 2008}, {"id": "overlay_wielded_steel_chunk", "fg": 2009}, {"id": "overlay_wielded_pipe", "fg": 2010}, {"id": "overlay_wielded_bottle_plastic", "fg": 2011}, {"id": "overlay_wielded_broom", "fg": 2012}, {"id": "overlay_wielded_sw_619", "fg": 2013}, {"id": "overlay_wielded_rolling_pin", "fg": 2014}, {"id": "overlay_wielded_makeshift_crowbar", "fg": 2015}, {"id": "overlay_female_wielded_bat", "fg": 2017}, {"id": "overlay_male_wielded_bat", "fg": 2016}, {"id": "overlay_male_wielded_wood_sheet", "fg": 2018}, {"id": "overlay_female_wielded_wood_sheet", "fg": 2019}, {"id": "overlay_wielded_jar_3l_glass_sealed", "fg": 2020}, {"id": "overlay_wielded_box_large", "fg": 2021}, {"id": "overlay_wielded_crowbar", "fg": 2025}, {"id": "overlay_male_wielded_screwdriver", "fg": 2026}, {"id": "overlay_female_wielded_screwdriver", "fg": 2022}, {"id": "overlay_wielded_shovel", "fg": 2027}, {"id": "overlay_wielded_wrench", "fg": 2023}, {"id": "overlay_wielded_hammer", "fg": 2024}, {"id": "overlay_wielded_arming_sword", "fg": 2028}, {"id": "overlay_wielded_brick", "fg": 2029}, {"id": "overlay_male_wielded_2x4", "fg": 2030}, {"id": "overlay_female_wielded_2x4", "fg": 2031}, {"id": "overlay_wielded_katana", "fg": 2032}, {"id": "overlay_wielded_bottle_plastic_small", "fg": 2033}, {"id": "overlay_wielded_sharp_rock", "fg": 2034}, {"id": ["overlay_wielded_glock_17", "overlay_wielded_glock_19", "overlay_wielded_glock_18c", "overlay_wielded_glock_22", "overlay_wielded_glock_31"], "fg": 2035}, {"id": "overlay_wielded_box_small", "fg": 2036}, {"id": "overlay_male_wielded_pillow", "fg": 2038}, {"id": "overlay_female_wielded_pillow", "fg": 2039}, {"id": "overlay_male_wielded_down_pillow", "fg": 2040}, {"id": "overlay_female_wielded_down_pillow", "fg": 2037}, {"id": "overlay_wielded_mop", "fg": 2041}, {"id": ["overlay_wielded_corpse_mon_ant", "overlay_wielded_corpse_mon_ant_soldier", "overlay_wielded_corpse_mon_ant_queen"], "fg": 2043}, {"id": ["overlay_wielded_corpse_mon_ant_acid", "overlay_wielded_corpse_mon_ant_acid_soldier", "overlay_wielded_corpse_mon_ant_acid_queen"], "fg": 2045}, {"id": ["overlay_male_wielded_corpse_mon_zombie", "overlay_male_wielded_corpse_mon_zombie_grappler", "overlay_male_wielded_corpse_mon_zombie_biter", "overlay_male_wielded_corpse_mon_zombie_tough", "overlay_male_wielded_corpse_mon_zombie_hunter", "overlay_male_wielded_corpse_mon_zombie_brute", "overlay_male_wielded_corpse_mon_zombie_predator", "overlay_male_wielded_corpse_mon_zombie_necro", "overlay_male_wielded_corpse_mon_zombie_thorny", "overlay_male_wielded_corpse_mon_zombie_smoker", "overlay_male_wielded_corpse_mon_zombie_shady", "overlay_male_wielded_corpse_mon_zombie_master", "overlay_male_wielded_corpse_mon_zombie_acidic", "overlay_male_wielded_corpse_mon_zombie_fat", "overlay_male_wielded_corpse_mon_zombie_corrosive", "overlay_male_wielded_corpse_mon_zombie_screecher", "overlay_male_wielded_corpse_mon_zombie_scientist", "overlay_male_wielded_corpse_mon_zombie_runner", "overlay_male_wielded_corpse_mon_zombie_spitter", "overlay_male_wielded_corpse_mon_zombie_labsecurity", "overlay_male_wielded_corpse_mon_zombie_child", "overlay_male_wielded_corpse_mon_zombie_hulk", "overlay_male_wielded_corpse_mon_zombie_brute_grappler", "overlay_male_wielded_corpse_mon_zombie_brute_ninja", "overlay_male_wielded_corpse_mon_zombie_kevlar_2", "overlay_male_wielded_corpse_mon_zombie_kevlar_1", "overlay_male_wielded_corpse_mon_zombie_hazmat", "overlay_male_wielded_corpse_mon_zombie_electric", "overlay_male_wielded_corpse_mon_zombie_technician", "overlay_male_wielded_corpse_mon_zombie_fungus", "overlay_male_wielded_corpse_mon_zombie_cop", "overlay_male_wielded_corpse_mon_zombie_child_fungus", "overlay_male_wielded_corpse_mon_zombie_swimmer", "overlay_male_wielded_corpse_mon_zombie_mancroc", "overlay_male_wielded_corpse_mon_zombie_soldier", "overlay_male_wielded_corpse_mon_zombie_skull", "overlay_male_wielded_corpse_mon_zombie_brainless", "overlay_male_wielded_corpse_mon_zombie_survivor", "overlay_male_wielded_corpse_mon_zombie_brute_shocker", "overlay_male_wielded_corpse_mon_zombie_soldier_acid_1", "overlay_male_wielded_corpse_mon_zombie_soldier_blackops_2", "overlay_male_wielded_corpse_mon_zombie_soldier_blackops_1", "overlay_male_wielded_corpse_mon_zombie_soldier_acid_2", "overlay_male_wielded_corpse_mon_zombie_shriekling", "overlay_male_wielded_corpse_mon_zombie_ears", "overlay_male_wielded_corpse_mon_zombie_nullfield", "overlay_male_wielded_corpse_mon_zombie_waif", "overlay_male_wielded_corpse_mon_zombie_sproglodyte", "overlay_male_wielded_corpse_mon_zombie_creepy", "overlay_male_wielded_corpse_mon_zombie_anklebiter", "overlay_male_wielded_corpse_mon_zombie_bio_op", "overlay_male_wielded_corpse_mon_zombie_armored", "overlay_male_wielded_corpse_mon_zombie_prisoner", "overlay_male_wielded_corpse_mon_zombie_military_pilot"], "fg": 2042}, {"id": ["overlay_female_wielded_corpse_mon_zombie", "overlay_female_wielded_corpse_mon_zombie_grappler", "overlay_female_wielded_corpse_mon_zombie_biter", "overlay_female_wielded_corpse_mon_zombie_tough", "overlay_female_wielded_corpse_mon_zombie_hunter", "overlay_female_wielded_corpse_mon_zombie_brute", "overlay_female_wielded_corpse_mon_zombie_predator", "overlay_female_wielded_corpse_mon_zombie_necro", "overlay_female_wielded_corpse_mon_zombie_thorny", "overlay_female_wielded_corpse_mon_zombie_smoker", "overlay_female_wielded_corpse_mon_zombie_shady", "overlay_female_wielded_corpse_mon_zombie_master", "overlay_female_wielded_corpse_mon_zombie_acidic", "overlay_female_wielded_corpse_mon_zombie_fat", "overlay_female_wielded_corpse_mon_zombie_corrosive", "overlay_female_wielded_corpse_mon_zombie_screecher", "overlay_female_wielded_corpse_mon_zombie_scientist", "overlay_female_wielded_corpse_mon_zombie_runner", "overlay_female_wielded_corpse_mon_zombie_spitter", "overlay_female_wielded_corpse_mon_zombie_labsecurity", "overlay_female_wielded_corpse_mon_zombie_child", "overlay_female_wielded_corpse_mon_zombie_hulk", "overlay_female_wielded_corpse_mon_zombie_brute_grappler", "overlay_female_wielded_corpse_mon_zombie_brute_ninja", "overlay_female_wielded_corpse_mon_zombie_kevlar_2", "overlay_female_wielded_corpse_mon_zombie_kevlar_1", "overlay_female_wielded_corpse_mon_zombie_hazmat", "overlay_female_wielded_corpse_mon_zombie_electric", "overlay_female_wielded_corpse_mon_zombie_technician", "overlay_female_wielded_corpse_mon_zombie_fungus", "overlay_female_wielded_corpse_mon_zombie_cop", "overlay_female_wielded_corpse_mon_zombie_child_fungus", "overlay_female_wielded_corpse_mon_zombie_swimmer", "overlay_female_wielded_corpse_mon_zombie_mancroc", "overlay_female_wielded_corpse_mon_zombie_soldier", "overlay_female_wielded_corpse_mon_zombie_skull", "overlay_female_wielded_corpse_mon_zombie_brainless", "overlay_female_wielded_corpse_mon_zombie_survivor", "overlay_female_wielded_corpse_mon_zombie_brute_shocker", "overlay_female_wielded_corpse_mon_zombie_soldier_acid_1", "overlay_female_wielded_corpse_mon_zombie_soldier_blackops_2", "overlay_female_wielded_corpse_mon_zombie_soldier_blackops_1", "overlay_female_wielded_corpse_mon_zombie_soldier_acid_2", "overlay_female_wielded_corpse_mon_zombie_shriekling", "overlay_female_wielded_corpse_mon_zombie_ears", "overlay_female_wielded_corpse_mon_zombie_nullfield", "overlay_female_wielded_corpse_mon_zombie_waif", "overlay_female_wielded_corpse_mon_zombie_sproglodyte", "overlay_female_wielded_corpse_mon_zombie_creepy", "overlay_female_wielded_corpse_mon_zombie_anklebiter", "overlay_female_wielded_corpse_mon_zombie_bio_op", "overlay_female_wielded_corpse_mon_zombie_armored", "overlay_female_wielded_corpse_mon_zombie_prisoner", "overlay_female_wielded_corpse_mon_zombie_military_pilot"], "fg": 2044}, {"id": "overlay_wielded_box_medium", "fg": 2046}, {"id": "overlay_wielded_rock", "fg": 2047}, {"id": "overlay_female_wielded_stick_long", "fg": 2048}, {"id": "overlay_male_wielded_stick_long", "fg": 2049}, {"id": "overlay_wielded_log", "fg": 2050}, {"id": "overlay_female_wielded_television", "fg": 2052}, {"id": "overlay_male_wielded_television", "fg": 2051}, {"id": "overlay_wielded_jar_glass_sealed", "fg": 2053}, {"id": "overlay_wielded_jar_3l_glass", "fg": 2054}, {"id": "overlay_female_wielded_bwirebat", "fg": 2055}, {"id": "overlay_male_wielded_bwirebat", "fg": 2056}, {"id": "overlay_wielded_bag_plastic", "fg": 2057}, {"id": "overlay_female_wielded_splinter", "fg": 2059}, {"id": "overlay_male_wielded_splinter", "fg": 2058}, {"id": "overlay_wielded_ar15", "fg": 2060}, {"id": "overlay_female_worn_pants_army", "fg": 2062}, {"id": "overlay_male_worn_pants_army", "fg": 2061}, {"id": "overlay_female_worn_hat_noise_cancelling", "fg": 2064}, {"id": "overlay_male_worn_hat_noise_cancelling", "fg": 2063}, {"id": "overlay_female_worn_striped_pants", "fg": 2065}, {"id": "overlay_male_worn_striped_pants", "fg": 2066}, {"id": "overlay_female_worn_motorbike_pants", "fg": 2068}, {"id": "overlay_male_worn_motorbike_pants", "fg": 2067}, {"id": "overlay_female_worn_beekeeping_hood", "fg": 2069}, {"id": "overlay_male_worn_beekeeping_hood", "fg": 2070}, {"id": "overlay_male_worn_ski_jacket", "fg": 2072}, {"id": "overlay_female_worn_ski_jacket", "fg": 2071}, {"id": "overlay_female_worn_boots_bunker", "fg": 2073}, {"id": "overlay_male_worn_boots_bunker", "fg": 2074}, {"id": "overlay_male_worn_leg_warmers", "fg": 2076}, {"id": "overlay_female_worn_leg_warmers", "fg": 2075}, {"id": "overlay_worn_dress_shoes", "fg": 2077}, {"id": "overlay_male_worn_glasses_bifocal", "fg": 2079}, {"id": "overlay_female_worn_glasses_bifocal", "fg": 2078}, {"id": "overlay_female_worn_glasses_safety", "fg": 2081}, {"id": "overlay_male_worn_glasses_safety", "fg": 2080}, {"id": "overlay_female_worn_ragpouch", "fg": 2082}, {"id": "overlay_male_worn_ragpouch", "fg": 2083}, {"id": "overlay_female_worn_welding_mask_crude_raised", "fg": 2084}, {"id": "overlay_male_worn_welding_mask_crude_raised", "fg": 2085}, {"id": "overlay_male_worn_gloves_leather", "fg": 2087}, {"id": "overlay_female_worn_gloves_leather", "fg": 2086}, {"id": "overlay_female_worn_helmet_army", "fg": 2088}, {"id": "overlay_male_worn_helmet_army", "fg": 2089}, {"id": "overlay_female_worn_pants_faux_fur", "fg": 2090}, {"id": "overlay_male_worn_pants_faux_fur", "fg": 2091}, {"id": "overlay_male_worn_long_glove_white", "fg": 2093}, {"id": "overlay_female_worn_long_glove_white", "fg": 2092}, {"id": "overlay_female_worn_jacket_army", "fg": 2094}, {"id": "overlay_male_worn_jacket_army", "fg": 2095}, {"id": "overlay_female_worn_pants_cargo", "fg": 2096}, {"id": "overlay_male_worn_pants_cargo", "fg": 2097}, {"id": "overlay_female_worn_gloves_work", "fg": 2098}, {"id": "overlay_male_worn_gloves_work", "fg": 2099}, {"id": "overlay_female_worn_geta", "fg": 2100}, {"id": "overlay_male_worn_geta", "fg": 2101}, {"id": "overlay_male_worn_hat_fur", "fg": 2102}, {"id": "overlay_female_worn_hat_fur", "fg": 2103}, {"id": "overlay_female_worn_gloves_wool", "fg": 2105}, {"id": "overlay_male_worn_gloves_wool", "fg": 2104}, {"id": "overlay_male_worn_arm_warmers", "fg": 2106}, {"id": "overlay_female_worn_arm_warmers", "fg": 2107}, {"id": "overlay_female_worn_beret", "fg": 2109}, {"id": "overlay_male_worn_beret", "fg": 2108}, {"id": "overlay_female_worn_boxer_briefs", "fg": 2110}, {"id": "overlay_male_worn_boxer_briefs", "fg": 2111}, {"id": "overlay_male_worn_touring_suit", "fg": 2113}, {"id": "overlay_female_worn_touring_suit", "fg": 2112}, {"id": "overlay_female_worn_pants_checkered", "fg": 2115}, {"id": "overlay_male_worn_pants_checkered", "fg": 2114}, {"id": "overlay_male_worn_turban", "fg": 2116}, {"id": "overlay_female_worn_turban", "fg": 2117}, {"id": "overlay_female_worn_pants_ski", "fg": 2119}, {"id": "overlay_male_worn_pants_ski", "fg": 2118}, {"id": "overlay_female_worn_glasses_bal", "fg": 2120}, {"id": "overlay_male_worn_glasses_bal", "fg": 2121}, {"id": "overlay_male_worn_boots", "fg": 2122}, {"id": "overlay_female_worn_boots", "fg": 2123}, {"id": "overlay_female_worn_corset", "fg": 2125}, {"id": "overlay_male_worn_corset", "fg": 2124}, {"id": "overlay_female_worn_welding_mask", "fg": 2126}, {"id": "overlay_male_worn_welding_mask", "fg": 2127}, {"id": "overlay_female_worn_jacket_flannel", "fg": 2128}, {"id": "overlay_male_worn_jacket_flannel", "fg": 2129}, {"id": "overlay_male_worn_shorts", "fg": 2131}, {"id": "overlay_female_worn_shorts", "fg": 2130}, {"id": "overlay_female_worn_dinosuit", "fg": 2133}, {"id": "overlay_male_worn_dinosuit", "fg": 2132}, {"id": "overlay_male_worn_undershirt", "fg": 2134}, {"id": "overlay_female_worn_boots_combat", "fg": 2135}, {"id": "overlay_male_worn_boots_combat", "fg": 2136}, {"id": "overlay_female_worn_stockings", "fg": 2137}, {"id": "overlay_male_worn_stockings", "fg": 2138}, {"id": "overlay_male_worn_skirt_leather", "fg": 2140}, {"id": "overlay_female_worn_skirt_leather", "fg": 2139}, {"id": "overlay_female_worn_boots_rubber", "fg": 2142}, {"id": "overlay_male_worn_boots_rubber", "fg": 2141}, {"id": "overlay_female_worn_dress_shirt", "fg": 2143}, {"id": "overlay_male_worn_dress_shirt", "fg": 2144}, {"id": "overlay_female_worn_gloves_golf", "fg": 2146}, {"id": "overlay_male_worn_gloves_golf", "fg": 2145}, {"id": "overlay_female_worn_army_top", "fg": 2147}, {"id": "overlay_male_worn_army_top", "fg": 2148}, {"id": "overlay_female_worn_boxer_shorts", "fg": 2150}, {"id": "overlay_male_worn_boxer_shorts", "fg": 2149}, {"id": "overlay_female_worn_helmet_kabuto", "fg": 2151}, {"id": "overlay_male_worn_helmet_kabuto", "fg": 2152}, {"id": "overlay_male_worn_shoes_bowling", "fg": 2153}, {"id": "overlay_female_worn_shoes_bowling", "fg": 2154}, {"id": "overlay_female_worn_gloves_medical", "fg": 2155}, {"id": "overlay_male_worn_gloves_medical", "fg": 2156}, {"id": "overlay_worn_jacket_jean", "fg": 2157}, {"id": "overlay_female_worn_boots_fur", "fg": 2158}, {"id": "overlay_male_worn_boots_fur", "fg": 2159}, {"id": "overlay_male_worn_blanket", "fg": 2162}, {"id": "overlay_female_worn_blanket", "fg": 2161}, {"id": "overlay_male_worn_down_blanket", "fg": 2160}, {"id": "overlay_female_worn_down_blanket", "fg": 2163}, {"id": "overlay_male_worn_cargo_pants", "fg": 2164}, {"id": "overlay_female_worn_panties", "fg": 2165}, {"id": "overlay_male_worn_panties", "fg": 2166}, {"id": "overlay_female_worn_hat_hard", "fg": 2167}, {"id": "overlay_male_worn_hat_hard", "fg": 2168}, {"id": "overlay_male_worn_glasses_eye", "fg": 2170}, {"id": "overlay_female_worn_glasses_eye", "fg": 2169}, {"id": "overlay_female_worn_helmet_chitin", "fg": 2172}, {"id": "overlay_male_worn_helmet_chitin", "fg": 2171}, {"id": "overlay_female_worn_boy_shorts", "fg": 2173}, {"id": "overlay_male_worn_boy_shorts", "fg": 2174}, {"id": "overlay_male_worn_sweatshirt", "fg": 2175}, {"id": "overlay_female_worn_sweatshirt", "fg": 2176}, {"id": "overlay_male_worn_rucksack", "fg": 2178}, {"id": "overlay_female_worn_rucksack", "fg": 2177}, {"id": "overlay_female_worn_sunglasses", "fg": 2180}, {"id": "overlay_male_worn_sunglasses", "fg": 2179}, {"id": "overlay_female_worn_mask_dust", "fg": 2181}, {"id": "overlay_male_worn_mask_dust", "fg": 2182}, {"id": "overlay_male_worn_helmet_motor", "fg": 2184}, {"id": "overlay_female_worn_helmet_motor", "fg": 2183}, {"id": "overlay_female_worn_sweater", "fg": 2185}, {"id": "overlay_male_worn_sweater", "fg": 2186}, {"id": "overlay_female_worn_jacket_light", "fg": 2187}, {"id": "overlay_male_worn_jacket_light", "fg": 2188}, {"id": "overlay_male_worn_skirt", "fg": 2190}, {"id": "overlay_female_worn_skirt", "fg": 2189}, {"id": "overlay_female_worn_striped_shirt", "fg": 2192}, {"id": "overlay_male_worn_striped_shirt", "fg": 2191}, {"id": "overlay_female_worn_hat_ball", "fg": 2194}, {"id": "overlay_male_worn_hat_ball", "fg": 2193}, {"id": "overlay_male_worn_bra", "fg": 2196}, {"id": "overlay_female_worn_bra", "fg": 2195}, {"id": "overlay_male_worn_glove_jackson", "fg": 2198}, {"id": "overlay_female_worn_glove_jackson", "fg": 2197}, {"id": "overlay_male_worn_boots_western", "fg": 2199}, {"id": "overlay_female_worn_boots_western", "fg": 2200}, {"id": "overlay_female_worn_hazmat_suit", "fg": 2201}, {"id": "overlay_male_worn_hazmat_suit", "fg": 2202}, {"id": "overlay_female_worn_scarf", "fg": 2204}, {"id": "overlay_male_worn_scarf", "fg": 2203}, {"id": "overlay_male_worn_kevlar", "fg": 2206}, {"id": "overlay_female_worn_kevlar", "fg": 2205}, {"id": "overlay_female_worn_backpack_leather", "fg": 2207}, {"id": "overlay_male_worn_backpack_leather", "fg": 2208}, {"id": "overlay_female_worn_armor_samurai", "fg": 2210}, {"id": "overlay_male_worn_armor_samurai", "fg": 2209}, {"id": "overlay_female_worn_jumpsuit", "fg": 2212}, {"id": "overlay_male_worn_jumpsuit", "fg": 2211}, {"id": "overlay_female_worn_jeans", "fg": 2213}, {"id": "overlay_male_worn_jeans", "fg": 2214}, {"id": "overlay_female_worn_boots_winter", "fg": 2216}, {"id": "overlay_male_worn_boots_winter", "fg": 2215}, {"id": "overlay_female_worn_shorts_denim", "fg": 2217}, {"id": "overlay_male_worn_shorts_denim", "fg": 2218}, {"id": "overlay_female_worn_gloves_rubber", "fg": 2220}, {"id": "overlay_male_worn_gloves_rubber", "fg": 2219}, {"id": "overlay_male_worn_hat_cotton", "fg": 2221}, {"id": "overlay_female_worn_hat_cotton", "fg": 2222}, {"id": "overlay_male_worn_robofac_jumpsuit", "fg": 2224}, {"id": "overlay_female_worn_robofac_jumpsuit", "fg": 2223}, {"id": "overlay_female_worn_gloves_liner", "fg": 2225}, {"id": "overlay_male_worn_gloves_liner", "fg": 2226}, {"id": "overlay_female_worn_shorts_cargo", "fg": 2228}, {"id": "overlay_male_worn_shorts_cargo", "fg": 2227}, {"id": "overlay_female_worn_coat_lab", "fg": 2230}, {"id": "overlay_male_worn_coat_lab", "fg": 2229}, {"id": "overlay_male_worn_tank_top", "fg": 2232}, {"id": "overlay_female_worn_tank_top", "fg": 2231}, {"id": "overlay_male_worn_socks", "fg": 2234}, {"id": "overlay_female_worn_socks", "fg": 2233}, {"id": "overlay_female_worn_sports_bra", "fg": 2235}, {"id": "overlay_male_worn_sports_bra", "fg": 2236}, {"id": "overlay_male_worn_bunker_coat", "fg": 2238}, {"id": "overlay_female_worn_bunker_coat", "fg": 2237}, {"id": "overlay_female_worn_gloves_winter", "fg": 2239}, {"id": "overlay_male_worn_gloves_winter", "fg": 2240}, {"id": "overlay_female_worn_mittens", "fg": 2242}, {"id": "overlay_male_worn_mittens", "fg": 2241}, {"id": "overlay_female_worn_glasses_reading", "fg": 2244}, {"id": "overlay_male_worn_glasses_reading", "fg": 2243}, {"id": "overlay_female_worn_longshirt", "fg": 2246}, {"id": "overlay_male_worn_longshirt", "fg": 2245}, {"id": "overlay_female_worn_gloves_cut_resistant", "fg": 2247}, {"id": "overlay_male_worn_gloves_cut_resistant", "fg": 2248}, {"id": "overlay_female_worn_pants", "fg": 2250}, {"id": "overlay_male_worn_pants", "fg": 2249}, {"id": "overlay_female_worn_maid_hat", "fg": 2253}, {"id": "overlay_female_worn_maid_dress", "fg": 2252}, {"id": "overlay_male_worn_maid_hat", "fg": 2251}, {"id": "overlay_male_worn_maid_dress", "fg": 2254}, {"id": "overlay_male_worn_bunker_pants", "fg": 2255}, {"id": "overlay_female_worn_bunker_pants", "fg": 2256}, {"id": "overlay_female_worn_helmet_bike", "fg": 2257}, {"id": "overlay_male_worn_helmet_bike", "fg": 2258}, {"id": "overlay_female_worn_pants_leather", "fg": 2259}, {"id": "overlay_male_worn_pants_leather", "fg": 2260}, {"id": "overlay_male_worn_boots_steel", "fg": 2262}, {"id": "overlay_female_worn_boots_steel", "fg": 2261}, {"id": "overlay_female_worn_survivor_suit", "fg": 2264}, {"id": "overlay_male_worn_survivor_suit", "fg": 2263}, {"id": "overlay_female_worn_pants_fur", "fg": 2265}, {"id": "overlay_male_worn_pants_fur", "fg": 2266}, {"id": "overlay_female_worn_gloves_fingerless", "fg": 2268}, {"id": "overlay_male_worn_gloves_fingerless", "fg": 2267}, {"id": "overlay_female_worn_union_suit", "fg": 2269}, {"id": "overlay_male_worn_union_suit", "fg": 2270}, {"id": "overlay_female_worn_sneakers", "fg": 2271}, {"id": "overlay_male_worn_sneakers", "fg": 2272}, {"id": "overlay_male_worn_flip_flops", "fg": 2274}, {"id": "overlay_female_worn_flip_flops", "fg": 2273}, {"id": "overlay_male_worn_tshirt", "fg": 2276}, {"id": "overlay_female_worn_tshirt", "fg": 2275}, {"id": "overlay_female_worn_boots_hiking", "fg": 2277}, {"id": "overlay_male_worn_boots_hiking", "fg": 2278}, {"id": "overlay_female_worn_gloves_fur", "fg": 2280}, {"id": "overlay_male_worn_gloves_fur", "fg": 2279}, {"id": "overlay_male_worn_firehelmet", "fg": 2282}, {"id": "overlay_female_worn_firehelmet", "fg": 2281}, {"id": "overlay_female_worn_welding_mask_raised", "fg": 2284}, {"id": "overlay_male_worn_welding_mask_raised", "fg": 2283}, {"id": "overlay_female_worn_bandana", "fg": 2285}, {"id": "overlay_male_worn_bandana", "fg": 2286}, {"id": "overlay_male_worn_hat_knit", "fg": 2288}, {"id": "overlay_female_worn_hat_knit", "fg": 2287}, {"id": "overlay_female_worn_hoodie", "fg": 2290}, {"id": "overlay_male_worn_hoodie", "fg": 2289}, {"id": "overlay_male_worn_coat_winter", "fg": 2291}, {"id": "overlay_female_worn_coat_winter", "fg": 2292}, {"id": "overlay_female_worn_duster", "fg": 2293}, {"id": "overlay_male_worn_duster", "fg": 2294}, {"id": "overlay_female_worn_glasses_monocle", "fg": 2295}, {"id": "overlay_male_worn_glasses_monocle", "fg": 2296}, {"id": "overlay_male_worn_welding_mask_crude", "fg": 2298}, {"id": "overlay_female_worn_welding_mask_crude", "fg": 2297}, {"id": "overlay_male_worn_balclava", "fg": 2300}, {"id": "overlay_female_worn_balclava", "fg": 2299}, {"id": "overlay_female_worn_motorbike_boots", "fg": 2302}, {"id": "overlay_male_worn_motorbike_boots", "fg": 2301}, {"id": "overlay_female_worn_helmet_barbute", "fg": 2303}, {"id": "overlay_male_worn_helmet_barbute", "fg": 2304}, {"id": "overlay_female_worn_gloves_tactical", "fg": 2306}, {"id": "overlay_male_worn_gloves_tactical", "fg": 2305}, {"id": "overlay_female_worn_jeans_red", "fg": 2308}, {"id": "overlay_male_worn_jeans_red", "fg": 2307}, {"id": "overlay_female_worn_cowboy_hat", "fg": 2309}, {"id": "overlay_male_worn_cowboy_hat", "fg": 2310}, {"id": "overlay_male_worn_sundress", "fg": 2312}, {"id": "overlay_female_worn_sundress", "fg": 2311}, {"id": "overlay_female_worn_coat_rain", "fg": 2313}, {"id": "overlay_male_worn_coat_rain", "fg": 2314}, {"id": "overlay_male_worn_gloves_light", "fg": 2316}, {"id": "overlay_female_worn_gloves_light", "fg": 2315}, {"id": "mon_skeleton", "fg": 2317, "bg": 1796}, {"id": "mon_dermatik", "fg": 2318, "bg": 1796}, {"id": "mon_exodii_worker", "fg": [{"weight": 15, "sprite": 2320}, {"weight": 15, "sprite": 2321}, {"weight": 10, "sprite": 2322}, {"weight": 10, "sprite": 2319}], "bg": 1796}, {"id": "mon_zombie_brainless", "fg": 2323, "bg": 1796}, {"id": "mon_zombie_soldier", "fg": 2324, "bg": 1796}, {"id": "mon_fungaloid", "fg": 2325, "bg": 1796}, {"id": "mon_zougar", "fg": 2326, "bg": 1796}, {"id": "mon_bee", "fg": 2327, "bg": 1796}, {"id": "mon_zombie_swimmer", "fg": 2328, "bg": 1796}, {"id": "mon_mosquito_giant", "fg": 2329, "bg": 1796}, {"id": "mon_cougar", "fg": 2330, "bg": 1796}, {"id": "mon_dragonfly_giant", "fg": 2331, "bg": 1796}, {"id": "mon_fly", "fg": 2332, "bg": 1796}], "//": "range 1713 to 2336", "sprite_width": 32, "sprite_height": 64, "sprite_offset_x": 0, "sprite_offset_y": -32}, {"file": "large.png", "tiles": [{"id": "f_rotary_clothesline", "fg": 2337}, {"id": "f_fridge", "fg": 2338}, {"id": "t_tree_young", "fg": [{"weight": 100, "sprite": 2351}, {"weight": 100, "sprite": 2349}], "bg": 2342}, {"id": "t_tree_young_season_summer", "fg": [{"weight": 100, "sprite": 2347}, {"weight": 100, "sprite": 2348}], "bg": 2345, "rotates": false}, {"id": "t_tree_young_season_autumn", "fg": [{"weight": 100, "sprite": 2353}, {"weight": 100, "sprite": 2352}], "bg": 2344, "rotates": false}, {"id": "t_tree_young_season_winter", "fg": [{"weight": 100, "sprite": 2350}, {"weight": 100, "sprite": 2346}], "bg": 2343, "rotates": false}, {"id": "mon_zoose", "fg": 2354, "bg": 2341}, {"id": "mon_zombie_acidic", "fg": 2357, "bg": 2339}, {"id": "mon_zombie_corrosive", "fg": 2355, "bg": 2339}, {"id": "mon_zombie_spitter", "fg": 2358, "bg": 2339}, {"id": "corpse_mon_zombie_spitter", "fg": 2356}, {"id": "mon_moose", "fg": [{"weight": 2, "sprite": 2360}, {"weight": 2, "sprite": 2359}], "bg": 2341}, {"id": "mon_zombear", "fg": 2361, "bg": 2340}, {"id": "mon_zombie_grappler", "fg": [{"weight": 1, "sprite": 2363}, {"weight": 1, "sprite": 2362}], "bg": 2339}, {"id": "mon_boomer", "fg": 2364, "bg": 2339}, {"id": "mon_zombie", "fg": [{"weight": 100, "sprite": 2365}, {"weight": 150, "sprite": 2368}, {"weight": 100, "sprite": 2370}, {"weight": 100, "sprite": 2366}, {"weight": 150, "sprite": 2367}], "bg": 2339}, {"id": ["corpse_mon_zombie", "corpse_mon_zombie_grappler", "corpse_mon_zombie_biter", "corpse_mon_zombie_hunter", "corpse_mon_zombie_brute", "corpse_mon_zombie_predator", "corpse_mon_zombie_necro", "corpse_mon_zombie_thorny", "corpse_mon_zombie_smoker", "corpse_mon_zombie_shady", "corpse_mon_zombie_master", "corpse_mon_zombie_acidic", "corpse_mon_zombie_fat", "corpse_mon_zombie_corrosive", "corpse_mon_zombie_screecher", "corpse_mon_zombie_scientist", "corpse_mon_zombie_runner", "corpse_mon_zombie_labsecurity", "corpse_mon_zombie_child", "corpse_mon_zombie_hulk", "corpse_mon_zombie_brute_grappler", "corpse_mon_zombie_brute_ninja", "corpse_mon_zombie_kevlar_2", "corpse_mon_zombie_kevlar_1", "corpse_mon_zombie_hazmat", "corpse_mon_zombie_electric", "corpse_mon_zombie_technician", "corpse_mon_zombie_fungus", "corpse_mon_zombie_cop", "corpse_mon_zombie_child_fungus", "corpse_mon_zombie_swimmer", "corpse_mon_zombie_mancroc", "corpse_mon_zombie_soldier", "corpse_mon_zombie_skull", "corpse_mon_zombie_brainless", "corpse_mon_zombie_survivor", "corpse_mon_zombie_brute_shocker", "corpse_mon_zombie_soldier_acid_1", "corpse_mon_zombie_soldier_blackops_2", "corpse_mon_zombie_soldier_blackops_1", "corpse_mon_zombie_soldier_acid_2", "corpse_mon_zombie_shriekling", "corpse_mon_zombie_ears", "corpse_mon_zombie_nullfield", "corpse_mon_zombie_waif", "corpse_mon_zombie_sproglodyte", "corpse_mon_zombie_creepy", "corpse_mon_zombie_anklebiter", "corpse_mon_zombie_bio_op", "corpse_mon_zombie_armored", "corpse_mon_zombie_prisoner", "corpse_mon_zombie_military_pilot"], "fg": 2369}, {"id": "mon_zombie_smoker", "fg": 2371, "bg": 2339}, {"id": "mon_zombie_necro", "fg": 2372, "bg": 2339}, {"id": "mon_zombie_biter", "fg": 2373, "bg": 2340}, {"id": "mon_exodii_quad", "fg": [{"weight": 15, "sprite": 2380}, {"weight": 10, "sprite": 2377}, {"weight": 15, "sprite": 2376}, {"weight": 15, "sprite": 2379}], "bg": 2341}, {"id": "mon_exodii_turret", "fg": [{"weight": 15, "sprite": 2378}, {"weight": 5, "sprite": 2375}, {"weight": 15, "sprite": 2374}, {"weight": 15, "sprite": 2381}], "bg": 2340}, {"id": "mon_zombie_hunter", "fg": 2382, "bg": 2340}, {"id": "mon_zombie_cop", "fg": 2384, "bg": 2339}, {"id": "mon_zombie_labsecurity", "fg": 2383, "bg": 2339}, {"id": "mon_zombie_rot", "fg": 2385, "bg": 2339}, {"id": "mon_zombie_gasbag", "fg": [{"weight": 1, "sprite": 2387}, {"weight": 1, "sprite": 2386}], "bg": 2339}, {"id": "mon_blob_large", "fg": 2388, "bg": 2341}, {"id": "mon_ant_soldier", "fg": 2393, "bg": 2341}, {"id": "mon_ant_acid_soldier", "fg": 2396, "bg": 2341}, {"id": "corpse_mon_ant_soldier", "fg": 2394}, {"id": "corpse_mon_ant_acid_soldier", "fg": 2392}, {"id": "mon_ant_queen", "fg": 2390, "bg": 2341}, {"id": "mon_ant_acid_queen", "fg": 2389, "bg": 2341}, {"id": "corpse_mon_ant_queen", "fg": 2391}, {"id": "corpse_mon_ant_acid_queen", "fg": 2395}, {"id": "mon_zombie_shady", "fg": 2397, "bg": 2339}, {"id": "mon_zombie_crawler", "fg": 2398, "bg": 2339}, {"id": "mon_zombie_fat", "fg": [{"weight": 1, "sprite": 2399}, {"weight": 1, "sprite": 2400}], "bg": 2339}, {"id": "mon_zombie_tough", "fg": 2401, "bg": 2339}, {"id": "corpse_mon_zombie_tough", "fg": 2402}, {"id": "mon_zombie_electric", "fg": [{"weight": 1, "sprite": 2405}, {"weight": 1, "sprite": 2403}], "bg": 2339}, {"id": "mon_zombie_nullfield", "fg": [{"weight": 1, "sprite": 2404}, {"weight": 1, "sprite": 2406}], "bg": 2339}, {"id": "mon_zombie_scientist", "fg": [{"weight": 1, "sprite": 2408}, {"weight": 1, "sprite": 2407}], "bg": 2339}, {"id": "mon_wasp", "fg": 2409, "bg": 2340}, {"id": "mon_zombie_runner", "fg": 2410, "bg": 2339}, {"id": "mon_mi_go", "fg": 2411, "bg": 2340}, {"id": "mon_zombie_brute", "fg": [{"weight": 100, "sprite": 2412}, {"weight": 100, "sprite": 2413}, {"weight": 50, "sprite": 2415}, {"weight": 50, "sprite": 2414}], "bg": 2340}, {"id": "mon_bear", "fg": 2416, "bg": 2340}], "//": "range 2337 to 2432", "sprite_width": 64, "sprite_height": 64, "sprite_offset_x": -16, "sprite_offset_y": -32}, {"file": "huge.png", "tiles": [{"id": "mon_zombie_hulk", "fg": 2433}], "//": "range 2433 to 2448", "sprite_width": 64, "sprite_height": 96, "sprite_offset_x": -16, "sprite_offset_y": -64}, {"file": "giant.png", "tiles": [{"id": "t_tree", "fg": [{"weight": 100, "sprite": 2457}, {"weight": 100, "sprite": 2456}, {"weight": 100, "sprite": 2458}, {"weight": 100, "sprite": 2452}], "bg": 2462}, {"id": "t_tree_season_summer", "fg": [{"weight": 100, "sprite": 2450}, {"weight": 100, "sprite": 2455}, {"weight": 100, "sprite": 2451}, {"weight": 100, "sprite": 2449}], "bg": 2463}, {"id": "t_tree_season_autumn", "fg": [{"weight": 100, "sprite": 2460}, {"weight": 100, "sprite": 2454}, {"weight": 100, "sprite": 2453}, {"weight": 100, "sprite": 2459}], "bg": 2461}, {"id": "t_tree_season_winter", "fg": [{"weight": 100, "sprite": 2466}, {"weight": 100, "sprite": 2467}, {"weight": 100, "sprite": 2465}, {"weight": 100, "sprite": 2468}], "bg": 2464}, {"id": "t_tree_dead", "fg": [{"weight": 100, "sprite": 2466}, {"weight": 100, "sprite": 2467}, {"weight": 100, "sprite": 2465}, {"weight": 100, "sprite": 2468}, {"weight": 100, "sprite": 2771}], "bg": 2462}, {"id": "t_tree_dead_season_summer", "fg": [{"weight": 100, "sprite": 2466}, {"weight": 100, "sprite": 2467}, {"weight": 100, "sprite": 2465}, {"weight": 100, "sprite": 2468}, {"weight": 100, "sprite": 2771}], "bg": 2463}, {"id": "t_tree_dead_season_autumn", "fg": [{"weight": 100, "sprite": 2466}, {"weight": 100, "sprite": 2467}, {"weight": 100, "sprite": 2465}, {"weight": 100, "sprite": 2468}, {"weight": 100, "sprite": 2771}], "bg": 2461}, {"id": "t_tree_dead_season_winter", "fg": [{"weight": 100, "sprite": 2466}, {"weight": 100, "sprite": 2467}, {"weight": 100, "sprite": 2465}, {"weight": 100, "sprite": 2468}, {"weight": 100, "sprite": 2771}], "bg": 2464}, {"id": "t_tree_birch", "fg": [{"weight": 1, "sprite": 2473}, {"weight": 1, "sprite": 2470}], "bg": 2462}, {"id": "t_tree_birch_season_summer", "fg": [{"weight": 1, "sprite": 2473}, {"weight": 1, "sprite": 2470}], "bg": 2463}, {"id": "t_tree_birch_season_winter", "fg": [{"weight": 1, "sprite": 2474}, {"weight": 1, "sprite": 2471}], "bg": 2464}, {"id": "t_tree_birch_season_autumn", "fg": [{"weight": 1, "sprite": 2472}, {"weight": 1, "sprite": 2469}], "bg": 2461}], "//": "range 2449 to 2480", "sprite_width": 96, "sprite_height": 96, "sprite_offset_x": -32, "sprite_offset_y": -64}, {"file": "incomplete.png", "tiles": [{"id": "f_sink", "multitile": true, "fg": 2491, "additional_tiles": [{"id": "center", "fg": 2496}, {"id": "corner", "fg": [2482, 2494, 2486, 2481]}, {"id": "t_connection", "fg": [2488, 2495, 2490, 2485]}, {"id": "edge", "fg": [2489, 2487]}, {"id": "end_piece", "fg": [2493, 2484, 2483, 2492]}, {"id": "unconnected", "fg": 2491}]}, {"id": "toolbox", "fg": 2497}, {"id": "acoustic_guitar", "fg": 2498}, {"id": "rope_6", "fg": 2499}, {"id": "colt_army", "fg": 2500}, {"id": "ref_lighter", "fg": 2501}, {"id": "soap", "fg": 2502}, {"id": "waffleiron", "fg": 2503}, {"id": "bubblewrap", "fg": 2504}, {"id": "soldering_iron", "fg": 2505}, {"id": "stepladder", "fg": 2506}, {"id": "mag_pistol", "fg": 2507}, {"id": "brazier", "fg": 2508}, {"id": "pliers", "fg": 2509}, {"id": "spray_can", "fg": 2510}, {"id": "condom", "fg": 2511}, {"id": "colt_navy", "fg": 2512}, {"id": "hotplate", "fg": 2513}, {"id": "charcoal", "fg": 2514}, {"id": "stanag30", "fg": 2515}, {"id": "keg", "fg": 2516}, {"id": "pitchfork", "fg": 2517}, {"id": "knife_steak", "fg": 2518}, {"id": "wood_beam", "fg": 2519}, {"id": "smart_phone", "fg": 2520}, {"id": "mosin91_30", "fg": 2521}, {"id": "extinguisher", "fg": 2522}, {"id": "hk_mp5", "fg": 2523}, {"id": "sw_610", "fg": 2524}, {"id": "colt_lightning", "fg": 2525}, {"id": "mag_smg", "fg": 2526}, {"id": "duct_tape", "fg": 2527}, {"id": "t_chainfence", "multitile": true, "rotates": false, "fg": 2528, "bg": 1463, "additional_tiles": [{"id": "edge", "bg": 1463, "fg": [2531, 2528]}, {"id": "end_piece", "bg": 1463, "fg": [2531, 2528, 2531, 2528]}, {"bg": 1463, "id": "unconnected", "fg": 2528}]}, {"id": "t_chainfence_season_winter", "multitile": true, "rotates": false, "fg": 2528, "bg": 682, "additional_tiles": [{"id": "edge", "bg": 682, "fg": [2531, 2528]}, {"id": "end_piece", "bg": 682, "fg": [2531, 2528, 2531, 2528]}, {"bg": 682, "id": "unconnected", "fg": 2528}]}, {"id": "t_chaingate_c", "fg": 2532, "bg": 1463}, {"id": "t_chaingate_l", "fg": 2533, "bg": 1463}, {"id": "t_chaingate_o", "fg": 2529, "bg": 1463}, {"id": "t_chainfence_posts", "fg": 2530, "bg": 1463}, {"id": "t_chaingate_c_season_winter", "fg": 2532, "bg": 682}, {"id": "t_chaingate_l_season_winter", "fg": 2533, "bg": 682}, {"id": "t_chaingate_o_season_winter", "fg": 2529, "bg": 682}, {"id": "t_chainfence_posts_season_winter", "fg": 2530, "bg": 682}, {"id": "t_strconc_wall", "fg": 2534}, {"id": "t_splitrail_fence_season_spring", "fg": 2535, "bg": 1312}, {"id": "t_splitrail_fence_season_summer", "fg": 2535, "bg": 1326}, {"id": "t_splitrail_fence_season_autumn", "fg": 2535, "bg": 1313}, {"id": "t_splitrail_fence_season_winter", "fg": 2535, "bg": 682}, {"id": "t_railing", "fg": 2536, "bg": 1312}, {"id": "t_console", "fg": 2537}, {"id": "t_underbrush", "fg": [{"weight": 100, "sprite": 2540}, {"weight": 100, "sprite": 2539}], "bg": 1312}, {"id": "t_underbrush_harvested", "fg": 2538, "bg": 1312}, {"id": "t_underbrush_season_summer", "fg": [{"weight": 100, "sprite": 2540}, {"weight": 100, "sprite": 2539}], "bg": 1326}, {"id": "t_underbrush_harvested_season_summer", "fg": 2538, "bg": 1326}, {"id": "t_underbrush_season_autumn", "fg": [{"weight": 100, "sprite": 2540}, {"weight": 100, "sprite": 2539}], "bg": 1313}, {"id": "t_underbrush_harvested_season_winter", "fg": 2538, "bg": 649}, {"id": "t_underbrush_season_winter", "fg": [{"weight": 100, "sprite": 2540}, {"weight": 100, "sprite": 2539}], "bg": 649}, {"id": ["t_window_boarded", "t_window_boarded_noglass"], "fg": 2541, "bg": 801}, {"id": "t_wall_metal", "fg": 2542}, {"id": ["t_window_reinforced", "t_window_reinforced_noglass"], "fg": 2543, "bg": 801}, {"id": "t_door_metal_o", "fg": 2544}, {"id": "t_window_frame", "fg": 2545}, {"id": "t_pavement_y", "fg": 2546}, {"id": "t_pavement_y_season_winter", "fg": 682}, {"id": "t_dirtmound", "fg": 2547}, {"id": "t_reinforced_glass_shutter", "fg": 2549}, {"id": "t_reinforced_glass_shutter_open", "fg": 2548}, {"id": "t_trunk", "multitile": true, "fg": [2550, 2551], "bg": [{"weight": 100, "sprite": 1312}, {"weight": 100, "sprite": 1315}]}, {"id": "t_trunk_season_summer", "multitile": true, "fg": [2550, 2551], "bg": [{"weight": 100, "sprite": 1326}, {"weight": 100, "sprite": 1306}]}, {"id": "t_trunk_season_autumn", "multitile": true, "fg": [2550, 2551], "bg": [{"weight": 100, "sprite": 1313}, {"weight": 100, "sprite": 1305}]}, {"id": "t_trunk_season_winter", "multitile": true, "fg": [2550, 2551], "bg": 682}, {"id": "t_console_broken", "fg": 2552}, {"id": ["t_junk_palisade", "t_junk_wall"], "fg": [{"weight": 100, "sprite": 2556}, {"weight": 100, "sprite": 2555}, {"weight": 100, "sprite": 2553}, {"weight": 100, "sprite": 2554}]}, {"id": "t_door_metal_c", "fg": 2557}, {"id": "fd_smoke", "fg": 2560}, {"id": "fd_fungal_haze", "fg": 2559}, {"id": "fd_nuke_gas", "fg": 2558}, {"id": "fd_acid", "fg": 2561}, {"id": "fd_blood", "fg": 2563}, {"id": ["fd_blood_insect", "fd_blood_invertebrate"], "fg": 2562}, {"id": "fd_electricity", "fg": [{"weight": 100, "sprite": 2565}, {"weight": 100, "sprite": 2564}]}, {"id": "fd_web", "fg": [{"weight": 100, "sprite": 2567}, {"weight": 100, "sprite": 2566}, {"weight": 25, "sprite": 2568}, {"weight": 25, "sprite": 2569}]}], "//": "range 2481 to 2576"}, {"file": "fillerhoder.png", "tiles": [{"id": "vp_aisle_horizontal", "fg": 2589}, {"id": "vp_aisle_vertical", "fg": 2586}, {"id": "vp_bed", "fg": 2585}, {"id": "vp_frame_cover", "fg": 2663}, {"id": "vp_frame_cross", "fg": 2662}, {"id": "vp_frame_handle", "fg": 2743}, {"id": "vp_frame_horizontal", "fg": 2680}, {"id": "vp_frame_horizontal_2", "fg": 2684}, {"id": "vp_frame_ne", "fg": 2641}, {"id": "vp_frame_nw", "fg": 2728}, {"id": "vp_frame_se", "fg": 2638}, {"id": "vp_frame_sw", "fg": 2726}, {"id": "vp_frame_vertical", "fg": 2648}, {"id": "vp_frame_vertical_2", "fg": 2711}, {"id": "vp_frame_wood_cover", "fg": 2748}, {"id": "vp_frame_wood_cross", "fg": 2693}, {"id": "vp_frame_wood_handle", "fg": 2743}, {"id": "vp_frame_wood_horizontal", "fg": 2612}, {"id": "vp_frame_wood_horizontal_2", "fg": 2588}, {"id": "vp_frame_wood_ne", "fg": 2617}, {"id": "vp_frame_wood_nw", "fg": 2671}, {"id": "vp_frame_wood_se", "fg": 2596}, {"id": "vp_frame_wood_sw", "fg": 2624}, {"id": "vp_frame_wood_vertical", "fg": 2599}, {"id": "vp_frame_wood_vertical_2", "fg": 2725}, {"id": "vp_hdboard_horizontal", "fg": 2737}, {"id": "vp_hdboard_ne", "fg": 2579}, {"id": "vp_hdboard_nw", "fg": 2659}, {"id": "vp_hdboard_se", "fg": 2602}, {"id": "vp_hdboard_sw", "fg": 2618}, {"id": "vp_hdboard_vertical", "fg": 2706}, {"id": "vp_hdframe_cover", "fg": 2732}, {"id": "vp_hdframe_cross", "fg": 2692}, {"id": "vp_hdframe_horizontal", "fg": 2687}, {"id": "vp_hdframe_horizontal_2", "fg": 2635}, {"id": "vp_hdframe_ne", "fg": 2738}, {"id": "vp_hdframe_nw", "fg": 2690}, {"id": "vp_hdframe_se", "fg": 2705}, {"id": "vp_hdframe_sw", "fg": 2644}, {"id": "vp_hdframe_vertical", "fg": 2651}, {"id": "vp_hdframe_vertical_2", "fg": 2752}, {"id": "vp_washing_machine", "fg": 2653}, {"id": "vp_woodboard_horizontal", "fg": 2708}, {"id": "vp_woodboard_ne", "fg": 2716}, {"id": "vp_woodboard_nw", "fg": 2613}, {"id": "vp_woodboard_se", "fg": 2667}, {"id": "vp_woodboard_sw", "fg": 2731}, {"id": "vp_woodboard_vertical", "fg": 2674}, {"id": "vp_woodhalfboard_horizontal", "fg": 2708}, {"id": "vp_woodhalfboard_horizontal_2", "fg": 2708}, {"id": "vp_woodhalfboard_ne", "fg": 2716}, {"id": "vp_woodhalfboard_nw", "fg": 2613}, {"id": "vp_woodhalfboard_se", "fg": 2667}, {"id": "vp_woodhalfboard_sw", "fg": 2731}, {"id": "vp_woodhalfboard_vertical", "fg": 2674}, {"id": "vp_woodhalfboard_vertical_2", "fg": 2674}, {"id": "vp_basketlg", "fg": 2622}, {"id": "vp_basketsm", "fg": 2622}, {"id": "vp_battery_motorbike", "fg": 2750}, {"id": "vp_blade_horizontal", "fg": 2749}, {"id": "vp_blade_vertical", "fg": 2593}, {"id": "vp_box", "fg": 2691}, {"id": "vp_cargo_space", "fg": 2646, "bg": 2725}, {"id": "vp_chemlab", "fg": 2591}, {"id": "vp_controls", "fg": 2665}, {"id": "vp_craft_rig", "fg": 2591}, {"id": "vp_door_internal", "fg": 2631}, {"id": "vp_door_opaque", "fg": 2661}, {"id": "vp_door_shutter", "fg": 2633}, {"id": "vp_door_sliding", "fg": 2678}, {"id": "vp_engine_1cyl", "fg": 2723}, {"id": "vp_engine_electric", "fg": 2628}, {"id": "vp_engine_electric_large", "fg": 2701}, {"id": "vp_engine_inline4", "fg": 2695}, {"id": "vp_engine_plasma", "fg": 2642}, {"id": "vp_engine_v12", "fg": 2710, "bg": 2713}, {"id": "vp_engine_v6", "fg": 2710}, {"id": "vp_engine_v8", "fg": 2713}, {"id": "vp_engine_vtwin", "fg": 2583}, {"id": "vp_external_gas_tank", "fg": 2580}, {"id": "vp_flamethrower", "fg": 2699}, {"id": "vp_floodlight", "fg": 2578, "bg": 2640}, {"id": "vp_foot_pedals", "fg": 2664}, {"id": "vp_fusion_gun", "fg": 2650}, {"id": "vp_gas_tank", "fg": 2580}, {"id": "vp_gas_tank_small", "fg": 2580}, {"id": "vp_hatch", "fg": 2717}, {"id": "vp_hatch_opaque", "fg": 2745}, {"id": "vp_hddoor", "fg": 2657}, {"id": "vp_hddoor_internal", "fg": 2679}, {"id": "vp_hddoor_opaque", "fg": 2625}, {"id": "vp_hddoor_shutter", "fg": 2608}, {"id": "vp_hddoor_sliding", "fg": 2681}, {"id": "vp_hddoor_trunk", "fg": 2660}, {"id": "vp_hdhatch", "fg": 2675}, {"id": "vp_hdhatch_opaque", "fg": 2639}, {"id": "vp_hdroof", "fg": 2719}, {"id": "vp_hydrogen_tank", "fg": 2682}, {"id": "vp_kitchen_unit", "fg": 2591}, {"id": "vp_laser_gun", "fg": 2650}, {"id": "vp_light_blue", "fg": 2670, "bg": 2733}, {"id": "vp_light_red", "fg": 2670, "bg": 2632}, {"id": "vp_lit_aisle_horizontal", "fg": 2589}, {"id": "vp_lit_aisle_vertical", "fg": 2586}, {"id": "vp_m249", "fg": 2729}, {"id": "vp_minifridge", "fg": 2689}, {"id": "vp_minireactor", "fg": 2614}, {"id": "vp_mounted_browning", "fg": 2729}, {"id": "vp_mounted_mk19", "fg": 2729}, {"id": "vp_muffler", "fg": 2714}, {"id": ["vp_omnicam", "vp_omnomnicam"], "fg": 2686, "bg": 2719}, {"id": "vp_plasma_gun", "fg": 2668}, {"id": "vp_plating_hard", "fg": 2672}, {"id": "vp_plating_military", "fg": 2590}, {"id": "vp_plating_spiked", "fg": 2707}, {"id": "vp_plating_steel", "fg": 2590}, {"id": "vp_plating_superalloy", "fg": 2620}, {"id": "vp_plating_wood", "fg": 2649}, {"id": "vp_recharge_station", "fg": 2750, "bg": 2691}, {"id": "vp_reinforced_solar_panel", "fg": 2724, "bg": 2601}, {"id": "vp_reinforced_solar_panel_v2", "fg": 2724, "bg": 2601}, {"id": "vp_reinforced_windshield", "fg": 2724, "bg": 2669}, {"id": "vp_roof", "fg": 2640}, {"id": "vp_roof_cloth", "fg": 2688}, {"id": "vp_seatbelt", "fg": 2584}, {"id": "vp_seatbelt_heavyduty", "fg": 2584}, {"id": "vp_small_storage_battery", "fg": 2750}, {"id": "vp_solar_panel", "fg": 2601}, {"id": "vp_solar_panel_v2", "fg": 2601}, {"id": "vp_solar_panel_v3", "fg": 2601}, {"id": "vp_spike", "fg": 2616}, {"id": "vp_storage_battery", "fg": 2750}, {"id": "vp_storage_car", "fg": 2750}, {"id": "vp_storage_truck", "fg": 2750}, {"id": "vp_trunk", "fg": 2691}, {"id": "vp_trunk_floor", "fg": 2594}, {"id": "vp_turret_mount", "fg": 2666, "bg": 2719}, {"id": "vp_v_curtain", "fg": 2598}, {"id": "vp_veh_forge", "fg": 2610}, {"id": "vp_veh_table", "fg": 2746}, {"id": "vp_water_tank", "fg": 2630}, {"id": "vp_welding_rig", "fg": 2734}, {"id": "vp_wheel", "fg": 2751}, {"id": "vp_wheel_armor", "fg": 2751}, {"id": "vp_wheel_armor_steerable", "fg": 2751}, {"id": "vp_wheel_bicycle", "fg": 2722}, {"id": "vp_wheel_bicycle_steerable", "fg": 2722}, {"id": "vp_wheel_caster", "fg": 2627}, {"id": "vp_wheel_motorbike", "fg": 2736}, {"id": "vp_wheel_motorbike_steerable", "fg": 2736}, {"id": "vp_wheel_small", "fg": 2581}, {"id": "vp_wheel_small_steerable", "fg": 2581}, {"id": "vp_wheel_steerable", "fg": 2751}, {"id": "vp_wheel_unicycle", "fg": 2722}, {"id": "vp_wheel_wheelchair", "fg": 2722}, {"id": "vp_wheel_wide", "fg": 2611}, {"id": "vp_wheel_wide_steerable", "fg": 2611}, {"id": "alloy_plate", "fg": 2620, "bg": 2658}, {"id": "foot_crank", "fg": 2664, "bg": 2658}, {"id": "frame", "fg": 2693, "bg": 2658}, {"id": "glass_sheet", "fg": 2669, "bg": 2658}, {"id": "hard_plate", "fg": 2672, "bg": 2658}, {"id": "kitchen_unit", "fg": 2591, "bg": 2658}, {"id": "motor", "fg": 2628, "bg": 2658}, {"id": "motor_large", "fg": 2701, "bg": 2658}, {"id": "muffler", "fg": 2714, "bg": 2658}, {"id": "plasma_engine", "fg": 2642, "bg": 2658}, {"id": "saddle", "fg": 2636, "bg": 2658}, {"id": "seat", "fg": 2615, "bg": 2658}, {"id": "solar_panel", "fg": 2601, "bg": 2658}, {"id": "spiked_plate", "fg": 2707, "bg": 2658}, {"id": "steel_plate", "fg": 2590, "bg": 2658}, {"id": "storage_battery", "fg": 2750, "bg": 2658}, {"id": "vehicle_controls", "fg": 2665, "bg": 2658}, {"id": "weldrig", "fg": 2734, "bg": 2658}, {"id": "forge", "fg": 2610, "bg": 2658}, {"id": "1cyl_combustion", "fg": 2723, "bg": 2658}, {"id": "i4_combustion", "fg": 2695, "bg": 2658}, {"id": "v2_combustion", "fg": 2583, "bg": 2658}, {"id": "v6_combustion", "fg": 2710, "bg": 2658}, {"id": "v8_combustion", "fg": 2713, "bg": 2658}, {"id": "vp_board_horizontal", "fg": 2652}, {"id": "vp_board_ne", "fg": 2621}, {"id": "vp_board_nw", "fg": 2739}, {"id": "vp_board_se", "fg": 2600}, {"id": "vp_board_sw", "fg": 2721}, {"id": "vp_board_vertical", "fg": 2709}, {"id": "vp_hdhalfboard_horizontal", "fg": 2577}, {"id": "vp_hdhalfboard_horizontal_2", "fg": 2609}, {"id": "vp_hdhalfboard_ne", "fg": 2747}, {"id": "vp_hdhalfboard_nw", "fg": 2730}, {"id": "vp_hdhalfboard_se", "fg": 2655}, {"id": "vp_hdhalfboard_sw", "fg": 2677}, {"id": "vp_hdhalfboard_vertical", "fg": 2703}, {"id": "vp_hdhalfboard_vertical_2", "fg": 2719}, {"id": "vp_hdstowboard_horizontal", "fg": 2623}, {"id": "vp_hdstowboard_ne", "fg": 2685}, {"id": "vp_hdstowboard_nw", "fg": 2697}, {"id": "vp_hdstowboard_se", "fg": 2587}, {"id": "vp_hdstowboard_sw", "fg": 2735}, {"id": "vp_hdstowboard_vertical", "fg": 2606}, {"id": "vp_stowboard_horizontal", "fg": 2742}, {"id": "vp_stowboard_ne", "fg": 2604}, {"id": "vp_stowboard_nw", "fg": 2673}, {"id": "vp_stowboard_se", "fg": 2720}, {"id": "vp_stowboard_sw", "fg": 2592}, {"id": "vp_stowboard_vertical", "fg": 2637}, {"id": "vp_wing_mirror", "fg": 2605}, {"id": "[vp_xlframe_cover],[vp_fxlframe_cover]", "fg": 2645}, {"id": "[vp_xlframe_cross],[vp_fxlframe_cross]", "fg": 2643}, {"id": "[vp_xlframe_horizontal_2],[vp_fxlframe_horizontal_2]", "fg": 2718}, {"id": "[vp_xlframe_horizontal],[vp_fxlframe_horizontal]", "fg": 2696}, {"id": "[vp_xlframe_ne],[vp_fxlframe_ne]", "fg": 2619}, {"id": "[vp_xlframe_nw],[vp_fxlframe_nw]", "fg": 2607}, {"id": "[vp_xlframe_se],[vp_fxlframe_se]", "fg": 2683}, {"id": "[vp_xlframe_sw],[vp_fxlframe_sw]", "fg": 2740}, {"id": "[vp_xlframe_vertical_2],[vp_fxlframe_vertical_2]", "fg": 2626}, {"id": "[vp_xlframe_vertical],[vp_fxlframe_vertical]", "fg": 2715}, {"id": "[vp_xlhalfboard_horizontal_2],[vp_fxlhalfboard_horizontal_2]", "fg": 2654}, {"id": "[vp_xlhalfboard_horizontal],[vp_fxlhalfboard_horizontal]", "fg": 2727}, {"id": "[vp_xlhalfboard_ne],[vp_fxlhalfboard_ne]", "fg": 2700}, {"id": "[vp_xlhalfboard_nw],[vp_fxlhalfboard_nw]", "fg": 2595}, {"id": "[vp_xlhalfboard_se],[vp_fxlhalfboard_se]", "fg": 2597}, {"id": "[vp_xlhalfboard_sw],[vp_fxlhalfboard_sw", "fg": 2634}, {"id": "[vp_xlhalfboard_vertical_2],[vp_fxlhalfboard_vertical_2]", "fg": 2647}, {"id": "[vp_xlhalfboard_vertical],[vp_fxlhalfboard_vertical]", "fg": 2603}, {"id": "wheel", "fg": 2751, "bg": 2658}, {"id": "wheel_bicycle", "fg": 2722, "bg": 2658}, {"id": "wheel_motorbike", "fg": 2736, "bg": 2658}, {"id": "wheel_small", "fg": 2581, "bg": 2658}, {"id": "wheel_wide", "fg": 2611, "bg": 2658}], "//": "range 2577 to 2768"}, {"file": "opengameartgiant.png", "tiles": [{"id": "t_tree_chestnut", "fg": 2770, "bg": 2462}, {"id": "t_tree_chestnut_season_summer", "fg": 2771, "bg": 2463}, {"id": "t_tree_chestnut_season_autumn", "fg": 2771, "bg": 2461}, {"id": "t_tree_chestnut_season_winter", "fg": 2771, "bg": 2464}, {"id": "t_tree_pine", "fg": 2774, "bg": 2462}, {"id": "t_tree_pine_season_summer", "fg": 2774, "bg": 2463}, {"id": "t_tree_pine_season_autumn", "fg": 2774, "bg": 2461}, {"id": "t_tree_pine_season_winter", "fg": 2774, "bg": 2464}, {"id": "t_tree_deadpine", "fg": 2772, "bg": 2462}, {"id": "t_tree_deadpine_season_summer", "fg": 2772, "bg": 2463}, {"id": "t_tree_deadpine_season_autumn", "fg": 2772, "bg": 2461}, {"id": "t_tree_deadpine_season_winter", "fg": 2772, "bg": 2464}, {"id": "t_tree_hickory", "fg": 2769, "bg": 2462}, {"id": "t_tree_hickory_season_summer", "fg": 2769, "bg": 2463}, {"id": "t_tree_hickory_season_autumn", "fg": 2769, "bg": 2461}, {"id": "t_tree_hickory_season_winter", "fg": 2773, "bg": 2464}, {"id": "t_tree_hickory_dead", "fg": 2773, "bg": 2462}, {"id": "t_tree_hickory_dead_season_summer", "fg": 2773, "bg": 2463}, {"id": "t_tree_hickory_dead_season_autumn", "fg": 2773, "bg": 2461}, {"id": "t_tree_hickory_dead_season_winter", "fg": 2773, "bg": 2464}], "//": "range 2769 to 2784", "sprite_width": 96, "sprite_height": 96, "sprite_offset_x": -32, "sprite_offset_y": -64}, {"file": "fallback.png", "tiles": [], "ascii": [{"offset": 0, "bold": false, "color": "BLACK"}, {"offset": 256, "bold": true, "color": "WHITE"}, {"offset": 512, "bold": false, "color": "WHITE"}, {"offset": 768, "bold": true, "color": "BLACK"}, {"offset": 1024, "bold": false, "color": "RED"}, {"offset": 1280, "bold": false, "color": "GREEN"}, {"offset": 1536, "bold": false, "color": "BLUE"}, {"offset": 1792, "bold": false, "color": "CYAN"}, {"offset": 2048, "bold": false, "color": "MAGENTA"}, {"offset": 2304, "bold": false, "color": "YELLOW"}, {"offset": 2560, "bold": true, "color": "RED"}, {"offset": 2816, "bold": true, "color": "GREEN"}, {"offset": 3072, "bold": true, "color": "BLUE"}, {"offset": 3328, "bold": true, "color": "CYAN"}, {"offset": 3584, "bold": true, "color": "MAGENTA"}, {"offset": 3840, "bold": true, "color": "YELLOW"}]}]} diff --git a/gfx/UltimateCataclysmDemo/tileset.txt b/gfx/UltimateCataclysmDemo/tileset.txt index 623cb620032d1..5058fd31a7450 100644 --- a/gfx/UltimateCataclysmDemo/tileset.txt +++ b/gfx/UltimateCataclysmDemo/tileset.txt @@ -1,4 +1,4 @@ -#Ultimate Cataclysm Demo Update 17 June 2020 +#Ultimate Cataclysm Demo Update 4 July 2020 NAME: UltimateCataclysmDemo VIEW: Ultica (Beta) JSON: tile_config.json diff --git a/lang/extract_json_strings.py b/lang/extract_json_strings.py index b1313bd274a1d..9e93578fdbc4e 100755 --- a/lang/extract_json_strings.py +++ b/lang/extract_json_strings.py @@ -148,6 +148,7 @@ def warning_supressed(filename): "MONSTER", "morale_type", "npc", + "proficiency", "npc_class", "overmap_land_use_code", "overmap_terrain", @@ -167,7 +168,8 @@ def warning_supressed(filename): "vehicle_part", "vitamin", "WHEEL", - "help" + "help", + "weather_type" } # for these objects a plural form is needed diff --git a/lang/po/cataclysm-dda.pot b/lang/po/cataclysm-dda.pot index 3863d4ff443f4..5bc7f89518f01 100644 --- a/lang/po/cataclysm-dda.pot +++ b/lang/po/cataclysm-dda.pot @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-26 12:50+0800\n" +"POT-Creation-Date: 2020-07-10 14:53+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -827,6 +827,17 @@ msgstr[1] "" msgid "Mixture of oxygen and nitrogen in proportions suitable for diving." msgstr "" +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -4195,6 +4206,24 @@ msgid "" "with some kind of mask or mouth protection." msgstr "" +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" + #: lang/json/AMMO_from_json.py #: lang/json/ammunition_type_from_json.py msgid "paper cartridge" @@ -5240,7 +5269,7 @@ msgstr[1] "" msgid "A can of yellow paint." msgstr "" -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "" @@ -7234,7 +7263,7 @@ msgstr[1] "" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." +"rockets will not fit. Use insert to store ammunition." msgstr "" #: lang/json/ARMOR_from_json.py @@ -7330,8 +7359,8 @@ msgstr[1] "" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." msgstr "" #: lang/json/ARMOR_from_json.py @@ -7344,7 +7373,7 @@ msgstr[1] "" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." +"20 arrows or bolts. Use insert to store arrows or bolts." msgstr "" #: lang/json/ARMOR_from_json.py @@ -7357,8 +7386,9 @@ msgstr[1] "" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" #: lang/json/ARMOR_from_json.py @@ -7371,7 +7401,7 @@ msgstr[1] "" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." +"hold 60 arrows or bolts. Use insert to store arrows or bolts." msgstr "" #: lang/json/ARMOR_from_json.py @@ -17274,7 +17304,7 @@ msgstr "" #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it " "around is not exactly comfortable." msgstr "" @@ -29389,6 +29419,18 @@ msgid "" "your pain at bay." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -30893,6 +30935,20 @@ msgid "" "on combining magic with EM radiation." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -36188,6 +36244,32 @@ msgid "" "cheese. Delicious." msgstr "" +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "" + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -40955,25 +41037,55 @@ msgid "" msgstr "" #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'wet dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange, " +"but dogs seem to love it." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'dry dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "wet cat food" +msgid_plural "wet cat food" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'wet cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." msgstr "" #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" +msgid "dry cat food" +msgid_plural "dry cat food" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'dry cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." msgstr "" #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py @@ -49707,6 +49819,12 @@ msgid "" "gutted for parts." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "broken laser turret" +msgid_plural "broken laser turrets" +msgstr[0] "" +msgstr[1] "" + #: lang/json/GENERIC_from_json.py msgid "fire brick" msgid_plural "fire bricks" @@ -50295,12 +50413,6 @@ msgid "" "like it could support a reinforcing sheet, either." msgstr "" -#: lang/json/GENERIC_from_json.py -msgid "broken laser turret" -msgid_plural "broken laser turrets" -msgstr[0] "" -msgstr[1] "" - #: lang/json/GENERIC_from_json.py msgid "TX-5LR Laser Cannon" msgid_plural "TX-5LR Laser Cannons" @@ -51183,7 +51295,7 @@ msgstr[1] "" #. ~ Use action msg for {'str': 'juvenile sourdough starter'}. #: lang/json/GENERIC_from_json.py msgid "" -"After feeding it and caring for it for weeks, your sourdough starter is " +"After feeding it and caring for it for a week, your sourdough starter is " "finally ready for the big leagues." msgstr "" @@ -51221,7 +51333,7 @@ msgstr "" #: lang/json/GENERIC_from_json.py msgid "" "This jar contains a floury paste with sourdough starter mixed in. It needs " -"a few hours to recover its strength before it can be used again." +"a day to recover its strength before it can be used again." msgstr "" #: lang/json/GENERIC_from_json.py @@ -51842,6 +51954,58 @@ msgid "" "wound." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -53629,7 +53793,7 @@ msgstr[1] "" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "" #: lang/json/GENERIC_from_json.py @@ -53813,6 +53977,19 @@ msgid "" "anything on its own." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -55673,6 +55850,109 @@ msgid "" "somewhat warm to the touch." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments " +"are extremely durable, despite showing signs of heavy wear and repair. The " +"structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves " +"is lost on you. It's heavy and sturdy in construction." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front, " +"you deduce this is some sort of camera. None of the inner workings make any " +"sense to you nor resemble any camera you've seen before." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar " +"to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -64608,6 +64888,34 @@ msgid "" "thrower." msgstr "" +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle, " +"custom designed and manufactured by the Exodii." +msgstr "" + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -65622,6 +65930,49 @@ msgid "" "able to give them back some humanity. If only they cared…" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait, " +"its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic " +"components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -65849,6 +66200,40 @@ msgid "" "appears to have a mininuke inside. If this is targeting you… Run." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a " +"quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the " +"air currents. It looks capable of hanging in the air for quite a long time " +"before running out of power." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "feral human" +msgid_plural "feral humans" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'feral human'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Pupils dilated and what remains to be seen of the iris and sclera are " +"bloodshot. It still breathes but the zombies treat it like one of them." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "They throw a loose brick at you!" +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -67684,6 +68069,21 @@ msgid "" "delivering the finishing blow with its enormous fangs." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -69453,6 +69853,20 @@ msgid "" "of infesting sewer lines." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "prototype laser turret" +msgid_plural "prototype laser turrets" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'prototype laser turret'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This appears to be a very experimental automated tower. Plating-less and " +"seemingly half-built, it's little more than an oversized laser emitter and a " +"camera, both welded to a swiveling platform." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "blob" msgid_plural "blobs" @@ -69829,6 +70243,20 @@ msgstr[1] "" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -69917,6 +70345,67 @@ msgid "" "for patient to assist." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and " +"its broad back is rippling with muscles and oozing wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat " +"like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "" +msgstr[1] "" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -70029,21 +70518,6 @@ msgid "" "outpace its two-legged friends." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -70153,6 +70627,48 @@ msgid "" "and its eyes bulge with black goo." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "zombie horse" +msgid_plural "zombie horses" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'zombie horse'} +#: lang/json/MONSTER_from_json.py +msgid "" +"From the looks of this zombie horse's ghastly features, with its protruding " +"ribs, whitish skull, and empty eyes, the exposed part of the internal organs " +"shows a seemingly lifeless color, and the black body fluid drips slowly. " +"The new strength makes the horse no longer dependent on its muscles, but it " +"can still pursue the enemy quickly." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -70709,6 +71225,46 @@ msgstr "" msgid "The impaler launches a barb!" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the " +"rubble with otherworldly speed." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic " +"and desperate manner." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -70890,12 +71446,12 @@ msgid "" msgstr "" #: lang/json/MONSTER_from_json.py -msgid "feral hunter" -msgid_plural "feral hunters" +msgid "zombie hunter" +msgid_plural "zombie hunters" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str': 'feral hunter'} +#. ~ Description for {'str': 'zombie hunter'} #: lang/json/MONSTER_from_json.py msgid "" "This once-human body is barely recognizable, scrambling about on all fours, " @@ -70978,12 +71534,12 @@ msgid "" msgstr "" #: lang/json/MONSTER_from_json.py -msgid "feral runner" -msgid_plural "feral runners" +msgid "zombie runner" +msgid_plural "zombie runners" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str': 'feral runner'} +#. ~ Description for {'str': 'zombie runner'} #: lang/json/MONSTER_from_json.py msgid "" "This recently-risen body moves quickly, darting its head back and forth and " @@ -70991,12 +71547,12 @@ msgid "" msgstr "" #: lang/json/MONSTER_from_json.py -msgid "feral predator" -msgid_plural "feral predators" +msgid "zombie predator" +msgid_plural "zombie predators" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str': 'feral predator'} +#. ~ Description for {'str': 'zombie predator'} #: lang/json/MONSTER_from_json.py msgid "" "With its joints in odd places and angles, this humanoid creature prowls " @@ -72955,20 +73511,6 @@ msgid "" "black eyes, and a tattered sail on its back." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a " -"huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -72980,33 +73522,6 @@ msgstr[1] "" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a " -"huge bipedal dinosaur with feathery edges. The head looks big, lots of big " -"teeth would fit in it." -msgstr "" - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -73115,20 +73630,6 @@ msgid "" "sickle-like claw." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a " -"medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -73182,6 +73683,350 @@ msgid "" "a frill." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing " +"black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body " +"bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms, " +"a long tail, and long sharp scythe-like claws. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent " +"bony crests on its head with ragged strips of ripped flesh hanging down like " +"a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a " +"huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a " +"huge bipedal dinosaur with feathery edges. The head looks big, lots of big " +"teeth would fit in it." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a " +"medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -73650,6 +74495,19 @@ msgid "" "off creatures that disturb it." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -74299,6 +75157,14 @@ msgstr "" msgid "a bird" msgstr "" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "" + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "" @@ -75173,6 +76039,17 @@ msgid "" "rune as a catalyst for recipes." msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "" @@ -75395,6 +76272,15 @@ msgstr "" msgid "Uses a little fatigue" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "" @@ -75821,6 +76707,10 @@ msgstr "" msgid "Haste" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "" @@ -75987,7 +76877,7 @@ msgstr "" msgid "Lightning Blast" msgstr "" -#: lang/json/SPELL_from_json.py src/weather_data.cpp +#: lang/json/SPELL_from_json.py lang/json/weather_type_from_json.py msgid "Lightning Storm" msgstr "" @@ -77904,7 +78794,7 @@ msgstr[1] "" msgid "" "Personal portable charging system consisting of an array of solar panels " "neatly folded in a form of a large backpack. It can be worn as one, and has " -"an integrated cable to plug it into a cable charger system." +"an integrated cable to plug it into a cable charger system CBM." msgstr "" #: lang/json/TOOL_ARMOR_from_json.py @@ -77917,7 +78807,7 @@ msgstr[1] "" #: lang/json/TOOL_ARMOR_from_json.py msgid "" "Unfolded array of portable solar panels ready to push some power into an " -"active cable charger system." +"active cable charger system CBM." msgstr "" #: lang/json/TOOL_ARMOR_from_json.py @@ -79478,6 +80368,19 @@ msgid_plural "bionic firestarters" msgstr[0] "" msgstr[1] "" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -79549,7 +80452,7 @@ msgstr[1] "" #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #: lang/json/TOOL_from_json.py -#: src/veh_interact.cpp +#: src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "" @@ -82066,12 +82969,6 @@ msgid_plural "pseudo butter churns" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -83485,10 +84382,11 @@ msgstr "" #: lang/json/TOOL_from_json.py msgid "" "This is a grenade that generates an electromagnetic pulse with a low-" -"inductance capacitor bank discharged into a single-loop antenna. Use this " -"item to pull the pin and light the fuse, turning it into an active EMP " -"grenade. You will then have three turns before it detonates, creating an " -"EMP field that damages robots and drains bionic energy." +"inductance capacitor bank discharged into a single-loop antenna. It also " +"produces a mild electric shock cloud. Use this item to pull the pin and " +"light the fuse, turning it into an active EMP grenade. You will then have " +"three turns before it detonates, creating an EMP field that damages robots " +"and drains bionic energy." msgstr "" #: lang/json/TOOL_from_json.py @@ -83501,8 +84399,8 @@ msgstr[1] "" #: lang/json/TOOL_from_json.py msgid "" "This EMP grenade is active, and will shortly detonate, creating a large EMP " -"field that damages robots and drains bionic energy. You may not want to be " -"holding it much longer." +"field that damages robots and drains bionic energy as well as a mild " +"electric shock cloud. You may not want to be holding it much longer." msgstr "" #: lang/json/TOOL_from_json.py @@ -84299,12 +85197,36 @@ msgid_plural "throwable fire extinguishers" msgstr[0] "" msgstr[1] "" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "" + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." +"regular fire extinguisher, you can use it from a distance. It has a plastic " +"plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." +msgstr "" + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" msgstr "" #: lang/json/TOOL_from_json.py @@ -87709,8 +88631,8 @@ msgstr "" #. ~ Description for {'str': 'shotgun trap'} #: lang/json/TOOL_from_json.py msgid "" -"This is a simple tripwire is attached to the trigger of a loaded double-" -"barreled shotgun. When pulled, the shotgun fires. Two shells are loaded; " +"This is a simple tripwire is attached to the trigger of a loaded double " +"slamfire shotgun. When pulled, the shotgun fires. Two shells are loaded; " "the first time the trigger is pulled, one or both shells may be discharged." msgstr "" @@ -90592,7 +91514,7 @@ msgid "Pheidippides was a hack" msgstr "" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "" #: lang/json/achievement_from_json.py @@ -90659,6 +91581,592 @@ msgstr "" msgid "Return to the location you started the game" msgstr "" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… " +"both. The things I will do, what they are, yet I know not. But they will " +"be the terrors of the earth." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "" + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become " +"part of each other." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "" + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "" @@ -91116,6 +92624,11 @@ msgstr "" msgid "canceling activity serialized with legacy code" msgstr "" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "" @@ -91418,6 +92931,10 @@ msgstr "" msgid "compressed air" msgstr "" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "" @@ -93270,6 +94787,62 @@ msgstr "" msgid "Merciful" msgstr "" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp #: src/scenario.cpp @@ -93896,10 +95469,6 @@ msgstr "" msgid "Take Paint Off Wall" msgstr "" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "" @@ -93940,6 +95509,30 @@ msgstr "" msgid "Mine Upstair" msgstr "" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "" @@ -96902,7 +98495,7 @@ msgstr "" msgid "You smoked too much." msgstr "" -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "" @@ -98880,6 +100473,18 @@ msgstr "" msgid "raging fire" msgstr "" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "" @@ -99914,7 +101519,6 @@ msgstr "" #: lang/json/furniture_from_json.py #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py #: lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp #: src/map.cpp msgid "crash!" msgstr "" @@ -100085,7 +101689,7 @@ msgstr "" #: lang/json/furniture_from_json.py #: lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "" @@ -100723,9 +102327,8 @@ msgstr "" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of " -"heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." +"heavy weights affixed to opposite ends of a sturdy pipe. You can adjust the " +"set by hand-picking the weights you wish to use." msgstr "" #: lang/json/furniture_from_json.py @@ -100814,6 +102417,18 @@ msgid "" "to be scavanged." msgstr "" +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing " +"a boat. This an older model with mechanical resistance adjustments, but it " +"works without power." +msgstr "" + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "" @@ -100826,6 +102441,18 @@ msgid "" "you're probably getting enough cardio on your own." msgstr "" +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "" @@ -102092,10 +103719,6 @@ msgstr "" msgid "filled arc furnace" msgstr "" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -102838,6 +104461,7 @@ msgid "auto" msgstr "" #: lang/json/gun_from_json.py +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" @@ -103020,9 +104644,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py #: lang/json/gunmod_from_json.py -#: src/item.cpp +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "" @@ -103086,7 +104709,7 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -#: src/item_factory.cpp +#: lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "" @@ -105832,15 +107455,15 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" msgstr[0] "" msgstr[1] "" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one " -"of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed " "around the world, with Česká zbrojovka only joining in the 90's. This " @@ -105953,6 +107576,39 @@ msgid "" "their egomaniac descendants in New England." msgstr "" +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good " +"infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -106064,6 +107720,21 @@ msgstr[1] "" msgid "Electricity unnaturally arcs from the tips of this alien frond." msgstr "" +#: lang/json/gun_from_json.py +msgid "hurled rubble" +msgid_plural "hurled rubbles" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "Stone at the ready to crush that which isn't part of the blob." +msgstr "" + +#: lang/json/gun_from_json.py +msgctxt "gun_type_type" +msgid "throw" +msgstr "" + #: lang/json/gun_from_json.py msgid "nail gun" msgid_plural "nail guns" @@ -106122,7 +107793,7 @@ msgstr[1] "" msgid "" "A short homemade lever-action shotgun with a small internal tube magazine. " "While still a primitive pipe and 2x4 design, it is a formiddable shotgun in " -"it's own right with room for improvement." +"its own right with room for improvement." msgstr "" #: lang/json/gun_from_json.py @@ -106460,8 +108131,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" +msgid "slam-fire pipe shotgun" +msgid_plural "slam-fire pipe shotguns" msgstr[0] "" msgstr[1] "" @@ -106471,6 +108142,18 @@ msgid "" "The lack of sights make this weapon only useful at point-blank range." msgstr "" +#: lang/json/gun_from_json.py +msgid "double slam-fire pipe shotgun" +msgid_plural "double slam-fire pipe shotguns" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "" +"A crude shotgun, composed of four thick steel pipes, two end caps and two " +"nails. The lack of sights make this weapon only useful at point-blank range." +msgstr "" + #: lang/json/gun_from_json.py msgid "flaregun" msgid_plural "flareguns" @@ -106905,11 +108588,6 @@ msgid "" "by hand." msgstr "" -#: lang/json/gun_from_json.py -msgctxt "gun_type_type" -msgid "throw" -msgstr "" - #: lang/json/gun_from_json.py msgid "slingshot" msgid_plural "slingshots" @@ -107152,6 +108830,26 @@ msgstr[1] "" msgid "Bionic one-shot subdermal .40 pistol integrated with your head." msgstr "" +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "" + #: lang/json/gun_from_json.py msgid "CRIT .5 LP" msgid_plural "CRIT .5 LPs" @@ -107937,12 +109635,6 @@ msgid "" "reliability." msgstr "" -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "" -msgstr[1] "" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -109913,6 +111605,12 @@ msgid "" "experiment" msgstr "" +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -111968,10 +113666,6 @@ msgstr "" msgid "Teleport yourself" msgstr "" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "" @@ -112587,6 +114281,11 @@ msgid "" "access the controls, or use the vehicle control key (default '^')." msgstr "" +#. ~ Please leave anything in unchanged. +#: lang/json/json_flag_from_json.py +msgid "When active, turns engines on and off automatically." +msgstr "" + #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "Illuminated items in this space will not illuminate nearby squares." @@ -113208,6 +114907,14 @@ msgstr "" msgid "Toggle sorting order" msgstr "" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "" @@ -113608,6 +115315,10 @@ msgstr "" msgid "Sleep" msgstr "" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "" @@ -114083,14 +115794,14 @@ msgstr "" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py #: src/editmap.cpp -#: src/editmap.cpp src/veh_interact.cpp +#: src/editmap.cpp src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "" #: lang/json/keybinding_from_json.py #: src/editmap.cpp #: src/editmap.cpp src/options.cpp -#: src/options.cpp src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "" @@ -114281,6 +115992,10 @@ msgstr "" msgid "Toggle tracking" msgstr "" +#: lang/json/keybinding_from_json.py +msgid "Toggle smart engine controller" +msgstr "" + #: lang/json/keybinding_from_json.py src/turret.cpp #: src/vehicle_use.cpp msgid "Set turret firing modes" @@ -119450,7 +121165,7 @@ msgstr "" msgid "There is always work to be done, song to be woven." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -119458,16 +121173,16 @@ msgid "" "you." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -120661,7 +122376,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "" #: lang/json/mission_def_from_json.py @@ -120670,7 +122385,7 @@ msgid "" msgstr "" #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." +msgid "Well, you're not dead… yet." msgstr "" #: lang/json/mission_def_from_json.py @@ -131752,7 +133467,7 @@ msgid "Well, maybe you'll just have to make your own world wide web." msgstr "" #: lang/json/mutation_from_json.py -#: lang/json/mutation_from_json.py lang/json/npc_from_json.py +#: lang/json/npc_from_json.py msgid "Survivor" msgstr "" @@ -132057,10 +133772,6 @@ msgid "" "are real and the only thing standing between this world and oblivion is you." msgstr "" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -132437,11 +134148,29 @@ msgid "" msgstr "" #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgid "Survivor: Confused 1" +msgstr "" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -132449,6 +134178,86 @@ msgstr "" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "" @@ -134190,11 +135999,6 @@ msgstr "" msgid "I'm tracking game." msgstr "" -#: lang/json/npc_class_from_json.py -#: lang/json/npc_from_json.py -msgid "Soldier" -msgstr "" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "" @@ -134946,10 +136750,6 @@ msgstr "" msgid "Laborer" msgstr "" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "" @@ -137460,6 +139260,18 @@ msgstr "" msgid "bridge" msgstr "" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "" @@ -152360,96 +154172,6 @@ msgstr "" msgid "I'd kill for a sip of water right now." msgstr "" -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you " -"like! Only joking, what's up ?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't " -"ending, just for a while?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "" @@ -154912,6 +156634,18 @@ msgstr "" msgid "Was it rough surviving thus far?" msgstr "" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -155627,6 +157361,302 @@ msgstr "" msgid " will follow normal engagement rules." msgstr "" +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you " +"like! Only joking, heh." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't " +"ending." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "" + +#: lang/json/snippet_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the " +"damn point?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -156766,6 +158796,14 @@ msgid "" "comes close.\"" msgstr "" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -156775,6 +158813,21 @@ msgid "" "reads: \"WE ARE HERE TO PROTECT YOU.\"" msgstr "" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -168039,11 +170092,11 @@ msgid "Acolyte." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" +msgid "You're back. Have you come to listen to the song?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" +msgid "You there. Quiet down. Can you hear it? The song?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -168078,8 +170131,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -168092,11 +170145,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by " -"taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" @@ -168114,11 +170167,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes " "this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" #: lang/json/talk_topic_from_json.py @@ -168127,7 +170180,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "" @@ -168141,10 +170194,10 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " +"The song can be weaved in many forms. Carved bone charms, weapons and armor " "all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it, " -"or end it. Makes no difference." +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" #: lang/json/talk_topic_from_json.py @@ -168154,7 +170207,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" @@ -168170,8 +170223,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" @@ -168181,9 +170234,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the " -"inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" #: lang/json/talk_topic_from_json.py @@ -168241,14 +170294,6 @@ msgstr "" msgid "Perhaps another time, Seer." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "" @@ -168257,10 +170302,6 @@ msgstr "" msgid "Not interested." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "" @@ -168277,20 +170318,13 @@ msgstr "" msgid "I'm off then." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an " -"unspoiled living creature." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "" @@ -168301,7 +170335,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "" #: lang/json/talk_topic_from_json.py @@ -168316,10 +170350,6 @@ msgstr "" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "I understand your reluctancy. Feel free to return when you see the way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "" @@ -168331,14 +170361,14 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " +"see it in others, but it happens to us, even you and I. How many times have " +"you fallen? Your flesh rent from your body, devoured. Or perhaps it was " +"the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the " +"bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" #: lang/json/talk_topic_from_json.py @@ -168371,6 +170401,14 @@ msgstr "" msgid "Skip it, let's get going." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "" @@ -168608,11 +170646,11 @@ msgstr "" msgid "" "I can help with some tasks if you show me where to work.\n" " Use the zone manager (keybind 'Y') to set up sorting zones for your loot, " -"or to draw blueprints for a building, or to define where you want to plant " +"or to draw blueprints for a building, or to define where you want to plant " "some crops, or where you'd like some trees cut down, or where you want a " "vehicle dismantled or repaired, or a good fishing spot. Then talk to me " "about my current activity and tell me to sort stuff, or build stuff, or cut " -"down trees, or repair or dismantle a vehicle, or do farmwork, or catch some " +"down trees, or repair or dismantle a vehicle, or do farmwork, or catch some " "fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want " "me to work - axes for logging, shovels and seeds and fertilizer for farming, " @@ -168869,8 +170907,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law " +"anymore…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -168892,7 +170930,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -168943,7 +170981,7 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." +msgid "No, just no…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -168955,7 +170993,7 @@ msgid "Make it quick, I want to go back to sleep." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." +msgid "Just few minutes more…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -169002,75 +171040,117 @@ msgid "I want to set some miscellaneous rules." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Can you teach me anything?" +msgid "I'd like to know a bit more about your abilities." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's trade items" +msgid "There's something I want you to do." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I want you to use this item." +msgid "I just wanted to talk for a bit." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hold on to this item." +msgid "Can you help me understand something? (HELP/TUTORIAL)" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Guard this position." +msgid "I'm going to go my own way for a while." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I want to assign you to work at this camp." +msgid "Let's go." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." +msgid "Sure, what did you want to say?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Find a horse and mount up!" +msgid "Mind if we just chat for a bit about your history?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Get off your mount, please." +msgid "Let's just chitchat for a while, I could use some relaxation." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Please go to this location." +msgid "I changed my mind, wanted to ask you something else." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." +msgid "I'm all ears, my friend." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" +msgid "You gonna give me orders?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" +msgid "What would you like?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." +msgid "Just say the word." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." +msgid "Can you teach me anything?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." +msgid "Let's trade items" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's go." +msgid "I want you to use this item." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Hold on to this item." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Guard this position." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I want to assign you to work at this camp." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Find a horse and mount up!" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Get off your mount, please." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Please go to this location." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I want you to build a camp here." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "We need to abandon this camp." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Show me what needs to be done at the camp." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about your current activity." msgstr "" #: lang/json/talk_topic_from_json.py @@ -169622,10 +171702,6 @@ msgstr "" msgid "Stay at your current position." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "" @@ -169698,59 +171774,6 @@ msgstr "" msgid "Sure thing, I'll make my way there." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -169806,7 +171829,7 @@ msgid "Hello there." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." +msgid "Okay, no sudden movements…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170159,7 +172182,7 @@ msgid "Ah, okay." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." +msgid "Not until I get some antibiotics…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170267,7 +172290,7 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." +msgid "Give it some time, I'll show you something new later…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170295,7 +172318,7 @@ msgid "See you around." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." +msgid "I really don't feel comfortable doing so…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170367,7 +172390,7 @@ msgid "Thanks, see you later!" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." +msgid "You picked up something that does not belong to you…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170461,13 +172484,13 @@ msgid "You might be seeing more of me…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" +msgid "Hey again. *kzzz*" msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "" #: lang/json/talk_topic_from_json.py @@ -170489,7 +172512,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170502,7 +172525,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "" @@ -170524,7 +172547,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170540,7 +172563,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170575,14 +172598,6 @@ msgstr "" msgid "Tell me how faction camps have changed." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "" @@ -170929,7 +172944,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." +"talk…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170952,6 +172967,50 @@ msgstr "" msgid "Actually, never mind." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "" @@ -170973,7 +173032,7 @@ msgid "May the earth flourish beneath our paths." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -171157,7 +173216,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " "spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" @@ -171583,6 +173642,18 @@ msgstr "" msgid "This is a npc_has_var, npc_remove_var test response." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "This is a u_add_var time test response." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "This is a npc_add_var time test response." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "This is a u_compare_var time test response for > 3_days." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "This is a u_adjust_var test response that increments by 1." msgstr "" @@ -171732,7 +173803,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -172177,6 +174248,38 @@ msgstr "" msgid "Huh." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time. " +"OK, well, I guess this all started with the riots, didn't it? We were just " +"leading our lives, doing our jobs, and then people started rioting. Not the " +"usual protests that turned violent or anything, either, people just left " +"their houses and started breaking shit. The news tried to downplay it but " +"they couldn't keep it off the internet. I don't know what caused it, they " +"said it was some kind of drug or toxin in the water? Still, I didn't really " +"realize how bad it was getting at first. Somewhere along the way the " +"\"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing " @@ -172229,8 +174332,8 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" #: lang/json/talk_topic_from_json.py @@ -172496,6 +174599,30 @@ msgstr "" msgid "Thanks for telling me that stuff. " msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is, " +"nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -172545,6 +174672,24 @@ msgid "" "in the crash, but I am not going back to find out." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't " +"have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone " +"else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -172578,6 +174723,21 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -172634,6 +174794,40 @@ msgid "" "pretty good life compared to those first few months." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but " +"like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy " +"in those days. It was a lot like the pandemic a few years back, except the " +"police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -172642,6 +174836,50 @@ msgid "" "out of there." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on " +"some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was " +"dragging a few human bodies behind it, I couldn't tell if they were dead or " +"unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see " +"a ways off. It was falling in but it kept the rain and wind off and gave me " +"a place out of sight. I stayed there until I ran out of those ass-tasting " +"ration bars I'd filled my backpack with. Then I took on the wanderin' life " +"until we met." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start " +"with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind " +"of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -172683,6 +174921,27 @@ msgstr "" msgid "Right. Sorry." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went " +"into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to " @@ -172695,6 +174954,19 @@ msgid "" "what happened to all those people." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course " +"to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a " @@ -172766,6 +175038,42 @@ msgstr "" msgid "Sorry for asking. " msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to " +"us. Intentionally, or at least sort-of intentionally." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -173354,6 +175662,48 @@ msgid "" "woods. I wasn't doing a great job of it, so I'm kinda glad you showed up." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be " +"a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -173399,6 +175749,128 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly " +"though it sounds, is aliens." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and " +"monsters and mutations." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them " +"before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about, " +"headed through a broken window, and holed up in there for a few days. I had " +"a fair bit of stolen food and I just kept to myself. When things started to " +"quiet down, I headed out, and here I am." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -173664,13 +176136,48 @@ msgstr "" msgid "I can respect that." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how " +"things were with China, they blamed it on them mostly. Made people violent " +"and ugly. There were riots. People I cared about joined them, and I guess " +"I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real " +"Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life " +"before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby. " +"I feel like I'd rather not remember." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life " "before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -173756,6 +176263,43 @@ msgid "" "don't ask again." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus " +"again. The military and the cops did their damndest to put it down but it " +"got out of hand. Then the virus mutated and started bringing the dead back " +"to life like in some kinda B-movie, and shit got really real. They let the " +"big things loose, or they set them on us, I dunno. Huge unspeakable " +"monsters… still makes me shudder to think of them. They obviously weren't " +"built for combat though, and the military took 'em down fast." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -174048,7 +176592,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot " -"of money in some very clever ways. Not clever enough, it turns out..." +"of money in some very clever ways. Not clever enough, it turns out…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -174221,6 +176765,32 @@ msgid "" "we're the meek that shall inherit the Earth. Although I don't love our odds." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a " +"plague of fire, I remember that one for sure, that was when there were bombs " +"and things going off everywhere to try to contain the riots. And then " +"demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -174228,6 +176798,23 @@ msgid "" "Hell on Earth. I wish I'd paid more attention in Sunday School." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*, " +"everyone's gone. Instead it was messy and dirty. Riots in the streets, the " +"military and police serving the Antichrist to gun down the people like - " +"what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd " +"ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -174441,10 +177028,6 @@ msgstr "" msgid "What was working for the Old Guard like?" msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "" @@ -174656,6 +177239,22 @@ msgstr "" msgid "What were you saying before that?" msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on, " +"but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming, " +"though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole, " +"like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "" @@ -175177,7 +177776,7 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -175569,10 +178168,6 @@ msgid "" "catastrophe." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "" @@ -176992,7 +179587,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" @@ -177716,7 +180311,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between " -"guitars right now, you know? Temporarily guitar-light, if you get my " +"guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -178809,12 +181404,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a " -"concentration center, and then we got on a bus to come here. The bus though, " -"it was rolled over by a giant monster, and many died. We made it out along " -"with a few others, and we kept going until we made it here. It wasn't much " -"farther, and for some reason the monster didn't chase us, just kept tearing " -"at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" #: lang/json/talk_topic_from_json.py @@ -178942,7 +181537,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " +"out in Western Canada. I'd always wanted to see New England, and I was down " "here on vacation when, well, you know. I got evacuated, but because I'm not " "a US citizen they weren't willing to take me downstairs. I can understand " "that, even if I don't like it much. To tell you the truth I'm still coming " @@ -179011,7 +181606,7 @@ msgid "Hm? Oh, hi." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "" #: lang/json/talk_topic_from_json.py @@ -179375,8 +181970,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what " -"we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" #: lang/json/talk_topic_from_json.py @@ -179393,9 +181988,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here, " @@ -179719,7 +182314,7 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." +msgid "I'm not in charge here, you're looking for someone else…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -179767,11 +182362,11 @@ msgid "Well, I'd better be going. Bye." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." +msgid "Welcome marshal…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." +msgid "Welcome…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -179999,11 +182594,11 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." +msgid "Marshal…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." +msgid "Citizen…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -180601,7 +183196,7 @@ msgid "" "protective gear: gas mask, suit and gear, at a considerable discount. We " "will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -180789,15 +183384,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." +msgid "Thinking I should go hunt something soon…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "" #: lang/json/talk_topic_from_json.py @@ -180837,7 +183432,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." +"marshal…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -180906,7 +183501,7 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." +msgid "Stand still while I get my clippers…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -181277,7 +183872,7 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." +msgid "Please leave me alone…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -181296,13 +183891,13 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me time..." +"I don't know what you could do. I've tried everything. Just give me time…" msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." +"seems like I can't keep anything down…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -181424,8 +184019,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but " -"you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "" #: lang/json/talk_topic_from_json.py @@ -181769,7 +184364,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "" @@ -181937,7 +184532,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -182097,7 +184692,7 @@ msgid "Oh, you again." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -182105,7 +184700,7 @@ msgid "I'm busy, what is it?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "" #: lang/json/talk_topic_from_json.py @@ -186320,183 +188915,14 @@ msgid "" msgstr "" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted " -"properly." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." +msgid "overgrown floor" msgstr "" -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it " -"out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of " -"maintenance." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "" - -#. ~ Description for yellow pavement +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "" - -#. ~ Description for wooden floor -#: lang/json/terrain_from_json.py -msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -186504,38 +188930,13 @@ msgid "SMASH!" msgstr "" #: lang/json/terrain_from_json.py -msgid "metal floor" +msgid "overgrown wall" msgstr "" -#. ~ Description for metal floor +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." -msgstr "" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -186619,6 +189020,21 @@ msgid "" "smoothed and the roof isn't quite filled in yet." msgstr "" +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -186626,6 +189042,10 @@ msgid "" "with a matching roof." msgstr "" +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "" @@ -186668,6 +189088,10 @@ msgid "" "resistance and sliding, commonly for recreational sports." msgstr "" +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -186750,45 +189174,150 @@ msgid "A blue section of flooring." msgstr "" #: lang/json/terrain_from_json.py -msgid "industrial carpet" +msgid "carpet" msgstr "" -#. ~ Description for industrial carpet +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base carpet!" +msgstr "" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Soft red carpet." +msgstr "" + +#. ~ Description for yellow carpet +#: lang/json/terrain_from_json.py +msgid "Soft yellow carpet." +msgstr "" + +#. ~ Description for green carpet +#: lang/json/terrain_from_json.py +msgid "Soft green carpet." +msgstr "" + +#. ~ Description for purple carpet +#: lang/json/terrain_from_json.py +msgid "Soft purple carpet." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "" + +#. ~ Description for industrial red carpet #: lang/json/terrain_from_json.py msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." msgstr "" #: lang/json/terrain_from_json.py -msgid "bunker carpet" +msgid "industrial yellow carpet" msgstr "" -#. ~ Description for bunker carpet +#. ~ Description for industrial yellow carpet #: lang/json/terrain_from_json.py msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on " +"bare concrete." msgstr "" -#. ~ Description for red carpet #: lang/json/terrain_from_json.py -msgid "Soft red carpet." +msgid "industrial green carpet" msgstr "" -#. ~ Description for yellow carpet +#. ~ Description for industrial green carpet #: lang/json/terrain_from_json.py -msgid "Soft yellow carpet." +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." msgstr "" -#. ~ Description for green carpet #: lang/json/terrain_from_json.py -msgid "Soft green carpet." +msgid "industrial purple carpet" msgstr "" -#. ~ Description for purple carpet +#. ~ Description for industrial purple carpet #: lang/json/terrain_from_json.py -msgid "Soft purple carpet." +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on " +"bare concrete." +msgstr "" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." msgstr "" #: lang/json/terrain_from_json.py @@ -186825,6 +189354,33 @@ msgid "" "you like the sound of rain on corrugated metal." msgstr "" +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "" + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "" @@ -186834,6 +189390,30 @@ msgstr "" msgid "Moist spongy moss." msgstr "" +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted " +"properly." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "" @@ -186843,6 +189423,131 @@ msgstr "" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it " +"out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of " +"maintenance." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "" + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "" @@ -190586,6 +193291,78 @@ msgstr "" msgid "A ladder leading down." msgstr "" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "" @@ -191078,7 +193855,7 @@ msgstr "" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py #: lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "" @@ -191269,6 +194046,10 @@ msgstr "" msgid "Car Chassis" msgstr "" +#: lang/json/vehicle_from_json.py +msgid "Hybrid Car" +msgstr "" + #: lang/json/vehicle_from_json.py msgid "City Car" msgstr "" @@ -192962,6 +195743,21 @@ msgid "" "disabled." msgstr "" +#: lang/json/vehicle_part_from_json.py +msgid "smart engine controller" +msgstr "" + +#. ~ Description for {'str': 'smart engine controller'} +#: lang/json/vehicle_part_from_json.py +#, no-python-format +msgid "" +"Electronic module that automatically switches combustion and electric " +"engines on and off minimizing fuel consumption and optimizing power output " +"and battery charge rate. Must be turned on to work. Simplified ruleset: 1. " +"When throttling, maximize acceleration. 2. Keep battery at 90%. 3. " +"Minimize fuel consumption." +msgstr "" + #: lang/json/vehicle_part_from_json.py msgid "5-point harness" msgstr "" @@ -194117,6 +196913,58 @@ msgstr "" msgid "Disgusting Diet" msgstr "" +#: lang/json/weather_type_from_json.py +msgid "NULL Weather - BUG" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Clear" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Sunny" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Cloudy" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Light Drizzle" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Drizzle" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Rain" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Thunder Storm" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Acidic Drizzle" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Acid Rain" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Flurries" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Snowing" +msgstr "" + +#: lang/json/weather_type_from_json.py +msgid "Snowstorm" +msgstr "" + #: src/achievement.cpp msgid "time of cataclysm" msgstr "" @@ -194364,7 +197212,7 @@ msgid "The lock stumps your efforts to pick it." msgstr "" #: src/activity_actor.cpp src/game.cpp -#: src/game.cpp src/iuse.cpp +#: src/game.cpp src/iexamine.cpp src/iuse.cpp #: src/iuse.cpp #: src/iuse.cpp src/iuse_actor.cpp #: src/iuse_actor.cpp @@ -194427,6 +197275,120 @@ msgstr "" msgid "Continue trying to fall asleep and don't ask again." msgstr "" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -198960,6 +201922,29 @@ msgstr "" msgid "Increased storage capacity by %i." msgstr "" +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "" @@ -199122,7 +202107,8 @@ msgid "(incapacitated)" msgstr "" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" +#, c-format +msgid "(fuel saving ON > %d %%)" msgstr "" #: src/bionics_ui.cpp @@ -199804,6 +202790,23 @@ msgstr "" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "" + +#: src/character.cpp +msgid " frees themselves!" +msgstr "" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "" @@ -200655,6 +203658,10 @@ msgstr "" msgid "Your body strains under the weight!" msgstr "" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -203608,6 +206615,14 @@ msgstr "" msgid "Game…" msgstr "" +#: src/debug_menu.cpp +msgid "Change [b]attery charge" +msgstr "" + +#: src/debug_menu.cpp +msgid "Vehicle…" +msgstr "" + #: src/debug_menu.cpp msgid "Teleport - short range" msgstr "" @@ -204238,9 +207253,7 @@ msgstr "" #: src/debug_menu.cpp #, c-format -msgid "" -"Current turn: %d.\n" -"%s\n" +msgid "Current turn: %d.\n" msgstr "" #: src/debug_menu.cpp @@ -204250,14 +207263,6 @@ msgid_plural "%d creatures exist.\n" msgstr[0] "" msgstr[1] "" -#: src/debug_menu.cpp -msgid "NPCs are going to spawn." -msgstr "" - -#: src/debug_menu.cpp -msgid "NPCs are NOT going to spawn." -msgstr "" - #: src/debug_menu.cpp #, c-format msgid "%s: map ( %d:%d ) pos ( %d:%d )" @@ -204312,6 +207317,22 @@ msgstr "" msgid "%1$s (%2$s)" msgstr "" +#: src/debug_menu.cpp +msgid "Vehicle condition" +msgstr "" + +#: src/debug_menu.cpp +msgid "Light damage" +msgstr "" + +#: src/debug_menu.cpp +msgid "Undamaged" +msgstr "" + +#: src/debug_menu.cpp +msgid "Disabled (tires or engine)" +msgstr "" + #: src/debug_menu.cpp msgid "Martial arts debug." msgstr "" @@ -204506,6 +207527,15 @@ msgstr "" msgid "%s is now level %d!" msgstr "" +#: src/debug_menu.cpp src/iuse.cpp +#: src/iuse.cpp +msgid "There's no vehicle there." +msgstr "" + +#: src/debug_menu.cpp +msgid "By how much? (in kJ, negative to discharge)" +msgstr "" + #: src/descriptions.cpp #, c-format msgid "" @@ -204729,15 +207759,6 @@ msgid "" "Roof: %s" msgstr "" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -207709,6 +210730,11 @@ msgstr "" msgid "Your local position: %d, %d, %d" msgstr "" +#: src/game.cpp +#, c-format +msgid "Total NPCs within %d OMTs: %d. %d are static NPCs." +msgstr "" + #: src/game.cpp msgid "East:" msgstr "" @@ -208650,6 +211676,10 @@ msgstr "" msgid "You aren't holding something you can reload." msgstr "" +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -211198,6 +214228,10 @@ msgstr "" msgid "Creature whitelisted: %s" msgstr "" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "" @@ -212543,11 +215577,28 @@ msgstr "" msgid "There is a %s there. Take down?" msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -213417,6 +216468,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "" + #: src/init.cpp msgid "Finalizing" msgstr "" @@ -213425,6 +216481,10 @@ msgstr "" msgid "Body parts" msgstr "" +#: src/init.cpp +msgid "Weather types" +msgstr "" + #: src/init.cpp msgid "Field types" msgstr "" @@ -214415,7 +217475,7 @@ msgid "" "very bad idea." msgstr "" -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -216075,6 +219135,13 @@ msgstr "" msgid "is not a container" msgstr "" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "" +msgstr[1] "" + #: src/item_contents.cpp msgid "is not rigid" msgstr "" @@ -216138,6 +219205,10 @@ msgstr "" msgid "Pocket %d:" msgstr "" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "" + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "" @@ -217284,10 +220355,6 @@ msgstr "" msgid "There is nothing to siphon nearby." msgstr "" -#: src/iuse.cpp -msgid "There's no vehicle there." -msgstr "" - #: src/iuse.cpp msgid "With a snarl, the combat chainsaw screams to life!" msgstr "" @@ -217908,10 +220975,6 @@ msgstr "" msgid "Sokoban" msgstr "" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "" @@ -220790,7 +223853,7 @@ msgstr "" msgid "You can't place a %s there. It contains a trap already." msgstr "" -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "" @@ -222527,6 +225590,15 @@ msgstr "" msgid "Summon" msgstr "" +#: src/magic.cpp +msgid "random creature" +msgstr "" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "" @@ -222547,6 +225619,10 @@ msgstr "" msgid "Spawned" msgstr "" +#: src/magic.cpp +msgid "Threshold" +msgstr "" + #: src/magic.cpp msgid "Recover" msgstr "" @@ -222599,6 +225675,15 @@ msgstr "" msgid "%s wounds are closing up!" msgstr "" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "" @@ -223056,29 +226141,22 @@ msgstr "" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "" - -#: src/map.cpp -msgid "You fail to disarm the trap." +msgid "Something has crawled out of the %s plants!" msgstr "" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" +#, c-format +msgid "Something has crawled out of the %s!" msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" +msgid "You've spotted a %1$ss!" msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" +msgid " triggers a %s!" msgstr "" #: src/map_extras.cpp @@ -224624,6 +227702,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -228371,6 +231462,11 @@ msgstr "" msgid "zombie slave" msgstr "" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "" + #: src/monexamine.cpp msgid "Rename" msgstr "" @@ -233389,11 +236485,14 @@ msgid "A scaling factor that determines density of item spawns." msgstr "" #: src/options.cpp -msgid "NPC spawn rate scaling factor" +msgid "Random NPC spawn time" msgstr "" #: src/options.cpp -msgid "A scaling factor that determines density of dynamic NPC spawns." +msgid "" +"Baseline average number of days between random NPC spawns. Average duration " +"goes up with the number of NPCs already spawned. Set to 0 days to disable " +"random NPCs." msgstr "" #: src/options.cpp @@ -233515,37 +236614,6 @@ msgid "" "If true, spawn zombies at shelters. Makes the starting game a lot harder." msgstr "" -#: src/options.cpp -msgid "Static NPCs" -msgstr "" - -#: src/options.cpp -msgid "" -"If true, static NPCs will spawn at pre-defined locations. Requires world " -"reset." -msgstr "" - -#: src/options.cpp -msgid "Starting NPCs spawn" -msgstr "" - -#: src/options.cpp -msgid "" -"Determines whether starting NPCs should spawn, and if they do, how exactly." -msgstr "" - -#: src/options.cpp -msgid "Scenario-based" -msgstr "" - -#: src/options.cpp -msgid "Random NPCs" -msgstr "" - -#: src/options.cpp -msgid "If true, the game will randomly spawn NPCs during gameplay." -msgstr "" - #: src/options.cpp msgid "Mutations by radiation" msgstr "" @@ -233554,17 +236622,6 @@ msgstr "" msgid "If true, radiation causes the player to mutate." msgstr "" -#: src/options.cpp -msgid "Z-levels" -msgstr "" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" - #: src/options.cpp msgid "Character point pools" msgstr "" @@ -238222,6 +241279,15 @@ msgctxt "grammatical gender list" msgid "n" msgstr "" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "" @@ -239889,6 +242955,34 @@ msgstr "" msgid "pile-up" msgstr "" +#: src/vehicle_move.cpp +msgid "Smart controller does not support flying vehicles." +msgstr "" + +#: src/vehicle_move.cpp +msgid "Smart controller detects only a single controllable engine." +msgstr "" + +#: src/vehicle_move.cpp +msgid "Smart controller is designed to control more than one engine." +msgstr "" + +#: src/vehicle_move.cpp +msgid "Smart controller does not support more than five engines." +msgstr "" + +#: src/vehicle_move.cpp +msgid "Smart controller is shutting down." +msgstr "" + +#: src/vehicle_move.cpp +msgid "Smart controller failed to start an engine." +msgstr "" + +#: src/vehicle_move.cpp +msgid "Smart controller optimizes engine state." +msgstr "" + #: src/vehicle_move.cpp #, c-format msgid "The %s is too leaky!" @@ -240261,6 +243355,11 @@ msgctxt "electronics menu option" msgid "water purifier" msgstr "" +#: src/vehicle_use.cpp +msgctxt "electronics menu option" +msgid "smart controller" +msgstr "" + #: src/vehicle_use.cpp msgid "Turn off camera system" msgstr "" @@ -241100,54 +244199,6 @@ msgstr "" msgid "The weather changed to %s!" msgstr "" -#: src/weather_data.cpp -msgid "Clear" -msgstr "" - -#: src/weather_data.cpp -msgid "Sunny" -msgstr "" - -#: src/weather_data.cpp -msgid "Cloudy" -msgstr "" - -#: src/weather_data.cpp -msgid "Light Drizzle" -msgstr "" - -#: src/weather_data.cpp -msgid "Drizzle" -msgstr "" - -#: src/weather_data.cpp -msgid "Rain" -msgstr "" - -#: src/weather_data.cpp -msgid "Thunder Storm" -msgstr "" - -#: src/weather_data.cpp -msgid "Acidic Drizzle" -msgstr "" - -#: src/weather_data.cpp -msgid "Acid Rain" -msgstr "" - -#: src/weather_data.cpp -msgid "Flurries" -msgstr "" - -#: src/weather_data.cpp -msgid "Snowing" -msgstr "" - -#: src/weather_data.cpp -msgid "Snowstorm" -msgstr "" - #: src/wish.cpp msgid "Nonvalid" msgstr "" diff --git a/lang/po/de.po b/lang/po/de.po index 08c69d286bab3..fa42264846d0d 100644 --- a/lang/po/de.po +++ b/lang/po/de.po @@ -19,18 +19,18 @@ # kurtice087 , 2020 # Chris , 2020 # Ziv Edo, 2020 -# Brett Dong , 2020 # Björn Hartmann , 2020 # Pupsi , 2020 # Matyas Taller , 2020 # Vlasov Vitaly , 2020 +# Brett Dong , 2020 # Wuzzy , 2020 # msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: Wuzzy , 2020\n" "Language-Team: German (https://www.transifex.com/cataclysm-dda-translators/teams/2217/de/)\n" @@ -958,6 +958,17 @@ msgstr "" "Ein Gemisch aus Sauerstoff und Stickstoff im tauchfähigen " "Mischungsverhältnis." +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -4982,6 +4993,24 @@ msgstr "" "verwendet werden kann. Am besten man benutzt eine Art Gasmaske oder anderen " "Atemschutz." +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -6197,7 +6226,7 @@ msgstr[1] "gelbe Farbe" msgid "A can of yellow paint." msgstr "Ein Farbeimer mit gelber Farbe." -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "" @@ -8517,7 +8546,7 @@ msgstr[1] "Munitionstaschen" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." +"rockets will not fit. Use insert to store ammunition." msgstr "" #: lang/json/ARMOR_from_json.py @@ -8625,11 +8654,9 @@ msgstr[1] "Köcher" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." msgstr "" -"Ein Lederköcher, der an der Taille getragen wird und 20 Pfeile enthalten " -"kann. Aktiviere ihn, um Pfeile einzulagern." #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -8641,10 +8668,8 @@ msgstr[1] "Birkenrindenköcher" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." +"20 arrows or bolts. Use insert to store arrows or bolts." msgstr "" -"Ein Köcher aus Birkenrindenstreifen, der an der Taille getragen wird und 20 " -"Pfeile aufnehmen kann. Aktiviere ihn, um Pfeile darin zu lagern." #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -8656,13 +8681,10 @@ msgstr[1] "große Köcher" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" -"Ein großer, mit Metall getrimmer Lederköcher, der auf dem Rücken getragen " -"wird und 80 Pfeile beinhalten kann. Historisch benutzt von Bogenschützen zu " -"Pferd, statt von Bogenschützen zu Fuß, aber keiner von IHNEN musste gegen " -"Zombies kämpfen. Aktiviere ihn, um Pfeile einzulagern." #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -8674,11 +8696,8 @@ msgstr[1] "große Birkenrindenköcher" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." +"hold 60 arrows or bolts. Use insert to store arrows or bolts." msgstr "" -"Ein großer aus Birkenrindenstreifen gewobener Köcher, der 60 Pfeile " -"enthalten kann. Er wird am Rücken getragen. Aktiviere ihn, um Pfeile " -"einzulagern." #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -19539,14 +19558,10 @@ msgstr "" #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." msgstr "" -"Eine mittelgroßer Rollenkoffer, der hauptsächlich zum Transport von Kleidung" -" und anderen Besitztümern auf Reisen verwendet wird. Er bietet einen einen " -"angemessenen Lagerplatz, aber es ist nicht sonderlich bequem, ihn " -"herumzuschleppen." #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -32705,6 +32720,19 @@ msgid "" "your pain at bay." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -34319,6 +34347,20 @@ msgid "" "on combining magic with EM radiation." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -40177,6 +40219,32 @@ msgstr "" "Gesalzene Chips aus Mais-Tortillas. Mit Hackfleisch und bedeckt in Käse. " "Lecker." +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "" + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -45382,30 +45450,56 @@ msgstr "" "Hülsenfrüchten. Das ist perfekt für kleine Vögel." #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "Hundefutter" -msgstr[1] "Hundefutter" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'wet dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "" +msgstr[1] "" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'dry dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." msgstr "" -"Dies ist Futter für Hunde. Es riecht seltsam, aber Hunde scheinen es zu " -"mögen." #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "Katzenfutter" -msgstr[1] "Katzenfutter" +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "" +msgstr[1] "" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'wet cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'dry cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." msgstr "" -"Dies ist Futter für Katzen. Es riecht seltsam, aber Katzen scheinen es zu " -"mögen." #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -52527,6 +52621,34 @@ msgstr "" "Filzfetzen, die für die Lagerung eng zusammengebunden wurden. Demontiere " "dies, um es auszupacken." +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -57107,6 +57229,58 @@ msgid "" "wound." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -58941,7 +59115,7 @@ msgstr[1] "" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "" #: lang/json/GENERIC_from_json.py @@ -59142,6 +59316,20 @@ msgid "" "anything on its own." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -61290,6 +61478,110 @@ msgid "" "somewhat warm to the touch." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -64792,6 +65084,17 @@ msgstr "" "Ein Metallwasserhahn, der an einem Wassertank für die einfache Entnahme " "angebracht werden kann." +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "" + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -70756,6 +71059,34 @@ msgid "" "thrower." msgstr "" +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "" + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -71833,6 +72164,49 @@ msgid "" "able to give them back some humanity. If only they cared…" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -72086,6 +72460,23 @@ msgid "" "appears to have a mininuke inside. If this is targeting you… Run." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -74110,6 +74501,21 @@ msgstr "" "mit seinen tödlichen Klauen, bevor er ihr mit seinen enormen Reißzähnen den " "Todesstoß versetzt." +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -76584,6 +76990,20 @@ msgstr[1] "" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -76676,6 +77096,72 @@ msgid "" "looking for patient to assist." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "Skeletthund" +msgstr[1] "Skeletthunde" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" +"Dieser ehemals Hundeartige hat all seine Haut verloren, was eine Kruste aus " +"verschmolzenen Knochen und Rippen offenbart. Ihm fehlt jegliches Fleisch. " +"Dieser gehende Anzug aus Knochen scheint von einem Netz aus Venen und Sehnen" +" gesteuert zu werden, durch denen ein glitzernder schwarzer Glibber " +"pulsiert." + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "" +msgstr[1] "" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -76793,26 +77279,6 @@ msgstr "" "Die deformierte, wiederbelebte Leiche eines Hundeartigen und ein sehniges " "Biest, das leicht seine zweibeinigen Freunde abhängen kann." -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "Skeletthund" -msgstr[1] "Skeletthunde" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" -"Dieser ehemals Hundeartige hat all seine Haut verloren, was eine Kruste aus " -"verschmolzenen Knochen und Rippen offenbart. Ihm fehlt jegliches Fleisch. " -"Dieser gehende Anzug aus Knochen scheint von einem Netz aus Venen und Sehnen" -" gesteuert zu werden, durch denen ein glitzernder schwarzer Glibber " -"pulsiert." - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -76943,6 +77409,32 @@ msgstr "" "Ein ansonsten normalaussehender Puma, außer, dass seine Hinterläufe " "angeschwollen und seine Augen mit einem schwarzen Glibber unterlaufen sind." +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -77577,6 +78069,46 @@ msgstr "" msgid "The impaler launches a barb!" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -79964,20 +80496,6 @@ msgid "" " black eyes, and a tattered sail on its back." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -79989,33 +80507,6 @@ msgstr[1] "" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "" - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -80124,20 +80615,6 @@ msgid "" "sickle-like claw." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "" -msgstr[1] "" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -80191,6 +80668,350 @@ msgid "" "like a frill." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -80660,6 +81481,19 @@ msgid "" "off creatures that disturb it." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -81332,6 +82166,14 @@ msgstr "" msgid "a bird" msgstr "" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "" + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "" @@ -82205,6 +83047,17 @@ msgid "" "rune as a catalyst for recipes." msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "" @@ -82427,6 +83280,15 @@ msgstr "" msgid "Uses a little fatigue" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "" @@ -82853,6 +83715,10 @@ msgstr "" msgid "Haste" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "" @@ -86990,6 +87856,19 @@ msgid_plural "bionic firestarters" msgstr[0] "Bionikanzünder" msgstr[1] "Bionikanzünder" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -87063,7 +87942,7 @@ msgstr[1] "" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "Licht" @@ -89977,12 +90856,6 @@ msgid_plural "pseudo butter churns" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -92515,17 +93388,37 @@ msgid_plural "throwable fire extinguishers" msgstr[0] "Wurf-Feuerlöscher" msgstr[1] "Wurf-Feuerlöscher" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "" + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." +msgstr "" + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" msgstr "" -"Dies ist ein Feuerlöscher im Formfaktor einer Granate. Er ist nicht so " -"effektiv wie ein regulärer Feuerlöscher, aber du kannst ihn aus der Ferne " -"anwenden. Er wird durch Hitze aktiviert, also wirf ihn einfach in die " -"Flammen." #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -99530,7 +100423,7 @@ msgid "Pheidippides was a hack" msgstr "" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "" #: lang/json/achievement_from_json.py @@ -99597,6 +100490,592 @@ msgstr "" msgid "Return to the location you started the game" msgstr "" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "Holzfäller" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "Dr. med." + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "Fallensteller" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "" + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "Minesweeper" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "Schneider" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "Überlebenskünstler" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "Soldat" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "Einbrecherin" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "" + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "" @@ -100049,6 +101528,11 @@ msgstr "" msgid "canceling activity serialized with legacy code" msgstr "" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "Fusionszelle" @@ -100351,6 +101835,10 @@ msgstr "sprühbare Chemikalie" msgid "compressed air" msgstr "" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "" @@ -102442,6 +103930,62 @@ msgstr "" msgid "Merciful" msgstr "" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -103072,10 +104616,6 @@ msgstr "Wand gelb anmalen" msgid "Take Paint Off Wall" msgstr "Farbe von Wand entfernen" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "Teppich entfernen" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "Boden mit roten Teppich belegen" @@ -103116,6 +104656,30 @@ msgstr "" msgid "Mine Upstair" msgstr "Nach oben abbauen" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "Fahrzeugbau beginnen" @@ -106348,7 +107912,7 @@ msgstr "Du nimmst einen Zug oder zwei." msgid "You smoked too much." msgstr "Du hast zu viel geraucht." -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "Zugedröhnt" @@ -108426,6 +109990,18 @@ msgstr "Feuer" msgid "raging fire" msgstr "wütendes Feuer" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "Altschotter" @@ -109449,8 +111025,7 @@ msgid "" msgstr "" #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "»Krach!«." @@ -109618,7 +111193,7 @@ msgid "" msgstr "" #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "»Knirsch!«." @@ -110260,9 +111835,8 @@ msgstr "Fitness-Gerät" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." msgstr "" #: lang/json/furniture_from_json.py @@ -110351,6 +111925,18 @@ msgid "" " to be scavanged." msgstr "" +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "" + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "Laufband" @@ -110363,6 +111949,18 @@ msgid "" "you're probably getting enough cardio on your own." msgstr "" +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "schwerer Sandsack" @@ -111647,10 +113245,6 @@ msgstr "" msgid "filled arc furnace" msgstr "" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "Räuchergestell" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -112406,7 +114000,8 @@ msgstr "Fake-Gewehr, welches Säureklumpen feuert." msgid "auto" msgstr "automatisch" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "Gewehr" @@ -112611,8 +114206,8 @@ msgstr "" "Isolierband und Elektronik besteht, wird sie von einer Standard-Esz. " "betrieben." -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "Pistole" @@ -112687,7 +114282,7 @@ msgstr "" "Ein mehrschüssiges pneumatisches Gewehr, welches aus Schrott selbst " "zusammengebaut wurde. Es ist sehr leise und tödlich." -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "halbautomatisch" @@ -113208,8 +114803,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" +msgid "MAS .223" +msgid_plural "MAS .223" msgstr[0] "" msgstr[1] "" @@ -115817,15 +117412,15 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" msgstr[0] "" msgstr[1] "" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " @@ -115955,6 +117550,39 @@ msgstr "" " Kaliber 12 besteht. Historisch von egomanischen Jägern in Afrika benutzt, " "nun von ihren egomanischen Nachkommen in Neuengland benutzt." +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -116501,8 +118129,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" msgstr[0] "" msgstr[1] "" @@ -117312,6 +118940,26 @@ msgstr[1] "" msgid "Bionic one-shot subdermal .40 pistol integrated with your head." msgstr "" +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "" +msgstr[1] "" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "" + #: lang/json/gun_from_json.py msgid "CRIT .5 LP" msgid_plural "CRIT .5 LPs" @@ -118103,12 +119751,6 @@ msgid "" "reliability." msgstr "" -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "" -msgstr[1] "" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -120295,6 +121937,12 @@ msgstr "" "Du suchst nach rettenswerter Bionik-Hardware in dem, was von diesem " "fehlgeschlagenem Experiment noch übrig geblieben ist." +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -122332,10 +123980,6 @@ msgstr "Etwas schreiben" msgid "Teleport yourself" msgstr "Dich selbst teleportieren" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "Ein Feuer löschen" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "Dich trocknen/reinigen" @@ -123708,6 +125352,14 @@ msgstr "Protagonistenerstellungsbildschirm verlassen" msgid "Toggle sorting order" msgstr "Sortierreihenfolge umschalten" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "Beschreibung hochscrollen" @@ -124108,6 +125760,10 @@ msgstr "Gegenstände demontieren" msgid "Sleep" msgstr "Schlafen" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "Fahrzeug steuern" @@ -124581,12 +126237,12 @@ msgstr "Farbvorlage laden" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "Ja" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "Nein" @@ -129994,7 +131650,7 @@ msgstr "" msgid "There is always work to be done, song to be woven." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -130002,16 +131658,16 @@ msgid "" " you." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -131389,10 +133045,8 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "" -"Ich werde dich dann sehen… oder auch nicht, und dann werde ich wissen, dass " -"ich die richtige Entscheidung getroffen habe. " #: lang/json/mission_def_from_json.py msgid "" @@ -131402,8 +133056,8 @@ msgstr "" " dich erahnen. " #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." -msgstr "Nun, du bist nicht tot… noch nicht. " +msgid "Well, you're not dead… yet." +msgstr "" #: lang/json/mission_def_from_json.py msgid "" @@ -143823,8 +145477,7 @@ msgid "Well, maybe you'll just have to make your own world wide web." msgstr "" "Tja, vielleicht musst du einfach nur dein eigenes World Wide Web spinnen." -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "Überlebender" @@ -144202,10 +145855,6 @@ msgid "" "you." msgstr "" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "Dr. med." - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -144615,11 +146264,29 @@ msgid "" msgstr "" #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "Überlebendengeschichte" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgid "Survivor: Confused 1" +msgstr "" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -144627,6 +146294,86 @@ msgstr "Überlebendengeschichte" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "Überlebendengeschichte" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "" @@ -146465,10 +148212,6 @@ msgstr "Ich versuche lediglich, zu überleben." msgid "I'm tracking game." msgstr "Ich verfolge Wild." -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "Soldat" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "Barkeeper" @@ -147218,10 +148961,6 @@ msgstr "Schläger" msgid "Laborer" msgstr "Arbeiter" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "Holzfäller" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "Holzarbeiter" @@ -149735,6 +151474,18 @@ msgstr "Straße mit Gullyloch" msgid "bridge" msgstr "Brücke" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "Straßensperre" @@ -165291,103 +167042,6 @@ msgstr "" msgid "I'd kill for a sip of water right now." msgstr "" -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "" -"Sicher, ich hab gemerkt, dass du ein Bier dabei hast! Lasst uns einen heben " -"und quatschen, , wie geht’s?" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "" -"Absolut, wie wäre es mit einem der Biere, die du dabei hast? Wie geht’s, wie" -" steht’s?" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "" -"Also wenn du diese Biere, die ich bei dir sehe, teilst, dann können wir die " -"ganze Zeit quatschen! Nur Spaß! Was geht, ?" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "Kein Problem, , ich brauch sowieso eine Pause, wie geht’s?" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "Ja, OK, , wie geht’s?" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "Sicher, lasst uns rumquatschen! In Ordnung?" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "Warum nicht? Wie geht es dir?" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "Okay. Was gibt’s?" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "Ich habe ein paar Minuten Zeit, wie stehen die Dinge?" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "Sicher, , alles klar?" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "In Ordnung, willst du etwas loswerden?" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "Immer bereit für einen guten Plausch! Aber wieso, bist du OK?" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "" -"OK , wir sollten uns besser kennen lernen. Wie kommst du zurecht?" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "Definitiv, ich mach mit. Wie geht es so?" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "verdammt" @@ -167853,6 +169507,18 @@ msgstr "" msgid "Was it rough surviving thus far?" msgstr "" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -168568,6 +170234,301 @@ msgstr "" msgid " will follow normal engagement rules." msgstr "" +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "Okay. Was gibt’s?" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "Sicher, , alles klar?" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "In Ordnung, willst du etwas loswerden?" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "Immer bereit für einen guten Plausch! Aber wieso, bist du OK?" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -169925,6 +171886,14 @@ msgstr "" "hülsenloser Munition. Die Beschriftung lautet: »Rivtechs hülsenlose 8×40mm-" "Munition: Nichts anderes kommt ihr nahe.«" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -169934,6 +171903,21 @@ msgid "" " reads: \"WE ARE HERE TO PROTECT YOU.\"" msgstr "" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -181957,11 +183941,11 @@ msgid "Acolyte." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" +msgid "You're back. Have you come to listen to the song?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" +msgid "You there. Quiet down. Can you hear it? The song?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -181996,8 +183980,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -182010,11 +183994,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" @@ -182032,11 +184016,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" #: lang/json/talk_topic_from_json.py @@ -182045,7 +184029,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "" @@ -182059,10 +184043,10 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" #: lang/json/talk_topic_from_json.py @@ -182072,7 +184056,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" @@ -182088,8 +184072,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" @@ -182099,9 +184083,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" #: lang/json/talk_topic_from_json.py @@ -182159,14 +184143,6 @@ msgstr "" msgid "Perhaps another time, Seer." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "" @@ -182175,10 +184151,6 @@ msgstr "" msgid "Not interested." msgstr "Bin nicht interessiert." -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "" @@ -182195,20 +184167,13 @@ msgstr "" msgid "I'm off then." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "" @@ -182219,7 +184184,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "" #: lang/json/talk_topic_from_json.py @@ -182234,11 +184199,6 @@ msgstr "" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "" @@ -182250,14 +184210,14 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" #: lang/json/talk_topic_from_json.py @@ -182284,6 +184244,14 @@ msgstr "" msgid "Skip it, let's get going." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "Lass uns über Fraktionslager sprechen." + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "" @@ -182462,7 +184430,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -182623,8 +184591,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -182646,7 +184614,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -182698,8 +184666,8 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." -msgstr "Nein, einfach nein, …" +msgid "No, just no…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Just let me sleep, !" @@ -182710,8 +184678,8 @@ msgid "Make it quick, I want to go back to sleep." msgstr "Mach schnell, ich will mich wieder schlafen legen." #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." -msgstr "Nur noch ein paar Minuten …" +msgid "Just few minutes more…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Anything to do before I go to sleep?" @@ -182756,6 +184724,68 @@ msgstr "" msgid "I want to set some miscellaneous rules." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "I'd like to know a bit more about your abilities." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "There's something I want you to do." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I just wanted to talk for a bit." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you help me understand something? (HELP/TUTORIAL)" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I'm going to go my own way for a while." +msgstr "Für eine Weile werde ich meinen eigenen Weg gehen." + +#: lang/json/talk_topic_from_json.py +msgid "Let's go." +msgstr "Los geht’s!" + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what did you want to say?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Mind if we just chat for a bit about your history?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Let's just chitchat for a while, I could use some relaxation." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I changed my mind, wanted to ask you something else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I'm all ears, my friend." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You gonna give me orders?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What would you like?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Just say the word." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Can you teach me anything?" msgstr "Kannst du mir irgendetwas beibringen?" @@ -182780,14 +184810,6 @@ msgstr "Bewach diese Position." msgid "I want to assign you to work at this camp." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "Lass uns über Fraktionslager sprechen." - #: lang/json/talk_topic_from_json.py msgid "Find a horse and mount up!" msgstr "" @@ -182801,33 +184823,21 @@ msgid "Please go to this location." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" -msgstr "" +msgid "I want you to build a camp here." +msgstr "Ich will, dass du hier ein Lager errichtest." #: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" -msgstr "" +msgid "We need to abandon this camp." +msgstr "Wir müssen dieses Lager aufgeben. " #: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." +msgid "Show me what needs to be done at the camp." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." +msgid "Let's talk about your current activity." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "Für eine Weile werde ich meinen eigenen Weg gehen." - -#: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "Los geht’s!" - #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." msgstr "" @@ -183369,10 +185379,6 @@ msgstr "" msgid "Stay at your current position." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "" @@ -183445,64 +185451,6 @@ msgstr "" msgid "Sure thing, I'll make my way there." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "" -"Ja, die Sommerhitze trifft mich hart. Lass uns eine kurze Pause machen. Wie " -"geht es ?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "" -"Okay, vielleicht wird es mir helfen, in diesem Wetter nicht zu erfrieren. " -"Was ist los?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -183557,8 +185505,8 @@ msgid "Hello there." msgstr "Hallo." #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." -msgstr "Okay, keine plötzlichen Bewegungen!" +msgid "Okay, no sudden movements…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep your distance!" @@ -183920,8 +185868,8 @@ msgid "Ah, okay." msgstr "Ah, okay." #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." -msgstr "Nicht, bevor ich ein paar Antibiotika kriege." +msgid "Not until I get some antibiotics…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "You asked me recently; ask again later." @@ -184028,8 +185976,8 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." -msgstr "Nur Geduld, ich werd dir später etwas neues zeigen …" +msgid "Give it some time, I'll show you something new later…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I have some reason for denying you training." @@ -184056,8 +186004,8 @@ msgid "See you around." msgstr "Wir sehen uns." #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." -msgstr "Damit fühl ich mich nicht so ganz wohl …" +msgid "I really don't feel comfortable doing so…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I'll give you some space." @@ -184128,7 +186076,7 @@ msgid "Thanks, see you later!" msgstr "Danke, bis später!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." +msgid "You picked up something that does not belong to you…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -184224,13 +186172,13 @@ msgid "You might be seeing more of me…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" +msgid "Hey again. *kzzz*" msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "" #: lang/json/talk_topic_from_json.py @@ -184252,7 +186200,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -184265,7 +186213,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "" @@ -184287,7 +186235,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -184303,7 +186251,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -184338,14 +186286,6 @@ msgstr "Sag mir, wie Fraktionslager funktionieren." msgid "Tell me how faction camps have changed." msgstr "Sag mir, wie sich Fraktionslager verändert haben." -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "Ich will, dass du hier ein Lager errichtest." - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "Wir müssen dieses Lager aufgeben. " - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "Nichts. Lass uns über etwas anderes reden." @@ -184597,10 +186537,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." +"talk…" msgstr "" -"Bist du sicher? Das scheint kein besonders sicherer Ort für Smalltalk zu " -"sein ..." #: lang/json/talk_topic_from_json.py msgid "It's fine, we've got a moment." @@ -184622,6 +186560,50 @@ msgstr "Worüber wolltest du reden?" msgid "Actually, never mind." msgstr "Ähm, vergiss es." +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "Ja, Freund?" @@ -184643,7 +186625,7 @@ msgid "May the earth flourish beneath our paths." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -184827,8 +186809,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" @@ -185437,7 +187419,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -185922,6 +187904,38 @@ msgstr "" msgid "Huh." msgstr "Huh." +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -185974,21 +187988,9 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" -"Irgendwann, ja. Es war stundenlang ruhig. Ich war ausgetrocknet, verletzt " -"und voller Furcht. Meine Ausbildung war vielleicht das Einzige, was mich " -"davon abhielt, durchzudrehen. Ich beschloss, mich hinauszuziehen und zu " -"sehen, wie schlimm meine Verletzungen waren. Es war leicht. Die Seite" -" des Transporters war aufgerissen und es zeigte sich, dass ich einfach nur " -"unter ein paar Trümmern begraben war, mit den Ruinen des Wagen um mich " -"herum, wie bei einem Zelt. Ich war noch nichtmal sonderlich schwer verletzt." -" Ich schnappte mir soviel Zeug, wie ich konnte, und zog mich hinaus. Es war " -"Nacht. Von weiter weg in der Stadt konnte ich Kämpfe hören, also ging ich in" -" die andere Richtung. Ich habe ein paar Häuserblocks geschafft, bevor ich " -" begegnet bin … Ich rannte von ihnen fort. Ich rannte und rannte, " -"und dann rannte ich noch mehr. Und hier bin ich." #: lang/json/talk_topic_from_json.py msgid "" @@ -186342,6 +188344,30 @@ msgstr "Armer Schmutziger Dan. " msgid "Thanks for telling me that stuff. " msgstr "Danke, dass du mir das Zeug erzählt hast. " +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -186404,6 +188430,24 @@ msgid "" "died in the crash, but I am not going back to find out." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -186443,6 +188487,21 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "Was glaubst du, was passiert ist? Siehst du sie hier irgendwo?" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -186512,6 +188571,40 @@ msgid "" "pretty good life compared to those first few months." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -186524,6 +188617,50 @@ msgstr "" "Er war mit den anderen Passagieren beschäftigt, also tat ich, was jeder tun " "würde und verpisste mich auf der Stelle." +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -186577,6 +188714,27 @@ msgstr "Entschuldigung! Könntest du mir mehr über sie erzählen?" msgid "Right. Sorry." msgstr "Richtig. Es tut uns leid." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -186599,6 +188757,19 @@ msgstr "" "der Ort war völlig verlassen. Ich habe keine Ahnung, was mit all diesen " "Leuten passiert ist." +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -186703,6 +188874,42 @@ msgstr "Tut mir leid, dass ich gefragt habe.. " msgid "Sorry for asking. " msgstr "Tut mir leid, dass ich gefragt habe.. " +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -187434,6 +189641,48 @@ msgstr "" "in die Wälder, um mich alleine durchzuschlagen. Ich hab mich nicht gerade " "gut angestellt, also bin ich ziemlich froh, dass du aufgetaucht bist." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -187500,6 +189749,128 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "Danke, dass du mir das alles erzählt hast. " +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -187832,13 +190203,48 @@ msgstr "" msgid "I can respect that." msgstr "Das kann ich respektieren." +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "Danke dafür." + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -187943,6 +190349,43 @@ msgstr "" " ich wütend. Wer ich war, ist fort. Tot. Dein Gelaber über »gesund sein« ist" " mir scheißegal, frag nicht noch mal. Himmel, Arsch und Zwirn!" +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -188321,11 +190764,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "" -"Steuerhinterziehung. Ich war Buchhalter und habe meinem Boss geholfen auf " -"einigen sehr cleveren Wegen verdammt viel Geld zu bewegen. Nicht clever " -"genug, wie sich herausgestellt hat ..." #: lang/json/talk_topic_from_json.py msgid "" @@ -188551,6 +190991,32 @@ msgstr "" "können, oder? Ich vermute, vielleicht sind wir die, die da reinen Herzens " "sind, welche die Erde erben sollen. Wobei ich unsere Chancen nicht mag." +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -188562,6 +191028,23 @@ msgstr "" " denke ich, wandere ich auf Höllen auf Erden. Ich wünschte, ich hätte mehr " "in der Sonntagsschule aufgepasst." +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -188838,10 +191321,6 @@ msgstr "Wie war es für die Freien Händler zu arbeiten?" msgid "What was working for the Old Guard like?" msgstr "Wie war es für die Alte Garde zu arbeiten?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "Danke dafür." - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "Danke dafür. Lass uns anfangen." @@ -189136,6 +191615,22 @@ msgstr "" msgid "What were you saying before that?" msgstr "Was hast du davor gesagt?" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "Hallöchen!" @@ -189659,7 +192154,7 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -190052,10 +192547,6 @@ msgid "" " catastrophe." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "" @@ -191553,7 +194044,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" @@ -192294,7 +194785,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -193435,12 +195926,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" #: lang/json/talk_topic_from_json.py @@ -193568,12 +196059,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" #: lang/json/talk_topic_from_json.py @@ -193637,7 +196128,7 @@ msgid "Hm? Oh, hi." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "" #: lang/json/talk_topic_from_json.py @@ -194007,8 +196498,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" #: lang/json/talk_topic_from_json.py @@ -194025,9 +196516,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -194391,9 +196882,8 @@ msgstr "" "und verschwinde verdammtnochmal von hier." #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." +msgid "I'm not in charge here, you're looking for someone else…" msgstr "" -"Ich bin nicht der Verantwortliche hier, du suchst nach jemand anderem …" #: lang/json/talk_topic_from_json.py msgid "Keep civil or I'll bring the pain." @@ -194440,12 +196930,12 @@ msgid "Well, I'd better be going. Bye." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." -msgstr "Willkommen, Marshal…" +msgid "Welcome marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." -msgstr "Willkommen…" +msgid "Welcome…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" @@ -194694,12 +197184,12 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." -msgstr "Marshal…" +msgid "Marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." -msgstr "Bürger…" +msgid "Citizen…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Can I trade for supplies?" @@ -195373,7 +197863,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -195558,15 +198048,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." +msgid "Thinking I should go hunt something soon…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "" #: lang/json/talk_topic_from_json.py @@ -195606,7 +198096,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." +"marshal…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -195676,8 +198166,8 @@ msgstr "" "Ich kann mir nicht vorstellen, wofür ich deine Hilfe benötigen könnte." #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." -msgstr "Rühr dich nicht vom Fleck, während ich meine Schere hole …" +msgid "Stand still while I get my clippers…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Thanks…" @@ -196119,8 +198609,8 @@ msgstr "" "Außenpostens aufhalten." #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." -msgstr "Bitte lass mich in Ruhe …" +msgid "Please leave me alone…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "What's wrong?" @@ -196141,20 +198631,14 @@ msgstr "Das ist traurig." #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." +"I don't know what you could do. I've tried everything. Just give me time…" msgstr "" -"Ich weiß nicht, was du tun könntest. Ich hab alles versucht. Gib mir nur " -"etwas Zeit …" #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." +"seems like I can't keep anything down…" msgstr "" -"Ich werde ständig krank! Zuerst dachte ich, dass es etwas war, das ich " -"gegessen habe, aber jetzt sieht es so aus, als ob ich nichts im Magen " -"behalten könnte." #: lang/json/talk_topic_from_json.py msgid "Uhm." @@ -196286,8 +198770,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "" #: lang/json/talk_topic_from_json.py @@ -196632,7 +199116,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "" @@ -196801,7 +199285,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -196969,7 +199453,7 @@ msgid "Oh, you again." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -196977,7 +199461,7 @@ msgid "I'm busy, what is it?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "" #: lang/json/talk_topic_from_json.py @@ -201356,208 +203840,14 @@ msgid "" msgstr "" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "Erde" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "" -"Es ist Erde. Sieht wie ein guter Boden zum Beackern aus. Könnte auch für " -"Bauprojekte ausgegraben werden." - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "»Bums«" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "" -"Ein großes Feld mit feinem Sand, der auf viele Weisen nützlich sein könnte, " -"wenn er ordnungsgemäßig entnommen würde." - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." +msgid "overgrown floor" msgstr "" -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "Ton" - -#. ~ Description for clay +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "" -"Ein Feld voll mit formbaren Ton, gut geeignet, um in einen Brennofen zu " -"benutzen, wenn man den Ton vorher ordentlich entnimmt." - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "Tonhügel" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "»Platsch!«" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "Sandhügel" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "Erdhügel" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "" -"Ein Feld mit gehäufter Erde, nicht leicht zu überqueren. Wenn man sich dies " -"genauer ansieht, ist das recht gut geeignet zum Pflanzen von Samen und " -"ähnlichen Dingen." - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "" -"Ein riesiger Erdhügel, der so aussieht, als könntest du zum Schutz in ihm " -"hereinkrabbeln." - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "seltsamer Bruch" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" -"Ein unnatürlich menschenförmiges Loch, es scheint seltsam vertraut zu sein. " -"Du hast ein komisches Gefühl, als du es näher untersuchst, als ob es " -"irgendwie zu dir gehören würde." - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "Steinboden" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "" -"Ein relativ flaches Feld aus Gestein. Sieht stabil genug aus, um mit den " -"richtigen Bergarbeiterwerkzeugen ausgegraben zu werden." - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "Straßenbelag" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." -msgstr "" -"Ein Stück Asphalt, langsam zerfällt er von Rissen, Frosthüben und fehlenden " -"Instandsarbeiten." - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "gelber Straßenbelag" - -#. ~ Description for yellow pavement -#: lang/json/terrain_from_json.py -msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" -"Streifen mit sorgfältig ausgerichteter gelber Farbe markieren die Straße, um" -" Fahrern mitzuteilen, sie nicht zu überqueren. Jetzt erzwingt niemand " -"erzwingt diese Reglen mehr." - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "Bügersteig" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "" -"Ein Feld mit herkömmlichen gegossenem Beton, beschädigt von Frosthüben und " -"großen Rissen aufgrund fehlender Instandsetzungsarbeiten." - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "" -"Ein neueres Feld mit gegossenem Beton mit Oberflächenbehandungen für die " -"Ästhetik und Widerstand gegenüber Frost-Tau-Zyklen." - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "Holzfußboden" - -#. ~ Description for wooden floor -#: lang/json/terrain_from_json.py -msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -201565,41 +203855,14 @@ msgid "SMASH!" msgstr "»SCHEPPER!«." #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "Metallboden" - -#. ~ Description for metal floor -#: lang/json/terrain_from_json.py -msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgid "overgrown wall" msgstr "" -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "Linoleum-Kachel" - -#. ~ Description for linoleum tile +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." -msgstr "" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "Erdboden" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." msgstr "" -"Ein Boden, der aus einer sorgfältig gemischten Erde besteht, die " -"zusammengestampft wurde." #: lang/json/terrain_from_json.py msgid "concrete floor" @@ -201698,6 +203961,23 @@ msgstr "" "Boden ist noch nicht geebnet und die Decke ist noch nicht vollständig " "gefüllt." +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "Steinboden" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "" +"Ein relativ flaches Feld aus Gestein. Sieht stabil genug aus, um mit den " +"richtigen Bergarbeiterwerkzeugen ausgegraben zu werden." + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "Metallboden" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -201707,6 +203987,10 @@ msgstr "" "Ein hochwertiger und harter karierter Boden, um das Risiko von Stolpern und " "Stürzen zu verringern, mit einer passenden Decke." +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "»Bums«" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "Boden" @@ -201755,6 +204039,10 @@ msgstr "" "Hartholzfußboden, der mit Chemikalien behandelt wurde, um den " "Rutschwiderstand zu verbessern, üblich für Freizeitsport." +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "Erdboden" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -201842,28 +204130,15 @@ msgid "A blue section of flooring." msgstr "" #: lang/json/terrain_from_json.py -msgid "industrial carpet" -msgstr "" - -#. ~ Description for industrial carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "bunker carpet" +msgid "carpet" msgstr "" -#. ~ Description for bunker carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." +msgid "Base carpet!" msgstr "" -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "Weicher roter Teppich." @@ -201883,6 +204158,124 @@ msgstr "Weicher grüner Teppich." msgid "Soft purple carpet." msgstr "Weicher violetter Teppich." +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "Linoleum-Kachel" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "" + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "farbiger Wachsboden" @@ -201921,6 +204314,37 @@ msgstr "" "postapokalyptischen Barackenstädten. Ich hoffe, du magst das Geräusch von " "Regen auf Wellblech." +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "Erde" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "" +"Es ist Erde. Sieht wie ein guter Boden zum Beackern aus. Könnte auch für " +"Bauprojekte ausgegraben werden." + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "" +"Ein großes Feld mit feinem Sand, der auf viele Weisen nützlich sein könnte, " +"wenn er ordnungsgemäßig entnommen würde." + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "Moos" @@ -201930,6 +204354,32 @@ msgstr "Moos" msgid "Moist spongy moss." msgstr "Feuchtes, schwammiges Moos." +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "Ton" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "" +"Ein Feld voll mit formbaren Ton, gut geeignet, um in einen Brennofen zu " +"benutzen, wenn man den Ton vorher ordentlich entnimmt." + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "Tonhügel" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "»Platsch!«" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "" @@ -201939,6 +204389,150 @@ msgstr "" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "Sandhügel" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "Erdhügel" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "" +"Ein Feld mit gehäufter Erde, nicht leicht zu überqueren. Wenn man sich dies " +"genauer ansieht, ist das recht gut geeignet zum Pflanzen von Samen und " +"ähnlichen Dingen." + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "" +"Ein riesiger Erdhügel, der so aussieht, als könntest du zum Schutz in ihm " +"hereinkrabbeln." + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "seltsamer Bruch" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" +"Ein unnatürlich menschenförmiges Loch, es scheint seltsam vertraut zu sein. " +"Du hast ein komisches Gefühl, als du es näher untersuchst, als ob es " +"irgendwie zu dir gehören würde." + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "Straßenbelag" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr "" +"Ein Stück Asphalt, langsam zerfällt er von Rissen, Frosthüben und fehlenden " +"Instandsarbeiten." + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "gelber Straßenbelag" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "" +"Streifen mit sorgfältig ausgerichteter gelber Farbe markieren die Straße, um" +" Fahrern mitzuteilen, sie nicht zu überqueren. Jetzt erzwingt niemand " +"erzwingt diese Reglen mehr." + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "Bügersteig" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "" +"Ein Feld mit herkömmlichen gegossenem Beton, beschädigt von Frosthüben und " +"großen Rissen aufgrund fehlender Instandsetzungsarbeiten." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "" +"Ein neueres Feld mit gegossenem Beton mit Oberflächenbehandungen für die " +"Ästhetik und Widerstand gegenüber Frost-Tau-Zyklen." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "Holzfußboden" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "" +"Ein Boden, der aus einer sorgfältig gemischten Erde besteht, die " +"zusammengestampft wurde." + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "Walnussbaum" @@ -206049,6 +208643,78 @@ msgstr "" msgid "A ladder leading down." msgstr "" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "Gefälle" @@ -206540,7 +209206,7 @@ msgstr "Klänk!" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "»Knall!«." @@ -209305,6 +211971,15 @@ msgid "" "extending the time until the food spoils." msgstr "" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "" @@ -210154,8 +212829,9 @@ msgstr "" msgid "The lock stumps your efforts to pick it." msgstr "Der Dietrich stumpft bei deinem Einbruchsversuch ab." -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "" @@ -210216,6 +212892,120 @@ msgstr "" msgid "Continue trying to fall asleep and don't ask again." msgstr "" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -214868,6 +217658,29 @@ msgstr "%s (%i Plätze);" msgid "Increased storage capacity by %i." msgstr "Bionik-Stromkapazität um %i erhöht." +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "" @@ -215038,7 +217851,8 @@ msgid "(incapacitated)" msgstr "" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" +#, c-format +msgid "(fuel saving ON > %d %%)" msgstr "" #: src/bionics_ui.cpp @@ -215740,6 +218554,23 @@ msgstr "" "Du versuchst, dich aus den Spinnennetzen zu befreien, doch du kommst nicht " "los!" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "" + +#: src/character.cpp +msgid " frees themselves!" +msgstr "" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "Du versucht, dem Abgrund zu entkommen, aber rutschst wieder herein." @@ -216602,6 +219433,10 @@ msgstr "" msgid "Your body strains under the weight!" msgstr "Dein Körper verrenkt sich unter der Last!" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -220735,15 +223570,6 @@ msgid "" "Roof: %s" msgstr "" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -224733,6 +227559,10 @@ msgstr "Du hast nichts zum Nachladen." msgid "You aren't holding something you can reload." msgstr "Du hältst nichts, was du nachladen kannst." +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -227326,6 +230156,10 @@ msgstr "Laseranvisierung wird ignoriert!" msgid "Creature whitelisted: %s" msgstr "Kreatur auf die Weißliste gesetzt: %s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "Selbstmord begehen?" @@ -228715,11 +231549,28 @@ msgstr "" msgid "There is a %s there. Take down?" msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "Dort ist 1 %s. Entschärfen?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "Du entschärfst die Falle!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "Dir misslingt das Entschärfen der Falle." + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "Du versagst beim Entschärfen der Falle und löst sie aus!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -229615,6 +232466,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "" + #: src/init.cpp msgid "Finalizing" msgstr "Fertigstellung" @@ -230663,7 +233519,7 @@ msgstr "" "Dieses Lebensmittel hat angefangen zu faulen. Es zu " "essen wäre eine sehr schlechte Idee. " -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -232410,6 +235266,13 @@ msgstr "" msgid "is not a container" msgstr "" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "" +msgstr[1] "" + #: src/item_contents.cpp msgid "is not rigid" msgstr "" @@ -232476,6 +235339,10 @@ msgstr "" msgid "Pocket %d:" msgstr "" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "" + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "" @@ -234319,10 +237186,6 @@ msgstr "Snake" msgid "Sokoban" msgstr "Sokoban" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "Minesweeper" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "Licht an!" @@ -237271,7 +240134,7 @@ msgstr "%s benötigt %s daneben." msgid "You can't place a %s there. It contains a trap already." msgstr "Du kannst hier keinen %s platzieren. Dort ist bereits eine Falle." -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "Du löst 1 %s aus!" @@ -239046,6 +241909,15 @@ msgstr "" msgid "Summon" msgstr "" +#: src/magic.cpp +msgid "random creature" +msgstr "" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "Reichweite" @@ -239066,6 +241938,10 @@ msgstr "" msgid "Spawned" msgstr "" +#: src/magic.cpp +msgid "Threshold" +msgstr "" + #: src/magic.cpp msgid "Recover" msgstr "" @@ -239118,6 +241994,15 @@ msgstr "" msgid "%s wounds are closing up!" msgstr "" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "" @@ -239575,30 +242460,23 @@ msgstr "" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "Du entschärfst die Falle!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "Dir misslingt das Entschärfen der Falle." +msgid "Something has crawled out of the %s plants!" +msgstr "Etwas krabbelte aus der Hose von %s!" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "Du versagst beim Entschärfen der Falle und löst sie aus!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "Etwas krabbelte aus %s!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "Etwas krabbelte aus der Hose von %s!" +msgid "You've spotted a %1$ss!" +msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "Etwas krabbelte aus %s!" +msgid " triggers a %s!" +msgstr "" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -241168,6 +244046,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "Ist von der Polizei gesucht geworden!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -245000,6 +247891,11 @@ msgstr "" msgid "zombie slave" msgstr "Zombiesklave" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "%s schieben" + #: src/monexamine.cpp msgid "Rename" msgstr "Umbenennen" @@ -250399,17 +253295,6 @@ msgstr "Mutationen durch Strahlung" msgid "If true, radiation causes the player to mutate." msgstr "Falls wahr, wird Strahlung den Spieler zum Mutieren bringen." -#: src/options.cpp -msgid "Z-levels" -msgstr "" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" - #: src/options.cpp msgid "Character point pools" msgstr "Punktevorratsmodi" @@ -255286,6 +258171,15 @@ msgctxt "grammatical gender list" msgid "n" msgstr "" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "Du trittst auf eine Luftpolsterfolie!" diff --git a/lang/po/es_AR.po b/lang/po/es_AR.po index 301b8ddb86cab..9681701566443 100644 --- a/lang/po/es_AR.po +++ b/lang/po/es_AR.po @@ -1,7 +1,7 @@ # # Translators: -# Brett Dong , 2020 # Vlasov Vitaly , 2020 +# Brett Dong , 2020 # Diego Gonzalo Ballesteros Palomo , 2020 # Noctivagante , 2020 # @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: Noctivagante , 2020\n" "Language-Team: Spanish (Argentina) (https://www.transifex.com/cataclysm-dda-translators/teams/2217/es_AR/)\n" @@ -935,6 +935,17 @@ msgstr "" "Es una mezcla respirable de oxígeno y nitrógeno en proporciones adecuadas " "para utilizar en buceo." +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "agente extintor" +msgstr[1] "agente extintor" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "Es una solución química seca efectiva para extinguir fuegos." + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -1561,7 +1572,7 @@ msgid "" "produced when it burns will quickly clog any firearm, but it could be used " "to make some vicious bombs." msgstr "" -"Un puñado de pólvora negra, hecha mezclando carbón y azufre con nitro. " +"Es un puñado de pólvora negra, hecha mezclando carbón y azufre con nitro. " "Bastante inservible para hacer cartuchos modernos, ya que el hollín " "producido cuando se quema obstruirá el arma, pero puede usarse para hacer " "algunas bombas." @@ -4914,6 +4925,31 @@ msgstr "" "química. Es mejor utilizarlo con alguna clase de máscara o protección para " "la boca." +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "bala 12.3ln" +msgstr[1] "balas 12.3ln" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" +"El cartucho 12.3ln fue presentado en Rumania al inicio del segundo conflicto" +" de los Cárpatos. El rifle PA md. 71 usaba esta munición y ganó popularidad " +"rápidamente en la Unión Europea, y desde allí, en el mundo. Debido a esto, " +"el 12.3ln se convirtió rápidamente en la bala estándar de combate en " +"Eurasia. Pudo ser fácilmente recolectada y almacenada por los Exodii. Se ve " +"y se siente parecido al cartucho .30-06 Springfield pero con un pulido " +"ligeramente más puntiagudo." + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -5258,7 +5294,7 @@ msgid "" "A heavy metal slug used with shotguns to give them the range capabilities of" " a rifle. Extremely damaging but rather inaccurate." msgstr "" -"Una posta pesada utilizada en escopetas para que tengan el alcance de un " +"Es una posta pesada utilizada en escopetas para que tengan el alcance de un " "rifle. Causan muchísimo daño pero son poco precisas." #: lang/json/AMMO_from_json.py @@ -6110,7 +6146,7 @@ msgstr[1] "pintura amarilla" msgid "A can of yellow paint." msgstr "Una lata de pintura amarilla." -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "alfombra roja" @@ -6957,7 +6993,7 @@ msgstr "" #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "lead pellets" msgid_plural "lead pelletss" -msgstr[0] "perdigón de plomo" +msgstr[0] "perdigones de plomo" msgstr[1] "perdigones de plomo" #. ~ Description for lead pellets @@ -8480,11 +8516,11 @@ msgstr[1] "bolsas de munición" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." +"rockets will not fit. Use insert to store ammunition." msgstr "" "Es una pequeña bolsa que puede usarse para almacenar la mayoría de las " -"municiones pequeñas, los misiles no entran. Hay que activarla para almacenar" -" la munición." +"municiones pequeñas, los misiles no entran. Usá insertar para guardar la " +"munición." #: lang/json/ARMOR_from_json.py msgid "ammo satchel" @@ -8595,11 +8631,11 @@ msgstr[1] "aljabas" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." msgstr "" "Es una aljaba de cuero que se usa en la cintura y puede almacenar hasta 20 " -"flechas. Hay que usarla para guardar flechas." +"flechas o pernos. Usá insertar para guardar las flechas o los pernos." #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -8611,11 +8647,11 @@ msgstr[1] "aljabas de abedul" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." +"20 arrows or bolts. Use insert to store arrows or bolts." msgstr "" "Es una aljaba tejida de pedazos de corteza de abedul, que se usa en la " -"cintura y puede almacenar hasta 20 flechas. Hay que usarla para guardar " -"flechas." +"cintura y puede almacenar hasta 20 flechas o pernos. Usá insertar para " +"guardar las flechas o los pernos." #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -8627,13 +8663,15 @@ msgstr[1] "aljabas grandes" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" "Es una aljaba grande de cuero adornada con metal, se usa en la espalda y " -"puede almacenar hasta 60 flechas. Históricamente fue utilizada por los " -"arqueros a caballo, más que por los que iban a pie, pero ninguno de ELLOS " -"tuvo que pelearse contra zombis. Hay que usarla para guardar flechas." +"puede almacenar hasta 60 flechas o pernos. Históricamente fue utilizada por " +"los arqueros a caballo, más que por los que iban a pie, pero ninguno de " +"ELLOS tuvo que pelearse contra zombis. Usá insertar para guardar las flechas" +" o los pernos." #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -8645,11 +8683,11 @@ msgstr[1] "aljabas grandes de abedul" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." +"hold 60 arrows or bolts. Use insert to store arrows or bolts." msgstr "" -"Es una aljaba grande tejida de pedazos de corteza de abedul, se usa en la " -"espalda y puede almacenar hasta 60 flechas. Hay que usarla para guardar " -"flechas." +"Es una aljaba grande tejida de pedazos de corteza de abedul, que se usa en " +"la espalda y puede almacenar hasta 60 flechas o pernos. Usá insertar para " +"guardar las flechas o los pernos." #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -9125,9 +9163,9 @@ msgid "" " doubles as an equipment belt with a reinforced loop for holding a large " "tool." msgstr "" -"Un cinturón resistente de bombero. Además de mantener tu ropa en su lugar, " -"también sirve llevar herramientas con una presilla reforzada para poner una " -"herramienta grande." +"Es un cinturón resistente de bombero. Además de mantener tu ropa en su " +"lugar, también sirve llevar herramientas con una presilla reforzada para " +"poner una herramienta grande." #: lang/json/ARMOR_from_json.py msgid "judo belt template" @@ -20155,13 +20193,13 @@ msgstr "" #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." msgstr "" -"Una valija mediana usada generalmente para transportar ropa y otras " -"posesiones durante los viajes. Tiene buena capacidad de almacenamiento pero " -"ir arrastrándola por ahí no es ni rápido ni cómodo." +"Es una valija mediana con ruedas usada generalmente para transportar ropa y " +"otras posesiones durante los viajes. Tiene buena capacidad de almacenamiento" +" pero ir arrastrándola por ahí no es ni rápido ni cómodo." #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -22676,8 +22714,8 @@ msgstr "" #: lang/json/ARMOR_from_json.py msgid "cestus" msgid_plural "cestuses" -msgstr[0] "caestus" -msgstr[1] "caestus" +msgstr[0] "cestus" +msgstr[1] "cesti" #. ~ Description for {'str': 'cestus', 'str_pl': 'cestuses'} #: lang/json/ARMOR_from_json.py @@ -22804,8 +22842,8 @@ msgstr "" #: lang/json/ARMOR_from_json.py msgid "sentinel-lx cloak" msgid_plural "sentinel-lx cloaks" -msgstr[0] "capa sentinel-lx" -msgstr[1] "capas sentinel-lx" +msgstr[0] "capa centinela-lx" +msgstr[1] "capas centinela-lx" #. ~ Description for {'str': 'sentinel-lx cloak'} #: lang/json/ARMOR_from_json.py @@ -22814,8 +22852,8 @@ msgid "" "unnatural shadow. Made from woven graphene, its lightweight and resistant, " "but cannot be repaired" msgstr "" -"Esta capa sentinel-lx hecha de vantablack, cuelga sobre los hombros como una" -" sombra sólida y antinatural. Hecha de grafeno tejido, es liviano y " +"Esta capa centinela-lx hecha de vantablack, cuelga sobre los hombros como " +"una sombra sólida y antinatural. Hecha de grafeno tejido, es liviano y " "resistente, pero no puede ser reparado." #: lang/json/ARMOR_from_json.py @@ -34932,6 +34970,19 @@ msgstr "" "Con un intenso ritual que recuerda al crossfit, lográs poner a raya un poco " "de tu dolor." +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "Pergamino de Polimorfia Siniestra" +msgstr[1] "Pergaminos de Polimorfia Siniestra" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "Transforma a tus enemigos en sapos." + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -36282,8 +36333,8 @@ msgstr "" #: lang/json/BOOK_from_json.py msgid "Scroll of Coagulant Weave" msgid_plural "Scrolls of Coagulant Weave" -msgstr[0] "Pergamino de Ola Coagulante" -msgstr[1] "Pergaminos de Ola Coagulante" +msgstr[0] "Pergamino de Tejido Coagulante" +msgstr[1] "Pergaminos de Tejido Coagulante" #. ~ Description for {'str': 'Scroll of Coagulant Weave', 'str_pl': 'Scrolls #. of Coagulant Weave'} @@ -36743,6 +36794,23 @@ msgstr "" "Este libro de referencia de laboratorio es grueso y desborda información " "sobre combinar magia con radiación electromagnética." +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "pedazo de Tableta Rúnica" +msgstr[1] "pedazos de Tableta Rúnica" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" +"Es una pequeña tableta de piedra negra, aparentemente cortada de un pedazo " +"mucho más grande. Tiene unas runas doradas brillando en su superficie y va " +"cambiando para formar oraciones inteligibles cuando las mirás." + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -42795,6 +42863,36 @@ msgid "" msgstr "" "Son nachos de maíz salados con carne picada y queso cremoso. Delicioso." +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "nacho de verdura" +msgstr[1] "nachos de verdura" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "" +"Son nachos de maíz salados, ahora con porotos. Le vendría bien un poco de " +"queso." + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "nachos de verdura con queso" +msgstr[1] "nachos de verdura con queso" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "" +"Son nachos de maíz salados con porotos y queso cremoso. Delicioso, incluso " +"si no sos vegetariano." + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -48176,30 +48274,65 @@ msgstr "" " perfecto para pájaros chiquitos." #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "comida para perros" -msgstr[1] "comida para perros" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "comida húmeda para perros" +msgstr[1] "comida húmeda para perros" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'wet dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "" +"Es comida húmeda para perros, hecha con carne fresca enlatada. Tiene un olor" +" extraño, pero a los perros parece que les gusta." + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "comida seca para perros" +msgstr[1] "comida seca para perros" + +#. ~ Description for {'str_sp': 'dry dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." msgstr "" -"Es comida para perros. Tiene un olor extraño, pero a los perros parece que " -"les gusta." +"Son trozos de comida para perros con una caducidad extensa. Hecha con carnes" +" y granos secos procesados, y enriquecida con vitaminas y minerales." #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "comida para gatos" -msgstr[1] "comida para gatos" +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "comida húmeda para gatos" +msgstr[1] "comida húmeda para gatos" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'wet cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." msgstr "" -"Es comida para gatos. Tiene un olor extraño, pero a los gatos parece que les" -" gusta." +"Es comida húmeda para gatos, hecha con carne fresca enlatada. Tiene un aroma" +" intenso que a los gatos parece encantarles." + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "comida seca para gatos" +msgstr[1] "comida seca para gatos" + +#. ~ Description for {'str_sp': 'dry cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" +"Son trozos de alimento balanceado para gatos con una caducidad extensa. " +"Hecho con carnes y granos secos procesados, y enriquecido con vitaminas y " +"minerales." #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -54536,14 +54669,14 @@ msgstr "Es un vaso pequeño que en algún momento estuvo sellado al vacío." #: lang/json/GENERIC_from_json.py msgid "glass flask" msgid_plural "glass flasks" -msgstr[0] "frasco de vidrio" -msgstr[1] "frascos de vidrio" +msgstr[0] "jarra de vidrio" +msgstr[1] "jarras de vidrio" #. ~ Description for {'str': 'glass flask'} #: lang/json/GENERIC_from_json.py msgid "A 250 ml laboratory conical flask, with a rubber bung." msgstr "" -"Es un frasco cónico de laboratorio con una capacidad de 250 ml y un tapón de" +"Es una jarra cónica de laboratorio con una capacidad de 250 ml y un tapón de" " goma." #: lang/json/GENERIC_from_json.py @@ -54626,8 +54759,8 @@ msgstr "" #: lang/json/GENERIC_from_json.py msgid "3L glass jar" msgid_plural "3L glass jars" -msgstr[0] "jarra de vidrio de 3L" -msgstr[1] "jarras de vidrio de 3L" +msgstr[0] "frasco de vidrio de 3L" +msgstr[1] "frascos de vidrio de 3L" #. ~ Description for {'str': '3L glass jar'} #: lang/json/GENERIC_from_json.py @@ -54639,8 +54772,8 @@ msgstr "" #: lang/json/GENERIC_from_json.py msgid "sealed 3L glass jar" msgid_plural "sealed 3L glass jars" -msgstr[0] "jarra sellada de vidrio de 3L" -msgstr[1] "jarras selladas de vidrio de 3L" +msgstr[0] "frasco sellado de vidrio de 3L" +msgstr[1] "frascos sellados de vidrio de 3L" #. ~ Description for {'str': 'sealed 3L glass jar'} #: lang/json/GENERIC_from_json.py @@ -54655,8 +54788,8 @@ msgstr "" #: lang/json/GENERIC_from_json.py msgid "glass jar" msgid_plural "glass jars" -msgstr[0] "jarra de vidrio" -msgstr[1] "jarras de vidrio" +msgstr[0] "frasco de vidrio" +msgstr[1] "frascos de vidrio" #. ~ Description for {'str': 'glass jar'} #: lang/json/GENERIC_from_json.py @@ -55672,6 +55805,38 @@ msgstr "" "Son pedazos de fieltro, atados para que ocupen menos espacio. Lo tenés que " "desarmar para abrirlo." +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "paquete de tablas" +msgstr[1] "paquetes de tablas" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "" +"Son diez tablas atadas juntas con una soga. Hay que desarmarlo para " +"desatarlas." + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "paquete de ramas fuertes" +msgstr[1] "paquetes de ramas fuertes" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "" +"Son diez ramas fuertes atadas juntas con una soga. Hay que desarmarlo para " +"desatarlas." + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -58485,8 +58650,8 @@ msgid "" "parts." msgstr "" "Es una mecha-gallina rota. A pesar de estar totalmente fuera de servicio " -"sigue siendo intimidatorio, posiblemente debido a su tamaño y masa. Puede " -"ser desarmado para recuperar las partes." +"sigue siendo intimidatoria, posiblemente debido a su tamaño y masa. Puede " +"ser desarmada para recuperar las partes." #: lang/json/GENERIC_from_json.py msgid "broken tribot" @@ -60415,6 +60580,68 @@ msgstr "" "Es un cadáver a medio decapitar. No está claro qué le puede haber causado " "esa herida." +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "trabajador exodii roto" +msgstr[1] "trabajadores exodii rotos" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "" +"Es un trabajador exodii roto. Es posible que pueda ser desarmado para " +"recuperar las partes." + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "cuadrúpedo exodii roto" +msgstr[1] "cuadrúpedos exodii rotos" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" +"Es un mecha-exodii roto. A pesar de estar totalmente fuera de servicio sigue" +" siendo intimidatorio, posiblemente debido a su tamaño y masa. Puede ser " +"desarmado para recuperar las partes." + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "torreta exodii rota" +msgstr[1] "torretas exodii rotas" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" +"Es una torreta exodii rota. A pesar de estar totalmente fuera de servicio " +"sigue siendo intimidatoria, posiblemente debido a su tamaño y masa. Puede " +"ser desarmada para recuperar las partes." + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "dron-globo exodii roto" +msgstr[1] "drones-globo exodii rotos" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" +"Es un dron-globo roto. El globo está destrozado pero la mayor parte del " +"chasis está intacta. Puede ser desarmado para recuperar partes." + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -62408,7 +62635,7 @@ msgstr[1] "micrófonos XLR" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "" "Es el típico micrófono utilizado para grabar o amplificar voces. Viene con " "un clip prendedor. Tiene un conector XLR de 3 pines en la parte de abajo " @@ -62625,6 +62852,22 @@ msgstr "" "Es un simple impulsor mecánico de hierro de una bomba. Así solo no sirve " "para mucho que digamos." +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "equipo de cañería" +msgstr[1] "equipos de cañería" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "" +"Son unos accesorios de caños de metal - tapones, empalmes y similares. " +"Pueden ser usados en una variedad de trabajos." + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -64824,6 +65067,136 @@ msgstr "" "de vidrio marino, congelado y arenoso, con las puntas redondeadas. Es, por " "alguna razón, tibio al tacto." +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "chasis de Exodii" +msgstr[1] "chasis de Exodii" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" +"Son una armazón y carrocería bastante hexagonales que parecen haber sido " +"fabricadas como una sola pieza monolítica. Los agujeros y uniones son " +"extremadamente resistentes a pesar de tener signos de gran desgaste y de " +"reparaciones. La estructura es versátil y probablemente podría ser diseñada " +"para servir un número de diferentes roles de combate." + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "chasis de dron Exodii" +msgstr[1] "chasis de dron Exodii" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" +"Son unas pequeñas armazón y carrocería bastante hexagonales que parecen " +"haber sido fabricadas como una sola pieza monolítica. Los agujeros y uniones" +" son extremadamente resistentes a pesar de tener signos de gran desgaste y " +"de reparaciones. La estructura es versátil y probablemente podría ser " +"diseñada para servir un número de diferentes roles de combate." + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "matriz neural cibernética" +msgstr[1] "matrices neurales cibernéticas" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" +"Es una serie de tanques y tubos con conexiones y fluidos, electricidad y " +"entradas y salidas. Esta compleja disposición está hecha para recibir un " +"cerebro y una columna vertebral y los órganos más difíciles de reemplazar " +"para mantenerlos vivos." + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "coso electrónico raro" +msgstr[1] "cosos electrónicos raros" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" +"Los cables y su forma general te sugieren que esto es una computadora o, por" +" lo menos, alguna clase de dispositivo electrónico, pero no tenés idea qué " +"es y qué función tiene. Tiene una construcción pesada y robusta." + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "placa inscripta de metal" +msgstr[1] "placas inscriptas de metal" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" +"Este dispositivo parece electrónico pero no sabés qué es. Es una serie " +"apretada de anillos que parecen de cobre, puestos de manera concéntrica. Hay" +" cables que salen de cada anillo y van hacia el eje en el medio." + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "sensor cibernético" +msgstr[1] "sensores cibernéticos" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" +"Por el gran ojo cristalino en el frente - del tamaño de un plato - deducís " +"que es alguna especie de cámara. El funcionamiento interno no tiene ningún " +"sentido para vos ni parece alguna cámara que hayas visto antes." + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "dispositivo rotatorio" +msgstr[1] "dispositivos rotatorios" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" +"Por las bobinas de alambre de cobre y el pistón sobresaliente, asumís que es" +" alguna especie de motor o generador, pero el diseño no se parece a nada que" +" hayas visto antes, y no te das cuenta cómo hacerlo funcionar." + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -68394,8 +68767,8 @@ msgstr "Es un lavarropas chico, diseñado para ser usado en vehículos." #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "programmable autopilot" msgid_plural "programmable autopilots" -msgstr[0] "autopiloto programable" -msgstr[1] "autopilotos programables" +msgstr[0] "piloto automático programable" +msgstr[1] "pilotos automáticos programables" #. ~ Description for {'str': 'programmable autopilot'} #: lang/json/GENERIC_from_json.py @@ -68489,6 +68862,18 @@ msgstr "" "Una canilla de metal que puede ser puesta en un tanque de agua para " "facilitar el uso." +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "soporte de madera para ruedas" +msgstr[1] "soportes de madera para ruedas" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "" +"Es un pedazo de madera con agujeros adecuados para una rueda de bicicleta." + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -68738,8 +69123,8 @@ msgstr "" #: lang/json/GENERIC_from_json.py msgid "broken sentinel-lx" msgid_plural "broken sentinels-lx" -msgstr[0] "sentinel-lx roto" -msgstr[1] "sentineles-lx rotos" +msgstr[0] "centinela-lx roto" +msgstr[1] "centinelas-lx rotos" #. ~ Description for {'str': 'broken sentinel-lx', 'str_pl': 'broken #. sentinels-lx'} @@ -68748,7 +69133,7 @@ msgid "" "The irreparably broken remains of a Sentinel-lx. Could be gutted for " "valuable parts." msgstr "" -"Son los restos rotos e irreparables de un Sentinel-lx. Puede ser desarmada " +"Son los restos rotos e irreparables de un Centinela-lx. Puede ser desarmada " "para recuperar partes." #: lang/json/GENERIC_from_json.py @@ -75076,6 +75461,40 @@ msgstr "" "Es un recipiente improvisado de 2lts, diseñado para alimentar un lanzador " "químico." +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "cargador PA Md. 71 Exodii 12.3ln" +msgstr[1] "cargadores PA Md. 71 Exodii 12.3ln" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" +"Es un pequeño cargador elegante basado en el clásico peine PA Md. 71, " +"rediseñado por los Exodii para ser usado en sus livianos drones. Su pequeño " +"tamaño no es apropiado para luchar en tierra contra hordas de zombis, porque" +" es un poco incómodo para recargar." + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "cargador PA Md. 68 Exodii 12.3ln" +msgstr[1] "cargadores PA Md. 68 Exodii 12.3ln" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "" +"Es un ilógicamente cargador grande para el ya de por sí gran rifle de " +"combate PA Md. 68, personalizado y fabricado por los Exodii." + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -76268,6 +76687,61 @@ msgstr "" "suficiente, se podría devolverle algo de humanidad. Lástima que no les " "importa..." +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "trabajador Exodii" +msgstr[1] "trabajadores Exodii" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "" +"Es un robot bastante humanoide equipado con varias herramientas de " +"construcción." + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "cuadrúpedo Exodii" +msgstr[1] "cuadrúpedos Exodii" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" +"Este enorme robot cuadrúpedo parece estar armado con diversas partes, la " +"mayoría de ellas desconocidas para vos. Se mueve con una marcha pesada y " +"extrañamente grácil, sus pasos van dejando pequeños cráteres. Está lleno de " +"un arsenal pero no parece estar en apuro de atacarte." + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "zomborg" +msgstr[1] "zomborgs" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" +"Es una mezcla de humano muerto con tecnología más muerta, esta cosa " +"retorcida de acero y carne se mueve como una marioneta en las manos de un " +"pibe enojado. Sus componentes robóticos parecen haberse apagado y nuevos " +"pedazos de carne se han enroscado sobre ellos, tironeándolos en direcciones " +"incómodas. Pedazos de esqueleto metálico y placas de blindaje sobresalen de " +"su carne pútrida." + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -76546,6 +77020,29 @@ msgstr "" "cuadrirrotor parece tener una minibomba nuclear adentro. Si te tiene como " "objetivo... corré." +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "dron-globo francotirador" +msgstr[1] "globo drone francotirador" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" +"Este inusual aparato parece una combinación de un globo meteorológico y un " +"cuadrirrotor. Debajo de esa rudimentaria caja con componentes cuelga un " +"pequeño brazo articulado con un rifle integrado. Sus propulsores se " +"encienden brevemente y se vuelven a apagar, manteniéndolo estático a pesar " +"de las corrientes de aire. Parece capaz de suspenderse en el aire por un " +"largo tiempo antes de quedarse sin energía." + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -78681,6 +79178,25 @@ msgstr "" "largas distancias con fuertes saltos, cazando su presa con sus mortales " "garras antes de dar el golpe final con sus enormes colmillos." +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "tigre" +msgstr[1] "tigres" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" +"Es el majestuoso tigre, un gran felino depredador. Nativo de Asia, ahora son" +" populosos en reservas privadas de los Estados Unidos. Rápido y poderoso, " +"este depredador es uno de los animales más reconocibles y amados del mundo. " +"También es uno de los más letales." + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -79214,7 +79730,7 @@ msgid "" "A hooved grazing mammal with a mane of hair, a sweeping tail, and powerful-" "looking muscles." msgstr "" -"Un mamífero de pastoreo con pezuñas con una melena, una cola grande y " +"Es un mamífero de pastoreo con pezuñas con una melena, una cola grande y " "músculos que parecen poderosos." #: lang/json/MONSTER_from_json.py @@ -80956,8 +81472,8 @@ msgid "" "black body glistens as it oozes its way along the ground. Eye stalks " "occasionally push their way out of the oily mass and look around." msgstr "" -"Una criatura similar a una babosa, de dos metros y medio de largo y ancha " -"como una heladera. Su cuerpo negro brilla mientras va rezumando por el " +"Es una criatura similar a una babosa, de dos metros y medio de largo y ancha" +" como una heladera. Su cuerpo negro brilla mientras va rezumando por el " "suelo. Sus ojos pedunculados salen ocasionalmente de la masa aceitosa y " "miran a su alrededor." @@ -80973,7 +81489,7 @@ msgid "" "A mutated leopard slug, as wide as a golf cart. Venom dripping from its " "fanged maw, it slithers ahead slowly, leaving a trail of glistening slime." msgstr "" -"Una babosa leopardo mutada, tan ancha como un carrito de golf. Le gotea " +"Es una babosa leopardo mutada, tan ancha como un carrito de golf. Le gotea " "veneno de sus fauces con colmillos, repta lentamente hacia adelante, dejando" " un rastro de baba brillante." @@ -81310,6 +81826,23 @@ msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "" "Es un parlante de gran potencia, que repite mensajes fuertes una y otra vez." +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "torreta supraciclada" +msgstr[1] "torretas supracicladas" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "" +"Esta pesada torreta parece estas compuestas de varios pedazos de tecnología," +" muchos de los cuales se ven extraños. Está equipado con una pesada " +"ametralladora." + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -81421,6 +81954,78 @@ msgstr "" "sentir muy incómodo. El fin del mundo no evitó que todavía esté esperando un" " paciente para asistir." +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "perro esquelético" +msgstr[1] "perros esqueléticos" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" +"Esto que alguna vez fue canino ha perdido toda su piel, revelando un " +"caparazón de costillas y huesos fusionados. Desprovisto completamente de " +"carne, este paquete de huesos ambulante parece estar controlado por una red " +"de venas y tendones relucientes de una viscosidad negra." + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "barghest" +msgstr[1] "barghests" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "" +"Es un enorme perro zombi hinchado, manchado de negro y baboso. Sus dientes " +"son largos y su ancha espalda está llena de músculos y heridas supurantes." + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "horror descomunal" +msgstr[1] "horrores descomunales" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" +"Es un cuerpo canino de cuatro patas, ahora grotescamente hinchado, con los " +"brazos anchos como tachos de basura y gigantescos dientes." + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "lobo óseo" +msgstr[1] "lobos óseos" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" +"Es una criatura de cuatro patas cubierta de placas óseas fusionadas, con " +"forma de perro o lobo. Las articulaciones y fisuras de su cuerpo chorrean " +"una viscosidad negra." + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "lobo esquelético" +msgstr[1] "lobos esqueléticos" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -81557,25 +82162,6 @@ msgstr "" "El cadáver deformado y reanimado de un canino, una bestia vigorosa que " "fácilmente puede dejar rezagados a sus amigos de dos patas." -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "perro esquelético" -msgstr[1] "perros esqueléticos" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" -"Esto que alguna vez fue canino ha perdido toda su piel, revelando un " -"caparazón de costillas y huesos fusionados. Desprovisto completamente de " -"carne, este paquete de huesos ambulante parece estar controlado por una red " -"de venas y tendones relucientes de una viscosidad negra." - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -81619,8 +82205,8 @@ msgid "" "A zombified wolf. Its mouth oozes with a black substance, coating the " "vicious-looking white fangs." msgstr "" -"Un lobo zombificado. De su boca chorrea una sustancia negra, cubriendo sus " -"feroces colmillos blancos." +"Es un lobo zombificado. De su boca chorrea una sustancia negra, cubriendo " +"sus feroces colmillos blancos." #: lang/json/MONSTER_from_json.py msgid "zombear" @@ -81708,6 +82294,36 @@ msgstr "" "Podría parecer un puma normal si no fuera que sus patas traseras están " "agrandadas, y sus ojos resaltan con una viscosidad negra." +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "tigrombi" +msgstr[1] "tigrombis" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "" +"Esto que podría parecer un tigre normal se va tambaleando y tropezando, con " +"su mandíbula floja y sus ojos bien abiertos de un negro brillante." + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "masa de arañas zombi" +msgstr[1] "masa de arañas zombi" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "" +"Miles, tal vez millones, de arañas amontonándose, cada una chorreando una " +"pus verde, luchando por mantener esta masa unida y moviéndose." + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -82375,6 +82991,54 @@ msgstr "" msgid "The impaler launches a barb!" msgstr "¡El impalador lanza una púa!" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "miembrostijeras" +msgstr[1] "miembrostijeras" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "" +"Es una araña pesadillesca de vísceras que sobresale entre las ruinas, y " +"mantiene una vigilancia silenciosa del paisaje arruinado. Sus miembros " +"larguiruchos de hueso se escurren entre los escombros con una velocidad " +"sobrenatural." + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "tripas colgantes" +msgstr[1] "tripas colgantes" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" +"Son grandes serpientes de carne colgando del techo, azotándose y " +"estirándose." + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "bulto espasmódico" +msgstr[1] "bultos espasmódicos" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "" +"Es una gran pila de cuerpos y carne mutada fundida. Tiene espasmos de una " +"manera arrítmica y desesperada." + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -82978,8 +83642,8 @@ msgid "" "skin. Joints and cracks around its body ooze with black goo." msgstr "" "La piel podrida de este zombi está cubierta de placas de hueso calcificadas," -" distorsionadas y sobrecrecidas. Las articulaciones y fisuras de este cuerpo" -" chorrean una viscosidad negra." +" distorsionadas y sobrecrecidas. Las articulaciones y fisuras de su cuerpo " +"chorrean una viscosidad negra." #: lang/json/MONSTER_from_json.py msgid "skeletal shocker" @@ -83328,8 +83992,8 @@ msgstr "" #: lang/json/MONSTER_from_json.py msgid "Wraitheon Sentinel-lx" msgid_plural "Wraitheon Sentinel-lxs" -msgstr[0] "sentinel-lxs Wraitheon" -msgstr[1] "sentineles-lxs Wraitheon" +msgstr[0] "Centinela-lx Wraitheon" +msgstr[1] "Centinelas-lxs Wraitheon" #. ~ Description for {'str': 'Wraitheon Sentinel-lx'} #: lang/json/MONSTER_from_json.py @@ -85145,7 +85809,7 @@ msgid "" " black, sticky liquid." msgstr "" "Es el cuerpo que va arrastrándose de un dinosaurio bípedo grande, con " -"plumas, piernas robustas. hombros anchos y un pico puntiagudo. Sus plumas " +"plumas, piernas robustas, hombros anchos y un pico puntiagudo. Sus plumas " "rotas están manchadas con un líquido pegajoso y negro." #: lang/json/MONSTER_from_json.py @@ -85163,23 +85827,6 @@ msgstr "" "Es un enorme cadáver pútrido de dinosaurio con una feroz cabeza similar a un" " cocodrilo, ojos negros purulentos y una vela medio rota en la espalda." -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "zombi Spinosaurus sombrío" -msgstr[1] "zombis Spinosaurus sombríos" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" -"Una extraña sombra envuelve a este dinosaurio. Podés distinguir la forma de " -"un enorme dinosaurio bípedo con una vela rota. La cabeza es larga y fina con" -" una trompa en forma de V." - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -85192,38 +85839,6 @@ msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "" "Enormes pilas de carne irregular y maloliente sostienen dientes enormes." -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "Z-Rex sombrío" -msgstr[1] "Z-Rexes sombríos" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "" -"Una extraña sombra envuelve a este dinosaurio. Podés distinguir la forma de " -"un enorme dinosaurio bípedo con bordes con plumas. La cabeza parece grande, " -"donde muchos dientes grandes podrían entrar bien." - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "S-Rex" -msgstr[1] "S-Rexes" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "" -"Es una monstruosa columna de hueso denso sosteniendo enormes dientes filosos" -" que chorrean una viscosidad negra." - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -85354,23 +85969,6 @@ msgstr "" "cubierto con plumas rotas y un líquido pútrido negro. Los dos pies lucen un " "garra grande similar a un hoz." -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "zombi Deinonychus sombrío" -msgstr[1] "zombis Deinonychus sombríos" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" -"Una extraña sombra envuelve a este dinosaurio. Podés distinguir la forma de " -"un dinosaurio bípedo de tamaño mediano con bordes con plumas. Los dos pies " -"lucen grandes garras como hoces." - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -85433,6 +86031,427 @@ msgstr "" "dientes filosos y dos crestas óseas prominentes en la cabeza, con tiras de " "carne arrancada colgando como un volado." +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "Gallimimus repugnante" +msgstr[1] "Gallimimus repugnantes" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" +"Es el cuerpo que va arrastrándose de un dinosaurio bípedo de tamaño medio " +"cubierto con plumas rotas y un líquido pútrido negro. Su cuerpo entero tiene" +" músculos dilatados sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "RompeCráneos" +msgstr[1] "RompeCráneos" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" +"Es el cuerpo que va arrastrándose de un dinosaurio bípedo de tamaño medio " +"cubierto con plumas rotas y un líquido pútrido negro. Su cabeza redonda como" +" un domo está sobre un cuerpo con músculos dilatados sobresaliendo, con " +"heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "Camptosaurus Triturador" +msgstr[1] "Camptosaurus Trituradores" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" +"Es el cuerpo que va arrastrándose de un dinosaurio bípedo grande, con " +"plumas, piernas sumamente hinchadas, hombros enormes y un feroz pico " +"puntiagudo. Sus plumas rotas están manchadas con un líquido pegajoso y " +"negro." + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "Spinosaurus Rompedor" +msgstr[1] "Spinosaurus Rompedores" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" +"Es un enorme cadáver pútrido de dinosaurio con una feroz cabeza similar a un" +" cocodrilo, ojos negros purulentos y una vela medio rota en la espalda. Su " +"cuerpo es más grande de lo normal, inflamado con músculos dilatados " +"sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "Rex Iracundo" +msgstr[1] "Rexs Iracundos" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" +"Pilas gigantescas de carne destrozada y apestosa sostienen unos dientes " +"enormes. Su cuerpo entero está abultado con músculos dilatados y heridas " +"infectadas e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "Albertosaurus Yunque" +msgstr[1] "Albertosaurus Yunques" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" +"Mandíbulas gigantescas y garras atrapantes se elevan junto a un cuerpo " +"abultado con músculos dilatados y heridas infectadas e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "Triceramión" +msgstr[1] "Triceramiones" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" +"Es un enorme dinosaurio tambaleante similar al rinoceronte, con una cresta " +"ósea desde la que le salen tres cuernos malvados. Desde sus ojos negros " +"gotea algo similar a lágrimas. Su cuerpo entero tiene músculos dilatados " +"sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "Stegosaurus Rompedor" +msgstr[1] "Stegosaurus Rompedores" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" +"Es un gran dinosaurio cuadrúpedo tambaleante con placas en su espalda, y una" +" cola con púas. Su cuerpo entero tiene músculos dilatados sobresaliendo, con" +" heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "Dino Tanque" +msgstr[1] "Dino Tanques" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" +"Es un dinosaurio zombi muy blindado. Su cuerpo entero está abultado con " +"músculos dilatados y heridas infectadas e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "Acorazado Zombi" +msgstr[1] "Acorazados Zombis" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" +"Es un enorme dinosaurio de cuatro patas y cuello largo, con una cola larga y" +" similar a un látigo. Su cuerpo entero tiene músculos dilatados " +"sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "Draco Titán" +msgstr[1] "Draco Titanes" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" +"Este zombi es enorme, escamoso, con muchas púas óseas, y se mueve a una " +"velocidad enorme. Sus cuernos coloridos y púas óseas salen de un cuerpo " +"abultado con músculos dilatados y heridas infectadas e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "Allosaurus Avalancha" +msgstr[1] "Allosaurus Avalanchas" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "" +"El cuerpo tambaleante de un gran dinosaurio depredador bípedo. Su cuerpo " +"entero está abultado con músculos dilatados y heridas infectadas e " +"hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "Deinonychus Destructor" +msgstr[1] "Deinonychus Destructores" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" +"Es el cuerpo que va arrastrándose de un dinosaurio bípedo de tamaño medio " +"cubierto con plumas rotas y un líquido pútrido negro. Sus dos pies tienen " +"unas grandes garras como hoces. Su cuerpo entero tiene músculos dilatados " +"sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "Utahraptor Agorero" +msgstr[1] "Utahraptor Agoreros" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" +"Es el cuerpo bamboleante de un gran dinosaurio bípedo con plumas en los " +"brazos, una cola larga, y garras largas como hoces. Su cuerpo entero tiene " +"músculos dilatados sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "Parasaurolophus Pegador" +msgstr[1] "Parasaurolophus Pegadores" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" +"Es un dinosaurio enorme con manchas y una cresta en la cabeza, con ojos " +"vacíos, muertos e hinchados. Su cuerpo entero tiene músculos dilatados " +"sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "Horror Alado" +msgstr[1] "Horrores Alados" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" +"Es el cuerpo volador de un reptil con plumas de casi un metro de largo, con " +"alas cortas y un gran pico colorido. Su cuerpo entero está abultado con " +"músculos dilatados y heridas infectadas e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "Triturador con Cresta" +msgstr[1] "Trituradores con Cresta" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" +"Es el cuerpo que va arrastrándose de un dinosaurio de tamaño medio con " +"dientes filosos y dos crestas óseas prominentes en la cabeza, con tiras de " +"carne arrancada colgando como un volado. Su cuerpo entero tiene músculos " +"dilatados sobresaliendo, con heridas supurantes e hinchadas." + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "zombi Spinosaurus sombrío" +msgstr[1] "zombis Spinosaurus sombríos" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" +"Una extraña sombra envuelve a este dinosaurio. Podés distinguir la forma de " +"un enorme dinosaurio bípedo con una vela rota. La cabeza es larga y fina con" +" una trompa en forma de V." + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "Z-Rex sombrío" +msgstr[1] "Z-Rexes sombríos" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "" +"Una extraña sombra envuelve a este dinosaurio. Podés distinguir la forma de " +"un enorme dinosaurio bípedo con bordes con plumas. La cabeza parece grande, " +"donde muchos dientes grandes podrían entrar bien." + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "zombi Deinonychus sombrío" +msgstr[1] "zombis Deinonychus sombríos" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" +"Una extraña sombra envuelve a este dinosaurio. Podés distinguir la forma de " +"un dinosaurio bípedo de tamaño mediano con bordes con plumas. Los dos pies " +"lucen grandes garras como hoces." + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "S-Rex" +msgstr[1] "S-Rexes" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "" +"Es una monstruosa columna de hueso denso sosteniendo enormes dientes filosos" +" que chorrean una viscosidad negra." + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "Albertosaurus Esquelético" +msgstr[1] "Albertosaurus Esqueléticos" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" +"Son unas monstruosas columnas de hueso denso que soportan unos dientes " +"puntiagudos y filoso que chorrean una viscosidad negra. Tiene unas garras " +"esqueléticas." + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "Dragón Óseo" +msgstr[1] "Dragones Óseos" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" +"Son unas monstruosas columnas de hueso denso que soportan unos dientes " +"puntiagudos y filoso que chorrean una viscosidad negra. Tiene púas y unos " +"cuernos coloridos sobresaliendo para completar el efecto visual." + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "allosaurus esquelético" +msgstr[1] "allosaurus esqueléticos" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" +"Es una monstruosa columna de hueso denso sosteniendo dientes filosos que " +"chorrean una viscosidad negra." + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "Utahraptor de Hueso" +msgstr[1] "Utahraptor de Hueso" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" +"Son unas monstruosas columnas de hueso denso que soportan unos dientes " +"puntiagudos y filoso que chorrean una viscosidad negra. Tiene una larga cola" +" y filosas garras como hoces." + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -86009,6 +87028,21 @@ msgstr "" "El aullador es un hongo del tamaño de un humano que emite unos gritos " "penetrantes para desorientar a las criaturas que lo molestan." +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "rana" +msgstr[1] "ranas" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "" +"Es la obviamente normal rana americana. Te conviene mantener al príncipe " +"azul alejado de ella." + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -86802,6 +87836,14 @@ msgstr "un anfibio" msgid "a bird" msgstr "un pájaro" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "un ciborg alienígena" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "ruidos sordos." + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "un reptil" @@ -87693,6 +88735,19 @@ msgstr "" "Este ritual crea una pequeña piedra adaptado a los Animistas. Podés usar la " "runa como catalizador en recetas." +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "Desgarralmas" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "" +"Arranca violentamente el espíritu del cuerpo, y une esa sombra a tu " +"voluntad." + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "Ignus Fatuus" @@ -87766,7 +88821,7 @@ msgstr "También causa efectos secundarios." #: lang/json/SPELL_from_json.py lang/json/effects_from_json.py msgid "Coagulant Weave" -msgstr "Ola Coagulante" +msgstr "Tejido Coagulante" #: lang/json/SPELL_from_json.py msgid "Crystallize Mana" @@ -87921,6 +88976,15 @@ msgstr "" msgid "Uses a little fatigue" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "" @@ -88372,6 +89436,10 @@ msgstr "Flecha de Maná" msgid "Haste" msgstr "Apuro" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "Polimorfia Siniestra" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "Rayo de Maná" @@ -91321,8 +92389,8 @@ msgstr "" #: lang/json/TOOL_ARMOR_from_json.py msgid "CRIT S-I G.E.A.R" msgid_plural "CRIT S-I G.E.A.Rs" -msgstr[0] "CRIT S-I G.E.A.R" -msgstr[1] "CRIT S-I G.E.A.R" +msgstr[0] "S-I G.E.A.R CRIT" +msgstr[1] "S-I G.E.A.R CRIT" #. ~ Description for CRIT S-I G.E.A.R #: lang/json/TOOL_ARMOR_from_json.py @@ -92779,6 +93847,19 @@ msgid_plural "bionic firestarters" msgstr[0] "magiclick biónico" msgstr[1] "magiclicks biónicos" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "soporte para ahumar" +msgstr[1] "soportes para ahumar" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -92855,7 +93936,7 @@ msgstr[1] "lámparas de calabaza" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "Luz" @@ -95955,12 +97036,6 @@ msgid_plural "pseudo butter churns" msgstr[0] "" msgstr[1] "" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -98644,16 +99719,43 @@ msgid_plural "throwable fire extinguishers" msgstr[0] "extintor arrojable" msgstr[1] "extintores arrojables" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "Quitar tapón" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "Le sacás el tapón al extintor arrojable." + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." msgstr "" -"Es un extintor del tamaño de una granada. Aunque no es tan eficaz como una " -"extintor normal, lo podés usar a distancia. Se activa debido al calor, así " -"que solo hay que tirarlo en las llamas." +"Es un extintor con la forma de una granada. Aunque no es tan eficaz como una" +" extintor normal, lo podés usar a distancia. Tiene un tapón plástico que " +"puede ser quitado, pero se activa primordialmente debido al calor, así que " +"solo hay que tirarlo en las llamas." + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "extintor arrojable activo" +msgstr[1] "extintores arrojables activos" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" +msgstr "" +"Es un extintor arrojable activado, y va a explotar en cualquier momento. " +"¡Tiralo ya!" #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -103932,8 +105034,8 @@ msgstr "" #: lang/json/TOOL_from_json.py msgid "inactive sentinel-lx" msgid_plural "inactive sentinel-lxs" -msgstr[0] "sentinel-lx inactivo" -msgstr[1] "sentineles-lx inactivos" +msgstr[0] "centinela-lx inactivo" +msgstr[1] "centinelas-lx inactivos" #. ~ Description for {'str': 'inactive sentinel-lx'} #: lang/json/TOOL_from_json.py @@ -104372,8 +105474,8 @@ msgstr "" #: lang/json/TOOL_from_json.py msgid "CRIT Reso-blade" msgid_plural "CRIT Reso-blades" -msgstr[0] "CRIT Reso-cuchilla" -msgstr[1] "CRIT Reso-cuchillas" +msgstr[0] "Reso-cuchilla CRIT" +msgstr[1] "Reso-cuchillas CRIT" #. ~ Description for CRIT Reso-blade #: lang/json/TOOL_from_json.py @@ -106139,7 +107241,7 @@ msgid "Pheidippides was a hack" msgstr "Filípides era un noob" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "Correr una maratón… y un poquito más." #: lang/json/achievement_from_json.py @@ -106206,6 +107308,621 @@ msgstr "Volver a tus raíces" msgid "Return to the location you started the game" msgstr "Volver al lugar de donde empezaste" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "Guarda con el árbol" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "" +"Si un árbol se cae en el bosque y no hay nadie cerca para escucharlo, ¿hace " +"ruido?" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "Leñador" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "¿Qué es un bosque para un hombre con un acha?" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "Deforestación" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "Si talás los árboles vas a encontrar al lobo." + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "Cavador de Tumbas" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "Eso es exactamente lo que necesitamos: más cadáveres." + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "Ladrón de Tumbas" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "Hey, ¿y si se convirtieron ahí abajo? Hay que revisar." + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "Funeral" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "" +"Es un privilegio ser enterrado entre los miles de millones que no lo serán." + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "Enterrador" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "No dejes que nadie se pudra entre los muertos vivientes." + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "Funeraria" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "No podés enterrar a todo el mundo, ¿no?" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "Ciberpunk" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "Spiritus quidem promptus; caro vero infirma." + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "Hombre Mecánico" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "" +"Por la más mecánica y sucia mano. Tomaré tal venganza contra ustedes... dos." +" Las cosas que haré, sean las que sean, aún no las conozco. Pero serán los " +"terrores de la tierra." + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "Homo Evolutis" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "" +"El mundo del humano ha terminado. Larga vida al mundo del transhumanismo." + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "Roto Pero no Derrotado" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "¿La obra social te cubre eso?" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "Mercado Libre" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "¡Extraordinarios artilugios a precios obscenamente bajos!" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "Cortarme Mi Propio Cuello" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "" +"Mi amigo eskimal, te estoy vendiendo este hielo a tan bajo precio que me " +"está cortando mi propio cuello." + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "Elocuente" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "Somos amgos, ¿o no?" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "Lengua de Plata" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "" +"Cuenta la leyenda que vos convenciste a un gigantón zombi de que se vaya." + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "El Hacker" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "" +"Este sistema operativo tiene una puerta trasera. Siempre hay una puerta " +"trasera." + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "Todavía ni parecido a Kevin" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "No estoy haciendo trampa. Es debugging." + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "Doctor en Medicina" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "¿Hay algún médico acá?" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "Dr House" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "Es lupus." + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "Ingeniero" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "Pasame mi pinza." + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "MacGyver" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "Todo esto se mantiene por la fe, escupida y cinta adhesiva." + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "Trampero" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "Una buena trampa no discrimina entre castores y castorombis." + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "Buscaminas" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "Todo lo que se necesita es no cometer errores." + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "As del Volante" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "Ninguna curva es demasiado cerrada." + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "El Stig" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "La Fórmula Uno es para los conductores domingueros." + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "Nadador" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "Como pez en el agua." + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "Michael Phelps" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "Más rápido que Tiburón." + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "Hacedor-Vos-Mismo" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "Agarrá eso, ponelo adentro de aquello y voilà." + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "El que Mucho Abarca" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "Con la cantidad justa de pegamento, no hay nada que no pueda hacer." + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "Master Chef" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "El lomito glaseado es pan comido." + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "Cocina Infernal" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "Menú del día: Soupe à l'oignon, Boeuf Bourguignon y Crème brûlée." + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "Sastre" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "Una aguja, un hilo y un sueño." + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "Diseñador de Moda" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "Hombre, mujer, mutante por igual." + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "Survivalista" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "La supervivencia es lo mío." + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "Bear Grylls" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "¿Así que podés sobrevivir con tu propia orina?" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "Ley de Ohm" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "" +"Trueno Ohm. Entran dos voltios, sale un voltio. La resistencia es inútil." + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "Nicola Tesla" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "Uno no prueba simplemente una batería de 9V." + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "Dar en el Blanco" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "Mejor que Legolas." + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "Robin Hood" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "¿Guillermo Tell? Nunca escuché ese nombre." + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "Ojo de Águila" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "Solo yo y mi objetivo." + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "Tiro de Gracia" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "No corras. Vas a morir cansado." + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "Pistolero" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "El calibre sí importa." + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "Hombre Cohete" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "Te voy a mandar a la luna. En pedacitos." + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "Chiquito Pero Mortal" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "El calibre no importa cuando estás del lado equivocado del cañón." + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "Harry el Sucio" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" +"Pero al ser una Magnum .44, el arma más potente del mundo y que te puede " +"arrancar la cabeza, te tenés que hacer una pregunta: ¿Me siento con suerte? " +"Bueno, ¿sentís suerte?" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "Hombre del Rifle" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "" +"Este es mi rifle. Hay muchos como él pero este es mío. Mi rifle es mi mejor " +"amigo. Es mi vida. Tengo que dominarlo como debo dominar mi vida." + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "Soldado" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" +"Sin mí, mi rifle es inútil. Sin mi rifle, yo soy inútil. Voy a mantener mi " +"rifle limpio y listo, incluso aunque yo esté limpio y listo. Nos volveremos " +"parte el uno del otro." + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "Doble Cañón, Doble Diversión" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "Cuando querés pegarle nueve veces a tu enemigo con un solo disparo." + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "Elmer Gruñón" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "¿Qué hay de nuevo, viejo? ¿Cazando conejitozz?" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "Chorro y Rezo" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "Alguna le pegará. Es cuestión de estadística." + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "¡El Subfsuil Hace BRRRT!" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "Definitivamente, vamos a necesitar más munición." + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "¡Sacudir!" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "Y no vuelvas más." + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "Kobe Bryant" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "¡Cuidado que explota!" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "Matón" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "Una botella en la mano izquierda, una pata de silla en la derecha." + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "Luchador Callejero" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "Lo que importa es ganar, no el estilo." + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "Bateador" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "Cada golpe me acerca a un home run." + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "Edad de Piedra" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "" +"El garrote fue la primera herramienta de la humanidad. Y puede ser la " +"última, así que ¿por qué no dominarla?" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "Camino de la Espada" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" +"Cuando la espada fue desenfundada, las pasiones del hombre dejaron de " +"prestar atención a la moderación." + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "Miyamoto Musashi" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "" +"La espada debe ser más que una simple arma; tiene que ser la respuesta a las" +" preguntas de la vida." + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "Elusivo" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "El golpe más poderoso es nada si no golpea." + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "Neo" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "¿Pero podés esquivar una bala?" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "Acero Frío" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "Mientras estabas de joda, yo estudiaba la espada." + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "Jack el Destripador" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "" +"¿Es esto una daga que tengo adelante, con el mango hacia mi mano? Vamos, " +"dejame agarrarte." + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "Camino a Shaolin" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "Siento un ejército en mi puño." + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "Sr Miyagi" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "Ser tu propia arma." + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "Chorra" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "¿Barreta? Qué barbaridad." + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "Cerrajero" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "Si hay una cerradura, hay una llave." + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "Tabla Periódica" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "Es más o menos como cocinar. Pero no chupes la cuchara." + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "Heisenberg" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "Ya saben quién soy. Soy el cocinero. Digan mi nombre." + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "Aspirante a Mago" @@ -106669,6 +108386,11 @@ msgstr "hackear" msgid "canceling activity serialized with legacy code" msgstr "cancelar actividad serializada con código legado" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "ejercitando" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "celda de fusión" @@ -106971,6 +108693,10 @@ msgstr "químico para aerosol" msgid "compressed air" msgstr "aire comprimido" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "cartucho 12.3ln" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "bote de metralla" @@ -109224,6 +110950,62 @@ msgstr "No matar personajes" msgid "Merciful" msgstr "Compasivo" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "El Undécimo Camino" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "No talar árboles" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "Homo Sapiens" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "Sin instalar implantes biónicos" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "Sin instalar biónicos no defectuosos" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "Sin mutaciones" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "Rayos-X limpios" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "Sangre Pura" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "Integridad Estructural" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "No romper huesos" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "Profesor, Deje a Los Pibes Tranquilos" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "Sin ganar niveles en habilidades" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "Analfabetismo Autoimpuesto" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "Sin leer libros" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -109856,10 +111638,6 @@ msgstr "Pintar Pared de Amarillo" msgid "Take Paint Off Wall" msgstr "Quitar Pintura de la Pared" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "Quitar Alfombra" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "Alfombrar con Rojo" @@ -109900,6 +111678,38 @@ msgstr "Construir Escalera de Madera" msgid "Mine Upstair" msgstr "Hacer Mina hacia Arriba" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "Construir Parte Baja de Rampa de Concreto" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" +"Construir una rampa de concreto que lleva al siguiente nivel superior, y la " +"correspondiente rampa que baja. La parte alta de la rampa debe ser " +"construida al lado para permitir el movimiento entre niveles en las dos " +"direcciones." + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "Construir Parte Alta de Rampa de Concreto" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" +"Construir una rampa de concreto que lleva al siguiente nivel superior, y la " +"correspondiente rampa que baja. Debe ser construida al lado de la parte baja" +" de la rampa para permitir el movimiento entre niveles en las dos " +"direcciones." + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "Empezar a Construir Vehículo" @@ -113174,7 +114984,7 @@ msgstr "Le pegás una pitada o dos." msgid "You smoked too much." msgstr "Fumaste demasiado." -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "Drogado" @@ -115315,6 +117125,18 @@ msgstr "fuego" msgid "raging fire" msgstr "fuego intenso" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "neblina de extintor" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "nube de extintor" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "nube espesa de extintor" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "escombro antiguo" @@ -116464,8 +118286,7 @@ msgstr "" "dejar un fuego sin atender." #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "¡crash!" @@ -116666,7 +118487,7 @@ msgstr "" "confort o el frío." #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "¡crunch!" @@ -117450,13 +119271,12 @@ msgstr "máquina de ejercicio" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." msgstr "" -"Es un esquipo de pesas para entrenar la fuerza, con un par de pesos fijos en" -" las puntas de un caño resistente. Las pesas son enormes y usarlas sin un " -"asistente sería una buena manera de lesionarse." +"Es un equipo de pesas para entrenar la fuerza, con un par de pesos fijos en " +"las puntas de un caño resistente. Podés ajustar el equipo eligiendo las " +"pesas que querés usar." #: lang/json/furniture_from_json.py msgid "ball machine" @@ -117569,6 +119389,21 @@ msgstr "" " emular la acción de remar en un bote. Sin alimentación eléctrica no puede " "ser utilizada, pero tiene algunas partes útiles que se pueden recuperar." +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "ergómetro mecánico" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "" +"Es una máquina de ejercicios con un grupo de manijas y platos diseñados para" +" emular la acción de remar en un bote. Es un modelo más viejo con ajustes de" +" resistencia mecánica, pero funciona sin energía eléctrica." + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "cinta para correr" @@ -117584,6 +119419,21 @@ msgstr "" "correr en el lugar. Sin alimentación eléctrica, es un desafío inmenso mover " "la cinta. Sin embargo, ya debés estar ejercitándote lo suficiente." +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "cinta para correr inclinada" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" +"Es una cinta transportadora con un panel de control mecánico para correr en " +"un lugar. La cinta transportadora está posicionada con un escalón, pero con " +"la inclinación ajustable, así que se vuelve a bajar con tu peso." + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "bolsa de boxeo grande" @@ -119083,10 +120933,6 @@ msgstr "" msgid "filled arc furnace" msgstr "horno de arco lleno" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "soporte para ahumar" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -119948,7 +121794,8 @@ msgstr "Es una pistola falsa que dispara un globo ácido." msgid "auto" msgstr "auto" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "rifle" @@ -120159,8 +122006,8 @@ msgstr "" "siglo XXI. Con poco de cinta adhesiva y partes electrónicas, funciona con un" " UPS normal." -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "pistola" @@ -120235,7 +122082,7 @@ msgstr "" "Un rifle neumático de múltiples impactos, hecho a mano con chatarra. Es muy " "silencioso y letal." -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "semi-auto" @@ -120769,10 +122616,10 @@ msgstr "" "AR-15, comercialmente dirigida como arma de defensa hogareña." #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" -msgstr[0] "MAS 223" -msgstr[1] "MAS 223" +msgid "MAS .223" +msgid_plural "MAS .223" +msgstr[0] "MAS .223" +msgstr[1] "MAS .223" #: lang/json/gun_from_json.py msgid "" @@ -122090,7 +123937,7 @@ msgid "" "lower-recoil alternative to 12 gauge shotguns, it is light and easy to " "manufacture." msgstr "" -"Es una escopeta de cañón de quiebre de un disparo con calibre .410. Diseñada" +"Es una escopeta de cañón basculante de un disparo con calibre .410. Diseñada" " como una alternativa de bajo retroceso a las escopetas 12 gauge, es liviana" " y simple de fabricar." @@ -122833,8 +124680,8 @@ msgstr "todos los cañones" #: lang/json/gun_from_json.py msgid "Elephant gun" msgid_plural "Elephant guns" -msgstr[0] "rifle de caza mayor" -msgstr[1] "rifles de caza mayor" +msgstr[0] "arma de caza mayor" +msgstr[1] "armas de caza mayor" #: lang/json/gun_from_json.py msgid "" @@ -122908,12 +124755,16 @@ msgid "" "function, their solid firepower and reliability in harsh conditions make " "them valuable weapons in this new world." msgstr "" +"Las copias civiles de la icónica Kalashnikov, como esta, fueron fabricadas e" +" importadas por muchas compañías diferentes. Incluso sin la función " +"automática, su sólida potencia de disparo y fiabilidad en condiciones " +"difíciles la hacen armas valoradas en este mundo nuevo." #: lang/json/gun_from_json.py msgid "Mini Draco" msgid_plural "Mini Dracos" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Mini Draco" +msgstr[1] "Mini Dracos" #: lang/json/gun_from_json.py msgid "" @@ -122921,6 +124772,9 @@ msgid "" "\"pistol\" has seen some popularity with civilian shooters and gangbangers " "alike." msgstr "" +"Es, esencialmente, una AK semiautomática con el cañón corto y sin culata. " +"Esta incómoda \"pistola\" ha sido popular entre los tiradores civiles y " +"bandas por igual" #: lang/json/gun_from_json.py msgid "Mosin-Nagant M44" @@ -123034,14 +124888,17 @@ msgstr "" #: lang/json/gun_from_json.py msgid "AT4" msgid_plural "AT4s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "AT4" +msgstr[1] "AT4" #: lang/json/gun_from_json.py msgid "" "Mil-Spec rocket launcher. An 84-mm unguided, portable, single-shot " "recoilless smoothbore weapon used primarily by the US military." msgstr "" +"Es un lanzacohetes Mil-Spec. Un arma de 84mm sin guía, portátil, de un " +"disparo solo, sin retroceso y de ánima lisa, usada primariamente por el " +"ejército de los Estados Unidos." #: lang/json/gun_from_json.py msgid "RM103A automagnum" @@ -123175,8 +125032,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Beretta 90-two" msgid_plural "Beretta 90-twos" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Beretta 90-two" +msgstr[1] "Beretta 90-two" #: lang/json/gun_from_json.py msgid "" @@ -123185,6 +125042,9 @@ msgid "" "futuristic-looking design owed in large parts to the polymer underbarrel " "rail cover." msgstr "" +"Es una versión más moderna de la popular serie 92 de Beretta, la 90-two " +"tiene un desempeña casi igual. La mayor diferencia es su diseño más elegante" +" y casi futurista debido a su cobertura de polímero bajo el cañón." #: lang/json/gun_from_json.py msgid "Calico M960" @@ -123233,8 +125093,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "H&K MP5A2" msgid_plural "H&K MP5A2s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "H&K MP5A2" +msgstr[1] "H&K MP5A2" #: lang/json/gun_from_json.py msgid "" @@ -123262,12 +125122,19 @@ msgid "" "waned in popularity among special forces due to its decreased terminal " "performance." msgstr "" +"El H&K MP5SD ofrece desempeño subsónico con casi el mismo impacto que el H&K" +" MP5, manteniendo su estabilidad. El silenciador grande reduce mucho el " +"destello de la bocacha, un beneficio para operaciones nocturnas. Ha tenido " +"popularidad con los equipos SWAT, ya que disminuye el riesgo de fuegos y " +"explosiones en laboratorios ilegales. Con el uso más común de armaduras " +"blindadas, el MP5SD ha perdido popularidad entre las fuerzas especiales " +"debido a su potencia terminal menor." #: lang/json/gun_from_json.py msgid "H&K MP5K-PDW" msgid_plural "H&K MP5K-PDWs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "H&K MP5K-PDW" +msgstr[1] "H&K MP5K-PDW" #: lang/json/gun_from_json.py msgid "" @@ -123277,12 +125144,17 @@ msgid "" "MP5K-PDW model features a shorter barrel, a built-in foregrip, and a side " "folding stock for vehicle or aircraft crew use." msgstr "" +"El Heckler & Koch MP5 es uno de los subfusiles más utilizados en el mundo, y" +" ha sido adoptado por las fuerzas policiales y militares especiales. Su alto" +" grado de precisión y su poco retroceso son elogiados universalmente. El " +"modelo MP5K-PDW tiene un cañón más corto, empuñadura delantera incorporada y" +" culata que se pliega hacia el costado para uso en vehículo." #: lang/json/gun_from_json.py msgid "PTR 603" msgid_plural "PTR 603s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "PTR 603" +msgstr[1] "PTR 603" #: lang/json/gun_from_json.py msgid "" @@ -123295,12 +125167,20 @@ msgid "" "offers convenient mounting for aftermarket optics, but precludes the use of " "claw mounts." msgstr "" +"El PTR 603 es una copia semiautomática de la famosa serie MP5, producida " +"para el mercado de Estados Unidos por PTR Industries con instrumental " +"Heckler and Koch. Como el MP5, su acción de rodillo de retraso de retroceso " +"ofrece una precisión y disparo más suaves, diferenciándolo de otros " +"subfusiles y pistolas con calibre de carabina. Este modelo está configurado " +"como pistola para evitar las regulaciones costosas e inconvenientes de NFA. " +"Una sección de riel M1913 soldado ofrece una montura conveniente para " +"ópticas de mercados secundarios, pero impide el uso de monturas de garra." #: lang/json/gun_from_json.py msgid "H&K operational briefcase" msgid_plural "H&K operational briefcases" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "maletín operativo H&K" +msgstr[1] "maletines operativos H&K" #: lang/json/gun_from_json.py msgid "" @@ -123312,6 +125192,13 @@ msgid "" "while bodyguarding, this is your gun. When the briefcase is open the MP5 " "may be reloaded or dismounted." msgstr "" +"Es un maletín rígido con un gatillo en la manija y un agujero oculto en el " +"costado. Para disparar la MP5K-PDW interna, hay que apoyar el maletín a la " +"cintura, asegurarse de estar apuntándolo hacia el enemigo y apretar el " +"gatillo. La precisión y la maniobrabilidad están severamente dificultadas, " +"pero si necesitás 'entregar la mercancía' o tener un perfil bajo mientras " +"estás cuidando a alguien, esta es tu arma. Cuando el maletín está abierto, " +"el MP5 puede ser recargado o quitado." #: lang/json/gun_from_json.py msgid "Kel-Tec SUB-2000" @@ -123330,8 +125217,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Beretta M9A1" msgid_plural "Beretta M9A1" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Beretta M9A1" +msgstr[1] "Beretta M9A1" #: lang/json/gun_from_json.py msgid "" @@ -123340,12 +125227,17 @@ msgid "" "enforcement before the advent of commercially available polymer-framed " "handguns and the FBI's adoption of .40S&W." msgstr "" +"Es la icónica pistola 9x19mm. La M9 fue el arma de apoyo estándar de las " +"fuerzas armadas de Estados Unidos desde 1985 hasta recientemente. Fue " +"popular entre las fuerzas de la ley antes de la llegada de las armas de mano" +" de polímero y disponibles comercialmente, y la adopción del .40 S&W por " +"parte del FBI." #: lang/json/gun_from_json.py msgid "Beretta Px4 Storm" msgid_plural "Beretta Px4 Storms" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Beretta Px4 Storm" +msgstr[1] "Beretta Px4 Storm" #: lang/json/gun_from_json.py msgid "" @@ -123354,6 +125246,10 @@ msgid "" "was also optimized for concealed carry, while maintaining the reliability " "the 92 series is known for." msgstr "" +"Más liviana que la icónica serie 92 de Beretta, la Px4 Storm fue construida " +"utilizando polímero liviano con inserciones de acero. Su forma fue " +"optimizada para poder llevar oculta pero manteniendo la fiabilidad por la " +"cual es famosa la serie 92." #: lang/json/gun_from_json.py msgid "pipe rifle: 9x19mm" @@ -123364,8 +125260,8 @@ msgstr[1] "rifles de caño: 9x19mm" #: lang/json/gun_from_json.py msgid "Luty SMG: 9x19mm" msgid_plural "Luty SMGs: 9x19mm" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Luty SMG: 9x19mm" +msgstr[1] "Luty SMG: 9x19mm" #: lang/json/gun_from_json.py msgid "" @@ -123375,6 +125271,11 @@ msgid "" "shop, but still very unreliable. This one is chambered for 9x19mm " "cartridges and accepts STEN compatible magazines." msgstr "" +"Es un subfusil de patrón Luty de ánima lisa, construida simplemente de " +"varias partes de acero, usando algunas de las armas de mano más avanzadas. " +"Probablemente sea una de las armas más complejas que se pueden hacer fuera " +"de una fábrica, pero igual es poco fiable. Esta tiene calibre 9x19mm y " +"acepta cargadores compatibles STEN." #: lang/json/gun_from_json.py msgid "STEN" @@ -123459,8 +125360,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Glock 18C" msgid_plural "Glock 18Cs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Glock 18C" +msgstr[1] "Glock 18C" #: lang/json/gun_from_json.py msgid "" @@ -123468,12 +125369,15 @@ msgid "" "Austria's EKO Cobra unit. It has compensator cuts along its barrel to make " "recoil more manageable." msgstr "" +"Es una variante de disparo selectivo de la Glock 17, originalmente diseñada " +"para la unidad EKO Cobra de Austria. Tiene cortes de compensación en el " +"cañón para hacer más manejable el retroceso." #: lang/json/gun_from_json.py msgid "Kel-Tec PF-9" msgid_plural "Kel-Tec PF-9s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Kel-Tec PF-9" +msgstr[1] "Kel-Tec PF-9" #: lang/json/gun_from_json.py msgid "" @@ -123482,24 +125386,30 @@ msgid "" "9x19mm, recoil is best described as unpleasant, and follow-up shots are " "difficult to place quickly." msgstr "" +"La Kel-Tec PF-9 sigue siendo una de las pistolas de apoyo más populares " +"debido a su histórica fiabilidad, bajo costo y ocultabilidad. Con calibre " +"9x19mm, su retroceso se puede describir como desagradable y los disparos " +"posteriores son difíciles de ubicar rápidamente." #: lang/json/gun_from_json.py msgid "M17" msgid_plural "M17s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "M17" +msgstr[1] "M17" #: lang/json/gun_from_json.py msgid "" "The M17 is a semi-automatic, short recoil operated pistol derived from the " "SIG Sauer P320." msgstr "" +"La M17 es una pistola semiautomática de retroceso corto derivada de la SIG " +"Sauer P320." #: lang/json/gun_from_json.py msgid "Browning Hi-Power 9x19mm" msgid_plural "Browning Hi-Power 9x19mms" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Browning Hi-Power 9x19mm" +msgstr[1] "Browning Hi-Power 9x19mm" #: lang/json/gun_from_json.py msgid "" @@ -123508,12 +125418,16 @@ msgid "" " Canada and Australia. This is a commercial variant produced by Browning " "Arms in 9x19mm Parabellum." msgstr "" +"La Browning Hi-Power es una arma de mano semiautomática desarrollada poco " +"antes de la segunda guerra mundial. Muy usada desde entonces, sigue en uso " +"en India, Canadá y Australia. Esta es la versión comercial producida por " +"Browning Arms con calibre 9x19mm Parabellum." #: lang/json/gun_from_json.py msgid "Walther P38" msgid_plural "Walther P38s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Walther P38" +msgstr[1] "Walther P38" #: lang/json/gun_from_json.py msgid "" @@ -123524,12 +125438,18 @@ msgid "" " more modern firearms such as the Beretta 92 series, and served Germany " "until 2004." msgstr "" +"La Walther P38 es un arma de mano semiautomática adoptada poco antes de la " +"segunda guerra mundial. Desarrollada debido al alto costo de producción de " +"su predecesora, la Luger P08, la P38 también tiene calibre 9mm Parabellum. " +"Este temprano diseño DA/SA de cierre bloqueado introduce características " +"vistas luego en armas más modernas como la serie Beretta 92, y fue usada por" +" Alemania hasta 2004." #: lang/json/gun_from_json.py msgid "Walther PPQ 9mm" msgid_plural "Walther PPQ 9mms" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Walther PPQ 9mm" +msgstr[1] "Walther PPQ 9mm" #: lang/json/gun_from_json.py msgid "" @@ -123537,12 +125457,15 @@ msgid "" "P99QA, and maintains compatibility with some of its predecessor's " "accessories. This model is chambered in 9x19mm Parabellum." msgstr "" +"La Walther PPQ es una pistola semiautomática desarrollada a partir de la " +"Walther P99QA y que mantiene compatibilidad con algunos accesorios de sus " +"predecesoras. Este modelo tiene calibre 9x19mm Parabellum." #: lang/json/gun_from_json.py msgid "Hi-Point C-9" msgid_plural "Hi-Point C-9s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Hi-Point C-9" +msgstr[1] "Hi-Point C-9" #: lang/json/gun_from_json.py msgid "" @@ -123551,28 +125474,39 @@ msgid "" "making said firearms bulky and uncomfortable. Hi-Points have slides made " "with a zinc pot-metal which is relatively fragile compared to steel slides." msgstr "" +"La Hi-Point C-9 es una pistola semiautomática con retroceso simple diseñada " +"por Hi-Point Firearms, que es conocida por hacer armas de fuego baratas y " +"por hacerlas incómodas y voluminosas. Las Hi-Point tiene corredora de zinc " +"que es relativamente frágil comparada con las corredoras de acero." #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" -msgstr[0] "" -msgstr[1] "" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" +msgstr[0] "CZ 75 B" +msgstr[1] "CZ 75 B" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " "pistol remains wildly popular among competition shooters." msgstr "" +"La CZ-75 B es una pistola semiautomática desarrollada en Checoslovaquia y es" +" una de las nueve maravillas originales. Aunque fue diseñada para exportar a" +" países del occidente, fue declarada como secreto de estado. La falta de " +"protección internacional de su patente hizo que muchas copias y variantes " +"fueran producidas y distribuidas por el mundo, con la Česká zbrojovka " +"llegando en la década del 90. Esta pistola sigue siendo popular entre los " +"tiradores de competición." #: lang/json/gun_from_json.py msgid "Walther CCP" msgid_plural "Walther CCPs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Walther CCP" +msgstr[1] "Walther CCP" #: lang/json/gun_from_json.py msgid "" @@ -123582,6 +125516,11 @@ msgid "" " accurate than many other pistols, though this may difficult to realize with" " its average trigger and short sight radius." msgstr "" +"La Walther CCP es una pistola semiautomática con retroceso simple de retardo" +" por gas, pensada para llevar oculta. Internamente, es casi idéntica a la " +"clásica de culto H&K P7. Su diseño de cañón fijo la hace potencialmente más " +"precisa que muchas otras pistolas, aunque sea difícil darse cuenta con su " +"gatillo común y su corto radio de mira." #: lang/json/gun_from_json.py msgid "Makarov PM" @@ -123616,8 +125555,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "BGM-71F TOW" msgid_plural "BGM-71F TOW" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "BGM-71F TOW" +msgstr[1] "BGM-71F TOW" #: lang/json/gun_from_json.py msgid "" @@ -123632,12 +125571,13 @@ msgstr "" #: lang/json/gun_from_json.py msgid "bionic shotgun" msgid_plural "bionic shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta biónica" +msgstr[1] "escopetas biónicas" #: lang/json/gun_from_json.py msgid "Bionic one-shot retracting shotgun integrated with your arm." msgstr "" +"Es una escopeta biónica retráctil de un disparo integrada en tu brazo." #: lang/json/gun_from_json.py msgid "laser finger" @@ -123648,8 +125588,8 @@ msgstr[1] "dedos láser" #: lang/json/gun_from_json.py lang/json/mutation_from_json.py msgid "Assault barbs" msgid_plural "Assault barbs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Púas de asalto" +msgstr[1] "Púas de asalto" #: lang/json/gun_from_json.py msgid "" @@ -123663,8 +125603,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "makeshift chemical thrower" msgid_plural "makeshift chemical throwers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzador químico improvisado" +msgstr[1] "lanzadores químicos improvisados" #: lang/json/gun_from_json.py msgid "" @@ -123686,11 +125626,58 @@ msgid "" " bore barrels. Historically used by egomaniac hunters in Africa, now used " "by their egomaniac descendants in New England." msgstr "" -"Es un arma de cañón de quiebre compuesta por un cañón .30-06 sobre dos " +"Es un arma de cañón basculante compuesta por un cañón .30-06 sobre dos " "cañones calibre 12 gauge suave. Históricamente usada por los cazadores " "egocéntricos en África, ahora es usado por los descendientes egocéntricos en" " New England." +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "rifle de combate PA Md. 68" +msgstr[1] "rifles de combate PA Md. 68" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" +"El arma más popular que usa el cartucho 12.3In es, obviamente, el PA Md. 71." +" Su predecesor, el Md., fue vista por muchos como un fracaso: aunque era " +"fiable y potente, era demasiado pesado para ser usado como arma para " +"infantería, y no lo suficientemente grande como para arma de apoyo. Igual " +"fueron fabricadas suficientes así que durante el apocalipsis zombi ganó " +"popularidad como arma ligera que usa munición ya disponible. Sirvió " +"perfectamente para los propósitos de los Exodii, que tenían mucho menos " +"problemas con su dificultad de manejo." + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "rifle cazazombis PA Md. 71" +msgstr[1] "rifles cazazombis PA Md. 71" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" +"Este rifle de asalto rumano extremadamente popular, que llegó a la fama en " +"la tercera Guerra de los Cárpatos, fue rediseñada levemente por los Exodii " +"para funcionar como arma de francotirador. Es adecuada para tiros precisos " +"contra objetivos prioritarios. Este diseño modificado utiliza una ráfaga " +"extremadamente rápida de 5 tiros, con la intención de destrozar el objetivo " +"y evitar la resucitación." + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -123769,12 +125756,14 @@ msgid "" "A beautifully decorated flintlock pistol. If using this doesn't make you " "feel a pirate, nothing will." msgstr "" +"Es una pistola de chispa hermosamente decorada. Si cuando usás esto no te " +"sentís como un pirata, ninguna otra cosa te lo hará sentir." #: lang/json/gun_from_json.py msgid "flintlock musket" msgid_plural "flintlock muskets" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mosquete de chispa" +msgstr[1] "mosquetes de chispa" #: lang/json/gun_from_json.py msgid "" @@ -123799,26 +125788,30 @@ msgid "" "has signficantly increased accuracy at the cost of taking even longer to " "reload." msgstr "" +"También conocido como rifle Pennsylvania, esta arma de chispa de cañón largo" +" tiene una precisión muy mejorada aunque tarda bastante en ser recargada." #: lang/json/gun_from_json.py msgid "barb launching organ" msgid_plural "barb launching organs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "órgano lanzapúas" +msgstr[1] "órganos lanzapúas" #: lang/json/gun_from_json.py msgid "A mutated organ capable of launching bony barbs at great speed." -msgstr "" +msgstr "Es un órgano mutado capaz de lanzar púas óseas a gran velocidad." #: lang/json/gun_from_json.py msgid "electric alien frond" msgid_plural "electric alien fronds" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "fronda alienígena eléctrica" +msgstr[1] "frondas alienígenas eléctricas" #: lang/json/gun_from_json.py msgid "Electricity unnaturally arcs from the tips of this alien frond." msgstr "" +"La electricidad salta sobrenaturalmente entre las puntas de esta fronda " +"alienígena." #: lang/json/gun_from_json.py msgid "nail gun" @@ -123831,6 +125824,8 @@ msgid "" "A tool used to drive nails into wood or other material. It could also be " "used as an ad-hoc weapon." msgstr "" +"Es una herramienta usada para meter clavos en la madera u otros materiales. " +"También puede usarse como arma." #: lang/json/gun_from_json.py msgid "Paintball gun" @@ -123860,8 +125855,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "12-gauge gatling gun" msgid_plural "12-gauge gatling guns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "ametralladora gatling 12-gauge" +msgstr[1] "ametralladoras gatling 12-gauge" #: lang/json/gun_from_json.py msgid "" @@ -123870,12 +125865,16 @@ msgid "" "six separate barrels make for difficult zeroing. The externally driven " "action means this is much less likely to jam." msgstr "" +"Es una escopeta eléctrica gatling de seis cañones, alimentada con cintas " +"hechas de tela. Incluso estando montada apropiadamente, es una bestia " +"incómoda y los seis cañones separados dificultan la puesta a cero. La acción" +" externa hace que sea mucho menos probable que se trabe." #: lang/json/gun_from_json.py msgid "handmade lever shotgun" msgid_plural "handmade lever shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta de palanca casera" +msgstr[1] "escopetas de palanca caseras" #: lang/json/gun_from_json.py msgid "" @@ -123883,12 +125882,15 @@ msgid "" "While still a primitive pipe and 2x4 design, it is a formiddable shotgun in " "it's own right with room for improvement." msgstr "" +"Es una escopeta de acción de palanca corta, hecha en casa, con un pequeño " +"tubo cargador interno. Aunque sigue siendo un primitivo diseño de caño y " +"tabla, es una formidable escopeta con algunos puntos para mejorar." #: lang/json/gun_from_json.py msgid "Browning Auto 5" msgid_plural "Browning Auto 5s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Browning Auto 5" +msgstr[1] "Browning Auto 5" #: lang/json/gun_from_json.py msgid "" @@ -123897,6 +125899,11 @@ msgid "" "million made between 1902 and 1998. The recoil tuning mechanism under the " "handguard and long dwell time of the action make for pleasant shooting." msgstr "" +"Esta escopeta de aspecto humilde fue la primera escopeta semiautomática " +"exitosa, y la segunda más exitosa en la historia de Estados Unidos, con más " +"de 2.7 millones fabricados entre 1902 y 1998. El mecanismo de ajuste de " +"retroceso bajo la empuñadura y el tiempo largo de la acción la hacen " +"placentera de disparar." #: lang/json/gun_from_json.py msgid "Kel-Tec KSG" @@ -123918,8 +125925,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Kel-Tec KSG-25" msgid_plural "Kel-Tec KSG-25" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Kel-Tec KSG-25" +msgstr[1] "Kel-Tec KSG-25" #: lang/json/gun_from_json.py msgid "" @@ -123929,6 +125936,11 @@ msgid "" "situations. The big brother of the KSG, it has a longer barrel and longer " "magazine tubes." msgstr "" +"Es una escopeta bullpup de acción de bombeo, la Kel-Tec KSG utiliza un par " +"de tubos cargadores para aumentar su capacidad. Cada tubo debe ser cargado " +"por separado, pero esto brinda la posibilidad de cargar diferente munición " +"para diferentes situaciones. La hermana mayor de la KSG, tiene un cañón más " +"largo y tubos cargadores más grandes." #: lang/json/gun_from_json.py msgid "M1014 shotgun" @@ -123944,12 +125956,16 @@ msgid "" "Combat Shotgun, the Benelli M4 is one of the finest combat shotguns " "available." msgstr "" +"Es la primera escopeta operada por gas de Benelli, con dos pistones para " +"mejorar la fiabilidad con varias cargas y culata colapsable que reduce el " +"largo en casi 20 centímetros. Adoptada en 1999 como la Escopeta de Combate " +"M1014, la Benelli M4 es una de las mejores escopetas de combate disponibles." #: lang/json/gun_from_json.py msgid "Mossberg 500 Field" msgid_plural "Mossberg 500 Field" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Mossberg 500 Field" +msgstr[1] "Mossberg 500 Field" #: lang/json/gun_from_json.py msgid "" @@ -123957,12 +125973,15 @@ msgid "" " for military use. It is noted for its high durability and low recoil. " "This one is fitted with a 28 inch barrel with sight rib." msgstr "" +"La Mossberg 500 es una serie popular de escopetas de acción de bombeo, " +"comúnmente utilizada por los militares. Es notable por su gran durabilidad y" +" su poco retroceso. Esta tiene un cañón de 70 centímetros con sight rib." #: lang/json/gun_from_json.py msgid "Mossberg 500 Security" msgid_plural "Mossberg 500 Security" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Mossberg 500 Security" +msgstr[1] "Mossberg 500 Security" #: lang/json/gun_from_json.py msgid "" @@ -123970,12 +125989,15 @@ msgid "" " for military use. It is noted for its high durability and low recoil. " "This one is fitted with an 18.5 inch barrel." msgstr "" +"La Mossberg 500 es una serie popular de escopetas de acción de bombeo, " +"comúnmente utilizada por los militares. Es notable por su gran durabilidad y" +" su poco retroceso. Esta tiene un cañón de 46 centímetros." #: lang/json/gun_from_json.py msgid "Mossberg 590A1" msgid_plural "Mossberg 590A1" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Mossberg 590A1" +msgstr[1] "Mossberg 590A1" #: lang/json/gun_from_json.py msgid "" @@ -123983,12 +126005,15 @@ msgid "" " 500. It features a heavier barrel, a bayonet lug, and a different magazine" " tube for easier cleaning and maintenance." msgstr "" +"La Mossberg 590A1 es una versión de la Mossberg 500 orientada para militares" +" y policías. Tiene un cañón más pesado, agarradera para bayoneta y un " +"cargador diferente para facilitar la limpieza y mantenimiento." #: lang/json/gun_from_json.py msgid "Mossberg 930 SPX" msgid_plural "Mossberg 930 SPXs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Mossberg 930 SPX" +msgstr[1] "Mossberg 930 SPX" #: lang/json/gun_from_json.py msgid "" @@ -123997,6 +126022,10 @@ msgid "" "Affordable pricing and decent ergonomics make this a popular entry-level " "3-gun shotgun." msgstr "" +"Esta versión semiautomática de Mossberg posee un sistema de gas de reducción" +" de retroceso, miras de rifle y un riel picatinny incorporado de fábrica. Su" +" precio accesible y ergonomía decente la hace una escopeta popular de nivel " +"3." #: lang/json/gun_from_json.py msgid "double-barrel pipe shotgun" @@ -124029,8 +126058,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Remington 870 Wingmaster" msgid_plural "Remington 870 Wingmaster" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Remington 870 Wingmaster" +msgstr[1] "Remington 870 Wingmaster" #: lang/json/gun_from_json.py msgid "" @@ -124039,12 +126068,16 @@ msgid "" "agencies alike thanks to its high accuracy and muzzle velocity. This one is" " a 28 inch barreled model for hunting fowl and game." msgstr "" +"Con más de 10 millones fabricadas, la Remington 870 es una de las escopetas " +"más populares del mercado, usada tanto por cazadores como por agencias de " +"fuerzas de la ley gracias a su alta precisión y velocidad de bocacha. Esta " +"tiene un cañón de 70 centímetros para caza mayor y de aves." #: lang/json/gun_from_json.py msgid "Remington 870 MCS" msgid_plural "Remington 870 MCSs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Remington 870 MCS" +msgstr[1] "Remington 870 MCS" #: lang/json/gun_from_json.py msgid "" @@ -124054,12 +126087,18 @@ msgid "" "doors you might come across. The grip's design makes for controllable yet " "unpleasant recoil, and the barrel lacks any sights." msgstr "" +"Esta escopeta Remigton 870 con sistema de combate modular es actualmente " +"configurada para operaciones de rompimiento, con un cañón de 25 centímetros " +"y sin culata. Es lo suficientemente chica como para llevar como arma " +"secundaria, específicamente para abrir puertas molestas que te puedas " +"cruzar. El diseño de la empuñadura le da un retroceso desagradable pero " +"controlable, y el cañón no posee miras." #: lang/json/gun_from_json.py msgid "Remington 870 express" msgid_plural "Remington 870 expresses" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Remington 870 express" +msgstr[1] "Remington 870 express" #: lang/json/gun_from_json.py msgid "" @@ -124068,12 +126107,16 @@ msgid "" "agencies alike thanks to its high accuracy and muzzle velocity. This one is" " an 18.5 inch barreled defensive model." msgstr "" +"Con más de 10 millones fabricadas, la Remington 870 es una de las escopetas " +"más populares del mercado, usada tanto por cazadores como por agencias de " +"fuerzas de la ley gracias a su alta precisión y velocidad de bocacha. Este " +"modelo defensivo tiene un cañón de 46 centímetros." #: lang/json/gun_from_json.py msgid "Remington 1100 competiton" msgid_plural "Remington 1100 competitons" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Remington 1100 competiton" +msgstr[1] "Remington 1100 competiton" #: lang/json/gun_from_json.py msgid "" @@ -124084,6 +126127,13 @@ msgid "" "the nickel finished, teflon coated competition model, with a full length " "magazine tube and 30 inch barrel." msgstr "" +"Esta escopeta semiautomática posee un sistema de gas compensatorio que puede" +" alimentar una gran variedad de cartuchos y disminuir su retroceso. " +"Introducida en 1963, es la favorita de las fuerzas de la ley, cazadores y " +"tiradores de competencia, y ha sido la escopeta más vendida de autocarga en " +"la historia de Estados Unidos. Este modelo de competición tiene terminación " +"en níquel y cobertura de teflón, con tubo cargador de tamaño completo y " +"cañón de 76 centímetros." #: lang/json/gun_from_json.py msgid "shotgun revolver" @@ -124113,6 +126163,11 @@ msgid "" "Mikhail Kalashnikov, and was popular in open division shotgun competitions " "prior to its ban from import via executive order." msgstr "" +"La Saiga-12 es una escopeta semiautomática diseñada con el mismo modelo de " +"Kalashnikov de los rifles AK47. Utiliza un cargador, en lugar de tener que " +"poner cada cartucho de a uno como en la mayoría de las escopetas. Es uno de " +"los últimos diseños de Mikhail Kalashnikov y fue popular en competiciones de" +" escopetas antes de prohibirse su importación por una orden ejecutiva." #: lang/json/gun_from_json.py msgid "double barrel shotgun" @@ -124147,8 +126202,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Cobray Streetsweeper" msgid_plural "Cobray Streetsweepers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Cobray Streetsweeper" +msgstr[1] "Cobray Streetsweeper" #: lang/json/gun_from_json.py msgid "" @@ -124158,12 +126213,18 @@ msgid "" " an ejector rod. Its unique design allows for all 12 shells to be fired in " "under 3 seconds, as demonstrated by the ATF technical branch." msgstr "" +"Es menos una escopeta que un revólver graciosamente grande, el Cobray " +"Streetsweeper se vendió poco antes de ser considerada un dispositivo de " +"destrucción. El cilindro está guiado por un contractor giratorio, no puede " +"ser preparado a mano y debe ser eyectado con un palo eyector. Su diseño " +"único le permite disparar los 12 cartuchos en menos de 3 segundos, como fue " +"demostrado por los técnicos de ATF." #: lang/json/gun_from_json.py msgid "Franchi SPAS-12" msgid_plural "Franchi SPAS-12s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Franchi SPAS-12" +msgstr[1] "Franchi SPAS-12" #: lang/json/gun_from_json.py msgid "" @@ -124173,12 +126234,16 @@ msgid "" "semi-automatic firearm, with an arm stabilizing hook for one handed " "shooting." msgstr "" +"De apariencia intimidatoria, la SPAS 12 tiene el dudoso honor de ser " +"declarada dispositivo de destrucción y ser prohibida su importación, además " +"de su considerable atractivo. Es una combinación de acción de bombeo y " +"semiautomática, con un brazo de estabilización para disparar con una mano." #: lang/json/gun_from_json.py msgid "Tavor TS12" msgid_plural "Tavor TS12s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Tavor TS12" +msgstr[1] "Tavor TS12" #: lang/json/gun_from_json.py msgid "" @@ -124188,12 +126253,17 @@ msgid "" "more like a sci-fi prop gun than a firearm. An integral top rail is " "provided for mounting sights." msgstr "" +"Es una escopeta bullpup de triple cargador y operada por gas fabricada por " +"Israeli Weapon Industries. Es capaz de cargar 15 cartuchos todo en un " +"paquete relativamente pequeño. Como muchos otros diseños de IWI, este parece" +" más un arma de ciencia ficción que un arma de fuego. Un riel integrado " +"superior permite montarle miras." #: lang/json/gun_from_json.py msgid "USAS 12" msgid_plural "USAS 12s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "USAS 12" +msgstr[1] "USAS 12" #: lang/json/gun_from_json.py msgid "" @@ -124202,12 +126272,16 @@ msgid "" "or drum magazines. The in-line recoil system and sheer weight make for " "pleasant shooting." msgstr "" +"La USAS 12 parece un caricatura medio cuadrada de la M16A2. Al igual que su " +"predecesor Auto Assault-12, es una escopeta de disparo selectivo alimentada " +"con cargadores de tambor o de caja. El sistema de retroceso interno y el " +"peso disminuido la hacen agradable de disparar." #: lang/json/gun_from_json.py msgid "1887 bootleg shotgun" msgid_plural "1887 bootleg shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta trucha 1887" +msgstr[1] "escopetas truchas 1887" #: lang/json/gun_from_json.py msgid "" @@ -124217,12 +126291,18 @@ msgid "" "today. This one has a very short barrel, no stock, and would pair nicely " "with a motorcycle jacket and a Harley Davidson." msgstr "" +"Una de las primeras escopetas de repetición comercialmente exitosas, la " +"Winchester 1887 fue realizada específicamente con acción de palanca por " +"pedido de Winchester. Aunque luego fue tapada por el éxito de mejores " +"diseños, la 1887 sigue siendo popular hoy. Esta tiene un cañón muy corto, no" +" tiene culata y hace buena pareja con una campera de motoquero y una Harley " +"Davidson." #: lang/json/gun_from_json.py msgid "M1897 Trench Gun" msgid_plural "M1897 Trench Guns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "M1897 de Trinchera" +msgstr[1] "M1897 de Trinchera" #: lang/json/gun_from_json.py msgid "" @@ -124233,18 +126313,27 @@ msgid "" " There aren't any more trenches to clear, so the next zombie infested town " "will have to suffice." msgstr "" +"La Winchester 1897 fue una de las primeras escopetas de acción de bombeo " +"exitosas. En esta configuración 'de trinchera' ha sido romantizada como un " +"ícono estadounidense de la Primera Guerra Mundial. Con su cañón tapado, " +"agarradera para bayoneta y bayoneta de 43 centímetros, esta escopeta es " +"innegablemente temida por su apariencia. Ya no hay tantas trincheras para " +"despejar, así que la próxima ciudad infectada de zombis va a tener que ser " +"el objetivo." #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" -msgstr[0] "" -msgstr[1] "" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" +msgstr[0] "escopeta cuatro vientos" +msgstr[1] "escopetas cuatro vientos" #: lang/json/gun_from_json.py msgid "" "A crude shotgun, composed of two thick steel pipes, an end cap and a nail. " "The lack of sights make this weapon only useful at point-blank range." msgstr "" +"Es una escopeta simple compuesta de dos caños gruesos de acero, una tapa en " +"la punta y un clavo. La ausencia de miras la hacen solamente útil de cerca." #: lang/json/gun_from_json.py msgid "flaregun" @@ -124275,8 +126364,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "CMES laser cannon" msgid_plural "CMES laser cannons" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "cañón láser CMES" +msgstr[1] "cañones láser CMES" #: lang/json/gun_from_json.py msgid "" @@ -124284,18 +126373,23 @@ msgid "" "rotating-barrel active-cooled rapid-fire laser system, can spray death " "downrange with ease." msgstr "" +"Es un sistema integrado de armas para el el mecatraje exoesqueleto CMES. Un " +"sistema de cañón rotativo de disparo rápido de láser que puede esparcir la " +"muerte con facilidad." #: lang/json/gun_from_json.py msgid "RMES marksman system" msgid_plural "RMES marksman systems" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "sistema francotirador RMES" +msgstr[1] "sistemas francotirador RMES" #: lang/json/gun_from_json.py msgid "" "This is the integral weapon system for the RMES exoskeleton mech-suit, a " "quiet and accurate marksman laser rifle." msgstr "" +"Es un sistema integrado de armas para el el mecatraje exoesqueleto RMES. Un " +"rifle de francotirador silencioso y preciso." #: lang/json/gun_from_json.py msgid "A7 laser rifle" @@ -124310,6 +126404,11 @@ msgid "" "corporate skulduggery. Though the Cataclysm put that on the ash heap of " "history, this weapon can still do the same to your foes." msgstr "" +"Es un rifle láser de última generación, desarrollado por el equipo de " +"investigación y desarrollo \"Aerial Lbas\". Compitió con lo mejor de " +"Rivtech, y hubo rumores sobre trampas empresariales. Aunque el Cataclismo " +"puso eso en la pila de cenizas de la historia, esta arma puede hacer lo " +"mismo con tus enemigos." #: lang/json/gun_from_json.py msgid "V29 laser pistol" @@ -124322,6 +126421,8 @@ msgid "" "This V29 laser pistol was one of the first handheld laser weapons. It is " "larger than most traditional handguns, but displays no recoil whatsoever." msgstr "" +"Esta pistola láser V29 fue una de las primeras armas láser de mano. Es más " +"grande que la mayoría de las pistolas, pero no tiene retroceso." #: lang/json/gun_from_json.py msgid "self bow" @@ -124335,6 +126436,9 @@ msgid "" " the person using it. Weak and wildly inaccurate, it doesn't work that " "well, unfortunately…" msgstr "" +"Es un arco primitivo de una sola pieza de madera, hecho específicamente para" +" la persona que lo está usando. No es potente y poco preciso… " +"lamentablemente, no es muy bueno." #: lang/json/gun_from_json.py msgid "short bow" @@ -124549,6 +126653,9 @@ msgid "" "projectiles instead of the traditional quarrel. Primarily intended for " "hunting small game." msgstr "" +"Es una versión modificada de la ballesta clásica, que te permite utilizar " +"piedras como proyectiles en lugar de los tradicionales pernos. " +"Originalmente, fue pensada para cazar animales pequeños." #: lang/json/gun_from_json.py msgid "pistol crossbow" @@ -124577,6 +126684,8 @@ msgid "" "A slow-loading hand weapon that launches bolts. Bolts fired from this " "weapon have a good chance of remaining intact for re-use." msgstr "" +"Es un arma de mano de recarga lenta que lanza pernos. Los pernos disparados " +"con esta arma tienen una gran probabilidad de no romperse." #: lang/json/gun_from_json.py msgid "composite crossbow" @@ -124645,8 +126754,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "PPA-5" msgid_plural "PPA-5s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "PPA-5" +msgstr[1] "PPA-5" #: lang/json/gun_from_json.py msgid "" @@ -124656,6 +126765,12 @@ msgid "" " It was designed to take down heavy vehicles, and was expected to fully " "enter US Army service not long before the Cataclysm." msgstr "" +"Llamado así por sus siglas en inglés de Acelerador Portátil de Plasma Modelo" +" Cinco, desarrollado por Lockheed Martin Corporation. Este dispositivo " +"utiliza bancos de capacitores avanzados par crear un anillo de plasma de " +"hidrógeno supercalentado y acelerarlo a increíble velocidad. Fue diseñado " +"para destruir vehículos grandes y se esperaba que entrara en servicio en el " +"Ejército de Estados Unidos poco antes del Cataclismo." #: lang/json/gun_from_json.py msgid "Boeing XM-P plasma rifle" @@ -124752,14 +126867,16 @@ msgstr "" msgctxt "weapon" msgid "sling" msgid_plural "slings" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "honda" +msgstr[1] "hondas" #: lang/json/gun_from_json.py msgid "" "A leather sling, can launch rocks much further and faster than throwing them" " by hand." msgstr "" +"Es una honda de cuero. Puede lanzar piedras mucho más lejos y rápido que si " +"lo hicieras con la mano." #: lang/json/gun_from_json.py msgctxt "gun_type_type" @@ -124777,18 +126894,22 @@ msgid "" "A forked piece of wood with an elastic band stretched between two of its " "tips. Can launch tiny pebbles and similar things at high speeds." msgstr "" +"Es un pedazo de madera bifurcado con una banda elástica estirada entre las " +"dos puntas. Puede lanzar piedritas y cosas similares a gran velocidad." #: lang/json/gun_from_json.py msgid "staff sling" msgid_plural "staff slings" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "honda con vara" +msgstr[1] "hondas con vara" #: lang/json/gun_from_json.py msgid "" "This staff can launch rocks with a whiping motion that sends them flying " "much further and faster than throwing them." msgstr "" +"Esta vara puede lanzar piedras con un movimiento de látigo que las arroja " +"volando mucho más lejos y rápido que si lo hicieras con la mano." #: lang/json/gun_from_json.py msgid "brace slingshot" @@ -124801,6 +126922,8 @@ msgid "" "A modern slingshot with a wrist brace, allowing it to fire tiny objects " "slightly more forcefully than a simple wooden slingshot." msgstr "" +"Es una gomera moderna con apoyo para la muñeca, que permite disparar " +"pequeños objetos un poco más ferozmente que con una gomera simple de madera." #: lang/json/gun_from_json.py msgid "pneumatic speargun" @@ -124929,20 +127052,22 @@ msgstr "" #: lang/json/gun_from_json.py msgid "vibrating bioblaster" msgid_plural "vibrating bioblasters" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "bioblaster vibrante" +msgstr[1] "bioblasteres vibrantes" #: lang/json/gun_from_json.py msgid "" "You ripped this from a mi-go abomination. You think you should wear gloves " "to reload it. " msgstr "" +"Le sacaste esto a una abominación mi-go. Te parece que deberías usar guantes" +" para recargarlo." #: lang/json/gun_from_json.py msgid "hard-light longbow" msgid_plural "hard-light longbows" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "arco largo de luz dura" +msgstr[1] "arcos largos de luz dura" #: lang/json/gun_from_json.py msgid "" @@ -124953,18 +127078,28 @@ msgid "" "not as powerful as conventional ballistic weapons. It runs off of UPS " "power, and rather efficiently so." msgstr "" +"Es un arco largo de metal blanco, elegante y sin cuerda, construido con " +"materiales ultralivianos de la era atómica. En lugar de usar munición, cada " +"disparo usa proyectores de alta tecnología para crear una cuerda y una " +"flecha de luz dura en el lugar, lo que otorga excelente precisión y " +"penetración de armadura. Igual, al ser un arco, no es tan potente como armas" +" de fuego convencionales. Funciona con un UPS y de manera bastante " +"eficiente." #: lang/json/gun_from_json.py msgid "deployed grenade launcher" msgid_plural "deployed grenade launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzagranadas desplegado" +msgstr[1] "lanzagranadas desplegados" #: lang/json/gun_from_json.py msgid "" "A grenade launcher mounted onto your right-hand wrist. Less powerful than a" " proper grenade launcher, but infinitely more portable, and quick to reload." msgstr "" +"Es un lanzagranadas montado en tu muñeca derecha. Menos potente que un " +"lanzagranadas convencional pero definitivamente más portátil y rápido de " +"recargar." #: lang/json/gun_from_json.py msgid "shoddy laser rifle" @@ -124983,8 +127118,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "eidolon derringer" msgid_plural "eidolon derringers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "derringer eidolon" +msgstr[1] "derringeres eidolon" #: lang/json/gun_from_json.py msgid "" @@ -124992,12 +127127,15 @@ msgid "" "operations and close range assassination. It will fire up to four 5x50mm " "penetrators simultaneously, to devastating effect." msgstr "" +"Es un derringer miniatura diseñado como arma de apoyo para operaciones " +"encubiertas y asesinatos a corta distancia. Puede disparar hasta cuatro " +"penetradores 5x50mm de manera simultánea, causando un efecto devastador." #: lang/json/gun_from_json.py msgid "wrist-stunner" msgid_plural "wrist-stunners" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "aturdidor de muñeca" +msgstr[1] "aturdidores de muñeca" #: lang/json/gun_from_json.py msgid "" @@ -125005,12 +127143,15 @@ msgid "" "laser stun gun embed on its wrist is still functional, and can be used when " "connected to an UPS." msgstr "" +"Es una mano robótica cortada de un Centinela Wraitheon. La potente arma de " +"aturdimiento de electroláser metida en su muñeca todavía funciona, y puede " +"ser usada si está conectada a un UPS." #: lang/json/gun_from_json.py msgid "wrist-trilaser" msgid_plural "wrist-trilasers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "triláser de muñeca" +msgstr[1] "triláseres de muñeca" #: lang/json/gun_from_json.py msgid "" @@ -125018,26 +127159,54 @@ msgid "" "the wraitheon drone it originally belonged too. Can still be fired when " "connected to an UPS." msgstr "" +"Es una potente arma láser de tres cañones, todavía montada en la mano " +"robótica de un dron wraitheon al que pertenecía originalmente. Todavía puede" +" ser disparada si se la conecta a un UPS." #: lang/json/gun_from_json.py msgid "trilaser" -msgstr "" +msgstr "triláser" #: lang/json/gun_from_json.py msgid "bionic skullgun" msgid_plural "bionic skullguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "arma craneal biónica" +msgstr[1] "armas craneales biónicas" #: lang/json/gun_from_json.py msgid "Bionic one-shot subdermal .40 pistol integrated with your head." msgstr "" +"Es una pistola biónica .40 de un disparo solo integrada en tu cabeza, bajo " +"la piel." + +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "Marlin 39A modificado" +msgstr[1] "Marlin 39A modificados" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "" +"Es un Marlin 39A modificado para ser usado en la torreta de un vehículo." + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "SKS modificada" +msgstr[1] "SKS modificadas" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "" +"Es una SKS modificada para ser adecuada para usar en la torreta de un " +"vehículo." #: lang/json/gun_from_json.py msgid "CRIT .5 LP" msgid_plural "CRIT .5 LPs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] ".5 LP CRIT" +msgstr[1] ".5 LP CRIT" #: lang/json/gun_from_json.py msgid "" @@ -125046,12 +127215,17 @@ msgid "" "compensates for the lack of raw power and yet the gun manages to be " "relatively easy to aim and lightweight due to the superalloy construction." msgstr "" +"Es un arma de apoyo experimental de baja potencia, bajo desarrollo de " +"C.R.I.T R&D. La .5 LP es una pistola láser relativamente débil pero precisa." +" El diseño con dos cañones compensa la falta de poder y de todas maneras el " +"arma logra ser fácil de apuntar y liviana debido a su construcción de " +"superaleación." #: lang/json/gun_from_json.py msgid "CRIT Chain Laser" msgid_plural "CRIT Chain Lasers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Láser Encadenado CRIT" +msgstr[1] "Láser Encadenado CRIT" #: lang/json/gun_from_json.py msgid "" @@ -125060,36 +127234,45 @@ msgid "" "drill, this gun is a relatively light weapon for the amount of UPS it eats " "and destruction it can cause." msgstr "" +"Es la comprobada favorita de las forjas infernales de R&D. Basada en un " +"video de investigación sobre tres .5 LP atados juntos en un taladro de mano," +" esta arma es relativamente liviana para la cantidad de UPS que consume y la" +" destrucción que puede causar." #: lang/json/gun_from_json.py msgid "CRIT Laser Carbine" msgid_plural "CRIT Laser Carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Carabina Láser CRIT" +msgstr[1] "Carabinas Láser CRIT" #: lang/json/gun_from_json.py msgid "" "A short-barrel lightweight laser gun developed by C.R.I.T R&D. Mainly " "developed to test out a new breakthrough in laser weapons." msgstr "" +"Es un arma láser liviana de cañón corto desarrollada por C.R.I.T. R&D. " +"Principalmente desarrollada para probar un nuevo descubrimiento en armas " +"láser." #: lang/json/gun_from_json.py msgid "CRIT Energy Rifle" msgid_plural "CRIT Energy Rifles" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Rifle de Energía CRIT" +msgstr[1] "Rifles de Energía CRIT" #: lang/json/gun_from_json.py msgid "" "A heavy energy gun developed by C.R.I.T R&D. Mainly developed to test out a" " new breakthrough in hybrid weaponry." msgstr "" +"Es un arma grande de energía desarrollada por C.R.I.T. R&D. Principalmente " +"desarrollada para probar un nuevo descubrimiento en armas híbridas." #: lang/json/gun_from_json.py msgid "CRIT CQB Standard Issue" msgid_plural "CRIT CQB Standard Issues" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "reglamentario CRIT de Pelea en Espacios Cerrados" +msgstr[1] "reglamentarios CRIT de Pelea en Espacios Cerrados" #: lang/json/gun_from_json.py msgid "" @@ -125099,26 +127282,34 @@ msgid "" "user's force and the rugged construction with tonfa-like grip can handle " "bashing in enemy heads." msgstr "" +"Es un simple arma combinada. Es una carabina semiautomática militar con la " +"versatilidad a media distancia del 9mm y la potencia de la escopeta 12 " +"gauge. Para completar más el aspecto de pelea en espacio cerrado, la culata " +"está construida para amplificar la fuerza del usuario y la construcción " +"robusta con una empuñadura similar a un tonfa puede romper la cabeza de un " +"enemigo." #: lang/json/gun_from_json.py msgid "CRIT Fire Glove" msgid_plural "CRIT Fire Gloves" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Guante de Fuego CRIT" +msgstr[1] "Guantes de Fuego CRIT" #: lang/json/gun_from_json.py msgid "Experimental CQB weapon system under development in C.R.I.T R&D." msgstr "" +"Es un sistema experimantal de pelea en espacios cerrados, bajo desarrollo de" +" C.R.I.T R&D." #: lang/json/gun_from_json.py msgid "blast" -msgstr "" +msgstr "explosión" #: lang/json/gun_from_json.py msgid "pellet gun" msgid_plural "pellet guns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "arma de aire comprimido" +msgstr[1] "armas de aire comprimido" #: lang/json/gun_from_json.py msgid "" @@ -125128,24 +127319,31 @@ msgid "" "short, but the break action charging system requires some arm strength to " "load a pellet." msgstr "" +"Es un arma de aire sorprendentemente potente que puede usarse para cazar " +"animales pequeños. Los pequeños perdigones de plomo o aleación que puede " +"usar brindan una potencia decente en cada tiro. Es bastante precisa y puede " +"hacer tanto daño como un .22 corto, pero el sistema de carga de cañón " +"basculante requiere un poco de fuerza de brazos para cargar los perdigones." #: lang/json/gun_from_json.py msgid "Plasma Cutter" msgid_plural "Plasma Cutters" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Cortador de Plasma" +msgstr[1] "Cortadores de Plasma" #: lang/json/gun_from_json.py msgid "" "Experimental cutting tool under development in C.R.I.T R&D. It fires an " "extremely hot wave of plasma that slices into materials." msgstr "" +"Es una herramienta experimental de corte desarrollada por C.R.I.T. R&D. " +"Dispara una onda extremadamente caliente de plasma que corta los materiales." #: lang/json/gun_from_json.py msgid "Rivet Driver" msgid_plural "Rivet Drivers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "remachadora eléctrica" +msgstr[1] "remachadoras eléctricas" #: lang/json/gun_from_json.py msgid "" @@ -125154,24 +127352,31 @@ msgid "" "firing it out, upon reaching a target, the fragile stake explodes into " "shards inside the target." msgstr "" +"Es una herramienta experimental de doble propósito bajo desarrollo de " +"C.R.I.T R&D. Usa un clavo normal y lo alarga en una fracción de segundo " +"antes de dispararlo, y al alcanzar el objetivo, el frágil proyectil explota " +"en esquirlas dentro." #: lang/json/gun_from_json.py msgid "Line Gun" msgid_plural "Line Guns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Cañón Líneal" +msgstr[1] "Cañones Líneales" #: lang/json/gun_from_json.py msgid "" "Experimental high power cutting tool under development in C.R.I.T R&D. It " "fires plasma in a wide line for slicing into dense materials." msgstr "" +"Es una herramienta experimental de corte de alta potencia desarrollada por " +"C.R.I.T. R&D. Dispara plasma en una línea ancha para cortar los materiales " +"densos." #: lang/json/gun_from_json.py msgid "Pulse Rifle" msgid_plural "Pulse Rifles" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Rifle de Pulso" +msgstr[1] "Rifles de Pulso" #: lang/json/gun_from_json.py msgid "" @@ -125179,22 +127384,27 @@ msgid "" "Great for enclosed spaces and mobs of enemies. Shoots alloy rounds which " "instantly mushroom out upon impact." msgstr "" +"Es un rifle subsónico experimental de tres cañones bajo desarrollo de " +"C.R.I.T R&D. Muy bueno para espacios cerrados y contra grupos de enemigos. " +"Dispara balas de aleación que se abren al impactar." #: lang/json/gun_from_json.py msgid "Ripper" msgid_plural "Rippers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Destripador" +msgstr[1] "Destripadores" #: lang/json/gun_from_json.py msgid "" "Experimental EM saw under development in C.R.I.T R&D. Great for distance " "cutting of material." msgstr "" +"Es una herramienta experimental electromagnética desarrollada por C.R.I.T. " +"R&D. Es muy buena para cortar materiales a distancia." #: lang/json/gun_from_json.py msgid "em field saw" -msgstr "" +msgstr "sierra de campo electromagnético" #: lang/json/gun_from_json.py msgid "" @@ -125211,8 +127421,8 @@ msgstr "" #: lang/json/gun_from_json.py msgid "Yeet Cannon" msgid_plural "Yeet Cannons" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Cañón Sacudidor" +msgstr[1] "Cañones Sacudidores" #: lang/json/gun_from_json.py msgid "" @@ -125220,6 +127430,8 @@ msgid "" "the zombies in your path, all the hulks, the spiders, and those damned mole " "rats." msgstr "" +"Podés sacudir todas las balas con esta joyita. Sacudiles a todos los zombis " +"que se te crucen, los gigantones, las arañas y todas esas ratas de mierda." #: lang/json/gun_from_json.py msgid "fake flamesword" @@ -125281,12 +127493,15 @@ msgid "" "much punch as the best of 'em and rewards the skilled shooter with easily-" "crafted ammunition." msgstr "" +"Esta antigua arma de fuego carece del ritmo de disparo de las armas modernas" +" pero causa tanto daño como la mejor, y premia al tirador habilidoso con una" +" munición fácil de fabricar." #: lang/json/gun_from_json.py msgid "pipe rifle" msgid_plural "pipe rifles" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "rifle de caño" +msgstr[1] "rifles de caño" #: lang/json/gun_from_json.py msgid "" @@ -125295,12 +127510,16 @@ msgid "" "There's no extractor, so it might be slow to reload, and its construction " "makes for poor reliability and longevity." msgstr "" +"Es un arma larga rudimentaria con calibre de munición estándar de rifle, " +"reforzada cerca de la recámara. Contiene una sola bala y tiene un mecanismo " +"rudimentario de disparo. No tiene extractor, así que es un poco lenta para " +"recargar, y su construcción la hace ser poco fiable y poco duradera." #: lang/json/gun_from_json.py msgid "survivor carbine" msgid_plural "survivor carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "carabina de supervivencia" +msgstr[1] "carabinas de supervivencia" #: lang/json/gun_from_json.py msgid "" @@ -125310,12 +127529,17 @@ msgid "" " ideal durability and reliability, but this should still be a serviceable " "weapon, provided you can stay accurate with it." msgstr "" +"Es una carabina de construcción rudimentaria con calibre para munición " +"estándar de rifle, alimentada con cargadores de rifles de servicio. Posee un" +" sistema rudimentario de acción de palanca. Las grandes presiones " +"involucradas y la construcción cuestionable la hacen poco fiable y poco " +"duradera, pero se puede usar, si sos capaz de ser preciso con ella." #: lang/json/gun_from_json.py msgid "antique pistol" msgid_plural "antique pistols" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "pistola antigua" +msgstr[1] "pistolas antiguas" #: lang/json/gun_from_json.py msgid "" @@ -125324,12 +127548,17 @@ msgid "" "and is theoretically sustainable. Range and accuracy are hampered by lack " "of rifling, but this old design is still plenty lethal." msgstr "" +"Esta anticuada pistola de un disparo solo que completa muy bien el uniforme " +"de pirata. Aunque es lenta para cargar, no necesita vainas de latón para " +"poder disparar, y es, teóricamente, ecológica. La distancia y la precisión " +"se ven disminuidas por la ausencia de estriado, pero este viejo diseño igual" +" es bastante letal." #: lang/json/gun_from_json.py msgid "antique revolver" msgid_plural "antique revolvers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "revólver antiguo" +msgstr[1] "revólveres antiguos" #: lang/json/gun_from_json.py msgid "" @@ -125338,12 +127567,16 @@ msgid "" "fairly lengthy process. Despite its age, this type of weapon would perform" " adequately against most two-legged threats." msgstr "" +"Es un viejo revólver diseñado durante el periodo de la emigración al oeste. " +"Deben cargarse cartuchos de papel de pólvora por cada disparo, lo que " +"resulta un proceso largo. A pesar de su edad, este tipo de armas se " +"desempeña adecuadamente contra la mayoría de amenazas de dos patas." #: lang/json/gun_from_json.py msgid "antique musket" msgid_plural "antique muskets" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mosquete antiguo" +msgstr[1] "mosquetes antiguos" #: lang/json/gun_from_json.py msgid "" @@ -125353,12 +127586,18 @@ msgid "" "theoretically sustainable to fire. Range and accuracy are hampered by lack " "of rifling, but this time-tested design is plenty lethal." msgstr "" +"Con un diseño antiguo, esta arma larga de ánima lisa se vería más acorde en " +"un campo de batalla de antes de 1850 que en tus manos durante el Cataclismo." +" Es lenta para cargar pero no necesita vainas de latón para poder disparar, " +"y es, teóricamente, ecológica de usar. La distancia y la precisión se ven " +"disminuidas por la ausencia de estriado, pero este diseño que superó el paso" +" del tiempo es bastante letal." #: lang/json/gun_from_json.py msgid "grenade launcher" msgid_plural "grenade launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzagranadas" +msgstr[1] "lanzagranadas" #: lang/json/gun_from_json.py msgid "" @@ -125368,12 +127607,17 @@ msgid "" "personnel. Still deadly against hard or soft targets, depending on what " "cartridges are available." msgstr "" +"Es un viejo lanzagranadas de un disparo, que es parecida a una escopeta " +"recortada. Aunque ya ha sido reemplazado por los lanzadores de bajo el " +"cañón, los modelos dedicados como este han sido usados por las fuerzas de la" +" ley y el personal antidisturbios. Sigue siendo letal contra objetivos " +"suaves o duros, dependiendo del cartucho que esté usando." #: lang/json/gun_from_json.py msgid "automatic grenade launcher" msgid_plural "automatic grenade launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzagranadas automático" +msgstr[1] "lanzagranadas automáticos" #: lang/json/gun_from_json.py msgid "" @@ -125384,12 +127628,19 @@ msgid "" " isn't enough to solve your problems, surely a dozen more are. This must be" " mounted on a frame to be fired, and reloading is a bit slow." msgstr "" +"Este lanzagranadas grande e incómodo parece el hijo de una ametralladora y " +"un mortero. Su calibre es enorme y su acción es simplemente masiva. Un " +"enorme cinturón con cartuchos de granada las cargan en la bandeja, lo que " +"permite lanzar varias granadas en sucesión rápida. Si una granada disparada " +"no es suficiente para resolver tu problema, seguro que una docena lo será. " +"Este lanzagranadas tiene que estar montado en una estructura para ser usado," +" y es lento para recargar." #: lang/json/gun_from_json.py msgid "grenade pistol" msgid_plural "grenade pistols" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "pistola de granadas" +msgstr[1] "pistolas de granadas" #: lang/json/gun_from_json.py msgid "" @@ -125401,12 +127652,19 @@ msgid "" "devastating against hard or soft targets. This could be attached to a " "suitable rifle, if so desired." msgstr "" +"Es una pistola regordeta de un disparo solo con un cañón de calibre grande, " +"adecuada para lanzar granadas y bengalas. Es un arma más conveniente para " +"transportar un lanzagranadas que los que van montados en rifles, común entre" +" las fuerzas especiales. En años más recientes, se vendieron algunas " +"versiones para lanzar bengalas. Con el cartucho adecuado, sería devastadora " +"contra objetivos duros o suaves. Puede ser unido a un rifle compatible, si " +"se quiere." #: lang/json/gun_from_json.py msgid "revolver grenade launcher" msgid_plural "revolver grenade launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "revólver lanzagranadas" +msgstr[1] "revólveres lanzagranadas" #: lang/json/gun_from_json.py msgid "" @@ -125416,12 +127674,18 @@ msgid "" "must be re-wound. Needless to say, six well placed shots is an incredible " "amount of firepower, depending on the cartridges loaded." msgstr "" +"Se parece a un revólver grande de un dibujito animado, este lanzador es " +"capaz de disparar seis granadas en una sucesión rápida. Su enorme cilindro " +"está envuelto por un contractor giratorio, que acelera el disparo pero hace " +"más lenta la recarga, ya que tiene que ser enrollado nuevamente. No hay " +"necesidad de decir pero seis disparos es una increíble cantidad de poder de " +"fuego, dependiendo de los cartuchos usados." #: lang/json/gun_from_json.py msgid "cowboy carbine" msgid_plural "cowboy carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "carabina de cowboy" +msgstr[1] "carabinas de cowboy" #: lang/json/gun_from_json.py msgid "" @@ -125431,12 +127695,17 @@ msgid "" "the number of calibers carried and squeeze more power from their pistol " "ammunition." msgstr "" +"Desde los primeros días de la emigración al oeste, cuando la munición era " +"escasa, los tiradores buscaron compartir munición entre sus armas de apoyo y" +" armas largas. Esta carabina de acción de palanca le permite al tirador " +"reducir el número de calibres llevados y exprimir más potencia de la " +"munición de pistola." #: lang/json/gun_from_json.py msgid "machine pistol" msgid_plural "machine pistols" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "pistola ametralladora" +msgstr[1] "pistolas ametralladora" #: lang/json/gun_from_json.py msgid "" @@ -125445,12 +127714,17 @@ msgid "" " Machine pistols mostly see use by vehicle crewmen or bodygaurds of VIPs. " "Due to its preposterous rate of fire it is difficult to control." msgstr "" +"Esta pistola es una ametralladora chiquita que podés meter en una funda y " +"con la que podés vaciarle el cargador a un velocidad feroz contra enemigos " +"cercanos. Las pistolas ametralladora son usadas mayormente por hombres en " +"vehículos o guardaespaldas. Su absurda velocidad de disparo la hace difícil " +"de controlar." #: lang/json/gun_from_json.py msgid "defensive pistol" msgid_plural "defensive pistols" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "pistola defensiva" +msgstr[1] "pistolas defensivas" #: lang/json/gun_from_json.py msgid "" @@ -125459,12 +127733,16 @@ msgid "" "capable of meeting FBI penetration minimums, the lack of a shoulder stock " "limits its utility." msgstr "" +"Es una pistola moderna ideal para servicio policial, militar o defensa " +"personal, con un cargador de caja extraíble y una acción fiable. A pesar de " +"que su calibre es capaz de cumplir con los requisitos de penetración del " +"FBI, la ausencia de culata de apoyo limita su utilidad." #: lang/json/gun_from_json.py msgid "survivalist carbine" msgid_plural "survivalist carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "carabina de supervivencia" +msgstr[1] "carabinas de supervivencia" #: lang/json/gun_from_json.py msgid "" @@ -125474,12 +127752,17 @@ msgid "" "with duty pistols, allowing one to transition to a more stable weapon " "without carrying extra ammo or magazines." msgstr "" +"Estas pequeñas carabinas comparten la munición y cargadores de las pistolas " +"comunes, lo que la hace más controlable que un rifle normal, y también " +"disminuye el costo de la munición. Debido a su compatibilidad, son buena " +"compañía de pistolas de servicio, permitiendo la transición a un arma más " +"estable sin tener que llevar otros cargadores o munición." #: lang/json/gun_from_json.py msgid "police revolver" msgid_plural "police revolvers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "revólver de policía" +msgstr[1] "revólveres de policía" #: lang/json/gun_from_json.py msgid "" @@ -125490,6 +127773,12 @@ msgid "" "make for a serviceable sidearm, and there are no magazines for you to lose " "or damage." msgstr "" +"Los revólveres como este, con calibre defensivo, fueron los favoritos de los" +" departamentos de policía por casi un siglo, hasta el tiroteo de Miami en " +"1986. Después de eso, los revólveres de recarga y disparo lento fueron " +"considerados un problema. Igual, la precisión de este modelo y el retroceso " +"moderado la vuelven utilizable y no hay cargadores que puedas perder o " +"romper." #: lang/json/gun_from_json.py msgid "submachine gun" @@ -125505,12 +127794,17 @@ msgid "" "controllable in automatic fire. It feeds from detachable box magazines, " "which are easy to unload into close range targets." msgstr "" +"Esta arma larga compacta con calibre de munición de pistola es perfecta para" +" atacar trincheras, hombres en vehículos, equipos SWAT y fuerzas especiales." +" Aunque no es tan precisa como un rifle apropiado, especialmente a grandes " +"distancias, es muy controlable en disparo automático. Utiliza cargadores de " +"caja extraíbles, lo que la hace fácil de usar con objetivos cercanos." #: lang/json/gun_from_json.py msgid "survivor subgun" msgid_plural "survivor subguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "fusil de supervivencia" +msgstr[1] "fusiles de supervivencia" #: lang/json/gun_from_json.py msgid "" @@ -125521,12 +127815,18 @@ msgid "" "their nations well enough, so this should be good for zombies... right? " "Accepts standard pistol ammunition." msgstr "" +"Es un subfusil automático fabricado rudimentariamente, que acepta cargadores" +" estándar de pistola y de subfusil. El cerrojo grande lo hace difícil de " +"apuntar y su construcción cuestionable le da una pobre fiabilidad y " +"longevidad. Algunos diseños similares de desesperación se usaron bastante " +"durante la Segunda Guerra Mundial, así que debería servir contra zombis... " +"¿no?" #: lang/json/gun_from_json.py msgid "hand cannon" msgid_plural "hand cannons" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "cañón de mano" +msgstr[1] "cañones de mano" #: lang/json/gun_from_json.py msgid "" @@ -125536,12 +127836,17 @@ msgid "" "deficiencies. Though tradtionally such magnums are revolvers, this one is a" " magazine fed semi-automatic." msgstr "" +"Esta pistola grande es casi tan pesada como una carabina chica, y casi con " +"la misma potencia. Con el potente calibre magnum, es adecuada para cazar " +"animales de tamaño medio, humanos o para compensar las propias deficiencias." +" Aunque tradicionalmente esos magnum eran revólveres, esta pistola utiliza " +"cargadores y es semiautomática." #: lang/json/gun_from_json.py msgid "magnum levergun" msgid_plural "magnum leverguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "arma magnum de palanca" +msgstr[1] "armas magnum de palanca" #: lang/json/gun_from_json.py msgid "" @@ -125551,12 +127856,17 @@ msgid "" "number of calibers carried, and allow you to squeeze more power from " "ammuntion." msgstr "" +"Es una versión moderna del clásico de acción de palanca, este rifle más " +"grande puede usar la poderosa munición magnum de pistola y también munición " +"de pistolas más débiles. Llevar esto con una pistola magnum te permite " +"reducir el número de calibres necesarios y permite también sacarle más " +"potencia a la munición." #: lang/json/gun_from_json.py msgid "handmade magnum carbine" msgid_plural "handmade magnum carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "carabina magnum casera" +msgstr[1] "carabinas magnum caseras" #: lang/json/gun_from_json.py msgid "" @@ -125565,12 +127875,17 @@ msgid "" "with a rudimentary lever action system. Its powerful cartridge and relative" " precision should serve well against zombies and medium game." msgstr "" +"Es una carabina de construcción rudimentaria con calibre para munición de " +"pistolas magnum y pistolas estándar. Utiliza cargadores comerciales de " +"pistola magnum, y tiene un sistema rudimentario de acción de palanca. Su " +"poderoso cartucho y relativa precisión deberían funcionar bien contra zombis" +" y animales medianos." #: lang/json/gun_from_json.py msgid "pipe magnum" msgid_plural "pipe magnums" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "magnum de caño" +msgstr[1] "magnums de caño" #: lang/json/gun_from_json.py msgid "" @@ -125579,12 +127894,16 @@ msgid "" "assembly to fire it. There's no extractor, so it might be slow to reload, " "and its construction makes for poor reliability and longevity." msgstr "" +"Es un arma hecha con un caño robusto, reforzada en la recámara. Contiene una" +" sola bala de pistola magnum o estándar y tiene un mecanismo rudimentario de" +" disparo. No tiene extractor, así que es un poco lenta para recargar, y su " +"construcción la hace ser poco fiable y poco duradera." #: lang/json/gun_from_json.py msgid "hunting magnum" msgid_plural "hunting magnums" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "magnum de caza" +msgstr[1] "magnums de caza" #: lang/json/gun_from_json.py msgid "" @@ -125593,12 +127912,17 @@ msgid "" "revolvers' cylinders can thus chamber both magnum and standard pistol " "ammunition. You could take medium to large game with this hefty piece." msgstr "" +"Las primeras armas de cazadores ayudaron a desarrollar la munición de magnum" +" de este revólver desde los calibres estándar, que necesitaban revólveres " +"más grandes para usar con seguridad. Los cilindros de estos revólveres " +"pueden usar munición tanto de pistolas magnum como estándar. Esta cosa " +"pesada se puede usar contra animales grandes y medianos." #: lang/json/gun_from_json.py msgid "plinker carbine" msgid_plural "plinker carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "carabina de práctica" +msgstr[1] "carabinas de práctica" #: lang/json/gun_from_json.py msgid "" @@ -125607,12 +127931,16 @@ msgid "" "of holding an impressive amount of its small cartridges. You could take " "small game with this, but anything bigger might not even notice." msgstr "" +"Con casi nada de retroceso y munición económica, rifles como este son " +"populares como armas para principiantes. Tiene un cargador integrado capaz " +"de contener una cantidad impresionante de pequeños cartuchos. Se pueden " +"cazar animales pequeños con esto pero algo más grande ni se mosqueará." #: lang/json/gun_from_json.py msgid "target pistol" msgid_plural "target pistols" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "pistola de práctica" +msgstr[1] "pistolas de práctica" #: lang/json/gun_from_json.py msgid "" @@ -125621,12 +127949,16 @@ msgid "" "unsuited for taking on anything but small game, as it is meant to poke holes" " in paper. Accepts box magazines." msgstr "" +"Esta pistola mediana dispara munición de práctica barata y es " +"excepcionalmente popular en prácticas de tiro. Esta pistola no es adecuada " +"para algo más que animales pequeños, y está pensada para hacer agujeros en " +"el papel. Puede usar cargadores de caja." #: lang/json/gun_from_json.py msgid "zip gun" msgid_plural "zip guns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "arma casera" +msgstr[1] "armas caseras" #: lang/json/gun_from_json.py msgid "" @@ -125636,6 +127968,11 @@ msgid "" "might be slow to reload, and its construction leaves its longevity in " "question." msgstr "" +"Es un arma de fuego rudimentaria de un disparo solo, hecha con componentes " +"hogareños, y con calibre para munición pequeña de práctica. Las armas como " +"esta generalmente aparecen en manos de criminales e insurgentes. No tiene " +"extractor así que es medio lenta para recargar, y su construcción pone en " +"duda su longevidad." #: lang/json/gun_from_json.py msgid "assault rifle" @@ -125651,6 +127988,11 @@ msgid "" "large creatures and light vehicles, this should take care of most of your " "problems out to several hundred meters." msgstr "" +"Un rifle como este, producto de décadas de mejoras, son cómodos, fiables y " +"adaptables. Es un 'rifle de asalto' capaz de brindar disparo semiautomático " +"preciso y ráfagas de disparo automático. Excepto criaturas grandes y " +"vehículos ligeros, esto podría encargarse de la mayoría de tus problemas " +"hasta unos cien metros de distancia." #: lang/json/gun_from_json.py msgid "light machine gun" @@ -125667,12 +128009,18 @@ msgid "" "does allow for a considerable amount of energy to be sent down range. Slow " "to reload." msgstr "" +"Esta ametralladora ligera es un implemento formidable para fuego de " +"supresión, una parte importante de la táctica de los escuadrones. Su " +"alimentación por cinto permite cargar cientos de balas y sus componentes " +"pesados pueden soportar grandes ráfagas de disparos. Aunque no sea tan " +"precisa como un rifle de servicio, una ametralladora ligera permite enviar " +"una cantidad considerable de energía. Es lenta de recargar." #: lang/json/gun_from_json.py msgid "sniper rifle" msgid_plural "sniper rifles" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "rifle francotirador" +msgstr[1] "rifles francotirador" #: lang/json/gun_from_json.py msgid "" @@ -125681,12 +128029,17 @@ msgid "" "interfaces for optics and supports. With care and practice, all should be " "quite capable of eliminating bipedal threats from very safe ranges. " msgstr "" +"Los rifles francotirador satisfacen la necesidad de disparos precisos a los " +"militares, policías y civiles. Los ejemplares modernos tienen cargadores " +"extraíbles y varias monturas para ópticas y soportes. Con cuidado y " +"práctica, cualquiera puede ser capaz de eliminar amenazas bípedas desde " +"distancias muy seguras." #: lang/json/gun_from_json.py msgid "sporter carbine" msgid_plural "sporter carbines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "carabina deportiva" +msgstr[1] "carabinas deportivas" #: lang/json/gun_from_json.py msgid "" @@ -125697,12 +128050,18 @@ msgid "" "rifles are just as adequate for taking on anything smaller than large game, " "however." msgstr "" +"Aunque a veces se la etiqueta incorrectamente como rifle de asalto, esta " +"común carabina barata que usa cargadores no es capaz de tener disparo " +"automático. Es efectiva casi de la misma manera que un rifle de servicio, la" +" variedad más amplia de componentes y diferentes niveles de mantenimiento la" +" hacen menos fiables que las versiones militares. Estos rifles son adecuados" +" para animales pequeños y medianos." #: lang/json/gun_from_json.py msgid "anti-materiel rifle" msgid_plural "anti-materiel rifles" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "rifle antimaterial" +msgstr[1] "rifles antimaterial" #: lang/json/gun_from_json.py msgid "" @@ -125711,12 +128070,16 @@ msgid "" "material weapon is best suited for blinding tanks, shooting at aircraft, or " "destroying explosives. It feeds from comically oversized magazines." msgstr "" +"Este rifle pesado, grande, intimidatorio y excesivo dispara grandes " +"proyectiles con precisión relativa. Aunque parece un rifle francotirador, " +"esta arma antimaterial es mejor para atacar tanques, aviones y para destruir" +" explosivos. Utiliza cargadores de un tamaño casi humorísticamente gigante.." #: lang/json/gun_from_json.py msgid "elephant rifle" msgid_plural "elephant rifles" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "rifle de caza mayor" +msgstr[1] "rifles de caza mayor" #: lang/json/gun_from_json.py msgid "" @@ -125726,6 +128089,11 @@ msgid "" "recoil is monstruous. You could probably kill anything with this, " "especially if you were to fire both barrels at once." msgstr "" +"Con grabados elegantes, acero azul brillante y madera veteada, este rifle " +"doble de acción de quiebre es casi demasiado linda para usar. Tu hombro te " +"va a pedir que no lo hagas. La recámara es casi tan ancha como para dos " +"dedos y el retroceso es monstruoso. Probablemente puedas matar cualquier " +"cosa con esto, especialmente si podés disparar los dos cañones a la vez." #: lang/json/gun_from_json.py msgid "heavy machine gun" @@ -125741,12 +128109,18 @@ msgid "" "drones are just as susceptible, as are any other 'smaller' threats. Slow to" " reload, incredibly loud, and must be mounted to be fired." msgstr "" +"Esta ametralladora grande y desgarbada, alimentada con cintas, dispara " +"proyectiles enormes y está pensada originalmente como un cambio en las armas" +" antivehiculares. Aunque ya no es adecuada contra tanques o aviones " +"modernos, los vehículos más ligeros o los drones pueden ser susceptibles, " +"como cualquier otra amenaza 'pequeña'. Lenta para recargar, increíblemente " +"ruidosa y debe estar montada para poder disparar." #: lang/json/gun_from_json.py msgid "disposable rocket launcher" msgid_plural "disposable rocket launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzacohetes descartable" +msgstr[1] "lanzacohetes descartables" #: lang/json/gun_from_json.py msgid "" @@ -125756,12 +128130,18 @@ msgid "" " portability and lack of dead weight once expended. Has a backblast, so " "make sure nothing you mind destroying is behind you." msgstr "" +"Construido con fibra de vidrio con miras rudimentarias de plástico y cañón " +"de titanio, esto es un lanzador de un solo misil. Aunque no es tan efectivo " +"como otras armas antiarmaduras, el valor verdadero de este lanzacohetes " +"descartable es su transportabilidad y ausencia de peso muerto una vez " +"utilizado. Tiene una descarga posterior así que asegurate de que no haya " +"nada importante atrás tuyo." #: lang/json/gun_from_json.py msgid "recoilless rocket launcher" msgid_plural "recoilless rocket launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzacohetes sin retroceso" +msgstr[1] "lanzacohetes sin retroceso" #: lang/json/gun_from_json.py msgid "" @@ -125774,12 +128154,20 @@ msgid "" "tremendous backblast, so make sure nothing you mind destroying is behind " "you." msgstr "" +"Este gigantesco tubo pesado tiene un mira óptica compleja y puede lanzar una" +" gran variedad de cargas explosivas, incluyendo misiles comunes o guiados " +"por láser. Dependiendo de la ojiva cargada, esta arma es efectiva contra " +"tanques antiguos, la mayoría de los vehículos, bunkers y personal. Está " +"pensado para ser usada por dos hombres así que la recarga es un poco lenta. " +"Su diseño sin retroceso permite un rango y daño superiores, pero tiene una " +"tremenda descarga trasera, así que asegurate que no haya nada importante " +"atrás tuyo." #: lang/json/gun_from_json.py msgid "double-barrel shotgun" msgid_plural "double-barrel shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta de doble cañón" +msgstr[1] "escopetas de doble cañón" #: lang/json/gun_from_json.py msgid "" @@ -125788,6 +128176,10 @@ msgid "" " Shotshells come in many varieties, and shotguns are suitable for anything " "from some large game to small birds." msgstr "" +"Es un antigua escopeta de doble cañón con un gatillo para cada uno. Los " +"dispares seguidos son increíblemente rápidos pero la recarga es lenta. Los " +"cartuchos vienen en una gran variedad y las escopetas son adecuadas para " +"cualquier cosa desde animales grandes hasta pájaros pequeños." #: lang/json/gun_from_json.py msgid "" @@ -125796,12 +128188,17 @@ msgid "" "there are no extractors or ejectors. Shotshells come in many varieties, and" " shotguns are suitable for anything from some large game to small birds." msgstr "" +"Esta escopeta rudimentaria de doble cañón con un gatillo para cada uno. Los " +"dispares seguidos son increíblemente rápidos pero la recarga es lenta ya que" +" no tienen extractores o eyectores. Los cartuchos vienen en una gran " +"variedad y las escopetas son adecuadas para cualquier cosa desde animales " +"grandes hasta pájaros pequeños." #: lang/json/gun_from_json.py msgid "sporting shotgun" msgid_plural "sporting shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta deportiva" +msgstr[1] "escopetas deportivas" #: lang/json/gun_from_json.py msgid "" @@ -125811,12 +128208,17 @@ msgid "" "varieties, and shotguns are suitable for anything from some large game to " "small birds." msgstr "" +"Con un diseño simple y popular, las escopetas deportivas son usadas por las " +"fuerzas de la ley, civiles y ocasionalmente militares. Su cargador interno " +"es pequeño comparado con los estándares modernos, y la velocidad de recarga " +"es baja. Los cartuchos vienen en una gran variedad y las escopetas son " +"adecuadas para cualquier cosa desde animales grandes hasta pájaros pequeños." #: lang/json/gun_from_json.py msgid "tactical shotgun" msgid_plural "tactical shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta táctica" +msgstr[1] "escopetas tácticas" #: lang/json/gun_from_json.py msgid "" @@ -125827,12 +128229,12 @@ msgid "" "known for being somewhat finicky, these can be tuned to run with some " "reliability." msgstr "" - -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "" -msgstr[1] "" +"Es una escopeta alimentada por un cargador extraíble, más que nada orientada" +" hacia civiles entusiastas de las armas. Con rieles y una apariencia negra " +"amenazante, esta clase de escopeta no parece ser deportiva. Los cargadores " +"reducen los tiempos de recarga que generalmente poseen las escopetas. Aunque" +" es conocida por ser un poco quisquillosa, puede llegar a funcionar con " +"bastante fiabilidad." #: lang/json/gun_from_json.py msgid "Ichaival" @@ -125846,24 +128248,28 @@ msgid "" " string. It has gold and silver ornaments on it, as well as an ornate " "Raven." msgstr "" +"Ichaival, el arco de Odín. Se dice que dispara 10 flechas por cada vez que " +"se usa. Tiene adornos de oro y plata, y también un Cuervo." #: lang/json/gun_from_json.py msgid "Druid composite bow" msgid_plural "Druid composite bows" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "arco compuesto de Druida" +msgstr[1] "arcos compuestos de Druida" #: lang/json/gun_from_json.py msgid "" "A bow made of multiple materials to maximize energy efficiency. There are " "two Druid runes embedded at the tips." msgstr "" +"Es un arco hecho con varios materiales para maximizar la eficiencia de la " +"energía. Tiene dos runas Druidas incrustadas en las puntas." #: lang/json/gun_from_json.py msgid "M47A1 Techno-Medusa" msgid_plural "M47A1 Techno-Medusae" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "M47A1 Techno-Medusa" +msgstr[1] "M47A1 Techno-Medusae" #: lang/json/gun_from_json.py msgid "" @@ -125872,12 +128278,16 @@ msgid "" "reliability with smaller cartridges, it is not as accurate as dedicated " "caliber revolvers due to freebore." msgstr "" +"Es una actualización de la M47 Medusa de Phillips & Rodgers, mejorada " +"mágicamente. Es un revólver multicalibre ideal para supervivientes. Aunque " +"la Tecnomancia mejora la fiabilidad con cartuchos más chicos, no es tan " +"precisa como revólveres de calibre dedicado debido a su freebore." #: lang/json/gun_from_json.py msgid "gunblade" msgid_plural "gunblades" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "espadarma" +msgstr[1] "espadarmas" #: lang/json/gun_from_json.py msgid "" @@ -125885,34 +128295,43 @@ msgid "" "barrel pump shotgun attached to the blade's spine for finishing blows or a " "first strike." msgstr "" +"Con una construcción similar a la falcata, esta cuchilla inclinada hacia " +"adelante tiene una escopeta de cañón corto unida a la cuchilla para dar el " +"primer golpe o el golpe final." #: lang/json/gun_from_json.py msgid "shotcestus" msgid_plural "shotcesti" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "shotcestus" +msgstr[1] "shotcesti" #: lang/json/gun_from_json.py msgid "" "A sawn-off double-barrel shotgun mounted on a metal cestus. The lack of a " "stock to absorb recoil means some strength is required to fire." msgstr "" +"Es una escopeta doble cañón recortada, montada sobre un cestus metálico. La " +"falta de culata para absorber el retroceso hace que se necesite un poco de " +"fuerza para poder usarla." #: lang/json/gun_from_json.py msgid "Woodbow" msgid_plural "Woodbows" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Maderarco" +msgstr[1] "Maderarcos" #: lang/json/gun_from_json.py msgid "" "A magically conjured ornate recurve bow of solid flexible wood. A matching " "conjured wooden arrow appears when you draw the string back for firing." msgstr "" +"Es un arco recurvo de madera flexible, adornado y conjurado mágicamente. La " +"correspondiente flecha de madera conjurada aparecerá cuando tires de la " +"cuerda para usar el arco." #: lang/json/gun_from_json.py msgid "Fake gun that fires barbed javelins." -msgstr "" +msgstr "Es una pistola falsa que dispara jabalinas con púas." #: lang/json/gunmod_from_json.py msgid "pipe combination gun shotgun" @@ -125925,8 +128344,8 @@ msgid "" "The integrated underbarrel shotgun of a pipe combination gun which holds two" " shots. It's irremovable." msgstr "" -"Es una escopeta integrada bajocañón de un arma de caño combinada, que tiene " -"dos disparos. No se puede quitar." +"Es el bajocañón integrado de escopeta de un arma de caño combinada, que " +"contiene dos disparos. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "underbarrel" @@ -126169,8 +128588,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "Leadworks magazine adapter" msgid_plural "Leadworks magazine adapters" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "adaptador de cargador Leadworks" +msgstr[1] "adaptadores de cargador Leadworks" #: lang/json/gunmod_from_json.py msgid "" @@ -126239,7 +128658,7 @@ msgid "" "A small extension above the grip which an arrow rests upon while being " "aimed. Improves accuracy with no drawbacks." msgstr "" -"Es una pequeña extensión sobre el mango que permite apoyar la flecha " +"Es una pequeña extensión sobre la empuñadura que permite apoyar la flecha " "mientras se está apuntando. Mejora la precisión y no tiene desventajas." #: lang/json/gunmod_from_json.py @@ -126262,8 +128681,9 @@ msgid "" "A counterweight placed forward of the bow's grip allows for greater " "accuracy. Aside from increased weight and size, there are no drawbacks." msgstr "" -"Es un contrapeso puesto delante del mango del arco, que permite mejorar la " -"precisión. La única desventaja que tiene es el incremento del peso." +"Es un contrapeso puesto delante de la empuñadura del arco, que permite " +"mejorar la precisión. La única desventaja que tiene es el incremento del " +"peso." #: lang/json/gunmod_from_json.py msgid "stabilizer" @@ -126309,8 +128729,8 @@ msgstr "amortiguación" #: lang/json/gunmod_from_json.py msgid "belt clip" msgid_plural "belt clips" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "clip de cinturón" +msgstr[1] "clips de cinturón" #: lang/json/gunmod_from_json.py msgid "" @@ -126320,36 +128740,41 @@ msgid "" " to carry with the chamber empty or select a firearm with a very heavy " "trigger pull." msgstr "" +"Es un clip para cinturón que se pone en la empuñadura o al costado de una " +"pistola para facilitar la 'portación a la mexicana', que es llevar encima el" +" arma sin funda. No ofrece ninguna protección para el gatillo así que se " +"recomienda a los usuarios llevarla con la recámara vacía o llevar un arma " +"con un gatillo difícil de apretar." #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rugerlcp" -msgstr "" +msgstr "rugerlcp" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "kp32" -msgstr "" +msgstr "kp32" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "kp3at" -msgstr "" +msgstr "kp3at" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "kpf9" -msgstr "" +msgstr "kpf9" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "cop_38" -msgstr "" +msgstr "cop_38" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "moss_brownie" -msgstr "" +msgstr "moss_brownie" #: lang/json/gunmod_from_json.py msgid "shortened barrel" @@ -126378,18 +128803,22 @@ msgid "" "Testmod for UPS drain on mods, this should never spawn, if you see this, " "it's a bug. 50x more UPS drain." msgstr "" +"Mod de prueba para el uso de UPS en modificaciones, esto no debería aparecer" +" nunca, si lo ves, es un bug. Multiplica por 50 el uso de UPS." #: lang/json/gunmod_from_json.py msgid "Power shot" msgid_plural "Power shots" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Tiro poderoso" +msgstr[1] "Tiros poderosos" #: lang/json/gunmod_from_json.py msgid "" "This is a pseudo item -- the builtin part of a fusion blaster for the " "maximum power firing mode." msgstr "" +"Es un pseudo objeto -- es la parte de la pistola de fusión para el modo de " +"máxima potencia." #: lang/json/gunmod_from_json.py msgid "brass catcher" @@ -126408,12 +128837,12 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid ".300 AAC Blackout AR-15 conversion kit" msgid_plural ".300 AAC Blackout AR-15 conversion kits" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "kit de conversión .300 AAC Blackout AR-15" +msgstr[1] "kits de conversión .300 AAC Blackout AR-15" #: lang/json/gunmod_from_json.py msgid "A complete AR-15 upper assembly with a .300 AAC Blackout barrel." -msgstr "" +msgstr "Es un montaje superior AR-15 con cañón .300 AAC Blackout." #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" @@ -126423,22 +128852,22 @@ msgstr "ar15" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "m4a1" -msgstr "" +msgstr "m4a1" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "m16a4" -msgstr "" +msgstr "m16a4" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "h&k416a5" -msgstr "" +msgstr "h&k416a5" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "m27iar" -msgstr "" +msgstr "m27iar" #: lang/json/gunmod_from_json.py msgid "lightweight replacement furniture" @@ -126451,19 +128880,19 @@ msgid "" "A set of lightweight composite grips and furniture that reduces a firearm's " "weight, and as a consequence, its handling and melee damage." msgstr "" -"Es un equipo de mangos compuestos y accesorios que reducen el peso de un " -"arma de fuego, y como consecuencia reduce también su manejo y daño para el " -"cuerpo a cuerpo." +"Es un equipo de empuñaduras compuestas y accesorios que reducen el peso de " +"un arma de fuego, y como consecuencia reduce también su manejo y daño para " +"el cuerpo a cuerpo." #: lang/json/gunmod_from_json.py msgid "grip" -msgstr "mango" +msgstr "empuñadura" #: lang/json/gunmod_from_json.py msgid "ergonomic grip" msgid_plural "ergonomic grips" -msgstr[0] "mango ergonómico" -msgstr[1] "mangos ergonómicos" +msgstr[0] "empuñadura ergonómica" +msgstr[1] "empuñaduras ergonómicas" #: lang/json/gunmod_from_json.py msgid "" @@ -126475,13 +128904,15 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "breacher grip" msgid_plural "breacher grips" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "empuñadura breacher" +msgstr[1] "empuñaduras breacher" #: lang/json/gunmod_from_json.py msgid "" "A very uncomfortable straight grip. Clearly not intended for regular use." msgstr "" +"Es una empuñadura recta muy incómoda. Claramente, no está hecha para un uso " +"regular." #: lang/json/gunmod_from_json.py msgid "beam scatterer" @@ -126506,14 +128937,17 @@ msgstr "lente" #: lang/json/gunmod_from_json.py msgid "focusing lens" msgid_plural "focusing lenses" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lente de enfoque" +msgstr[1] "lentes de enfoque" #: lang/json/gunmod_from_json.py msgid "" "A set of optics to concentrate the laser beam on a smaller focus point. " "This increases range and damage output, but complicates targeting." msgstr "" +"Es un conjunto de ópticas para concentrar un rayo láser a un punto de " +"enfoque más pequeño. Esto incrementa la distancia y el daño, pero dificulta " +"la precisión." #: lang/json/gunmod_from_json.py msgid "electrolaser conversion" @@ -126534,14 +128968,16 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "effective emitter" msgid_plural "effective emitters" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "emisor efectivo" +msgstr[1] "emisores efectivos" #: lang/json/gunmod_from_json.py msgid "" "A set of electronics to optimize emitter workcycle and increase overall " "energy efficiency. Decreases power consumption." msgstr "" +"Es un grupo de electrónicos que mejoran el trabajo del emisor e incrementan " +"la eficiencia general de la energía. Disminuye el consumo de energía." #: lang/json/gunmod_from_json.py msgid "emitter" @@ -126558,6 +128994,8 @@ msgid "" "A capacitor with a higher energy density increases range and damage; at the " "cost of a markedly increased power consumption." msgstr "" +"Es un capacitor con energía de alta densidad que incrementa el alcance y el " +"daño, pero consume bastante más energía." #: lang/json/gunmod_from_json.py msgid "speedloader chute" @@ -126575,7 +129013,7 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "loading port" -msgstr "" +msgstr "puerto de carga" #: lang/json/gunmod_from_json.py msgid "match trigger" @@ -126613,17 +129051,17 @@ msgstr "" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "ar15_retool_300blk" -msgstr "" +msgstr "ar15_retool_300blk" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "ar_pistol" -msgstr "" +msgstr "ar_pistol" #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "oa93" -msgstr "" +msgstr "oa93" #: lang/json/gunmod_from_json.py msgid "lightning link" @@ -126663,8 +129101,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "replaceable furniture kit" msgid_plural "replaceable furniture kits" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "kit de accesorios reemplazables" +msgstr[1] "kits de accesorios reemplazables" #: lang/json/gunmod_from_json.py msgid "" @@ -126673,16 +129111,21 @@ msgid "" "furniture so that it could be easily changed if needed. This allows " "installing any kind of more advanced grips or other furniture." msgstr "" +"Es un kit que consiste en varias partes de acero y plástico que cuando se " +"instala, modificará permanentemente y reemplazará parcialmente algunos " +"accesorios del arma, para que puedan ser cambiados si es necesario. Esto " +"permite instalar cualquier clase de empuñaduras más avanzadas u otros " +"accesorios." #: lang/json/gunmod_from_json.py msgid "grip mount" -msgstr "" +msgstr "montura de empuñadura" #: lang/json/gunmod_from_json.py msgid "side mount" msgid_plural "side mounts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "montura lateral" +msgstr[1] "monturas laterales" #: lang/json/gunmod_from_json.py msgid "" @@ -126690,16 +129133,19 @@ msgid "" "permanently installed onto almost any weapon, along with some fasteners. " "Ideal for bringing out your inner tacticool on older guns." msgstr "" +"Es una montura plástica para poner un accesorio de riel, diseñada para ser " +"instalada permanentemente en casi cualquier arma, y tiene unos ganchos. " +"Ideal para hacerte el tacticool con tus armas viejas." #: lang/json/gunmod_from_json.py msgid "rail mount" -msgstr "" +msgstr "montura de riel" #: lang/json/gunmod_from_json.py msgid "sights mount" msgid_plural "sights mounts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "montura de mira" +msgstr[1] "monturas de mira" #: lang/json/gunmod_from_json.py msgid "" @@ -126708,12 +129154,15 @@ msgid "" "with some fasteners. Ideal for bringing out your inner tacticool on older " "guns." msgstr "" +"Es una montura plástica para poner una mira, diseñada para ser instalada " +"permanentemente en casi cualquier arma excepto lanzadores y pistolas, y " +"tiene unos ganchos. Ideal para hacerte el tacticool con tus armas viejas." #: lang/json/gunmod_from_json.py msgid "launcher sights mount" msgid_plural "launcher sights mounts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "montura de mira de lanzador" +msgstr[1] "monturas de mira de lanzador" #: lang/json/gunmod_from_json.py msgid "" @@ -126721,12 +129170,15 @@ msgid "" "installed onto almost any launcher, along with some fasteners. Ideal for " "bringing out your inner tacticool on rocket launchers." msgstr "" +"Es una montura plástica para poner una mira, diseñada para ser instalada " +"permanentemente en casi cualquier lanzador, y tiene unos ganchos. Ideal para" +" hacerte el tacticool con tus lanzamisiles." #: lang/json/gunmod_from_json.py msgid "pistol sights mount" msgid_plural "pistol sights mounts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "montura de mira para pistola" +msgstr[1] "monturas de mira para pistola" #: lang/json/gunmod_from_json.py msgid "" @@ -126734,12 +129186,15 @@ msgid "" "installed onto almost any pistol, along with some fasteners. Ideal for " "bringing out your inner tacticool on pocket pistols." msgstr "" +"Es una montura plástica para poner una mira, diseñada para ser instalada " +"permanentemente en casi cualquier pistola, y tiene unos ganchos. Ideal para " +"hacerte el tacticool con tus pistolas." #: lang/json/gunmod_from_json.py msgid "replaceable stock kit" msgid_plural "replaceable stock kits" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "kit de culata reemplazable" +msgstr[1] "kits de culata reemplazable" #: lang/json/gunmod_from_json.py msgid "" @@ -126749,16 +129204,22 @@ msgid "" "simply attach a stock mount if gun had no stock to start with. This allows " "easy installation of any kind of more advanced stocks." msgstr "" +"Es un kit que consiste en varias partes de acero que cuando se instalan, " +"quitaran la culata fija original del arma, instalará una nueva montura de " +"culata, modificará la culata original para que sea compatible y volver a " +"ponerla en el arma, o solamente unirá la montura de culata si el arma no " +"tenía una originalmente. Este permite una fácil instalación de cualquier " +"culata más avanzada." #: lang/json/gunmod_from_json.py msgid "stock mount" -msgstr "" +msgstr "montura de culata" #: lang/json/gunmod_from_json.py msgid "bottom mount" msgid_plural "bottom mounts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "montura de abajo" +msgstr[1] "monturas de abajo" #: lang/json/gunmod_from_json.py msgid "" @@ -126766,10 +129227,13 @@ msgid "" "be permanently installed onto almost any weapon, along with some fasteners." " Ideal for bringing out your inner tacticool on older guns." msgstr "" +"Es una montura plástica para poner un accesorio bajo el cañón, diseñada para" +" ser instalada permanentemente en casi cualquier arma, y tiene unos ganchos." +" Ideal para hacerte el tacticool con tus armas viejas." #: lang/json/gunmod_from_json.py msgid "underbarrel mount" -msgstr "" +msgstr "montura de bajocañón" #: lang/json/gunmod_from_json.py msgid "ported barrel" @@ -126808,8 +129272,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified muzzle brake" msgid_plural "modified muzzle brakes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "freno modificado de boca" +msgstr[1] "frenos modificados de boca" #: lang/json/gunmod_from_json.py msgid "" @@ -126818,6 +129282,11 @@ msgid "" " This one was modified and customized to mount on pretty much any firearm " "other than launchers, if you so want." msgstr "" +"El freno de boca redirige los gases de la combustión de la pólvora para " +"compensar el levantamiento de la bocacha. Disminuye el retroceso pero " +"aumenta el tamaño y el ruido, y reduce un poco la precisión. Este fue " +"modificado y personalizado para poner en casi cualquier arma de fuego " +"excepto lanzadores." #: lang/json/gunmod_from_json.py msgid "homemade suppressor" @@ -126836,12 +129305,19 @@ msgid "" "when attached, will interfere with your ability to aim down the base sights " "of the gun." msgstr "" +"Es un silenciador casero hecho con un caño y trapos. Mientras los trapos " +"aguanten, reducirá el ruido y el destello de la bocacha generados al " +"disparar. Las armas de fuego son extremadamente ruidosas y puede dañar tu " +"audición si no usás protección; un silenciador reduce el ruido a niveles " +"seguros, y también reduce un poco el retroceso y la velocidad de bocacha. " +"Este silenciador es grande y, cuando se lo pone, interfiere tu habilidad " +"para apuntar." #: lang/json/gunmod_from_json.py msgid "'solvent trap' suppressor" msgid_plural "'solvent trap' suppressors" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "silenciador 'trampa de solvente'" +msgstr[1] "silenciadores 'trampa de solvente'" #: lang/json/gunmod_from_json.py msgid "" @@ -126853,12 +129329,19 @@ msgid "" " attached, will interfere with your ability to aim down the base sights of " "the gun." msgstr "" +"Es un filtro de automotores adaptado rudimentariamente para coincidir con el" +" cañón del arma, armando un silenciador ilegal y no registrado. Qué bueno " +"que no parece haber ningún agente de la ATF que te pueda arrestar. Aunque es" +" similar en diseño a un silenciador real, no fue diseñado para grandes " +"presiones y eventualmente perderá efectividad. El filtro instalado es grande" +" y cuando está puesto, interferirá tu habilidad de apuntar con las miras del" +" arma." #: lang/json/gunmod_from_json.py msgid "soda bottle silencer" msgid_plural "soda bottle silencers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "silenciador de botella" +msgstr[1] "silenciadores de botella" #: lang/json/gunmod_from_json.py msgid "" @@ -126870,6 +129353,13 @@ msgid "" "suppressor is large and, when attached, will interfere with your ability to " "aim down the base sights of the gun." msgstr "" +"Es un 'silenciador' hecho con una botella de gaseosa de 2 litros, algunas " +"botellas más chicas que son como bafles, y un buen pedazo de cinta adhesiva." +" Los disparos son estrepitosamente fuertes y pueden dañar tu audición si no " +"tenés protección y podés estar seguro de que esto no te va a proteger las " +"orejas. Lo que puede hacer es permitirte disparar un tiro o dos con un poco " +"menos de ruido. Este simple silenciador es grande y, cuando está puesto, " +"interferirá en tu habilidad para apuntar con las miras del arma." #: lang/json/gunmod_from_json.py msgid "RK6S34 suppressor" @@ -126898,6 +129388,8 @@ msgid "" "A large suppressor designed to work with shotguns. It's a lot more complex " "than a suppressor for a pistol or rifle." msgstr "" +"Es un silenciador grande diseñado para funcionar en escopetas. Es mucho más " +"complejo que un silenciador para pistola o para rifle." #: lang/json/gunmod_from_json.py msgid "suppressor" @@ -126920,8 +129412,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "MP5SD integral suppressor" msgid_plural "MP5SD integral suppressors" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "silenciador integrado MP5SD" +msgstr[1] "silenciadores integrados MP5SD" #: lang/json/gunmod_from_json.py msgid "" @@ -126930,6 +129422,10 @@ msgid "" "most ammo subsonic at the cost of terminal performance. It is not as " "effective as modern designs." msgstr "" +"Es un silenciador integrado para la H&K MP5SD. Su recámara de gran expansión" +" desacelera la munición a través de varios puertos en el cañón, volviendo " +"subsónica a la mayoría de la munición a cambio de un poco de desempeño " +"terminal. No es tan efectivo como los diseños modernos." #: lang/json/gunmod_from_json.py msgid "compact suppressor" @@ -126948,8 +129444,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "rail-mounted crossbow" msgid_plural "rail-mounted crossbows" -msgstr[0] "ballesta montable de riel" -msgstr[1] "ballestas montables de riel" +msgstr[0] "ballesta montable en riel" +msgstr[1] "ballestas montables en riel" #: lang/json/gunmod_from_json.py msgid "" @@ -126966,8 +129462,8 @@ msgstr "riel" #: lang/json/gunmod_from_json.py msgid "modified rail-mounted crossbow" msgid_plural "modified rail-mounted crossbows" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "ballesta modificada montable en riel" +msgstr[1] "ballestas modificadas montables en riel" #: lang/json/gunmod_from_json.py msgid "" @@ -126976,6 +129472,10 @@ msgid "" " and customized to mount on pretty much any weapon other than pistols and " "SMGs, if you so want." msgstr "" +"Es un kit para poner un par de brazos de ballesta y riel de tiro en el cañón" +" de un arma larga. Permite disparar pernos de ballestas. Esta ha sido " +"modificada y personalizada para poder ponerse en casi cualquier arma si " +"querés, excepto pistolas y subfusiles." #: lang/json/gunmod_from_json.py msgid "offset iron sights" @@ -126995,8 +129495,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified offset iron sights" msgid_plural "modified offset iron sights" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mirilla modificada metálica de compensación" +msgstr[1] "mirillas modificadas metálicas de compensación" #: lang/json/gunmod_from_json.py msgid "" @@ -127004,6 +129504,10 @@ msgid "" "other modification prevents use of the primary sights. This one was " "modified and customized to mount on pretty much any weapon, if you so want." msgstr "" +"Es un equipo alternativo de mirillas metálicas montadas a 45º para usar " +"cuando una mira o alguna otra modificación impide el uso de las mirillas " +"primarias. Esta ha sido modificada y personalizada para poner en casi " +"cualquier arma." #: lang/json/gunmod_from_json.py msgid "offset sight rail" @@ -127020,14 +129524,16 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified offset sight rail" msgid_plural "modified offset sight rails" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mirilla metálica de riel de compensación" +msgstr[1] "mirillas metálicas de riel de compensación" #: lang/json/gunmod_from_json.py msgid "" "An additional rail set at 45° for attaching a secondary optic. This one was" " modified and customized to mount on pretty much any weapon, if you so want." msgstr "" +"Es un grupo de rieles adicionales en 45° para poner una óptica secundaria. " +"Esta ha sido modificada y personalizada para poner en casi cualquier arma." #: lang/json/gunmod_from_json.py msgid "rail laser sight" @@ -127063,8 +129569,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified gyroscopic stabilizer" msgid_plural "modified gyroscopic stabilizers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "estabilizador giroscópico modificado" +msgstr[1] "estabilizadores giroscópicos modificados" #: lang/json/gunmod_from_json.py msgid "" @@ -127073,6 +129579,10 @@ msgid "" "one was modified and customized to mount on pretty much any weapon other " "than pistols, if you so want." msgstr "" +"Es una unidad avanzada que se ata con una correa al costado del arma de " +"fuego y reduce la vibración, lo que reduce mucho el retroceso e incrementa " +"levemente la precisión. Este fue modificado y personalizado para poner en " +"casi cualquier arma excepto pistolas." #: lang/json/gunmod_from_json.py msgid "five pin bow sight" @@ -127187,12 +129697,15 @@ msgid "" "A 3-18x44 rifle scope. It is adjustable for windage and elevation in 1/10th" " mrad increments and is remarkably small and light for its magnification." msgstr "" +"Es una mira de rifle 3-18x44. Se puede ajustar por desviación y elevación en" +" incrementos de 1/10mo mrad y es notablemente pequeña y liviana por su " +"aumento." #: lang/json/gunmod_from_json.py msgid "modified rifle scope" msgid_plural "modified rifle scopes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mira modificada para rifle" +msgstr[1] "miras modificadas para rifle" #: lang/json/gunmod_from_json.py msgid "" @@ -127201,6 +129714,10 @@ msgid "" "This one was modified and customized to mount on pretty much any weapon " "other than pistols and SMGs, if you so want." msgstr "" +"Es una mira de rifle 3-18x44. Se puede ajustar por desviación y elevación en" +" incrementos de 1/10mo mrad y es notablemente pequeña y liviana por su " +"aumento. Esta fue modificada y personalizada para poner en casi cualquier " +"arma excepto pistolas y subfusiles." #: lang/json/gunmod_from_json.py msgid "ACOG scope" @@ -127213,12 +129730,14 @@ msgid "" "A 4x32 TA01 Advanced Combat Optical Gunsight with a tritium illuminated " "crosshair." msgstr "" +"Es una Mira Óptica Avanzada de Combate 4x32 TA01 con puntos de mira de " +"tritio iluminados." #: lang/json/gunmod_from_json.py msgid "modified ACOG scope" msgid_plural "modified ACOG scopes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mira modificada ACOG" +msgstr[1] "miras modificadas ACOG" #: lang/json/gunmod_from_json.py msgid "" @@ -127226,6 +129745,9 @@ msgid "" "crosshair. This one was modified and customized to mount on pretty much any" " weapon other than pistols, if you so want." msgstr "" +"Es una Mira Óptica Avanzada de Combate 4x32 TA01 con puntos de mira de " +"tritio iluminados. Esta fue modificada y personalizada para poner en casi " +"cualquier arma excepto pistolas." #: lang/json/gunmod_from_json.py msgid "RS1219 scope" @@ -127255,6 +129777,9 @@ msgid "" "crosshairs. Not as good as the ones made before the Cataclysm. Increases " "weight but improves accuracy." msgstr "" +"Es una simple mira telescópica hecha a mano, es como un telescopio con " +"puntos de mira. No tan buena como las fabricadas antes del Cataclismo. " +"Incrementa el peso pero mejora la precisión." #: lang/json/gunmod_from_json.py msgid "telescopic pistol sight" @@ -127322,8 +129847,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "folding wire stock" msgid_plural "folding wire stocks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "culata de alambre plegable" +msgstr[1] "culatas de alambre plegables" #: lang/json/gunmod_from_json.py msgid "" @@ -127331,6 +129856,9 @@ msgid "" "before use. It's somewhat wobbly but is better than nothing at all. " "Increases the time needed to wield the weapon." msgstr "" +"Es una culata de alambre plegable que puede ocupar muy poco espacio pero " +"necesita desplegarse antes de usar. Es medio endeble pero es mejor que nada." +" Incrementa el tiempo necesario para empuñar el arma." #: lang/json/gunmod_from_json.py msgid "pistol stock" @@ -127341,6 +129869,8 @@ msgstr[1] "culatas para pistola" #: lang/json/gunmod_from_json.py msgid "An add-on stock for handguns considerably improving control of recoil." msgstr "" +"Es una culata para pistolas que mejora considerablemente el control del " +"retroceso." #: lang/json/gunmod_from_json.py msgid "recoil stock" @@ -127390,8 +129920,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified bipod" msgid_plural "modified bipods" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "bípode modificado" +msgstr[1] "bípodes modificados" #: lang/json/gunmod_from_json.py msgid "" @@ -127401,6 +129931,11 @@ msgid "" "was modified and customized to mount on pretty much any weapon, if you so " "want." msgstr "" +"Los bípodes son usados comúnmente en los rifles y ametralladoras, para " +"proveer de un apoyo adelante y reducir el movimiento. Aunque mejoran mucho " +"el manejo del retroceso, solo pueden usarse en ciertas superficies y son " +"lentos para armar. Este ha sido modificado y personalizado pra poner en casi" +" cualquier arma." #: lang/json/gunmod_from_json.py msgid "combination gun shotgun" @@ -127413,14 +129948,14 @@ msgid "" "The integrated underbarrel shotgun of a combination gun which holds two " "shots. It's irremovable." msgstr "" -"Es una escopeta integrada bajocañón de un arma combinada, que tiene dos " -"disparos. No se puede quitar." +"Es el bajocañón integrado de escopeta de un arma combinada, que contiene dos" +" disparos. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "factory handguard" msgid_plural "factory handguards" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "guardamano de fábrica" +msgstr[1] "guardamanos de fábrica" #: lang/json/gunmod_from_json.py msgid "" @@ -127428,32 +129963,35 @@ msgid "" " as efficient as a proper forward grip or bipod at controlling recoil, but " "it's better than nothing." msgstr "" +"Es una empuñadura extraíble que se vuelve estándar en armas sin riel. No es " +"tan eficiente como una empuñadura delantera apropiada o un bípode para " +"controlar el retroceso, pero es mejor que nada." #: lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "fs2000" -msgstr "" +msgstr "fs2000" #: lang/json/gunmod_from_json.py msgid "forward grip" msgid_plural "forward grips" -msgstr[0] "mango vertical" -msgstr[1] "mangos verticales" +msgstr[0] "empuñadura delantera" +msgstr[1] "empuñaduras delanteras" #: lang/json/gunmod_from_json.py msgid "" "A grip placed forward on the barrel allows for greater control. Not as " "effective as a bipod but usable under all conditions." msgstr "" -"Es un mango que se pone en el cañón del arma, lo que permite tener mayor " -"control. No es tan efectivo como un bípode pero se puede usar bajo cualquier" -" condición." +"Es una empuñadura que se pone en el cañón del arma, lo que permite tener " +"mayor control. No es tan efectiva como un bípode pero se puede usar bajo " +"cualquier condición." #: lang/json/gunmod_from_json.py msgid "modified forward grip" msgid_plural "modified forward grips" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "empuñadura delantera modificada" +msgstr[1] "empuñaduras delanteras modificadas" #: lang/json/gunmod_from_json.py msgid "" @@ -127461,6 +129999,10 @@ msgid "" "effective as a bipod but usable under all conditions. This one was modified" " and customized to mount on pretty much any weapon, if you so want." msgstr "" +"Es una empuñadura que se pone en el cañón del arma, lo que permite tener " +"mayor control. No es tan efectivo como un bípode pero se puede usar bajo " +"cualquier condición. Esta fue modificada y personalizada para poner en casi " +"cualquier arma." #: lang/json/gunmod_from_json.py msgid "integrated bayonet" @@ -127487,44 +130029,50 @@ msgid "" "The integrated second shotgun magazine of the Kel-Tec KSG which holds 7 " "shots. It's irremovable." msgstr "" -"Es el cargador de escopeta secundario integrado del Kel-Tec KSG, que " -"contiene 7 disparos. No se puede quitar." +"Es un segundo cargador de escopeta integrado de Kel-Tec KSG, que contiene 7 " +"disparos. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "KSG-25 second magazine" msgid_plural "KSG-25 second magazines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "cargador secundario KSG-25" +msgstr[1] "cargadores secundarios KSG-25" #: lang/json/gunmod_from_json.py msgid "" "The integrated second shotgun magazine of the Kel-Tec KSG-25 which holds 12 " "shots. It's irremovable." msgstr "" +"Es un segundo cargador de escopeta integrado de Kel-Tec KSG-25, que contiene" +" 12 disparos. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "TS12 second magazine" msgid_plural "TS12 second magazines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "cargador secundario TS12" +msgstr[1] "cargadores secundarios TS12" #: lang/json/gunmod_from_json.py msgid "" "The integrated second shotgun magazine of the Tavor TS12 which holds 5 " "shots. It's irremovable." msgstr "" +"Es un segundo cargador de escopeta integrado de Tavor TS12, que contiene 5 " +"disparos. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "TS12 third magazine" msgid_plural "TS12 third magazines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "cargador terciario TS12" +msgstr[1] "cargadores terciarios TS12" #: lang/json/gunmod_from_json.py msgid "" "The integrated third shotgun magazine of the Tavor TS12 which holds 5 shots." " It's irremovable." msgstr "" +"Es un tercer cargador de escopeta integrado de Tavor TS12, que contiene 5 " +"disparos. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "underbarrel laser sight" @@ -127553,6 +130101,9 @@ msgid "" "The Lemat revolver is unique in that its cylinder axis pin is also a fully " "functional 20ga percussion-primed smoothbore barrel. It's irremovable." msgstr "" +"El revólver Lemat es único en que su eje cilíndrico es también un cañón " +"completamente funcional de ánima lisa, activado por percusión, calibre 20ga." +" No se puede quitar." #: lang/json/gunmod_from_json.py msgid "M203" @@ -127573,8 +130124,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified M203" msgid_plural "modified M203s" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "M203 modificado" +msgstr[1] "M203 modificados" #: lang/json/gunmod_from_json.py msgid "" @@ -127583,6 +130134,10 @@ msgid "" "and fired. This one was modified and customized to mount on pretty much any" " weapon other than pistols and pump-action guns, if you so want." msgstr "" +"El lanzagranadas M203 fue diseñado originalmente para usar variantes del " +"M16, pero hoy en día puede ser adjuntado a cualquier rifle. Permite cargar y" +" disparar una granada 40mm. Este fue modificado y personalizado para poner " +"en casi cualquier arma excepto pistolas y armas de acción de bombeo." #: lang/json/gunmod_from_json.py msgid "M320 GLM" @@ -127597,12 +130152,15 @@ msgid "" " be either attached to a rifle or combined with a buttstock for standalone " "use." msgstr "" +"El Módulo M320 Lanzagranadas ofrece la funcionalidad de lanzadores más " +"grandes en un tamaño pequeño, a cambio de una menor precisión. Puede ser " +"adjuntado a un rifle o combinado con una culata para ser usado solo." #: lang/json/gunmod_from_json.py msgid "modified M320 GLM" msgid_plural "modified M320 GLMs" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "M320 GLM modificado" +msgstr[1] "M320 GLM modificados" #: lang/json/gunmod_from_json.py msgid "" @@ -127612,18 +130170,25 @@ msgid "" "use. This one was modified and customized to mount on pretty much any " "weapon other than pistols and pump-action guns, if you so want." msgstr "" +"El Módulo M320 Lanzagranadas ofrece la funcionalidad de lanzadores más " +"grandes en un tamaño pequeño, a cambio de una menor precisión. Puede ser " +"adjuntado a un rifle o combinado con una culata para ser usado solo. Este " +"fue modificado y personalizado para poner en casi cualquier arma excepto " +"pistolas y armas de acción de bombeo." #: lang/json/gunmod_from_json.py msgid "M6 Survival Gun shotgun" msgid_plural "M6 Survival Gun shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "cañón de supervivencia M6" +msgstr[1] "cañones de supervivencia M6" #: lang/json/gunmod_from_json.py msgid "" "The integrated 12 gauge shotgun barrel of the Chiappa M6 Survival Gun. It's" " irremovable." msgstr "" +"Es el cañón integrado calibre 12 gauge de la escopeta Chiappa M6 de " +"supervivencia. No se puede quitar." #: lang/json/gunmod_from_json.py msgid "masterkey shotgun" @@ -127644,8 +130209,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified masterkey shotgun" msgid_plural "modified masterkey shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta masterkey modificada" +msgstr[1] "escopetas masterkey modificadas" #: lang/json/gunmod_from_json.py msgid "" @@ -127654,6 +130219,10 @@ msgid "" "fired. This one was modified and customized to mount on pretty much any " "weapon other than pistols and pump-action guns, if you so want." msgstr "" +"Es una escopeta minimalista de acción de bombeo, que puede ser puesta bajo " +"el cañón de varios rifles. Permite cargar y disparar un total de cuatro " +"cartuchos de escopeta. Este fue modificado y personalizado para poner en " +"casi cualquier arma excepto pistolas y armas de acción de bombeo." #: lang/json/gunmod_from_json.py msgid "40mm pipe launcher" @@ -127666,6 +130235,8 @@ msgid "" "This is a home built launcher tube that can be attached to almost any weapon" " except handguns. It allows a single 40mm grenade to be loaded and fired." msgstr "" +"Es un tubo lanzador casero que puede ser adjuntado a casi cualquier arma, " +"excepto pistolas. Permite cargar y disparar una granada 40mm." #: lang/json/gunmod_from_json.py msgid "pistol bayonet" @@ -127701,8 +130272,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified RM121 aux shotgun" msgid_plural "modified RM121 aux shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta auxiliar modificada RM121" +msgstr[1] "escopetas auxiliares modificadas RM121" #: lang/json/gunmod_from_json.py msgid "" @@ -127711,6 +130282,10 @@ msgid "" "Accepts RMSA10 box magazines. This one was modified and customized to mount" " on pretty much any weapon other than pistols, if you so want." msgstr "" +"El sistema auxiliar Rivtech RM121 es una escopeta semiautomática sin vaina, " +"que puede ser montada debajo del cañón de varios rifles. Acepta los " +"cargadores de caja RMSA10. Este fue modificado y personalizado para poner en" +" casi cualquier arma excepto pistolas." #: lang/json/gunmod_from_json.py msgid "underslung shotgun" @@ -127729,8 +130304,8 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "modified underslung shotgun" msgid_plural "modified underslung shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta colgante modificada" +msgstr[1] "escopetas colgantes modificadas" #: lang/json/gunmod_from_json.py msgid "" @@ -127739,6 +130314,10 @@ msgid "" " was modified and customized to mount on pretty much any weapon other than " "pistols, if you so want." msgstr "" +"Es una escopeta corta con dos cañones que puede ser puesta bajo el cañón de " +"varios rifles. Permite cargar y disparar un total de dos cartuchos de " +"escopeta. Este fue modificado y personalizado para poner en casi cualquier " +"arma excepto pistolas." #: lang/json/gunmod_from_json.py msgid "spare magazine" @@ -127814,32 +130393,36 @@ msgstr "" #: lang/json/gunmod_from_json.py msgid "Underslung flare launcher" msgid_plural "Underslung flare launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzabengalas colgante" +msgstr[1] "lanzabengalas colgantes" #: lang/json/gunmod_from_json.py msgid "" "A small barrel which launches signal flares. However, due to its awkward " "position, it has lower accuracy compared to an actual flaregun." msgstr "" +"Es un pequeño cañón que lanza bengalas. Sin embargo, debido a su incómoda " +"posición, tiene poca precisión comparada con una pistola de bengalas normal." #: lang/json/gunmod_from_json.py msgid "CQB SI shotgun" msgid_plural "CQB SI shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta CQB SI" +msgstr[1] "escopetas CQB SI" #: lang/json/gunmod_from_json.py msgid "" "The integrated underbarrel shotgun of this gun which holds a single shot. " "It's irremovable." msgstr "" +"Es el bajocañón integrado de escopeta que contiene un disparo. No se puede " +"quitar." #: lang/json/gunmod_from_json.py msgid "butt hook stock" msgid_plural "butt hook stocks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "culata gancho" +msgstr[1] "culatas gancho" #: lang/json/gunmod_from_json.py msgid "" @@ -127847,12 +130430,15 @@ msgid "" "and the pivoting hook which latches onto your forearm allows for greater " "stability. " msgstr "" +"Es una culata militar que se pliega para reducir el tamaño del arma. El peso" +" y el gancho giratorio que se engancha en tu antebrazo permiten una gran " +"estabilidad." #: lang/json/gunmod_from_json.py msgid "diffracting lens" msgid_plural "diffracting lenses" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lente difractario" +msgstr[1] "lentes difractarios" #: lang/json/gunmod_from_json.py msgid "" @@ -127860,36 +130446,43 @@ msgid "" "beam into several lower powered beams. This slightly increases point-blank " "damage and makes it difficult to not hit, but reduces range" msgstr "" +"Es un conjunto de ópticas hechas para ponerse en armas láser, que difractan " +"el rayo láser en varios rayos de bajo poder. Esto incrementa levemente el " +"daño a quemarropa, pero reduce su alcance." #: lang/json/gunmod_from_json.py msgid "tactical flashlight" msgid_plural "tactical flashlights" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "linterna táctica" +msgstr[1] "linternas tácticas" #: lang/json/gunmod_from_json.py msgid "" "A compact flashlight which is mounted to the side of your weapon, not " "powerful, but good enough for tight hallways." msgstr "" +"Es una linterna compacta que se pone en el costado del arma, no es muy " +"potente pero es suficiente para espacios pequeños." #: lang/json/gunmod_from_json.py msgid "tactical flashlight (on)" msgid_plural "tactical flashlights (on)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "linterna táctica (enc.)" +msgstr[1] "linternas tácticas (enc.)" #: lang/json/gunmod_from_json.py msgid "" "A compact flashlight which is attached to the side of your weapon, not " "powerful, but good enough for tight hallways." msgstr "" +"Es una linterna compacta puesta en el costado del arma, no es muy potente " +"pero es suficiente para espacios pequeños." #: lang/json/gunmod_from_json.py msgid "underbarrel launcher" msgid_plural "underbarrel launchers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzador bajocañón" +msgstr[1] "lanzadores bajocañón" #: lang/json/gunmod_from_json.py msgid "" @@ -127901,12 +130494,19 @@ msgid "" "targets. The launcher can be detached and its sights reattached to the " "could be disassembled and attached to a suitable rifle, if so desired." msgstr "" +"Es un lanzador regordete de un disparo con un cañón de calibre grande, " +"adecuado para granadas y bengalas. Este lanzador puede ser unido a un rifle " +"u otra arma adecuada, e incluye su propio grupo de miras. En años más " +"recientes, se vendieron algunas versiones para lanzar bengalas. Con el " +"cartucho adecuado, sería devastadora contra objetivos duros o suaves. Este " +"lanzador puede ser quitado y sus miras vueltas a poner para poder desarmar y" +" poner en un rifle adecuado." #: lang/json/gunmod_from_json.py msgid "underbarrel launcher (modified)" msgid_plural "underbarrel launcher (modified)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "lanzador bajocañón (modificado)" +msgstr[1] "lanzadores bajocañón (modificados)" #: lang/json/gunmod_from_json.py msgid "" @@ -127917,36 +130517,45 @@ msgid "" "would be devastating against hard or soft targets. A crude homemade bracket " "has been attached, allowing a wider variety of hosts." msgstr "" +"Es un lanzador regordete de un disparo adecuado para granadas y bengalas. " +"Este lanzador puede ser unido a un rifle u otra arma adecuada, e incluye su " +"propio grupo de miras. En años más recientes, se vendieron algunas versiones" +" para lanzar bengalas. Con el cartucho adecuado, sería devastadora contra " +"objetivos duros o suaves. Tiene puesto un soporte rudimentario que permite " +"una variedad más amplia de receptores." #: lang/json/gunmod_from_json.py msgid "underbarrel shotgun" msgid_plural "underbarrel shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta bajocañón" +msgstr[1] "escopetas bajocañón" #: lang/json/gunmod_from_json.py msgid "modified underbarrel shotgun" msgid_plural "modified underbarrel shotguns" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "escopeta bajocañón modificada" +msgstr[1] "escopetas bajocañón modificadas" #: lang/json/gunmod_from_json.py msgid "'Silent Winds' suppressor" msgid_plural "'Silent Winds' suppressors" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "silenciador 'Vientos Silenciosos'" +msgstr[1] "silenciadores 'Vientos Silenciosos'" #: lang/json/gunmod_from_json.py msgid "" "Rather than using purely wipe media, an additional localized silence spell " "in this tube quiets gunshots going through to hearing-safe levels." msgstr "" +"Más que usar trapos como material, un hechizo de silencio ha sido localizado" +" en este tubo para silenciar los disparos a niveles seguros para la " +"audición." #: lang/json/gunmod_from_json.py msgid "mana laser sight (rail)" msgid_plural "mana laser sights (rail)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mirilla láser de maná (riel)" +msgstr[1] "mirillas láser de maná (riel)" #: lang/json/gunmod_from_json.py msgid "" @@ -127955,12 +130564,16 @@ msgid "" "acquisition. Aside from increased weight, there are no drawbacks. You can " "rotate the attachment rail to fit under the barrel." msgstr "" +"Es una pequeña mira láser que usa luz a través de un cristal de maná, que se" +" monta sobre el riel de accesorios del arma de fuego para mejorar la " +"facilidad y velocidad para apuntar. La única desventaja que tiene es el " +"incremento del peso. Podés rotar el riel para ponerla bajo el cañón." #: lang/json/gunmod_from_json.py msgid "mana laser sight (underbarrel)" msgid_plural "mana laser sights (underbarrel)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mirilla láser de maná (bajocañón)" +msgstr[1] "mirillas láser de maná (bajocañón)" #: lang/json/gunmod_from_json.py msgid "" @@ -127969,18 +130582,25 @@ msgid "" "acquisition. Aside from increased weight, there are no drawbacks. You can " "rotate the attachment rail to fit on the rail." msgstr "" +"Es una pequeña mira láser que usa luz a través de un cristal de maná, que se" +" monta sobre el riel de accesorios del arma de fuego para mejorar la " +"facilidad y velocidad para apuntar. La única desventaja que tiene es el " +"incremento del peso. Podés rotar el riel para ponerla sobre el riel." #: lang/json/gunmod_from_json.py msgid "mana dot sight" msgid_plural "mana dot sights" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mirilla de punto de maná" +msgstr[1] "mirillas de punto de maná" #: lang/json/gunmod_from_json.py msgid "" "Adds a blue dot optic made from crystallized mana to the top of your gun, " "replacing the iron sights. Increases accuracy and weight." msgstr "" +"Agrega un punto azul óptico hecho de maná cristalizado a la parte superior " +"del arma, reemplazando la mirilla metálica del arma. Incrementa la precisión" +" y el peso." #: lang/json/harvest_from_json.py msgid "You gut and fillet the fish" @@ -127998,6 +130618,14 @@ msgstr "" "Buscás cualquier pedazo de biónico rescatable que pueda haber en este " "experimento fallido" +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "" +"Buscás cualquier pedazo rescatable que pueda quedar en este monstruo de " +"metal y carne" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -128016,15 +130644,17 @@ msgstr "" #: lang/json/harvest_from_json.py msgid "" -msgstr "" +msgstr "" #: lang/json/harvest_from_json.py msgid "You laboriously dissect the colossal insect. " msgstr "" +"Con mucho trabajo lográs diseccionar el gigantesco insecto. " +"" #: lang/json/harvest_from_json.py msgid "" -msgstr "" +msgstr "" #: lang/json/harvest_from_json.py msgid "" @@ -128033,6 +130663,10 @@ msgid "" " tissue sacs that appear to be floating, which doesn't fit with what you " "know about real bees." msgstr "" +"Lo que parece ser pelo de insecto en la quitina de esta criatura se parece " +"más a pequeñas plumas cuando las cortás. Adentro hay un grupo de sacos " +"similares a burbujas que parecen estar flotando, lo que no se ajusta a tu " +"conocimiento sobre abejas reales." #: lang/json/harvest_from_json.py msgid "" @@ -128041,6 +130675,10 @@ msgid "" "tissue sacs that appear to be floating, which doesn't fit with what you know" " about real wasps." msgstr "" +"Hay una membrana similar a la piel, un poco peluda, cubierta de vasos " +"sanguíneos debajo de la quitina de esta criatura. Adentro hay un grupo de " +"sacos similares a burbujas que parecen estar flotando, lo que no se ajusta a" +" tu conocimiento sobre avispas reales." #: lang/json/harvest_from_json.py msgid "You laboriously hack and dig through the remains of the fungal mass." @@ -130687,10 +133325,6 @@ msgstr "Escribir algo" msgid "Teleport yourself" msgstr "Teletransportarse" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "Extinguir fuego" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "Secarse/limpiarse" @@ -131141,11 +133775,13 @@ msgid "" "This gear requires careful balance to use. Being hit while wearing it could " "make you fall down." msgstr "" +"Este equipo necesita un equilibrio cuidadoso para ser usado. Ser golpeado " +"mientras se utiliza te podría hacer caer." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This item can be used to communicate with radio waves." -msgstr "" +msgstr "Este objeto puede ser usado para comunicarse mediante ondas de radio." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131153,11 +133789,14 @@ msgid "" "This item can be used to pick locks with zero " "effort." msgstr "" +"Este objeto puede ser usado para abrir cerraduras sin " +"ningún esfuerzo." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This clothing is designed to keep you dry in the rain." msgstr "" +"Esta ropa está diseñada para mantenerte seco bajo la lluvia." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131165,6 +133804,8 @@ msgid "" "It seems partially intangible, and can occupy the same space as" " other things when worn." msgstr "" +"Parece parcialmente intangible, y puede ocupar el mismo espacio" +" que otras cosas cuando se lleva puesto." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131249,7 +133890,7 @@ msgstr "" #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This item can be worn simultaneously with power armor." -msgstr "" +msgstr "Este objeto puede ser usado simultáneamente con la armadura de poder." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131285,6 +133926,8 @@ msgid "" "This gear has certain parts padded with steel to increase " "protection with moderate increase to encumbrance." msgstr "" +"Este equipo tiene algunas partes acolchadas con acero para incrementar" +" la protección pero con un leve aumento de incomodidad." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131312,12 +133955,12 @@ msgstr "Este objeto tiene una receta de nanofabricador." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This bionic is faulty." -msgstr "" +msgstr "Este biónico está defectuoso." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This bionic provides power." -msgstr "" +msgstr "Este biónico provee energía." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131330,6 +133973,8 @@ msgid "" "This food is unappetizing in a way that can't be covered up " "by most cooking." msgstr "" +"Esta comida es poco apetecible de tal manera que su sabor no" +" puede ser cubierto por otra comida." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131337,6 +133982,8 @@ msgid "" "This food is raw, and will be more nutritious if " "cooked." msgstr "" +"Esta comida está cruda, y será más nutritiva si se" +" la cocina." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131394,6 +134041,8 @@ msgid "" "You can 'e'xamine the tile to access the controls, or use the vehicle " "control key (default '^')." msgstr "" +"Podés 'e'xaminar el espacio para acceder a los controles, o usar la tecla " +"para controlar vehículos (por defecto '^')." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131401,6 +134050,9 @@ msgid "" "With a seat or saddle, you drive from here. You can 'e'xamine the tile to " "access the controls, or use the vehicle control key (default '^')." msgstr "" +"Manejás desde acá con un asiento o una montura. Podés 'e'xaminar el espacio " +"para acceder a los controles o usar la tecla para controlar vehículos (por " +"defecto '^')." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -131545,12 +134197,12 @@ msgstr "" #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This has a flat surface. It would be a nice place to eat." -msgstr "" +msgstr "Esto tiene una superficie plana. Sería un buen lugar para comer." #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "You can craft here." -msgstr "" +msgstr "Podés fabricar acá." #: lang/json/keybinding_from_json.py src/input.cpp src/messages.cpp msgid "Scroll up" @@ -131638,15 +134290,15 @@ msgstr "Marcar objeto seleccionado" #: lang/json/keybinding_from_json.py msgid "Enable auto note for map extra" -msgstr "" +msgstr "Activar noto automática para mapa" #: lang/json/keybinding_from_json.py msgid "Toggle auto notes option" -msgstr "" +msgstr "Cambiar opción de auto notas" #: lang/json/keybinding_from_json.py msgid "Disable auto note for map extra" -msgstr "" +msgstr "Desactivar noto automática para mapa" #: lang/json/keybinding_from_json.py msgid "Add rule" @@ -131706,11 +134358,11 @@ msgstr "Elegir armadura para mover" #: lang/json/keybinding_from_json.py msgid "Select panel for moving" -msgstr "" +msgstr "Elegir panel para mover" #: lang/json/keybinding_from_json.py msgid "Toggle panel off" -msgstr "" +msgstr "Desactivar panel" #: lang/json/keybinding_from_json.py msgid "Change side armor is worn on" @@ -131846,11 +134498,11 @@ msgstr "Borrar nota" #: lang/json/keybinding_from_json.py msgid "Edit Note" -msgstr "" +msgstr "Editar Nota" #: lang/json/keybinding_from_json.py msgid "Mark as Dangerous" -msgstr "" +msgstr "Marcar como Peligroso" #: lang/json/keybinding_from_json.py msgid "Create/Edit Note" @@ -131870,11 +134522,11 @@ msgstr "Activar/Desactivar Transparencias" #: lang/json/keybinding_from_json.py msgid "Toggle Land Use Codes" -msgstr "" +msgstr "Cambiar Códigos de Uso en Tierra" #: lang/json/keybinding_from_json.py msgid "Toggle Map Notes" -msgstr "" +msgstr "Cambiar Notas de Mapa" #: lang/json/keybinding_from_json.py msgid "Toggle City Labels" @@ -131918,7 +134570,7 @@ msgstr "Salir" #: lang/json/keybinding_from_json.py msgid "Choose destination" -msgstr "" +msgstr "Elegir destino" #: lang/json/keybinding_from_json.py msgid "Fire Weapon" @@ -131962,7 +134614,7 @@ msgstr "Cambiar Modo de Disparo" #: lang/json/keybinding_from_json.py msgid "Toggle turret lines" -msgstr "" +msgstr "Cambiar líneas de torreta" #: lang/json/keybinding_from_json.py msgid "Toggle Snap to Target" @@ -131970,7 +134622,7 @@ msgstr "Activar/Desactivar Saltar a objetivo" #: lang/json/keybinding_from_json.py msgid "Toggle moving view / cursor" -msgstr "" +msgstr "Cambiar cursor / vista de movimiento" #: lang/json/keybinding_from_json.py msgid "Select" @@ -132038,7 +134690,7 @@ msgstr "Recrear personaje aleatorio y escenario" #: lang/json/keybinding_from_json.py msgid "Pick random character description" -msgstr "" +msgstr "Seleccionar descripción aleatoria de personaje" #: lang/json/keybinding_from_json.py msgid "Choose character start location" @@ -132052,6 +134704,14 @@ msgstr "Salir de la pantalla de personaje nuevo" msgid "Toggle sorting order" msgstr "Cambiar orden" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "Profesión aleatoria" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "Escenario aleatorio" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "Desplazar arriba descripción" @@ -132154,7 +134814,7 @@ msgstr "Cambiar tamaño" #: lang/json/keybinding_from_json.py msgid "To start" -msgstr "" +msgstr "Para arrancar" #: lang/json/keybinding_from_json.py msgid "Swap origin and target" @@ -132178,11 +134838,11 @@ msgstr "Modificar campos" #: lang/json/keybinding_from_json.py msgid "Edit terrain" -msgstr "" +msgstr "Modificar terreno" #: lang/json/keybinding_from_json.py msgid "Edit furniture" -msgstr "" +msgstr "Modificar mueble" #: lang/json/keybinding_from_json.py msgid "Edit overmap / mapgen" @@ -132222,7 +134882,7 @@ msgstr "Activar/Desactivar Modo de selección de categoría" #: lang/json/keybinding_from_json.py msgid "Toggle inventory view to show item categories" -msgstr "" +msgstr "Cambiar viste de inventario para mostrar categorías" #: lang/json/keybinding_from_json.py msgid "Set item filter" @@ -132230,7 +134890,7 @@ msgstr "Establecer filtro de objetos" #: lang/json/keybinding_from_json.py msgid "Toggle item as favorite" -msgstr "" +msgstr "Hacer o sacar objeto como favorito" #: lang/json/keybinding_from_json.py msgid "Toggle activate/examine" @@ -132238,11 +134898,11 @@ msgstr "Activar/Desactivar Examinar" #: lang/json/keybinding_from_json.py msgid "Toggle safe fuel mod" -msgstr "" +msgstr "Cambiar mod de combustible seguro" #: lang/json/keybinding_from_json.py msgid "Toggle auto start mod" -msgstr "" +msgstr "Cambiar mod de auto arrancar" #: lang/json/keybinding_from_json.py src/martialarts.cpp msgid "Pause" @@ -132294,11 +134954,11 @@ msgstr "Inventario avanzado" #: lang/json/keybinding_from_json.py msgid "Pick up Nearby Item(s)" -msgstr "" +msgstr "Agarrar objeto(s) cercanos" #: lang/json/keybinding_from_json.py msgid "Pickup Item(s) at Player Feet" -msgstr "" +msgstr "Agarrar objeto(s) bajo los pies" #: lang/json/keybinding_from_json.py msgid "Grab something nearby" @@ -132326,7 +134986,7 @@ msgstr "Mirar alrededor" #: lang/json/keybinding_from_json.py msgid "Toggle thief mode" -msgstr "" +msgstr "Cambiar modo ladrón" #: lang/json/keybinding_from_json.py msgid "Peek Around Corners" @@ -132370,7 +135030,7 @@ msgstr "Sacarse objeto puesto" #: lang/json/keybinding_from_json.py msgid "Consume Item Menu" -msgstr "" +msgstr "Menú de Consumir Objeto" #: lang/json/keybinding_from_json.py msgid "Wield" @@ -132382,7 +135042,7 @@ msgstr "Elegir Estilo de Artes Marciales" #: lang/json/keybinding_from_json.py msgid "Reload Weapons" -msgstr "" +msgstr "Recargar Armas" #: lang/json/keybinding_from_json.py msgid "Reload Wielded Item" @@ -132452,13 +135112,17 @@ msgstr "Desarmar objetos" msgid "Sleep" msgstr "Dormir" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "Ejercicio" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "Manejar vehículo" #: lang/json/keybinding_from_json.py msgid "Toggle Auto Travel Mode" -msgstr "" +msgstr "Cambiar Modo de Auto Viaje" #: lang/json/keybinding_from_json.py msgid "Toggle Safe Mode" @@ -132490,7 +135154,7 @@ msgstr "Ver Mapa" #: lang/json/keybinding_from_json.py msgid "Look at the sky" -msgstr "" +msgstr "Mirar el cielo" #: lang/json/keybinding_from_json.py msgid "View Factions" @@ -132498,7 +135162,7 @@ msgstr "Ver Bandos" #: lang/json/keybinding_from_json.py msgid "View Achievements, Scores, and Kills" -msgstr "" +msgstr "Ver Logros, Puntos y Muertes" #: lang/json/keybinding_from_json.py msgid "View Morale" @@ -132534,23 +135198,23 @@ msgstr "Ver Mapa de Olor" #: lang/json/keybinding_from_json.py msgid "View Scent Type" -msgstr "" +msgstr "Ver Tipo de Olor" #: lang/json/keybinding_from_json.py msgid "View Temperature Map" -msgstr "" +msgstr "Ver Mapa de Temperatura" #: lang/json/keybinding_from_json.py msgid "View Visibility Map" -msgstr "" +msgstr "Ver Mapa de Visibilidad" #: lang/json/keybinding_from_json.py msgid "View Lighting Map" -msgstr "" +msgstr "Ver Mapa de Luz" #: lang/json/keybinding_from_json.py msgid "View Radiation Map" -msgstr "" +msgstr "Ver Mapa de Radiació" #: lang/json/keybinding_from_json.py msgid "Switch Sidebar Style" @@ -132562,15 +135226,15 @@ msgstr "Act./Desact. Pantalla completa" #: lang/json/keybinding_from_json.py msgid "Toggle Minimap" -msgstr "" +msgstr "Mostrar/Ocultar Minimapa" #: lang/json/keybinding_from_json.py msgid "Toggle Panel Admin" -msgstr "" +msgstr "Mostrar/Ocultar Panel de Administrador" #: lang/json/keybinding_from_json.py msgid "Reload Item" -msgstr "" +msgstr "Recargar objeto" #: lang/json/keybinding_from_json.py msgid "Reload Tileset" @@ -132594,7 +135258,7 @@ msgstr "Activar/Desactivar auto recolectar" #: lang/json/keybinding_from_json.py msgid "Toggle Auto Pickup" -msgstr "" +msgstr "Cambiar Auto Agarrar" #: lang/json/keybinding_from_json.py msgid "Action Menu" @@ -132674,27 +135338,27 @@ msgstr "Mods Activos de Mundo" #: lang/json/keybinding_from_json.py msgid "Cycle move mode (run/walk/crouch)" -msgstr "" +msgstr "Cambiar modo de movimiento (correr/caminar/agacharse)" #: lang/json/keybinding_from_json.py msgid "Reset Movement to Walk" -msgstr "" +msgstr "Volver a Caminar" #: lang/json/keybinding_from_json.py msgid "Toggle Run" -msgstr "" +msgstr "Empezar a Correr" #: lang/json/keybinding_from_json.py msgid "Toggle Crouch" -msgstr "" +msgstr "Empezar a Agacharse" #: lang/json/keybinding_from_json.py msgid "Movement Mode Menu" -msgstr "" +msgstr "Menú de Modo de Movimiento" #: lang/json/keybinding_from_json.py msgid "Spellcasting" -msgstr "" +msgstr "Hechizos" #: lang/json/keybinding_from_json.py src/game_inventory.cpp msgid "Compare" @@ -132769,7 +135433,7 @@ msgstr "Agregar atajo de teclado global" #: lang/json/keybinding_from_json.py msgid "Execute action keybinding" -msgstr "" +msgstr "Tecla de ejecutar acción" #: lang/json/keybinding_from_json.py msgid "Add zone" @@ -132845,7 +135509,7 @@ msgstr "Mover todos los objetos" #: lang/json/keybinding_from_json.py msgid "Mark/unmark non-favorite items in multidrop menu" -msgstr "" +msgstr "Marcar/Desmarcar no favoritos en menú de soltar varios objetos" #: lang/json/keybinding_from_json.py msgid "Select items @ North-West" @@ -132925,18 +135589,18 @@ msgstr "Cargar plantilla de color" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "Sí" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "No" #: lang/json/keybinding_from_json.py msgid "Quit" -msgstr "" +msgstr "Salir" #: lang/json/keybinding_from_json.py msgid "Ignore further distractions and finish" @@ -132956,19 +135620,19 @@ msgstr "Cancelar" #: lang/json/keybinding_from_json.py msgid "Describe creature" -msgstr "" +msgstr "Describir criatura" #: lang/json/keybinding_from_json.py msgid "Describe furniture" -msgstr "" +msgstr "Describir mueble" #: lang/json/keybinding_from_json.py msgid "Describe terrain" -msgstr "" +msgstr "Describir terreno" #: lang/json/keybinding_from_json.py msgid "Switch lists" -msgstr "" +msgstr "Cambiar listas" #: lang/json/keybinding_from_json.py src/action.cpp msgid "Back" @@ -132976,19 +135640,19 @@ msgstr "Volver" #: lang/json/keybinding_from_json.py msgid "More" -msgstr "" +msgstr "Más" #: lang/json/keybinding_from_json.py msgid "Examine item" -msgstr "" +msgstr "Examinar objeto" #: lang/json/keybinding_from_json.py msgid "Cancel trading" -msgstr "" +msgstr "Cancelar negociación" #: lang/json/keybinding_from_json.py src/player_display.cpp msgid "Change profession name" -msgstr "" +msgstr "Cambiar nombre de profesión" #: lang/json/keybinding_from_json.py src/vehicle_use.cpp src/vehicle_use.cpp msgid "Control multiple electronics" @@ -133024,7 +135688,7 @@ msgstr "Luces atómicas" #: lang/json/keybinding_from_json.py src/vehicle_use.cpp msgid "Control autopilot" -msgstr "" +msgstr "Controlar piloto automático" #: lang/json/keybinding_from_json.py msgid "Toggle camera system" @@ -133060,11 +135724,11 @@ msgstr "Activar/Desactivar freezer" #: lang/json/keybinding_from_json.py msgid "Toggle space heater" -msgstr "" +msgstr "Prender/Apagar caloventor" #: lang/json/keybinding_from_json.py msgid "Toggle cooler" -msgstr "" +msgstr "Prender/Apagar refrigerador" #: lang/json/keybinding_from_json.py msgid "Toggle headlights" @@ -133145,88 +135809,88 @@ msgstr "Nada" #. ~ Description for {'str': 'Nothing'} #: lang/json/map_extra_from_json.py msgid "Nothing of interest is here." -msgstr "" +msgstr "Acá no hay nada de interés." #: lang/json/map_extra_from_json.py msgid "Crater" -msgstr "" +msgstr "Cráter" #. ~ Description for {'str': 'Crater'} #: lang/json/map_extra_from_json.py msgid "There is a crater here." -msgstr "" +msgstr "Acá hay un cráter." #: lang/json/map_extra_from_json.py msgid "College Kids" -msgstr "" +msgstr "Estudiantes" #. ~ Description for {'str': 'College Kids'} #: lang/json/map_extra_from_json.py msgid "Several corpses of college kids are here." -msgstr "" +msgstr "Acá hay varios cadáveres de niños estudiantes." #: lang/json/map_extra_from_json.py msgid "Drug Deal" -msgstr "" +msgstr "Transacción de Droga" #. ~ Description for {'str': 'Drug Deal'} #: lang/json/map_extra_from_json.py msgid "Several corpses of drug dealers are here." -msgstr "" +msgstr "Acá hay varios cadáveres de narcotraficantes." #: lang/json/map_extra_from_json.py msgid "Roadworks" -msgstr "" +msgstr "Obras viales" #. ~ Description for {'str': 'Roadworks'} #: lang/json/map_extra_from_json.py msgid "Roadworks are here." -msgstr "" +msgstr "Acá hay unas obras sobre la calle." #: lang/json/map_extra_from_json.py msgid "Road Mayhem" -msgstr "" +msgstr "Caos en la Calle" #. ~ Description for {'str': 'Road Mayhem'} #: lang/json/map_extra_from_json.py msgid "Road mayhem is here." -msgstr "" +msgstr "Acá hay algún quilombo en la calle." #: lang/json/map_extra_from_json.py msgid "Roadblock (Military)" -msgstr "" +msgstr "Barricada (Militar)" #. ~ Description for {'str': 'Roadblock (Military)'} #: lang/json/map_extra_from_json.py msgid "This road is blocked by military." -msgstr "" +msgstr "Acá la calle está bloqueada por los militares." #: lang/json/map_extra_from_json.py msgid "Roadblock (Bandits)" -msgstr "" +msgstr "Barricada (Bandidos)" #. ~ Description for {'str': 'Roadblock (Bandits)'} #: lang/json/map_extra_from_json.py msgid "This road is blocked by bandits." -msgstr "" +msgstr "Acá la calle está bloqueada por los bandidos." #: lang/json/map_extra_from_json.py msgid "Minefield" -msgstr "" +msgstr "Campo Minado" #. ~ Description for {'str': 'Minefield'} #: lang/json/map_extra_from_json.py msgid "Mines are scattered here." -msgstr "" +msgstr "Acá hay minas plantadas." #: lang/json/map_extra_from_json.py msgid "Supply Drop" -msgstr "" +msgstr "Suministros" #. ~ Description for {'str': 'Supply Drop'} #: lang/json/map_extra_from_json.py msgid "Several supply crates were dropped here." -msgstr "" +msgstr "Hay varias cajas con suministros que cayeron acá." #: lang/json/map_extra_from_json.py msgctxt "Map Extra" @@ -133236,7 +135900,7 @@ msgstr "Militar" #. ~ Description for {'str': 'Military', 'ctxt': 'Map Extra'} #: lang/json/map_extra_from_json.py msgid "Several corpses of soldiers are here." -msgstr "" +msgstr "Acá hay varios cadáveres de soldados." #: lang/json/map_extra_from_json.py msgid "Helicopter Crash" @@ -133245,52 +135909,52 @@ msgstr "Helicóptero Estrellado" #. ~ Description for {'str': 'Helicopter Crash'} #: lang/json/map_extra_from_json.py msgid "Helicopter crashed here." -msgstr "" +msgstr "Acá se cayó un helicóptero." #: lang/json/map_extra_from_json.py msgid "Scientists" -msgstr "" +msgstr "Científicos" #. ~ Description for {'str': 'Scientists'} #: lang/json/map_extra_from_json.py msgid "Several corpses of scientists are here." -msgstr "" +msgstr "Acá hay varios cadáveres de científicos." #: lang/json/map_extra_from_json.py msgid "Portal" -msgstr "" +msgstr "Portal" #. ~ Description for {'str': 'Portal'} #: lang/json/map_extra_from_json.py msgid "Portal is here." -msgstr "" +msgstr "Acá hay un portal." #: lang/json/map_extra_from_json.py msgid "Portal In" -msgstr "" +msgstr "Portal de Entrada" #. ~ Description for {'str': 'Portal In'} #: lang/json/map_extra_from_json.py msgid "Another portal is here." -msgstr "" +msgstr "Acá hay otro portal." #: lang/json/map_extra_from_json.py msgid "Spider Nest" -msgstr "" +msgstr "Nido de Arañas" #. ~ Description for {'str': 'Spider Nest'} #: lang/json/map_extra_from_json.py msgid "Spider nest is here." -msgstr "" +msgstr "Acá hay un nido de arañas." #: lang/json/map_extra_from_json.py msgid "Wasp Nest" -msgstr "" +msgstr "Nido de Avispas" #. ~ Description for {'str': 'Wasp Nest'} #: lang/json/map_extra_from_json.py msgid "Wasp nest is here." -msgstr "" +msgstr "Acá hay un nido de avispas." #: lang/json/map_extra_from_json.py src/gamemode_defense.cpp msgid "Spiders" @@ -133300,179 +135964,182 @@ msgstr "Arañas" #: lang/json/map_extra_from_json.py msgid "This area is covered with webs. Probably spiders are nearby" msgstr "" +"Este área está cubierta de telarañas. Probablemente haya arañas cerca." #. ~ Description for {'str': 'Shia LaBeouf'} #: lang/json/map_extra_from_json.py msgid "Cannibal is nearby." -msgstr "" +msgstr "Hay un caníbal cerca." #: lang/json/map_extra_from_json.py msgid "Jabberwock" -msgstr "" +msgstr "Jabberwock" #. ~ Description for {'str': 'Jabberwock'} #: lang/json/map_extra_from_json.py msgid "Jabberwock is nearby." -msgstr "" +msgstr "Hay un jabberwock cerca." #: lang/json/map_extra_from_json.py msgid "Grove" -msgstr "" +msgstr "Arboleda" #. ~ Description for {'str': 'Grove'} #: lang/json/map_extra_from_json.py msgid "This area is covered with a single type of trees." -msgstr "" +msgstr "Esta área está cubierta con un solo tipo de árboles." #: lang/json/map_extra_from_json.py msgid "Shrubberry" -msgstr "" +msgstr "Arbustos" #. ~ Description for {'str': 'Shrubberry'} #: lang/json/map_extra_from_json.py msgid "This area is covered with a single type of shrubs." -msgstr "" +msgstr "Esta área está cubierta con un solo tipo de arbusto." #: lang/json/map_extra_from_json.py msgid "Clearcut" -msgstr "" +msgstr "Claro" #. ~ Description for {'str': 'Clearcut'} #: lang/json/map_extra_from_json.py msgid "Most trees in this area were uniformly cut down." -msgstr "" +msgstr "En esta área la mayoría de los árboles fueron talados." #: lang/json/map_extra_from_json.py msgid "Pond" -msgstr "" +msgstr "Charco" #. ~ Description for {'str': 'Pond'} #: lang/json/map_extra_from_json.py msgid "Small pond is here." -msgstr "" +msgstr "Acá hay un pequeño charco." #: lang/json/map_extra_from_json.py msgid "Stand of trees" -msgstr "" +msgstr "Línea de árboles" #. ~ Description for {'str': 'Stand of trees'} #: lang/json/map_extra_from_json.py msgid "A copse of trees." -msgstr "" +msgstr "Es un bosquecillo de árboles." #: lang/json/map_extra_from_json.py msgid "Tall grass" -msgstr "" +msgstr "Pasto alto" #. ~ Description for {'str': 'Tall grass'} #: lang/json/map_extra_from_json.py msgid "A meadow of tall grass." -msgstr "" +msgstr "Es un campo con pasto alto." #: lang/json/map_extra_from_json.py msgid "Derelict shed" -msgstr "" +msgstr "Caseta abandonada" #. ~ Description for {'str': 'Derelict shed'} #: lang/json/map_extra_from_json.py msgid "A collapsed shed." -msgstr "" +msgstr "Es una caseta medio derrumbada." #: lang/json/map_extra_from_json.py msgid "Clay Deposit" -msgstr "" +msgstr "Depósito de Arcilla" #. ~ Description for {'str': 'Clay Deposit'} #: lang/json/map_extra_from_json.py msgid "Small clay deposit is here." -msgstr "" +msgstr "Acá hay un pequeño depósito de arcilla." #: lang/json/map_extra_from_json.py msgid "Dead Vegetation" -msgstr "" +msgstr "Vegetación Muerta" #. ~ Description for {'str': 'Dead Vegetation'} #. ~ Description for {'str': 'Dead Vegetation (Point)'} #: lang/json/map_extra_from_json.py msgid "Dead vegetation is here." -msgstr "" +msgstr "Acá hay vegetación muerta." #: lang/json/map_extra_from_json.py msgid "Dead Vegetation (Point)" -msgstr "" +msgstr "Vegetación Muerta (Punto)" #: lang/json/map_extra_from_json.py msgid "Burned Ground" -msgstr "" +msgstr "Suelo Quemado" #. ~ Description for {'str': 'Burned Ground'} #. ~ Description for {'str': 'Burned Ground (Point)'} #: lang/json/map_extra_from_json.py msgid "Burned ground is here." -msgstr "" +msgstr "Acá está el suelo quemado." #: lang/json/map_extra_from_json.py msgid "Burned Ground (Point)" -msgstr "" +msgstr "Suelo Quemado (Punto)" #: lang/json/map_extra_from_json.py msgid "Marloss Pilgrimage" -msgstr "" +msgstr "Peregrinación Marloss" #. ~ Description for {'str': 'Marloss Pilgrimage'} #: lang/json/map_extra_from_json.py msgid "Marloss Pilgrimage is here." -msgstr "" +msgstr "Acá hay una peregrinación marloss." #: lang/json/map_extra_from_json.py msgid "Casings" -msgstr "" +msgstr "Vainas" #. ~ Description for {'str': 'Casings'} #: lang/json/map_extra_from_json.py msgid "Several spent casings are here." -msgstr "" +msgstr "Acá hay varias vainas servidas." #: lang/json/map_extra_from_json.py msgid "Looters" -msgstr "" +msgstr "Saqueadores" #. ~ Description for {'str': 'Looters'} #: lang/json/map_extra_from_json.py msgid "Some looters gathering everything not nailed down." -msgstr "" +msgstr "Hay unos saqueadores que se están llevando todo lo que pueden." #: lang/json/map_extra_from_json.py msgid "Corpses" -msgstr "" +msgstr "Cadáveres" #. ~ Description for {'str': 'Corpses'} #: lang/json/map_extra_from_json.py msgid "Some unfortunates from the billions lost in the Cataclysm." msgstr "" +"Algunos de los desafortunados entre los miles de millones perdidos en el " +"Cataclismo." #. ~ Description for {'str': 'Wasp Nest'} #: lang/json/map_extra_from_json.py msgid "A wasp nest." -msgstr "" +msgstr "Es un nido de avispas." #: lang/json/map_extra_from_json.py msgid "Dermatik Nest" -msgstr "" +msgstr "Nido de Dermatik" #. ~ Description for {'str': 'Dermatik Nest'} #: lang/json/map_extra_from_json.py msgid "A dermatik nest." -msgstr "" +msgstr "Es un nido de dermatiks." #: lang/json/map_extra_from_json.py lang/json/vehicle_from_json.py msgid "Prison Bus" -msgstr "" +msgstr "Colectivo de Cárcel" #. ~ Description for {'str': 'Prison Bus'} #: lang/json/map_extra_from_json.py msgid "A prison bus." -msgstr "" +msgstr "Es un colectivo para trasladar presos." #: lang/json/map_extra_from_json.py msgid "Mass Grave" @@ -133481,34 +136148,34 @@ msgstr "Fosa Común" #. ~ Description for {'str': 'Mass Grave'} #: lang/json/map_extra_from_json.py msgid "A mass grave." -msgstr "" +msgstr "Es una fosa común." #: lang/json/map_extra_from_json.py msgid "Grave" -msgstr "" +msgstr "Tumba" #. ~ Description for {'str': 'Grave'} #: lang/json/map_extra_from_json.py msgid "A grave." -msgstr "" +msgstr "Es una tumba." #: lang/json/map_extra_from_json.py msgid "Zombie Trap" -msgstr "" +msgstr "Trampa Zombi" #. ~ Description for {'str': 'Zombie Trap'} #: lang/json/map_extra_from_json.py msgid "Zombie trap." -msgstr "" +msgstr "Es una trampa para zombi." #: lang/json/map_extra_from_json.py msgid "Reed" -msgstr "" +msgstr "Junco" #. ~ Description for {'str': 'Reed'} #: lang/json/map_extra_from_json.py msgid "Water vegetation." -msgstr "" +msgstr "Es vegetación en el agua." #. ~ Computer name #: lang/json/mapgen_from_json.py @@ -133530,6 +136197,8 @@ msgstr "Banco Computarizado Consolidado de Hacienda de Alta Seguridad" msgid "" "ERROR! Access denied! Unauthorized access will be met with lethal force!" msgstr "" +"¡ERROR! ¡Acceso denegado! ¡El acceso no autorizado será castigado con fuerza" +" letal!" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -133634,7 +136303,7 @@ msgstr " Zona de Basura" #. ~ Sign #: lang/json/mapgen_from_json.py msgid "St. John Dairy. 555-0199 Daily Farm Tours" -msgstr "" +msgstr "Granja San Juan. 555-0199 Visitas a la Granja" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -133905,7 +136574,7 @@ msgstr "Aviso de Seguridad [1057]" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Security Reminder [1058]" -msgstr "" +msgstr "Aviso de Seguridad [1058]" #. ~ Computer option #: lang/json/mapgen_from_json.py @@ -133950,87 +136619,87 @@ msgstr "Analizar sangre" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Irradiation Facility Operation Console" -msgstr "" +msgstr "Consola de Operación de Irradiación" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Uplink to mainframe servers" -msgstr "" +msgstr "Enlace a servidores centrales" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Cycle conveyor belt" -msgstr "" +msgstr "Cambiar cinta transportadora" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Toggle safety shutters" -msgstr "" +msgstr "Cambiar obturadores de seguridad" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Probe radiation levels" -msgstr "" +msgstr "Sondear niveles de radiación" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Commence irradiation sequence" -msgstr "" +msgstr "Iniciar secuencia de irradiación" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "[Maintenance] Extract radiation core" -msgstr "" +msgstr "[Mantenimiento] Extraer núcleo de radiación" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Hazardous Materials Containment" -msgstr "" +msgstr "Contención de Materiales Peligrosos" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Access containment zone" -msgstr "" +msgstr "Acceder zona de contención" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Geiger counter readout" -msgstr "" +msgstr "Lectura de contador geiger" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Security Access Terminal" -msgstr "" +msgstr "Terminal de Acceso de Seguridad" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Open doors" -msgstr "" +msgstr "Abrir puertas" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Access security locker" -msgstr "" +msgstr "Acceder casillero de seguridad" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Power Management" -msgstr "" +msgstr "Administración de Energía" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "External power management" -msgstr "" +msgstr "Administración de energía externa" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Backup power management" -msgstr "" +msgstr "Administración de energía de reserva" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Run emergency auto-diagnostic" -msgstr "" +msgstr "Iniciar autodiagnóstico de emergencia" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134199,7 +136868,7 @@ msgstr "funciona." #. ~ Sign #: lang/json/mapgen_from_json.py msgid "Restricted area! Violators will be shot!" -msgstr "" +msgstr "¡Área restringida! ¡Se disparará contra los infractores!" #. ~ Computer name #: lang/json/mapgen_from_json.py @@ -134223,7 +136892,7 @@ msgstr "" #. ~ Sign #: lang/json/mapgen_from_json.py msgid "Travelier MOTEL" -msgstr "" +msgstr "HOTEL Viajero" #. ~ Computer name #: lang/json/mapgen_from_json.py @@ -134343,17 +137012,17 @@ msgstr "¡NO tirarse de cabeza!" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Armory Access" -msgstr "" +msgstr "Acceso a Armería" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Open Armory Door" -msgstr "" +msgstr "Abrir Puerta de Armería" #. ~ Sign #: lang/json/mapgen_from_json.py msgid "Private property. No trespassing!" -msgstr "" +msgstr "Propiedad privada. ¡No pasar!" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134449,7 +137118,7 @@ msgstr "el nombre ya no está pero quedó el slogan: 'Te vamos a reparar todo'" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "EnviroCom OS v2.03 - Basement Access" -msgstr "" +msgstr "EnviroCom OS v2.03 - Acceso Sótano" #. ~ Computer option #: lang/json/mapgen_from_json.py @@ -134459,12 +137128,12 @@ msgstr "Abrir escaleras" #. ~ Sign #: lang/json/mapgen_from_json.py msgid "Authorized personnel only" -msgstr "" +msgstr "Solo para personal autorizado" #. ~ Sign #: lang/json/mapgen_from_json.py msgid " sewage treatment plant" -msgstr "" +msgstr " planta de tratamiento de aguas cloacales" #. ~ Computer name #: lang/json/mapgen_from_json.py @@ -134561,7 +137230,7 @@ msgstr "Instalar Modificación de Repetidor" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Browse Audio Archive" -msgstr "" +msgstr "Revisar Archivo de Audio" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134576,7 +137245,7 @@ msgstr "Casa de Té La Hoja Verde" #. ~ Sign #: lang/json/mapgen_from_json.py msgid "RESTRICTED AREA! AUTHORIZED PERSONNEL ONLY" -msgstr "" +msgstr "¡ÁREA RESTRINGIDA! SOLO PERSONAL AUTORIZADO" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134701,7 +137370,7 @@ msgstr "DESTRABAR ALMACENAMIENTO" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Prototype DARPA-713 AUTHORIZED PILOTS ONLY" -msgstr "" +msgstr "Prototype DARPA-713 SOLO PILOTOS AUTORIZADOS" #. ~ Computer name #: lang/json/mapgen_from_json.py @@ -134746,12 +137415,12 @@ msgstr "Ver Rutas de Subte" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Security Terminal" -msgstr "" +msgstr "Terminal de Seguridad" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "UNLOCK SECURITY DOORS" -msgstr "" +msgstr "ABRIR PUERTAS DE SEGURIDAD" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134762,6 +137431,11 @@ msgid "" "\n" "Regulation EX-127 applies." msgstr "" +"Peligro:\n" +"Sala dimensionalmente inestable.\n" +"No pasar la línea amarilla.\n" +"\n" +"Se aplica la regulación EX-127." #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134772,16 +137446,21 @@ msgid "" "\n" "Ration VC+983 appliance." msgstr "" +"Pegrilo;\n" +"Sala dimen inesta sional.\n" +"Pasar la amínea linilla.\n" +"\n" +"Aplique VC+983 ración." #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Surgery room computer" -msgstr "" +msgstr "Computadora sala de cirugía" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Open Storage Chambers" -msgstr "" +msgstr "Abrir Cámaras de Almacenamiento" #. ~ Computer option #: lang/json/mapgen_from_json.py src/mapgen.cpp src/mapgen.cpp @@ -134791,32 +137470,32 @@ msgstr "Manifiesto" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Medical Storage Access" -msgstr "" +msgstr "Acceso Almacenamiento Médico" #. ~ Computer option #: lang/json/mapgen_from_json.py msgid "Open Storage Door" -msgstr "" +msgstr "Abrir Puerta de Almacenamiento" #. ~ Sign #: lang/json/mapgen_from_json.py msgid "DANGER MINEFIELD" -msgstr "" +msgstr "PELIGRO CAMPO MINADO" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Vehicle Testing Track" -msgstr "" +msgstr "Pista de Prueba de Vehículo" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Weapons Testing Range" -msgstr "" +msgstr "Prueba de Rango de Armas" #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "Armory Entrance" -msgstr "" +msgstr "Entrada Armería" #. ~ Sign #: lang/json/mapgen_from_json.py @@ -134824,11 +137503,13 @@ msgid "" "Whately Family Mortuary Services. Serving New England for three hundred " "years.'" msgstr "" +"Servicios Funerarios Familia Whately. Sirviendo a New England por " +"trescientos años." #. ~ Computer name #: lang/json/mapgen_from_json.py msgid "DinoLab Operating Theater Controls" -msgstr "" +msgstr "Controles De Operación DinoLab al Teatro" #: lang/json/martial_art_from_json.py msgid "No style" @@ -134842,13 +137523,13 @@ msgstr "No es un arte marcial, es el viejo y conocido pegar piñas y patadas." #. ~ initiate message for martial art '{'str': 'No style'}' #: lang/json/martial_art_from_json.py msgid "You decide to not use any martial arts." -msgstr "" +msgstr "Decidís no usar ninguna arte marcial." #. ~ initiate message for martial art '{'str': 'No style'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s enters a generic combat stance." -msgstr "" +msgstr "%s adopta una postura genérica de combate." #: lang/json/martial_art_from_json.py msgid "Force unarmed" @@ -134866,13 +137547,13 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Force unarmed'}' #: lang/json/martial_art_from_json.py msgid "You force yourself to fight unarmed." -msgstr "" +msgstr "Te forzás a pelear desarmado." #. ~ initiate message for martial art '{'str': 'Force unarmed'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s decides to fight unarmed." -msgstr "" +msgstr "%s decide pelera desarmado." #: lang/json/martial_art_from_json.py msgid "Aikido" @@ -134885,21 +137566,24 @@ msgid "" "injury to the attacker. It uses defensive throws and disarms but lacks " "offensive techniques." msgstr "" +"El aikido es un arte marcial japonés focalizado en la defensa propia y en " +"minimizar el daño hacia el atacante. Utiliza desarmes y tiradas defensivas, " +"pero no tiene técnicas ofensivas." #. ~ initiate message for martial art '{'str': 'Aikido'}' #: lang/json/martial_art_from_json.py msgid "You enter the hamni stance." -msgstr "" +msgstr "Adoptás la postura hamni." #. ~ initiate message for martial art '{'str': 'Aikido'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s changes into a relaxed combat posture." -msgstr "" +msgstr "%s cambia y adopta una postura relajada de combate." #: lang/json/martial_art_from_json.py msgid "Aikido Stance" -msgstr "" +msgstr "Postura de Aikido" #. ~ Description of buff 'Aikido Stance' for martial art '{'str': 'Aikido'}' #: lang/json/martial_art_from_json.py @@ -134909,10 +137593,13 @@ msgid "" "\n" "Blocked damage reduced by 100% of Dexterity." msgstr "" +"Al dejar de lado la ofensiva en favor de la defensa propia, te hacés mejor protegiendo.\n" +"\n" +"El daño bloqueado se reduce un 100% de tu Destreza." #: lang/json/martial_art_from_json.py msgid "Intermediate Aikido" -msgstr "" +msgstr "Aikido Intermedio" #. ~ Description of buff 'Intermediate Aikido' for martial art '{'str': #. 'Aikido'}' @@ -134924,10 +137611,14 @@ msgid "" "Blocked Damage reduced by 100% of Dexterity.\n" "+1 Block attempts, +1 Dodge attempts." msgstr "" +"Un practicante intermedio de aikido puede protegerse contra varios oponentes a la vez.\n" +"\n" +"El daño bloqueado se reduce un 100% de tu Destreza.\n" +"+1 intentos de Bloqueo, +1 intentos de Esquivar." #: lang/json/martial_art_from_json.py msgid "Advanced Aikido" -msgstr "" +msgstr "Aikido Avanzado" #. ~ Description of buff 'Advanced Aikido' for martial art '{'str': 'Aikido'}' #: lang/json/martial_art_from_json.py @@ -134936,6 +137627,9 @@ msgid "" "\n" "+1 Block attempts, +1 Dodge attempts." msgstr "" +"Un practicante avanzado de aikido puede protegerse contra varios oponentes a la vez, más que lo normal.\n" +"\n" +"+1 intentos de Bloqueo, +1 intentos de Esquivar." #: lang/json/martial_art_from_json.py msgid "Boxing" @@ -134948,21 +137642,24 @@ msgid "" "of the Victorian era. Strength reduces blocked damage and moving increase " "dodge skill." msgstr "" +"El deporte del verdadero caballero. El boxeo moderno ha evolucionado desde " +"los combates profesionales de la era victoriana. La fuerza reduce el daño " +"bloqueado y moverse incrementa la habilidad para esquivar." #. ~ initiate message for martial art '{'str': 'Boxing'}' #: lang/json/martial_art_from_json.py msgid "You lower your chin and raise your fists to eye level." -msgstr "" +msgstr "Bajás tu mentón y levantás tus puños al nivel de los ojos." #. ~ initiate message for martial art '{'str': 'Boxing'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s prepares to fight with raised fists." -msgstr "" +msgstr "%s se prepara para pelear levantando los puños." #: lang/json/martial_art_from_json.py msgid "Boxing Stance" -msgstr "" +msgstr "Postura de Boxeo" #. ~ Description of buff 'Boxing Stance' for martial art '{'str': 'Boxing'}' #: lang/json/martial_art_from_json.py @@ -134972,6 +137669,9 @@ msgid "" "\n" "+2 Bash damage, Blocked damge reduced by 50% of Strength." msgstr "" +"Una postura sólida te permite bloquear más daño que lo normal y meter mejores piñas.\n" +"\n" +"+2 daño Golpeante, Daño bloqueado disminuido en 50% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Footwork" @@ -134985,6 +137685,10 @@ msgid "" "+1.0 Dodge skill.\n" "Lasts for 1 turns. Stacks 2 times." msgstr "" +"Te hacés más difícil de recibir golpes al mecerte y zigzaguear mientras te movés.\n" +"\n" +"+1.0 a Esquivar.\n" +"Dura 1 turno. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Counter Chance" @@ -134999,6 +137703,10 @@ msgid "" "+25% Bash damage.\n" "Lasts for 1 turn." msgstr "" +"Ya tuviste tu oportunidad. ¡Ahora golpeá!\n" +"\n" +"+25% daño Golpeante.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Brawling" @@ -135011,21 +137719,24 @@ msgid "" "unarmed or with any weapon to a certain extent. It's not stylish or " "sporting, but it gets the job done." msgstr "" +"Estás acostumbrado a la pelea mano contra pata. Sabés cómo pelear desarmado " +"o con cualquier arma hasta cierto punto. No tiene estilo ni es deportivo, " +"pero funciona bien." #. ~ initiate message for martial art '{'str': 'Brawling'}' #: lang/json/martial_art_from_json.py msgid "You grit your teeth and prepare for a good fight." -msgstr "" +msgstr "Apretás los dientes y te preparás para una buena pelea." #. ~ initiate message for martial art '{'str': 'Brawling'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s gets ready to brawl." -msgstr "" +msgstr "%s se prepara para las piñas." #: lang/json/martial_art_from_json.py msgid "Enhanced Blocking" -msgstr "" +msgstr "Bloqueo Mejorado" #. ~ Description of buff 'Enhanced Blocking' for martial art '{'str': #. 'Brawling'}' @@ -135035,6 +137746,9 @@ msgid "" "\n" "+1 Block attempts." msgstr "" +"La experiencia en el combate te llevó a ser capaz de bloquear varios ataques a la vez.\n" +"\n" +"+1 intentos de Bloqueo." #: lang/json/martial_art_from_json.py msgid "Capoeira" @@ -135047,21 +137761,25 @@ msgid "" "on fluid movement and sweeping kicks. Moving briefly enables stronger " "techniques. Missing an attack grants bonus damage for a short time." msgstr "" +"Es un estilo similar a la danza que tiene sus raíces en la esclavitud en " +"Brasil. La capoeira está focalizada en la fluidez de los movimientos y las " +"patadas barridas. Moverte habilita brevemente las técnicas más potentes. Al " +"errar un ataque tenés un bonus al daño por un breve tiempo." #. ~ initiate message for martial art '{'str': 'Capoeira'}' #: lang/json/martial_art_from_json.py msgid "You begin performing the ginga." -msgstr "" +msgstr "Empezás a interpretar la ginga." #. ~ initiate message for martial art '{'str': 'Capoeira'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s begins to rhythmically rock back and forth." -msgstr "" +msgstr "%s comienza a moverse hacia adelante y atrás de manera rítmica." #: lang/json/martial_art_from_json.py msgid "Capoeira Stance" -msgstr "" +msgstr "Postura de Capoeira" #. ~ Description of buff 'Capoeira Stance' for martial art '{'str': #. 'Capoeira'}' @@ -135071,10 +137789,13 @@ msgid "" "\n" "+1.0 Dodge skill, +1 Dodge attempts." msgstr "" +"No dejás de moverte nunca mientras hacés la ginga. Esto te hace muy movedizo mientras peleás.\n" +"\n" +"+1.0 a Esquivar, +1 intentos de Esquivar." #: lang/json/martial_art_from_json.py msgid "Capoeira Momentum" -msgstr "Momentum Capoeira" +msgstr "Impulso de Capoeira" #. ~ Description of buff 'Capoeira Momentum' for martial art '{'str': #. 'Capoeira'}' @@ -135086,6 +137807,11 @@ msgid "" "Enables \"Spin Kick\" and \"Sweep Kick\" techniques.\n" "Lasts 3 turns." msgstr "" +"Podés sentir el ritmo mientras te movés. No solo sos más difícil de golpear, ¡también tus patadas son más copadas!\n" +"\n" +"+1.0 a Esquivar.\n" +"Habilita las técnicas \"Patada Giratoria\" y \"Patada Barredora\".\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Capoeira Tempo" @@ -135101,6 +137827,10 @@ msgid "" "+15% Bash damage.\n" "Lasts 2 turns. Stacks 3 times." msgstr "" +"No le erraste, es solamente parte de la danza y ¡la mejor parte está por empezar!\n" +"\n" +"+15% daño Golpeante.\n" +"Dura 2 turnos. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Crane Kung Fu" @@ -135113,17 +137843,21 @@ msgid "" "techniques and jumping dodges. Dexterity determines your damage, rather " "than Strength; you also receive a dodge bonus move or dodge an attack." msgstr "" +"Uno de los cinco estilos animales Shaolin. La Grulla utiliza técnicas " +"intrincadas de mano y saltos para esquivar. La destreza determina el daño " +"que causás, más que la fuerza. También tenés un bonus a un movimiento para " +"esquivar o a esquivar un ataque." #. ~ initiate message for martial art '{'str': 'Crane Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You raise your leg slightly and balance like a crane." -msgstr "" +msgstr "Levantás tu pierna levemente y te balanceas como una grulla." #. ~ initiate message for martial art '{'str': 'Crane Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a crane-like stance." -msgstr "" +msgstr "%s adopta la postura de la grulla." #: lang/json/martial_art_from_json.py msgid "Crane's Precision" @@ -135139,6 +137873,10 @@ msgid "" "\n" "Bash damage increased by 75% of Dexterity but decreased by 75% of Strength." msgstr "" +"Tus ataques golpean las debilidades de tus enemigos con velocidad y precisión en lugar de fuerza bruta.\n" +"La Destreza incrementa el daño de cuerpo a cuerpo en lugar de la Fuerza.\n" +"\n" +"El daño Golpeante se incrementa en 75% de tu Destreza pero disminuye en un 75% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Crane's Flight" @@ -135153,10 +137891,14 @@ msgid "" "+1.0 Dodge skill.\n" "Lasts 2 turns." msgstr "" +"Igualito a un pájaro, te elevás en el aire para esquivar el peligro.\n" +"\n" +"+1.0 a Esquivar.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Crane's Grace" -msgstr "" +msgstr "Gracia de Grulla" #. ~ Description of buff 'Crane's Grace' for martial art '{'str': 'Crane Kung #. Fu'}' @@ -135167,6 +137909,10 @@ msgid "" "+1 Dodge attempts, +1.0 Dodge skill.\n" "Lasts 2 turns." msgstr "" +"Similar a una grulla, te volvés rápido para esquivar el peligro.\n" +"\n" +"+1 intentos de Esquivar, +1.0 a Esquivar.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Dragon Kung Fu" @@ -135180,17 +137926,21 @@ msgid "" "Your attacks lead to counterattacks which disable your opponents and set " "them up for a powerful finishing move." msgstr "" +"Uno de los cinco estilos animales Shaolin. El Dragón utiliza movimientos " +"fluidos y golpes fuertes. La Inteligencia mejora tu precisión en lugar de la" +" Destreza. Tus ataques son para contratacar lo que desarma a tus oponentes y" +" los prepara para un potente movimiento final." #. ~ initiate message for martial art '{'str': 'Dragon Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You relax and patiently await conflict like the great dragon." -msgstr "" +msgstr "Te relajás y esperás pacientemente el conflicto como un gran dragón." #. ~ initiate message for martial art '{'str': 'Dragon Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a dragon-like stance." -msgstr "" +msgstr "%s adopta la postura del dragón." #: lang/json/martial_art_from_json.py msgid "Dragon's Flight" @@ -135206,10 +137956,15 @@ msgid "" "Enables \"Dragon Vortex Block\" and \"Dragon Wing Dodge\"\n" "Lasts 1 turn." msgstr "" +"La vida y el combate son un círculo. El ataque lleva a un contraataque y a un ataque otra vez. Buscá completar el ciclo.\n" +"\n" +"+1 a Precisión, +2 daño Golpeante.\n" +"Habilita \"Bloqueo del Dragón\" y \"Ala Esquivadora de Dragón\"\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Dragon's Knowledge" -msgstr "" +msgstr "Conocimiento de Dragón" #. ~ Description of buff 'Dragon's Knowledge' for martial art '{'str': 'Dragon #. Kung Fu'}' @@ -135221,6 +137976,10 @@ msgid "" "\n" "Accuracy increased by 25% of Intelligence but decreased by 25% of Dexterity." msgstr "" +"Planeás tu ataque con mucha anticipación confiando en tu intuición en lugar de tu velocidad para atacar.\n" +"La Inteligencia incrementa la Precisión en lugar de tu Destreza.\n" +"\n" +"La Precisión se incrementa en un 25% de la Inteligencia pero disminuye en un 25% de tu Destreza." #: lang/json/martial_art_from_json.py msgid "Eskrima" @@ -135240,17 +137999,17 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Eskrima'}' #: lang/json/martial_art_from_json.py msgid "You enter an open guard stance and prepare to strike." -msgstr "" +msgstr "Entrás en una postura de guardia abierta y te preparás para golpear." #. ~ initiate message for martial art '{'str': 'Eskrima'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s enters an open stance." -msgstr "" +msgstr "%s entra en una postura abierta." #: lang/json/martial_art_from_json.py msgid "Eskrima Stance" -msgstr "" +msgstr "Postura de Eskrima" #. ~ Description of buff 'Eskrima Stance' for martial art '{'str': 'Eskrima'}' #: lang/json/martial_art_from_json.py @@ -135259,6 +138018,9 @@ msgid "" "\n" "+2 Accuracy." msgstr "" +"Tenés habilidad para sacar lo mejor de cada arma. El término 'arma' puede ser muy subjetivo.\n" +"\n" +"+2 a Precisión." #: lang/json/martial_art_from_json.py msgid "Eskrima Combination" @@ -135275,6 +138037,11 @@ msgid "" "Enables \"Combination Strike\" technique.\n" "Lasts 3 turns. Stacks 3 times." msgstr "" +"Podés continuar un golpe crítico con un ataque más potente si la oportunidad se presenta.\n" +"\n" +"+15% bonus a todo el daño.\n" +"Habilita la técnica \"Golpe Combinado\".\n" +"Dura 3 turnos. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Fencing" @@ -135288,21 +138055,25 @@ msgid "" "Skilled fencers can take advantage of blocks and feints to deliver accurate " "strikes." msgstr "" +"El noble arte de la esgrima se aprende con espadas flexibles de competición," +" pero las técnicas provienen de (y se aplican a) ejemplos más funcionales. " +"Los esgrimistas habilidosos pueden sacar ventaja de los bloqueos y fintas " +"para ejecutar golpes precisos." #. ~ initiate message for martial art '{'str': 'Fencing'}' #: lang/json/martial_art_from_json.py msgid "You move into the en-garde stance." -msgstr "" +msgstr "Te movés para ponerte en-garde." #. ~ initiate message for martial art '{'str': 'Fencing'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s moves into a fencing stance." -msgstr "" +msgstr "%s se mueve para adoptar la postura de esgrima." #: lang/json/martial_art_from_json.py msgid "Fencing Stance" -msgstr "" +msgstr "Postura de Esgrima" #. ~ Description of buff 'Fencing Stance' for martial art '{'str': 'Fencing'}' #: lang/json/martial_art_from_json.py @@ -135312,6 +138083,9 @@ msgid "" "\n" "Blocked damage reduced by 50% of Dexterity." msgstr "" +"Tu postura de costado minimiza las oportunidades de ser dañado en el combate.\n" +"\n" +"El daño bloqueado se reduce un 50% de tu Destreza." #: lang/json/martial_art_from_json.py lang/json/technique_from_json.py msgid "Parry" @@ -135325,10 +138099,14 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn." msgstr "" +"Tu próximo golpe encontrará la marca mucho más fácil desde el golpe que paraste.\n" +"\n" +"+1 a Precisión.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Remise" -msgstr "" +msgstr "Remise" #. ~ Description of buff 'Remise' for martial art '{'str': 'Fencing'}' #: lang/json/martial_art_from_json.py @@ -135339,6 +138117,11 @@ msgid "" "Enables \"Compound Attack\" technique.\n" "Lasts 1 turn." msgstr "" +"¡Tu finta es la trampa perfecta para el ataque devastador que le sigue!\n" +"\n" +"+1 a Precisión.\n" +"Habilita la técnica \"Ataque Compuesto\".\n" +"Dura 1 turno." #. ~ Description for martial art '{'str': 'Fior Di Battaglia'}' #: lang/json/martial_art_from_json.py @@ -135347,21 +138130,24 @@ msgid "" "\"Flower of Battle\" places great focus on countering one's opponent and " "knocking them down before landing a killing blow" msgstr "" +"Son técnicas marciales de la Europa medieval para lucha con armas de asta. " +"La \"Flor de la Batalla\" pone mucha atención en contrarrestar al oponente y" +" derribarlo antes de dar el golpe final." #. ~ initiate message for martial art '{'str': 'Fior Di Battaglia'}' #: lang/json/martial_art_from_json.py msgid "You hold your weapon in a firm grip, ready to block any attack." -msgstr "" +msgstr "Agarrás tu arma firmemente, preparado para bloquear cualquier ataque." #. ~ initiate message for martial art '{'str': 'Fior Di Battaglia'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s grips their weapon tightly." -msgstr "" +msgstr "%s agarra su arma firmemente." #: lang/json/martial_art_from_json.py msgid "Stand Your Ground" -msgstr "" +msgstr "Mantenerse Firme" #. ~ Description of buff 'Stand Your Ground' for martial art '{'str': 'Fior Di #. Battaglia'}' @@ -135372,10 +138158,13 @@ msgid "" "\n" "+2 Block attempts, -1.0 Dodge skill, blocked damage reduced by 50% of Strength." msgstr "" +"Sos recio y no te rendirás ante ninguna amenaza.\n" +"\n" +"+2 intentos de Bloqueo, -1.0 a Esquivar, daño bloqueado reducido en 50% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Tactical Retreat" -msgstr "" +msgstr "Retirada Táctica" #. ~ Description of buff 'Tactical Retreat' for martial art '{'str': 'Fior Di #. Battaglia'}' @@ -135387,10 +138176,14 @@ msgid "" "-2 Block attempts, +1.0 Dodge skill, blocked damaged increased by 50% of Strength.\n" "Lasts 1 turn." msgstr "" +"¡Te movés y anulás los efectos de Mantenerse Firme!\n" +"\n" +"-2 intentos de Bloqueo, +1.0 a Esquivar, daño bloqueado reducido en 50% de tu Fuerza.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Defense Break" -msgstr "" +msgstr "Romper Defensa" #. ~ Description of buff 'Defense Break' for martial art '{'str': 'Fior Di #. Battaglia'}' @@ -135401,10 +138194,14 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn. Stacks 3 times." msgstr "" +"Cada bloqueo exitoso revela una oportunidad en la guardia de tu oponente.\n" +"\n" +"+1 a Precisión.\n" +"Dura 1 turno. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Tactical Feinting" -msgstr "" +msgstr "Finta Táctica" #. ~ Description of buff 'Tactical Feinting' for martial art '{'str': 'Fior Di #. Battaglia'}' @@ -135415,6 +138212,10 @@ msgid "" "Enables \"Hook and Drag\" technique.\n" "Lasts 1 turn." msgstr "" +"¡Se tragan tu finta!\n" +"\n" +"Habilita la técnica \"Enganchar y Arrastrar\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Judo" @@ -135427,21 +138228,25 @@ msgid "" "offensive. You are resistant to most effects that can knock you down and " "can counter grab and takedown attacks with strong judo throw." msgstr "" +"El judo es un arte marcial que se focaliza en agarradas y tiradas, tanto " +"defensivas como ofensivas. Sos resistente a la mayoría de los efectos que " +"pueden derribarte y podés contrarrestar un agarre y desarmar ataques con una" +" tirada de judo." #. ~ initiate message for martial art '{'str': 'Judo'}' #: lang/json/martial_art_from_json.py msgid "You prepare yourself for a grapple." -msgstr "" +msgstr "Te preparás para un agarre." #. ~ initiate message for martial art '{'str': 'Judo'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s prepares for a grapple." -msgstr "" +msgstr "%s se prepara para un agarre." #: lang/json/martial_art_from_json.py msgid "Judo Stance" -msgstr "" +msgstr "Postura de Judo" #. ~ Description of buff 'Judo Stance' for martial art '{'str': 'Judo'}' #: lang/json/martial_art_from_json.py @@ -135449,6 +138254,8 @@ msgid "" "Your knowledge of grappling allows you to recover from knock down effects instantly.\n" "In addition, you can counter grabs and takedown attacks with a judo throw." msgstr "" +"Tu conocimiento de los agarres te permite recuperarte de una caída instantáneamente.\n" +"Además, podés contrarrestar agarres y desarmar ataques con una tirada de judo." #: lang/json/martial_art_from_json.py msgid "Karate" @@ -135469,17 +138276,17 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Karate'}' #: lang/json/martial_art_from_json.py msgid "You adopt a classic karate stance." -msgstr "" +msgstr "Adoptás la clásica postura de karate." #. ~ initiate message for martial art '{'str': 'Karate'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s adopts a classic karate stance." -msgstr "" +msgstr "%s adopta la clásica postura de karate." #: lang/json/martial_art_from_json.py msgid "Karate Strike" -msgstr "" +msgstr "Golpe de Karate" #. ~ Description of buff 'Karate Strike' for martial art '{'str': 'Karate'}' #: lang/json/martial_art_from_json.py @@ -135490,10 +138297,14 @@ msgid "" "+2 Block attempts, +1 Dodges attempts, blocked damge reduced by 50% of Strength.\n" "Lasts 2 turns." msgstr "" +"Acertar un golpe te permite posicionarte perfectamente para una defensa máxima contra múltiples oponentes.\n" +"\n" +"+2 intentos de Bloqueo, +1 intentos de Esquivar, daño bloqueado reducido en 50% de tu Fuerza.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Karate Stance" -msgstr "" +msgstr "Postura de Karate" #. ~ Description of buff 'Karate Stance' for martial art '{'str': 'Karate'}' #: lang/json/martial_art_from_json.py @@ -135502,6 +138313,9 @@ msgid "" "\n" "+2 Accuracy." msgstr "" +"Tu seria postura te permite golpear con mayor precisión.\n" +"\n" +"+2 a Precisión." #: lang/json/martial_art_from_json.py msgid "Krav Maga" @@ -135522,17 +138336,17 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Krav Maga'}' #: lang/json/martial_art_from_json.py msgid "You assume a practical combat stance." -msgstr "" +msgstr "Asumís una postura práctica para el combate." #. ~ initiate message for martial art '{'str': 'Krav Maga'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a practical combat stance." -msgstr "" +msgstr "%s asume una postura práctica para el combate." #: lang/json/martial_art_from_json.py msgid "Krav Maga Stance" -msgstr "" +msgstr "Postura de Krav Maga" #. ~ Description of buff 'Krav Maga Stance' for martial art '{'str': 'Krav #. Maga'}' @@ -135542,6 +138356,9 @@ msgid "" "\n" "+1 Accuracy, +1 Block attempts." msgstr "" +"Tu entrenamiento hace más fácil acertar golpes y pelear contra múltiples oponentes.\n" +"\n" +"+1 a Precisión, +1 intentos de Bloqueo." #: lang/json/martial_art_from_json.py msgid "Leopard Kung Fu" @@ -135555,21 +138372,25 @@ msgid "" "than Strength. Moving increases dodge skill and accuracy further; attacking" " after moving increases damage." msgstr "" +"Uno de los cinco estilos animales Shaolin. El Leopardo se focaliza en golpes" +" rápidos, estratégicamente planeados. La Destreza determina tu daño, en " +"lugar de la Fuerza. Al moverte incrementás más tu habilidad para esquivar y " +"tu precisión; atacar después de moverte incrementa el daño." #. ~ initiate message for martial art '{'str': 'Leopard Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You prepare to pounce like a leopard." -msgstr "" +msgstr "Te preparás para saltar como un leopardo." #. ~ initiate message for martial art '{'str': 'Leopard Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a leopard-like stance." -msgstr "" +msgstr "%s adopta una postura similar a un leopardo." #: lang/json/martial_art_from_json.py msgid "Leopard's Strategy" -msgstr "" +msgstr "Estrategia del Leopardo" #. ~ Description of buff 'Leopard's Strategy' for martial art '{'str': #. 'Leopard Kung Fu'}' @@ -135581,10 +138402,14 @@ msgid "" "\n" "Bash damage increased by 75% of Dexterity but decreased by 75% of Strength." msgstr "" +"Peleás abrumando a tus oponentes con golpes rápidos que son mucho más difíciles de defender.\n" +"La Destreza incrementa el daño de cuerpo a cuerpo en lugar de la Fuerza.\n" +"\n" +"El daño Golpeante se incrementa en 75% de tu Destreza pero disminuye en un 75% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Leopard's Agility" -msgstr "" +msgstr "Agilidad de Leopardo" #. ~ Description of buff 'Leopard's Agility' for martial art '{'str': 'Leopard #. Kung Fu'}' @@ -135594,6 +138419,9 @@ msgid "" "\n" "+1.0 Dodge skill." msgstr "" +"Igual que un gato, sos rápido, ágil y difícil de agarrar.\n" +"\n" +"+1.0 a Esquivar." #: lang/json/martial_art_from_json.py msgid "Leopard's Stalk" @@ -135609,10 +138437,15 @@ msgid "" "Enables \"Leopard's Pounce\" buff.\n" "Lasts 1 turn." msgstr "" +"Acechás orgullosamente por las sombras y te preparas para saltar con una furia imparable.\n" +"\n" +"+2 a Precisión.\n" +"Habilita la técnica \"Salto del Leopardo\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Leopard's Pounce" -msgstr "" +msgstr "Salto del Leopardo" #. ~ Description of buff 'Leopard's Pounce' for martial art '{'str': 'Leopard #. Kung Fu'}' @@ -135624,6 +138457,10 @@ msgid "" "+25% bonus to all damage.\n" "Lasts 1 turn." msgstr "" +"Estás preparado. ¡Atacá y reclamá tu presa!\n" +"\n" +"+25% bonus a todo el daño.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Medieval Swordsmanship" @@ -135638,21 +138475,26 @@ msgid "" "treatise compares the Italian and German traditions of medieval combat with " "detailed step-by-step pictures." msgstr "" +"El arte de la espada larga y de la espada y escudo, previo al posterior " +"desarrollo de la esgrima. Diseñado para el combate tanto con armadura como " +"sin ella, incluye el forcejeo y también las técnicas defensivas y ofensivas " +"con la espada. Este tratado comprara las tradiciones italiana y alemana del " +"combate medieval con dibujos detallados." #. ~ initiate message for martial art '{'str': 'Medieval Swordsmanship'}' #: lang/json/martial_art_from_json.py msgid "You take on a knightly stance." -msgstr "" +msgstr "Adoptás una postura caballeresca." #. ~ initiate message for martial art '{'str': 'Medieval Swordsmanship'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s takes on a knightly stance." -msgstr "" +msgstr "%s adopta una postura caballeresca." #: lang/json/martial_art_from_json.py msgid "Swordsman's Stance" -msgstr "" +msgstr "Postura de Espadachín" #. ~ Description of buff 'Swordsman's Stance' for martial art '{'str': #. 'Medieval Swordsmanship'}' @@ -135663,10 +138505,13 @@ msgid "" "\n" "+1 Dodge attempts, blocked damage decreased by 50% of Strength." msgstr "" +"A través de la caballería y la vigilancia, tu defensa con una espada se ha incrementado.\n" +"\n" +"+1 intentos de Esquivar, daño bloqueado reducido en 50% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Deflection" -msgstr "" +msgstr "Desviación" #. ~ Description of buff 'Deflection' for martial art '{'str': 'Medieval #. Swordsmanship'}' @@ -135676,10 +138521,13 @@ msgid "" "Enables \"Sweeping Strike\" and \"Deathblow\" techniques.\n" "Lasts 1 turn." msgstr "" +"¡Desviaste el ataque de tu enemigo y ahora esta vulnerable a un contrataque!\n" +"Habilita las técnicas \"Golpe de Barrido\" and \"Golpe Mortal\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Manslayer" -msgstr "" +msgstr "Asesino de Hombres" #. ~ Description of buff 'Manslayer' for martial art '{'str': 'Medieval #. Swordsmanship'}' @@ -135689,6 +138537,9 @@ msgid "" "Enables \"Vicious Strike\" techniques.\n" "Lasts 1 turn." msgstr "" +"¡Tu poderoso ataque te da la oportunidad de terminar esta pelea ahora mismo!\n" +"Habilita la técnica \"Golpe Feroz\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Muay Thai" @@ -135702,21 +138553,25 @@ msgid "" " blocked damage. Blocking attacks or getting hit will increase your damage " "and blocked damage further." msgstr "" +"También conocido como el \"Arte de los 8 Miembros\", el Muay Thai es una " +"técnica de lucha popular de Tailandia que utiliza golpes poderosos. Tu " +"fuerza disminuye el daño bloqueado. Bloquear ataques o recibir golpes " +"incrementará tu daño y el daño bloqueado." #. ~ initiate message for martial art '{'str': 'Muay Thai'}' #: lang/json/martial_art_from_json.py msgid "You perform a short wai khru in honor of your teachers." -msgstr "" +msgstr "Hacés un pequeño wai khru en honor a tus maestros." #. ~ initiate message for martial art '{'str': 'Muay Thai'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s performs a short war-dance." -msgstr "" +msgstr "%s representa una pequeña danza de guerra." #: lang/json/martial_art_from_json.py msgid "Muay Thai Stance" -msgstr "" +msgstr "Postura de Muay Thai" #. ~ Description of buff 'Muay Thai Stance' for martial art '{'str': 'Muay #. Thai'}' @@ -135727,10 +138582,13 @@ msgid "" "\n" "Blocked damage decreased by 50% of Strength." msgstr "" +"La fuerza es todo en el Muay Thai y sabés cómo sacar lo mejor de la tuya.\n" +"\n" +"Daño bloqueado reducido en un 50% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Determination" -msgstr "" +msgstr "Determinación" #. ~ Description of buff 'Determination' for martial art '{'str': 'Muay #. Thai'}' @@ -135742,6 +138600,10 @@ msgid "" "+Bash damage increased by 25% of Strength, blocked damage decreased by 50% of Strength.\n" "Lasts 5 turns." msgstr "" +"Recibir un golpe no te va a frenar. Vas a durar más que tu oponente y ganar esta pelea.\n" +"\n" +"Daño Golpeante incrementado en un 25% de tu Fuerza, daño bloqueado en un 50% de tu Fuerza.\n" +"Dura 5 turnos." #: lang/json/martial_art_from_json.py msgid "Ninjutsu" @@ -135755,21 +138617,26 @@ msgid "" " silent and does extra damage on the first attack. It also provides small " "combat bonuses every time you move." msgstr "" +"El ninjutsu es un arte marcial y un conjunto de tácticas utilizadas por los " +"ninjas en la época feudal de Japón. Se focaliza en golpes rápidos, precisos " +"y silenciosos. El ninjutsu es casi completamente silencioso y causa más daño" +" en el primer ataque. También provee pequeños bonus al combate cada vez que " +"te movés." #. ~ initiate message for martial art '{'str': 'Ninjutsu'}' #: lang/json/martial_art_from_json.py msgid "You perform a kuji-in mantra with your hands. Rin, Kai, Jin!" -msgstr "" +msgstr "Hacés un mantra kuji-in con tus manos. ¡Rin, Kai, Jin!" #. ~ initiate message for martial art '{'str': 'Ninjutsu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s performs a series of intricate hand signs." -msgstr "" +msgstr "%s hace una serie de signos intrincados con la mano." #: lang/json/martial_art_from_json.py msgid "Ninjutsu Stance" -msgstr "" +msgstr "Postura de Ninjutsu" #. ~ Description of buff 'Ninjutsu Stance' for martial art '{'str': #. 'Ninjutsu'}' @@ -135779,10 +138646,13 @@ msgid "" "\n" "Melee and unarmed attacks generate 0 noise. Moving generates 1/2 as much noise." msgstr "" +"Tu entrenamiento te permite no hacer ruido cuando atacás y menos ruido cuando te movés.\n" +"\n" +"Ataques de cuerpo a cuerpo o desarmado generan 0 ruido. Moverse genera la mitad del ruido." #: lang/json/martial_art_from_json.py msgid "Sneak Attack" -msgstr "" +msgstr "Ataque Sigiloso" #. ~ Description of buff 'Sneak Attack' for martial art '{'str': 'Ninjutsu'}' #: lang/json/martial_art_from_json.py @@ -135792,10 +138662,13 @@ msgid "" "\n" "+50% all damage." msgstr "" +"Para el verdadero shinobi, el primer golpe y el último son el mismo.\n" +"\n" +"+50% a todo el daño." #: lang/json/martial_art_from_json.py msgid "Momentum Shift" -msgstr "" +msgstr "Cambio de Impulso" #. ~ Description of buff 'Momentum Shift' for martial art '{'str': #. 'Ninjutsu'}' @@ -135807,10 +138680,14 @@ msgid "" "+1.0 Dodge skill, Accuracy increased by 20% of Dexterity.\n" "Last 1 turn." msgstr "" +"Los ninjas están entrenados para ser extremadamente ágiles y móviles.\n" +"\n" +"+1.0 habilidad Esquivar, Precisión incrementada en un 20% de tu Destreza.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Loss of Surprise" -msgstr "" +msgstr "Pérdida de Sorpresa" #. ~ Description of buff 'Loss of Surprise' for martial art '{'str': #. 'Ninjutsu'}' @@ -135822,10 +138699,14 @@ msgid "" "-50% all damage.\n" "Last 3 turns." msgstr "" +"¡Tus intenciones son reveladas! Vas a tardar unos momentos para volverte sigiloso.\n" +"\n" +"-50% a todo el daño.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Escape Plan" -msgstr "" +msgstr "Plan de Escape" #. ~ Description of buff 'Escape Plan' for martial art '{'str': 'Ninjutsu'}' #: lang/json/martial_art_from_json.py @@ -135835,6 +138716,10 @@ msgid "" "+2 Dodge attempts, +10 movement speed.\n" "Last 3 turns." msgstr "" +"Tu objetivo ha muerto. Es momento de irse y planear tu próximo ataque.\n" +"\n" +"+2 intentos de Esquivar, +10 velocidad de movimiento.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Niten Ichi-Ryu" @@ -135849,21 +138734,26 @@ msgid "" "attacking reduces dodging and damage until you pause. Pausing for a moment " "increases Dodge skill." msgstr "" +"El Niten Ichi-Ryu es una vieja escuela de combate, que transmite el estilo " +"clásico japonés en el uso de las espadas, concebido por el guerrero Miyamoto" +" Musashi. La Percepción incrementa el daño y reduce el daño bloqueado. " +"Moverse y atacar reduce la posibilidad de esquivar y el daño hasta que " +"parás. Parar por un momento incrementa tu habilidad de Esquivar." #. ~ initiate message for martial art '{'str': 'Niten Ichi-Ryu'}' #: lang/json/martial_art_from_json.py msgid "You clear your mind as you prepare yourself for combat." -msgstr "" +msgstr "Limpiás tu mente mientras te preparás para el combate." #. ~ initiate message for martial art '{'str': 'Niten Ichi-Ryu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s relaxes and prepares for combat." -msgstr "" +msgstr "%s se relaja y se prepara para el combate." #: lang/json/martial_art_from_json.py msgid "Niten Ichi-Ryu Stance" -msgstr "" +msgstr "Postura de Niten Ichi-Ryu" #. ~ Description of buff 'Niten Ichi-Ryu Stance' for martial art '{'str': #. 'Niten Ichi-Ryu'}' @@ -135876,10 +138766,15 @@ msgid "" "\n" "Bash and Cut armor penetration increased by 50% of Perception, blocked damage reduced by 100% of Perception." msgstr "" +"Ojos atentos cuidadosos\n" +"miden y muestran tu habilidad.\n" +"La práctica hace la perfección.\n" +"\n" +"Penetración de armadura en Golpe y Corte incrementada en un 50% de tu Percepción, daño bloqueado reducido en un 100% de tu Percepción." #: lang/json/martial_art_from_json.py msgid "Waning Moon" -msgstr "" +msgstr "Cuarto Menguante" #. ~ Description of buff 'Waning Moon' for martial art '{'str': 'Niten Ichi- #. Ryu'}' @@ -135892,10 +138787,16 @@ msgid "" "-5.0 Dodge skill.\n" "Lasts 1 turn." msgstr "" +"Ennegrecido como la oscuridad,\n" +"las pesadillas se acercan de todos lados.\n" +"¡Huí a toda costa!\n" +"\n" +"-5.0 habilidad Esquivar.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Moonlight" -msgstr "" +msgstr "Luz de Luna" #. ~ Description of buff 'Moonlight' for martial art '{'str': 'Niten Ichi- #. Ryu'}' @@ -135908,10 +138809,16 @@ msgid "" "Enables \"In-One Timing\".\n" "Lasts 1 turn." msgstr "" +"Suerte es luz,\n" +"en una noche oscura y nubosa\n" +"mientras brilla la luna\n" +"\n" +"Habilita \"En Un Tiempo\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Falling Leaf" -msgstr "" +msgstr "Hoja Cayendo" #. ~ Description of buff 'Falling Leaf' for martial art '{'str': 'Niten Ichi- #. Ryu'}' @@ -135924,10 +138831,16 @@ msgid "" "-1.0 Dodge skill, -1 bash damage, -1 cut damage.\n" "Lasts 1 turn. Stacks 5 times." msgstr "" +"Un espada filosa corta de verdad.\n" +"Aunque, todas las cosas desaparecen al tiempo.\n" +"El control afila tus habilidades.\n" +"\n" +"-1.0 habilidad Esquivar, -1 daño Golpeante, -1 daño Cortante.\n" +"Dura 1 turno. Se acumula hasta 5 veces." #: lang/json/martial_art_from_json.py msgid "Stillness" -msgstr "" +msgstr "Quietud" #. ~ Description of buff 'Stillness' for martial art '{'str': 'Niten Ichi- #. Ryu'}' @@ -135941,6 +138854,12 @@ msgid "" "+2 Accuracy, Dodge skill increased by 50% of Perception.\n" "Lasts 2 turns." msgstr "" +"El ojo de la tormenta,\n" +"un breve momento de paz,\n" +"que se va sin dejar rastro.\n" +"\n" +"+2 a Precisión, habilidad Esquivar aumentada en un 50% de tu Percepción.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Pankration" @@ -135953,21 +138872,24 @@ msgid "" "and wrestling techniques to create a brutal sport, though modern revival of " "the art is less of no-holds-barred in nature." msgstr "" +"Es un antiguo arte marcial griego usado por los espartanos. Combina técnicas" +" de boxeo y de lucha para crear un deporte brutal, aunque el estilo moderno " +"de este arte no es tan \"vale todo\" como antes." #. ~ initiate message for martial art '{'str': 'Pankration'}' #: lang/json/martial_art_from_json.py msgid "You crouch slightly and prepare to rush forward." -msgstr "" +msgstr "Te agachás un poco y te preparás para lanzarte hacia adelante." #. ~ initiate message for martial art '{'str': 'Pankration'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s crouches slightly, ready to rush forward." -msgstr "" +msgstr "%s se agacha un poco, listo para lanzarse hacia adelante." #: lang/json/martial_art_from_json.py msgid "Close Combat" -msgstr "" +msgstr "Combate Cercano" #. ~ Description of buff 'Close Combat' for martial art '{'str': #. 'Pankration'}' @@ -135979,6 +138901,10 @@ msgid "" "+20% bash damage.\n" "Lasts 1 turn." msgstr "" +"¡Tenés a tus oponentes justo donde los querías!\n" +"\n" +"+20% daño Golpeante.\n" +"Dura 1 turno." #. ~ Description of buff 'Counter Chance' for martial art '{'str': #. 'Pankration'}' @@ -135989,6 +138915,9 @@ msgid "" "+10% bash damage. Enables \"Close Combat\" buff.\n" "Lasts 1 turn." msgstr "" +"El enemigo ha mostrado una apertura en su defensa.\n" +"+10% daño Golpeante. Habilita la técnica \"Combate Cercano\" buff.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Silat" @@ -136008,13 +138937,13 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Silat'}' #: lang/json/martial_art_from_json.py msgid "You give a salute of respect as you prepare to combat." -msgstr "" +msgstr "Hacés un saludo de respeto y te preparás para el combate." #. ~ initiate message for martial art '{'str': 'Silat'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s gives a combat salute." -msgstr "" +msgstr "%s hace un saludo de combate." #: lang/json/martial_art_from_json.py msgid "Silat Stance" @@ -136027,10 +138956,13 @@ msgid "" "\n" "+1 Dodge attempts." msgstr "" +"Intentás mantenerte lo más relajado posible en la pelea para tener más oportunidades de esquivar.\n" +"\n" +"+1 intentos de Esquivar." #: lang/json/martial_art_from_json.py msgid "Silat Evasion" -msgstr "" +msgstr "Evasión de Silat" #. ~ Description of buff 'Silat Evasion' for martial art '{'str': 'Silat'}' #: lang/json/martial_art_from_json.py @@ -136040,10 +138972,14 @@ msgid "" "+1 Dodge attempts.\n" "Lasts 2 turn." msgstr "" +"Te mantenés agachado mientras te movés, haciendo difícil que tus enemigos te acorralen.\n" +"\n" +"+1 intento de Esquivar.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Silat Appraisal" -msgstr "" +msgstr "Estimación de Silat" #. ~ Description of buff 'Silat Appraisal' for martial art '{'str': 'Silat'}' #: lang/json/martial_art_from_json.py @@ -136054,6 +138990,10 @@ msgid "" "Accuracy increased by 15% of Dexterity.\n" "Lasts 2 turns. Stacks 3 times." msgstr "" +"Cada vez que esquivás un ataque, aprendés un poco más acerca del estilo de lucha de tu oponente. Esto permite que puedas realizar ataques más precisos.\n" +"\n" +"Precisión incrementada en un 15% de tu Destreza.\n" +"Dura 2 turnos. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Snake Kung Fu" @@ -136067,21 +139007,25 @@ msgid "" " than Dexterity. Standing still will increases your accuracy and damage of " "your next attack." msgstr "" +"Uno de los cinco estilos animales Shaolin. La Serpiente se focaliza en " +"movimientos sinuosos y golpes precisos. La Percepción determina tu Precisión" +" en lugar de la Destreza. Al quedarte quieto incrementás tu precisión y daño" +" en tu próximo ataque." #. ~ initiate message for martial art '{'str': 'Snake Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You adopt a fluid stance, ready to strike like a snake." -msgstr "" +msgstr "Adoptás una postura fluida, listo para atacar como una serpiente." #. ~ initiate message for martial art '{'str': 'Snake Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a snake-like stance." -msgstr "" +msgstr "%s adopta una postura como una serpiente." #: lang/json/martial_art_from_json.py msgid "Snake's Sight" -msgstr "" +msgstr "Vista de Serpiente" #. ~ Description of buff 'Snake's Sight' for martial art '{'str': 'Snake Kung #. Fu'}' @@ -136092,10 +139036,13 @@ msgid "" "\n" "Perception increases Accuracy instead of Dexterity. Accuracy increased by 25% of Perception but decreased by 25% of Dexterity." msgstr "" +"Sos paciente y sabés dónde golpear a tu oponente para tener mejores resultados.\n" +"\n" +"La Percepción incrementa la Precisión en lugar de la Destreza. Precisión incrementada en un 25% de tu Percepción pero disminuida en un 25% de tu Destreza." #: lang/json/martial_art_from_json.py msgid "Snake's Coil" -msgstr "" +msgstr "Bucle de Serpiente" #. ~ Description of buff 'Snake's Coil' for martial art '{'str': 'Snake Kung #. Fu'}' @@ -136107,6 +139054,10 @@ msgid "" "+1 Accuracy, gain armor penetration equal to 50% of Perceptions.\n" "Lasts 1 turn. Stacks 3 times." msgstr "" +"Cada serpiente espera el momento perfecto para atacar. ¡Apuntás mientras tus oponentes se preparan y atacás sus debilidades sin piedad!\n" +"\n" +"+1 Precisión, mejora penetración de armadura igual al 50% de tu Percepción.\n" +"Dura 1 turno. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Sōjutsu" @@ -136120,17 +139071,21 @@ msgid "" "to maintain advantage in combat. Standing still gives you an extra block " "attempt but moving will briefly increase your damage." msgstr "" +"Sōjutsu, \"El Camino de la Lanza\", es el arte marcial japonés de luchar con" +" una lanza. El Sōjutsu se enfoca en mantener a los oponentes a la distancia " +"necesaria para mantener la ventaja en el combate. Quedarte quieto te da un " +"intento de bloqueo más pero moverte incremente brevemente tu daño." #. ~ initiate message for martial art '{'str': 'Sōjutsu'}' #: lang/json/martial_art_from_json.py msgid "You prepare to defend against all that approach you." -msgstr "" +msgstr "Te preparás para defenderte contra los que se aproximan." #. ~ initiate message for martial art '{'str': 'Sōjutsu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a wide, defensive stance." -msgstr "" +msgstr "%s adopta una postura amplia y defensiva." #: lang/json/martial_art_from_json.py msgid "Sōjutsu Stance" @@ -136143,10 +139098,13 @@ msgid "" "\n" "+1 Block attempt." msgstr "" +"Tu entrenamiento de otorga una mejor defensa cuando usás un arma de asta.\n" +"\n" +"+1 intentos de Bloqueo." #: lang/json/martial_art_from_json.py msgid "Superior Positioning" -msgstr "" +msgstr "Posicionamiento Superior" #. ~ Description of buff 'Superior Positioning' for martial art '{'str': #. 'Sōjutsu'}' @@ -136158,6 +139116,10 @@ msgid "" "+10% damage, -1 Block attempts.\n" "Lasts 1 turn." msgstr "" +"Abandonás tus defensas por un momento para incrementar el daño de tus ataques.\n" +"\n" +"+10% al daño, -1 intentos de Bloqueo.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Taekwondo" @@ -136172,20 +139134,25 @@ msgid "" "extra damage and your attacks do more damage if you are not holding " "anything." msgstr "" +"El taekwondo es el deporte nacional de Corea, y fue utilizado por el " +"ejército coreano en el siglo XX. Se enfoca en usar patadas así que no se " +"beneficia por empuñar armas. También incluye entrenamiento de fuerza; tus " +"bloqueos absorben daño y tus ataques hacen más daño si no estás empuñando " +"nada." #. ~ initiate message for martial art '{'str': 'Taekwondo'}' #: lang/json/martial_art_from_json.py msgid "You adopt a narrow fighting stance." -msgstr "" +msgstr "Adoptás una postura reducida de lucha." #. ~ initiate message for martial art '{'str': 'Taekwondo'}' #: lang/json/martial_art_from_json.py msgid "You adopts a narrow fighting stance." -msgstr "" +msgstr "adopta una postura reducida de lucha." #: lang/json/martial_art_from_json.py msgid "Taekwondo Stance" -msgstr "" +msgstr "Postura de Taekwondo" #. ~ Description of buff 'Taekwondo Stance' for martial art '{'str': #. 'Taekwondo'}' @@ -136196,10 +139163,13 @@ msgid "" "\n" "Blocked damage decreased by 50% of Strength." msgstr "" +"Usando tus piernas para atacar te permite tener las manos libres para una mejor defensa.\n" +"\n" +"El daño bloqueado reducido en un 50% de tu Fuerza." #: lang/json/martial_art_from_json.py msgid "Unhindered" -msgstr "" +msgstr "Sin Obstáculos" #. ~ Description of buff 'Unhindered' for martial art '{'str': 'Taekwondo'}' #: lang/json/martial_art_from_json.py @@ -136209,6 +139179,9 @@ msgid "" "\n" "+33% bash damage when not using a weapon." msgstr "" +"Tus ataques son más fuertes si no tenés nada en las manos.\n" +"\n" +"+33% daño Golpeante cuando no usás un arma." #: lang/json/martial_art_from_json.py msgid "Tai Chi" @@ -136222,21 +139195,26 @@ msgid "" " the force of an attack makes your Perception decrease damage further on a " "block. Pausing for a moment enables powerful palm strike techniques." msgstr "" +"Aunque el Tai Chi es visto a menudo como un ejercicio físico y mental, es un" +" legítimo arte marcial focalizado en la defensa propia. Su capacidad de " +"absorber la fuerza de un ataque hace que tu Percepción disminuya el daño en " +"un bloqueo. Frenar por un momento te permite técnicas poderosas de golpe de " +"palma." #. ~ initiate message for martial art '{'str': 'Tai Chi'}' #: lang/json/martial_art_from_json.py msgid "You settle into a gentle stance and prepare to defend yourself." -msgstr "" +msgstr "Establecés una postura gentil y te preparás para defenderte." #. ~ initiate message for martial art '{'str': 'Tai Chi'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s settles into a gentle stance." -msgstr "" +msgstr "%s establece una postura gentil." #: lang/json/martial_art_from_json.py msgid "Tai Chi Stance" -msgstr "" +msgstr "Postura de Tai Chi" #. ~ Description of buff 'Tai Chi Stance' for martial art '{'str': 'Tai Chi'}' #: lang/json/martial_art_from_json.py @@ -136246,10 +139224,13 @@ msgid "" "\n" "+1 Block attempts, blocked damage reduced by 100% Perception." msgstr "" +"Te enfocás en la defensa y predecís los ataques de tus oponentes.\n" +"\n" +"+1 intentos de Bloqueo, daño bloqueado reducido en un 100% de tu Percepción." #: lang/json/martial_art_from_json.py msgid "Repulse the Monkey" -msgstr "" +msgstr "Repeler el Mono" #. ~ Description of buff 'Repulse the Monkey' for martial art '{'str': 'Tai #. Chi'}' @@ -136261,10 +139242,14 @@ msgid "" "Accuracy increased by 20% of Perception, gain bash Armor Penetration equal to 50% of Perception.\n" "Lasts 2 turns." msgstr "" +"Al perfeccionar tu posicionamiento y el de tu oponente, te has vuelto más preciso y podés evadir la defensa de tu oponente.\n" +"\n" +"Precisión incrementada en un 20% de tu Percepción, recibís penetración de armadura por golpe igual al 50% de tu Percepción.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Cross Hands" -msgstr "" +msgstr "Manos Cruzadas" #. ~ Description of buff 'Cross Hands' for martial art '{'str': 'Tai Chi'}' #: lang/json/martial_art_from_json.py @@ -136276,6 +139261,11 @@ msgid "" "Enables \"Palm Strike\" and \"Double Palm Strike\" techniques.\n" "Lasts 3 turns." msgstr "" +"Al tomarte un tiempo para prepararte, podés usar tu cuerpo entero para atacar y defender.\n" +"\n" +"+1.0 habilidad Esquivar, daño bloqueado reducido en un 50% de tu Percepción.\n" +"Habilita las técnicas \"Golpe de Palma\" and \"Doble Golpe de Palma\".\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Tiger Kung Fu" @@ -136295,13 +139285,13 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Tiger Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You clench your hands into ferocious, tiger-like claws." -msgstr "" +msgstr "Tensás tus manos en una forma parecida a garras feroces de tigre." #. ~ initiate message for martial art '{'str': 'Tiger Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a tiger-like stance." -msgstr "" +msgstr "%s adopta una postura similar a un tigre." #: lang/json/martial_art_from_json.py msgid "Tiger Fury" @@ -136317,10 +139307,14 @@ msgid "" "+10% damage.\n" "Lasts 3 turns. Stacks 4 times." msgstr "" +"Atacás con una descarga incesante de golpes. Cuanto más golpeás, más fuerte te volvés.\n" +"\n" +"+10% al daño.\n" +"Dura 3 turnos. Se acumula hasta 4 veces." #: lang/json/martial_art_from_json.py msgid "Tiger's Strength" -msgstr "" +msgstr "Fuerza de Tigre" #. ~ Description of buff 'Tiger's Strength' for martial art '{'str': 'Tiger #. Kung Fu'}' @@ -136332,10 +139326,14 @@ msgid "" "\n" "Accuracy increased by 25% of Strength but decreased by 25% of Dexterity." msgstr "" +"No necesitás defensa. No necesitás tener un plan. Necesitás fuerza. La fuerza romperá la defensa de tus oponentes y los abrumará.\n" +"Tu Fuerza incrementa la Precisión en lugar de la Destreza.\n" +"\n" +"Precisión incrementada en un 25% de tu Fuerza pero disminuida en un 25% de tu Destreza." #: lang/json/martial_art_from_json.py msgid "Tiger Rampage" -msgstr "" +msgstr "Violencia de Tigre" #. ~ Description of buff 'Tiger Rampage' for martial art '{'str': 'Tiger Kung #. Fu'}' @@ -136347,10 +139345,14 @@ msgid "" "Gain Armor Penetration equal to 50% of Strength.\n" "Lasts 1 turns. Stacks 2 times." msgstr "" +"La pérdida de tu oponente es tu ganancia. Tu próximo ataque romperá la guardia de tu oponente.\n" +"\n" +"Recibís penetración de armadura igual al 50% de tu Fuerza.\n" +"Dura 1 turno. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Wing Chun" -msgstr "" +msgstr "Wing Chun" #. ~ Description for martial art '{'str': 'Wing Chun'}' #: lang/json/martial_art_from_json.py @@ -136361,21 +139363,27 @@ msgid "" "sensitivity to the opponent's direction of force, and flowing around it to " "get back to hitting." msgstr "" +"El Wing Chun es un arte marcial chino que comienza seleccionando las " +"técnicas efectivas más fáciles de aprender de varias formas animales " +"Shaolin. Tiene una postura alta con el peso completamente en la pierna " +"trasera. Wing Chun se focaliza en la sensibilidad de la dirección de fuerza " +"del oponente, y seguirlo para volver a golpear." #. ~ initiate message for martial art '{'str': 'Wing Chun'}' #: lang/json/martial_art_from_json.py msgid "You take your stance and prepare to receive the gift of violence." msgstr "" +"Adoptás tu postura y te preparás para recibir el regalo de la violencia." #. ~ initiate message for martial art '{'str': 'Wing Chun'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s patiently assumes a curiously pigeon-toed stance." -msgstr "" +msgstr "%s adopta pacientemente una postura curiosamente como una paloma." #: lang/json/martial_art_from_json.py msgid "Chain Punch" -msgstr "" +msgstr "Piña en Cadena" #. ~ Description of buff 'Chain Punch' for martial art '{'str': 'Wing Chun'}' #: lang/json/martial_art_from_json.py @@ -136386,10 +139394,14 @@ msgid "" "-10% move cost.\n" "Lasts 1 turn. Stacks 3 times." msgstr "" +"Tus trompadas tienen el ritmo apropiado para no darle a tu oponente ningún descanso de tus golpes.\n" +"\n" +"-10% al costo de movimiento.\n" +"Dura 1 turno. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Chi-Sao Sensitivity" -msgstr "" +msgstr "Sensibilidad Chi-Sao" #. ~ Description of buff 'Chi-Sao Sensitivity' for martial art '{'str': 'Wing #. Chun'}' @@ -136400,10 +139412,13 @@ msgid "" "\n" " Dodging Skill increased by 15% of Perception. Blocked damage reduced by 50% of Perception." msgstr "" +"Tenés una mayor comprensión del balance y la técnica. Esto te da mejor oportunidad de esquivar los ataques de tu oponente.\n" +"\n" +"Habilidad de Esquivar incrementada en un 15% de tu Percepción. Daño bloqueado reducido en un 50% de tu Percepción." #: lang/json/martial_art_from_json.py msgid "Biu Ji" -msgstr "" +msgstr "Biu Ji" #. ~ Description of buff 'Biu Ji' for martial art '{'str': 'Wing Chun'}' #: lang/json/martial_art_from_json.py @@ -136414,6 +139429,10 @@ msgid "" "Accuracy increased by 20% of Perception, Enables \"Straight Punch (Knockback)\" and \"L-Hook (Knockback)\" techniques.\n" "Lasts 2 turns." msgstr "" +"A través de la perfecta aplicación de la forma de Dedos Empujantes podés golpear los puntos débiles de tus oponentes, forzándolos a alejarse ¡y seguir!\n" +"\n" +"Precisión incrementada en un 20% de tu Percepción, Activa las técnicas \"Golpe Recto (Empujar)\" y \"Gancho (Empujar)\".\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Zui Quan" @@ -136428,21 +139447,26 @@ msgid "" " dodge, you inflict more damage with your counterattack for until the end of" " your next turn." msgstr "" +"También conocido como \"boxeo de borracho\", Zui Quan imita el movimiento de" +" un borracho para confundir al enemigo. Recibís un bonus pasivo a esquivar y" +" a la precisión basados en tu inteligencia. El movimiento te da un intento " +"adicional de esquivar y cada vez que esquivás un golpe, inflingís más daño " +"en tu contrataque hasta que termine tu próximo turno." #. ~ initiate message for martial art '{'str': 'Zui Quan'}' #: lang/json/martial_art_from_json.py msgid "You begin to sway to and fro with a confident swagger." -msgstr "" +msgstr "Empezás a moverte hacia adelante y atrás un poco canchereando." #. ~ initiate message for martial art '{'str': 'Zui Quan'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s stumbles as if pretending to be drunk." -msgstr "" +msgstr "%s se tropieza como si estuviera borracho." #: lang/json/martial_art_from_json.py msgid "Zui Quan Stance" -msgstr "" +msgstr "Postura de Zui Quan" #. ~ Description of buff 'Zui Quan Stance' for martial art '{'str': 'Zui #. Quan'}' @@ -136453,10 +139477,13 @@ msgid "" "\n" "Dodging Skill increased by 15% of Intelligence." msgstr "" +"Los otros pueden pensar que tus tropiezos son aleatorios pero vos sabés lo que hacés. Cada movimiento está calculado para evadir el daño de mejor manera.\n" +"\n" +"Habilidad de Esquivar incrementado en un 15% de tu Inteligencia." #: lang/json/martial_art_from_json.py msgid "Advanced Zui Quan" -msgstr "" +msgstr "Zui Quan Avanzado" #. ~ Description of buff 'Advanced Zui Quan' for martial art '{'str': 'Zui #. Quan'}' @@ -136467,10 +139494,13 @@ msgid "" "\n" "+1 Dodge attempts, Accuracy increased by 15% of Intelligence." msgstr "" +"Tenés una mayor comprensión del Zui Quan. Tus habilidades para esquivar y acertar goles es mucho mejor.\n" +"\n" +"+1 intentos de Esquivar. Precisión incrementado en un 15% de tu Inteligencia." #: lang/json/martial_art_from_json.py msgid "Drunken Stumble" -msgstr "" +msgstr "Tropiezo de Borracho" #. ~ Description of buff 'Drunken Stumble' for martial art '{'str': 'Zui #. Quan'}' @@ -136481,10 +139511,14 @@ msgid "" "+2 Dodge attempts.\n" "Lasts 3 turns." msgstr "" +"Con unos pocos pasos rápidos, cambiás completamente tu orientación y esquivás ataques adicionales.\n" +"\n" +"+2 intentos de Esquivar.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Drunken Dodging" -msgstr "" +msgstr "Esquive Borracho" #. ~ Description of buff 'Drunken Dodging' for martial art '{'str': 'Zui #. Quan'}' @@ -136496,6 +139530,10 @@ msgid "" "Gain Armor Penetration equal to 25% of Intelligence.\n" "Lasts 1 turn. Stacks 4 times." msgstr "" +"Cada vez que esquivás, tu ventaja posicional incrementa contra tus oponentes. Esto hace que tus ataques golpeen más fuerte con cada esquive exitoso.\n" +"\n" +"Recibís penetración de armadura igual al 25% de tu Inteligencia.\n" +"Dura 1 turno. Se acumula hasta 4 veces." #: lang/json/martial_art_from_json.py msgid "Debug Mastery" @@ -136511,13 +139549,13 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Debug Mastery'}' #: lang/json/martial_art_from_json.py msgid "You get ready pwn some zeds!" -msgstr "" +msgstr "¡Te preparás para golpear algunos zombis!" #. ~ initiate message for martial art '{'str': 'Debug Mastery'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s prepares to cheat at martial arts!" -msgstr "" +msgstr "%s se prepara para hacer trampa con las artes marciales!" #: lang/json/martial_art_from_json.py msgid "Elemental resistance" @@ -136536,7 +139574,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Getting Angry" -msgstr "" +msgstr "Enojándose" #. ~ Description of buff 'Getting Angry' for martial art '{'str': 'Debug #. Mastery'}' @@ -136544,10 +139582,12 @@ msgstr "" msgid "" "When I get my hands on you… +2 bash damage for 2 turns. Stacks 5 times." msgstr "" +"Cuando te ponga las manos encima… +2 al daño Golpeante durante 2 turnos. Se" +" acumula hasta 5 veces." #: lang/json/martial_art_from_json.py msgid "Lightning Strike" -msgstr "" +msgstr "Rayo Golpeante" #. ~ Description of buff 'Lightning Strike' for martial art '{'str': 'Debug #. Mastery'}' @@ -136556,11 +139596,13 @@ msgid "" "Lightning strikes twice. +Perception electric damage for 3 turns. Stacks 2" " times." msgstr "" +"El rayo golpea dos veces. + Percepción del daño eléctrico por 3 turnos. Se " +"acumula hasta 2 veces." #. ~ Description of buff 'On Fire' for martial art '{'str': 'Debug Mastery'}' #: lang/json/martial_art_from_json.py msgid "YOU ARE ON FIRE! +5 fire damage for 5 turns." -msgstr "" +msgstr "¡ESTÁS EN LLAMAS! +5 al daño de fuego por 5 turnos." #: lang/json/martial_art_from_json.py msgid "Bionic Combatives" @@ -136573,21 +139615,24 @@ msgid "" "Bionic Combatives combines integrated weaponry, armor and augments into an " "consolidated fighting discipline." msgstr "" +"Es un estilo de combate moderno para el humano post-moderno. Se lo apoda " +"\"Biojutsu\", el Combativo Biónico combina armamento, armadura y mejoras " +"integradas, en una disciplina de combate consolidada." #. ~ initiate message for martial art '{'str': 'Bionic Combatives'}' #: lang/json/martial_art_from_json.py msgid "BEGINNING BIONIC COMBATIVES PROGRAM. INITIATING COMBAT PROTOCOLS." -msgstr "" +msgstr "INICIAR PROGRAMA COMBATIVO BIÓNICO. INICIAR PROTOCOLOS DE COMBATE." #. ~ initiate message for martial art '{'str': 'Bionic Combatives'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s starts moving with swift robotic precision." -msgstr "" +msgstr "%s comienza a moverse con precisión robótica." #: lang/json/martial_art_from_json.py msgid "Biojutsu Stance" -msgstr "" +msgstr "Postura de Biojutsu" #. ~ Description of buff 'Biojutsu Stance' for martial art '{'str': 'Bionic #. Combatives'}' @@ -136600,10 +139645,16 @@ msgid "" "\n" "+2 Blocks attempts, +1 Accuracy." msgstr "" +"void player::ApplyBiojutsuStatic() {\n" +" blocks_left += 2;\n" +" set_hit_bonus( get_hit_bonus() + 1 );\n" +"}\n" +"\n" +"+2 intentos de Bloqueo, +1 Precisión." #: lang/json/martial_art_from_json.py msgid "Optimization" -msgstr "" +msgstr "Optimización" #. ~ Description of buff 'Optimization' for martial art '{'str': 'Bionic #. Combatives'}' @@ -136616,6 +139667,12 @@ msgid "" "+1 Accuracy, +2 all damage.\n" "Lasts 3 turns. Stacks 3 times." msgstr "" +">10 LOCALIZAR OBJETIVO\n" +">20 EJECUTAR OBJETIVO\n" +">30 GOTO 10\n" +"\n" +"+1 Precisión, +2 a todo el daño.\n" +"Dura 3 turnos. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Centipede Kung Fu" @@ -136628,21 +139685,25 @@ msgid "" " an onslaught of rapid strikes. Each attack you land increases your attack " "speed. Critical hits increase your damage further." msgstr "" +"Es uno de los Cinco Venenos Mortales, usado por Zhang Yiaoatian. El estilo " +"del Ciempiés usa arremetidas de golpes rápidos. Cada ataque exitoso que " +"hacés incrementa tu velocidad de ataque. Los golpes críticos incrementan más" +" tu daño." #. ~ initiate message for martial art '{'str': 'Centipede Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You ready yourself to attack as fast as possible." -msgstr "" +msgstr "Te preparás para atacar lo más rápido posible." #. ~ initiate message for martial art '{'str': 'Centipede Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a centipede-like stance." -msgstr "" +msgstr "%s adopta una postura similar a un ciempiés." #: lang/json/martial_art_from_json.py msgid "Centipede's Frenzy" -msgstr "" +msgstr "Frenesí de Ciempiés" #. ~ Description of buff 'Centipede's Frenzy' for martial art '{'str': #. 'Centipede Kung Fu'}' @@ -136653,10 +139714,14 @@ msgid "" "-4 move cost.\n" "Lasts 3 turns. Stacks 4 times." msgstr "" +"Tus ataques son un borrón de manos y piernas que se vuelve más rápido a medida que golpeás a tu oponente sin descanso.\n" +"\n" +"-4 al costo de movimiento.\n" +"Dura 3 turnos. Se acumula hasta 4 veces." #: lang/json/martial_art_from_json.py msgid "Centipede's Venom" -msgstr "" +msgstr "Veneno de Ciempiés" #. ~ Description of buff 'Centipede's Venom' for martial art '{'str': #. 'Centipede Kung Fu'}' @@ -136667,6 +139732,10 @@ msgid "" "+2 bashing damage.\n" "Lasts 2 turns." msgstr "" +"Tu veneno quema a tus oponentes de la peor manera.\n" +"\n" +"+2 al daño Golpeante.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Lizard Kung Fu" @@ -136680,21 +139749,26 @@ msgid "" "bonus to Dodge skill and moving near a wall gives a large bonus to accuracy." " Stronger techniques are enabled when near a wall." msgstr "" +"Es uno de los Cinco Venenos Mortales, usado por Meng Tianxia. El Estilo del " +"Lagarto se focaliza en usar las paredes como tu ventaja. Al pararte cerca de" +" una pared tenés un gran bonus a tu habilidad para Esquivar, y moverte cerca" +" de una pared te da un gran bonus a la precisión. Las técnicas más fuertes " +"son activadas cerca de una pared." #. ~ initiate message for martial art '{'str': 'Lizard Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You ready yourself to attack from any angle." -msgstr "" +msgstr "Te preparás para atacar desde cualquier ángulo." #. ~ initiate message for martial art '{'str': 'Lizard Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a lizard-like stance." -msgstr "" +msgstr "%s adopta una postura similar a un lagarto." #: lang/json/martial_art_from_json.py msgid "Lizard's Venom" -msgstr "" +msgstr "Veneno de Lagarto" #. ~ Description of buff 'Lizard's Venom' for martial art '{'str': 'Lizard #. Kung Fu'}' @@ -136705,10 +139779,14 @@ msgid "" "+2 bash damage.\n" "Lasts 4 turns." msgstr "" +"Tu veneno causa un dolor duradero que tus oponentes nunca olvidarán.\n" +"\n" +"+2 al daño Golpeante.\n" +"Dura 4 turnos." #: lang/json/martial_art_from_json.py msgid "Lizard's Cunning" -msgstr "" +msgstr "Astucia de Lagarto" #. ~ Description of buff 'Lizard's Cunning' for martial art '{'str': 'Lizard #. Kung Fu'}' @@ -136719,10 +139797,14 @@ msgid "" "+3.0 Dodge skill when near a wall.\n" "Enables \"Lizard Tail\" and \"Lizard Wall Counter\" techniques when near a wall." msgstr "" +"Al escalar, saltar o empujarte contra una pared brevemente, podés evitar la mayoría de los ataques de tus oponentes.\n" +"\n" +"+3.0 habilidad Esquivar cuando estás cerca de una pared.\n" +"Habilita las técnicas \"Cola de Lagarto\" y \"Contrataque de Pared de Lagarto\" cuando estás cerca de una pared." #: lang/json/martial_art_from_json.py msgid "Lizard's Leap" -msgstr "" +msgstr "Salto de Lagarto" #. ~ Description of buff 'Lizard's Leap' for martial art '{'str': 'Lizard Kung #. Fu'}' @@ -136733,6 +139815,10 @@ msgid "" "+3 Accuracy when near a wall.\n" "Lasts 3 turns." msgstr "" +"Al escalar, saltar o empujarte contra una pared, podés atacar hacia abajo a los oponentes distraídos.\n" +"\n" +"+3 Precisión cuando estás cerca de una pared.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Scorpion Kung Fu" @@ -136746,21 +139832,26 @@ msgid "" "enables a stunning pincer attack. Critical hits do massive damage and knock" " your opponent back along with anyone your opponent comes in contact with." msgstr "" +"Uno de los Cinco Venenos Mortales, usado por Gao Ji. El estilo del Escorpión" +" es un arte misterioso en el que se utiliza las manos como pinzas y una " +"patada de aguijón. Al moverte activás una patada de pinza aturdidora. Los " +"golpes críticos causan un daño masivo y empujan al enemigo y a todos con " +"quienes entre en contacto." #. ~ initiate message for martial art '{'str': 'Scorpion Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You prepare to capture and sting your foes." -msgstr "" +msgstr "Te preparás para capturar y picar a tus oponentes." #. ~ initiate message for martial art '{'str': 'Scorpion Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a scorpion-like stance." -msgstr "" +msgstr "%s adopta una postura similar a un escorpión." #: lang/json/martial_art_from_json.py msgid "Scorpion's Venom" -msgstr "" +msgstr "Veneno de Escorpión" #. ~ Description of buff 'Scorpion's Venom' for martial art '{'str': 'Scorpion #. Kung Fu'}' @@ -136770,10 +139861,13 @@ msgid "" "\n" "+2 bashing damage." msgstr "" +"Tu veneno es una amenaza constante de la que nadie podrá escapar.\n" +"\n" +"+2 daño Golpeante." #: lang/json/martial_art_from_json.py msgid "Scorpion's Charge" -msgstr "" +msgstr "Carga de Escorpión" #. ~ Description of buff 'Scorpion's Charge' for martial art '{'str': #. 'Scorpion Kung Fu'}' @@ -136786,10 +139880,15 @@ msgid "" "Enables \"Pincer Strike\" technique.\n" "Stacks 2 times. Lasts 2 turns." msgstr "" +"¡Lanzate y atrapá a tu presa!\n" +"\n" +"+10% al daño.\n" +"Habilita la técnica \"Golpe de Pinza\".\n" +"Dura 2 turnos. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Scorpion's Intimidation" -msgstr "" +msgstr "Intimidación de Esorpión" #. ~ Description of buff 'Scorpion's Intimidation' for martial art '{'str': #. 'Scorpion Kung Fu'}' @@ -136800,6 +139899,10 @@ msgid "" "+1 Dodge attempts.\n" "Lasts 1 turn." msgstr "" +"Nada causa más miedo que un escorpión enojado. Tus ataques pueden mantener a distancia a los demás.\n" +"\n" +"+1 intento de Esquivar.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Toad Kung Fu" @@ -136813,17 +139916,22 @@ msgid "" "armor against physical attacks, though you will lose focus when you move. " "You can meditate by pausing, giving yourself more armor for a short time." msgstr "" +"Uno de los Cinco Venenos Mortales, usado por Liang Shen. Los maestros del " +"Estilo del Sapo pueden enfocarse para protegerse contra todos los ataques. " +"Tenés una armadura poderosa contra los ataques físicos, aunque vas a perder " +"enfoque cuando te movés. Podés meditar al quedarte quieto, dándote más " +"armadura por un breve tiempo." #. ~ initiate message for martial art '{'str': 'Toad Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You pause for a moment and focus on your invincible body." -msgstr "" +msgstr "Frenás por un momento y te enfocás en tu invencible cuerpo." #. ~ initiate message for martial art '{'str': 'Toad Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a toad-like stance." -msgstr "" +msgstr "%s adopta una postura similar a una rana." #: lang/json/martial_art_from_json.py msgid "Toad's Iron Skin" @@ -136837,6 +139945,9 @@ msgid "" "\n" "+6 bash, cut, and stab armor." msgstr "" +"Tue cuerpo es tan fuerte como el hierro pero solo si no te movés.\n" +"\n" +"+6 a la armadura contra daño golpeante, cortante y punzante." #: lang/json/martial_art_from_json.py msgid "Iron Skin Dissipation" @@ -136851,10 +139962,14 @@ msgid "" "-1 bash, cut, and stab armor.\n" "Lasts 6 turns. Stacks 6 times." msgstr "" +"Moverte causa que pierdas tu piel de hierro.\n" +"\n" +"-1 a la armadura contra daño golpeante, cortante y punzante.\n" +"Dura 6 turnos. Se acumula hasta 6 veces." #: lang/json/martial_art_from_json.py msgid "Toad's Meditation" -msgstr "" +msgstr "Meditación de Rana" #. ~ Description of buff 'Toad's Meditation' for martial art '{'str': 'Toad #. Kung Fu'}' @@ -136865,10 +139980,14 @@ msgid "" "+3 bash, cut, and stab armor.\n" "Lasts 2 turns." msgstr "" +"Al concentrarte por un momento, podés reafirmar la fuerza de tu piel de hierro.\n" +"\n" +"+3 a la armadura contra daño golpeante, cortante y punzante.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Toad's Venom" -msgstr "" +msgstr "Veneno de Rana" #. ~ Description of buff 'Toad's Venom' for martial art '{'str': 'Toad Kung #. Fu'}' @@ -136879,6 +139998,10 @@ msgid "" "+2 bash damage.\n" "Lasts 5 turns." msgstr "" +"Tu veneno es solamente otra lección acerca de la fuerza de tu cuerpo de hierro.\n" +"\n" +"+2 al daño Golpeante.\n" +"Dura 5 turnos." #: lang/json/martial_art_from_json.py msgid "Viper Kung Fu" @@ -136892,21 +140015,25 @@ msgid "" "dodge, then follows up with a stunning Viper Bite and then finishes with the" " legendary Viper Strike." msgstr "" +"Un heredero de los Cinco Venenos Mortales, usado por Qi Dong. El Estilo de " +"la Víbora (llamado originalmente Estilo de la Serpiente) tiene un combo " +"único de tres partes, que comienza con esquivar un golpe, luego una " +"aturdidora Mordura de Víbora y termina con el legendario Golpe de Víbora." #. ~ initiate message for martial art '{'str': 'Viper Kung Fu'}' #: lang/json/martial_art_from_json.py msgid "You prepare to strike your foes' weaknesses." -msgstr "" +msgstr "Preparás para atacar las debilidades de tus enemigos." #. ~ initiate message for martial art '{'str': 'Viper Kung Fu'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes a viper-like stance." -msgstr "" +msgstr "%s adopta una postura similar a una víbora." #: lang/json/martial_art_from_json.py msgid "Viper's Patience" -msgstr "" +msgstr "Paciencia de Víbora" #. ~ Description of buff 'Viper's Patience' for martial art '{'str': 'Viper #. Kung Fu'}' @@ -136916,10 +140043,13 @@ msgid "" "\n" "+1.0 Dodge skill." msgstr "" +"Cada serpiente espera el momento perfecto para golpear. ¡Convertí los errores de tus oponentes en tu oportunidad para golpear!\n" +"\n" +"+1.0 habilidad de Esquivar." #: lang/json/martial_art_from_json.py msgid "Viper's Ambush" -msgstr "" +msgstr "Emboscada de Víbora" #. ~ Description of buff 'Viper's Ambush' for martial art '{'str': 'Viper Kung #. Fu'}' @@ -136930,10 +140060,14 @@ msgid "" "Enables \"Viper Bite\" technique.\n" "Lasts 1 turn." msgstr "" +"Tu evasión ha dejado a tu oponente disponible para una poderosa mordedura.\n" +"\n" +"Habilita la técnica \"Mordedura de Víbora\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Viper's Venom" -msgstr "" +msgstr "Veneno de Víbora" #. ~ Description of buff 'Viper's Venom' for martial art '{'str': 'Viper Kung #. Fu'}' @@ -136944,14 +140078,18 @@ msgid "" "+2 bash damage.\n" "Lasts 3 turn." msgstr "" +"Tu veneno es un duro recordatorio de nunca molestar a un depredador.\n" +"\n" +"+2 daño Golpeante.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Sojutsu" -msgstr "" +msgstr "Sojutsu" #: lang/json/martial_art_from_json.py msgid "CRIT Blade-work" -msgstr "" +msgstr "CRIT de Manejo de Cuchilla" #. ~ Description for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -136959,11 +140097,13 @@ msgid "" "An offensive style centered around rapid slashes and prodding. Each attack " "landed increases combat ability but leaves you increasingly vunerable" msgstr "" +"Es un estilo ofensivo centrado en los golpes rápidos y punzantes. Cada " +"ataque acertado incrementa la habilidad de combate pero te deja vulnerable." #. ~ initiate message for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py msgid "You prepare to whittle down your enemies." -msgstr "" +msgstr "Te preparás para reducir a tus enemigos." #. ~ initiate message for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -136973,7 +140113,7 @@ msgstr "%s inicia el manejo de cuchilla." #: lang/json/martial_art_from_json.py msgid "Unwavering Edge" -msgstr "" +msgstr "Filo Firme" #. ~ Description of buff 'Unwavering Edge' for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -136981,10 +140121,13 @@ msgid "" "Gain minor Accuracy, Cutting and Stabbing Arpen per stack. Greatly reduces " "dodge skill. 2 stacks max" msgstr "" +"Recibís un poco de Precisión, penetración de armadura contra daño Cortante y" +" Punzante por vez. Reduce mucho la habilidad de Esquivar. Se acumula hasta 2" +" veces." #: lang/json/martial_art_from_json.py msgid "Ruthlessness" -msgstr "" +msgstr "Impiedad" #. ~ Description of buff 'Ruthlessness' for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -136992,10 +140135,12 @@ msgid "" "Additional Stabbing and Cutting damage per stack. Reduces dodge attempts. 4" " stacks max." msgstr "" +"Daño Punzante y Cortante adicionales por vez. Reduce los intentos de " +"Esquivar. Se acumula hasta 4 veces." #: lang/json/martial_art_from_json.py msgid "Rending Strikes" -msgstr "" +msgstr "Golpes Desgarradores" #. ~ Description of buff 'Rending Strikes' for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -137003,10 +140148,12 @@ msgid "" "Additional Armor penetration per stack. Further reduces dodge attempts. 3 " "stacks max." msgstr "" +"Penetración de armadura adicional por vez. Reduce más los intentos de " +"Esquivar. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Calculating Eyes" -msgstr "" +msgstr "Ojos Calculadores" #. ~ Description of buff 'Calculating Eyes' for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -137015,10 +140162,13 @@ msgid "" "weaponry. Gain great Cutting and Stabbing Armor Penetration on top of minor " "Accuracy" msgstr "" +"Te han enseñado a utilizar apropiadamente armas de filo pequeñas o medianas." +" Recibís mucha penetración de armadura Cortante y Punzante y un poco de " +"Precisión." #: lang/json/martial_art_from_json.py msgid "Honed Movements" -msgstr "" +msgstr "Movimientos Pulidos" #. ~ Description of buff 'Honed Movements' for martial art 'CRIT Blade-work' #: lang/json/martial_art_from_json.py @@ -137026,10 +140176,12 @@ msgid "" "Your skill and handling with sharp weaponry has improved. Gain extra Cutting" " and Stabbing damage." msgstr "" +"Tu habilidad y manejo de las armas con filo ha mejorado. Ganás más daño " +"Cortante y Punzante." #: lang/json/martial_art_from_json.py msgid "C.R.I.T Enforcement" -msgstr "" +msgstr "C.R.I.T. de Ejecución" #. ~ Description for martial art 'C.R.I.T Enforcement' #: lang/json/martial_art_from_json.py @@ -137038,30 +140190,34 @@ msgid "" "grounding enemies. Each attack landed increases your armor by 0.125 and " "offers other combat bonuses based on stats." msgstr "" +"Es un estilo defensivo centrado en golpes aturdidores, empujes y derribar " +"enemigos. Cada ataque acertado incrementa tu armadura en 0.125 y ofrece " +"otros bonus al combate basado en estadísticas." #. ~ initiate message for martial art 'C.R.I.T Enforcement' #: lang/json/martial_art_from_json.py msgid "You ready yourself to stand your ground." -msgstr "" +msgstr "Te preparás para mantenerte firme." #. ~ initiate message for martial art 'C.R.I.T Enforcement' #: lang/json/martial_art_from_json.py #, python-format msgid "%s draws a line in the sand." -msgstr "" +msgstr "%s dibuja una línea en la arena." #: lang/json/martial_art_from_json.py msgid "Bulwark" -msgstr "" +msgstr "Baluarte" #. ~ Description of buff 'Bulwark' for martial art 'C.R.I.T Enforcement' #: lang/json/martial_art_from_json.py msgid "+0.5 armor and other small bonuses per stack. Max of 2 stacks" msgstr "" +"+0.5 en armadura y otros pequeños bonus por vez. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Unyielding Front" -msgstr "" +msgstr "Frente Inflexible" #. ~ Description of buff 'Unyielding Front' for martial art 'C.R.I.T #. Enforcement' @@ -137070,10 +140226,12 @@ msgid "" "Stand strong in the face of adversity. +1 armor. STR provides accuracy and " "minor bash arpen." msgstr "" +"Mantenete fuerte ante la adversidad. +1 de armadura. La Fuerza brinda " +"Precisión y un poco de penetración de armadura contra golpes." #: lang/json/martial_art_from_json.py msgid "CRIT CQB" -msgstr "" +msgstr "CRIT de Pelea en Espacios Cerrados" #. ~ Description for martial art 'CRIT CQB' #: lang/json/martial_art_from_json.py @@ -137081,31 +140239,35 @@ msgid "" "A style centered around rapid strikes and piercing jabs. Each attack landed" " adds a plethora of combat bonuses." msgstr "" +"Es un estilo centrado en golpes rápidos y trompadas penetrantes. Cada ataque" +" acertado agrega una gran cantidad de bonus al combate." #. ~ initiate message for martial art 'CRIT CQB' #: lang/json/martial_art_from_json.py msgid "You shift your weight for the oncoming fight." -msgstr "" +msgstr "Establecés el peso de tu cuerpo para la pelea que se viene." #. ~ initiate message for martial art 'CRIT CQB' #: lang/json/martial_art_from_json.py #, python-format msgid "%s prepares for hand-to-hand battle." -msgstr "" +msgstr "%s se prepara para la pelea mano a mano." #: lang/json/martial_art_from_json.py msgid "Fluid Tenacity" -msgstr "" +msgstr "Tenacidad Fluida" #. ~ Description of buff 'Fluid Tenacity' for martial art 'CRIT CQB' #: lang/json/martial_art_from_json.py msgid "" "+Atk Speed and other small bonuses based on DEX per stack. Max of 5 stacks" msgstr "" +"+ Velocidad de ataque y otros pequeños bonus basados en la Destreza por vez." +" Se acumula hasta 5 veces." #: lang/json/martial_art_from_json.py msgid "Tactful Initiative" -msgstr "" +msgstr "Iniciativa Discreta" #. ~ Description of buff 'Tactful Initiative' for martial art 'CRIT CQB' #: lang/json/martial_art_from_json.py @@ -137113,6 +140275,9 @@ msgid "" "You have gained an advantage by always remaing mindful of common weaknesses." " DEX provides dodge ability, accuracy and armor penetration." msgstr "" +"Ganaste una ventaja al permanecer atento a las debilidades comunes. La " +"Destreza brinda habilidad para Esquivar, Precisión y penetración de " +"armadura." #: lang/json/martial_art_from_json.py msgid "Desert Wind" @@ -137137,16 +140302,18 @@ msgstr "" msgid "" "You feel a wave of heat wash over you as you assume a running combat stance." msgstr "" +"Sentís una ola de calor que te baña mientras adoptás la postura de combate " +"corriendo." #. ~ initiate message for martial art '{'str': 'Desert Wind'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s assumes into a running combat stance." -msgstr "" +msgstr "%s adopta la postura de combate corriendo." #: lang/json/martial_art_from_json.py msgid "Wind Stride" -msgstr "" +msgstr "Zancada de Viento" #. ~ Description of buff 'Wind Stride' for martial art '{'str': 'Desert #. Wind'}' @@ -137157,10 +140324,14 @@ msgid "" "+1.0 Dodging skill.\n" "Lasts 1 turn." msgstr "" +"Una brisa tibia gira alrededor tuyo mientras te movés rápidamente.\n" +"\n" +"+1.0 habilidad Esquivar.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Zephyr Dance" -msgstr "" +msgstr "Danza Céfiro" #. ~ Description of buff 'Zephyr Dance' for martial art '{'str': 'Desert #. Wind'}' @@ -137171,6 +140342,10 @@ msgid "" "+1.0 Dodging skill, +1 Dodge attempt\n" "Lasts 1 turn." msgstr "" +"Girás grácilmente y te alejás de los ataques, dando vueltas como un céfiro del desierto corriendo por la arena.\n" +"\n" +"+1.0 habilidad Esquivar, +1 intentos de Esquivar\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Diamond Mind" @@ -137196,17 +140371,17 @@ msgstr "" #. ~ initiate message for martial art '{'str': 'Diamond Mind'}' #: lang/json/martial_art_from_json.py msgid "You concentrate and become very still for a moment." -msgstr "" +msgstr "Te concentrás y te quedás muy quieto por un momento." #. ~ initiate message for martial art '{'str': 'Diamond Mind'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s becomes very still for a moment." -msgstr "" +msgstr "%s se queda muy quieto por un momento." #: lang/json/martial_art_from_json.py msgid "Stance of Alacrity" -msgstr "" +msgstr "Postura de Celeridad" #. ~ Description of buff 'Stance of Alacrity' for martial art '{'str': #. 'Diamond Mind'}' @@ -137217,10 +140392,13 @@ msgid "" "\n" "-10% move cost" msgstr "" +"Te movés un poco más rápido de lo normal debido a una combinación de confianza y claridad de la mente. Esta leve ventaja se acumula en cada acción\n" +"\n" +"-10% al costo de movimiento." #: lang/json/martial_art_from_json.py msgid "Pearl of Black Doubt" -msgstr "" +msgstr "Perla de Duda Negra" #. ~ Description of buff 'Pearl of Black Doubt' for martial art '{'str': #. 'Diamond Mind'}' @@ -137231,10 +140409,14 @@ msgid "" "+1 Dodge attempt\n" "Lasts 1 turn. Stacks 2 times" msgstr "" +"Con cada fallo, tus oponentes se vuelven más inseguros, su duda crece como una perla irritante en la boca de una ostra desamparada.\n" +"\n" +"+1 intentos de Esquivar.\n" +"Dura 1 turno. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Quicksilver Motion" -msgstr "" +msgstr "Movimiento de Mercurio" #. ~ Description of buff 'Quicksilver Motion' for martial art '{'str': #. 'Diamond Mind'}' @@ -137245,10 +140427,14 @@ msgid "" "+50 Speed.\n" "Lasts 1 turn." msgstr "" +"En un abrir y cerrar de ojos, hacés tu movimiento. Tu velocidad, reflejos y confianza ilimitada se combinan para permitirte hacer movimientos rápidos y osados que agarran a tus enemigos con la guardia baja.\n" +"\n" +"+50 a Velocidad.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Mind over Body" -msgstr "" +msgstr "Mente sobre Cuerpo" #. ~ Description of buff 'Mind over Body' for martial art '{'str': 'Diamond #. Mind'}' @@ -137259,10 +140445,14 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn. Stacks 2 times" msgstr "" +"Tu entrenamiento y resistencia mental te permiten usar tu enfoque para sobreponerte a las amenazas físicas.\n" +"\n" +"+1 Precisión.\n" +"Dura 1 turno. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Hylian Swordsmanship" -msgstr "" +msgstr "Espadachín Hyliano" #. ~ Description for martial art '{'str': 'Hylian Swordsmanship'}' #: lang/json/martial_art_from_json.py @@ -137272,21 +140462,25 @@ msgid "" "defense by using spins, jumps, and flips to confuse enemies and strike from " "unexpected angles." msgstr "" +"Esta extraña forma de combate ha sido practicada por muchos héroes " +"legendarios a través de los años. El Espadachín Hyliano favorece la " +"movilidad para la ofensiva y la defensa usando giros, saltos y vueltas para " +"confundir a los enemigos y golpearlos desde ángulos inesperados." #. ~ initiate message for martial art '{'str': 'Hylian Swordsmanship'}' #: lang/json/martial_art_from_json.py msgid "You begin to step lightly from side to side." -msgstr "" +msgstr "Empezás a moverte ágilmente de un lado a otro." #. ~ initiate message for martial art '{'str': 'Hylian Swordsmanship'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s begins to step lightly from side to side." -msgstr "" +msgstr "%s empieza a moverse ágilmente de un lado a otro." #: lang/json/martial_art_from_json.py msgid "Combat Acrobat" -msgstr "" +msgstr "Acróbata de Combate" #. ~ Description of buff 'Combat Acrobat' for martial art '{'str': 'Hylian #. Swordsmanship'}' @@ -137296,10 +140490,13 @@ msgid "" "\n" "+1.0 Dodging skill." msgstr "" +"Siempre te mantenés agíl de pies. Es mejor esquivar que ser golpeado.\n" +"\n" +"+1.0 habilidad Esquivar." #: lang/json/martial_art_from_json.py msgid "Intermediate Combat Acrobat" -msgstr "" +msgstr "Acróbata Intermedio de Combate" #. ~ Description of buff 'Intermediate Combat Acrobat' for martial art #. '{'str': 'Hylian Swordsmanship'}' @@ -137309,10 +140506,13 @@ msgid "" "\n" "+1.0 Dodging skill." msgstr "" +"Después de mucha práctica, te has vuelto incluso más ágil en combate.\n" +"\n" +"+1.0 habilidad Esquivar." #: lang/json/martial_art_from_json.py msgid "Master Combat Acrobat" -msgstr "" +msgstr "Acróbata Maestro de Combate" #. ~ Description of buff 'Master Combat Acrobat' for martial art '{'str': #. 'Hylian Swordsmanship'}' @@ -137322,10 +140522,13 @@ msgid "" "\n" "+1.0 Dodging skill." msgstr "" +"¡Has visto tanto combate que tu habilidad para esquivar se ha vuelto de excelencia!\n" +"\n" +"+1.0 habilidad Esquivar." #: lang/json/martial_art_from_json.py msgid "Dash Attack" -msgstr "" +msgstr "Ataque Lanzado" #. ~ Description of buff 'Dash Attack' for martial art '{'str': 'Hylian #. Swordsmanship'}' @@ -137337,10 +140540,14 @@ msgid "" "+10% damage.\n" "Lasts 1 turn. Stacks 3 times." msgstr "" +"Sacando ventaja del impulso, te lanzás contra los enemigos para meter un golpe potente.\n" +"\n" +"+10% al daño.\n" +"Dura 1 turno. Se acumula hasta 3 veces." #: lang/json/martial_art_from_json.py msgid "Flurry Rush" -msgstr "" +msgstr "Ráfaga Apurada" #. ~ Description of buff 'Flurry Rush' for martial art '{'str': 'Hylian #. Swordsmanship'}' @@ -137352,10 +140559,14 @@ msgid "" "-25% move cost.\n" "Lasts 1 turn." msgstr "" +"Cuando esquivás perfectamente un ataque, podés atacar rápidamente por un breve tiempo.\n" +"\n" +"-25% al costo de movimiento.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Charge Up" -msgstr "" +msgstr "Cargar" #. ~ Description of buff 'Charge Up' for martial art '{'str': 'Hylian #. Swordsmanship'}' @@ -137367,10 +140578,14 @@ msgid "" "+20% damage, enables \"Spin Attack\" technique.\n" "Lasts 1 turn." msgstr "" +"Tomándote un momento para prepararte, ¡podés desplegar un ataque fuerte y giratorio!\n" +"\n" +"+20% al daño, habilita la técnica \"Ataque Giratorio\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Iron Heart" -msgstr "" +msgstr "Corazón de Hierro" #. ~ Description for martial art '{'str': 'Iron Heart'}' #: lang/json/martial_art_from_json.py @@ -137381,21 +140596,26 @@ msgid "" "of uncanny martial skill—weaving patterns of steel that dizzy, confuse, and " "ultimately kill with no recourse." msgstr "" +"El objetivo de la disciplina Corazón de Hierro es el dominio absoluto de la " +"espada. A través de prácticas y estudios interminables, el estudiante de " +"Corazón de Hierro consigue habilidades superhumanas con sus armas. Sus " +"maniobras son demostraciones de una habilidad marcial asombrosa -patrones " +"entrelazados de acero que marean, confunden y finalmente matan sin remedio." #. ~ initiate message for martial art '{'str': 'Iron Heart'}' #: lang/json/martial_art_from_json.py msgid "You push away your fear and stand tall." -msgstr "" +msgstr "Alejás tu miedo y te parás altanero." #. ~ initiate message for martial art '{'str': 'Iron Heart'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s takes a bold and fearless stance." -msgstr "" +msgstr "%s adopta una postura intrépida y valiente." #: lang/json/martial_art_from_json.py msgid "Panzer Kunst" -msgstr "" +msgstr "Panzer Kunst" #. ~ Description for martial art '{'str': 'Panzer Kunst'}' #: lang/json/martial_art_from_json.py @@ -137403,21 +140623,23 @@ msgid "" "Panzer Kunst or \"Armor Art\" is a futuristic martial art devised for " "cyborgs fighting in zero-gravity environments." msgstr "" +"Panzer Kunst o \"Arte de Armadura\" es una arte marcial futurista concebida " +"para ciborgs peleando en ambientes de gravedad cero." #. ~ initiate message for martial art '{'str': 'Panzer Kunst'}' #: lang/json/martial_art_from_json.py msgid "You adopt a panzer kunst stance." -msgstr "" +msgstr "Adoptás la postura de panzer kunst." #. ~ initiate message for martial art '{'str': 'Panzer Kunst'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s adopts a panzer kunst stance." -msgstr "" +msgstr "%s adopta la postura de panzer kunst." #: lang/json/martial_art_from_json.py msgid "Schatten Folgen" -msgstr "" +msgstr "Schatten Folgen" #. ~ Description of buff 'Schatten Folgen' for martial art '{'str': 'Panzer #. Kunst'}' @@ -137429,10 +140651,14 @@ msgid "" "\n" "+1 Dodge attemps, Dodge Skill increased by 12%% of Perception." msgstr "" +"\"Rastreo Sombrío\"\n" +"Como un künstler, estás entrenado para mantenerte en el punto ciego de tu objetivo.\n" +"\n" +"+1 intentos de Esquivar, Habilidad Esquivar incrementada en%% de tu Percepción." #: lang/json/martial_art_from_json.py msgid "Einzug Rüstungen" -msgstr "" +msgstr "Einzug Rüstungen" #. ~ Description of buff 'Einzug Rüstungen' for martial art '{'str': 'Panzer #. Kunst'}' @@ -137443,10 +140669,14 @@ msgid "" "+5 bash Armor Penetration.\n" "Lasts 2 turns." msgstr "" +"\"Penetración de Armadura\"\n" +"Al armonizar con el ritmo de tu oponente, podés golpearlo cuando su guardia sea más débil.\n" +"+5 penetración de armadura contra Golpe.\n" +"Dura 2 turnos." #: lang/json/martial_art_from_json.py msgid "Pokken" -msgstr "" +msgstr "Pokken" #. ~ Description for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -137457,21 +140687,27 @@ msgid "" "arts such as boxing and karate. Amazingly, it actually works. Some might " "even say it's a super effective way to fight." msgstr "" +"Pokkén o \"Puño Bolsillo\" es una extraña arte marcial desarrollada por la " +"famosa serie de videojuegos Pokémon. De alguna manera, un grupo de fanáticos" +" dedicados lograron combinar los movimientos usados por varios pokemones con" +" múltiples artes marciales existentes como el boxeo y el karate. De manera " +"sorprendente, funciona. Algunos incluso dirán que es una manera " +"superefectiva de pelear." #. ~ initiate message for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py msgid "You get ready to battle." -msgstr "" +msgstr "Te preparás para la batalla." #. ~ initiate message for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s is about to challenge someone to a battle." -msgstr "" +msgstr "%s está por desafiar a alguien a pelear." #: lang/json/martial_art_from_json.py msgid "Stamina" -msgstr "" +msgstr "Resistencia" #. ~ Description of buff 'Stamina' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -137482,10 +140718,14 @@ msgid "" "Gain bash, cut, stab armor equal to 50% of Strength.\n" "Lasts 3 turns." msgstr "" +"Estimula tu defensa después de que recibís un golpe.\n" +"\n" +"Recibís armadura contra golpe, corte y penetración igual a un 50% de tu Fuerza.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Sniper" -msgstr "" +msgstr "Francotirador" #. ~ Description of buff 'Sniper' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -137496,10 +140736,14 @@ msgid "" "+50% damage.\n" "Lasts 1 turn." msgstr "" +"Activa técnicas después de que hayas realizado un golpe crítico.\n" +"\n" +"+50% al daño.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Moxie" -msgstr "" +msgstr "Agallas" #. ~ Description of buff 'Moxie' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -137510,10 +140754,14 @@ msgid "" "+50% damage.\n" "Lasts 3 turns." msgstr "" +"Aumenta tu daño después de vencer a un oponente.\n" +"\n" +"+50% al daño.\n" +"Dura 3 turnos." #: lang/json/martial_art_from_json.py msgid "Setting Sun" -msgstr "" +msgstr "Sol Poniente" #. ~ Description for martial art '{'str': 'Setting Sun'}' #: lang/json/martial_art_from_json.py @@ -137523,21 +140771,25 @@ msgid "" "attack, a Setting Sun warrior sends a charging enemy tumbling in a new " "direction." msgstr "" +"La disciplina Sol Poniente enseña a sus iniciados a convertir la fuerza del " +"oponente en contra de ellos mismos. Con un rápido cambio de postura y un " +"ataque cuidadoso, un luchador de Sol Poniente recibe un enemigo atacando y " +"lo envía tropezando hacia otra dirección." #. ~ initiate message for martial art '{'str': 'Setting Sun'}' #: lang/json/martial_art_from_json.py msgid "You shift your weight and prepare to defend yourself." -msgstr "" +msgstr "Establecés el peso de tu cuerpo para defenderte." #. ~ initiate message for martial art '{'str': 'Setting Sun'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s shifts their weight and assumes a new stance." -msgstr "" +msgstr "%s establece el peso de su cuerpo y adopta una nueva postura." #: lang/json/martial_art_from_json.py msgid "Baffling Defense" -msgstr "" +msgstr "Defensa Desconcertante" #. ~ Description of buff 'Baffling Defense' for martial art '{'str': 'Setting #. Sun'}' @@ -137549,10 +140801,14 @@ msgid "" "Dodging Skill increased by 20% of Intelligence, enables \"Mighty Throw\" and \"Ballista Throw\" techniques.\n" "Lasts 1 turn." msgstr "" +"Intencionalmente, te movés y posicionás de manera extraña para confundir y descolocar a tus oponentes.\n" +"\n" +"Habilidad de Esquivar incrementada en un 20% de tu Inteligencia, activa las técnicas \"Tirada Poderosa\" y \"Tirada de Balista\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Feigned Opening" -msgstr "" +msgstr "Apertura Falsa" #. ~ Description of buff 'Feigned Opening' for martial art '{'str': 'Setting #. Sun'}' @@ -137563,10 +140819,14 @@ msgid "" "+20 Speed.\n" "Lasts 1 turn." msgstr "" +"Al bajar intencionalmente tu guardia, forzás a tu oponente a sobreextenderse y ¡podés sacar ventaja de tu próximo ataque!\n" +"\n" +"+20 Velocidad.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Shii-Cho" -msgstr "" +msgstr "Shii-Cho" #. ~ Description for martial art '{'str': 'Shii-Cho'}' #: lang/json/martial_art_from_json.py @@ -137577,19 +140837,25 @@ msgid "" " understand the basics of armed combat. Shii-Cho excels at fighting against" " groups but lacks the offensive power of the other lightsaber forms." msgstr "" +"Shii-Cho, \"El camino del Sarlacc\" fue la primera forma de combate con " +"sable de luz desarrollado por los Jedi durante su transición de las armas de" +" metal a las de luz. Shii-Cho es considerado una forma de entrenamiento que " +"todos los Jedi aprenden a entender las bases del combate armado. Shii-Cho se" +" distingue en la lucha contra grupos pero carece de potencia ofensiva para " +"otras formas de sable." #. ~ initiate message for martial art '{'str': 'Shii-Cho'}' #: lang/json/martial_art_from_json.py msgid "" "You place one foot back and hold your weapon vertically on your dominant " "side." -msgstr "" +msgstr "Ponés un pie atrás y sostenés tu arma vertical en tu lado dominante." #. ~ initiate message for martial art '{'str': 'Shii-Cho'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s places one foot back and hold their weapon vertically." -msgstr "" +msgstr "%s pone un pie atrás y sostiene su arma verticalmente." #. ~ Description of buff 'Determination' for martial art '{'str': 'Shii-Cho'}' #: lang/json/martial_art_from_json.py @@ -137599,10 +140865,13 @@ msgid "" "\n" "Blocked damage reduced by 100% of Strength, +1 Accuracy." msgstr "" +"Sos un guerrero determinado. Tu calma interna te ayuda a acertar tus golpes y protegerte.\n" +"\n" +"Daño bloqueado reducido en un 100% de tu Fuerza, +1 Precisión." #: lang/json/martial_art_from_json.py msgid "Apprentice Training" -msgstr "" +msgstr "Entrenamiento de Aprendiz" #. ~ Description of buff 'Apprentice Training' for martial art '{'str': 'Shii- #. Cho'}' @@ -137612,10 +140881,13 @@ msgid "" "\n" "+1 block attempts, +1 block effectiveness." msgstr "" +"Tu entrenamiento en Shii-Cho te enseña cómo combatir contra múltiples oponentes.\n" +"\n" +"+1 intentos de Bloqueo, +1 efectividad de Bloqueo." #: lang/json/martial_art_from_json.py msgid "Knight Training" -msgstr "" +msgstr "Entrenamiento de Caballero" #. ~ Description of buff 'Knight Training' for martial art '{'str': 'Shii- #. Cho'}' @@ -137625,10 +140897,13 @@ msgid "" "\n" "+1 block attempts, +1 block effectiveness." msgstr "" +"El entrenamiento más avanzado en Shii-Cho mejora tu habilidad en el combate contra múltiples oponentes.\n" +"\n" +"+1 intentos de Bloqueo, +1 efectividad de Bloqueo." #: lang/json/martial_art_from_json.py msgid "Master Training" -msgstr "" +msgstr "Entrenamiento Maestro" #. ~ Description of buff 'Master Training' for martial art '{'str': 'Shii- #. Cho'}' @@ -137638,10 +140913,13 @@ msgid "" "\n" "+1 block attempts, +1 block effectiveness." msgstr "" +"Como maestro del Shii-Cho, tu habilidad para pelear contra grupos es insuperable.\n" +"\n" +"+1 intentos de Bloqueo, +1 efectividad de Bloqueo." #: lang/json/martial_art_from_json.py msgid "Stone Dragon" -msgstr "" +msgstr "Dragón de Piedra" #. ~ Description for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py @@ -137651,21 +140929,26 @@ msgid "" "single, focused blow. Stone Dragon's defensive abilities focus on tapping " "into the enduring power of stone to turn aside attacks." msgstr "" +"La disciplina del Dragón de Piedra se focaliza en la fuerza, potencia y " +"fortaleza. Sus enseñanzas otorgan al experto marcial la habilidad de romper " +"el acero con un solo golpe focalizado. Las habilidades defensivas del Dragón" +" de Piedra se focaliza en otorgar acceso al poder de resistencia de la " +"piedra para desviar ataques." #. ~ initiate message for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py msgid "You dig your heels into the ground and steady yourself." -msgstr "" +msgstr "Clavás tus talones en el suelo y te mantenés firme." #. ~ initiate message for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s digs their heels into the ground." -msgstr "" +msgstr "%s clava sus talones en el suelo." #: lang/json/martial_art_from_json.py msgid "Stone Bones" -msgstr "" +msgstr "Huesos de Piedra" #. ~ Description of buff 'Stone Bones' for martial art '{'str': 'Stone #. Dragon'}' @@ -137676,10 +140959,14 @@ msgid "" "+1 bash, cut, and stab armor.\n" "Lasts 1 turn. Stacks 5 times." msgstr "" +"Focalizás tu energía en mejorar tus defensas, extrayendo el poder del impacto de tu arma para fortalecerte contra un contrataque.\n" +"\n" +"+1 armardura Golpeante, Cortante y Penetrante.\n" +"Dura 1 turno. Se acumula hasta 5 veces." #: lang/json/martial_art_from_json.py msgid "Stonefoot Stance" -msgstr "" +msgstr "Postura Pie Pétreo" #. ~ Description of buff 'Stonefoot Stance' for martial art '{'str': 'Stone #. Dragon'}' @@ -137690,10 +140977,13 @@ msgid "" "\n" "+10% damage, +2 bash, cut, and stab armor." msgstr "" +"Te agachás y establecés tus pies en el suelo, extrayendo la resiliencia de la tierra a tu cuerpo. Sin embargo, si te movés mucho perdés tu postura.\n" +"\n" +"+10% al daño, +2 armadura Golpeante, Cortante y Punzante." #: lang/json/martial_art_from_json.py msgid "Cracked Stone" -msgstr "" +msgstr "Piedra Agrietada" #. ~ Description of buff 'Cracked Stone' for martial art '{'str': 'Stone #. Dragon'}' @@ -137704,10 +140994,14 @@ msgid "" "Enables \"Shattered Stone\" buff.\n" "Lasts 1 turn." msgstr "" +"Moverte mucho negará los efectos de la Postura de Pie Seguro. ¡Quedate quieto para evitar romper tu postura!\n" +"\n" +"Habilita la técnica \"Piedra Destruida\".\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Stattered Stone" -msgstr "" +msgstr "Piedra Destruida" #. ~ Description of buff 'Stattered Stone' for martial art '{'str': 'Stone #. Dragon'}' @@ -137719,10 +141013,14 @@ msgid "" "-10% damage, -2 bash, cut, and stab armor.\n" "Lasts 4 turn." msgstr "" +"No sos capaz de mantener tu Postura de Pie Seguro y tenés que dejar de moverte por un breve tiempo para volver a recibir sus beneficios.\n" +"\n" +"-10% al daño, -2 armadura Golpeante, Cortante y Punzante.\n" +"Dura 4 turnos." #: lang/json/martial_art_from_json.py msgid "Iron Bones" -msgstr "" +msgstr "Huesos de Hierro" #. ~ Description of buff 'Iron Bones' for martial art '{'str': 'Stone #. Dragon'}' @@ -137733,10 +141031,14 @@ msgid "" "+5 bash, cut, and stab armor.\n" "Lasts 1 turn." msgstr "" +"Cuando lográs un ataque exitoso, entrás en un estado de meditación que te deja casi invulnerable al daño.\n" +"\n" +"+5 armadura Golpeante, Cortante y Punzante.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Tiger Claw" -msgstr "" +msgstr "Garra de Tigre" #. ~ Description for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py @@ -137746,21 +141048,25 @@ msgid "" "with a furry similar to that of a barbarian, and rely on overwhelming, " "vicious assaults to defeat their enemies." msgstr "" +"La disciplina de la Garra de Tigre aprovecha la furia salvaje que acecha en " +"el corazón de los iniciados. En la batalla, esos guerreros rugirán como " +"animales salvajes, atacarán con una furia similar a la de los bárbaros, y " +"dependerán de sus asaltos aplastantes y despiadados para derrotar enemigos." #. ~ initiate message for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py msgid "You emit a low growl as you prepare for battle." -msgstr "" +msgstr "Emitís un rugido bajo al prepararte para la batalla." #. ~ initiate message for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s hunkers down like a wild animal." -msgstr "" +msgstr "%s se agacha como un animal salvaje." #: lang/json/martial_art_from_json.py msgid "Improved Critical" -msgstr "" +msgstr "Golpe Crítico Mejorado" #. ~ Description of buff 'Improved Critical' for martial art '{'str': 'Tiger #. Claw'}' @@ -137771,10 +141077,13 @@ msgid "" "\n" "+5% critical hit chance." msgstr "" +"Siempre golpeá con toda la fuerza. Nunca te guardes nada salvo que quieras morir.\n" +"\n" +"+5% a la probabilidad de golpe crítico." #: lang/json/martial_art_from_json.py msgid "Pounching Charge" -msgstr "" +msgstr "Ataque de Trompada" #. ~ Description of buff 'Pounching Charge' for martial art '{'str': 'Tiger #. Claw'}' @@ -137786,10 +141095,14 @@ msgid "" "+2 Accuracy, +10% damage.\n" "Lasts 1 turn." msgstr "" +"Con el rugido de una bestia salvaje, te lanzás a la refriega. Golpeá primero y golpeá fuerte.\n" +"\n" +"+2 Precisión, +10% al daño.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Cornered Predator" -msgstr "" +msgstr "Depredador Acorralado" #. ~ Description of buff 'Cornered Predator' for martial art '{'str': 'Tiger #. Claw'}' @@ -137801,10 +141114,14 @@ msgid "" "-20% move cost.\n" "Lasts 1 turn." msgstr "" +"Un animal acorralado es una criatura terrorífica y peligrosa. A vos te pasa lo mismo.\n" +"\n" +"-20% al costo de movimiento.\n" +"Dura 1 turno." #: lang/json/martial_art_from_json.py msgid "Blood In The Water" -msgstr "" +msgstr "Sangre En El Agua" #. ~ Description of buff 'Blood In The Water' for martial art '{'str': 'Tiger #. Claw'}' @@ -137816,10 +141133,14 @@ msgid "" "+1 Accuracy, +15% damage.\n" "Lasts 1 turn. Stacks 2 times." msgstr "" +"El olor de la sangre te hace ponerte loco. Querés más. ¡AHORA!\n" +"\n" +"+1 Precisión, +15% al daño.\n" +"Dura 1 turno. Se acumula hasta 2 veces." #: lang/json/martial_art_from_json.py msgid "Prey on the Weak" -msgstr "" +msgstr "Presa Débil" #. ~ Description of buff 'Prey on the Weak' for martial art '{'str': 'Tiger #. Claw'}' @@ -137830,6 +141151,10 @@ msgid "" "+30 Speed.\n" "Lasts 2 turns. Stacks 2 times" msgstr "" +"Cortás a través de los enemigos más débiles como un poderoso depredador suelto entre una horda de presas.\n" +"\n" +"+30 Velocidad.\n" +"Dura 2 turnos. Se acumula hasta 2 veces." #: lang/json/material_from_json.py src/bionics.cpp msgid "Alcohol" @@ -137857,7 +141182,7 @@ msgstr "completamente dañado/a" #: lang/json/material_from_json.py msgid "Resin" -msgstr "" +msgstr "Resina" #: lang/json/material_from_json.py src/veh_interact.cpp msgid "dented" @@ -137929,7 +141254,7 @@ msgstr "Acero Berreta" #: lang/json/material_from_json.py msgid "Cardboard" -msgstr "" +msgstr "Cartón" #: lang/json/material_from_json.py msgid "ripped" @@ -137961,7 +141286,7 @@ msgstr "roto/a" #: lang/json/material_from_json.py msgid "Dragon Scale" -msgstr "" +msgstr "Escama de Dragón" #: lang/json/material_from_json.py msgid "Chitin" @@ -137985,7 +141310,7 @@ msgstr "Diamante" #: lang/json/material_from_json.py msgid "Gemstone" -msgstr "" +msgstr "Piedra Preciosa" #: lang/json/material_from_json.py msgid "Egg" @@ -138021,7 +141346,7 @@ msgstr "completamente mutilado/a" #: lang/json/material_from_json.py msgid "Gutskin" -msgstr "" +msgstr "Piel de Tripa" #: lang/json/material_from_json.py msgid "Fresh Clay" @@ -138081,7 +141406,7 @@ msgstr "Comida chatarra" #: lang/json/material_from_json.py msgid "Foodplace's delicious foodstuff" -msgstr "" +msgstr "comida cosa deliciosa de Foodplace" #: lang/json/material_from_json.py msgid "Kevlar" @@ -138089,11 +141414,11 @@ msgstr "Kevlar" #: lang/json/material_from_json.py msgid "Layered Kevlar" -msgstr "" +msgstr "Kevlar en Capas" #: lang/json/material_from_json.py msgid "Rigid Kevlar" -msgstr "" +msgstr "Kevlar Rígido" #: lang/json/material_from_json.py msgid "Lead" @@ -138105,7 +141430,7 @@ msgstr "Cuero" #: lang/json/material_from_json.py msgid "Lycra" -msgstr "" +msgstr "Licra" #: lang/json/material_from_json.py msgid "Dairy" @@ -138133,7 +141458,7 @@ msgstr "Papel" #: lang/json/material_from_json.py msgid "Dry Plant" -msgstr "" +msgstr "Planta Seca" #: lang/json/material_from_json.py msgid "Plastic" @@ -138153,15 +141478,15 @@ msgstr "Platino" #: lang/json/material_from_json.py msgid "Rubber" -msgstr "" +msgstr "Goma" #: lang/json/material_from_json.py msgid "stressed" -msgstr "" +msgstr "tirante" #: lang/json/material_from_json.py msgid "slashed" -msgstr "" +msgstr "rajado" #: lang/json/material_from_json.py src/item_location.cpp msgid "worn" @@ -138169,7 +141494,7 @@ msgstr "puesto" #: lang/json/material_from_json.py msgid "ruined" -msgstr "" +msgstr "arruinado" #: lang/json/material_from_json.py msgid "Steel" @@ -138185,15 +141510,15 @@ msgstr "Superaleación" #: lang/json/material_from_json.py msgid "layered carbide" -msgstr "" +msgstr "carburo en capas" #: lang/json/material_from_json.py msgid "Synthetic Fabric" -msgstr "" +msgstr "Tela Sintética" #: lang/json/material_from_json.py msgid "Tin" -msgstr "" +msgstr "Estaño" #: lang/json/material_from_json.py msgid "Vegetable Matter" @@ -138259,27 +141584,27 @@ msgstr "molido/a" #: lang/json/material_from_json.py msgid "Dried Vegetable" -msgstr "" +msgstr "Verdura Desecada" #: lang/json/material_from_json.py msgid "Cured Meat" -msgstr "" +msgstr "Carne Curada" #: lang/json/material_from_json.py msgid "Processed Food" -msgstr "" +msgstr "Comida Procesada" #: lang/json/material_from_json.py msgid "Cheese" -msgstr "" +msgstr "Queso" #: lang/json/material_from_json.py msgid "Ice Cream" -msgstr "" +msgstr "Helado" #: lang/json/material_from_json.py msgid "Soil" -msgstr "" +msgstr "Tierra Fértil" #: lang/json/material_from_json.py msgid "Zinc" @@ -138287,11 +141612,11 @@ msgstr "Zinc" #: lang/json/material_from_json.py msgid "Titanium" -msgstr "" +msgstr "Titanio" #: lang/json/material_from_json.py msgid "Graphene Weave" -msgstr "" +msgstr "Grafeno Tejido" #: lang/json/material_from_json.py msgid "scarred" @@ -138299,35 +141624,35 @@ msgstr "con cicatrices" #: lang/json/material_from_json.py msgid "Prismetallic Blend" -msgstr "" +msgstr "Mezcla Prismetálica" #: lang/json/material_from_json.py msgid "Chromogenic Weave" -msgstr "" +msgstr "Tejido Cromogénico" #: lang/json/material_from_json.py msgid "Collagenic Polymer" -msgstr "" +msgstr "Polímero Colágeno" #: lang/json/material_from_json.py msgid "Emulsified Hydrogel" -msgstr "" +msgstr "Hidrogel Emulsionado" #: lang/json/material_from_json.py msgid "pulped" -msgstr "" +msgstr "destruido" #: lang/json/material_from_json.py msgid "Arcane Skin" -msgstr "" +msgstr "Piel Arcana" #: lang/json/material_from_json.py msgid "Black Dragon Hide" -msgstr "" +msgstr "Pellejo de Dragón Negro" #: lang/json/material_from_json.py msgid "Demon Chitin" -msgstr "" +msgstr "Quitina Demoníaca" #: lang/json/material_from_json.py msgid "Orichalcum" @@ -138335,57 +141660,67 @@ msgstr "Oricalco" #: lang/json/material_from_json.py msgid "Sugar" -msgstr "" +msgstr "Azúcar" #: lang/json/mission_def_from_json.py msgid "Gather bones for Brigitte LaCroix. About 8 should do it." -msgstr "" +msgstr "Recolectá huesos para Brigitte LaCroix. Con 8 debería estar bien." #: lang/json/mission_def_from_json.py msgid "There is always work to be done, song to be woven." -msgstr "" +msgstr "Siempre hay trabajo para hacer, y canción para tejer." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " "between your fingertips. Then bring me the bones and I shall carve them for" " you." msgstr "" +"Si querés que te pongan en el camino de la iluminación, primero tenés que " +"aprender a escuchar y oir la canción. Salí, carneá una criatura y sentí el " +"poder entre la punta de tus dedos. Luego traeme los huesos y yo te los voy a" +" tallar." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." -msgstr "" +msgstr "Excelente. Ahora andá." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "" +"Entiendo tu reticencia. Sentite libre de volver cuando veas el camino." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " "an unspoiled living creature." msgstr "" +"Los cuerpos tambaleantes que vemos por todos lados se mueven en " +"discordancia. Su canción puede ser usada pero para un Acólito, sería " +"innecesariamente difícil. Asegurate de tallar una criatura viva pura." #: lang/json/mission_def_from_json.py msgid "Have you felt the song in your hands yet?" -msgstr "" +msgstr "¿Ya sentiste la canción en tus manos?" #: lang/json/mission_def_from_json.py msgid "" "And so, another cycle ends. You have done well. I will now bestow my mark " "upon you, so that others may know the path you walk and aid you." msgstr "" +"Y así, otro círculo se cierra. Lo hiciste bien. Ahora voy a otorgar mi marca" +" sobre vos, así los otros sabrán el camino que andás y te ayudarán." #: lang/json/mission_def_from_json.py msgid "So you say, but the song sings otherwise." -msgstr "" +msgstr "Eso decís, pero la canción canta otra cosa." #: lang/json/mission_def_from_json.py msgid "Then you shall try again, until you hear." -msgstr "" +msgstr "Entonces deberás volver a intentarlo, hasta que oigas." #: lang/json/mission_def_from_json.py msgid "Follow Sarcophagus Team" @@ -138393,7 +141728,7 @@ msgstr "Seguir Equipo de Sarcófago" #: lang/json/mission_def_from_json.py msgid "You wouldn't believe what I found…" -msgstr "" +msgstr "No me vas a creer lo que encontré…" #: lang/json/mission_def_from_json.py msgid "" @@ -138456,17 +141791,19 @@ msgstr "Encontrar inhalador" #: lang/json/mission_def_from_json.py msgid "I'm… short… of breath…" -msgstr "" +msgstr "No… puedo… respirar…" #: lang/json/mission_def_from_json.py msgid "I'm asthmatic. I need you to get an inhaler for me…" -msgstr "" +msgstr "Soy asmático. Necesito que me consigas un inhalador…" #: lang/json/mission_def_from_json.py msgid "" "Oh, thank god, thank you so much! I won't last more than a couple of days, " "so hurry…" msgstr "" +"¡Oh, gracias a dios, te agradezco mucho! No voy a aguantar más de dos días, " +"así que rápido…" #: lang/json/mission_def_from_json.py msgid "What?! Please, without your help!" @@ -138499,11 +141836,11 @@ msgstr "Encontrar Antibióticos" #: lang/json/mission_def_from_json.py msgid "This infection is bad, bad…" -msgstr "" +msgstr "La infección está mal, mal…" #: lang/json/mission_def_from_json.py msgid "I'm infected. Badly. I need you to get some antibiotics for me…" -msgstr "" +msgstr "Estoy infectado. Mal. Necesito que me consigas unos antibióticos…" #: lang/json/mission_def_from_json.py msgid "Find any antibiotics yet?" @@ -138525,6 +141862,11 @@ msgid "" " me a black box from one of the wrecks I'll look into where we might open'er" " at." msgstr "" +"Tenemos la bandera pero ahora necesitamos encontrar las tropas de EE.UU para" +" ver en qué podemos ayudar. No vi a nadie pero supongo que uno de esos " +"helicópteros que andaban por ahí cuando empezó todo es un buen lugar para " +"revisar. Si me podés conseguir una caja negra de uno de los estrellados, voy" +" a ver dónde la podemos abrir." #: lang/json/mission_def_from_json.py msgid "Do you have any better ideas?" @@ -138607,7 +141949,7 @@ msgstr "Encontrar Placa de Ayudante" #: lang/json/mission_def_from_json.py msgid "Those twisted snakes…" -msgstr "" +msgstr "Esas serpientes retorcidas…" #: lang/json/mission_def_from_json.py msgid "" @@ -138630,10 +141972,12 @@ msgid "" "We're also official… just hang in there and I'll show you what we can really" " do." msgstr "" +"También somos oficiales… solo quedate por ahí y te voy a mostrar lo que " +"podemos hacer." #: lang/json/mission_def_from_json.py msgid "They shouldn't be that hard to find… should they?" -msgstr "" +msgstr "No deberían ser tan difíciles de encontrar… ¿no?" #: lang/json/mission_def_from_json.py msgid "Any luck?" @@ -138645,7 +141989,7 @@ msgstr "Buen trabajo, Ayudante. Estamos en marcha." #: lang/json/mission_def_from_json.py msgid "Thanks for trying… I guess." -msgstr "" +msgstr "Gracias por intentarlo… supongo." #: lang/json/mission_def_from_json.py msgid "The day of reckoning will come for the criminals if it hasn't already." @@ -138676,7 +142020,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "Seriously? God damned commie…" -msgstr "" +msgstr "¿En serio? Maldita sea, camarada…" #: lang/json/mission_def_from_json.py msgid "Find a large federal building or school, they must have one." @@ -138695,6 +142039,9 @@ msgid "" "You give up? This country fell apart because no one could find a good man " "to rely on… might as well give up, I guess." msgstr "" +"¿Te das por vencido? Este país se cae a pedazos porque nadie puede conseguir" +" un buen hombre en el cual confiar… yo también debería darme por vencido, " +"supongo." #: lang/json/mission_def_from_json.py msgid "Find Corporate Accounts" @@ -138736,6 +142083,9 @@ msgid "" "Great, let's see… uh… hmmm… Fine, I didn't even do my own taxes but I'm " "sure this will prove their guilt if we get an expert to examine it." msgstr "" +"Buenísimo, vamos a ver… uh… hmmm… Bien, ni siquiera miro mis propios " +"impuestos pero estoy seguro que esto probará su culpa si conseguimos un " +"experto que lo pueda examinar. " #: lang/json/mission_def_from_json.py msgid "" @@ -138750,7 +142100,7 @@ msgstr "Encontrar Registros de Pacientes" #: lang/json/mission_def_from_json.py msgid "I hope I don't see many names I know…" -msgstr "" +msgstr "Espero que no encuentre muchos nombres que conozca…" #: lang/json/mission_def_from_json.py msgid "" @@ -138784,11 +142134,11 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "Oh dear, I thought Timmy would have made it…" -msgstr "" +msgstr "Oh dios, pensé que Timmy se había salvado…" #: lang/json/mission_def_from_json.py msgid "I bet some of them are still out there…" -msgstr "" +msgstr "Estoy seguro que alguno de ellos todavía anda por ahí…" #: lang/json/mission_def_from_json.py msgid "Find Weather Log" @@ -138796,7 +142146,7 @@ msgstr "Encontrar Registro de Clima" #: lang/json/mission_def_from_json.py msgid "I wonder if a retreat might exist…" -msgstr "" +msgstr "Me pregunto si puede existir un retiro…" #: lang/json/mission_def_from_json.py msgid "" @@ -138824,6 +142174,8 @@ msgstr "Sí, reconozco que era un posibilidad lejana." #: lang/json/mission_def_from_json.py msgid "I'm not sure, maybe a news station would have what we are looking for?" msgstr "" +"No estoy seguro, ¿tal vez los medios de noticias puedan tener lo que estamos" +" buscando?" #: lang/json/mission_def_from_json.py msgid "These look more complicated than I thought, just give me some time." @@ -138844,7 +142196,7 @@ msgstr "Encontrar Reliquia" #: lang/json/mission_def_from_json.py msgid "St. Michael the archangel defend me in battle…" -msgstr "" +msgstr "El arcángel San Miguel me defiende en la batalla…" #: lang/json/mission_def_from_json.py msgid "" @@ -138853,6 +142205,10 @@ msgid "" "truth to them. Please go and find me a religious relic… I doubt it will be" " of much use but I've got to hope in something." msgstr "" +"Como el mundo parece abandonar la realidad que supimos conocer, se hace " +"probable que las viejas supersticiones que fueron dejadas de lado puedan " +"tener algo de verdad en ellas. Por favor, buscame una reliquia religiosa… " +"dudo que sea de mucha ayuda pero tengo que creer en algo." #: lang/json/mission_def_from_json.py msgid "" @@ -138862,7 +142218,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "Ya, I guess the stress may just be getting to me…" -msgstr "" +msgstr "Sí, supongo que el stress me está haciendo mal…" #: lang/json/mission_def_from_json.py msgid "I suppose a large church or cathedral may have something." @@ -138876,7 +142232,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "Thank you, I need some time alone now…" -msgstr "" +msgstr "Gracias, ahora necesito un tiempo solo…" #: lang/json/mission_def_from_json.py msgid "What good does this do us?" @@ -138884,7 +142240,7 @@ msgstr "¿Para qué nos sirve esto?" #: lang/json/mission_def_from_json.py msgid "It was a lost cause anyways…" -msgstr "" +msgstr "De todas maneras, era un caso perdido…" #: lang/json/mission_def_from_json.py msgid "Retrieve Deposit Box" @@ -138938,7 +142294,7 @@ msgstr "Recuperar Software" #: lang/json/mission_def_from_json.py msgid "Oh man, I can't believe I forgot to download it…" -msgstr "" +msgstr "Uh loco, no puedo creer que me olvidé de descargarlo…" #: lang/json/mission_def_from_json.py msgid "There's some important software on my computer that I need on USB." @@ -138954,7 +142310,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "Seriously? It's an easy job…" -msgstr "" +msgstr "¿De en serio? Es una tarea fácil…" #: lang/json/mission_def_from_json.py msgid "Take this USB drive. Use the console, and download the software." @@ -138970,7 +142326,7 @@ msgstr "¡Excelente, gracias!" #: lang/json/mission_def_from_json.py msgid "Wow, you failed? All that work, down the drain…" -msgstr "" +msgstr "¿Guau, no pudiste? Todo ese trabajo, perdido para siempre…" #: lang/json/mission_def_from_json.py msgid "Analyze Zombie Blood" @@ -138979,6 +142335,7 @@ msgstr "Analizar Sangre de Zombi" #: lang/json/mission_def_from_json.py msgid "It could be very informative to perform an analysis of zombie blood…" msgstr "" +"Puede ser muy informativo realizar un análisis de la sangre de un zombi…" #: lang/json/mission_def_from_json.py msgid "" @@ -139002,6 +142359,8 @@ msgstr "" msgid "" "Are you sure? The scientific value of that blood data could be priceless…" msgstr "" +"¿Estás seguro? El valor científico de la información de esa sangre puede ser" +" invalorable…" #: lang/json/mission_def_from_json.py msgid "" @@ -139025,7 +142384,7 @@ msgstr "¡Esperá, no puede ser que tengas la información! ¡Mentiroso!" #: lang/json/mission_def_from_json.py msgid "What a shame, that data could have proved invaluable…" -msgstr "" +msgstr "Qué lástima, esa información puede ser invalorable…" #: lang/json/mission_def_from_json.py msgid "Investigate Cult" @@ -139040,6 +142399,12 @@ msgid "" "location for me? I'm not sure what was going on here but the priest seemed " "fairly worried about it." msgstr "" +"No tenés idea de qué tan interesante es este diario. Encontré dos pistas " +"prometedoras… Primero lo primero, la Iglesia Católica ha estado llevando a " +"cabo sus propias investigaciones acerca del fenómeno del culto global y " +"parece que recientemente se ha vuelto muy interesada en un culto local. " +"¿Podrías investigar un lugar por mí? No estoy seguro que hacían ahí, pero el" +" cura parece bastante preocupado al respecto." #: lang/json/mission_def_from_json.py msgid "" @@ -139049,6 +142414,11 @@ msgid "" "before and after the outbreak. The name of the cult is believed to be the " "Church of Starry Wisdom but it is noted that accounts differ." msgstr "" +"Te deseo la mejor de las suertes, que el dios que te guste guíe tu camino… " +"Tal vez lo necesites más ahora que en las excursiones anteriores que " +"hiciste. Hay una nota acerca de posibles sacrificios humanos en los días " +"previos y luego del comienzo. Se cree que el nombre del culto es la Iglesia " +"de la Sabiduría Estrellada, pero se sabe que los informes difieren." #: lang/json/mission_def_from_json.py msgid "" @@ -139056,10 +142426,14 @@ msgid "" "not sure what you might be looking for but I'm positive you'll find " "something out of the ordinary if you look long enough." msgstr "" +"Dudo de que el lugar todavía esté ocupado pero yo llevaría por lo menos un " +"arma de fuego… No estoy seguro de lo que tengas que buscar pero sí sé que " +"vas a encontrar algo fuera de lo común si buscás bien." #: lang/json/mission_def_from_json.py msgid "I'm positive there is something there… there has to be, any luck?" msgstr "" +"Estoy seguro de que hay algo ahí… tiene que haber algo, ¿tuviste suerte?" #: lang/json/mission_def_from_json.py msgid "" @@ -139068,6 +142442,10 @@ msgid "" "survivors of this cult… I don't known if they are responsible for the " "outbreak but they certainly know more about it than I do." msgstr "" +"Gracias, tu informe sobre estas… creaciones demoníacas prueba que los miedos" +" de las iglesias eran fundados. Nuestra prioridad debería ser descartar que " +"haya sobrevivido alguno de este culto… No sé si ellos son responsables por " +"el comienzo de esto pero seguro que saben más que yo." #: lang/json/mission_def_from_json.py msgid "Prison Visionary" @@ -139083,6 +142461,13 @@ msgid "" "in a position to cast out the account just yet… it seems the man has " "prophesied events accurately before concerning the Church of Starry Wisdom." msgstr "" +"Tengo otra tarea si tenés ganas. Hay un prisionero sobre el que el cura hace" +" especial mención. Me pregunto si podrías revisar qué puede haber pasado con" +" él o si dejó algo en su celda. El cura admite que el individuo es bastante " +"inestable, para decirlo a la ligera, pero el cura personalmente creía que " +"este hombre era una clase de visionario arrepentido. No estoy en posición " +"olvidar el informe todavía… parece que el hombre ya había profetizado " +"sucesos acertadamente acerca de la Iglesia de la Sabiduría Estrellada." #: lang/json/mission_def_from_json.py msgid "" @@ -139091,6 +142476,10 @@ msgid "" "sure what they would have decided to do with the inmates when they knew " "death was almost certain. " msgstr "" +"Te deseo la mejor de las suertes, que el dios que te guste guíe tu camino… " +"Solo puedo imaginar que la cárcel va a ser un pequeño pedazo del infierno. " +"No estoy seguro de que lo que hubieran decidido hacer con los presos cuando " +"sabían que la muerte era algo casi seguro." #: lang/json/mission_def_from_json.py msgid "" @@ -139114,7 +142503,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "Well damn, you must be the guys here to pick me up…" -msgstr "" +msgstr "Bueno, por fin, ustedes deben ser los que venían a buscarme…" #: lang/json/mission_def_from_json.py msgid "" @@ -139158,11 +142547,11 @@ msgstr "¿Algún problema, jefe?" #: lang/json/mission_def_from_json.py msgid "Wait… are you really making me a deputy?" -msgstr "" +msgstr "Esperá… ¿en serio me estás haciendo el ayudante?" #: lang/json/mission_def_from_json.py msgid "I don't think so…" -msgstr "" +msgstr "No me parece…" #: lang/json/mission_def_from_json.py msgid "Quitting already?" @@ -139174,7 +142563,7 @@ msgstr "Matar 100 Zombis" #: lang/json/mission_def_from_json.py msgid "You seem to know this new world better than most…" -msgstr "" +msgstr "Parece que conocés este mundo nuevo mejor que la mayoría…" #: lang/json/mission_def_from_json.py msgid "" @@ -139185,6 +142574,13 @@ msgid "" " to the best of my ability but you really showed promise taking out that " "other beast. You, I, and a 100 zombies laid to rest, what do you say?" msgstr "" +"Estás mejor equipado que la mayoría… ¿te interesaría hacer este mundo un " +"poquito mejor para el resto de nosotros? Los pueblos tienen suficientes " +"provisiones para que los sobrevivientes empecemos a asegurarnos un punto de " +"apoyo, pero no tenemos a nadie con la habilidad y el equipo para achicar el " +"número de muertos vivientes. Te voy a ayudar todo lo que pueda porque " +"mostraste habilidad para eliminar esa otra bestia. Vos, yo, y 100 zombis " +"para matar, ¿qué te parece?" #: lang/json/mission_def_from_json.py msgid "" @@ -139200,6 +142596,9 @@ msgid "" "most of us survivors won't make it unless someone decides to take the " "initiative." msgstr "" +"Hey, yo tampoco sería voluntario para una cosa así… pero luego me acuerdo " +"que la mayoría de los sobrevivientes no vamos a hacerlo salvo que alguien " +"decida tomar la iniciativa." #: lang/json/mission_def_from_json.py msgid "I'd secure an ammo cache and try to sweep a town in multiple passes." @@ -139216,6 +142615,8 @@ msgid "" "Man… you're a goddamn machine. It was a pleasure working with you. You " "know, you may just change our little neck of the world if you keep this up." msgstr "" +"Chabón… sos una máquina. Fue un placer trabajar con vos. Ya sabés, puede que" +" cambies nuestro lugar en el mundo si seguís así." #: lang/json/mission_def_from_json.py msgid "I don't think that was quite a hundred dead zeds." @@ -139228,6 +142629,8 @@ msgstr "Matar Líder de Horda" #: lang/json/mission_def_from_json.py msgid "I've heard some bad rumors so I hope you are up for another challenge…" msgstr "" +"Escuché algunos rumores malos, así que espero que estés dispuesto a " +"enfrentar otro desafío…" #: lang/json/mission_def_from_json.py msgid "" @@ -139280,6 +142683,8 @@ msgid "" "The eater of the dead… something was ripping zombies to shreds and only " "leaving a few scattered limbs…" msgstr "" +"El comedor de muertos… algo está desgarrando a los zombis en pedazos y solo " +"deja algunas partes desparramadas…" #: lang/json/mission_def_from_json.py msgid "" @@ -139329,6 +142734,8 @@ msgid "" "I'm glad you came back alive… I wasn't sure if I had sent you to your " "death." msgstr "" +"Me alegra que hayas vuelto vivo… no estaba seguro si te había mandado a la " +"muerte." #: lang/json/mission_def_from_json.py msgid "Kill Zombie Mom" @@ -139336,29 +142743,32 @@ msgstr "Matar Mamá Zombi" #: lang/json/mission_def_from_json.py msgid "Oh god, I can't believe it happened…" -msgstr "" +msgstr "Oh dios, no puedo creer lo que pasó…" #: lang/json/mission_def_from_json.py msgid "" "My mom… she's… she was killed, but then she just got back up… she's one of " "those things now. Can you put her out of her misery for me?" msgstr "" +"Mi mamá… ella… la mataron, pero después se volvió a levantar… se convirtió " +"en una de esas cosas. ¿Podés hacerme el favor de terminar con su miserable " +"vida?" #: lang/json/mission_def_from_json.py msgid "Thank you… she would've wanted it this way." -msgstr "" +msgstr "Gracias… ella lo hubiera querido así. " #: lang/json/mission_def_from_json.py msgid "Please reconsider, I know she's suffering…" -msgstr "" +msgstr "Por favor, pensalo, yo sé que ella está sufriendo…" #: lang/json/mission_def_from_json.py msgid "Find a gun if you can, make it quick…" -msgstr "" +msgstr "Buscate un arma si podés, hacelo rápido…" #: lang/json/mission_def_from_json.py msgid "Well…? Did you… finish things for my mom?" -msgstr "" +msgstr "¿Y…? ¿Ya pudiste… terminar lo de mi mamá?" #: lang/json/mission_def_from_json.py msgid "Thank you. I couldn't rest until I knew that was finished." @@ -139366,7 +142776,7 @@ msgstr "Gracias. No podía descansar hasta saber que se había terminado. " #: lang/json/mission_def_from_json.py msgid "Really… that's too bad." -msgstr "" +msgstr "En serio… qué mal." #: lang/json/mission_def_from_json.py msgid "Null mission" @@ -139378,7 +142788,7 @@ msgstr "Llegar a Casa de Granja" #: lang/json/mission_def_from_json.py msgid "I just need a place to start over…" -msgstr "" +msgstr "Solo quiero un lugar para empezar de nuevo…" #: lang/json/mission_def_from_json.py msgid "" @@ -139387,6 +142797,11 @@ msgid "" " the first to go. I'd like to start over, just rebuild at one of the farms " "in the countryside. Can you help me secure one?" msgstr "" +"He aceptado que todos los que conocía están muertos… de una forma o de otra." +" Realmente quisiera haber podido hacer algo para salvar a mi hermano pero él" +" fue uno de los primeros en irse. Me gustaría empezar de nuevo, solo " +"reconstruir en una de las granjas del campo. ¿Me podés ayudar a asegurar " +"una?" #: lang/json/mission_def_from_json.py msgid "" @@ -139432,7 +142847,7 @@ msgstr "Llegar a Campamento FEMA" #: lang/json/mission_def_from_json.py msgid "Maybe they escaped to one of the camps…" -msgstr "" +msgstr "Tal vez se escaparon a alguno de esos campamentos…" #: lang/json/mission_def_from_json.py msgid "" @@ -139441,10 +142856,14 @@ msgid "" " of the FEMA camps? I know some were overrun but I don't want to believe " "all of them could have fallen." msgstr "" +"No puedo agradecerte lo suficiente que me hayas traído los registros de " +"pacientes, pero tengo otro pedido. Parece que conocés el lugar… ¿me podrías " +"llevar a uno de los campamentos FEMA? Sé que algunos fueron infestados pero " +"no quiero creer que todos han caído." #: lang/json/mission_def_from_json.py msgid "Thank you, just bring me to the camp… I just want to see." -msgstr "" +msgstr "Gracias, solo llevame hasta el campamento… Solo quiero verlo." #: lang/json/mission_def_from_json.py msgid "Please, I don't know what else to do." @@ -139471,7 +142890,7 @@ msgstr "Alcanzar Sitio Seguro" #: lang/json/mission_def_from_json.py msgid "Reach The Mansion And Finish This Delivery" -msgstr "" +msgstr "Ir a la Mansión y Terminar La Entrega" #: lang/json/mission_def_from_json.py msgid "Recover Priest's Diary" @@ -139519,18 +142938,28 @@ msgid "" "woods. Wasn't sure how long we were going to be so I told him to just camp " "there until we picked him up." msgstr "" +"Tenemos otro problema que enfrentar pero no creo que podamos hacerlo " +"nosotros solos. Así que, pregunté y conseguí un voluntario… más o menos. Es " +"más egoísta que la mierda pero tiene habilidad con las armas. Se suponía que" +" iba a agarrar todo lo que tuviera de valor y se encontraría con nosotros en" +" la cabaña del bosque. No estaba seguro de cuánto íbamos a tardar así que le" +" dije que se quede ahí hasta que lo pasáramos a buscar." #: lang/json/mission_def_from_json.py msgid "" "Rodger, if he's a no-show then any other gunslinger will do… but I doubt " "he'll quit before we even begin." msgstr "" +"Rodger, si no aparece entonces cualquier otro pistolero servirá… pero dudo " +"de que se rinda antes de empezar." #: lang/json/mission_def_from_json.py msgid "" "I hope the bastard is packing heat… else we'll need to grab him a gun before" " we hit our next target." msgstr "" +"Espero que el bastardo esté trayendo fierros… si no vamos a necesitar " +"conseguirle un arma antes de buscar nuestro próximo objetivo." #: lang/json/mission_def_from_json.py msgid "Found a gunslinger?" @@ -139550,7 +142979,7 @@ msgstr "Encontrar Perro Perdido" #: lang/json/mission_def_from_json.py msgid "Oh, my poor puppy…" -msgstr "" +msgstr "Oh, mi pobre cachorrito…" #: lang/json/mission_def_from_json.py msgid "" @@ -139585,43 +143014,51 @@ msgstr "¡Muchas gracias por encontrarlo!" #: lang/json/mission_def_from_json.py msgid "Oh no! My poor puppy…" -msgstr "" +msgstr "¡Oh no! Mi pobre cachorrito…" #: lang/json/mission_def_from_json.py msgid "Break into armory to retrieve family photo" -msgstr "" +msgstr "Entrar en la armería y recuperar la foto familiar" #: lang/json/mission_def_from_json.py msgid "I need you to get my family photo from the armory safe." msgstr "" +"Necesito que consigas la foto de mi familia que está en la caja fuerte de la" +" armería." #: lang/json/mission_def_from_json.py msgid "" "I left the only photo I have from my family in the armory. I don't have the" " code, can you get in?" msgstr "" +"Dejé la única foto que tenía de mi familia en la armería. No tengo el " +"código, ¿podrás entrar igual?" #: lang/json/mission_def_from_json.py msgid "Thanks, it's great to see someone willing to help a out." -msgstr "" +msgstr "Gracias, qué bueno es encontrarse gente dispuesta a ayudar." #: lang/json/mission_def_from_json.py msgid "" "Well, I'll find someone else to do it for me, real shame with all those guns" " locked up too…" msgstr "" +"Bueno, voy a buscar otro que lo quiera hacer por mí, una verdadera lástima " +"con todas esas armas guardadas ahí…" #: lang/json/mission_def_from_json.py msgid "You look like a resourceful sort, maybe you can hack it or something." -msgstr "" +msgstr "Parece que tenés recursos, por ahí podés hackearla o algo así." #: lang/json/mission_def_from_json.py msgid "Got the photo? Should've been in my gun safe." -msgstr "" +msgstr "¿Tenés la foto? Debería estar en mi caga fuerte de armas." #: lang/json/mission_def_from_json.py msgid "Thanks! I'll be sure to put in a good word for you around town." msgstr "" +"¡Gracias! Me voy a asegurar de que se enteren lo que hiciste por mí en el " +"pueblo." #: lang/json/mission_def_from_json.py msgid "OK, then hand it over." @@ -139633,15 +143070,15 @@ msgstr "Es lo que hay." #: lang/json/mission_def_from_json.py msgid "Find Antibiotics Before You Die!" -msgstr "" +msgstr "¡Encontrar Antibióticos Antes de Morir!|" #: lang/json/mission_def_from_json.py msgid "Prove your worth to Foodperson" -msgstr "" +msgstr "Probar tu valor a Foodperson" #: lang/json/mission_def_from_json.py msgid "Prove your dedication to Foodplace." -msgstr "" +msgstr "Probar tu dedicación a Foodplace." #: lang/json/mission_def_from_json.py msgid "" @@ -139649,42 +143086,49 @@ msgid "" "you worthy of my friendship. Ten loyalty cards should be enough, I'm sure " "you already have much more than that waiting for you at home, right?" msgstr "" +"Mostrame la prueba de tu lealtad al gran Foodplace, y voy a considerar si te" +" merecés mi amistad. Diez tarjetas de lealtad deberían ser suficientes, " +"estoy seguro que ya tenés más que eso esperandote en tu casa, ¿no?" #: lang/json/mission_def_from_json.py msgid "That's the spirit! Good luck kid." -msgstr "" +msgstr "¡Ese es el ánimo! Buena suerte, pibe." #: lang/json/mission_def_from_json.py msgid "That's alright not everyone is cutout for this." -msgstr "" +msgstr "Está bien, no todos están hechos para esto." #: lang/json/mission_def_from_json.py msgid "" "Those are very precious, people would probably keep them on their person or " "in bank vaults. And definitely not throw them in the trash!" msgstr "" +"Esas son muy preciadas, la gente probablemente las lleva consigo o las " +"guarda en el banco. ¡Y definitivamente no las tirarían en la basura!" #: lang/json/mission_def_from_json.py msgid "How is it going? Do you have them?" -msgstr "" +msgstr "¿Cómo va? ¿Las conseguiste?" #: lang/json/mission_def_from_json.py msgid "" "YES! I knew you could do it! You proved your worth and I'm proud to call " "you a friend." msgstr "" +"¡SÍ! ¡Sabía que lo podías hacer! Probaste tu valía y me enorgullece llamarte" +" amigo." #: lang/json/mission_def_from_json.py msgid "Well… where are they?" -msgstr "" +msgstr "Bueno… ¿dónde están?" #: lang/json/mission_def_from_json.py msgid "I'm so disappointed in you kid…" -msgstr "" +msgstr "Estoy muy decepcionado de vos, pibe…" #: lang/json/mission_def_from_json.py msgid "Prove You're A Survivor" -msgstr "" +msgstr "Probá que Sos un Superviviente" #. ~ Description for mission '{'str': "Prove You're A Survivor"}' #: lang/json/mission_def_from_json.py @@ -139692,10 +143136,14 @@ msgid "" "Prove you're a survivor by surviving for 10 days after the Cataclysm, and " "then returning to the person who gave you this mission." msgstr "" +"Probá que sos un superviviente sobreviviendo 10 días después del Cataclismo," +" y después volviendo a la persona que te dio esta misión." #: lang/json/mission_def_from_json.py msgid "It's hard to tell who actually has the skills to survive these days…" msgstr "" +"Es difícil decir quién tiene realmente las habilidades para sobrevivir estos" +" días…" #: lang/json/mission_def_from_json.py msgid "" @@ -139707,38 +143155,50 @@ msgid "" "know you've got what it takes, or you don't and I'll know that I was right " "not to follow you." msgstr "" +"Es difícil sobrevivir solo, y probablemente tengamos mejores oportunidades " +"si trabajamos juntos. El problema es que no te conozco y no sé de qué sos " +"capaz. Tal vez tengas lo necesario, tal vez no. De cualquier manera voy a " +"necesitar pruebas. Volvé en unos días y te voy a seguir con gusto. " +"Básicamente, es una situación de ganar y ganar para mí: o volvés y sé que " +"tenés lo necesario, o no volvés y sé que tenía razón al no ir con vos." #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." -msgstr "" +"I'll see you then… or I won't, and then I'll know I made the right decision." +msgstr "Te veo después… o no, y entonces sabré que tomé la decisión correcta." #: lang/json/mission_def_from_json.py msgid "" "Don't die. If you're asking me for advice, that doesn't bode well for you." msgstr "" +"No te mueras. Si me pedís un consejo, eso no sería un buen presagio para " +"vos." #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." -msgstr "" +msgid "Well, you're not dead… yet." +msgstr "Bueno, no estás muerto… todavía." #: lang/json/mission_def_from_json.py msgid "" "I'll be honest, I wasn't really expecting to see you again. A promise is a " "promise, I'll follow you now!" msgstr "" +"Voy a ser sincero, no esperaba volver a verte. Pero una promesa es una " +"promesa, ¡voy con vos!" #: lang/json/mission_def_from_json.py msgid "I know time is relative and all that." -msgstr "" +msgstr "Ya sé que el tiempo es relativo y todo eso." #: lang/json/mission_def_from_json.py msgid "I'm not quite sure how you failed to survive AND are talking to me." msgstr "" +"No estoy muy seguro cómo hiciste para no sobrevivir Y estar acá hablando " +"conmigo." #: lang/json/mission_def_from_json.py msgid "Gather cattail stalks to create cattail jelly" -msgstr "" +msgstr "Recolectar tallos de junco para crear gelatina de junco" #. ~ Description for mission '{'str': 'Gather cattail stalks to create cattail #. jelly'}' @@ -139750,6 +143210,11 @@ msgid "" "harvesting cattail stalks. Bring back the provided " "bag as well." msgstr "" +"Recolectar 80 tallos de junco del pantano y " +"traerlos para aprender cómo hacer gelatina de " +"junco. Levanta tu habilidad de supervivencia a por" +" lo menos 1 al recolectar los tallos. Traé de " +"nuevo la bolsa que te dieron también." #: lang/json/mission_def_from_json.py msgid "" @@ -139757,6 +143222,9 @@ msgid "" "have been surviving using their wits and the bounty of Mother Nature for a " "long time. Care to learn a little?" msgstr "" +"Los servicios médicos son un poco escasos después del , pero " +"la gente ha sobrevivido usando su ingenio y la abundancia de la Madre " +"Naturaleza por mucho tiempo. ¿Querés aprender un poco?" #: lang/json/mission_def_from_json.py msgid "" @@ -139766,51 +143234,62 @@ msgid "" "collect 80 cattail stalks, and bring them back here. In exchange, I'll show" " you how to harvest the jelly." msgstr "" +"¿Sabías que los juncos son un recurso para hacer una gelatina que funciona " +"como antiséptico y analgésico? Algo como esto es probable que te sea útil. " +"Quiero que te lleves esta bolsa, vayas hasta el pantano más cerca, " +"recolectes 80 tallos de junco y los traigas para acá. A cambio te voy a " +"mostrar cómo extraer la gelatina." #: lang/json/mission_def_from_json.py msgid "" "Great! This bag should be big enough to hold all of the stalks we'll need." " Don't forget to bring it back." msgstr "" +"¡Genial! Esta bolsa debería ser suficientemente grande para contener todos " +"los tallos que necesitamos. No te olvides de traerla de vuelta." #: lang/json/mission_def_from_json.py msgid "Your loss." -msgstr "" +msgstr "Vos te lo perdés." #: lang/json/mission_def_from_json.py msgid "The cattails grow in the fresh water in swamps. You can't miss them." msgstr "" +"Los juncos crecen cerca del agua potable en los pantanos. No te los podés " +"perder." #: lang/json/mission_def_from_json.py msgid "" "Got those cattail stalks yet? Don't forget to bring back my bag and improve" " your survival skill to at least 1 as well." msgstr "" +"¿Ya conseguiste los tallos de junco? No te olvides de traerme mi bolsa y de " +"mejorar tu habilidad de supervivencia a 1 por lo menos." #: lang/json/mission_def_from_json.py msgid "Great! Hand them over and I'll show you how this works." -msgstr "" +msgstr "¡Genial! Damelos y te muestro cómo se hace." #: lang/json/mission_def_from_json.py msgid "OK, then hand them over." -msgstr "" +msgstr "Bueno, damelos." #: lang/json/mission_def_from_json.py msgid "Well, that's a shame." -msgstr "" +msgstr "Bueno, qué lástima." #: lang/json/mission_def_from_json.py msgid "Picky Meals" -msgstr "" +msgstr "Quisquilloso" #. ~ Description for mission '{'str': 'Picky Meals'}' #: lang/json/mission_def_from_json.py msgid "Find 100 salt." -msgstr "" +msgstr "Encontrar 100 unidades de sal." #: lang/json/mission_def_from_json.py msgid "I need a supply of salt." -msgstr "" +msgstr "Necesito suministro de sal." #: lang/json/mission_def_from_json.py msgid "" @@ -139818,46 +143297,53 @@ msgid "" " just need it as a seasoning, it's also vital for food preservation. Could " "you find about 20 pounds of salt for me?" msgstr "" +"Ya sé que no suena muy importante, pero me estoy quedando sin sal. No " +"solamente la necesitamos para condimentar, también es vital para la " +"conservación de comida. ¿Podrías conseguirme unos 10 kilos de sal?" #: lang/json/mission_def_from_json.py msgid "Don't forget to tell me when you have them." -msgstr "" +msgstr "No te olvides de avisarme cuando la consigas." #: lang/json/mission_def_from_json.py msgid "It's okay, I can do without them. Just let me know if you reconsider." -msgstr "" +msgstr "Está bien, no es tan importante. Pero avisame si te arrepentís." #: lang/json/mission_def_from_json.py msgid "" "There's a lot of places to look. They are common in house kitchens, " "restaurants or grocery stores." msgstr "" +"Hay muchos lugares para buscar. Es común que haya en las cocinas de las " +"casas, restoranes y almacenes." #: lang/json/mission_def_from_json.py msgid "How is the search going? Have you found 'em?" -msgstr "" +msgstr "¿Cómo va la búsqueda? ¿La conseguiste?" #: lang/json/mission_def_from_json.py msgid "" "I really apreciate your help. Don't worry, you won't leave empty-handed." msgstr "" +"Realmente aprecio tu ayuda. No te preocupes, no te vas a ir con las manos " +"vacías." #: lang/json/mission_def_from_json.py msgid "Don't worry about it, it's not that important." -msgstr "" +msgstr "No te preocupes por eso, no es tan importante." #: lang/json/mission_def_from_json.py msgid "Pickled Meals" -msgstr "" +msgstr "Comidas al Escabeche" #. ~ Description for mission '{'str': 'Pickled Meals'}' #: lang/json/mission_def_from_json.py msgid "Find 5 glass jars." -msgstr "" +msgstr "Encontrar 5 frascos de vidrio." #: lang/json/mission_def_from_json.py msgid "I need several glass jars." -msgstr "" +msgstr "Necesito varios frascos de vidrio." #: lang/json/mission_def_from_json.py msgid "" @@ -139866,48 +143352,57 @@ msgid "" "could do our own canning if we had some more glass jars. I could get by " "with 5 for now." msgstr "" +"Esta tarea es un poco más seria. No tengo los suficientes frascos para " +"preservar la comida perecedera, y no podemos almacenar todo en sal. " +"Podríamos hacer nuestras propias conservas si tuviéramos más frascos de " +"vidrio. Con 5 ya estaríamos bien, por ahora." #: lang/json/mission_def_from_json.py msgid "" "Thanks for accepting this task. It'll take a load off my shoulders. I " "finally won't have to worry about this problem anymore." msgstr "" +"Gracias por aceptar esta tarea. Me sacás un peso de encima. Finalmente no " +"tendré que preocuparme por este problema." #: lang/json/mission_def_from_json.py msgid "Just let me know if you change your mind." -msgstr "" +msgstr "Haceme saber si cambiás de idea." #: lang/json/mission_def_from_json.py msgid "" "Glass jars are not that hard to find. I'd look for them in residental " "areas." msgstr "" +"Los frascos de vidrio no son difíciles de encontrar. Yo los buscaría en las " +"casas." #: lang/json/mission_def_from_json.py msgid "Have you found the jars?" -msgstr "" +msgstr "¿Encontraste los frascos?" #: lang/json/mission_def_from_json.py msgid "" "Thank you for your help. Here's your reward. I have one more task to do." msgstr "" +"Gracias por tu ayuda. Acá está tu recompensa. Tengo otra tarea para hacer." #: lang/json/mission_def_from_json.py msgid "It's not a big deal, it isn't that urgent." -msgstr "" +msgstr "No es gran cosa, no es tan urgente." #: lang/json/mission_def_from_json.py msgid "Prickled Meals" -msgstr "" +msgstr "Comidas Espinosas" #. ~ Description for mission '{'str': 'Prickled Meals'}' #: lang/json/mission_def_from_json.py msgid "Find a butcher knife." -msgstr "" +msgstr "Encontrar cuchillo de carnicero." #: lang/json/mission_def_from_json.py msgid "I need something sharper." -msgstr "" +msgstr "Necesito algo más afilado." #: lang/json/mission_def_from_json.py msgid "" @@ -139915,168 +143410,186 @@ msgid "" "hard without it. It's good to have one, even though I won't use it that " "often. Could you get me one?" msgstr "" +"No tengo ningún cuchillo de carnicero acá. Es difícil cortar algo duro sin " +"uno de esos. Está bueno tener uno, incluso aunque no lo necesite muy " +"seguido. ¿Me podrás conseguir uno?" #: lang/json/mission_def_from_json.py msgid "Thank you for accepting. I can't cut anything with this dull knife." msgstr "" +"Gracias por aceptar. No puedo cortar nada con este cuchillo desafilado." #: lang/json/mission_def_from_json.py msgid "I guess I have to cut them with my steak knife." -msgstr "" +msgstr "Supongo que voy a tener que cortarlos con mi cuchillo para carne." #: lang/json/mission_def_from_json.py msgid "" "Butcher knives are not that rare to find. They are commonly found in " "kitchens." msgstr "" +"Los cuchillos de carnicero no son tan difíciles de conseguir. Comúnmente " +"están en cualquier cocina." #: lang/json/mission_def_from_json.py msgid "Do you have that knife now?" -msgstr "" +msgstr "¿Ya tenés el cuchillo?" #: lang/json/mission_def_from_json.py msgid "I am grateful for the help you've done." -msgstr "" +msgstr "Estoy agradecido por la ayuda que me diste." #: lang/json/mission_def_from_json.py msgid "Busy While Work" -msgstr "" +msgstr "Ocupado en el Trabajo" #. ~ Description for mission '{'str': 'Busy While Work'}' #: lang/json/mission_def_from_json.py msgid "Find 3 mystery novels." -msgstr "" +msgstr "Encontrar 3 novelas de misterio." #: lang/json/mission_def_from_json.py msgid "I'd like to read some mystery novels." -msgstr "" +msgstr "Me gustaría leer unas novelas de misterio." #: lang/json/mission_def_from_json.py msgid "" "Hmm, that would be great! But if you do, please bring more than just one. " "I could read a single novel in a day. Could you get me… 3 mystery novels?" msgstr "" +"Hmm, ¡eso estaría buenísimo! Pero si vas, por favor traeme más de uno. Puedo" +" leer una novela en un día. ¿Podrías traerme… 3 novelas de misterio?" #: lang/json/mission_def_from_json.py msgid "Just bring it to me when you have it." -msgstr "" +msgstr "Traémelos cuando los tengas." #: lang/json/mission_def_from_json.py msgid "Nevermind then. I hope you'll change your mind." -msgstr "" +msgstr "Entonces no importa. Espero que cambies de idea." #: lang/json/mission_def_from_json.py msgid "I'd loot libraries and bookstores." -msgstr "" +msgstr "Yo buscaría en bibliotecas y librerías." #: lang/json/mission_def_from_json.py msgid "So, have you found the books?" -msgstr "" +msgstr "¿Y? ¿Encontraste los libros?" #: lang/json/mission_def_from_json.py msgid "" "Thank you. This will keep me busy for a while. Please take this as a token" " of my gratitude." msgstr "" +"Gracias. Esto me va a tener entretenido por un tiempo. Por favor, aceptá " +"esto como una muestra de mi gratitud." #: lang/json/mission_def_from_json.py msgid "Could you give them to me?" -msgstr "" +msgstr "¿Me los podés dar?" #: lang/json/mission_def_from_json.py msgid "Fine. I can read something else." -msgstr "" +msgstr "Bien. Puedo leer otras cosas." #: lang/json/mission_def_from_json.py msgid "Timber!" -msgstr "" +msgstr "¡Guarda con el árbol!" #. ~ Description for mission '{'str': 'Timber!'}' #: lang/json/mission_def_from_json.py msgid "Bring five logs." -msgstr "" +msgstr "Traer cinco troncos." #: lang/json/mission_def_from_json.py msgid "I need 5 logs for fences." -msgstr "" +msgstr "Necesito 5 troncos para hacer vallas." #: lang/json/mission_def_from_json.py msgid "" "I need to build fences and ditches around my rabbits. Could you find about…" " five logs for me?" msgstr "" +"Necesito construir vallas y zanjas alrededor de mis conejos. ¿Podrías " +"traerme unos… cinco troncos?" #: lang/json/mission_def_from_json.py msgid "There's a lot of places to look. Trees are pretty common." -msgstr "" +msgstr "Hay muchos lugares para buscar. Los árboles son bastante comunes." #: lang/json/mission_def_from_json.py msgid "How is the search going? Have you found'em?" -msgstr "" +msgstr "¿Cómo va la búsqueda? ¿Los conseguiste?" #: lang/json/mission_def_from_json.py msgid "" "I really appreciate your help. Don't worry, you won't leave empty-handed." msgstr "" +"Realmente aprecio tu ayuda. No te preocupes, no te vas a ir con las manos " +"vacías." #: lang/json/mission_def_from_json.py msgid "Sweets" -msgstr "" +msgstr "Golosinas" #. ~ Description for mission '{'str': 'Sweets'}' #: lang/json/mission_def_from_json.py msgid "Find 25 blackberries." -msgstr "" +msgstr "Encontrar 25 zarzamoras." #: lang/json/mission_def_from_json.py msgid "I need 25 blackberries." -msgstr "" +msgstr "Necesito 25 zarzamoras." #: lang/json/mission_def_from_json.py msgid "Fruits would let me break the monotony of grains and meats." msgstr "" +"Las frutas me van a permitir romper la monotonía de los granos y las carnes." #: lang/json/mission_def_from_json.py msgid "" "Thanks for accepting this task. Otherwise I might kill a stranger for some " "oranges. Just kidding." msgstr "" +"Gracias por aceptar esta tarea. De otra manera, podría matar a un extraño " +"por algunas naranjas. Es un chiste." #: lang/json/mission_def_from_json.py msgid "Find someone growing berries or an orchard." -msgstr "" +msgstr "Buscá algunos arbustos o un huerto de árboles." #: lang/json/mission_def_from_json.py msgid "Have you found the fruit?" -msgstr "" +msgstr "¿Encontraste la fruta?" #: lang/json/mission_def_from_json.py msgid "Thank you for your help. Here's your reward." -msgstr "" +msgstr "Gracias por tu ayuda. Acá está tu recompensa." #: lang/json/mission_def_from_json.py msgid "Return Barry to Eddie at the dairy." -msgstr "" +msgstr "Llevar a Barry con Eddie en el tambo." #: lang/json/mission_def_from_json.py msgid "I just want to go home." -msgstr "" +msgstr "Solo quiero irme a casa." #: lang/json/mission_def_from_json.py msgid "I can't believe you are here, please take me back to the ranch." msgstr "" +"No puedo creer que estés acá, por favor, llevame de nuevo a la granja." #: lang/json/mission_def_from_json.py msgid "Thank you, I thought I was dead." -msgstr "" +msgstr "Gracias, pensé que estaba muerto." #: lang/json/mission_def_from_json.py msgid "Please god no!" -msgstr "" +msgstr "¡Por favor, Dios, no!" #: lang/json/mission_def_from_json.py msgid "We shouldn't stay here too long, more might show up." -msgstr "" +msgstr "No tendríamos que quedarnos mucho tiempo acá, podrían venir más." #: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "How much further?" @@ -140087,66 +143600,74 @@ msgid "" "Thanks, we'll never be able to repay you, Here's a token of my gratitude, I " "made these suits for my family and always keep a few extra around." msgstr "" +"Gracias, nunca te lo voy a poder pagar. Acá hay una muestra de mi gratitud, " +"hice estos trajes para mi familia y siempre tengo unos de más." #: lang/json/mission_def_from_json.py msgid "I don't feel saved…" -msgstr "" +msgstr "No me siento rescatado…" #: lang/json/mission_def_from_json.py msgid "Tell my family that I love them…" -msgstr "" +msgstr "Decile a mi familia que los amo…" #: lang/json/mission_def_from_json.py msgid "Find an anvil" -msgstr "" +msgstr "Encontrar un yunque" #: lang/json/mission_def_from_json.py msgid "I need an anvil to do advanced metal work." -msgstr "" +msgstr "Necesito un yunque para hacer trabajo de herrería más complejo." #: lang/json/mission_def_from_json.py msgid "I could really use an anvil." -msgstr "" +msgstr "Me vendría bien un yunque." #: lang/json/mission_def_from_json.py msgid "You might be able to find one in a hardware store or similar." -msgstr "" +msgstr "Podrías encontrar uno en alguna ferretería o negocio similar." #: lang/json/mission_def_from_json.py msgid "Thanks anyway, we'll find the time to make it ourselves." msgstr "" +"Igual, gracias, vamos a intentar tomarnos el tiempo para hacerlo nosotros." #: lang/json/mission_def_from_json.py msgid "If you can't find one, maybe you can make one for me." -msgstr "" +msgstr "Si no podés encontrar uno, tal vez puedas fabricarme uno." #: lang/json/mission_def_from_json.py msgid "Do you have the anvil?" -msgstr "" +msgstr "¿Tenés el yunque?" #: lang/json/mission_def_from_json.py msgid "" "I appreciate it, this will really make a difference, here's some horse armor" " I've been working on. Eventually I'll have the whole herd outfitted." msgstr "" +"Te lo agradezco, esto va a hacer la diferencia. Acá tenés armadura de " +"caballo que estuve haciendo. Eventualmente, voy a poder tener toda la manada" +" equipada." #: lang/json/mission_def_from_json.py msgid "What good does this do me?" -msgstr "" +msgstr "¿Para qué me sirve esto?" #: lang/json/mission_def_from_json.py msgid "Find Chris Isherwood" -msgstr "" +msgstr "Encontrar a Chris Isherwood" #: lang/json/mission_def_from_json.py msgid "" "Chris hasn't come back from his latest search for Barry, I'm getting " "concerned." msgstr "" +"Chris no volvió de la última vez que fue a buscar a Barry, me está " +"preocupando." #: lang/json/mission_def_from_json.py msgid "Can you go find my son and tell him to check in with us." -msgstr "" +msgstr "¿Podrías ir a buscar a mi hijo y decirle que se comunique?" #: lang/json/mission_def_from_json.py lang/json/mission_def_from_json.py #: lang/json/talk_topic_from_json.py lang/json/talk_topic_from_json.py @@ -140155,13 +143676,15 @@ msgstr "Gracias. " #: lang/json/mission_def_from_json.py msgid "Oh well. I hope he turns up soon." -msgstr "" +msgstr "Oh, bueno. Espero que vuelva pronto." #: lang/json/mission_def_from_json.py msgid "" "He might be on the property somewhere, maybe by that old cabin near the " "entrance, sometimes he camps there." msgstr "" +"Puede estar en algún lugar de la propiedad, tal vez cerca de esa cabaña en " +"la entrada, a veces hace campamento por ahí." #: lang/json/mission_def_from_json.py msgid "How is the search going?" @@ -140172,42 +143695,50 @@ msgid "" "Thanks, I was getting ready to go look myself. Now that I have the anvil, " "I've been working on new armor for the horses, take this prototype I made." msgstr "" +"Gracias, ya estaba por ir yo mismo. Ahora que tengo el yunque, estuve " +"trabajando en una nueva armadura para los caballos, llevate este prototipo " +"que hice." #: lang/json/mission_def_from_json.py msgid "I hope he didn't meet Barry's fate…" -msgstr "" +msgstr "Espero que no le haya pasado lo mismo que a Barry…" #: lang/json/mission_def_from_json.py msgid "Free Barry from the mysterious structure" -msgstr "" +msgstr "Liberar a Barry de esa misteriosa estructura" #: lang/json/mission_def_from_json.py msgid "" "We need to investigate the alien encampment and try to find out what " "happened to Barry." msgstr "" +"Necesitamos investigar ese campamento alienígena e intentar encontrar qué le" +" pasó a Barry." #: lang/json/mission_def_from_json.py msgid "I can take you to the structure, I tracked them to it." -msgstr "" +msgstr "Te puedo llevar hasta la estructura, los pude rastrear." #: lang/json/mission_def_from_json.py msgid "Awesome, I want some answers!" -msgstr "" +msgstr "¡Genial, quiero respuestas!" #: lang/json/mission_def_from_json.py msgid "Thanks anyway, I'll keep my eye on it, maybe I'll find a way one day." msgstr "" +"Gracias igual, voy a seguir prestando atención, tal vez encuentre una manera" +" alguna vez." #: lang/json/mission_def_from_json.py msgid "" "I feel like we are underprepared if they see us, I marked the location for " "you." msgstr "" +"Siento que no estamos preparados si nos ven, marqué el lugar para vos." #: lang/json/mission_def_from_json.py msgid "You ready?" -msgstr "" +msgstr "¿Estás listo?" #: lang/json/mission_def_from_json.py msgid "" @@ -140215,147 +143746,174 @@ msgid "" "for my family before we left. If we survive, the cabin should be fixed up " "and ready for you to move in if you want to stay." msgstr "" +"Es más alto de lo que recuerdo, deberíamos buscar prisioneros. Dejé una nota" +" para mi familia antes de salir. Si sobrevivimos, la cabaña debería ser " +"arreglada para que te puedas mudar si querés quedarte." #: lang/json/mission_def_from_json.py msgid "Well it was here…" -msgstr "" +msgstr "Bueno, estaba acá…" #: lang/json/mission_def_from_json.py msgid "Gather 50 dandelions" -msgstr "" +msgstr "Recolectar 50 dientes de león" #: lang/json/mission_def_from_json.py msgid "I could use some help foraging ingredients." -msgstr "" +msgstr "Me vendría bien un poco ayuda recolectando ingredientes." #: lang/json/mission_def_from_json.py msgid "" "I could use some fresh dandelions for the next batch of wine. Can you bring" " me 50 dandelions?" msgstr "" +"Me vendrían bien unos dientes de león frescos para la siguiente tanda de " +"vino. ¿Me podrías traer 50 dientes de león?" #: lang/json/mission_def_from_json.py msgid "Thank you, I'll put these to good use." -msgstr "" +msgstr "Gracias, les voy a dar un buen uso." #: lang/json/mission_def_from_json.py msgid "Oh well. Maybe some other time, thanks." -msgstr "" +msgstr "Ah, bueno. Tal vez en otro momento, gracias." #: lang/json/mission_def_from_json.py msgid "You can find them in the fields during the spring and summer months." msgstr "" +"Podrías encontrarlas en los campos durante los meses de primavera y verano." #: lang/json/mission_def_from_json.py msgid "Thanks. Here's a small reward to show my appreciation for your help." msgstr "" +"Gracias. Acá tenés una pequeña recompensa como muestra de mi agradecimiento " +"por tu ayuda." #: lang/json/mission_def_from_json.py msgid "I wonder if the wildlife ate all the greens…" -msgstr "" +msgstr "Me pregunto si los animales se habrán comido todo lo verde…" #: lang/json/mission_def_from_json.py msgid "Find 20 bee balm seeds" -msgstr "" +msgstr "Encontrar 20 semillas de monarda" #: lang/json/mission_def_from_json.py msgid "I could use some seeds from the forest." -msgstr "" +msgstr "Me vendrían bien unas semillas del bosque." #: lang/json/mission_def_from_json.py msgid "" "We could use some seeds for the next planting season. Can you bring me 20 " "bee balm seeds?" msgstr "" +"Nos vendrían bien unas semillas para la próxima temporada de siembra. ¿Me " +"podrías traer 20 semillas de monarda?" #: lang/json/mission_def_from_json.py msgid "" "Thank you. It's important to have a good stock before the flu season hits." msgstr "" +"Gracias. Es importante tener un buen suministro antes de que empiece la " +"temporada de gripe." #: lang/json/mission_def_from_json.py msgid "" "You should search through the forest, make sure to check in the underbrush " "for beebalm and then harvest its seeds." msgstr "" +"Deberías buscar en el bosque, y asegurarte de buscar entre la maleza para " +"encontrar monardas y recolectar sus semillas." #: lang/json/mission_def_from_json.py msgid "" "Wow, perfect. Here are some of my own remedies and if those don't work try " "my other gift." msgstr "" +"Wow, perfecto. Acá tenés algunos remedios míos y si esos no te funcionan, " +"probá con mi otro regalo." #: lang/json/mission_def_from_json.py msgid "I'll have to find someone more at home in the forest…" -msgstr "" +msgstr "Voy a tener que buscar otra persona que se sienta mejor en el bosque…" #: lang/json/mission_def_from_json.py msgid "Find and capture a cat" -msgstr "" +msgstr "Encontrar y capturar un gato" #: lang/json/mission_def_from_json.py msgid "I could use a barn cat to keep the mice down." -msgstr "" +msgstr "Me vendría bien un gato para controlar a los ratones." #: lang/json/mission_def_from_json.py msgid "" "I saw some feral cats out by the old cabin. Can you capture one for me?" msgstr "" +"Vi algunos gatos salvajes cerca de la vieja cabaña. ¿Podrás capturar uno " +"para mí?" #: lang/json/mission_def_from_json.py msgid "" "Thank you! Please hurry back! Take this cage so you have a chance of " "capturing one." msgstr "" +"¡Gracias! ¡Por favor, apurate! Llevate esta jaula así lo podés capturar." #: lang/json/mission_def_from_json.py msgid "I didn't want to use chemicals on these rats." -msgstr "" +msgstr "No quise usar químicos en estas ratas." #: lang/json/mission_def_from_json.py msgid "" "Take this pet carrier; if you can get close to a cat, you can put it inside." " If you're having problems, try befriending it with cat food." msgstr "" +"Llevate este transportador para mascota, si te podés acercar a un gato, " +"podés ponerlo adentro. Si tenés problemas, tratá de acercarte con comida " +"para gato." #: lang/json/mission_def_from_json.py msgid "Have you found a cat?" -msgstr "" +msgstr "¿Encontraste un gato?" #: lang/json/mission_def_from_json.py msgid "" "Thank you so much, I want you to have this copy of my natural remedy " "journal. I'll name this handsome fellow Joshua." msgstr "" +"Muchas gracias, quiero que tengas esta copia de mi cuaderno de remedios " +"naturales. A este bonito le voy a poner Joshua." #: lang/json/mission_def_from_json.py msgid "What?! You're lying, I can tell! Did you even bring back my cage?" msgstr "" +"¡¿Qué?! ¡Estás mintiendo, me doy cuenta! ¿Por lo menos me trajiste la jaula?" #: lang/json/mission_def_from_json.py msgid "Oh no! I guess they are too nimble for you…" -msgstr "" +msgstr "¡Oh, no! Supongo que son demasiado rápidos para vos…" #: lang/json/mission_def_from_json.py msgid "Gather 120 Rocks" -msgstr "" +msgstr "Recolectar 120 piedras" #: lang/json/mission_def_from_json.py msgid "We need to build some kilns." -msgstr "" +msgstr "Necesitamos construir algunas fosas de carbonización." #: lang/json/mission_def_from_json.py msgid "I could use 120 rocks to construct some kilns." msgstr "" +"Podría usar 120 piedras para construir algunas fosas de carbonización." #: lang/json/mission_def_from_json.py msgid "" "You can break up some larger stones, or gather them up from the fields." -msgstr "" +msgstr "Podés romper algunas piedras grandes, o juntarlas de los campos." #: lang/json/mission_def_from_json.py msgid "Thanks anyway, we'll find the time to get them ourselves." msgstr "" +"Gracias, igual. Vamos a hacernos un tiempo para ir a recolectarlas nosotros." #: lang/json/mission_def_from_json.py msgid "Mining would always be an option if you had the resources." @@ -140367,173 +143925,201 @@ msgstr "¿Ya tenés la piedra?" #: lang/json/mission_def_from_json.py msgid "I appreciate it, this will make Luke happy." -msgstr "" +msgstr "Te lo agradezco, esto va a poner feliz a Luke." #: lang/json/mission_def_from_json.py msgid "Gather 2000 units of sand" -msgstr "" +msgstr "Recolectar 2000 unidades de arena" #: lang/json/mission_def_from_json.py msgid "I do have some resource gathering I could use help with." msgstr "" +"Tengo una tarea de recolección de materiales en la que me podrías ayudar." #: lang/json/mission_def_from_json.py msgid "" "Now that the forge is set up, we could use 2000 units of sand to get " "production going." msgstr "" +"Ahora que la forja ya está puesta, necesitaríamos 2000 unidades de arena " +"para comenzar la producción." #: lang/json/mission_def_from_json.py msgid "Oh well. I'll try to find time to get it myself, thanks." msgstr "" +"Ah, bueno. Voy a intentar hacerme el tiempo para buscarla yo mismo, gracias." #: lang/json/mission_def_from_json.py msgid "" "You can find it along river banks, or maybe landscaping supplies and " "hardware stores." msgstr "" +"Podés encontrar en las orillas de los ríos, o tal vez en los negocios de " +"paisajismo o en ferreterías." #: lang/json/mission_def_from_json.py msgid "Thanks, now Luke can get started. Here's a token of my thanks." msgstr "" +"Gracias, ahora Luke puede empezar. Acá está mi muestra de agradecimiento." #: lang/json/mission_def_from_json.py msgid "I wonder where all the sand went…" -msgstr "" +msgstr "Me pregunto qué habrá pasado con toda la arena…" #: lang/json/mission_def_from_json.py msgid "Gather 1000 units of clay" -msgstr "" +msgstr "Recolectar 2000 unidades de arcilla" #: lang/json/mission_def_from_json.py msgid "I do have some resource gathering I could use help if you have time." msgstr "" +"Tengo una tarea de recolección de materiales en la que necesito ayuda si " +"tenés tiempo." #: lang/json/mission_def_from_json.py msgid "" "Now that the clay kiln is set up, we could use 1000 units of clay to get " "production going." msgstr "" +"Ahora que la fosa de carbonización está puesta, necesitaríamos 1000 unidades" +" de arcilla para comenzar la producción." #: lang/json/mission_def_from_json.py msgid "" "You can find it along river banks, or maybe look for deposits in the forest." msgstr "" +"Podés encontrar en las orillas de los ríos, o tal vez en pequeños " +"yacimientos en el bosque." #: lang/json/mission_def_from_json.py msgid "" "Thanks, now Luke can get started making jugs, We'd like to give you a cow, " "Here's Daisy, take good care of her and she'll provide you with milk." msgstr "" +"Gracias, ahora Luke puede empezar a hacer jarros. Nos gustaría darte una " +"vaca, acá está Daisy. Cuidala bien y ella te va a brindar su leche." #. ~ Nickname for creature 'mon_cow' #: lang/json/mission_def_from_json.py msgid "Daisy" -msgstr "" +msgstr "Daisy" #: lang/json/mission_def_from_json.py msgid "Find 10 3L jars" -msgstr "" +msgstr "Encontrar 10 frascos de 3L" #: lang/json/mission_def_from_json.py msgid "I could use some help scavenging." -msgstr "" +msgstr "Necesitaría ayuda buscando cosas." #: lang/json/mission_def_from_json.py msgid "" "We could use some 3 liter jars to preserve our produce. Can you bring me 10" " large three liter jars? I'll give you some preserves in exchange." msgstr "" +"Nos vendrían bien algunos frascos de 3 litros parar preservar nuestra " +"producción. ¿Podrías traerme 10 frascos grandes de tres litros? Te voy a dar" +" unas conservas a cambio." #: lang/json/mission_def_from_json.py msgid "Thank you. It's important to preserve foods while we can." -msgstr "" +msgstr "Gracias. Es importante poder preservar la comida mientras podamos." #: lang/json/mission_def_from_json.py msgid "Oh well. I'll see if I can find another way, thanks." -msgstr "" +msgstr "Ah, bueno. Voy a ver si encuentro otra manera, gracias." #: lang/json/mission_def_from_json.py msgid "Grocery stores, house kitchens, there's plenty of places to look." msgstr "" +"En los mercados, las cocinas de las casas, hay muchos lugares donde " +"buscarlos." #: lang/json/mission_def_from_json.py msgid "Wow, perfect. Thanks. Here's your reward." -msgstr "" +msgstr "Wow, perfecto. Gracias. Acá está tu recompensa." #: lang/json/mission_def_from_json.py msgid "I wonder where all the jars went…" -msgstr "" +msgstr "Me pregunto qué habrá pasado con todos los frascos…" #: lang/json/mission_def_from_json.py msgid "Find 100 wheat seeds" -msgstr "" +msgstr "Encontrar 20 semillas de trigo" #: lang/json/mission_def_from_json.py msgid "I do have some more scavenging for you." -msgstr "" +msgstr "Tengo una tarea para que me vayas a buscar algo." #: lang/json/mission_def_from_json.py msgid "" "We could use some seeds for the next planting season. Can you bring me 100 " "wheat seeds? I'll give you some fresh produce." msgstr "" +"Nos vendrían bien unas semillas para la próxima temporada de siembra. ¿Me " +"podrías traer 100 semillas de trigo? Te voy a dar producción fresca a " +"cambio." #: lang/json/mission_def_from_json.py msgid "Thank you. It's important to preserve healthy foods while we can." -msgstr "" +msgstr "Gracias. Es importante tener comida saludable mientras podamos." #: lang/json/mission_def_from_json.py msgid "Oh well. I'll see if I can find another supplier, thanks." -msgstr "" +msgstr "Ah, bueno. Voy a ver si encuentro otro que me ayude, gracias." #: lang/json/mission_def_from_json.py msgid "I wonder where all the seeds went…" -msgstr "" +msgstr "Me pregunto qué habrá pasado con todas las semillas…" #: lang/json/mission_def_from_json.py msgid "Kill monster" -msgstr "" +msgstr "Matar monstruo" #: lang/json/mission_def_from_json.py msgid "We could use some help killing some wolves." -msgstr "" +msgstr "Nos vendría bien un poco de ayudar para matar unos lobos." #: lang/json/mission_def_from_json.py msgid "" "There's been some wolves that keep scaring our chickens and horses, I'd be " "grateful if you can kill them." msgstr "" +"Hay unos lobos que están asustando a nuestras gallinas y caballos, estaría " +"agradecido si los podés matar." #: lang/json/mission_def_from_json.py msgid "Wonderful, let me know when it is done." -msgstr "" +msgstr "Maravilloso, avisame cuando ya lo hayas hecho." #: lang/json/mission_def_from_json.py msgid "Thanks anyway, we will try some traps." -msgstr "" +msgstr "Gracias, igual, vamos a probar con unas trampas." #: lang/json/mission_def_from_json.py msgid "A gun will probably help." -msgstr "" +msgstr "Un arma te podría ayudar." #: lang/json/mission_def_from_json.py msgid "Did you kill it?" -msgstr "" +msgstr "¿Lo mataste?" #: lang/json/mission_def_from_json.py msgid "" "I appreciate it, I've got this old saddle I want you to have. I'll be happy" " to put a horse under it if you want to do some more heroics." msgstr "" +"Te lo agradezco, tengo esta vieja montura que me gustaría darte. Me pondría " +"contento poner un caballo abajo de ella si estás interesado en hacer algunos" +" actos heroicos más." #: lang/json/mission_def_from_json.py msgid "Show me the bodies." -msgstr "" +msgstr "Mostrame los cadáveres." #: lang/json/mission_def_from_json.py msgid "We could use some help killing some monsters." -msgstr "" +msgstr "Nos vendría bien un poco de ayuda para matar unos monstruos." #: lang/json/mission_def_from_json.py msgid "" @@ -140541,47 +144127,59 @@ msgid "" "are, but they're very fast, I'm willing to outfit you with a horse if you " "succeed." msgstr "" +"Nos vendría bien un poco de ayuda para matar una horda de monstruos. No sé " +"dónde están pero son muy rápidos, estoy dispuesto a darte un caballo si " +"lográs tener éxito." #: lang/json/mission_def_from_json.py msgid "Be ready for anything." -msgstr "" +msgstr "Preparate para cualquier cosa." #: lang/json/mission_def_from_json.py msgid "" "I appreciate it, this will help keep our animals safe. This is, Steve, he's" " a good, steady horse. You should talk to Carlos about some armor for him." msgstr "" +"Te lo agradecería, esto nos ayudará a mantener seguros a los animales. Este " +"es Steve, es un caballo bueno y tranquilo. Tendrías que hablar con Carlos " +"para conseguirle armadura al caballo." #. ~ Nickname for creature 'mon_horse' #: lang/json/mission_def_from_json.py msgid "Steve" -msgstr "" +msgstr "Steve" #: lang/json/mission_def_from_json.py msgid "Find The Art of Glassblowing book" -msgstr "" +msgstr "Encontrar el libro El Arte de Soplar Vidrio" #: lang/json/mission_def_from_json.py msgid "I need more knowledge to get the glass blowing started." msgstr "" +"Necesito más conocimiento para poder comenzar con la producción de vidrio " +"soplado." #: lang/json/mission_def_from_json.py msgid "" "I could really use a book on glass blowing. With the internet gone, I don't" " have any handy references." msgstr "" +"Me vendría bien un libro sobre el arte de soplar vidrio. Ahora que no hay " +"internet no tengo material a mano." #: lang/json/mission_def_from_json.py msgid "Fantastic, I'm not supposed to leave our land." -msgstr "" +msgstr "Fantástico, se supone que yo no tengo que salir de acá." #: lang/json/mission_def_from_json.py msgid "Oh well, figured I'd have to do a lot of practice anyway." -msgstr "" +msgstr "Ah, bueno, igual voy a tener que hacer un montón de práctica." #: lang/json/mission_def_from_json.py msgid "A library, bookstore or a glass blower's studio should have one." msgstr "" +"Una biblioteca, una librería o un taller de un soplador de vidrio deberían " +"tener uno de esos." #: lang/json/mission_def_from_json.py msgid "Do you have the book?" @@ -140589,33 +144187,37 @@ msgstr "¿Ya conseguiste el libro?" #: lang/json/mission_def_from_json.py msgid "I appreciate it, this will make my life so much easier." -msgstr "" +msgstr "Te lo agradezco, esto facilitará mucho mi vida." #: lang/json/mission_def_from_json.py msgid "I don't see a book…?" -msgstr "" +msgstr "No veo un libro…" #: lang/json/mission_def_from_json.py msgid "At least you escaped with your life…" -msgstr "" +msgstr "Por lo menos, escapaste con vida…" #: lang/json/mission_def_from_json.py msgid "Find a copy of DIY Compendium" -msgstr "" +msgstr "Encontrar una copia del Compendio Hágalo Usted Mismo" #: lang/json/mission_def_from_json.py msgid "I need more knowledge to get better pottery." -msgstr "" +msgstr "Necesito más conocimiento para poder hacer mejor alfarería." #: lang/json/mission_def_from_json.py msgid "" "I could really use the book, DIY Compendium. With the internet gone, I " "don't have any handy references." msgstr "" +"Me vendría bien el libro, Compendio Hágalo Usted Mismo. Ahora que no hay " +"internet no tengo material a mano." #: lang/json/mission_def_from_json.py msgid "A library, bookstore should have one, schools are another good idea." msgstr "" +"Una biblioteca, una librería deberían tener uno, las escuelas podrían ser " +"otro lugar." #: lang/json/mission_def_from_json.py msgid "Locate Commo Team" @@ -140623,7 +144225,7 @@ msgstr "Localizar Eq. de Comunicaciones" #: lang/json/mission_def_from_json.py msgid "We need help…" -msgstr "" +msgstr "Necesitamos ayuda…" #: lang/json/mission_def_from_json.py msgid "" @@ -140651,6 +144253,8 @@ msgid "" "I don't know why you would bother wasting your time down here if you can't " "handle a few small tasks…" msgstr "" +"No sé por qué te tendrías que molestar en perder el tiempo acá abajo si no " +"podés encargarte de unas pequeñas tareas…" #: lang/json/mission_def_from_json.py msgid "We were briefed that the communications array was on this level." @@ -140852,13 +144456,15 @@ msgstr "Llegar al Centro de Refugiados" #: lang/json/mission_def_from_json.py msgid "Bring 40 small cardboard boxes" -msgstr "" +msgstr "Traer 40 cajitas de cartón" #: lang/json/mission_def_from_json.py msgid "" "Gotta start small right? Little ones for keeping little things safe. I " "could use 'em." msgstr "" +"¿Hay que empezar de abajo, no? Cajitas para poner cosas chiquitas. Me " +"vendrían bien." #: lang/json/mission_def_from_json.py msgid "" @@ -140866,77 +144472,88 @@ msgid "" "could use 'em. I need a bunch of 'em. Little ones, you know? Can you " "bring me like… like… forty?" msgstr "" +"¿Hay que empezar de abajo, no? Cajitas para poner cosas chiquitas. Me " +"vendrían bien. Necesito muchas. Chiquitas, ¿eh? ¿Me podrías traer unas… " +"cuarenta?" #: lang/json/mission_def_from_json.py msgid "Oh man, thanks so much my friend. You won't regret it." -msgstr "" +msgstr "Uh, chabón, muchas gracias. No te vas a arrepentir." #: lang/json/mission_def_from_json.py msgid "I didn't think so." -msgstr "" +msgstr "No me parece." #: lang/json/mission_def_from_json.py msgid "Watch out, he's looking for it too." -msgstr "" +msgstr "Cuidado, él también las está buscando." #: lang/json/mission_def_from_json.py msgid "Got the little ones yet?" -msgstr "" +msgstr "¿Conseguiste las cajitas ya?" #: lang/json/mission_def_from_json.py msgid "Oh this is so great, so great!" -msgstr "" +msgstr "¡Uh, esto es genial, genial!" #: lang/json/mission_def_from_json.py msgid "Oh, that's too bad. Guess they're eating it all." -msgstr "" +msgstr "Uh, qué mal. Supongo que se las están comiendo todas." #: lang/json/mission_def_from_json.py msgid "Bring a roll of duct tape" -msgstr "" +msgstr "Traer un rollo de cinta adhesiva" #: lang/json/mission_def_from_json.py msgid "" "These ones are good, good ones. They need something to, you know, bind them" " together. Surround them, light side, dark side." msgstr "" +"Estos están buenos, buenos. Necesitan algo para, ya sabés, mantenerlos " +"unidos. Rodearlos, lado de luz, lado oscuro." #: lang/json/mission_def_from_json.py msgid "" "These ones are good, good ones. They need something to, you know, bind them" " together. Surround them, light side, dark side. Bring me the Force!" msgstr "" +"Estos están buenos, buenos. Necesitan algo para, ya sabés, mantenerlos " +"unidos. Rodearlos, lado de luz, lado oscuro.¡Traeme la Fuerza!" #: lang/json/mission_def_from_json.py msgid "It's all around us… but did you get it in a crude matter form?" -msgstr "" +msgstr "Está a nuestro alrededor… pero ¿la conseguiste en forma cruda?" #: lang/json/mission_def_from_json.py msgid "Bring 10 medium-sized cardboard boxes" -msgstr "" +msgstr "Traer 10 cajas medianas de cartón" #: lang/json/mission_def_from_json.py msgid "" "Ten bigger ones now please. The list doesn't lie. You've done so well." msgstr "" +"Diez de las grandes ahora, por favor. La lista no miente. Lo hiciste muy " +"bien." #: lang/json/mission_def_from_json.py msgid "" "Ten bigger ones now please. The list doesn't lie. You've done so well. I " "got a little more on the list, but we're more than half there." msgstr "" +"Diez de las grandes ahora, por favor. La lista no miente. Lo hiciste muy " +"bien. Tengo un poco más en la lista pero vamos por un poco más de la mitad." #: lang/json/mission_def_from_json.py msgid "Any luck? Bigger ones?" -msgstr "" +msgstr "¿Tuviste suerte? ¿De las grandes?" #: lang/json/mission_def_from_json.py msgid "I'm so happy now!" -msgstr "" +msgstr "¡Soy tan feliz!" #: lang/json/mission_def_from_json.py msgid "Bring 10 large plastic sheets" -msgstr "" +msgstr "Traer 10 láminas grandes de plástico" #: lang/json/mission_def_from_json.py msgid "" @@ -140963,29 +144580,31 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "We're almost there, now." -msgstr "" +msgstr "Casi que terminamos, ahora." #: lang/json/mission_def_from_json.py msgid "They keep a lot of this stuff in hardware stores and lumber yards." -msgstr "" +msgstr "Guardan muchas de estas cosas en las ferreterías y las madereras." #: lang/json/mission_def_from_json.py msgid "" "I really feel bad sending you on this one, it's dangerous. Have you found " "anything?" msgstr "" +"Me siento un poco mal mandándote a hacer esto, es peligroso. ¿Encontraste " +"algo?" #: lang/json/mission_def_from_json.py msgid "Nice, this will do perfectly!" -msgstr "" +msgstr "¡Bien, esto va a andar perfecto!" #: lang/json/mission_def_from_json.py msgid "Oh, that's too bad." -msgstr "" +msgstr "Uh, qué mal." #: lang/json/mission_def_from_json.py msgid "Bring 5 large cardboard boxes" -msgstr "" +msgstr "Traer 5 cajas grandes de cartón" #: lang/json/mission_def_from_json.py msgid "" @@ -140993,6 +144612,9 @@ msgid "" "parts myself, it's been easier with more cardboard around. Can you bring me" " five more really big cardboard boxes?" msgstr "" +"Esto es lo último que necesito. Estuve juntando otras partes, es más fácil " +"con más cartón alrededor. ¿Me podrías traer cinco más de las cajas bien " +"grandes?" #: lang/json/mission_def_from_json.py msgid "" @@ -141001,32 +144623,38 @@ msgid "" " five more really big cardboard boxes? Five more cardboard boxes, as big as" " it gets. I have a few already stored up, that should be all I need." msgstr "" +"Esto es lo último que necesito. Estuve juntando otras partes, es más fácil " +"con más cartón alrededor. ¿Me podrías traer cinco más de las cajas bien " +"grandes? Cinco cajas más de cartón, tan grandes como haya. Ya tengo algunas " +"guardadas, eso sería todo lo que necesito." #: lang/json/mission_def_from_json.py msgid "Yes! The home stretch!" -msgstr "" +msgstr "¡Sí! ¡La casa se agranda!" #: lang/json/mission_def_from_json.py msgid "Oh man, but we're so close!" -msgstr "" +msgstr "¡Uh, chabón, pero ya estamos por terminar!" #: lang/json/mission_def_from_json.py msgid "Try looking in cargo storage areas." -msgstr "" +msgstr "Fijate buscando en los lugares de almacenamiento." #: lang/json/mission_def_from_json.py msgid "Did you bring me those last few boxes?" -msgstr "" +msgstr "¿Me trajiste esas últimas cajas?" #: lang/json/mission_def_from_json.py msgid "" "Brilliant! You're a true hero. I'll see if I can find a place to set these" " up now." msgstr "" +"¡Buenísimo! Sos un verdadero héroe. Voy a ver si encuentro un lugar para " +"poner esto ahora." #: lang/json/mission_def_from_json.py msgid "No! Oh god, no, this can't be happening…" -msgstr "" +msgstr "¡No! Por dios, no, esto no puede estar pasando…" #: lang/json/mission_def_from_json.py msgid "Find Dana's family sourdough culture" @@ -149038,7 +152666,7 @@ msgstr "Miembros Elásticos" #. ~ Description for {'str': 'Stretchy Limbs'} #: lang/json/mutation_from_json.py msgid "Your limbs seem to have a little more 'give' to them. +1 Dexterity." -msgstr "Tus miembros parecen tener un poco más de elasticidad. Destreza +1." +msgstr "Tus miembros parecen tener un poco más de elasticidad. +1 a Destreza." #: lang/json/mutation_from_json.py msgid "Rubbery Limbs" @@ -152022,8 +155650,7 @@ msgid "Well, maybe you'll just have to make your own world wide web." msgstr "" "Bueno, tal vez tengas que hacer tu propia telaraña informática mundial." -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "Superviviente" @@ -152388,10 +156015,6 @@ msgid "" "you." msgstr "" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "Doctor en Medicina" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -152801,11 +156424,29 @@ msgid "" msgstr "" #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "Historia de Superviviente" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgid "Survivor: Confused 1" +msgstr "" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -152813,6 +156454,86 @@ msgstr "Historia de Superviviente" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "Historia de Superviviente" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "" @@ -154637,10 +158358,6 @@ msgstr "Solo estoy intentando sobrevivir." msgid "I'm tracking game." msgstr "Estoy rastreando animales." -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "Soldado" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "Barman" @@ -155390,10 +159107,6 @@ msgstr "Cartonero" msgid "Laborer" msgstr "Peón de campo" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "Leñador" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "Ebanista" @@ -157901,6 +161614,18 @@ msgstr "calle, cámara de inspección" msgid "bridge" msgstr "puente" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "restobar de ruta" @@ -173440,102 +177165,6 @@ msgstr "" msgid "I'd kill for a sip of water right now." msgstr "" -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "" -"Sí, claro, ¡no pude evitar darme cuenta que tenés cerveza! Abramos una y " -"charlemos, , ¿cómo va?" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "" -"Ah, definitivamente. ¿Qué tal una de esas cervezas que tenés encima? ¿Qué " -"onda vos?" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "" -"¡Sí, convidame alguna de esas birras que veo que tenés y podemos conversar " -"todo lo que quieras! Es joda, ¿cómo va, ?" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "Ey, dale, , así descanso un rato, ¿cómo andás?" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "Sí dale, , ¿cómo va?" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "¡Dale, vamos a charlar un rato! ¿Todo bien?" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "¿Por qué no? ¿Cómo te va?" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "Me parece bien, ¿cómo va?" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "Puedo tomarme unos minutos, ¿cómo andan las cosas?" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "Dale,, ¿vos bien?" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "Bueno, ¿necesitas descargarte sobre algo?" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "¡Siempre dispuesto a una buena charla! Pero ¿por qué, estás bien?" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "OK, , así nos conocemos un poco más, ¿cómo la vas llevando?" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "Definitivamente, buena idea. ¿Cómo te trata esto?" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "maldición" @@ -176002,6 +179631,18 @@ msgstr "" msgid "Was it rough surviving thus far?" msgstr "" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -176717,6 +180358,301 @@ msgstr "" msgid " will follow normal engagement rules." msgstr "" +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "Me parece bien, ¿cómo va?" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "Dale,, ¿vos bien?" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "Bueno, ¿necesitas descargarte sobre algo?" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "¡Siempre dispuesto a una buena charla! Pero ¿por qué, estás bien?" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -178047,6 +181983,14 @@ msgstr "" "casquillo. El texto dice: \"8x40mm sin casquillo de Rivtech. Nada se le " "asemeja.\"" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -178056,6 +182000,21 @@ msgid "" " reads: \"WE ARE HERE TO PROTECT YOU.\"" msgstr "" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -189990,11 +193949,11 @@ msgid "Acolyte." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" +msgid "You're back. Have you come to listen to the song?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" +msgid "You there. Quiet down. Can you hear it? The song?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -190029,8 +193988,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -190043,11 +194002,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" @@ -190065,11 +194024,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" #: lang/json/talk_topic_from_json.py @@ -190078,7 +194037,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "" @@ -190092,10 +194051,10 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" #: lang/json/talk_topic_from_json.py @@ -190105,7 +194064,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" @@ -190121,8 +194080,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" @@ -190132,9 +194091,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" #: lang/json/talk_topic_from_json.py @@ -190192,14 +194151,6 @@ msgstr "" msgid "Perhaps another time, Seer." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "" @@ -190208,10 +194159,6 @@ msgstr "" msgid "Not interested." msgstr "No estoy interesado." -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "" @@ -190228,20 +194175,13 @@ msgstr "" msgid "I'm off then." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "" @@ -190252,7 +194192,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "" #: lang/json/talk_topic_from_json.py @@ -190267,11 +194207,6 @@ msgstr "" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "" @@ -190283,14 +194218,14 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" #: lang/json/talk_topic_from_json.py @@ -190317,6 +194252,14 @@ msgstr "" msgid "Skip it, let's get going." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "Hablemos de los campamentos de bandos." + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "" @@ -190495,7 +194438,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -190656,8 +194599,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -190679,7 +194622,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -190731,8 +194674,8 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." -msgstr "No, solo no..." +msgid "No, just no…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Just let me sleep, !" @@ -190743,8 +194686,8 @@ msgid "Make it quick, I want to go back to sleep." msgstr "Hacelo rápido, quiero irme a dormir." #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." -msgstr "Unos minutitos más..." +msgid "Just few minutes more…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Anything to do before I go to sleep?" @@ -190790,76 +194733,118 @@ msgid "I want to set some miscellaneous rules." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Can you teach me anything?" -msgstr "¿Me podés enseñar algo?" +msgid "I'd like to know a bit more about your abilities." +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's trade items" -msgstr "Vamos a intercambiar objetos" +msgid "There's something I want you to do." +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I want you to use this item." +msgid "I just wanted to talk for a bit." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hold on to this item." +msgid "Can you help me understand something? (HELP/TUTORIAL)" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Guard this position." -msgstr "Cuidá esta posición." +msgid "I'm going to go my own way for a while." +msgstr "Voy a seguir mi propio camino por un tiempo." #: lang/json/talk_topic_from_json.py -msgid "I want to assign you to work at this camp." +msgid "Let's go." +msgstr "Vamos." + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." +msgid "Sure, what did you want to say?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "Hablemos de los campamentos de bandos." +msgid "Mind if we just chat for a bit about your history?" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Find a horse and mount up!" +msgid "Let's just chitchat for a while, I could use some relaxation." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Get off your mount, please." +msgid "I changed my mind, wanted to ask you something else." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Please go to this location." +msgid "I'm all ears, my friend." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." +msgid "You gonna give me orders?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" +msgid "What would you like?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" +msgid "Just say the word." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." +msgid "Can you teach me anything?" +msgstr "¿Me podés enseñar algo?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's trade items" +msgstr "Vamos a intercambiar objetos" + +#: lang/json/talk_topic_from_json.py +msgid "I want you to use this item." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." +msgid "Hold on to this item." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "Voy a seguir mi propio camino por un tiempo." +msgid "Guard this position." +msgstr "Cuidá esta posición." #: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "Vamos." +msgid "I want to assign you to work at this camp." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Find a horse and mount up!" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Get off your mount, please." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Please go to this location." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I want you to build a camp here." +msgstr "Quiero que construyas un campamento acá." + +#: lang/json/talk_topic_from_json.py +msgid "We need to abandon this camp." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Show me what needs to be done at the camp." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about your current activity." +msgstr "" #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." @@ -191401,10 +195386,6 @@ msgstr "" msgid "Stay at your current position." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "" @@ -191477,62 +195458,6 @@ msgstr "" msgid "Sure thing, I'll make my way there." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "" -"Sí, el calor de este verano me está pegando mal, vamos a descansar un rato, " -"¿cómo andás, ?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "OK, así dejo de cagarme de frío un rato. ¿Cómo va?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -191587,8 +195512,8 @@ msgid "Hello there." msgstr "Hola, ¿qué tal?" #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." -msgstr "Bueno, sin hacer movimientos repentinos..." +msgid "Okay, no sudden movements…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep your distance!" @@ -191946,8 +195871,8 @@ msgid "Ah, okay." msgstr "Ah, ok." #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." -msgstr "Hasta que no tenga algún antibiótico, no..." +msgid "Not until I get some antibiotics…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "You asked me recently; ask again later." @@ -192055,8 +195980,8 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." -msgstr "Dale tiempo, te voy a mostrar algo nuevo después..." +msgid "Give it some time, I'll show you something new later…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I have some reason for denying you training." @@ -192083,8 +196008,8 @@ msgid "See you around." msgstr "Nos vemos por ahí." #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." -msgstr "Realmente no me siento cómodo haciendo eso..." +msgid "I really don't feel comfortable doing so…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I'll give you some space." @@ -192155,7 +196080,7 @@ msgid "Thanks, see you later!" msgstr "¡Gracias, nos vemos después!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." +msgid "You picked up something that does not belong to you…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -192249,13 +196174,13 @@ msgid "You might be seeing more of me…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" +msgid "Hey again. *kzzz*" msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "" #: lang/json/talk_topic_from_json.py @@ -192277,7 +196202,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -192290,7 +196215,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "" @@ -192312,7 +196237,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -192328,7 +196253,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -192363,14 +196288,6 @@ msgstr "Decime cómo funcionan los campamentos de bandos." msgid "Tell me how faction camps have changed." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "Quiero que construyas un campamento acá." - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "Nada. Hablemos de otra cosa." @@ -192592,10 +196509,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." +"talk…" msgstr "" -"¿Seguro? Este no parece un lugar particularmente seguro para ponerse a " -"charlar..." #: lang/json/talk_topic_from_json.py msgid "It's fine, we've got a moment." @@ -192617,6 +196532,50 @@ msgstr "¿De qué querés hablar?" msgid "Actually, never mind." msgstr "En realidad, no importa." +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "" @@ -192638,7 +196597,7 @@ msgid "May the earth flourish beneath our paths." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -192822,8 +196781,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" @@ -193397,7 +197356,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -193879,6 +197838,38 @@ msgstr "" msgid "Huh." msgstr "Ah." +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -193931,19 +197922,9 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" -"Eventualmente, sí. Estuvo tranquilo por unas horas. Tenía sed, estaba herido" -" y con mucho miedo. Mi entrenamiento era lo único que evitaba que me " -"volviera loco. Decidí intentar salir y ver cuáles eran mis heridas. Fue " -" fácil. El costado de la camioneta estaba destrozado, así que al final" -" solo estaba tirado abajo de un poco de escombro, con las ruinas de la " -"camioneta formando como una carpa encima mío. Ni siquiera tenía heridas " -"graves. Agarré todo el equipamiento que pude, y salí. Era de noche. Podía " -"escuchar ruido de luchas alejadas, así que fui para el otro lado. Hice unas " -"cuadras hasta que me encontré algún ... Salí corriendo. Corrí y " -"corrí y corrí un poco más. Y acá estoy." #: lang/json/talk_topic_from_json.py msgid "" @@ -194283,6 +198264,30 @@ msgstr "Pobre Dan el Sucio. " msgid "Thanks for telling me that stuff. " msgstr "Gracias por contarme. " +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -194344,6 +198349,24 @@ msgid "" "died in the crash, but I am not going back to find out." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -194382,6 +198405,21 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "¿Qué pensás que les pasó? ¿Los volviste a ver?" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -194450,6 +198488,40 @@ msgid "" "pretty good life compared to those first few months." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -194462,6 +198534,50 @@ msgstr "" "Estaba ocupado con los otros pasajeros, así que hice lo que hubiera hecho " "cualquiera y salí cagando." +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -194513,6 +198629,27 @@ msgstr "Perdón. ¿Me podés contar algo más de ellos?" msgid "Right. Sorry." msgstr "Está bien. Perdón." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -194533,6 +198670,19 @@ msgstr "" "pude llevarme. Volví unos días después pero el lugar estaba abandonado. No " "sé qué le pasó a toda esa gente." +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -194631,6 +198781,42 @@ msgstr "Perdón por preguntar. " msgid "Sorry for asking. " msgstr "Perdón por preguntar. " +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -195345,6 +199531,48 @@ msgstr "" "un shopping abandonado pero como necesitaba comida me fui al bosque. No me " "estaba yendo muy bien, así que me alegra que hayas aparecido." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -195409,6 +199637,128 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "Gracias por decirme todo eso. " +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -195733,13 +200083,48 @@ msgstr "" msgid "I can respect that." msgstr "Puedo respetar eso." +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "Gracias por eso." + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -195841,6 +200226,43 @@ msgstr "" "enojar. El que yo era antes ya no está. Se murió. Me importa un carajo lo " "que te parezca 'sano', no me vuelvas a preguntar, ." +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -196202,11 +200624,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "" -"Evasión de impuestos. Yo era contador, y lo ayudaba a mi jefe a mover una " -"montaña de plata de manera inteligente. No suficientemente inteligente, " -"parece ser..." #: lang/json/talk_topic_from_json.py msgid "" @@ -196427,6 +200846,32 @@ msgstr "" "Supongo que seremos los humildes quienes poblaremos la Tierra. Aunque no me " "gustan nuestras posibilidades." +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -196438,6 +200883,23 @@ msgstr "" " a transitar este Infierno en la Tierra. Me arrepiento de no haber prestado " "atención en Catecismo." +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -196706,10 +201168,6 @@ msgstr "¿Cómo era trabajar para los Mercaderes Libres?" msgid "What was working for the Old Guard like?" msgstr "¿Y cómo era trabajar para la Vieja Guardia?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "Gracias por eso." - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "Gracias por eso. Vamos yendo." @@ -196974,6 +201432,22 @@ msgstr "" msgid "What were you saying before that?" msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "Hola, ¿qué tal?" @@ -197497,7 +201971,7 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -197890,10 +202364,6 @@ msgid "" " catastrophe." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "" @@ -199379,7 +203849,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" @@ -200113,7 +204583,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -201175,12 +205645,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" #: lang/json/talk_topic_from_json.py @@ -201308,12 +205778,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" #: lang/json/talk_topic_from_json.py @@ -201377,7 +205847,7 @@ msgid "Hm? Oh, hi." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "" #: lang/json/talk_topic_from_json.py @@ -201741,8 +206211,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" #: lang/json/talk_topic_from_json.py @@ -201759,9 +206229,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -202123,8 +206593,8 @@ msgid "" msgstr "No hospedamos basuras como vos, terminá con tus negocios y tomatelas." #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." -msgstr "No estoy al mando acá, estás buscando a otra persona..." +msgid "I'm not in charge here, you're looking for someone else…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep civil or I'll bring the pain." @@ -202171,12 +206641,12 @@ msgid "Well, I'd better be going. Bye." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." -msgstr "Bienvenido, alguacil..." +msgid "Welcome marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." -msgstr "Bienvenido..." +msgid "Welcome…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" @@ -202427,12 +206897,12 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." -msgstr "Alguacil..." +msgid "Marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." -msgstr "Ciudadano..." +msgid "Citizen…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Can I trade for supplies?" @@ -203095,7 +207565,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -203280,15 +207750,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." +msgid "Thinking I should go hunt something soon…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "" #: lang/json/talk_topic_from_json.py @@ -203328,7 +207798,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." +"marshal…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -203397,8 +207867,8 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "No puedo ni imaginar para qué necesitaría tu ayuda." #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." -msgstr "Quedate quieto mientras busco mis tijeras..." +msgid "Stand still while I get my clippers…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Thanks…" @@ -203832,8 +208302,8 @@ msgstr "" " la mayor parte del tiempo afuera del puesto." #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." -msgstr "Por favor, dejame solo..." +msgid "Please leave me alone…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "What's wrong?" @@ -203853,17 +208323,14 @@ msgstr "Qué triste." #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." -msgstr "No sé qué podés hacer. Yo probé de todo. Dame un poco de tiempo..." +"I don't know what you could do. I've tried everything. Just give me time…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." +"seems like I can't keep anything down…" msgstr "" -"¡Sigo enfermándome! Al principio pensé que era algo que comí pero ahora " -"parece que no puedo mantener nada adentro..." #: lang/json/talk_topic_from_json.py msgid "Uhm." @@ -203993,8 +208460,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "" #: lang/json/talk_topic_from_json.py @@ -204339,7 +208806,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "" @@ -204508,7 +208975,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -204675,7 +209142,7 @@ msgid "Oh, you again." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -204683,7 +209150,7 @@ msgid "I'm busy, what is it?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "" #: lang/json/talk_topic_from_json.py @@ -204830,7 +209297,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Lizard Tail" -msgstr "" +msgstr "Cola de Lagarto" #: lang/json/technique_from_json.py #, python-format @@ -204859,7 +209326,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Lizard Wall Counter" -msgstr "" +msgstr "Contrataque de Pared de Lagarto" #: lang/json/technique_from_json.py #, python-format @@ -205051,7 +209518,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Centipede Strike" -msgstr "" +msgstr "Golpe de Ciempiés" #: lang/json/technique_from_json.py #, python-format @@ -205065,17 +209532,18 @@ msgstr " golpea velozmente %s" #: lang/json/technique_from_json.py msgid "Centipede Bite" -msgstr "" +msgstr "Mordida de Ciempiés" #: lang/json/technique_from_json.py #, python-format msgid "You palm strike %s with a painful Centipede Bite" -msgstr "" +msgstr "Le das un golpe de palma al %s con una dolorosa Mordida de Ciempiés" #: lang/json/technique_from_json.py #, python-format msgid " palm strikes %s with a painful Centipede Bite" msgstr "" +" le da un golpe de palma al %s con una dolorosa Mordida de Ciempiés" #: lang/json/technique_from_json.py #, python-format @@ -205624,31 +210092,31 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Sweep Kick" -msgstr "" +msgstr "Patada Barredora" #: lang/json/technique_from_json.py #, python-format msgid "You sweep kick %s" -msgstr "" +msgstr "Le tirás una patada barredora al %s" #: lang/json/technique_from_json.py #, python-format msgid " sweep kicks %s" -msgstr "" +msgstr " le tira una patada barredora al %s" #: lang/json/technique_from_json.py msgid "Spin Kick" -msgstr "" +msgstr "Patada Giratoria" #: lang/json/technique_from_json.py #, python-format msgid "You spin kick %s" -msgstr "" +msgstr "Le tirás una patada giratoria al %s" #: lang/json/technique_from_json.py #, python-format msgid " spin kicks %s" -msgstr "" +msgstr " le tira una patada giratoria al %s" #: lang/json/technique_from_json.py msgid "Crane Wing" @@ -205708,21 +210176,21 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Dragon Claw" -msgstr "" +msgstr "Garra de Dragón" #: lang/json/technique_from_json.py #, python-format msgid "You lash out at %s with a Dragon Claw" -msgstr "" +msgstr "Atacás al %s con la Garra de Dragón" #: lang/json/technique_from_json.py #, python-format msgid " lashes out at %s with a Dragon Claw" -msgstr "" +msgstr " ataca al %s con la Garra de Dragón" #: lang/json/technique_from_json.py msgid "Dragon Vortex Block" -msgstr "" +msgstr "Bloqueo del Dragón" #: lang/json/technique_from_json.py #, python-format @@ -205736,7 +210204,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Dragon Wing Dodge" -msgstr "" +msgstr "Ala Esquivadora de Dragón" #: lang/json/technique_from_json.py #, python-format @@ -205750,17 +210218,17 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Dragon Tail" -msgstr "" +msgstr "Cola de Dragón" #: lang/json/technique_from_json.py #, python-format msgid "You sweep %s with a quick Dragon Tail" -msgstr "" +msgstr "Barrés al %s con una rápida Cola de Dragón" #: lang/json/technique_from_json.py #, python-format msgid " sweeps %s with a quick Dragon Tail sweep" -msgstr "" +msgstr " barre al %s con una rápida barrida de la Cola de Dragón" #: lang/json/technique_from_json.py msgid "Dragon Strike" @@ -205769,12 +210237,12 @@ msgstr "Golpe de Dragón" #: lang/json/technique_from_json.py #, python-format msgid "You descend upon %s with a powerful Dragon Strike" -msgstr "" +msgstr "Descendés sobre el %s con un potente Golpe de Dragón" #: lang/json/technique_from_json.py #, python-format msgid " descends upon %s with a powerful Dragon Strike" -msgstr "" +msgstr " desciende sobre el %s con un potente Golpe de Dragón" #: lang/json/technique_from_json.py msgid "Round Strike" @@ -205820,7 +210288,7 @@ msgstr " le da un golpe seco al %s" #: lang/json/technique_from_json.py msgid "Combination Strike" -msgstr "" +msgstr "Golpe Combinado" #: lang/json/technique_from_json.py #, python-format @@ -205886,17 +210354,18 @@ msgstr " le da un golpe de esgrima al %s" #: lang/json/technique_from_json.py msgid "Compound Attack" -msgstr "" +msgstr "Ataque Compuesto" #: lang/json/technique_from_json.py #, python-format msgid "Your feint leads to a compound attack against %s" -msgstr "" +msgstr "Tu finta te lleva a hacer un ataque compuesto contra el %s" #: lang/json/technique_from_json.py #, python-format msgid "'s feint leads to a compound attack against %s" msgstr "" +"La finta de lo lleva a hacer un ataque compuesto contra el %s" #: lang/json/technique_from_json.py msgid "Fencing Riposte" @@ -205966,7 +210435,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Hook and Drag" -msgstr "" +msgstr "Enganchar y Arrastrar" #: lang/json/technique_from_json.py #, python-format @@ -206258,7 +210727,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Sweeping Strike" -msgstr "" +msgstr "Golpe de Barrido" #: lang/json/technique_from_json.py #, python-format @@ -206272,7 +210741,7 @@ msgstr " hace caer %s con un golpe de barrido" #: lang/json/technique_from_json.py msgid "Vicious Strike" -msgstr "" +msgstr "Golpe Feroz" #: lang/json/technique_from_json.py #, python-format @@ -206704,12 +211173,12 @@ msgstr "" #: lang/json/technique_from_json.py #, python-format msgid "You crouch low and sweep-kick %s" -msgstr "" +msgstr "Te agachás y le tirás una patada barredora al %s" #: lang/json/technique_from_json.py #, python-format msgid " crouches low and sweep-kicks %s" -msgstr "" +msgstr " se agacha y le tira una patada barredora al %s" #: lang/json/technique_from_json.py #, python-format @@ -206723,17 +211192,17 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Palm Strike" -msgstr "" +msgstr "Golpe de Palma" #: lang/json/technique_from_json.py #, python-format msgid "You palm strike %s" -msgstr "" +msgstr "Le das un golpe de palma al %s" #: lang/json/technique_from_json.py #, python-format msgid " palm strikes %s" -msgstr "" +msgstr " le da un golpe de palma al %s" #: lang/json/technique_from_json.py msgid "Grasp the Sparrow's Tail" @@ -206751,17 +211220,17 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Double Palm Strike" -msgstr "" +msgstr "Doble Golpe de Palma" #: lang/json/technique_from_json.py #, python-format msgid "You double-handed palm strike %s" -msgstr "" +msgstr "Le das un golpe de palma con las dos manos al %s" #: lang/json/technique_from_json.py #, python-format msgid " double-handed palm strikes %s" -msgstr "" +msgstr " le da un golpe de palma con las dos manos al %s" #: lang/json/technique_from_json.py msgid "Tiger Palm" @@ -206807,7 +211276,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Straight Punch (Knockback)" -msgstr "" +msgstr "Golpe Recto (Empujar)" #: lang/json/technique_from_json.py #, python-format @@ -206835,7 +211304,7 @@ msgstr "" #: lang/json/technique_from_json.py msgid "L-hook (Knockback)" -msgstr "" +msgstr "Gancho (Empujar)" #: lang/json/technique_from_json.py #, python-format @@ -207536,17 +212005,18 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Spin Attack" -msgstr "" +msgstr "Ataque Giratorio" #: lang/json/technique_from_json.py #, python-format msgid "You unleash a spin attack against %s and those nearby" -msgstr "" +msgstr "Desplegás un ataque giratorio contra el %s y los que estén cerca" #: lang/json/technique_from_json.py #, python-format msgid " unleashes a spin attack against %s and those nearby" msgstr "" +" desplega un ataque giratorio contra el %s y los que estén cerca" #: lang/json/technique_from_json.py msgid "Disarming Strike" @@ -207774,31 +212244,31 @@ msgstr "" #: lang/json/technique_from_json.py msgid "Mighty Throw" -msgstr "" +msgstr "Tirada Poderosa" #: lang/json/technique_from_json.py #, python-format msgid "You toss %s aside with a Mighty Throw" -msgstr "" +msgstr "Tirás al %s para un lado con tu Tirada Poderosa" #: lang/json/technique_from_json.py #, python-format msgid " tosses %s with a Mighty Throw" -msgstr "" +msgstr " tira al %s con su Tirada Poderosa" #: lang/json/technique_from_json.py msgid "Ballista Throw" -msgstr "" +msgstr "Tirada de Balista" #: lang/json/technique_from_json.py #, python-format msgid "You spin and hurl %s away with a Ballista Throw" -msgstr "" +msgstr "Girás y arrojás al %s con tu Tirada de Balista" #: lang/json/technique_from_json.py #, python-format msgid " spins and hurls %s away with a Ballista Throw" -msgstr "" +msgstr " gira y arroja al %s para un lado con su Tirada de Balista" #: lang/json/technique_from_json.py msgid "Flowing Water" @@ -209045,209 +213515,14 @@ msgid "" msgstr "" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "tierra" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "" -"Es tierra. Parece que es de buena calidad como para cultivar. También puede " -"ser quitada para usar en alguna construcción." - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "tomp" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "" -"Es un área grande con arena que podría utilizarse de varias maneras, si se " -"la extrae de manera apropiada." - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "arcilla" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "" -"Es un campo lleno de arcilla maleable, ideal para la alfarería si se la " -"extrae de manera apropiada." - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "montículo de arcilla" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "¡splash!" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "montículo de arena" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "montículo de tierra" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "" -"Es un área de tierra removida, difícil para caminar por ahí. Si se la " -"examina un poco, se ve que es bastante favorable para plantar semillas y " -"cosas así." - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "" -"Es una pilla gigante de tierra en la que parece que podrías meterte para " -"usar de refugio." - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "desperfecto extraño" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" -"Es un agujero antinatural con forma humanoide, y te resulta extrañamente " -"familiar. Sentís una extraña sensación al examinarlo, como si te " -"perteneciera de alguna manera." - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "suelo de piedra" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "" -"Es un área relativamente plana de piedra y roca. Parece lo suficientemente " -"estable como para poder ser extraída con el equipo adecuado de minería." - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "pavimento" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." -msgstr "" -"Es un pedazo de asfalto, lentamente degradándose por las rajaduras, el " -"congelamiento y la falta de mantenimiento." - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "pavimento amarillo" - -#. ~ Description for yellow pavement -#: lang/json/terrain_from_json.py -msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" -"Son rayas de pintura amarilla cuidadosamente alineadas en la ruta para " -"informar a los conductores que no deben cruzarlas. Aunque ya nadie cuida que" -" estas cosas se cumplan." - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "vereda" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." +msgid "overgrown floor" msgstr "" -"Es un área con concreto común, dañado por el congelamiento y las rajaduras " -"grandes que tiene debido a la falta de mantenimiento." -#. ~ Description for concrete +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "" -"Es un sector nuevo con concreto con terminaciones en la superficie para " -"hacerlo más estético y resistente a los ciclos de congelamiento y " -"descongelamiento." - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "" - -#. ~ Description for wooden floor -#: lang/json/terrain_from_json.py -msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -209255,41 +213530,15 @@ msgid "SMASH!" msgstr "¡SMASH!" #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "suelo de metal" - -#. ~ Description for metal floor -#: lang/json/terrain_from_json.py -msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgid "overgrown wall" msgstr "" -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "baldosa de linóleo" - -#. ~ Description for linoleum tile +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." msgstr "" -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "suelo de tierra" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." -msgstr "" -"Es un piso que consiste en tierra fina mezclada que ha sido apisonada." - #: lang/json/terrain_from_json.py msgid "concrete floor" msgstr "suelo de concreto" @@ -209387,6 +213636,23 @@ msgstr "" "terminado. Al piso todavía no lo emparejaron y el techo todavía no está " "completamente lleno." +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "suelo de piedra" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "" +"Es un área relativamente plana de piedra y roca. Parece lo suficientemente " +"estable como para poder ser extraída con el equipo adecuado de minería." + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "suelo de metal" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -209396,6 +213662,10 @@ msgstr "" "Es un piso de buena calidad y resistente con baldosas cuadriculadas que " "reduce el riesgo de patinarse y caerse, con un techo que combina." +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "tomp" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "suelo" @@ -209444,6 +213714,10 @@ msgstr "" "Es un piso de madera dura que ha sido tratado con químicos para disminuir la" " posibilidad de patinarse, generalmente utilizado para deportes recreativos." +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "suelo de tierra" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -209530,28 +213804,15 @@ msgid "A blue section of flooring." msgstr "" #: lang/json/terrain_from_json.py -msgid "industrial carpet" +msgid "carpet" msgstr "" -#. ~ Description for industrial carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." +msgid "Base carpet!" msgstr "" -#: lang/json/terrain_from_json.py -msgid "bunker carpet" -msgstr "" - -#. ~ Description for bunker carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." -msgstr "" - -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "Es una suave alfombra roja." @@ -209571,6 +213832,124 @@ msgstr "Es una suave alfombra verde." msgid "Soft purple carpet." msgstr "Es una suave alfombra púrpura." +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "baldosa de linóleo" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "" + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "suelo pintado encerado" @@ -209609,6 +213988,37 @@ msgstr "" "apocalípticas. Espero que te guste el sonido de la lluvia sobre el metal " "corrugado." +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "tierra" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "" +"Es tierra. Parece que es de buena calidad como para cultivar. También puede " +"ser quitada para usar en alguna construcción." + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "" +"Es un área grande con arena que podría utilizarse de varias maneras, si se " +"la extrae de manera apropiada." + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "musgo" @@ -209618,6 +214028,32 @@ msgstr "musgo" msgid "Moist spongy moss." msgstr "Es musguito esponjoso y húmedo." +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "arcilla" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "" +"Es un campo lleno de arcilla maleable, ideal para la alfarería si se la " +"extrae de manera apropiada." + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "montículo de arcilla" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "¡splash!" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "" @@ -209627,6 +214063,150 @@ msgstr "" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "montículo de arena" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "montículo de tierra" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "" +"Es un área de tierra removida, difícil para caminar por ahí. Si se la " +"examina un poco, se ve que es bastante favorable para plantar semillas y " +"cosas así." + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "" +"Es una pilla gigante de tierra en la que parece que podrías meterte para " +"usar de refugio." + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "desperfecto extraño" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" +"Es un agujero antinatural con forma humanoide, y te resulta extrañamente " +"familiar. Sentís una extraña sensación al examinarlo, como si te " +"perteneciera de alguna manera." + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "pavimento" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr "" +"Es un pedazo de asfalto, lentamente degradándose por las rajaduras, el " +"congelamiento y la falta de mantenimiento." + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "pavimento amarillo" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "" +"Son rayas de pintura amarilla cuidadosamente alineadas en la ruta para " +"informar a los conductores que no deben cruzarlas. Aunque ya nadie cuida que" +" estas cosas se cumplan." + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "vereda" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "" +"Es un área con concreto común, dañado por el congelamiento y las rajaduras " +"grandes que tiene debido a la falta de mantenimiento." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "" +"Es un sector nuevo con concreto con terminaciones en la superficie para " +"hacerlo más estético y resistente a los ciclos de congelamiento y " +"descongelamiento." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "" +"Es un piso que consiste en tierra fina mezclada que ha sido apisonada." + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "nogal" @@ -213723,6 +218303,78 @@ msgstr "" msgid "A ladder leading down." msgstr "" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "pendiente hacia abajo" @@ -214214,7 +218866,7 @@ msgstr "¡Clank!" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "¡Bang!" @@ -216956,6 +221608,15 @@ msgid "" "extending the time until the food spoils." msgstr "" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "" @@ -217806,8 +222467,9 @@ msgstr "" msgid "The lock stumps your efforts to pick it." msgstr "La cerradura no cede a tus intentos de forzarla." -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "" @@ -217868,6 +222530,120 @@ msgstr "" msgid "Continue trying to fall asleep and don't ask again." msgstr "" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -222511,6 +227287,29 @@ msgstr "%s (%i lugares);" msgid "Increased storage capacity by %i." msgstr "Capacidad de almacenamiento incrementada en %i." +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "" @@ -222681,7 +227480,8 @@ msgid "(incapacitated)" msgstr "" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" +#, c-format +msgid "(fuel saving ON > %d %%)" msgstr "" #: src/bionics_ui.cpp @@ -222750,7 +227550,7 @@ msgstr "Precisión" #: src/bonuses.cpp msgid "Critical Hit Chance" -msgstr "" +msgstr "Probabilidad de Golpe Crítico" #: src/bonuses.cpp src/martialarts.cpp msgid "Dodge" @@ -223374,6 +228174,23 @@ msgstr "¡ consigue liberarse de las telarañas!" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "¡Intentás liberarte de las telarañas, pero no podés!" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "" + +#: src/character.cpp +msgid " frees themselves!" +msgstr "" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "Intentás escaparte del pozo, pero te resbalás y volvés a caer." @@ -224244,6 +229061,10 @@ msgstr "" msgid "Your body strains under the weight!" msgstr "¡Tu cuerpo se esfuerza en mantener tanto peso!" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -226912,7 +231733,7 @@ msgstr "¡Golpe en la cabeza!" #: src/creature.cpp src/iuse.cpp src/melee.cpp msgid "Critical!" -msgstr "Critico!" +msgstr "¡Crítico!" #: src/creature.cpp msgid "Good hit!" @@ -228379,15 +233200,6 @@ msgid "" "Roof: %s" msgstr "" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -232536,6 +237348,10 @@ msgstr "No tenés nada para recargar." msgid "You aren't holding something you can reload." msgstr "" +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -235110,6 +239926,10 @@ msgstr "¡Ignorar láser de determinación de objetivo!" msgid "Creature whitelisted: %s" msgstr "Criatura permitida: %s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "¿Te querés suicidar?" @@ -236497,11 +241317,28 @@ msgstr "" msgid "There is a %s there. Take down?" msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "Hay un %s ahí. ¿Lo querés desarmar?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "¡Desarmás la trampa!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "No pudiste desarmar la trampa." + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "¡No pudiste desarmar la trampa, y la hiciste accionar!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -237394,6 +242231,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "" + #: src/init.cpp msgid "Finalizing" msgstr "Terminando" @@ -238427,7 +243269,7 @@ msgid "" "very bad idea." msgstr "" -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -239341,7 +244183,7 @@ msgstr "" #: src/item.cpp #, c-format msgid "Critical hit chance %d%% - %d%%" -msgstr "" +msgstr "Probabilidad de Golpe Crítico %d%% - %d%%" #: src/item.cpp msgid "Bashing: " @@ -240149,6 +244991,13 @@ msgstr "" msgid "is not a container" msgstr "" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "" +msgstr[1] "" + #: src/item_contents.cpp msgid "is not rigid" msgstr "" @@ -240215,6 +245064,10 @@ msgstr "abierto" msgid "Pocket %d:" msgstr "Bolsillo %d:" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "" + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "" @@ -242047,10 +246900,6 @@ msgstr "S N A K E" msgid "Sokoban" msgstr "Sokoban" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "Buscaminas" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "¡Luces encendidas!" @@ -244973,7 +249822,7 @@ msgstr "El %s necesita un %s al lado." msgid "You can't place a %s there. It contains a trap already." msgstr "No podés poner un %s ahí. Ya tiene una trampa." -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "¡Hacés disparar un %s!" @@ -246740,6 +251589,15 @@ msgstr "" msgid "Summon" msgstr "" +#: src/magic.cpp +msgid "random creature" +msgstr "" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "Alcance" @@ -246760,6 +251618,10 @@ msgstr "" msgid "Spawned" msgstr "" +#: src/magic.cpp +msgid "Threshold" +msgstr "" + #: src/magic.cpp msgid "Recover" msgstr "" @@ -246812,6 +251674,15 @@ msgstr "" msgid "%s wounds are closing up!" msgstr "" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "" @@ -247280,30 +252151,23 @@ msgstr "" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "¡Desarmás la trampa!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "No pudiste desarmar la trampa." +msgid "Something has crawled out of the %s plants!" +msgstr "¡Algo salió arrastrándose de las plantas de %s!" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "¡No pudiste desarmar la trampa, y la hiciste accionar!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "¡Algo salió arrastrándose del/a %s!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "¡Algo salió arrastrándose de las plantas de %s!" +msgid "You've spotted a %1$ss!" +msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "¡Algo salió arrastrándose del/a %s!" +msgid " triggers a %s!" +msgstr "" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -248094,7 +252958,7 @@ msgstr "" #: src/melee.cpp msgid "You miss and stumble with the momentum." -msgstr "Le errás y te tropezás por el ímpetu." +msgstr "Le errás y te tropezás por el impulso." #: src/melee.cpp msgid "You swing wildly and miss." @@ -248107,7 +252971,7 @@ msgstr "Le errás." #: src/melee.cpp #, c-format msgid "%s misses and stumbles with the momentum." -msgstr "%s le erra y tropieza por el ímpetu." +msgstr "%s le erra y tropieza por el impulso." #: src/melee.cpp #, c-format @@ -248490,13 +253354,13 @@ msgstr "%s pero no causás daño." #: src/melee.cpp #, c-format msgid "%s. Critical!" -msgstr "%s. ¡Critico!" +msgstr "%s. ¡Crítico!" #. ~ someone hits something for %d damage (critical) #: src/melee.cpp #, c-format msgid "%s for %d damage. Critical!" -msgstr "" +msgstr "%s por %d de daño. ¡Crítico!" #. ~ NPC hits something #: src/melee.cpp @@ -248859,6 +253723,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "¡Ahora sos buscada por la policía!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -252665,6 +257542,11 @@ msgstr "" msgid "zombie slave" msgstr "esclavo zombi" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "Empujar %s" + #: src/monexamine.cpp msgid "Rename" msgstr "Renombrar" @@ -258034,17 +262916,6 @@ msgstr "Mutaciones por radiación" msgid "If true, radiation causes the player to mutate." msgstr "Si está activado, la radiación causará mutaciones en el personaje." -#: src/options.cpp -msgid "Z-levels" -msgstr "" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" - #: src/options.cpp msgid "Character point pools" msgstr "Grupos de puntos de personaje" @@ -262894,6 +267765,15 @@ msgctxt "grammatical gender list" msgid "n" msgstr "" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "¡Pisaste plástico de burbuja!" diff --git a/lang/po/es_ES.po b/lang/po/es_ES.po index 48399e4e65948..3b1825809680a 100644 --- a/lang/po/es_ES.po +++ b/lang/po/es_ES.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-06-26 12:50+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: Miguel de Dios Matias , 2020\n" "Language-Team: Spanish (Spain) (https://www.transifex.com/cataclysm-dda-translators/teams/2217/es_ES/)\n" @@ -51742,6 +51742,34 @@ msgid "" "Felt patches, bundled tightly together for storage. Disassemble to unpack." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -63669,6 +63697,17 @@ msgstr "" "Una canillas de metal que puede ser puesta en un tanque de agua para " "facilitar el uso." +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "" +msgstr[1] "" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "" + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -111313,8 +111352,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" +msgid "MAS .223" +msgid_plural "MAS .223" msgstr[0] "" msgstr[1] "" @@ -205133,6 +205172,15 @@ msgid "" "extending the time until the food spoils." msgstr "" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "" diff --git a/lang/po/ja.po b/lang/po/ja.po index 4d504309dc8a6..c9cfb1371ab6c 100644 --- a/lang/po/ja.po +++ b/lang/po/ja.po @@ -24,15 +24,15 @@ # xyz , 2020 # Susuki Mochiduki, 2020 # T5idr3, 2020 -# TEATIME , 2020 # zojirushi, 2020 +# TEATIME , 2020 # Pigmentblue15, 2020 # msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: Pigmentblue15, 2020\n" "Language-Team: Japanese (https://www.transifex.com/cataclysm-dda-translators/teams/2217/ja/)\n" @@ -799,6 +799,16 @@ msgstr[0] "ナイトロックス" msgid "Mixture of oxygen and nitrogen in proportions suitable for diving." msgstr "酸素と窒素を潜水に適した比率で混合した気体です。" +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "消火剤" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "消火に効果的な粉末薬品です。" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -3992,6 +4002,25 @@ msgid "" "with some kind of mask or mouth protection." msgstr "化学物質噴霧器に装填して使う、強力な殺虫剤です。使用の際はマスクなどで口を防護しましょう" +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "弾薬(12.3ln)" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" +"12.3ln弾は第二次カルパチア紛争をきっかけにルーマニアで導入されました。この弾薬を使うPA " +"md.71ライフルが東側諸国で急速に人気を博し、その後世界に広まったという経緯から、12.3ln弾はユーラシア圏の標準的な軍用弾薬になりました。そのため、エクゾディはこの弾薬を容易に収集、備蓄できました。見た目は.30-06口径スプリングフィールド弾と非常によく似ていますが、先端が少し細くなっています。" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -4965,7 +4994,7 @@ msgstr[0] "塗料(黄)" msgid "A can of yellow paint." msgstr "塗料(黄)の入った缶です。" -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "絨毯(赤)" @@ -6917,7 +6946,7 @@ msgstr[0] "弾倉ポーチ" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." +"rockets will not fit. Use insert to store ammunition." msgstr "ほとんどの種類の小型弾薬を入れて持ち運べる小さなポーチです。流石にロケット弾は入りません。使用すると弾薬を装填します。" #: lang/json/ARMOR_from_json.py @@ -7009,9 +7038,9 @@ msgstr[0] "矢筒" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." -msgstr "革製の腰掛け矢筒です。20本の矢を収納できます。" +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." +msgstr "腰に掛けて使う革製の矢筒です。使用すると最大20本の矢を収納します。" #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -7022,8 +7051,8 @@ msgstr[0] "矢筒(白樺樹皮)" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." -msgstr "白樺樹皮を編んで作った、腰に身に着ける矢筒です。20本の矢を収納できます。使用すると矢を収納します。" +"20 arrows or bolts. Use insert to store arrows or bolts." +msgstr "白樺樹皮を編んで作った、腰に掛けて使う矢筒です。使用すると最大20本の矢を収納します。" #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -7034,10 +7063,11 @@ msgstr[0] "矢筒(大型)" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" -"肩に背負って使う、金属で補強した大型の革製矢筒です。矢が60本入ります。歴史的には徒歩弓兵よりも弓騎兵が好んで使っていましたが、ゾンビとの戦いに役立つかは未知数です。使用すると矢を収納します。" +"革製の金属で補強した、肩に背負って使う大型の矢筒です。歴史上では弓騎兵、徒歩弓兵などが使っていましたが、ゾンビとの戦いに役立つかは未知数です。使用すると最大60本の矢を収納します。" #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -7048,8 +7078,8 @@ msgstr[0] "矢筒(大型/白樺樹皮)" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." -msgstr "白樺樹皮で作られた大型の矢筒です。肩に掛けて背負います。60本の矢を収納できます。" +"hold 60 arrows or bolts. Use insert to store arrows or bolts." +msgstr "白樺樹皮を編んで作った、肩に背負って使う大型の矢筒です。使用すると最大60本の矢を収納します。" #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -16465,10 +16495,10 @@ msgstr "" #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." -msgstr "主に旅行中の衣服を運ぶ用途に使う、中型サイズのスーツケースです。収納性は抜群ですが、持ち運びにはあまり適しません。" +msgstr "主に旅行中の衣服を運ぶ用途に使う、車輪が付いた中型サイズのスーツケースです。収納性は抜群ですが、持ち運びにはあまり適しません。" #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -21586,14 +21616,14 @@ msgstr "背骨と脳幹の間に移植された爆弾です。タイマーが付 #: lang/json/BIONIC_ITEM_from_json.py lang/json/bionic_from_json.py msgid "Skullgun CBM" msgid_plural "Skullgun CBMs" -msgstr[0] "" +msgstr[0] "CBM: スカルガン" #. ~ Description for {'str': 'Skullgun CBM'} #: lang/json/BIONIC_ITEM_from_json.py lang/json/bionic_from_json.py msgid "" "Concealed in your head is a single shot .40 pistol. Activate the bionic to " "fire and reload the skullgun." -msgstr "" +msgstr "頭部に.40口径の単発銃を埋め込みます。起動することで射撃したり装填したりできます。" #: lang/json/BIONIC_ITEM_from_json.py msgid "Precision Solderers CBM" @@ -28361,6 +28391,18 @@ msgid "" "your pain at bay." msgstr "激しいフィットネスのような儀式を行うことで苦痛を和らげます。" +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "巻物(ベールフル・ポリモーフ)" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "敵をカエルに変えます。" + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -29868,6 +29910,20 @@ msgid "" "on combining magic with EM radiation." msgstr "魔法と電磁波の融合に関する情報がびっしりと載っている、研究所の参考資料です。" +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "ルーン文字の石板片" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" +"更に大きな厚板から切り出されたように見える、小さな黒い石板です。表面に刻まれた金色に光るルーン文字を見つめると、ゆっくりと読みやすい文字に変化します。" + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -34832,6 +34888,30 @@ msgid "" "cheese. Delicious." msgstr "塩味の効いたトルティーヤチップスに挽肉を添え、溶かしたチーズをかけました。とても美味しいです。" +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "ナチョス(豆)" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "塩味の効いたトルティーヤチップスに豆を添えました。溶かしたチーズをかけるとより美味しく食べられます。" + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "ナチョス(豆とチーズ)" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "塩味の効いたトルティーヤチップスに豆を添え、溶かしたチーズをかけました。ベジタリアンではなくても美味しく食べられます。" + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -39286,24 +39366,52 @@ msgid "" msgstr "鳥用の餌です。主成分は種子や牧草、マメ科の草であり、小鳥に最適の飼料です。" #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "ドッグフード" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "ドッグフード(ウェット)" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'wet dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." -msgstr "犬用の餌です。変な匂いがしますが、犬はこれが大好き。" +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "缶詰に入った、生肉を使ったイヌ用の柔らかい餌です。変な匂いがしますが、イヌはこれが大好きです。" #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "キャットフード" +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "ドッグフード(ドライ)" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'dry dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." -msgstr "猫用の餌です。変な匂いがしますが、猫はこれが大好き。" +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "長く保存できる、イヌ用の硬い餌です。乾燥した肉や穀物を使っており、ビタミンやミネラルが豊富です。" + +#: lang/json/COMESTIBLE_from_json.py +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "キャットフード(ウェット)" + +#. ~ Description for {'str_sp': 'wet cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." +msgstr "缶詰に入った、生肉を使ったネコ用の柔らかい餌です。ネコが好きそうな変な臭いがします。" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "キャットフード(ドライ)" + +#. ~ Description for {'str_sp': 'dry cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "長く保存できる、ネコ用の硬い餌です。乾燥した肉や穀物を使っており、ビタミンやミネラルが豊富です。" #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -45546,6 +45654,32 @@ msgid "" "Felt patches, bundled tightly together for storage. Disassemble to unpack." msgstr "保管のためにしっかりと束ねたフェルトの生地です。分解して使いましょう。" +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "素材束(木材)" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "10枚の建設用木材をロープで固定したものです。分解して使いましょう。" + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "素材束(頑丈な短枝)" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "10本の頑丈な短枝をロープで固定したものです。分解して使いましょう。" + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -49505,6 +49639,54 @@ msgid "" "wound." msgstr "顎から上が消失した死体です。何が原因でこうなったのか見当もつきません。" +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -51181,7 +51363,7 @@ msgstr[0] "マイク" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "音声の録音や増幅に使われる、クリップが付いた一般的なマイクです。底面にはアンプに接続するための3ピンXLRコネクタが備わっています。" #: lang/json/GENERIC_from_json.py @@ -51353,6 +51535,19 @@ msgid "" "anything on its own." msgstr "井戸から飲み水を汲み上げるために使う、昔ながらの機械式ポンプです。個人で使用するにしても少々心もとない性能です。" +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "管継手セット" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "エンドキャップ、分岐継手などの金属パイプ用継手が複数揃っています。色々な作業に役立ちます。" + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -53132,6 +53327,110 @@ msgid "" msgstr "" "奇妙な樹脂の断片です。縁は丸みを帯びていて艶があり、表面がざらついた巨大なビーチグラスのようにも見えます。触ってみるとほのかに温かさを感じます。" +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "シャシー(エクゾディ)" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" +"おおよそ六角形に造られたフレームとそれに付随する車体は、まるで単一の素材から切り出されたようにみえます。重度の摩耗や修理の痕跡があるにもかかわらず、取付穴や付属品は非常に耐久性に優れています。汎用性が高い構造になっており、激しい戦闘にも耐えられるように感じます。" + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "シャシー(エクゾディドローン)" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" +"おおよそ六角形に造られた小さなフレームとそれに付随する車体は、まるで単一の素材から切り出されたようにみえます。重度の摩耗や修理の痕跡があるにもかかわらず、取付穴や付属品は非常に耐久性に優れています。汎用性が高い構造になっており、激しい戦闘にも耐えられるように感じます。" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "サイバネティック神経回路装置" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" +"液体と電力、信号をやり取りするためのタンクとチューブが連なった複雑な形状の装置です。生きた状態で移植することが最も困難な臓器である、脳と脊椎を収容するために使います。" + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "奇妙な電子機械" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" +"配線と形状を見れば、コンピュータかそれに類する電子機器であることは推察できますが、それが何なのか、どのような役割を果たすのかは、全く分かりません。非常に重く頑丈な作りになっています。" + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "金属製の装置" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" +"電子機器のようですが、見たこともない外見です。金属の板に銅色のリングが同心円状にはめ込まれており、そのリングから中央の軸に向かってワイヤーが伸びています。" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "サイバネティックセンサー" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" +"ガラスで作られた目玉のような物体です。小さな皿ほどの大きさから推察するに、ある種のカメラだと考えられます。内部の仕組みはまったく理解できず、今までに見たどのカメラとも似ていません。" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "回転装置" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" +"銅線のような物を巻いたコイルとピストンが付いているため、恐らくモーターや発電機の一種だと考えられます。今までに見たこともないデザインのため、どのように動かすのか見当もつきません。" + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -56113,6 +56412,16 @@ msgstr[0] "蛇口" msgid "A metal faucet that can be attached to a water tank for easy access." msgstr "金属製の蛇口です。給水タンクに取り付けると内部の液体を簡単に流せます。" +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "木製ホイールハブ" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "自転車のホイールを取り付ける穴が付いた木製部品です。" + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -56912,7 +57221,7 @@ msgstr "フォトニック技術で作り出した神経繊維の軸索は、化 #: lang/json/GENERIC_from_json.py msgid "neurosynaptic interface matrix" msgid_plural "neurosynaptic interface matrices" -msgstr[0] "神経シナプス接続マトリックス" +msgstr[0] "神経シナプス接続回路網" #. ~ Description for {'str': 'neurosynaptic interface matrix', 'str_pl': #. 'neurosynaptic interface matrices'} @@ -59254,7 +59563,7 @@ msgstr "分類: 木材" #. ~ Description for Loot: Wood #: lang/json/LOOT_ZONE_from_json.py msgid "Destination for firewood and items that can be used as such." -msgstr "焚き木として利用できるアイテムを置く区域です。" +msgstr "焚物として利用できるアイテムを置く区域です。" #: lang/json/LOOT_ZONE_from_json.py msgid "Loot: Custom" @@ -61524,6 +61833,34 @@ msgid "" "thrower." msgstr "噴霧器に化学物質を供給する容量2Lの自家製加圧容器です。" +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "弾倉(12.3ln/PA Md.71エクゾディ)" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" +"古典的なPA " +"Md.71クリップをベースとした、スタイリッシュな小型弾倉です。エクゾディによる改造を経て、空気より軽いドローンで運用できるようになりました。小型かつ装填が少し不便なため、ゾンビの大群を相手にした地上戦には向きません。" + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "弾倉(12.3ln/PA Md.68エクゾディ)" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "重量があるPA Md.68バトルライフル用の、途方もなく重い大型弾倉です。エクゾディが独自に設計、製造しました。" + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -62513,6 +62850,48 @@ msgid "" msgstr "" "人間の身体に金属部品とワイヤーが絡み付き融合しています。その目は虚ろですが、時折、異様な人体の不可逆性を思い出したかのように悲痛な表情を浮かべます。十分な外科手術の技術があれば、ある程度人間らしい姿に戻してやることもできます。このサイボーグがそれを望んでいるならの話ですが..." +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "エクゾディ作業ロボット" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "様々な建設工具を備えた人型ロボットです。" + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "エクゾディ四足歩行ロボット" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" +"見慣れない部品を組み合わせて作られた、巨大な四足歩行ロボットです。足音と共に重々しく妙に優雅な足取りで移動し、地面に浅いクレーターを残します。様々な武器を搭載していますが、こちらを狙っているようには見えません。" + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "サイボーグゾンビ" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" +"死んだ人間と死んだ技術が合わさって作られた怪物です。鋼と肉が混じり合い、怒った幼児に振り回される人形のように滅茶苦茶に動きます。機械部品の動力は停止したようで、肉の帯がそれらを包み込み、でたらめに引っ張り固定しています。金属製の骨格と装甲の裂け目から、腐りかけの肉が飛び出しています。" + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -62731,6 +63110,23 @@ msgid "" "appears to have a mininuke inside. If this is targeting you… Run." msgstr "4つの回転翼を備えた通常の何倍も大きなマンハックです。小型原子爆弾を内蔵しているようです。もしも運悪く標的にされたなら...逃げましょう。" +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "狙撃ドローン" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" +"観測気球とクワッドローターを組み合わせたような姿の、奇妙な機械です。本体と思しきシンプルな箱の下には、ライフルを装備した小型の多関節腕が吊るされています。プロペラが一瞬起動した後すぐに停止し、気流をものともしないほとんど静止した状態を維持しています。電源が切れるまでかなり長く空中に留まっていられそうです。" + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -64449,6 +64845,21 @@ msgid "" msgstr "" "アメリカ東部に生息するピューマは、大柄なネコ科の捕食者です。この地域では絶滅したと思われていましたが、種の保全努力により、個体数を回復させる事に成功しました。素早く静かに動くこの狩人は、強いジャンプ力によって遠距離から獲物を狙い、致命的な攻撃力をもつ爪で捕獲し、発達した牙で噛み殺します。" +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "トラ" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" +"ネコ科の大型肉食動物、荘厳な姿のトラです。原産はアジアですが、現在ではアメリカ国内の私有地に最も多く生息しています。素早くパワフルなこの肉食動物は、世界でもっとも有名で愛されていますが、同時に最も危険な動物でもあります。" + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -66520,6 +66931,19 @@ msgstr[0] "拡声装置" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "大音量でメッセージを繰り返し伝え続ける、強力な拡声器です。" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "改造タレット" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "この重厚なタレットは、まるで様々な技術を組み合わせてボルトで固定したような、極めて異質な形状です。重そうなマシンガンを装備しています。" + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -66606,6 +67030,63 @@ msgid "" msgstr "" "Uncanny社の最初の製品である、優しい顔でたたずむ4本腕の人型ロボットです。その容貌は驚くほど細部まで作りこまれていますが、手触りは硬く不快です。世界が崩壊しても支援すべき患者を探し続けています。" +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "スケルトン犬" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" +"かつてイヌだったものは、全ての皮膚が剥がれ、融合した骨の甲殻が露わになっています。肉がすべて失われた動く骨は、血管や筋肉のように全身を覆う艶やかな黒い粘液の脈動によって制御されているようです。" + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -66715,21 +67196,6 @@ msgid "" "outpace its two-legged friends." msgstr "活発に動き回る形の崩れた犬の死体です。筋肉質の恐るべき獣は、二本足で歩く人間を易々と追い越します。" -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "スケルトン犬" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" -"かつてイヌだったものは、全ての皮膚が剥がれ、融合した骨の甲殻が露わになっています。肉がすべて失われた動く骨は、血管や筋肉のように全身を覆う艶やかな黒い粘液の脈動によって制御されているようです。" - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -66833,6 +67299,30 @@ msgid "" "and its eyes bulge with black goo." msgstr "ゾンビ化したピューマです。後ろ脚が肥大化し、目は黒く粘つく何かによって膨張して見えます。" +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "ゾンビトラ" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "一見すると普通のトラですが、時折よろめき、顎は外れかけており、大きく開いた目は黒く輝いています。" + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "ゾンビクモの大群" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "何千、何万ものクモが高々と積み上がり、粘り気のある緑色の体液を滲ませながら、悪臭を放つ死骸を必死に動かそうとしています。" + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -67365,6 +67855,43 @@ msgstr "身体が不気味に捻じれて昆虫のような姿に変形してい msgid "The impaler launches a barb!" msgstr "毒虫ゾンビは針を射出しました!" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -69548,19 +70075,6 @@ msgid "" " black eyes, and a tattered sail on its back." msgstr "瞳から黒い液体が滲み出ている、ボロボロの帆を背負ったワニのような獰猛な顔つきのゾンビ恐竜です。" -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "冥暗ゾンビスピノサウルス" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "ボロボロの帆を背負った巨大な二足歩行恐竜です。頭部は細長く、口が尖っています。不気味な影に包まれており、輪郭がぼやけています。" - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -69571,31 +70085,6 @@ msgstr[0] "ゾンビティラノサウルス" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "巨大な牙が生えた、悪臭を放つ傷だらけの筋肉の塊です。" -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "冥暗ゾンビティラノサウルス" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "羽毛が生えた巨大な二足歩行恐竜のゾンビです。頭部は大きく、口元から鋭い歯列が覗いています。不気味な影に包まれており、輪郭がぼやけています。" - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "スケルトンティラノサウルス" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "黒い粘液が滴る大きな尖った歯を見せつけている、巨大な骨の集合体です。" - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -69697,20 +70186,6 @@ msgid "" "sickle-like claw." msgstr "ボロボロの羽毛と酷く臭う黒い液体で覆われた、フラフラと歩く中型二足歩行恐竜のゾンビです。両足から生えた鎌のような爪を振り回しています。" -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "冥暗ゾンビデイノニクス" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" -"羽毛が生えた中型の二足歩行恐竜のゾンビです。両足から生えた大鎌のような爪を振り回しています。不気味な影に包まれており、輪郭がぼやけています。" - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -69761,6 +70236,326 @@ msgid "" msgstr "" "脚を引きずって歩く中型恐竜のゾンビです。鋭い牙が生えており、頭部には特徴的な2つの頭骨があります。傷ついた身体から肉片がフリルのように垂れ下がっています。" +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "冥暗ゾンビスピノサウルス" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "ボロボロの帆を背負った巨大な二足歩行恐竜です。頭部は細長く、口が尖っています。不気味な影に包まれており、輪郭がぼやけています。" + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "冥暗ゾンビティラノサウルス" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "羽毛が生えた巨大な二足歩行恐竜のゾンビです。頭部は大きく、口元から鋭い歯列が覗いています。不気味な影に包まれており、輪郭がぼやけています。" + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "冥暗ゾンビデイノニクス" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" +"羽毛が生えた中型の二足歩行恐竜のゾンビです。両足から生えた大鎌のような爪を振り回しています。不気味な影に包まれており、輪郭がぼやけています。" + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "スケルトンティラノサウルス" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "黒い粘液が滴る大きな尖った歯を見せつけている、巨大な骨の集合体です。" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -70213,6 +71008,18 @@ msgid "" "off creatures that disturb it." msgstr "敵を追い払うために鋭い金切り声を発する、人間大のキノコです。" +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "カエル" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "アメリカで一般的なウシガエルです。王子様は逃げた方が良さそうです。" + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -70848,6 +71655,14 @@ msgstr "両生類" msgid "a bird" msgstr "鳥類" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "異星サイボーグ" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "[重々しい衝撃音]" + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "爬虫類" @@ -71582,19 +72397,19 @@ msgstr "頭蓋爆弾発動に使われる疑似呪文です。致命的なダメ #: lang/json/SPELL_from_json.py msgid "Skullgun Snapback" -msgstr "" +msgstr "スカルガン反動(CBM)" #. ~ Description for Skullgun Snapback #: lang/json/SPELL_from_json.py msgid "" "This fake spell occurs on skullgun activation. May be fatal if done in " "critical condition." -msgstr "" +msgstr "スカルガン発動に使われる疑似呪文です。体力によっては致命的なダメージを与える可能性があります。" #. ~ Message for SPELL 'Skullgun Snapback' #: lang/json/SPELL_from_json.py msgid "Your head snaps back from the force of the shot." -msgstr "" +msgstr "発射の反動で首が後ろに折れ曲がりました。" #: lang/json/SPELL_from_json.py msgid "psi stun" @@ -71718,6 +72533,17 @@ msgid "" "rune as a catalyst for recipes." msgstr "儀式によってアニミストと波長の合う神秘的な石を創り出します。石はレシピの触媒として利用できます。" +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "ソウルレンド" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "敵の肉体から精神を無理やり引き剥がし、その結果生じる亡霊を意志の力で縛ります。" + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "イグニス・ファトゥス" @@ -71940,6 +72766,15 @@ msgstr "疲労増加(デバッグ専用)" msgid "Uses a little fatigue" msgstr "疲労が少し増加します。" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "ポリモーフ(デバッグ)" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "体重を減らしたかったんですか?" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "HP消費(デバッグ専用)" @@ -72371,6 +73206,10 @@ msgstr "マナ・ボルト" msgid "Haste" msgstr "ヘイスト" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "ベールフル・ポリモーフ" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "マナ・ビーム" @@ -75038,7 +75877,7 @@ msgstr "雷の神トールが身に着けていた魔法の帯、またはその #: lang/json/TOOL_ARMOR_from_json.py msgid "lesser dimensional toolbelt" msgid_plural "lesser dimensional toolbelts" -msgstr[0] "" +msgstr[0] "小型次元ツールベルト" #. ~ Description for {'str': 'lesser dimensional toolbelt'} #: lang/json/TOOL_ARMOR_from_json.py @@ -75046,12 +75885,12 @@ msgid "" "A sturdy workman's belt that fits around your waist, covered in easy to " "access pouches. Like all dimensional spaces, they hold more than they " "should with a fair weight reduction." -msgstr "" +msgstr "収納しやすいポーチがたくさん付いた、腰にフィットする丈夫な作業用ベルトです。他の次元アイテムと同様に、収納した物の重量が軽減されます。" #: lang/json/TOOL_ARMOR_from_json.py msgid "greater dimensional toolbelt" msgid_plural "greater dimensional toolbelts" -msgstr[0] "" +msgstr[0] "大型次元ツールベルト" #. ~ Description for {'str': 'greater dimensional toolbelt'} #: lang/json/TOOL_ARMOR_from_json.py @@ -75060,6 +75899,7 @@ msgid "" "access pouches. Like all dimensional spaces, they hold far more than they " "should with a substantial weight reduction." msgstr "" +"収納しやすいポーチがたくさん付いた、腰にフィットする大型の作業用ベルトです。他の次元アイテムと同様に、収納した物の重量が大幅に軽減されます。" #: lang/json/TOOL_ARMOR_from_json.py msgid "Belt of Weaponry" @@ -76081,6 +76921,18 @@ msgid "bionic firestarter" msgid_plural "bionic firestarters" msgstr[0] "発火装置(CBM)" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "燻製ラック" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "これはcrafting_pseudo_itemであり、所持している場合はバグが発生しています。" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -76146,7 +76998,7 @@ msgstr[0] "ジャック・オ・ランタン" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "点火する" @@ -78692,12 +79544,6 @@ msgid "pseudo butter churn" msgid_plural "pseudo butter churns" msgstr[0] "バター撹拌機" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "これはcrafting_pseudo_itemであり、所持している場合はバグが発生しています。" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -80880,14 +81726,37 @@ msgid "throwable fire extinguisher" msgid_plural "throwable fire extinguishers" msgstr[0] "投擲式消火器" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "ピンを引き抜く" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "投擲式消火器のピンを引き抜きました。" + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." msgstr "" -"手榴弾の形をした消火器です。一般的な消火器ほど効果的ではありませんが、遠くから投げることで効果を発揮します。熱を加えることで消火剤が噴き出します。" +"手榴弾の形をした消火器です。一般的な消火器ほど効果的ではありませんが、近寄らずに火を消せます。プラスチック製のピンを引き抜くと起動しますが、熱を加えても起動するので、そのまま炎の中に投げ入れても大丈夫です。" + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "投擲式消火器(起動)" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" +msgstr "投擲式消火器のピンは既に引かれており、今にも消火剤をまき散らしそうです。投げましょう!" #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -87000,7 +87869,7 @@ msgid "Pheidippides was a hack" msgstr "新世界のフィリッピデス" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "マラソン...にもうちょっと足した距離を走る" #: lang/json/achievement_from_json.py @@ -87045,7 +87914,7 @@ msgstr "タンクスーツを装備する" #: lang/json/achievement_from_json.py msgid "What are they hiding?" -msgstr "どんな秘密を見つけた?" +msgstr "非公開情報" #: lang/json/achievement_from_json.py msgid "Enter a lab finale room" @@ -87067,6 +87936,594 @@ msgstr "全てはここから始まった" msgid "Return to the location you started the game" msgstr "ゲーム開始地点に戻る" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "木こり入門" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "誰もいない森の中で木が倒れたとき、その音はするのでしょうか?" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "木こり" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "斧を持った人間にとっての森とは何でしょうか?" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "森林破壊" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "森を拓けばオオカミが飛び出します。" + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "墓掘り人" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "求めるものは、より多くの死体です。" + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "墓泥棒" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "ちょっと、断られたらどうするんです?本人に許可を取りましょうよ。" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "告別式" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "数多の人間が死んでも放っておかれる状況で、埋葬は特権です。" + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "葬儀屋" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "腐敗する遺体をゾンビと一緒に扱うべきではありません。" + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "葬儀場" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "世界を埋葬するなんて可能なのでしょうか?" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "サイバーパンク" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "心は熱しているが、肉体は弱い。" + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "時計仕掛けの人間" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "機械の汚れた手で、お前に復讐しよう...お前にも。それが何であれ、私にもまだ分からぬ。だが世界は恐怖におののく。" + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "ホモ・エボルティス" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "人類の世は終わりを告げ、長きに渡る超人類の世が幕を開けます。" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "破壊されたが敗北はしていない" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "医療保険は適用されますか?" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "自由貿易" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "並外れた商品をバカバカしいほどの安値でご提供!" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "カット・ミー・オウン・スロート・ディブラー" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "イヌイットのお客さん、氷はいかがかな。とっても安いよ、出血大サービスだよ。" + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "口八丁" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "私たち、友達だろ?" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "雄弁" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "巨体ゾンビを説得して帰らせたという伝説があります。" + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "ハッカーマン" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "このOSには非常口がある。どんなところにも非常口はあるものだ。" + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "Kevinと似て非なるもの" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "チートではありません。デバッグです。" + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "医療関係者" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "お客様の中にお医者様はいらっしゃいませんか?" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "Dr. HOUSE" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "この患者はSLEだ。" + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "技術者" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "いいからレンチを取ってくれ。" + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "マクガイバー" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "この計画の要は信仰と唾とダクトテープです。" + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "罠猟師" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "良い罠はビーバーとゾンビーバーを区別しません。" + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "マインスイーパー" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "一度のミスが命取り。" + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "エースドライバー" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "曲がれないカーブはありません。" + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "The Stig" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "F1なんて休日のドライブみたいなものです。" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "スイマー" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "水を得た魚のようです。" + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "マイケル・フェルプス" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "ジョーズよりずっと速い。" + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "DIY" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "これをそこに置いて、あれをそれに入れたら、はい出来上がり。" + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "何でも屋" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "接着剤さえ用意できれば不可能はありません。" + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "料理長" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "ヒレ肉の照り焼きも朝飯前です。" + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "ヘルズ・キッチン" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "本日のメニューはスープ・ア・ロニオン、ブルゴーニュ風牛ワイン煮込み、クレームブリュレです。" + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "仕立て屋" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "針と糸と夢を携えています。" + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "ファッションデザイナー" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "男性、女性、変異体のファッションが得意分野です。" + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "サバイバー" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "サバイバルは得意分野です。" + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "ベア・グリルス" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "自分の尿まで使って生き残るというのですか?" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "オームの法則" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "サンダーオーム。2ボルトが1ボルトになる。抵抗は無意味だ。" + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "ニコラ・テスラ" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "9V電池の味は簡単に確かめられるものではない。" + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "大当たり" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "レゴラスより上手です。" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "ロビン・フッド" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "ウィリアム・テル?知らない人ですね。" + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "鷹の目" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "狙い撃ち。" + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "百発百中" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "逃げるな。疲れて死ぬだけだ。" + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "砲手" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "口径の差を見せつけましょう。" + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "ロケットマン" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "月まで届けてあげよう。バラバラにしてね。" + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "小さくても油断は禁物" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "銃口の先に立った者はわざわざ口径を測ったりしません。" + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "ダーティハリー" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" +"こいつはマグナム44って言って世界一強力な拳銃なんだ。お前のドタマなんて一発で消し飛ぶぜ?楽にあの世まで逝けるんだ。運が良けりゃな。さあどうする?" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "ライフル銃兵" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "これが我が銃。銃は数あれど我が物は一つ。これぞ我が最良の友。我が命。我銃を制すなり。我が命を制するごとく。" + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "兵士" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" +"我なくして銃役立たず。銃なくして我役立たず。我的確に銃を撃つなり。我が銃を常に清く保ち備えん。我が体を常に清く保ち備えるがごとく。我らは共に一体とならん。" + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "銃身が2倍で楽しさも2倍" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "1発で9回命中させるのも夢ではありません。" + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "エルマー・ファッド" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "どったのセンセー?ウハギ狩り?" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "スプレー・アンド・プレイ" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "1発は当たるでしょう。統計的な問題ですね。" + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "SMGをバババババ!" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "もっと弾薬が必要です。" + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "ぽーい!" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "そして二度と戻ってはこなかった。" + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "コービー・ブライアント" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "手榴弾投擲!" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "暴れ者" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "左手にガラス瓶、右手に椅子の脚。" + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "ストリートファイター" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "重要なのはスタイルではなく勝利です。" + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "バッター" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "素振りをする度にホームランに近付きます。" + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "石器時代" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "棍棒は人類最初の道具でした。最後の道具になるかもしれません。習得しておきましょう。" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "剣の道" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "宮本武蔵" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "剣とは単なる武器以上のもの、すなわち人生に対する問いへの答えとなるべきものです。" + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "煙に巻く" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "最強の攻撃も当たらなければ意味はありません。" + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "ネオ" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "弾丸も躱せるでしょうか?" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "白刃" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "お前がパーティーを楽しんでいる間、ずっと刃物の研究をしていたんだ。" + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "切り裂きジャック" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "目の前に見えるのは短剣か?取っ手を俺の方に向けている。よし、掴んでみよう。" + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "少林寺への道" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "拳に軍団が宿っている気がします。" + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "ミヤギ先生" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "お前自身が武器となるのだ。" + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "空き巣" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "バール?そんなの野蛮ですよ。" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "錠前師" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "どんな錠前にも鍵はあります。" + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "周期表" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "大体は料理と同じですが、スプーンを舐めるのは止めましょう。" + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "ハイゼンベルク" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "すでに知ってるはずだ。私はメスを作っている。私の名は。" + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "魔法使い志望者" @@ -87521,6 +88978,11 @@ msgstr "ハッキング" msgid "canceling activity serialized with legacy code" msgstr "古いコードでシリアライズされた行動の取消" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "運動" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "核融合セル" @@ -87822,6 +89284,10 @@ msgstr "噴霧薬品" msgid "compressed air" msgstr "圧縮空気" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "弾薬(12.3ln)" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "紙筒弾" @@ -89739,6 +91205,62 @@ msgstr "1体のキャラクターも殺していません。" msgid "Merciful" msgstr "慈悲の心" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "エルフの小道" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "木を伐採しない" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "ホモ・サピエンス" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "CBMを移植しない" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "欠陥CBMを移植しない" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "変異しない" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "X線検査異常なし" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "純血種" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "構造的完全性" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "四肢の骨を折らない" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "教師よ、子供にかまうな" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "スキルレベルを上げない" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "自称文盲" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "本を読まない" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -90363,10 +91885,6 @@ msgstr "壁を黄色に塗る" msgid "Take Paint Off Wall" msgstr "壁の塗料を落とす" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "絨毯を取り除く" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "絨毯(赤)を敷く" @@ -90407,6 +91925,30 @@ msgstr "階段(木)を設置する" msgid "Mine Upstair" msgstr "上階を掘削する" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "車両建造を始める" @@ -90497,7 +92039,7 @@ msgstr "貯蔵穴の設置には深い穴が必要です。" #: lang/json/construction_from_json.py msgid "Mark firewood source" -msgstr "焚木置き場の印を付ける" +msgstr "焚物置き場の印を付ける" #: lang/json/construction_from_json.py msgid "" @@ -93401,7 +94943,7 @@ msgstr "結構な量のタバコをふかしました。" msgid "You smoked too much." msgstr "タバコの吸い過ぎです。" -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "高揚" @@ -95425,6 +96967,18 @@ msgstr "火" msgid "raging fire" msgstr "燃え盛る炎" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "薄い消火剤" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "消火剤" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "濃い消火剤" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "旧瓦礫" @@ -96457,8 +98011,7 @@ msgid "" msgstr "室内で安全に火を起こすために使う、一般的な家具です。煙を屋外に排出するための煙突が付いています。火をつけたまま放置するのは危険です。" #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "ガチャン!" @@ -96627,7 +98180,7 @@ msgid "" msgstr "積み上げられた枯れ草です。快適さや暖かさを気にしないなら、ベッドとして使えます。" #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "バリバリッ!" @@ -97286,11 +98839,9 @@ msgstr "運動器具" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." -msgstr "" -"頑丈なパイプの骨組みの端に重いバーベルが取り付けてある、筋力トレーニングで用いる装置です。バーベルは非常に大きく、補助員なしで使うと重傷を負うことになります。" +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." +msgstr "頑丈なパイプの骨組みの端に重いバーベルが取り付けてある、筋力トレーニングで用いる装置です。プレートを着け外しして重量を調整できます。" #: lang/json/furniture_from_json.py msgid "ball machine" @@ -97373,7 +98924,7 @@ msgstr "" #: lang/json/furniture_from_json.py msgid "ergometer" -msgstr "エルゴメーター" +msgstr "電動エルゴメーター" #. ~ Description for ergometer #: lang/json/furniture_from_json.py @@ -97383,9 +98934,21 @@ msgid "" " to be scavanged." msgstr "ハンドルと踏台を使ってボート漕ぎのような運動を行う器具です。電力がないと動かせませんが、分解すれば役に立つ部品が手に入るかもしれません。" +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "エルゴメーター" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "ハンドルと踏台を使ってボート漕ぎのような運動を行う器具です。内部機構で負荷を調整する旧式モデルですが、電力なしでも動かせます。" + #: lang/json/furniture_from_json.py msgid "treadmill" -msgstr "ランニングマシーン" +msgstr "電動トレッドミル" #. ~ Description for treadmill #: lang/json/furniture_from_json.py @@ -97395,6 +98958,18 @@ msgid "" "you're probably getting enough cardio on your own." msgstr "移動せずに走り続けるための、制御盤が付いた電動ベルトコンベアです。こんな運動器具がなくても、有酸素運動はたっぷり行っている気がします。" +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "トレッドミル" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "内部機構で負荷を調整できるベルトコンベアーです。踏み台の角度が急勾配になっていますが、使用者の自重によって適切な位置に調整されます。" + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "サンドバッグ" @@ -98689,10 +100264,6 @@ msgstr "アーク炉です。コークスと石灰石を混ぜた粉末を入れ msgid "filled arc furnace" msgstr "アーク炉(装填済)" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "燻製ラック" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -99443,7 +101014,8 @@ msgstr "酸溜まりを発射する疑似アイテムです。" msgid "auto" msgstr "オート" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "ライフル" @@ -99614,8 +101186,8 @@ msgid "" msgstr "" "21世紀半ばに開発されたV29レーザーピストルをベースにして自作した銃器です。有り体に言えばダクトテープと電子部品の塊です。一般的なUPSで作動します。" -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "ハンドガン" @@ -99675,7 +101247,7 @@ msgid "" "deadly." msgstr "スクラップから自作した多工程の空圧式ライフルです。とても静かで高い殺傷力があります。" -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "セミオート" @@ -100107,9 +101679,9 @@ msgid "" msgstr "古風なデザインのAR-15を小型化した、自衛用に市販されている銃身約19cmの銃です。" #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" -msgstr[0] "ライフル(.223口径/MAS 223)" +msgid "MAS .223" +msgid_plural "MAS .223" +msgstr[0] "ライフル(.223口径/MAS .223)" #: lang/json/gun_from_json.py msgid "" @@ -102370,14 +103942,14 @@ msgstr "" "Firearms社が開発したブローバック式セミオートピストルです。この企業は安価かつ嵩張って扱い辛い小型の銃を製造することで有名です。鋼鉄製に比べて壊れやすい鋳造亜鉛スライドが使われています。" #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" -msgstr[0] "ハンドガン(9mm/CZ-75)" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" +msgstr[0] "ハンドガン(9mm/CZ75B)" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " @@ -102486,6 +104058,40 @@ msgid "" msgstr "" ".30-06口径の銃身と2つの散弾用滑腔銃身を併せ持った、中折式の複合銃です。かつて自己中心的なハンター達がアフリカで振り回していた銃を、自己中心的な子孫達がニューイングランドで振り回しています。" +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "ライフル(12.3ln/PA Md.68バトルライフル)" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" +"12.3ln弾を使う銃で最も人気だったのは、もちろんPA " +"md.71でしたが、その前身であるmd.68はある種の失敗作だという意見が多数ありました。信頼性と威力はあったものの、歩兵が持つ銃器としては重すぎて扱い辛かったことが理由です。しかしゾンビによる世界崩壊が訪れたことで、手に入りやすい弾薬を使う据え付けの銃として復活を遂げました。この銃は扱い辛さという懸念がはるかに少ないエクゾディに打って付けだったのです。" + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "ライフル(12.3ln/PA Md.71ゾンビハント)" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" +"第三次カルパチア戦争で一躍有名になった人気の高いルーマニア製アサルトライフルを、狙撃兵器として機能するようにエクゾディが再設計したものです。優先度の高い標的を確実に撃ち抜きます。再設計によって、標的を粉々にして復活を防ぐための非常に高速な5連バースト射撃が可能になています。" + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -102983,8 +104589,8 @@ msgstr "" "ウィンチェスター1897は、商業的に成功した最初のポンプアクションショットガンの一つです。その「トレンチ(塹壕)」向けの設計から、第一次世界大戦中はアメリカの理想を鮮やかに体現した象徴とされていました。放熱板と着剣装置、そして銃剣を備えたこの銃の外見は、間違いなく恐ろしいものです。掃討する塹壕は見当たらないので、ゾンビがはびこる街で活躍させましょう。" #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" msgstr[0] "ショットガン(簡易)" #: lang/json/gun_from_json.py @@ -103640,10 +105246,28 @@ msgstr "三連レーザー" #: lang/json/gun_from_json.py msgid "bionic skullgun" msgid_plural "bionic skullguns" -msgstr[0] "" +msgstr[0] "ショットガン(.40口径/スカルガン)" #: lang/json/gun_from_json.py msgid "Bionic one-shot subdermal .40 pistol integrated with your head." +msgstr "頭部と一体化した、.40口径単発銃です。" + +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." msgstr "" #: lang/json/gun_from_json.py @@ -104426,11 +106050,6 @@ msgid "" msgstr "" "主にマニアックな民間人向けの、取り外し可能な弾倉を備えたショットガンです。付属のレールと威圧感のある黒い塗装は、狩猟用途には見えません。弾倉の導入によって装填に掛かる時間は短縮されました。丁寧に扱う必要がある銃器ですが、ある程度の信頼性は保証されています。" -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "ショットガン(連射)" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -106328,6 +107947,12 @@ msgid "" " experiment" msgstr "実験の失敗作の中から取り出せそうなCBMが残っていないか探りました。" +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "肉と金属が混じった怪物から取り出せそうな部品が残っていないか探りました。" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -108445,10 +110070,6 @@ msgstr "書く" msgid "Teleport yourself" msgstr "瞬間移動する" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "火を消す" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "体の濡れ/汚れを拭く" @@ -108699,7 +110320,7 @@ msgstr "このアイテムは火を起こせます。" #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py msgid "This item can serve as a firewood." -msgstr "このアイテムは焚き木として利用できます。" +msgstr "このアイテムは焚物として利用できます。" #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -109688,6 +111309,14 @@ msgstr "終了/キャラクター新規作成メニュー" msgid "Toggle sorting order" msgstr "切替/整列順序" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "ランダム職業" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "ランダムシナリオ" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "説明を上にスクロール" @@ -110088,6 +111717,10 @@ msgstr "アイテムを分解する" msgid "Sleep" msgstr "睡眠" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "運動" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "車両を運転する" @@ -110561,12 +112194,12 @@ msgstr "読込/色設定テンプレート" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "Yes" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "No" @@ -115247,6 +116880,10 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn. Stacks 2 times" msgstr "" +"鍛錬と不屈の精神によって、集中力を高めることで物理的な脅威を克服します。\n" +"\n" +"命中+1\n" +"1ターン継続、最大蓄積数2" #: lang/json/martial_art_from_json.py msgid "Hylian Swordsmanship" @@ -115361,7 +116998,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Charge Up" -msgstr "" +msgstr "突進" #. ~ Description of buff 'Charge Up' for martial art '{'str': 'Hylian #. Swordsmanship'}' @@ -115373,6 +117010,10 @@ msgid "" "+20% damage, enables \"Spin Attack\" technique.\n" "Lasts 1 turn." msgstr "" +"回転しながら強烈な斬撃を放つために、ある程度勢いをつけます。\n" +"\n" +"全与ダメージ+20%、「回転斬り」有効化\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Iron Heart" @@ -115487,7 +117128,7 @@ msgstr "%sはバトルを挑む準備を整えました。" #: lang/json/martial_art_from_json.py msgid "Stamina" -msgstr "" +msgstr "持久力" #. ~ Description of buff 'Stamina' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -115498,10 +117139,14 @@ msgid "" "Gain bash, cut, stab armor equal to 50% of Strength.\n" "Lasts 3 turns." msgstr "" +"攻撃を受けると防御力が上昇します。\n" +"\n" +"筋力x50%の打撃/斬撃/刺突耐性上昇\n" +"3ターン継続" #: lang/json/martial_art_from_json.py msgid "Sniper" -msgstr "" +msgstr "スナイパー" #. ~ Description of buff 'Sniper' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -115512,10 +117157,14 @@ msgid "" "+50% damage.\n" "Lasts 1 turn." msgstr "" +"会心攻撃が命中すると攻撃力が上昇します。\n" +"\n" +"与ダメージ+50%\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Moxie" -msgstr "" +msgstr "自信過剰" #. ~ Description of buff 'Moxie' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -115526,6 +117175,10 @@ msgid "" "+50% damage.\n" "Lasts 3 turns." msgstr "" +"敵を倒すと攻撃力が上昇します。\n" +"\n" +"与ダメージ+50%\n" +"3ターン継続" #: lang/json/martial_art_from_json.py msgid "Setting Sun" @@ -115554,7 +117207,7 @@ msgstr "%sは重心をずらし、今までと異なる構えをとりました #: lang/json/martial_art_from_json.py msgid "Baffling Defense" -msgstr "" +msgstr "奇妙な構え" #. ~ Description of buff 'Baffling Defense' for martial art '{'str': 'Setting #. Sun'}' @@ -115566,10 +117219,14 @@ msgid "" "Dodging Skill increased by 20% of Intelligence, enables \"Mighty Throw\" and \"Ballista Throw\" techniques.\n" "Lasts 1 turn." msgstr "" +"わざと不用意に動いて適当に構え、敵を混乱させてその隙に投げ技を仕掛けます。\n" +"\n" +"知性x20%の回避スキル上昇、「全力投げ」「巨砲投げ」有効化\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Feigned Opening" -msgstr "" +msgstr "偽装降伏" #. ~ Description of buff 'Feigned Opening' for martial art '{'str': 'Setting #. Sun'}' @@ -115580,6 +117237,10 @@ msgid "" "+20 Speed.\n" "Lasts 1 turn." msgstr "" +"意図的に防御態勢を解くことで相手を油断させて、不意打ちを狙います。\n" +"\n" +"速度+20\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Shii-Cho" @@ -115671,7 +117332,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Stone Dragon" -msgstr "" +msgstr "岩竜" #. ~ Description for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py @@ -115681,21 +117342,22 @@ msgid "" "single, focused blow. Stone Dragon's defensive abilities focus on tapping " "into the enduring power of stone to turn aside attacks." msgstr "" +"強さ、筋力、持久力に重きを置く戦術です。この教えを学べば、武術に長けた者なら一撃で鋼鉄を砕くことすら可能になります。防御面では石がもっている恒久性に着目し、攻撃を逸らすことに焦点を当てています。" #. ~ initiate message for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py msgid "You dig your heels into the ground and steady yourself." -msgstr "" +msgstr "踵で地面をしっかりと踏みしめ、体勢を安定させました。" #. ~ initiate message for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s digs their heels into the ground." -msgstr "" +msgstr "%sは踵で地面をしっかりと踏みしめました。" #: lang/json/martial_art_from_json.py msgid "Stone Bones" -msgstr "" +msgstr "岩の骨" #. ~ Description of buff 'Stone Bones' for martial art '{'str': 'Stone #. Dragon'}' @@ -115706,10 +117368,14 @@ msgid "" "+1 bash, cut, and stab armor.\n" "Lasts 1 turn. Stacks 5 times." msgstr "" +"精神を集中して防御力を高め、武器が敵に当たったときの衝撃を利用してカウンターに備えました。\n" +"\n" +"打撃/斬撃/刺突耐性+1\n" +"1ターン継続、最大蓄積数5" #: lang/json/martial_art_from_json.py msgid "Stonefoot Stance" -msgstr "" +msgstr "岩足の構え" #. ~ Description of buff 'Stonefoot Stance' for martial art '{'str': 'Stone #. Dragon'}' @@ -115720,10 +117386,13 @@ msgid "" "\n" "+10% damage, +2 bash, cut, and stab armor." msgstr "" +"しゃがみこんで地面を足で踏みしめ、力を溜める構えです。ただし、動き過ぎると体勢が崩れてしまいます。\n" +"\n" +"与ダメージ+10%、打撃/斬撃/刺突耐性+2" #: lang/json/martial_art_from_json.py msgid "Cracked Stone" -msgstr "" +msgstr "ヒビ割れた岩" #. ~ Description of buff 'Cracked Stone' for martial art '{'str': 'Stone #. Dragon'}' @@ -115734,10 +117403,14 @@ msgid "" "Enables \"Shattered Stone\" buff.\n" "Lasts 1 turn." msgstr "" +"動き過ぎると岩足の構えの効果が薄れてしまいます。姿勢を崩さないように、じっとしていましょう。\n" +"\n" +"「崩れた岩」有効化\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Stattered Stone" -msgstr "" +msgstr "崩れた岩" #. ~ Description of buff 'Stattered Stone' for martial art '{'str': 'Stone #. Dragon'}' @@ -115749,10 +117422,14 @@ msgid "" "-10% damage, -2 bash, cut, and stab armor.\n" "Lasts 4 turn." msgstr "" +"適切な体勢を維持できていません。構え直すためにしばらくその場でじっとしている必要があります。\n" +"\n" +"与ダメージ-10%、打撃/斬撃/刺突耐性-2\n" +"4ターン継続" #: lang/json/martial_art_from_json.py msgid "Iron Bones" -msgstr "" +msgstr "鉄の骨" #. ~ Description of buff 'Iron Bones' for martial art '{'str': 'Stone #. Dragon'}' @@ -115763,10 +117440,14 @@ msgid "" "+5 bash, cut, and stab armor.\n" "Lasts 1 turn." msgstr "" +"攻撃が命中すると瞑想状態になり、ダメージをほとんど受けなくなります。\n" +"\n" +"打撃/斬撃/刺突耐性+5\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Tiger Claw" -msgstr "" +msgstr "虎の爪" #. ~ Description for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py @@ -115776,21 +117457,22 @@ msgid "" "with a furry similar to that of a barbarian, and rely on overwhelming, " "vicious assaults to defeat their enemies." msgstr "" +"虎の爪の規律は、その者の心の奥底に潜む猛烈な怒りを受け入れることを目指しています。実戦では虎の爪の戦士は野生動物のように唸り、蛮族のような毛皮をまとって戦い、敵を倒すために圧倒的かつ悪質な攻撃を繰り出します。" #. ~ initiate message for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py msgid "You emit a low growl as you prepare for battle." -msgstr "" +msgstr "低い唸り声を発し、戦いに備えました。" #. ~ initiate message for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s hunkers down like a wild animal." -msgstr "" +msgstr "%sは野生動物のように屈みこみました。" #: lang/json/martial_art_from_json.py msgid "Improved Critical" -msgstr "" +msgstr "強化会心攻撃" #. ~ Description of buff 'Improved Critical' for martial art '{'str': 'Tiger #. Claw'}' @@ -115801,10 +117483,13 @@ msgid "" "\n" "+5% critical hit chance." msgstr "" +"どんな時も全力で攻撃します。死にたくないのなら、この衝動を押し込めてはいけません。\n" +"\n" +"会心発生+5%" #: lang/json/martial_art_from_json.py msgid "Pounching Charge" -msgstr "" +msgstr "先制パンチ" #. ~ Description of buff 'Pounching Charge' for martial art '{'str': 'Tiger #. Claw'}' @@ -115816,10 +117501,14 @@ msgid "" "+2 Accuracy, +10% damage.\n" "Lasts 1 turn." msgstr "" +"野獣のような雄たけびをあげて戦いに身を投じます。鋭い先制攻撃を繰り出します。\n" +"\n" +"命中+2、与ダメージ+10%\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Cornered Predator" -msgstr "" +msgstr "手負いの獣" #. ~ Description of buff 'Cornered Predator' for martial art '{'str': 'Tiger #. Claw'}' @@ -115831,10 +117520,14 @@ msgid "" "-20% move cost.\n" "Lasts 1 turn." msgstr "" +"追いつめられた動物は恐ろしく危険です。今の状況はまさにそれです。\n" +"\n" +"行動コスト-20%\n" +"1ターン継続" #: lang/json/martial_art_from_json.py msgid "Blood In The Water" -msgstr "" +msgstr "血潮の香り" #. ~ Description of buff 'Blood In The Water' for martial art '{'str': 'Tiger #. Claw'}' @@ -115846,10 +117539,14 @@ msgid "" "+1 Accuracy, +15% damage.\n" "Lasts 1 turn. Stacks 2 times." msgstr "" +"血の香りを嗅いで精神が駆り立てられました。もっと欲しい。今すぐ欲しい!\n" +"\n" +"命中+1、与ダメージ+15%\n" +"1ターン継続、最大蓄積数2" #: lang/json/martial_art_from_json.py msgid "Prey on the Weak" -msgstr "" +msgstr "弱肉強食" #. ~ Description of buff 'Prey on the Weak' for martial art '{'str': 'Tiger #. Claw'}' @@ -115860,6 +117557,10 @@ msgid "" "+30 Speed.\n" "Lasts 2 turns. Stacks 2 times" msgstr "" +"草食動物の群れの中に放たれた猛獣のように、弱い相手を次々に切り裂きます。\n" +"\n" +"速度+30\n" +"2ターン継続、最大蓄積数2" #: lang/json/material_from_json.py src/bionics.cpp msgid "Alcohol" @@ -116345,7 +118046,7 @@ msgstr "乳化ハイドロゲル" #: lang/json/material_from_json.py msgid "pulped" -msgstr "" +msgstr "ドロドロの" #: lang/json/material_from_json.py msgid "Arcane Skin" @@ -116375,7 +118076,7 @@ msgstr "ブリジット・ラクロワのために骨を集めましょう。8 msgid "There is always work to be done, song to be woven." msgstr "どこにでもやるべき仕事があり、作られるべき歌がある。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -116384,16 +118085,16 @@ msgid "" msgstr "" "悟りへの道を歩むなら、まず歌に耳を傾け学びなさい。旅立ち、生き物を解体し、指先で力を感じ取りなさい。そして骨を持って来なさい。彫刻を作ってあげよう。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "素晴らしい。さあ取り掛かるのだ。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "気が進まないことは理解できる。道を見出したらまた来なさい。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -117623,7 +119324,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "じゃあ、また会おう...もし二度と会えなかったら、私は正しい決断をしたってことだな。" #: lang/json/mission_def_from_json.py @@ -117632,7 +119333,7 @@ msgid "" msgstr "死ぬな。アドバイスを求めるなんて、順調な滑り出しとは言えないな。" #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." +msgid "Well, you're not dead… yet." msgstr "おや、生きてるみたいだな…今の所は。" #: lang/json/mission_def_from_json.py @@ -118365,7 +120066,7 @@ msgstr "物資を探すのを手伝ってくれると助かるんだけど。" msgid "" "We could use some 3 liter jars to preserve our produce. Can you bring me 10" " large three liter jars? I'll give you some preserves in exchange." -msgstr "" +msgstr "ガラス瓶を使って農作物を保存したいんだ。3Lのガラス瓶を10個持ってきてもらえないか?報酬としてジャムをあげよう。" #: lang/json/mission_def_from_json.py msgid "Thank you. It's important to preserve foods while we can." @@ -120151,14 +121852,14 @@ msgstr "何もないじゃないか。自分で金を探すことにするよ。 #: lang/json/mission_def_from_json.py msgid "Active Noise Control" -msgstr "" +msgstr "ノイズを消し去る" #. ~ Description for mission 'Active Noise Control' #: lang/json/mission_def_from_json.py msgid "" "Investigate Hub 01's radio tower, discover the source of the interference, " "and fix the problem." -msgstr "" +msgstr "ハブ01の電波塔を調査して電波への干渉源を見つけ出し、問題を解決しましょう。" #: lang/json/mission_def_from_json.py msgid "" @@ -120166,69 +121867,70 @@ msgid "" "stopped working recently. If you are willing to be my back up while I check" " it out, I'll owe you a favor." msgstr "" +"先日、近くにあるタワーに無線送信機を設置したんだが、ついさっき機能しなくなってしまったんだ。原因を調査する手伝いをしてくれたら、非常にありがたいな。" #: lang/json/mission_def_from_json.py msgid "Alright, lets be off. You don't mind taking point, right?" -msgstr "" +msgstr "よし、さっそく現場へ向かおう。もちろん、来てくれるよな?" #: lang/json/mission_def_from_json.py msgid "Well thanks for offering, I guess." -msgstr "" +msgstr "そうか、話を聞いてくれただけでも嬉しいよ。" #: lang/json/mission_def_from_json.py msgid "" "I'm sure we'll figure it out once there. In any case, make sure to shoot " "first." -msgstr "" +msgstr "一度現場へ行ってみないと原因は分からないだろうな。いずれにせよ、発砲準備はしておこう。" #: lang/json/mission_def_from_json.py msgid "You think we killed the culprit?" -msgstr "" +msgstr "原因を取り除けたか?" #: lang/json/mission_def_from_json.py msgid "Sure seems like it. Lets go back to the hub." -msgstr "" +msgstr "確かにそうみたいだ。ハブに戻ろう。" #: lang/json/mission_def_from_json.py msgid "Sure, thanks for nothing." -msgstr "" +msgstr "ああ、そりゃどうも。" #: lang/json/mission_def_from_json.py msgid "Return to Hub 01" -msgstr "" +msgstr "ハブ01へ戻る" #. ~ Description for mission 'Return to Hub 01' #: lang/json/mission_def_from_json.py msgid "Return to Hub 01." -msgstr "" +msgstr "ハブ01へ戻りましょう。" #: lang/json/mission_def_from_json.py msgid "Lets go back to the Hub" -msgstr "" +msgstr "ハブへ戻ろう。" #: lang/json/mission_def_from_json.py msgid "Well…" -msgstr "" +msgstr "ええと..." #: lang/json/mission_def_from_json.py msgid "You keep a map around don't you? I do, and you probably should too." -msgstr "" +msgstr "マップがあるだろ?私も持ってるが、自分で見た方が早い。" #: lang/json/mission_def_from_json.py msgid "We there yet?" -msgstr "" +msgstr "まだか?" #: lang/json/mission_def_from_json.py msgid "Thanks for having my back. As I said, I owe you one." -msgstr "" +msgstr "手伝ってくれてありがとう。一つ借りができたな。" #: lang/json/mission_def_from_json.py msgid "Are you lost or something?" -msgstr "" +msgstr "道に迷いでもしたのか?" #: lang/json/mission_def_from_json.py msgid "Can't believe we got lost…" -msgstr "" +msgstr "まさか迷子になるなんて..." #: lang/json/mission_def_from_json.py msgid "Make 2 Stills" @@ -123902,7 +125604,7 @@ msgstr "頭部から発光器官が生えています。意識的にはコント #: lang/json/mutation_from_json.py msgid "Reflex Photophore (on)" -msgstr "" +msgstr "反射性発光器官(オン)" #: lang/json/mutation_from_json.py msgid "Weak Photophore" @@ -123918,12 +125620,12 @@ msgstr "頭部から発光器官が伸び、弱々しい光を放っています #: lang/json/mutation_from_json.py msgid "Weak Photophore (on)" -msgstr "" +msgstr "弱い発光器官(オン)" #. ~ Description for {'str': 'Weak Photophore (on)'} #: lang/json/mutation_from_json.py msgid "Your photophore is glowing softly." -msgstr "" +msgstr "発光器官がほのかに光っています。" #: lang/json/mutation_from_json.py msgid "Photophore" @@ -123932,16 +125634,16 @@ msgstr "発光器官" #. ~ Description for {'str': 'Photophore'} #: lang/json/mutation_from_json.py msgid "You can make your photophore glow brightly." -msgstr "" +msgstr "発光器官が眩い光を放っています。" #: lang/json/mutation_from_json.py msgid "Photophore (on)" -msgstr "" +msgstr "発光器官(オン)" #. ~ Description for {'str': 'Photophore (on)'} #: lang/json/mutation_from_json.py msgid "You photophore is glowing brightly." -msgstr "" +msgstr "発光器官が明るく光っています。" #: lang/json/mutation_from_json.py msgid "Normal Human" @@ -124060,7 +125762,7 @@ msgid "" "Your wounds heal themselves quicker than usual. You heal 50% faster whilst " "asleep and 20% faster whilst awake. Your broken limbs also heal twice as " "fast." -msgstr "" +msgstr "傷が普通より早く治ります。睡眠時は通常より50%、起きている間は通常より20%早くHPが回復します。骨折した手足も2倍の速さで治ります。" #: lang/json/mutation_from_json.py msgid "Light Eater" @@ -124543,7 +126245,7 @@ msgstr "武術鍛錬" msgid "" "You have received some martial arts training at a local dojo. You start " "with your choice of Karate, Judo, Aikido, Tai Chi, Taekwondo, or Pankration." -msgstr "道場で格闘術の教えを受けてきました。空手、柔道、合気道、太極拳、テコンドー、パンクラチオンの内1つを修得した状態で始まります。" +msgstr "道場で格闘術の教えを受けてきました。空手、柔道、合気道、太極拳、テコンドー、パンクラチオンのいずれかを選択して開始します。" #: lang/json/mutation_from_json.py msgid "Self-Defense Classes" @@ -124555,7 +126257,7 @@ msgid "" "You have taken some self-defense classes at a nearby gym. You start with " "your choice of Capoeira, Krav Maga, Muay Thai, Ninjutsu, Wing Chun, or Zui " "Quan." -msgstr "近所のジムで護身術を習っていました。カポエイラ、クラヴマガ、ムエタイ、忍術、詠春拳、酔拳のうち1つを修得しています。" +msgstr "近所のジムで護身術を習っていました。カポエイラ、クラヴマガ、ムエタイ、忍術、詠春拳、酔拳のいずれかを選択して開始します。" #: lang/json/mutation_from_json.py msgid "Shaolin Adept" @@ -124579,7 +126281,7 @@ msgid "" "Eskrima, Fencing, Fior Di Battaglia, Medieval Swordsmanship, Niten Ichi-Ryu," " Pentjak Silat, or Sōjutsu." msgstr "" -"武器を使った戦闘術を鍛錬してきました。開始時からエスクリマ、フェンシング、西洋長柄武器術、中世剣術、二天一流、プンチャック・シラット、槍術のうち1つを習得しています。" +"武器を使った戦闘術を鍛錬してきました。開始時からエスクリマ、フェンシング、西洋長柄武器術、中世剣術、二天一流、プンチャック・シラット、槍術のいずれかを選択して開始します。" #: lang/json/mutation_from_json.py msgid "Competitive Fencer" @@ -124698,7 +126400,7 @@ msgstr "低速治癒" msgid "" "Your wounds heal a little slower than most. Your HP whilst asleep as well " "as your broken limbs heal at 75% the regular rate." -msgstr "" +msgstr "傷の治りが普通より遅くなります。睡眠中のHP回復速度はもちろん、骨折した手足の回復速度も通常の75%です。" #: lang/json/mutation_from_json.py msgid "Poor Healer" @@ -124710,7 +126412,7 @@ msgstr "治癒力不足" msgid "" "Your health recovery is severely impaired. Your HP whilst asleep as well as" " your broken limbs heal at 33% the regular rate." -msgstr "" +msgstr "回復力が著しく損なわれています。睡眠中のHP回復速度はもちろん、骨折した手足の回復速度も通常の33%です。" #: lang/json/mutation_from_json.py msgid "Imperceptive Healer" @@ -124722,7 +126424,7 @@ msgstr "治癒力欠乏" msgid "" "Wounds are incredibly dangerous to you, as they barely heal at all. Your HP" " whilst asleep as well as your broken limbs heal at 10% the regular rate." -msgstr "" +msgstr "回復力は無いに等しく、死の危険性が付きまといます。睡眠中のHP回復速度はもちろん、骨折した手足の回復速度も通常の10%です。" #: lang/json/mutation_from_json.py msgid "Far-Sighted" @@ -125442,6 +127144,7 @@ msgid "" "Your wounds heal very quickly. You heal 50% faster whilst asleep and 66% " "faster whilst awake. Your broken limbs also heal 4 times faster than usual." msgstr "" +"傷が普通より非常に早く治ります。睡眠時は通常より50%、起きている間は通常より60%早くHPが回復します。骨折した手足も4倍の速さで治ります。" #: lang/json/mutation_from_json.py msgid "Regeneration" @@ -125455,6 +127158,7 @@ msgid "" " whilst asleep and 200% faster whilst awake. Your broken limbs also heal 16" " times faster than usual." msgstr "" +"傷が信じられないほど早く治ります。睡眠時は通常より150%、起きている間は通常より200%早くHPが回復します。骨折した手足も16倍の速さで治ります。" #: lang/json/mutation_from_json.py msgid "Reptilian Healing" @@ -125465,7 +127169,7 @@ msgstr "爬虫類の治癒力" msgid "" "Your broken limbs mend themselves without significant difficulty. You do " "not require splints and broken limbs heal 20 times faster than usual." -msgstr "" +msgstr "手足が骨折しても自力で治るため、大した問題になりません。骨折した部位に添え木を着用する必要がなく、通常の20倍の速度で回復します。" #: lang/json/mutation_from_json.py msgid "Very Little Sleep" @@ -128934,8 +130638,7 @@ msgstr "クモ" msgid "Well, maybe you'll just have to make your own world wide web." msgstr "あなただけのワールド・ワイド・ウェブを構築しましょうか。" -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "サバイバー" @@ -129251,10 +130954,6 @@ msgid "" msgstr "" "真のフードパーソンです。ただのマスコットだと思っている人もいますが、実は違います。自分自身がフードパーソンです。マスクが顔そのものです。この世界と無意識の中間に立つ唯一の存在です。" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "医療関係者" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -129631,14 +131330,32 @@ msgstr "高反射神経" #: lang/json/mutation_from_json.py msgid "" "You have fast reflexes, allowing you to dodge attacks and grabs more easily." -msgstr "" - -#: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "サバイバーストーリー" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgstr "反射神経が高く、攻撃や拘束をより簡単に回避できます。" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Confused 1" +msgstr "生存者: 混乱1" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -129646,6 +131363,86 @@ msgstr "サバイバーストーリー" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "このNPCはどうやって大変動から生き残ったのか語ります。" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "生存者: 過去抹消1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "生存者: 過去抹消2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "生存者: 過去抹消3" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "生存者: 過去抹消4" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "生存者: 過去抹消5" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "生存者: 信仰1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "生存者: 信仰2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "生存者: 空想家1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "生存者: 結婚式1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "生存者: 避難者1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "生存者: 避難者2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "生存者: 避難者3" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "生存者: 避難者4" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "生存者: 避難者5" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "生存者: 避難者6" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "生存者: FEMA避難者1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "生存者: 見殺し1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "生存者: 見殺し2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "生存者: 見殺し2" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "サバイバーストーリー" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "占骨術師の印" @@ -130897,7 +132694,7 @@ msgid "" "You are a martial adept and learned one of the martial disciplines of the " "Sublime Way. You start with your choice of Desert Wind, Diamond Mind, Iron " "Heart, Setting Sun, Stone Dragon, or Tiger Claw." -msgstr "" +msgstr "「崇高な道」が使う武術を学んだ武術の達人です。砂漠の旋風、金剛石の心、鋼の心、落陽、岩竜、虎の爪のいずれかを選択して開始します。" #: lang/json/mutation_from_json.py msgid "Magus" @@ -131408,10 +133205,6 @@ msgstr "生き残ろうと必死に頑張ってるところさ。" msgid "I'm tracking game." msgstr "足跡を追って狩りをしているんだ。" -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "兵士" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "バーテンダー" @@ -132161,10 +133954,6 @@ msgstr "戦闘員" msgid "Laborer" msgstr "労働者" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "木こり" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "木工師" @@ -134683,6 +136472,18 @@ msgstr "道路(マンホール)" msgid "bridge" msgstr "橋" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "休憩所" @@ -135612,7 +137413,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Professional Cyclist" -msgstr "プロの自転車乗り" +msgstr "プロのロードレーサー" #. ~ Profession (male Professional Cyclist) description #: lang/json/professions_from_json.py @@ -135628,7 +137429,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Professional Cyclist" -msgstr "プロの自転車乗り" +msgstr "プロのロードレーサー" #. ~ Profession (female Professional Cyclist) description #: lang/json/professions_from_json.py @@ -135986,7 +137787,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Chain Smoker" -msgstr "ヘビースモーカー" +msgstr "チェーンスモーカー" #. ~ Profession (male Chain Smoker) description #: lang/json/professions_from_json.py @@ -136001,7 +137802,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Chain Smoker" -msgstr "ヘビースモーカー" +msgstr "チェーンスモーカー" #. ~ Profession (female Chain Smoker) description #: lang/json/professions_from_json.py @@ -136016,7 +137817,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Crackhead" -msgstr "高純度コカイン常用者" +msgstr "高純度コカイン乱用者" #. ~ Profession (male Crackhead) description #: lang/json/professions_from_json.py @@ -136031,7 +137832,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Crackhead" -msgstr "高純度コカイン常用者" +msgstr "高純度コカイン乱用者" #. ~ Profession (female Crackhead) description #: lang/json/professions_from_json.py @@ -136078,7 +137879,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Tweaker" -msgstr "薬物中毒者" +msgstr "アンフェタミン乱用者" #. ~ Profession (male Tweaker) description #: lang/json/professions_from_json.py @@ -136093,7 +137894,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Tweaker" -msgstr "薬物中毒者" +msgstr "アンフェタミン乱用者" #. ~ Profession (female Tweaker) description #: lang/json/professions_from_json.py @@ -136108,7 +137909,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Pillhead" -msgstr "アヘン中毒者" +msgstr "アヘン乱用者" #. ~ Profession (male Pillhead) description #: lang/json/professions_from_json.py @@ -136123,7 +137924,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Pillhead" -msgstr "アヘン中毒者" +msgstr "アヘン乱用者" #. ~ Profession (female Pillhead) description #: lang/json/professions_from_json.py @@ -137698,7 +139499,7 @@ msgstr "大切な日に大変動が起き、結婚式の服装のまま一目散 #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Punk Rock Dude" -msgstr "パンクロックの伊達男" +msgstr "パンクロッカー" #. ~ Profession (Punk Rock Dude) description #: lang/json/professions_from_json.py @@ -137711,7 +139512,7 @@ msgstr "黙示録の世界を歌う邪悪な歌に命が吹き込まれました #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Punk Rock Girl" -msgstr "パンクロックの少女" +msgstr "パンクロッカー" #. ~ Profession (Punk Rock Girl) description #: lang/json/professions_from_json.py @@ -139802,7 +141603,7 @@ msgstr "" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "EMT" -msgstr "" +msgstr "救急隊員" #. ~ Profession (male EMT) description #: lang/json/professions_from_json.py @@ -139812,11 +141613,12 @@ msgid "" "Now all you have is your trusty ambulance, ready to transport patients " "through the apocalypse." msgstr "" +"同僚からの応援要請に対応しようとしていましたが、結局合流はできませんでした。信頼できる救急車に乗っており、世界が崩壊する状況でも患者を輸送する準備はできています。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "EMT" -msgstr "" +msgstr "救急隊員" #. ~ Profession (female EMT) description #: lang/json/professions_from_json.py @@ -139826,11 +141628,12 @@ msgid "" "Now all you have is your trusty ambulance, ready to transport patients " "through the apocalypse." msgstr "" +"同僚からの応援要請に対応しようとしていましたが、結局合流はできませんでした。信頼できる救急車に乗っており、世界が崩壊する状況でも患者を輸送する準備はできています。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Paramedic" -msgstr "" +msgstr "救急救命士" #. ~ Profession (male Paramedic) description #: lang/json/professions_from_json.py @@ -139839,12 +141642,12 @@ msgid "" "You were separated from your partner while out on a call. You managed to " "hang onto some medical supplies, but it's looking like the only life that " "needs saving now is yours." -msgstr "" +msgstr "同僚に応援を要請しましたが、結局合流はできませんでした。医薬品はなんとか持ち出せましたが、今はまず自分の命を救う必要がありそうです。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Paramedic" -msgstr "" +msgstr "救急救命士" #. ~ Profession (female Paramedic) description #: lang/json/professions_from_json.py @@ -139853,12 +141656,12 @@ msgid "" "You were separated from your partner while out on a call. You managed to " "hang onto some medical supplies, but it's looking like the only life that " "needs saving now is yours." -msgstr "" +msgstr "同僚に応援を要請しましたが、結局合流はできませんでした。医薬品はなんとか持ち出せましたが、今はまず自分の命を救う必要がありそうです。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Combat Medic" -msgstr "" +msgstr "衛生兵" #. ~ Profession (male Combat Medic) description #: lang/json/professions_from_json.py @@ -139867,12 +141670,12 @@ msgid "" "You were on the front-lines when everything happened, patching up the " "wounded and providing support. But they wouldn't stop coming. Now you're " "on your own." -msgstr "" +msgstr "負傷者に包帯を巻き、添え木を当てていたまさにその時、大変動が訪れました。負傷者は増え続け、やがて誰もいなくなりました。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Combat Medic" -msgstr "" +msgstr "衛生兵" #. ~ Profession (female Combat Medic) description #: lang/json/professions_from_json.py @@ -139881,12 +141684,12 @@ msgid "" "You were on the front-lines when everything happened, patching up the " "wounded and providing support. But they wouldn't stop coming. Now you're " "on your own." -msgstr "" +msgstr "負傷者に包帯を巻き、添え木を当てていたまさにその時、大変動が訪れました。負傷者は増え続け、やがて誰もいなくなりました。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Heroin Addict" -msgstr "" +msgstr "ヘロイン乱用者" #. ~ Profession (male Heroin Addict) description #: lang/json/professions_from_json.py @@ -139895,12 +141698,12 @@ msgid "" "The last thing you remember was meeting God behind the local Foodplace. " "Then people started eating each other. This doesn't feel like a fever " "dream." -msgstr "" +msgstr "地元のフードプレイスの裏手で神に出会ったのが、最後の記憶です。そして人々は互いを喰い始めました。これは熱狂がもたらす幻覚なのでしょうか。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Heroin Addict" -msgstr "" +msgstr "ヘロイン乱用者" #. ~ Profession (female Heroin Addict) description #: lang/json/professions_from_json.py @@ -139909,7 +141712,7 @@ msgid "" "The last thing you remember was meeting God behind the local Foodplace. " "Then people started eating each other. This doesn't feel like a fever " "dream." -msgstr "" +msgstr "地元のフードプレイスの裏手で神に出会ったのが、最後の記憶です。そして人々は互いを喰い始めました。これは熱狂がもたらす幻覚なのでしょうか。" #: lang/json/professions_from_json.py msgctxt "profession_male" @@ -140093,6 +141896,7 @@ msgid "" "you in the middle of your 16 hour extended shift, and you barely managed to " "escape the building, tools in hand." msgstr "" +"CBMの製造に関係する警備の厳重な施設で、面白味のない技師の仕事をしていました。残業含め16時間の業務をこなしている途中で最後の避難命令が発出され、工具を掴んでなんとか屋外へ脱出しました。" #: lang/json/professions_from_json.py msgctxt "profession_female" @@ -140108,6 +141912,7 @@ msgid "" "you in the middle of your 16 hour extended shift, and you barely managed to " "escape the building, tools in hand." msgstr "" +"CBMの製造に関係する警備の厳重な施設で、面白味のない技師の仕事をしていました。残業含め16時間の業務をこなしている途中で最後の避難命令が発出され、工具を掴んでなんとか屋外へ脱出しました。" #: lang/json/professions_from_json.py msgctxt "profession_male" @@ -141412,7 +143217,7 @@ msgstr "テストでズルをするために使っていた魔法は、大変動 #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Introspectionist" -msgstr "" +msgstr "瞑想者" #. ~ Profession (male Introspectionist) description #: lang/json/professions_from_json.py @@ -141422,11 +143227,12 @@ msgid "" "improving yourself. It was you and your best friend, but now the apocalypse" " won't leave you alone. " msgstr "" +"自分を磨くことに集中したかったため、社会からはなれたところにいました。孤独こそが唯一の友人だったのに、この状況では嫌でも天変地異に好かれてしまいます。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Introspectionist" -msgstr "" +msgstr "瞑想者" #. ~ Profession (female Introspectionist) description #: lang/json/professions_from_json.py @@ -141436,11 +143242,12 @@ msgid "" "improving yourself. It was you and your best friend, but now the apocalypse" " won't leave you alone. " msgstr "" +"自分を磨くことに集中したかったため、社会からはなれたところにいました。孤独こそが唯一の友人だったのに、この状況では嫌でも天変地異に好かれてしまいます。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Vengeful Preacher" -msgstr "" +msgstr "不良牧師" #. ~ Profession (male Vengeful Preacher) description #: lang/json/professions_from_json.py @@ -141450,11 +143257,12 @@ msgid "" "yourself to death ever since. God is punishing everyone with this " "apocalypse, you are going to show them your brand of mercy." msgstr "" +"配偶者が病気で死んだとき、信仰を失いました。それ以来、いつも飲んだくれています。神はこの黙示録の日にあらゆる人を罰しています。わずかに残った慈悲を人々に見せるべきでしょうか。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Vengeful Preacher" -msgstr "" +msgstr "不良牧師" #. ~ Profession (female Vengeful Preacher) description #: lang/json/professions_from_json.py @@ -141464,11 +143272,12 @@ msgid "" "yourself to death ever since. God is punishing everyone with this " "apocalypse, you are going to show them your brand of mercy." msgstr "" +"配偶者が病気で死んだとき、信仰を失いました。それ以来、いつも飲んだくれています。神はこの黙示録の日にあらゆる人を罰しています。わずかに残った慈悲を人々に見せるべきでしょうか。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Techno-Prepper" -msgstr "" +msgstr "テクノプレッパー" #. ~ Profession (male Techno-Prepper) description #: lang/json/professions_from_json.py @@ -141476,12 +143285,12 @@ msgctxt "prof_desc_male" msgid "" "You've long suspected the world might suddenly turn over. With your " "training, spells, and revolver, your chances are far better than most." -msgstr "" +msgstr "世界がいつか突然崩壊するだろうと信じていました。訓練と呪文とリボルバーがあれば、生き延びるチャンスは大いに高まります。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Techno-Prepper" -msgstr "" +msgstr "テクノプレッパー" #. ~ Profession (female Techno-Prepper) description #: lang/json/professions_from_json.py @@ -141489,12 +143298,12 @@ msgctxt "prof_desc_female" msgid "" "You've long suspected the world might suddenly turn over. With your " "training, spells, and revolver, your chances are far better than most." -msgstr "" +msgstr "世界がいつか突然崩壊するだろうと信じていました。訓練と呪文とリボルバーがあれば、生き延びるチャンスは大いに高まります。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Bionic Pseudovamp" -msgstr "" +msgstr "疑似バンパイア" #. ~ Profession (male Bionic Pseudovamp) description #: lang/json/professions_from_json.py @@ -141504,11 +143313,12 @@ msgid "" "augment yourself with spells and bionics into a denizen of the night. Your " "neglect to your health in your pursuit has left you pale and unlively." msgstr "" +"小さい頃からホラーノベルを溺愛しており、資産を使って呪文や生体部品で夜の住人を増やしていました。趣味に没頭するあまり健康意識が低くなり、青白く不健康な身体になってしまいました。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Bionic Pseudovamp" -msgstr "" +msgstr "疑似バンパイア" #. ~ Profession (female Bionic Pseudovamp) description #: lang/json/professions_from_json.py @@ -141518,11 +143328,12 @@ msgid "" "augment yourself with spells and bionics into a denizen of the night. Your " "neglect to your health in your pursuit has left you pale and unlively." msgstr "" +"小さい頃からホラーノベルを溺愛しており、資産を使って呪文や生体部品で夜の住人を増やしていました。趣味に没頭するあまり健康意識が低くなり、青白く不健康な身体になってしまいました。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Academy Wizard" -msgstr "" +msgstr "魔法学校の生徒" #. ~ Profession (male Academy Wizard) description #: lang/json/professions_from_json.py @@ -141532,11 +143343,12 @@ msgid "" "and a handful of useful spells. With the teachers converted into the undead " "and classes cancelled, the final lesson has begun." msgstr "" +"魔法学校に入学して1年が経ち、忍耐力、知恵、そしていくつかの便利な魔法を学びました。教師がゾンビになったので、もう授業はありません。最後のレッスンの始まりです。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Academy Wizard" -msgstr "" +msgstr "魔法学校の生徒" #. ~ Profession (female Academy Wizard) description #: lang/json/professions_from_json.py @@ -141546,11 +143358,12 @@ msgid "" "and a handful of useful spells. With the teachers converted into the undead " "and classes cancelled, the final lesson has begun." msgstr "" +"魔法学校に入学して1年が経ち、忍耐力、知恵、そしていくつかの便利な魔法を学びました。教師がゾンビになったので、もう授業はありません。最後のレッスンの始まりです。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Corrosive Rocker" -msgstr "" +msgstr "過激なロッカー" #. ~ Profession (male Corrosive Rocker) description #: lang/json/professions_from_json.py @@ -141559,11 +143372,12 @@ msgid "" "Your metal career soared to new heights when you swapped special effects for" " acrid gore and spiked whips. It seems the Cataclysm is now your final tour." msgstr "" +"特殊効果を活用して強烈で刺激的なステージを作りあげ、所属していたメタルバンドは大躍進を遂げました。大変動の世界を舞台にしたファイナルツアーの幕開けです。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Corrosive Rocker" -msgstr "" +msgstr "過激なロッカー" #. ~ Profession (female Corrosive Rocker) description #: lang/json/professions_from_json.py @@ -141572,11 +143386,12 @@ msgid "" "Your metal career soared to new heights when you swapped special effects for" " acrid gore and spiked whips. It seems the Cataclysm is now your final tour." msgstr "" +"特殊効果を活用して強烈で刺激的なステージを作りあげ、所属していたメタルバンドは大躍進を遂げました。大変動の世界を舞台にしたファイナルツアーの幕開けです。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Shock Officer" -msgstr "" +msgstr "魔法警官" #. ~ Profession (male Shock Officer) description #: lang/json/professions_from_json.py @@ -141586,11 +143401,12 @@ msgid "" "decrease suspect casualties and equipment costs by substituting tasers and " "bullets for less-lethal Stormshaping." msgstr "" +"実験的な法執行プログラムに登録されました。容疑者の死傷を減らしコストも削減できることから、テーザー銃と銃弾の代わりにストームシェイプの魔法を使っています。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Shock Officer" -msgstr "" +msgstr "魔法警官" #. ~ Profession (female Shock Officer) description #: lang/json/professions_from_json.py @@ -141600,11 +143416,12 @@ msgid "" "decrease suspect casualties and equipment costs by substituting tasers and " "bullets for less-lethal Stormshaping." msgstr "" +"実験的な法執行プログラムに登録されました。容疑者の死傷を減らしコストも削減できることから、テーザー銃と銃弾の代わりにストームシェイプの魔法を使っています。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Earthquake Brawler" -msgstr "" +msgstr "魔法格闘家" #. ~ Profession (male Earthquake Brawler) description #: lang/json/professions_from_json.py @@ -141614,11 +143431,12 @@ msgid "" "unstoppable punching machine. Now that all your opponents are undead, " "there's no need to hold back." msgstr "" +"地下で開かれているマジックボクシング大会で、無敵の削岩機として名を馳せていました。対戦相手は皆ゾンビになったので、もう手加減する必要はありません。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Earthquake Brawler" -msgstr "" +msgstr "魔法格闘家" #. ~ Profession (female Earthquake Brawler) description #: lang/json/professions_from_json.py @@ -141628,6 +143446,7 @@ msgid "" "unstoppable punching machine. Now that all your opponents are undead, " "there's no need to hold back." msgstr "" +"地下で開かれているマジックボクシング大会で、無敵の削岩機として名を馳せていました。対戦相手は皆ゾンビになったので、もう手加減する必要はありません。" #: lang/json/professions_from_json.py msgctxt "profession_male" @@ -143303,7 +145122,7 @@ msgstr "金属加工炉" #: lang/json/recipe_from_json.py msgid "Let's build an anvil and crucible to increase our crafting options." -msgstr "" +msgstr "金床とるつぼを置いて、作れるものを増やしましょう。" #: lang/json/recipe_from_json.py msgid "add an anvil and crucible" @@ -150053,96 +151872,6 @@ msgstr "こんなに喉が渇いたのは生まれて初めてだ。" msgid "I'd kill for a sip of water right now." msgstr "一杯の水のためなら何だってやるさ。" -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "いいね、ビールを用意してくれた事にはもちろん気づいていたさ!冷えた奴を飲みながら話そう。、景気はどう?" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "もちろんだ。そのビールをあけながらってのもいいな?ともかく、最近どう?" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "ああ、君が持ってるビールを分けてくれるなら、好きなだけ話そう!まぁそれは冗談だけど、、調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "ねえ、冷たいビールがあればお喋りはもっと盛り上がるだろうな。調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "雑談中にビールを空ければ...しばらくの間は世界の崩壊について考えずにいられそうじゃないか?" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "こっちにも一缶くれないか。古き良き時代の話をしよう、。" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "ああ、もちろん、。そろそろ一息入れたかったんだ。調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "もちろんいいよ。、調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "ああ、くだらないことを話そう!最近どう?" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "断ると思う?最近は元気にしてる?" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "ああいいよ。元気でやってる?" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "数分ぐらいならいいか。元気かい?" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "よし、、元気かい?" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "もちろん良いよ。話していれば君も胸のつかえが取れるだろ?" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "いつでも語り合う準備はできてたよ!でもどうしたんだ、大丈夫?" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "そうだな、。もっとお互いの事を知るべきだ。最近は上手くやってる?" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "もちろん、いい気晴らしになるよ。調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "、いいアイデアだ。しばらく世界の惨状は忘れよう。調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "ああ、そりゃいいや。最近調子はどう?" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "いいね。ええと、じゃあ、天気の話でもする?" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "チクショウ" @@ -152607,6 +154336,18 @@ msgstr "どうやって大変動を生き延びたのか教えてほしい。" msgid "Was it rough surviving thus far?" msgstr "今までどうやって無事に乗り切ったんだ?" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "どうしてこんなことになった?一体何が起きたのかな?" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "どうなってるんだ?世界で何が起きているんだ?" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "どのようにして世界が崩壊したのか、何か聞いたことはないか?" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -153322,6 +155063,311 @@ msgstr "は可能な限り敵と戦いません。" msgid " will follow normal engagement rules." msgstr "は通常の戦闘規則に従います。" +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "それはいいな、ビールを飲もうじゃないか。" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "そうだな。ビールを用意しないか?" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "ああ、君が持ってるビールを分けてくれるなら、好きなだけ話そう!ハハ、冗談だよ。" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "ねえ、冷たいビールがあればお喋りはもっと盛り上がるだろうな。" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "雑談中にビールを空ければ...世界の崩壊について悩まずにいられそうだな。" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "、こっちにも一缶くれないか。" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "ああ、この暑さには参るよな?" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "夏を満喫しよう。" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "正直、もう少し涼しくなればいいのにと思うよ。" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "いいよ。話していれば凍えずに済むからな。" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "そうそう、雪は嫌いじゃないんだ。" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "ゾンビが凍らないのは変だよな。" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "ええと、かなり体調が悪いんだけど...分かったよ。" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "ちょうど息抜きしたかったんだけど、そっちも?" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "それで、調子はどう?" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "くだらない話をしよう!も話したいよな?" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "ああいいよ。元気でやってる?" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "数分ぐらいならいいよな。元気かい?" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "よし、、元気かい?" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "もちろん良いよ。話していれば君も胸のつかえが取れるだろ?" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "いつでも語り合う準備はできてたよ!でもどうしたんだ、大丈夫?" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "分かったよ、。調子はどう?" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "いいね。調子はどう?" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "しばらく世界の惨状は忘れよう。調子はどう?" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "そりゃいいや。最近調子はどう?" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "ええと、じゃあ、天気の話でもする?" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "時間を作ってくれてありがとう。最近どう?" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "ちょうど脚が疲れてきたんだ。そっちも?" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "今日は最高の気分だ。何故かは分からないけど、かなり良い感じだよ。" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" +"世界が終わったなんて信じられないよ。全てが崩壊したあの日のことが頭から離れないんだ。暴動。デマ。狂人。こんなことになるなんて思いもしなかった。" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" +"世界が終わる前に出回ってた噂に真実が混じってるとか、思ったことある?確か水道水に洗脳薬が混じってるとか、バイオテロとかだったかな?筋の通った話もあるけど、非現実的すぎる。なんたって、こっちは本物のゾンビを相手してるんだからな。" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "この状況でもっと信心深くなるべきなのか、それとも信仰を捨てるべきなのか、悩んでるんだ。はどう思う?" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "荷物の整頓について考えてた。散らかりすぎだ。武器を取ろうと思ったらチョコバーだったなんて、嫌だろ?" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "どうしてこんなに悩んでるんだって、不思議に思たことはないか?どうせ最後はゾンビになるのに、戦うのを止めない。何か意味があるんだろうか?" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "今すぐゾンビの群れに突っ込んで、弾丸をぶち込んでやりたいよ。もちろん大騒動になって命の危険に晒されるのは無しで。" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "目を閉じる度に、暴動の様子が浮かぶんだ。私だけだろうか。分かってくれるか?" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "世界が崩壊する前までに過ごしてきた時間が、全部夢だったんじゃないかって思ったことない?" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "世界が終わるんだと実感したのはいつだった?私は、YouTubeで赤ん坊を殺す女を見たときだ。酷いもんだよ、なぁ?" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "政府の役人は今もどこかの地下壕に引きこもってるんだろうか。" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" +"世界が終わった時に流れていた狂ったニュースを覚えてるか?暴動事件の話にかき消されてしまったようだけどね。ほら、ロードアイランド州の知事が合衆国から独立するとか宣言してただろ?" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" +"ゾンビは、人間だった頃の自分を覚えてるんじゃないだろうか。そして、死体の中に意識だけ閉じ込められて、自分のやったことを見続けるんだ。気になって眠れないよ。" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "洗脳薬を水道水に入れて暴動を引き起こしたって話があったけど...あの薬は今も水道水に残ってるんだろうか?" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" +"誰がこんなことを引き起こしたのか、考えずにはいられないな。ニュースは信用できない。ゾンビのことを「暴徒」だと何週間も主張し続けていたからな。原因は何だ?ゾンビの起源とは?" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" +"中国についての噂に少しでも真実があるなら、中国の国内もこんな感じなんだろうか?それともアメリカが隔離所みたいな扱いになっていて、世界のどこかは今も無事なのか?" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" +"ケガの治り方がいつもと違うことに気づいたか?世界が崩壊する前から兆候はあったが、より顕著になってきた。傷が塞がる過程で肉芽組織がほとんど形成されないなんて事があるのか。" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "ゾンビがどうやってエネルギーを得ているのかまだ理解できない。まるで永久機関だ。" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" +"パズルのピースがなかなか嵌らないな。誰がゾンビを作ったのか?エネルギー源は?洗脳薬の噂は本当だったのかもしれない。もしくは、生物工学者が死者を生き返らせる方法を見つけたのかな。" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "ゾンビたちはどうやって動いてるんだ?何を食べている?いつかは腐って動かなくなるんだろうか?" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "最近は、トイレットペーパー不足が心配だな。どう思う?" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "密室になってる建物を開けたら中にゾンビが1体いるなんて、変だと思わないか?どうやって入ったんだ?" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" +"時々思うんだけど、発狂して暴れた奴以外も、人類全員が精神異常者になったんじゃないか?世界が崩壊してからこんなに好き放題できるなんて思わなかったよ。" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "最近は何か面白い本を読んだ?本が残っていてほっとしたよ。" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" +"何か恋しいものはある?私は映画館だ。ハリウッドは生き残ってるかな?ゾンビ俳優がいるかも。ゾンビになってもクソ映画を撮り続けてたりして。ハハ、見てみたいな。" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "ちゃんと聞いてるよ、..." + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "色々なことが思い浮かぶよ..." + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "うん、うん。そんなことを考えてたのか..." + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -154642,6 +156688,14 @@ msgid "" msgstr "" "Rivtech社の弾薬の広告です。装甲板の真ん中に穴が開いており、その横には派手な色の弾薬が写っています。見出しには「Rivtechの8x40mmケースレス弾。圧倒的な威力」と書かれています。" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -154652,6 +156706,21 @@ msgid "" msgstr "" "ノースロップ社の支援ロボット軍事モデルの広告です。フェンスを背景に暗緑色で特徴的なクモの巣状の模様が描かれた機体が載っています。機体は背後の地平線に浮かぶ黒い影を捉え、小型のロボットを高速で射出しています。見出しには「あなたを守るためにここにいる」と書かれています。" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -163182,7 +165251,7 @@ msgstr "沼地にもゾンビがいるらしいな。ゾンビが恐竜を噛ん msgid "" "I know there aren't alligators in the sewer, but I heard there was some kind" " of big lizard down there. Probably not a good idea to check." -msgstr "" +msgstr "下水道にワニはいないだろうが、大きなトカゲはいるそうだ。覗いてみようなんて思わない方がいい。" #: lang/json/snippet_from_json.py msgid "" @@ -163190,12 +165259,13 @@ msgid "" "something nice and gave them a pet you could ride them like a pony. Or " "maybe they'd eat you instead." msgstr "" +"大型恐竜の中には、結構聞き分けの良さそうな奴もいる。何か餌を食べさせてペットにすれば、ポニーみたいに騎乗できるんじゃないか?失敗すればこっちが食べられるだろうけど。" #: lang/json/snippet_from_json.py msgid "" "One time I found a strange egg out in the woods. It was probably a " "dinosaur, but I cooked it and it was pretty good!" -msgstr "" +msgstr "森の中で、奇妙な卵を見つけたことがある。恐竜の卵だったのかもしれないけど、調理したら結構おいしかったよ。" #: lang/json/snippet_from_json.py msgid "" @@ -163212,6 +165282,7 @@ msgid "" "were already prepared and are proceeding ahead of schedule. The hosts are " "most receptive to improvement." msgstr "" +"訪問者たちの研究は着実に進んでいる。大型レーザー作戦は十分な資金を得られなかったが、次善策の改造兵士については既に準備が整っており、予定よりも前倒しで進んでいる。改造希望者は多数用意できる。" #: lang/json/snippet_from_json.py msgid "" @@ -166267,7 +168338,7 @@ msgstr "郊外" #: lang/json/start_location_from_json.py msgid "Desert Island" -msgstr "" +msgstr "無人島" #: lang/json/start_location_from_json.py msgid "Experiment Cell" @@ -166414,11 +168485,11 @@ msgid "Acolyte." msgstr "修行者よ。" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" +msgid "You're back. Have you come to listen to the song?" msgstr "戻ってきたな。歌を聞きに来たのか?" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" +msgid "You there. Quiet down. Can you hear it? The song?" msgstr "そこのお前。静かに。この歌が聞こえるか?" #: lang/json/talk_topic_from_json.py @@ -166453,8 +168524,8 @@ msgstr "もう行くよ。お気をつけて、占い師さん。" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "注意深く耳を傾けろ。骨たちが...歌っている。聞こえるか?歌っているだろう?物語が聞こえるだろう?" #: lang/json/talk_topic_from_json.py @@ -166467,11 +168538,11 @@ msgstr "ええと...ああ、そうだね。もう行かないと。" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" "大変動が起きた時、あらゆるものが...変化した。あらゆる生物の骨は大抵、歌を歌う。生物は破壊され、変化し、再び立ち上がる。無限の輪廻だ。死人が生き返り歩きだす。化け物たちが互いを引き裂きあう。よく観察すれば、野蛮な力が共鳴して静かに震えているのが分かるはずだ。骨を取れば、輪廻の輪は断ち切られる。その物語や、歌や、力がお前のものとなる。" @@ -166490,11 +168561,11 @@ msgstr "ええと、そうだな、その話を信じている人は他にもい #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" "骨を潰せば、その持ち主が再び立ち上がることはない。骨を調べれば、その持ち主に何があったのか分かる。すなわち、物語だ。変化を引き起こす源は生きており、私たちすべての中で動き、この新世界を構成する必然的な一要素となっている。それは変化の力を持っている。すなわち、強さだ。二つが合わさり...美しい歌となる。" @@ -166504,7 +168575,7 @@ msgstr "同意できるかはともかく、あなたが言いたいことは伝 #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "この主張に同意する者は存在する。彼らを助けよ。我らは多数ではないだろうが、歌に導かれて力を得る。" @@ -166518,10 +168589,10 @@ msgstr "主張?どうして骨を集めるんだ?" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" "歌は様々な方法で形を成す。骨を彫って作った魔除けや武器、防具は計り知れぬ力を秘めている。時が来れば私や私の縁者たちが数多の歌を集めて歌い、世界を復元し、あるいは終焉させる。復元と終焉。そこに違いはない。" @@ -166532,7 +168603,7 @@ msgstr "世界の終焉?何だって?" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" "一つの歌に十分な力を集めれば、大変動を巻き戻す...もしくは、時を加速させ、全てを終わらせることができる。どちらも等しく世界の終焉だ。しかし、望ましいのは、どちらの選択肢も選べる現状の世界だ。" @@ -166549,8 +168620,8 @@ msgstr "狂人め。" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" "受け入れてくれるのだな。この上なく良い心がけだ。きっと、お前もいつか歌の力を感じ、我らの縁者となるだろう。修行者よ、歌を感じ取れるよう、今は耳を傾け続けなさい。" @@ -166561,9 +168632,9 @@ msgstr "あ...ありがとう。" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" "お前が疑うのももっともだ。きっと、お前もいつか歌を聞き、その力を感じる時がくるだろう。だがそれまではお前は修行者であり続け、縁者への道は閉ざされたままだ。" @@ -166622,15 +168693,6 @@ msgstr "話してくれ。" msgid "Perhaps another time, Seer." msgstr "またいつか会おう、占い師さん。" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" -"悟りへの道を歩むなら、まず歌に耳を傾け学びなさい。旅立ち、生き物を解体し、指先で力を感じ取りなさい。そして骨を持って来なさい。彫刻を作ってあげよう。" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "ああ、その話をもっと詳しく知りたい。協力するよ。" @@ -166639,10 +168701,6 @@ msgstr "ああ、その話をもっと詳しく知りたい。協力するよ。 msgid "Not interested." msgstr "興味が無いね。" -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "素晴らしい。さあ取り掛かるのだ。" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "仕事は終わったけど、私からも尋ねたいことがある..." @@ -166659,21 +168717,13 @@ msgstr "私の活動に役立つ道具を分けてもらえない?" msgid "I'm off then." msgstr "もう行くよ。" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "" -"いたるところで見かける動く死体は、敵意を持って動いている。あれらの歌を聞くのもいいが、修行の身には堪えよう。自然のままの生き物を狙うといい。" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "つまり、ゾンビでも怪物でもない普通の生物だな。分かったよ。" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "悟りへの道はお前自身で歩め。私の助けはお前の歩みを妨げ、お前の歌を迷わせることになる。" @@ -166684,7 +168734,7 @@ msgstr "なるほど。よく分かったよ。" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "私はお前に印を与えた。つまり、お前が歌を聞く方法を学び取れるかもしれないという事だ。そうだな、私の力を貸し与えよう。" #: lang/json/talk_topic_from_json.py @@ -166699,11 +168749,6 @@ msgstr "そう言ってもらえると嬉しいよ。さあ行こう。" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "良い提案だが、今は一人で取り組みたいことがある。またいつか聞いてくれ。" -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "気が進まないことは理解できる。道を見出したらまた来なさい。" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "どうだろうな。話を変えよう..." @@ -166715,14 +168760,14 @@ msgstr "なるほど。私はもう行くよ。" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" "大変動で変わったのは、歩く死体や怪物だけではない。ある種の...輪廻が生まれたのだ。全ては繰り返される。自分自身の輪廻は知覚できないが、我ら全て、つまりお前にも、私にも起こることだ。お前は何度倒れた?お前は身体から肉を剥がされ、食い尽くされる。あるいはかすかな呻き声とともに死に絶える。だが、お前の骨は再び立ち上がる。異なる肉、異なる名、時には異なる記憶を同じ骨に纏って。我らは皆同じ輪廻に囚われている。ただ忘却し続ける。だからこそ、我らは歌を集める必要がある。それが、復活ではなく破壊を意味するとしても終焉を目指さねばならない理由だ。" @@ -166752,6 +168797,14 @@ msgstr "その話はもういい。" msgid "Skip it, let's get going." msgstr "その話はもういい、そろそろ行こう。" +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "この世界で生き抜くために役立つ話はある?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "拠点について話そう。" + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "「大抵の」指示とは、どういう意味だ?" @@ -166957,7 +169010,7 @@ msgstr "医薬品の渡し方を教えてくれ。" #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -167162,8 +169215,8 @@ msgstr "やあ、。" #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" msgstr "止まれ、両手を上にあげろ!ああ、驚かせてしまったな...もう法律なんて無いのに..." #: lang/json/talk_topic_from_json.py @@ -167185,7 +169238,7 @@ msgstr "もう行かないと。" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "事が起こったとき、私は持ち場で見張り中だった。連絡を入れても警官は誰一人戻らず、それどころか人間は一人残らずいなくなった..." #: lang/json/talk_topic_from_json.py @@ -167239,7 +169292,7 @@ msgstr "" "ああ、私のように街で立て籠もってる奴がいる。何度か取引をしたが...たまに知らない放浪者も来て、自分が置き去りにしたものより良い商品がないかとチェックしているな。" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." +msgid "No, just no…" msgstr "やめろ、おい やめろ..." #: lang/json/talk_topic_from_json.py @@ -167251,7 +169304,7 @@ msgid "Make it quick, I want to go back to sleep." msgstr "まだ眠いんだ、すぐにでも寝直したいよ。" #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." +msgid "Just few minutes more…" msgstr "あと5分..." #: lang/json/talk_topic_from_json.py @@ -167298,6 +169351,68 @@ msgstr "戦闘時の指示を出したい。" msgid "I want to set some miscellaneous rules." msgstr "その他の規則を設定したい。" +#: lang/json/talk_topic_from_json.py +msgid "I'd like to know a bit more about your abilities." +msgstr "あなたについてもっと詳しく知りたい。" + +#: lang/json/talk_topic_from_json.py +msgid "There's something I want you to do." +msgstr "やってほしいことがあるんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "I just wanted to talk for a bit." +msgstr "ちょっと話がしたくなったんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "Can you help me understand something? (HELP/TUTORIAL)" +msgstr "色々と教えてもらえないか?(ヘルプ/チュートリアル)" + +#: lang/json/talk_topic_from_json.py +msgid "I'm going to go my own way for a while." +msgstr "当分は一人で行動させて欲しい。" + +#: lang/json/talk_topic_from_json.py +msgid "Let's go." +msgstr "行こう。" + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" +msgstr "*ザザッ* 冗談だろ?これは携帯電話じゃないんだ。直接会った時にしてくれないか?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what did you want to say?" +msgstr "分かったよ、何の話だ?" + +#: lang/json/talk_topic_from_json.py +msgid "Mind if we just chat for a bit about your history?" +msgstr "あなたの過去について話してもらえないか?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's just chitchat for a while, I could use some relaxation." +msgstr "気分転換に、少し雑談でもしようか。" + +#: lang/json/talk_topic_from_json.py +msgid "I changed my mind, wanted to ask you something else." +msgstr "気が変わった、他に聞きたいことがあるんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "I'm all ears, my friend." +msgstr "友よ、ちゃんと聞いてるよ。" + +#: lang/json/talk_topic_from_json.py +msgid "You gonna give me orders?" +msgstr "何か指示を出してくれるのか?" + +#: lang/json/talk_topic_from_json.py +msgid "What would you like?" +msgstr "用事は何だ?" + +#: lang/json/talk_topic_from_json.py +msgid "Just say the word." +msgstr "詳しく言ってくれ。" + #: lang/json/talk_topic_from_json.py msgid "Can you teach me anything?" msgstr "何か教えてくれないか?" @@ -167322,14 +169437,6 @@ msgstr "この場所を見張ってくれ。" msgid "I want to assign you to work at this camp." msgstr "この拠点で仕事をしてくれ。" -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." -msgstr "現在の行動について話そう。" - -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "拠点について話そう。" - #: lang/json/talk_topic_from_json.py msgid "Find a horse and mount up!" msgstr "ウマを探して騎乗しろ!" @@ -167343,32 +169450,20 @@ msgid "Please go to this location." msgstr "この場所へ向かってくれ。" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." -msgstr "あなたについてもっと詳しく知りたい。" - -#: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" -msgstr "この世界で生き抜くために役立つ話はある?" - -#: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" -msgstr "あなたの過去について話してもらえないか?" - -#: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." -msgstr "気分転換に、少し雑談でもしようか。" +msgid "I want you to build a camp here." +msgstr "ここに拠点を作ろう。" #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." -msgstr "あなたへの指示について教えてくれ(NPCチュートリアル)。" +msgid "We need to abandon this camp." +msgstr "この拠点を放棄しよう。" #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "当分は一人で行動させて欲しい。" +msgid "Show me what needs to be done at the camp." +msgstr "拠点でやるべきことを教えてくれ。" #: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "行こう。" +msgid "Let's talk about your current activity." +msgstr "現在の行動について話そう。" #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." @@ -167910,10 +170005,6 @@ msgstr "この場所へ向かってくれ..." msgid "Stay at your current position." msgstr "その場に留まってくれ。" -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "拠点でやるべきことを教えてくれ。" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "私は現在、をしている。" @@ -167986,60 +170077,6 @@ msgstr "...ザザザザ...了解、指定された場所へ向かう、どうぞ msgid "Sure thing, I'll make my way there." msgstr "分かった、指定された場所へ向かう。" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "ああ、この暑さに私も参っていたんだ。ちょっと休憩しよう。、調子はどう?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "いいよ。話していれば凍えずに済むからな。最近どう?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "そうだな、そろそろ息抜きの時間だ!最近調子はどう?" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "まだ日は落ちていないようだな?調子はどう?" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "その、今はかなり体調が悪いんだけど...それでもやるのか?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "よし、そうだな、私の依頼をたくさん引き受けてくれてありがとう!それで、の調子はどう?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "よし、すこし休憩しよう。ああ、そうだ、頼みを聞いてくれてありがとう。それで...調子はどう?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "今なら少し時間があるな。思えばもう1か月くらいは経ったんだな...これから先、どうするつもりなんだ?" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "なるほどね、悪くない、悪くないよ..." - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -168094,7 +170131,7 @@ msgid "Hello there." msgstr "やあ、君か。" #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." +msgid "Okay, no sudden movements…" msgstr "よし、急に動いたりはするなよ..." #: lang/json/talk_topic_from_json.py @@ -168447,7 +170484,7 @@ msgid "Ah, okay." msgstr "あぁ、分かった。" #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." +msgid "Not until I get some antibiotics…" msgstr "抗生物質さえあれば..." #: lang/json/talk_topic_from_json.py @@ -168555,7 +170592,7 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "車両を運転している間は、ちゃんと訓練できないよ!" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." +msgid "Give it some time, I'll show you something new later…" msgstr "少し時間をくれないか。後で話をしよう。" #: lang/json/talk_topic_from_json.py @@ -168583,7 +170620,7 @@ msgid "See you around." msgstr "またな。" #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." +msgid "I really don't feel comfortable doing so…" msgstr "申し訳ないが、本当に嫌なんだ..." #: lang/json/talk_topic_from_json.py @@ -168655,7 +170692,7 @@ msgid "Thanks, see you later!" msgstr "ありがとう、それじゃあまた!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." +msgid "You picked up something that does not belong to you…" msgstr "自分の所有物ではないものを拾ったな..." #: lang/json/talk_topic_from_json.py @@ -168749,13 +170786,13 @@ msgid "You might be seeing more of me…" msgstr "これからもよろしく..." #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" +msgid "Hey again. *kzzz*" msgstr "また会ったな。*ザザザザ*" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "ワ...私は自由だ。*ザザザザ* 自由なんだ!*ブブブ* 久しぶりに人と会えたよ。" #: lang/json/talk_topic_from_json.py @@ -168777,7 +170814,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "失礼、私には関係ないことだ。存分に自由を満喫してくれ。" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "*ブブブ* もちろん!これからどうするんだ?" #: lang/json/talk_topic_from_json.py @@ -168790,7 +170827,7 @@ msgstr "これからは別々の道を歩もう。自由を満喫してくれ。 #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "...なんだって。*ビィィィ* どうして君を信用したんだろうな?*ザザザザ* 奴らと同じくらい悪人じゃないか!" @@ -168812,8 +170849,8 @@ msgstr "この話は忘れてくれ。自由を満喫するといい。" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" -msgstr "分かった、分かったよ、*ブブブブ* 悪かった!痛いのはもう嫌だ!チップを入れること以外なら何でもする!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +msgstr "分かった、分かったよ、*ブブブブ* 悪かった!痛いのはもう嫌だ!チップの移植以外なら何でもする!" #: lang/json/talk_topic_from_json.py msgid "Follow me and do my bidding, then." @@ -168828,7 +170865,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "いや、私が悪かった。そんなつもりじゃなかったんだ。これからは好きに生きればいい。" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "...お前を...*ザザザザ*...殺す!" #: lang/json/talk_topic_from_json.py @@ -168863,14 +170900,6 @@ msgstr "拠点の仕組みを教えてくれ。" msgid "Tell me how faction camps have changed." msgstr "拠点の仕組みがどう変わったか教えてくれ。" -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "ここに拠点を作ろう。" - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "この拠点を放棄しよう。" - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "何でもない。他の話をしよう。" @@ -169144,7 +171173,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." +"talk…" msgstr "本気か?ここが下らない話ができるほど安全な場所だとは思えないな..." #: lang/json/talk_topic_from_json.py @@ -169167,6 +171196,50 @@ msgstr "何について話そうか?" msgid "Actually, never mind." msgstr "やっぱり何でもない。" +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "友よ、どうしました?" @@ -169188,7 +171261,7 @@ msgid "May the earth flourish beneath our paths." msgstr "我々の旅路のもとで、大地が繁栄しますように。" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "魂、精神、そして肉体の統一..." #: lang/json/talk_topic_from_json.py @@ -169376,11 +171449,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" -"私は農場で育ったから、化け物やゴブリンのことはよく分からない。でも、手間暇かけて農作物を育てているよ。田舎は良いよ。綺麗だし。危険も少ないし。いや、少ないといいな。" +"私は農場で育ったから、化け物やゴブリンのことはよく分からない。でも、手間暇かけて農作物を育てているよ。田舎は良い。綺麗だし。危険も少ないし。いや、少ないといいな。" #: lang/json/talk_topic_from_json.py msgid "Hey, I didn't expect to live long enough to see another living human!" @@ -169958,7 +172031,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "私のことは気にしないで。もう行くよ。" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "確かに私だ!唯一無二のフードパーソン!" #: lang/json/talk_topic_from_json.py @@ -170415,6 +172488,39 @@ msgstr "" msgid "Huh." msgstr "ふぅん。" +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "「今の状況」をまったく理解できない。どうして私が、世界が崩壊したことを知っていると思ったんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "よし、分かった。これまでの経験の中で、覚えていることだけでいいから、教えてもらえるか?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" +"何、そんなことも知らないのか?いや、申し訳ない、これじゃ不公平だな。不気味な事件だったよ。始まりは暴動だった、よな?普通に人生を送り、仕事をしていたら、人々が暴動を起こし始めたんだ。一般的な抗議行動とも、暴力的なものでもない。ただ外に出て、滅茶苦茶暴れ出した。ニュースは無視しようとしてたけど、インターネット上はそうもいかなかい。何が原因かは分からないが、水道水に薬だか毒が混入したとか言われてたかな?それでも、最初はこんなに酷くなるとは思いもしなかった。途中で倒れた「暴徒」が立ち上がり、胸に穴が空いたまま歩き出したのが本当の混乱の幕開けさ。その出来事の数日後、いや数週間後か...そこから先が、ぼやけているんだ。他の誰かに、世界が完全に崩壊するまでの状況を尋ねる必要があるな。" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "詳しく教えてくれてありがとう。" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -170470,10 +172576,10 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" -"最終的にはそうだな。周囲は何時間も静かだった。私は喉がカラカラで、怪我もしていたし、何より怖かった。発狂しないで済んだのは日々の訓練のお陰だろうな。私は何とか抜け出して、怪我の程度を見てみようと思ったんだ。簡単だったよ。バンの側面は裂けて外に通じていたし、私を圧し潰していた瓦礫もそこまで大きくはないようだったからね。バンの残骸がテントのように覆いかぶさってくれていたんだ。怪我もそこまで酷くはなかった。私はできる限り装備をたくさん持って、抜け出したんだ。辺りは夜になっていて、街の外からは戦闘しているような音がしたから、中心部に向かった。何ブロックか歩くと、と遭遇したから...逃げ出した。逃げて逃げて逃げ続けて、ここに辿り付いたんだ。" +"最終的にはそうだな。周囲は何時間も静かだった。喉がカラカラで、怪我もしていたし、何より怖かった。発狂しないで済んだのは日々の訓練のお陰だろうな。私は何とか抜け出して、怪我の程度を見てみようと思ったんだ。簡単だったよ。バンの側面は裂けて外に通じていたし、私を圧し潰していた瓦礫もそこまで大きくはないようだったからね。バンの残骸がテントのように覆いかぶさってくれていたんだ。怪我もそこまで酷くはなかった。私はできる限り装備をたくさん持って、抜け出したんだ。辺りは夜になっていて、街の外からは戦闘しているような音がしたから、中心部に向かった。何ブロックか歩くと、と遭遇したから...逃げ出した。逃げて逃げて逃げ続けて、ここに辿り付いたんだ。" #: lang/json/talk_topic_from_json.py msgid "" @@ -170757,6 +172863,32 @@ msgstr "かわいそうなフィルシー・ダン。 msgid "Thanks for telling me that stuff. " msgstr "話してくれてありがとう。" +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" +"ええと、たしか、本当にヤバい暴動があった、んだっけ?皆が暴力的で不快な気持ちに満たされていたな。実を言うと、私は少し精神的な旅に出ていたから、あまり覚えていないんだ。一番奇妙に思ったのは、誰もが互いを*心配*していなかったことだ。人間の思いやりが全部吸い取られてしまったみたいだった。きっとこれは、ある種のネガティブエネルギーの仕業だ。死者を生き返ったのもそのせいだ。それから、ええと、怪物?そこまでは分からないよ。" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "色々知っているみたいだな。原因は何だと思う?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" +"難問だな。でも、世界が終わる一年くらい前に、ある夢を見たことを思い出したんだ。夢の中に出てきた大きな悪のエネルギーは、地球上のあらゆる正の感情を吸い上げようとしていた。きっとそのせいで、人間がモンスターやゾンビになってしまったんじゃないか?そして、今に至る、ということだ。ありえないことが起きてるってことだろう?" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -170809,6 +172941,25 @@ msgid "" msgstr "" "に関しては解決できたと思い込んでいたってことさ。気が大きくなって、段々と遠出をするようになったんだ。ある時叫び声をあげるゾンビが私を見つけて、他の群れを呼び寄せたんだ。その群れに交じってたのが、、フォルクスワーゲンくらいある胴体が全て骨の装甲で覆われた、巨大な獣じみた顔のゾンビだ。あんなの勝てっこない。そのデカブツは他のゾンビ共のせいで身動きが取れていなかったから、大急ぎで拠点に戻ったよ。窓を閉めて鍵を掛けたが、遅すぎた。追ってきたデカブツが壁を叩き壊し始めたんだ。私は持てるものだけ持って、地平線のかなたまで逃げた。去り際に見えたのは、完全に崩れ落ちた拠点だ。デカブツは恐らく崩壊に巻き込まれて死んだと思うけど、調べに戻ろうとは思わないよ。" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" +"何があったかって?よく分からないな。知っての通り、政府や警察は、暴動なんかを含めたあらゆる騒動を完全に抑え込めなかった。原因はよく分からない。最初はよくある事だと思ったけど、そうじゃなかったんだ。ちょっと興奮したし、革命の始まりだと思って恐ろしくもなった。でも参加しようと考えるほど熱狂もしなかった。もし参加したら死んでいただろうね。とりあえず自宅に籠って、小さな非常持ち出し袋を準備したんだ。そうこうしてると、酷い傷を負って倒れた暴徒が立ち上がってそのまま暴れ出す動画がネット上に流れ始めた。初めてそれを見て信じた奴がどれだけいるのかは知らないが、それがきっかけで、私は街を捨てて避難シェルターへ向かった。その後何が起きたのかは、正確には分からない。私が暮らしていた都市部は荒れ放題で、今は人っ子一人いないよ。携帯電話も圏外になっていたけど、昨日政府が転覆したっていう緊急メッセージだけは例外だった。そして数日が経ち、電気もストップしてしまったんだ。" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -170844,6 +172995,22 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "一体何が起きたんだろう?他の場所でもそいつらを見かけた?" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" +"ええと、暴徒や、軍隊や、警官や、ゾンビや、大地を闊歩してる悪夢みたいな気色悪い化け物について、私が知ってると思うのか?何が原因だと訊かれても、そんなの、知るか、としか言えないよ。きっと、政府が生物兵器の実験か何かで事故を起こしたんじゃないかな。起きたことを最初から最後まで嘘でごまかそうとしたんだろう。「中国からの攻撃」なんてたわ言が本気にされてるとは思えない。それで、地球上のどこかの国が災厄を封じ込めようとして、今の終末に至るってとこか。アメリカのどこかでマジの核兵器が爆発した、って話も聞いた。多分ヨーロッパらへんの国が、なんとかこの状況をアメリカで押し留めようとしてるんだ。もしかしたら効果があったのかも。今も酷い状況だけど、これ以上酷いことにはならないだろう。" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -170905,6 +173072,42 @@ msgid "" msgstr "" "そうだ。拠点の居心地はかなり良かったが、段々と気が狂いそうになってきたんだ。一日中暗く、肌寒い場所で、拾ってきたジャンクフードを食べて過ごす...そんな生活じゃ精神が長くは持たない。地上の気候が暖かくなって日照時間も伸びてきた頃に、ようやくちょっと勇気を出すことにした。について学ぶ時間は十分あったから、その後はかなり順調だったよ。転々と寝床を変えながら木の実なんかを食べて暮らしたけど、最初の数か月に比べたらずいぶん良い生活が送れるようになったな。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" +"はぁ、、何が発端なのかすら分からないよ。暴動か?いや、兆候はそれ以前からあった。数週間前から変な噂が広まっていたんだ。本当に恐ろしい、普通じゃない犯罪、誰かが人を食ったとか、口にも出したくない類の話を聞いただろ?だから、暴動が始まった時は既に、これは普通じゃないって気がしていたんだ。それもあってか、安全なうちに避難できたし、買い溜めしておく時間もあった。あまり遠出しないようにもしていたよ。あの頃は皆メチャクチャにイカレていた。何年か前にあった感染症の大流行を思い出したけど、警察が市街地に集まって狂ったようにに市民を撃ち殺して回ったりはしなかったさ。" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "何が原因なのか、心当たりはないか?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" +"さあね。政府からの情報も矛盾するものばかりだったし、実際に凶悪事件は起きていた。あれだよ、女が赤ん坊を殺す動画、見ただろう?あぁ、まだ悪夢を見る。あれは何だったんだろうな。女の表情はよく見えなかった。もちろん、もっと酷い出来事を、この目で実際に見てきた。でも、あの光景が今でも私を悩ませるんだ。とにかく、暴動はいつまで経っても治まらず、暴徒がゾンビになったときは、何もかも手遅れだった。士気が下がっただけなのか、他の原因があるのかは知らないが、軍と警察も暴徒と同じように同士討ちを始めたって噂を聞いた。死者が生き返った根本的な原因は何かって?何の手掛かりも浮かばないね。" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -170914,6 +173117,53 @@ msgid "" msgstr "" "たくさんの避難民と一緒に避難センター行きのバスに乗っていたら、途中で今までに見たこともないような巨大なゾンビと衝突したんだ。何も特別なことはしていないが、化け物は他の乗客を狙っていたから、何とか逃げ出せたよ。" +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "話を続けてくれ、それから何が起きたんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" +"肺が口から飛び出しそうになるまで走ったよ。それから、森の中のモミの木の根元で一夜を過ごした。朝起きたら、誰かの話し声が聞こえたから、見に行ったんだ。周囲には暴徒や狂人がたくさんいたから、かなり慎重に動いたよ。そして目撃したのは、ゾンビよりもたちの悪い怪物さ。壊れたテープレコーダーみたいに無意味な台詞を呟く巨大な昆虫みたいな奴だ。そいつは生死も分からない倒れた人間を何人か引きずっていた。正直、正体を探るなんて無理だった。茂みに身を潜めて、声が聞こえなくなるまで息をせずじっとしていたよ。" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "それからどこへ向かったんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" +"茂みから出ても何も起きなかったから、少し離れたところにある古い小屋へ向かったよ。雨が降ってきていたけど、そこなら雨風を防げるし、人目にもつかない。バックパックに詰め込んだクソみたいな味の栄養バーがなくなるまでは、そこで過ごしたんだ。その後はこうして別の人間と出会うまで、放浪生活さ。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" +"何だろう、バック・トゥ・ザ・フューチャーみたいなものかな?世界は終わった、それだけさ。地震や、鳥や、ヘビや、飛行機は関係ない。暴動から始まって、犯罪者を始末するために警察を、そして軍を派遣したんだ、。政府は洗脳攻撃だって主張して時間稼ぎをしようとしたけど、まあそれはいつも通りのクソだね。政府なんてのはのは法を破る口実を探してる、権利を持った赤ん坊だ。今回は特に酷かった。結局どうしようもなくなって逃げ出したんだけどな。暴動を鎮圧するために都市の中心部を爆撃しているなんて噂も聞いた。流石にそれは極端すぎるって思ったよ。" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -170957,6 +173207,29 @@ msgstr "悪かった。ハチについて詳しく教えてもらえないかな msgid "Right. Sorry." msgstr "それもそうだな。悪かったよ。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" +"分かった、聞いてほしい。政府の言うことは信じるな。暴動の発生、軍による制圧の失敗、過去数日の間に現れた核でも使わないと倒せないような巨大モンスター。これらすべてに共通点がある。" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "興味深い話だ。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" +"マトリックスって映画を見たことは?まさにあれなんだ。この生活が。このシミュレーションの作者は、私たちをここに閉じ込めておくために、ある程度辛い状況に置き続ける必要がある。最近ありえない事ばかり起きているのは、きっとアルゴリズムが滅茶苦茶になって、暴走状態に陥ったに違いない。でも、この幻想が終わらないんだから、まだ機能はしているんだ。" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -170970,6 +173243,20 @@ msgid "" msgstr "" "ええと、携帯電話の警報が鳴りやんで、避難シェルターへ行けってメッセージが流れたから、その通りにしたんだ。避難シェルターはものすごく混雑していたから、皆は避難センターへ向かうバスを待っていたけど、いくら待ってもバスはこなかった。その後はもう分かるだろう。パニック状態になって、喧嘩が起きた。それからどうなったのかはよく分からない。私はシェルターのロッカーから荷物を持てるだけ持って森へ逃げたんだ。数日後に戻ったら、もぬけの殻だったよ。他の人がどうなったかなんて、想像もつかないな。" +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" +"避難所で色々な話は聞いたが、正直言って、それらしい説は一つだけだった。これはある種の科学実験が失敗している状態なんだ。そもそもどうして暴動とゾンビが発生したのかは知らないが、世界中で制圧に失敗したなんて考えられない。ああ、私も「政府は崩壊した」なんてビラを見たけど、そういった噂が急速に広まっても*意味*がないじゃないか。恐らく私たちはある種の隔離ゾーンにいるんだ。中で何が起きたとしても、経過や機能を確認するために実験を継続して、次の有事にもっと上手く対応できるようにする。ゾーンの外では、きっと普段通りの生活が営まれているはずだ。" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -171044,6 +173331,44 @@ msgstr "悪いことを聞いてしまったな。" msgid "Sorry for asking. " msgstr "悪いことを聞いてしまったな。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "へぇ、ブッ飛んだ意見を聞く心の準備はできた?政府がやったんだよ、。意図的に、あるいは多少意図的にね。" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "えっ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" +"まさに言葉のとおりだ。政府は嘘をついていた。何が起こってるのかは神のみぞ知る、ってね。実際は何が起きているのか理解させたくなかったんだ。恐らく、最初は、人々を統制する手法として始まった。それがいつの間にか裏目に出た。多分、最初は市民から教育を奪おうとしたんだ。簡単に欺けるようにね。それが失敗したので、次は水道水に薬物を混ぜて市民を愚鈍にしようとした。愚鈍というか、暴力的になった奴もいたけど。政府はその状況を利用して戒厳令を敷こうとしたが、上手くいかず、あちこちで戦闘が発生してしまった。バラまいた薬物が変異源だったから、人々はゾンビに変わってしまったんだよ、。" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "その他の異変はどうなんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" +"それもきっと変異だろう。何を使ったのか知らないが、こんなありえないことをやってのけるなんて、科学は狂ってるな。水道に何を入れたのか知らないけど、知覚が少しおかしくなってる可能性もある。怪物も幻覚かもしれないな?ちょっと想定外だったし、今も信じられないけど、他に考えようがない。" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -171671,6 +173996,51 @@ msgid "" msgstr "" "大変な大騒ぎの中で、避難がずいぶん遅れてしまったんだ。街から出られなかったから、地下室でガールスカウトクッキーとか温いルートビアを飲んで数日間生き延びたよ。結局、に見つかることもなく逃げ出して、その後は放棄されたショッピングモールにしばらく立て籠もった。でも、食べ物が必要になったから、野外で暮らそうと森へ向かっていたんだ。野外生活は今一うまく行かなかったから、君に会えてほっとしているよ。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" +"よし、じゃあ、聞いてくれ。おかしいと思うかもしれないけど、、ゾンビに上手く対処できてるんだから、そういうのは放っておいていいんじゃないかな。ギリシャ神話は知ってる?" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "そんなに知らないな。それと何の関係が?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "ああ。どうしてそんな質問を?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" +"ああ、ええと、インディージョーンズのボツシナリオみたいに聞こえるかもしれないけど、きっと誰かがパンドラの箱を開けたんだ。もしくはそれに近いものをね。そしてその力を何かの用途に使おうとした。もしかしたら、上手くいくかもしれないと思って。そうだな、神々の力って単語は、なんだかクリーンエネルギーっぽいからな。その企てが失敗し、何かマズいものが解き放たれた。フィクションに出てくる比喩的な奴じゃなくて、本物のハデスの力を地球上にもたらしたんだ。ああ、現実離れした話ってことは分かってる。最初に言っただろ、放っておけって。" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "何?パンドラの箱?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" +"神話に出てくるんだ。パンドラが神々の家で封をされた箱を見つけて、中を調べてみようと考えた。彼女が箱を開けると、中から想像を絶する恐怖と病があふれ出した。聞いたことある展開だろ?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "なるほど、それがどう関係してくるんだ?" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -171719,6 +174089,137 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "詳しく教えてくれてありがとう。" +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" +"暴動やら何やらの原因は何だってことか?そうだな、中国の生物兵器だって話も聞いたが、こんな大掛かりなことをやってのける生物兵器を作れるとは思えない。バカみたいに聞こえるかもしれないが、私が思い付く説はただ一つ、宇宙人だ。" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "宇宙人の侵略だということか?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" +"多分、そうかも。でも、まともな侵略にしては無秩序すぎると思うんだ。これは想像だけど、北極の氷に何かが封印されていたんだ。数年前、氷の中から発見された宇宙人の死体がネットで話題になったのを覚えてるか?君はそこまで知らないかもしれないけど、しばらく話題になった後でデマだったことが判明した。ただ、その後私は、その死体に似た姿の宇宙人が歩いているところを目撃したんだ。きっと、デマって話は嘘で、隠蔽工作だったんだ。恐らく、宇宙人はウイルスのようなものをもっていたんだろう。世界中を巡って、静かに、あらゆるものを感染させたんだ。そして、どういう訳か今になってそれが活性化し、凶暴化や怪物化、変異を引き起こしているんだよ。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" +"包み隠さず話そう。私は最初、暴動に参加していた。あの時何を考えていたのか覚えていないんだ。それ以前も警察の残虐行為への抗議活動に参加したことはあるが、あれはそんなもんじゃない。看板を持って行進せずに、屋外でバットを振り回して何もかもぶっ壊すんだ。あんなに腹が立ったのは初めてだよ。暴動が始まってしばらく経っていた時期だったが、政府がまた市民を弾圧しようとしてるみたいに見えたんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "暴徒たちは気が狂ったに違いないという噂が出回っていた。" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "暴動に参加して無事に戻ってきた人はあまりいない。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" +"ああ、その通りだ。あの暴動は...人間のやることとは思えない。活動家とまではいかないが、今までに参加した抗議活動とは全く違うものだった。でも、止められなかったんだ。他の暴徒と同じくらい、酷いことをしたよ。窓を割り、傍観者を殴り、車を燃やした。警官から戦闘服を剥ぎ取って...もう止めよう。思い出したくないんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "どうやって生き残ったんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "何がきっかけで正気に戻ったんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" +"ある時、目が覚めたんだ。暴動鎮圧用のタレットを搭載した軍用車両が出てきた頃だったかな。そんな装備を初めて見たかどうかすら覚えていない精神状態だっだ。とにかく、それから銃声が聞こえて、気が付いたら重装備の軍用施設に突撃する暴徒の群れの端っこにいた。何が起きたのか確かめようと暴徒を見たら、あいつらが、野生動物、いや、ゾンビみたいな目つきをしていることに気づいた。すぐにその場を離れたよ。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" +"正直言って、分からないな。時間が経てば、他の暴徒も正気に戻ったんだろうか。私は何も特別じゃない。きっと他の奴らも目が覚めたけど、偶然にも群衆の端にいなかっただけだ。そして、私が正気に戻ったとたん、他の暴徒が私を獲物として見ていることに気づいた。その後何が起きるのか、確かめる気なんてなかったけどね。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" +"近辺の街のことはよく知っていた。廃墟になってる建物へ向かい、割れた窓から侵入して、数日間そこに籠ったよ。かなりの量の食料を盗んで、独り占めした。周囲が静まり返ってきたから、外へ出て、そしてここに来たんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" +"ああ、暴動に至るまでの経過は私も覚えているよ。悲惨な状態だった。酷い犯罪のニュースもあったし、警官の対処法が問題になって、いつものように人種問題でピリピリしていた。そして市民は暴動を始めたんだ。珍しいことじゃないけど、暴動が起きた場所が奇妙だったんだ。中流階級の住宅地や、中西部の小さな町とかな。まあともかく、私は暴動に加わった。その後のことはあまりはっきりとは覚えていないんだ。" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "暴動に参加したのか?" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "何が原因か、心当たりがあるようだな。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" +"そうだな。暴動は洗脳薬のせいだと言っている者もいるらしいが、率直に言って、的外れな説だとは思えない。実際にそんな感じだったんだ。意識がトんだって程ではなかったけど、目が覚めるまでは奇妙な感覚だった。でも、ゾンビや怪物は洗脳薬じゃ説明できない。原因を推測してはみたけど、悪魔の呪いとか、エイリアンの新兵器とか、下手なSFじみた話しか思いつかないな。" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -172002,15 +174503,52 @@ msgstr "" msgid "I can respect that." msgstr "もっともな意見だ。" +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "過去の話はあまりしたくないんだ、分かってくれないか?" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "漠然とした話でもいい、少しだけでも教えてもらえないか?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" +"ええと...ああ。水道水に麻薬か、生物兵器を混ぜたんじゃないかな。知ってのとおり、非難の的になっていたのは、中国だ。人々は醜く、暴力的にふるまった。暴動が始まり、親しい人々もそれに参加した。何故そんなことをするのか分からなかったよ。暴動は軍と警察を巻き込み、更に悪化した。暴徒だけじゃない、あらゆる人間が動物のようにふるまっていた。そして、本当のハルマゲドンが訪れたかのように怪物や悪魔が世界を闊歩するようになった。人間は死んで、モンスターになって蘇ったんだ。そういう話だろ。もっと知りたいなら、他の人に聞くんだな。" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "話してくれてありがとう。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" +"実は...まったく覚えていないんだ。世界がこんなことになる前の人生は、ぼんやりと思い出せる。でも、が訪れた時の事は?もやが掛かっているみたいだ。何か酷い目に遭ったに違いないとは思ってる。覚えていることは、暴力、赤ん坊を殺す女性。忘れた方がいい気がするな。" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" -"実は...まったく覚えていないんだ。世界がこんなことになる前の人生は、ぼんやりと思い出せる。でも、が訪れた時の事は?もやが掛かっているみたいだ。今いる場所も、何が起きたのかも分からない。どうやらかなりひどい目に遭ったみたいだ。それとも頭を強く打ったのかな。いや、その両方かも。" +"実は...まったく覚えていないんだ。世界がこんなことになる前の人生は、ぼんやりと思い出せる。でも、が訪れた時の事は?もやが掛かっているみたいだ。今いる場所も、何が起きたのかも分からない。どうやらかなりひどい目に遭ったみたいだ。それとも頭を強く打ったのかな。いや、その両方かも。その可能性が高そうだな。はっきりとした最初の記憶は、携帯電話に既読メールが入っていたことだ。政府の緊急放送システムから送られてきた奴で、アメリカは陥落したって書いてあった。" #: lang/json/talk_topic_from_json.py msgid "" @@ -172102,6 +174640,46 @@ msgid "" msgstr "" "おい。はっきり言ったはずだ。またしつこく聞くようなら怒るからな。かつての私は死んだ。消えたんだ。その下らない「健全」とかいう話は止めろ、、二度と言うな。" +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" +"何が原因かって聞いてるのか?ニュースでやってたろ。中国の生物兵器だよ。何年か前のパンデミックと同じだが、今回の対処は正しかった。いや、正し過ぎたかな。今となってはどうでもいいが、中国の本国にも伝染して、あっちも全滅だって聞いたよ。正義は成されたな。" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "実際に何があったのか、詳しく教えてもらえないか?" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "他のおかしな出来事はどうやって説明するんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" +"まあ、知ってのとおりさ。最初に水道に洗脳薬が混入され、暴動が起きた。その薬がウイルスだったって、今なら分かるね。軍と警察が必死になって制圧しようとしたが、手に負えなかった。それからウイルスが突然変異して、まるでB級映画のように死者を生き返らせ始めたんだ。そしてB級映画は現実になった。あのデカい怪物を中国が誤って逃がしたのか意図的に解き放ったのかは、分からない。名状しがたい巨大な怪物...あれのことを考えると今でも背筋が凍るよ。でも戦闘用じゃないのは確かだ。軍がすぐに倒してしまったからね。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" +"何?あれも同じさ。手法が生物兵器から核兵器になったんだ。水爆よりもっと酷い奴さ。アメリカはなんとかして鎮圧しようとしたけど、もう手遅れだったんだ。" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -172409,7 +174987,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "脱税だよ。会計士をしていたんだが、賢いやり方で上司が大金を動かすのを手伝ったんだ。いや、賢くはなかった。捕まったんだからな..." #: lang/json/talk_topic_from_json.py @@ -172594,6 +175172,34 @@ msgid "" msgstr "" "信仰を守り、祈り、地獄からの使いを見かけたら打ち倒す。私たちにできることなんて、それぐらいしか無いだろう?もしかしたら、地球を素直に明け渡してしまった方が楽なのかもしれない。でも、そんなのは癪だからな。" +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" +"明白じゃないか?あれは...携挙だ。私がまだ地上にいる、その理由は分からないが、私はどんな患難の中にあろうとイエスキリストを信じている。患難が過ぎ去れば、きっと私を天国に迎え入てくださるのだろう。まぁ...大筋はこんなところだと思っている。私が考えているとおりに事が運ぶとは限らないが、これは予言と言ってもいい。" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "もっと現実的な話かと思っていたよ。何が起きたんだ?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" +"えっ、ああ、私の記憶が確かなら、一連の出来事は黙示録の文章に沿っているんだ。牧師とはあまり話していないけどね。最初の災い...これは数年前の感染症の大流行だ。人々は終末が近いと言うようになった。次は血の災い、いや、暴力の災いだったかな?これが暴動を表してる。水が血に変わる、ってのが撃たれる人々だな。それから火の災い。暴動を封じ込めようとする中で爆弾なんかがあちこちで爆発していたのを覚えている。そして悪魔や怪物が地上を闊歩し、死者が墓から抜け出し、最後に柔和な人々がこの地を受け継ぐ。極めて明白だ。" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -172602,6 +175208,24 @@ msgid "" msgstr "" "他のみんなと同じさ。神様から目を背けて、その代償を支払ってるところだよ。携挙が訪れたけど、私は取り残された。そして今、地上の地獄を彷徨っているんだ。もっと真面目に日曜学校へ行っておけばよかったな。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" +"そうだな、これは携挙だったんだろう。思った通りには行かなかったけど。光が点滅するように、皆が*パッ*と居なくなるって聞いてたのに、滅茶苦茶の大混乱だ。通りでは暴動が発生し、軍と警察は反キリストの手先となって人々を殺して回る...これは父が言っていたんだけど、麦と殻を選り分けるって話が思い浮かばないか?私たちの真の罪が示された時、神は真の災いをお与えになる。死者が歩き始め、機関銃の弾痕を残したまま軍隊と戦う。軍でも内部で反乱が起き始める。そして、地獄の軍団が現れるんだ。巨大な怪物は想像以上に恐ろしい力をもっており、全てを引き裂き街を壊滅させた。軍も到着したがすぐに劣勢になり、私たちは死者から身を隠し逃げようとしたんだ。それから数日経って、停電が起きた。" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -172826,10 +175450,6 @@ msgstr "自由商人に雇われていた頃はどんな仕事をしていたん msgid "What was working for the Old Guard like?" msgstr "オールドガードに雇われていた頃はどんな仕事をしていたんだ?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "話してくれてありがとう。" - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "話してくれてありがとう。さあ行こうか。" @@ -173057,6 +175677,23 @@ msgstr "" msgid "What were you saying before that?" msgstr "前の話をもう一度聞かせてもらえないかな?" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" +"正直に言うと、結婚式の計画を立ててたから、現状に至る発端の出来事なんて気にしていなかったんだ。暴動が起きてることは知ってたが、住んでる街の外だったからね。近所で暴動があった時も、無視を決め込んでいた。ゾンビが現れてようやく、とてもおかしなことが起きてるって気づいたんだ。式場から逃げてる最中に、空が裂けて、裂け目からインデペンデンス・デイの宇宙人みたいな奴が飛び出してきた。まるで黒魔術の儀式か何かだったよ。" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "こんにちは。" @@ -173593,8 +176230,8 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "私の農場から立ち去った方がいい。政府の策略には乗らないよ。" #: lang/json/talk_topic_from_json.py -msgid "Go on..." -msgstr "何を話そうか..." +msgid "Go on…" +msgstr "続けて..." #: lang/json/talk_topic_from_json.py msgid "Is your forge operational?" @@ -174001,10 +176638,6 @@ msgid "" " catastrophe." msgstr "うちの土地から出て行け。政府はこの大災害で無能さを露呈したな。" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "何を話そうか..." - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "あなたの妻について聞きたい。近くにいるのか?" @@ -175468,11 +178101,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" -"気味が悪いだろ?ムダ毛みたいなものだ。大変動からしばらく経って、至る所から生え始めた。原因は分からない。嫌だからと言って怒っても仕方がない、まぁ、嫌だけど。" +"気味が悪いだろ?ムダ毛みたいなものだ。大変動からしばらく経って、体中に生え始めた。原因は分からない。嫌だからと言って怒っても仕方がない、まぁ、嫌だけど。" #: lang/json/talk_topic_from_json.py msgid "" @@ -176222,7 +178855,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -177332,12 +179965,12 @@ msgstr "どうやってここにたどり着いたんだ?" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" "ダナが妊娠していたから、2人で早めに避難したんだ。避難所に詰め込まれ、ここへ向かうバスに乗った。でも道中で巨大な化け物がバスを横転させて、ほとんどの避難者が死んだんだ。私たちは生き残った数人と一緒にここを目指し、たどり着いた。そんなに遠い道のりじゃなかったし、どういう訳か、化け物は私たちを狙わずバスを攻撃し続けていたからね。" @@ -177471,12 +180104,12 @@ msgstr "どうにか元気にやっている、と思いたいな。気にかけ #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" "長い、長い話だ。実はこの辺じゃなくて、カナダ西部の郊外から来た。ニューイングランドへは前から行きたいと思っていたから、休暇に出かけたんだ。私は確かに避難者だがアメリカ国民ではないので、階下へは連れて行ってもらえなかった。嫌な話だが、仕方ない。実を言うと、家族や友人の状況が分からなくて、何とかしようとしている最中なんだ。" @@ -177545,7 +180178,7 @@ msgid "Hm? Oh, hi." msgstr "うん?おや、どうも。" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "...やあ。" #: lang/json/talk_topic_from_json.py @@ -177923,10 +180556,10 @@ msgstr "そうしよう。どんな手を使って彼らに退去を認めさせ #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" -"いくら事態が片付いても、全員分のベッドも足りないし、物資も不十分だ。耐えるしかない。私たちもできる限りのことはしている...少なくとも避難場所は提供した。" +"いくら事態が片付いても、全員分のベッドは足りないし、物資も不十分だ。耐えるしかない。私たちもできる限りのことはしている...少なくとも避難場所は提供した。" #: lang/json/talk_topic_from_json.py msgid "" @@ -177943,9 +180576,9 @@ msgstr "その区画は何が不味いんだ?" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -178275,8 +180908,8 @@ msgid "" msgstr "お前のようなクズと話すことなんか無い、諦めて失せろ。" #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." -msgstr "私はここの担当者ではない。他を当たってくれ。" +msgid "I'm not in charge here, you're looking for someone else…" +msgstr "私はここの担当者ではない。他を当たってくれ..." #: lang/json/talk_topic_from_json.py msgid "Keep civil or I'll bring the pain." @@ -178323,11 +180956,11 @@ msgid "Well, I'd better be going. Bye." msgstr "ええと、そろそろ行くよ。さようなら。" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." +msgid "Welcome marshal…" msgstr "ようこそ、執行官..." #: lang/json/talk_topic_from_json.py -msgid "Welcome..." +msgid "Welcome…" msgstr "ようこそ..." #: lang/json/talk_topic_from_json.py @@ -178571,11 +181204,11 @@ msgstr "" "残念ながら、無理だ。農園へ行った人の大部分は上階で待機していた避難民だ。安全な寝床を待つよりもリスクが少ないからな。地下から出ていったのはほんの少しだし、元から混雑した状態だったからな。もっとたくさんの人が太陽や新鮮な空気、重労働を求めて牧場に向かってくれるといいが...知ってるだろうが、みんなゾンビの大群に襲われるのが怖いんだ。" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." +msgid "Marshal…" msgstr "執行官..." #: lang/json/talk_topic_from_json.py -msgid "Citizen..." +msgid "Citizen…" msgstr "市民..." #: lang/json/talk_topic_from_json.py @@ -179195,7 +181828,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" "現状だと、ガスマスク、スーツ、道具をセットで割引価格で売ってやるよ。うちで使ってるコイン2枚でどうだ。\n" "\n" @@ -179251,11 +181884,11 @@ msgstr "分かった。" #: lang/json/talk_topic_from_json.py msgid "Better keep our eyes on the road." -msgstr "" +msgstr "道中は注意しておいた方がいい。" #: lang/json/talk_topic_from_json.py msgid "Better be careful around here." -msgstr "" +msgstr "この辺は気を付けて行動した方がいい。" #: lang/json/talk_topic_from_json.py msgid "Yes?" @@ -179279,7 +181912,7 @@ msgstr "会えて嬉しいよ。" #: lang/json/talk_topic_from_json.py msgid "About those jobs…" -msgstr "" +msgstr "それらの仕事について..." #: lang/json/talk_topic_from_json.py msgid "Good to see you around." @@ -179291,7 +181924,7 @@ msgstr "何か手伝ってほしいことはある?" #: lang/json/talk_topic_from_json.py msgid "Lets set a combat strategy" -msgstr "" +msgstr "戦闘時の約束事を決めよう。" #: lang/json/talk_topic_from_json.py msgid "" @@ -179346,7 +181979,7 @@ msgstr "どうかした?" #: lang/json/talk_topic_from_json.py msgid "Want help with something?" -msgstr "" +msgstr "何か手伝おうか?" #: lang/json/talk_topic_from_json.py msgid "What do you know about our employers?" @@ -179391,15 +182024,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "その話を聞いて、確かに奇妙だと思えてきたよ。" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." +msgid "Thinking I should go hunt something soon…" msgstr "今から狩りにでも向かおうかと思案してるんだ..." #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "この世界がいつマトモになるのか考えてたんだ..." #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "うん?いいや、ただここで一休みするのが好きなんだ。" #: lang/json/talk_topic_from_json.py @@ -179439,7 +182072,7 @@ msgstr "大人しくしていろよ。" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." +"marshal…" msgstr "まだ外には無法者がうろついてる。執行官、あなたの仕事は多い..." #: lang/json/talk_topic_from_json.py @@ -179509,7 +182142,7 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "私が君の手伝いを必要とする状況ってのがちょっと想像できないな。" #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." +msgid "Stand still while I get my clippers…" msgstr "バリカンを使うからじっとしててくれ..." #: lang/json/talk_topic_from_json.py @@ -179891,7 +182524,7 @@ msgid "" msgstr "思うに、車両回収部隊はいつだって手伝いを必要としてるはずなんだが、連中は常に外にいるから、なかなか捕まらないんだよな。" #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." +msgid "Please leave me alone…" msgstr "ほっといてくれ..." #: lang/json/talk_topic_from_json.py @@ -179910,15 +182543,14 @@ msgstr "気の毒に。" #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." +"I don't know what you could do. I've tried everything. Just give me time…" msgstr "あんたに何が出来る。出来ることは自分で試したよ。ほっといてくれ..." #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." -msgstr "具合が悪いんだよ!何か悪いものを食ったんだと思うんだがとにかくゲロが止まらんのだ..." +"seems like I can't keep anything down…" +msgstr "具合が悪いんだよ!何か悪いものを食ったんだと思うんだが、とにかくゲロが止まらないんだ..." #: lang/json/talk_topic_from_json.py msgid "Uhm." @@ -180043,8 +182675,8 @@ msgstr "仲間に加わるのは止めておこう。" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "ここで?果物やベリー類だよ。他には農機具もあるが、購入には暗号通貨が必要だ。" #: lang/json/talk_topic_from_json.py @@ -180396,7 +183028,7 @@ msgstr "ようこそ。腹が減ったのか?" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "腹が減ってるようだな。この世は飢えに満ちている。捕食者たちの時代がやってきたんだ。" @@ -180569,7 +183201,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "捕食者たちのお役に立てて幸せだよ。指示に従おう。" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "素晴らしい。上手くやってくれよ。" #: lang/json/talk_topic_from_json.py @@ -180731,7 +183363,7 @@ msgid "Oh, you again." msgstr "ああ、またお前か。" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "あ?*モゴモゴ*...誰だ?" #: lang/json/talk_topic_from_json.py @@ -180739,7 +183371,7 @@ msgid "I'm busy, what is it?" msgstr "忙しいのだ、何か用か?" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "我が塔と我が研究を置いてか?そうはいかない。" #: lang/json/talk_topic_from_json.py @@ -182338,7 +184970,7 @@ msgstr "は%sに勢いよく切り込みました。" #: lang/json/technique_from_json.py msgid "Mordhau" -msgstr "" +msgstr "モルダウ" #: lang/json/technique_from_json.py #, python-format @@ -183590,17 +186222,17 @@ msgstr "大いなる天眼の一撃" #: lang/json/technique_from_json.py msgid "Spin Attack" -msgstr "スピンアタック" +msgstr "回転斬り" #: lang/json/technique_from_json.py #, python-format msgid "You unleash a spin attack against %s and those nearby" -msgstr "スピンアタックを放ち、周囲を巻き込みながら%sを攻撃しました。" +msgstr "回転斬りを放ち、周囲を巻き込みながら%sを攻撃しました。" #: lang/json/technique_from_json.py #, python-format msgid " unleashes a spin attack against %s and those nearby" -msgstr "はスピンアタックを放ち、周囲を巻き込みながら%sを攻撃しました。" +msgstr "は回転斬りを放ち、周囲を巻き込みながら%sを攻撃しました。" #: lang/json/technique_from_json.py msgid "Disarming Strike" @@ -183898,59 +186530,59 @@ msgstr "は周囲を巻き込みながら素早く%sを薙ぎ払いま #: lang/json/technique_from_json.py msgid "Mountain Hammer" -msgstr "" +msgstr "巨大鎚" #: lang/json/technique_from_json.py #, python-format msgid "You crush %s with the weight of your Mountain Hammer" -msgstr "" +msgstr "%sを押し潰しました。" #: lang/json/technique_from_json.py #, python-format msgid " crushes %s with the weight of their Mountain Hammer" -msgstr "" +msgstr "は%sを押し潰しました。" #: lang/json/technique_from_json.py msgid "Irrestistible Mountain Strike" -msgstr "" +msgstr "大嶽殺" #: lang/json/technique_from_json.py #, python-format msgid "You smash down on %s with a Mountain Strike" -msgstr "" +msgstr "%sを叩きのめし、押し潰しました。" #: lang/json/technique_from_json.py #, python-format msgid " smashes down on %s with a Mountain Strike" -msgstr "" +msgstr "は%sを叩きのめし、押し潰しました。" #: lang/json/technique_from_json.py msgid "Colossus Strike" -msgstr "" +msgstr "巨大な一撃" #: lang/json/technique_from_json.py #, python-format msgid "You completely shatter %s with a Colossus Strike" -msgstr "" +msgstr "%sを完璧に轢き潰す攻撃を繰り出しました。" #: lang/json/technique_from_json.py #, python-format msgid " completely shatters %s with a Colossus Strike" -msgstr "" +msgstr "は%sを完璧に轢き潰す攻撃を繰り出しました。" #: lang/json/technique_from_json.py msgid "Wolverine Stance" -msgstr "" +msgstr "イタチの構え" #: lang/json/technique_from_json.py #, python-format msgid "The %s tries to grab you, but you thrash your way to freedom!" -msgstr "" +msgstr "%sが掴みかかろうとしましたが、転げ回って自由になりました!" #: lang/json/technique_from_json.py #, python-format msgid "The %s tries to grab , but they thrash their way to freedom!" -msgstr "" +msgstr "は%sに掴まれそうになりましたが、転げ回って自由になりました!" #: lang/json/ter_furn_transform_messages_from_json.py msgid "The earth here does not listen to your command to move." @@ -184970,226 +187602,29 @@ msgid "" msgstr "金属製の手すりです。道路外への落下や侵入を防ぐために設置されています。" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "土" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "土です。耕作に適した土壌のようです。掘り返して建設準備を行うことも可能です。" - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "ゴツン" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "上手く掘り出せば色々なことに役立ちそうな細かい砂からなる地面です。" - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "泥" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "濡れて光沢を放つ泥です。" - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "粘土" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "柔らかい粘土からなる地面です。粘土を上手く掘り出せば、色々な使い道がありそうです。" - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "粘土の山" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "粘土質の土の山です。" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "バシャッ!" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "砂の山" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "砂の山です。" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "畝" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "土が盛り上がっており、乗り越えて移動するのに時間がかかりそうです。よく見ると種などを植えられそうです。" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "大きな土の山です。中を掘りぬけばシェルターになりそうです。" - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "奇妙な亀裂" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" -"この異様な人型の穴を、何故かよく知っているような気がします。これが自分の物であるような気がして、もっと近寄って見てみたいという奇妙な感覚になります。" - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "墓穴" +msgid "overgrown floor" +msgstr "床(繁茂した肉)" -#. ~ Description for grave +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "少し草が茂った、既に埋まっている墓穴です。少なくともここにいる死者は安らかに眠っています。" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" -"真新しい墓穴です。誰かが掘り返さないように、もしくは中からこじ開けられないように、石の蓋が置いてあります。2枚の板切れで、ここで誰かが永遠の休息を取っている事を示す印が形作られています。" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "床(岩石)" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "比較的平坦な岩石の床です。安定しており、適切な道具があれば掘削できそうです。" - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "道路" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." -msgstr "アスファルトの一部は氷結や整備不足からゆっくりとひび割れ、劣化し始めています。" - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "車線" - -#. ~ Description for yellow pavement -#: lang/json/terrain_from_json.py -msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" -"丁寧に並んだ黄色いペンキの縞模様は、運転者が道路をはみ出さないよう注意するために付けられた印です。こんなルールを強制する者はもう誰一人残っていません。" - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "歩道" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "公共区画に敷かれたコンクリートは氷結によって損傷し、整備不足のために大きなひびが入っています。" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "より美しく霜が付きにくい表面仕上げが施された、比較的新しい公共区画のコンクリートです。" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "より美しく霜が付きにくい表面仕上げが施された、比較的新しい公共区画のコンクリートです。黄色の塗料で縞模様が描かれています。" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "床(木)" - -#. ~ Description for wooden floor -#: lang/json/terrain_from_json.py -msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." -msgstr "木の板を隙間なく敷き詰めて釘で打ち付けた床です。テラスなどでよく見られます。" +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." +msgstr "剥き出しのコンクリート床は、繊毛を揺らめかせる灰色の肉に覆われています。" #: lang/json/terrain_from_json.py msgid "SMASH!" msgstr "ガシャン!" #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "床(金属)" +msgid "overgrown wall" +msgstr "壁(繁茂した肉)" -#. ~ Description for metal floor +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." -msgstr "頑丈で高品質な床材を使って転倒のリスクを軽減した格子模様の床です。" - -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "リノリウムタイル" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." -msgstr "ゴムのような丈夫な素材で作られた、シンプルな白色の床です。" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "ゴムのような丈夫な素材で作られた、灰色の床です。" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "床(土)" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." -msgstr "目の細かい土を押し固めて作った床です。" +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." +msgstr "コンクリートの床は、血管や瘤が生えたグロテスクな肉の網に覆われています。" #: lang/json/terrain_from_json.py msgid "concrete floor" @@ -185274,6 +187709,21 @@ msgid "" "smoothed and the roof isn't quite filled in yet." msgstr "鉄筋の間にコンクリートを注いだだけの未完成の状態です。表面は滑らかになっておらず、屋根も塞がれていない部分が残っています。" +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "床(岩石)" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "比較的平坦な岩石の床です。安定しており、適切な道具があれば掘削できそうです。" + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "床(金属)" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -185281,6 +187731,10 @@ msgid "" " with a matching roof." msgstr "硬い格子模様がついた高品質な床材を使って転倒のリスクを軽減した、屋根と揃いの床です。" +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "ゴツン" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "床" @@ -185323,6 +187777,10 @@ msgid "" "resistance and sliding, commonly for recreational sports." msgstr "表面に転倒を防止し滑らかさを改善する化学物質が塗られた、主にレクリエーションスポーツ用途で使われる硬材製フローリングです。" +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "床(土)" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -185405,28 +187863,15 @@ msgid "A blue section of flooring." msgstr "青色の床です。" #: lang/json/terrain_from_json.py -msgid "industrial carpet" -msgstr "絨毯(工業)" +msgid "carpet" +msgstr "絨毯" -#. ~ Description for industrial carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." -msgstr "剥き出しのコンクリート上に敷設するための、毛羽が少なく丈夫で衝撃に強い灰色の絨毯です。" +msgid "Base carpet!" +msgstr "カーペットのベースです!" -#: lang/json/terrain_from_json.py -msgid "bunker carpet" -msgstr "絨毯(掩体壕)" - -#. ~ Description for bunker carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." -msgstr "断熱層を備えた、毛羽が少なく丈夫で衝撃に強いクリーム色の絨毯です。" - -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "赤色の柔らかい絨毯です。" @@ -185446,6 +187891,124 @@ msgstr "緑色の柔らかい絨毯です。" msgid "Soft purple carpet." msgstr "紫色の柔らかい絨毯です。" +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "カーペット" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "コンクリート床上のカーペットのベースです!" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "絨毯(工業/赤)" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "剥き出しのコンクリート上に敷設するための、毛羽が少なく丈夫で衝撃に強い赤色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "絨毯(工業/黄)" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "剥き出しのコンクリート上に敷設するための、毛羽が少なく丈夫で衝撃に強い黄色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "絨毯(工業/緑)" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "剥き出しのコンクリート上に敷設するための、毛羽が少なく丈夫で衝撃に強い緑色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "絨毯(工業/紫)" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "剥き出しのコンクリート上に敷設するための、毛羽が少なく丈夫で衝撃に強い紫色の絨毯です。" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "金属床上のカーペットのベースです!" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "絨毯(掩体壕/赤)" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "断熱層を備えた、毛羽が少なく丈夫で衝撃に強い赤色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "絨毯(掩体壕/黄)" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "断熱層を備えた、毛羽が少なく丈夫で衝撃に強い黄色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "絨毯(掩体壕/緑)" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "断熱層を備えた、毛羽が少なく丈夫で衝撃に強い緑色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "絨毯(掩体壕/紫)" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "断熱層を備えた、毛羽が少なく丈夫で衝撃に強い紫色の絨毯です。" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "リノリウムタイル" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "ゴムのような丈夫な素材で作られた、シンプルな白色の床です。" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "ゴムのような丈夫な素材で作られた、灰色の床です。" + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "ワックスを塗った床" @@ -185481,6 +188044,33 @@ msgid "" msgstr "" "頑丈な骨組みにボルトとワイヤーで固定された廃金属製の壁です。ポストアポカリプス的なボロ家に良く似合う見た目をしています。トタン屋根に雨粒が当たる音が気にならないと良いのですが。" +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "土" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "土です。耕作に適した土壌のようです。掘り返して建設準備を行うことも可能です。" + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "上手く掘り出せば色々なことに役立ちそうな細かい砂からなる地面です。" + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "泥" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "濡れて光沢を放つ泥です。" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "苔" @@ -185490,6 +188080,30 @@ msgstr "苔" msgid "Moist spongy moss." msgstr "湿ったフワフワの苔です。" +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "粘土" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "柔らかい粘土からなる地面です。粘土を上手く掘り出せば、色々な使い道がありそうです。" + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "粘土の山" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "粘土質の土の山です。" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "バシャッ!" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "床(紙)" @@ -185499,6 +188113,134 @@ msgstr "床(紙)" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "粘着性のあるスズメバチの唾液で覆われた、パルプ状の物質で作られた床です。" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "砂の山" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "砂の山です。" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "畝" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "土が盛り上がっており、乗り越えて移動するのに時間がかかりそうです。よく見ると種などを植えられそうです。" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "大きな土の山です。中を掘りぬけばシェルターになりそうです。" + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "奇妙な亀裂" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" +"この異様な人型の穴を、何故かよく知っているような気がします。これが自分の物であるような気がして、もっと近寄って見てみたいという奇妙な感覚になります。" + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "墓穴" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "少し草が茂った、既に埋まっている墓穴です。少なくともここにいる死者は安らかに眠っています。" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" +"真新しい墓穴です。誰かが掘り返さないように、もしくは中からこじ開けられないように、石の蓋が置いてあります。2枚の板切れで、ここで誰かが永遠の休息を取っている事を示す印が形作られています。" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "道路" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr "アスファルトの一部は氷結や整備不足からゆっくりとひび割れ、劣化し始めています。" + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "車線" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "" +"丁寧に並んだ黄色いペンキの縞模様は、運転者が道路をはみ出さないよう注意するために付けられた印です。こんなルールを強制する者はもう誰一人残っていません。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "歩道" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "公共区画に敷かれたコンクリートは氷結によって損傷し、整備不足のために大きなひびが入っています。" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "より美しく霜が付きにくい表面仕上げが施された、比較的新しい公共区画のコンクリートです。" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "より美しく霜が付きにくい表面仕上げが施された、比較的新しい公共区画のコンクリートです。黄色の塗料で縞模様が描かれています。" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "床(木)" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "木の板を隙間なく敷き詰めて釘で打ち付けた床です。テラスなどでよく見られます。" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "頑丈で高品質な床材を使って転倒のリスクを軽減した格子模様の床です。" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "目の細かい土を押し固めて作った床です。" + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "クルミの木" @@ -186724,12 +189466,12 @@ msgstr "危ない!給油ポンプは壊れており、価値ある液体を汲 #. ~ Description for fuel tank #: lang/json/terrain_from_json.py msgid "A tank filled with diesel." -msgstr "" +msgstr "灯油を満載したタンクです。" #. ~ Description for broken fuel tank #: lang/json/terrain_from_json.py msgid "A broken tank which was filled with diesel." -msgstr "" +msgstr "灯油を満載した壊れたタンクです。" #: lang/json/terrain_from_json.py msgid "diesel pump" @@ -189329,6 +192071,78 @@ msgstr "上方に伸びた梯子です。" msgid "A ladder leading down." msgstr "下方に伸びた梯子です。" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "下り傾斜路(上端)" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "下へと続くアスファルト坂の上端です。" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "下り傾斜路(下端)" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "下へと続くアスファルト坂の下端です。" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "上り傾斜路(上端)" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "上へと続くアスファルト坂の上端です。" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "上り傾斜路(下端)" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "上へと続くアスファルト坂の下端です。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "下りスロープ(上端)" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "下へと続くアスファルト製スロープの上端です。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "下りスロープ(下端)" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "下へと続くアスファルト製スロープの下端です。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "上りスロープ(上端)" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "上へと続くアスファルト製スロープの上端です。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "上りスロープ(下端)" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "上へと続くアスファルト製スロープの下端です。" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "下り坂" @@ -189673,7 +192487,7 @@ msgstr "持ち上げ(セルフ)" #: lang/json/tool_quality_from_json.py msgid "siphoning" -msgstr "" +msgstr "抜取" #: lang/json/tool_quality_from_json.py msgid "chiseling" @@ -189822,7 +192636,7 @@ msgstr "ガチャンッ!" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "バァン!" @@ -189882,7 +192696,7 @@ msgstr "縦樋漏斗" #: lang/json/trap_from_json.py msgid "firewood source" -msgstr "焚木置き場" +msgstr "焚物置き場" #: lang/json/trap_from_json.py msgid "practice target" @@ -191237,7 +194051,7 @@ msgstr "車載/M249" #: lang/json/vehicle_part_from_json.py msgid "mounted M249S" -msgstr "" +msgstr "車載/M249S" #: lang/json/vehicle_part_from_json.py msgid "mounted gatling shotgun" @@ -191265,7 +194079,7 @@ msgstr "車載/M60" #: lang/json/vehicle_part_from_json.py msgid "mounted M60 Semi Auto" -msgstr "" +msgstr "車載/M60セミオート" #: lang/json/vehicle_part_from_json.py msgid "mounted Mark 19 grenade launcher" @@ -191642,7 +194456,7 @@ msgstr "ボートが浸水するのを防ぐ木製の板です。" #. ~ Description for {'str': 'raft boat hull'} #: lang/json/vehicle_part_from_json.py msgid "Logs tied together that will keep your boat out of the water." -msgstr "" +msgstr "丸太同士が水に浮くように繋がっています。" #. ~ Description for {'str': 'plastic boat hull'} #: lang/json/vehicle_part_from_json.py @@ -192087,7 +194901,7 @@ msgstr "非常に重い牽引ケーブルです。ケーブルのもう一方端 #: lang/json/vehicle_part_from_json.py msgid "flimsy wooden seat" -msgstr "" +msgstr "簡易座席(木)" #. ~ Description for {'str': 'flimsy wooden seat'} #. ~ Description for {'str': 'wooden seat'} @@ -192307,6 +195121,15 @@ msgid "" "extending the time until the food spoils." msgstr "容量60Lの冷蔵タンクです。電源を入れると中に入れた液体が冷え、日持ちするようになります。" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "自転車やバイクのホイールを取り付ける穴が付いた木製部品です。" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "木製ホイールハブ (転舵輪)" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "小型ホイールハブ (転舵輪)" @@ -192956,7 +195779,7 @@ msgstr "%sに達成" #: src/achievement.cpp #, c-format msgid "Failed %s" -msgstr "" +msgstr "%sに失敗しました" #: src/achievement.cpp msgid "" @@ -193145,8 +195968,9 @@ msgstr "解錠に失敗し、道具を少し壊してしまいました。" msgid "The lock stumps your efforts to pick it." msgstr "上手く鍵を開けられませんでした。" -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "騎乗中にその行動はできません。" @@ -193183,7 +196007,7 @@ msgstr "それはピッキングできません。" #: src/activity_actor.cpp msgid "" "You feel you should've fallen asleep by now, but somehow you're still awake." -msgstr "" +msgstr "さっき眠りに落ちたはずなのに、何故かまだ起きています。" #: src/activity_actor.cpp msgid "You toss and turn…" @@ -193191,7 +196015,7 @@ msgstr "寝返りを打ちました..." #: src/activity_actor.cpp msgid "You try to sleep, but can't." -msgstr "" +msgstr "眠ろうとしましたが眠れません。" #: src/activity_actor.cpp msgid "You have trouble sleeping, keep trying?" @@ -193209,6 +196033,120 @@ msgstr "睡眠" msgid "Continue trying to fall asleep and don't ask again." msgstr "睡眠(以降の中断警告を無視)" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "疲れ過ぎていて運動できません。" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "喉が渇き過ぎていて運動できません。" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "まず装備を外してください。" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "腕が折れていては訓練できません。" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -197767,6 +200705,29 @@ msgstr "%s(%iスロット)" msgid "Increased storage capacity by %i." msgstr "蓄電容量が%i増加しました。" +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "起動する電力量を選択" @@ -197933,8 +200894,9 @@ msgid "(incapacitated)" msgstr "(使用不可)" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" -msgstr "(節約ON)" +#, c-format +msgid "(fuel saving ON > %d %%)" +msgstr "" #: src/bionics_ui.cpp #, c-format @@ -198007,7 +200969,7 @@ msgstr "命中" #: src/bonuses.cpp msgid "Critical Hit Chance" -msgstr "" +msgstr "会心発生率" #: src/bonuses.cpp src/martialarts.cpp msgid "Dodge" @@ -198617,6 +201579,23 @@ msgstr "はクモの巣を払って、自由になりました!" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "クモの巣を払おうとしましたが、上手く払えませんでした!" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "" + +#: src/character.cpp +msgid " frees themselves!" +msgstr "" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "穴からの脱出を試みましたが、滑り落ちてしまいました。" @@ -198902,7 +201881,7 @@ msgstr "潤喉 *" #: src/character.cpp msgid "Satisfied" -msgstr "" +msgstr "満足" #: src/character.cpp msgid "Hungry" @@ -198926,7 +201905,7 @@ msgstr "空腹 ***" #: src/character.cpp msgid "ERROR!" -msgstr "" +msgstr "エラー!" #: src/character.cpp src/npctalk.cpp msgid "Exhausted" @@ -199470,6 +202449,10 @@ msgstr "EXTRA_EXERCISE" msgid "Your body strains under the weight!" msgstr "身体が重荷に悲鳴を上げました。" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -199865,7 +202848,7 @@ msgstr "友好NPCはこの区域内から発生する正体不明の音のみを #: src/clzones.cpp msgid "Source: Firewood" -msgstr "供給: 焚き木" +msgstr "供給: 焚物" #: src/clzones.cpp msgid "" @@ -199873,7 +202856,7 @@ msgid "" " automatically refuel fires. This will be done to maintain light during " "long-running tasks such as crafting, reading or waiting." msgstr "" -"印を付けたタイルに置かれている焚き木など可燃物は、火の中へ自動的に補給されます。製作や読書などの長時間の作業時には、火を絶やさないよう自動補給機能が働きますが、火の傍でただ立っているだけの時などは、自動補給は行われません。" +"印を付けたタイルに置かれている木材などの可燃物は、火の中へ自動的に補給されます。製作や読書などの長時間の作業時には、火を絶やさないよう自動補給機能が働きますが、火の傍でただ立っているだけの時などは、自動補給は行われません。" #: src/clzones.cpp msgid "Construction: Blueprint" @@ -203628,19 +206611,6 @@ msgstr "" "屋内: %s\n" "屋根: %s" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" -"視認: %d\n" -"回避: %d\n" -"難易度: %d\n" -"無害: %s" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -204346,12 +207316,12 @@ msgstr "伝説的" #: src/faction.cpp msgctxt "Faction respect" msgid "Unchallenged" -msgstr "無名" +msgstr "傑出" #: src/faction.cpp msgctxt "Faction respect" msgid "Mighty" -msgstr "強大" +msgstr "高名" #: src/faction.cpp msgctxt "Faction respect" @@ -204361,12 +207331,12 @@ msgstr "有名" #: src/faction.cpp msgctxt "Faction respect" msgid "Well-Known" -msgstr "有名" +msgstr "名うて" #: src/faction.cpp msgctxt "Faction respect" msgid "Spoken Of" -msgstr "語り草" +msgstr "風の噂" #: src/faction.cpp msgctxt "Faction respect" @@ -204381,22 +207351,22 @@ msgstr "虫けら" #: src/faction.cpp msgctxt "Faction respect" msgid "Despicable" -msgstr "卑賤" +msgstr "軽蔑" #: src/faction.cpp msgctxt "Faction respect" msgid "Parasite" -msgstr "寄生虫" +msgstr "厄介者" #: src/faction.cpp msgctxt "Faction respect" msgid "Leech" -msgstr "腰巾着" +msgstr "取り巻き" #: src/faction.cpp msgctxt "Faction respect" msgid "Laughingstock" -msgstr "笑い者" +msgstr "軽視" #: src/faction.cpp msgctxt "Faction respect" @@ -204406,7 +207376,7 @@ msgstr "中立的" #: src/faction.cpp msgctxt "Faction wealth" msgid "Filthy rich" -msgstr "守銭奴" +msgstr "大富豪" #: src/faction.cpp msgctxt "Faction wealth" @@ -204421,7 +207391,7 @@ msgstr "潤沢" #: src/faction.cpp msgctxt "Faction wealth" msgid "Well-Off" -msgstr "余裕がある" +msgstr "余裕" #: src/faction.cpp msgctxt "Faction wealth" @@ -204431,32 +207401,32 @@ msgstr "快適" #: src/faction.cpp msgctxt "Faction wealth" msgid "Wanting" -msgstr "物足りない" +msgstr "不足ぎみ" #: src/faction.cpp msgctxt "Faction wealth" msgid "Failing" -msgstr "破綻傾向" +msgstr "貧乏" #: src/faction.cpp msgctxt "Faction wealth" msgid "Impoverished" -msgstr "不毛" +msgstr "困窮" #: src/faction.cpp msgctxt "Faction wealth" msgid "Destitute" -msgstr "貧困" +msgstr "絶望的" #: src/faction.cpp msgctxt "Faction food" msgid "Overflowing" -msgstr "有り余る" +msgstr "豊穣" #: src/faction.cpp msgctxt "Faction food" msgid "Well-Stocked" -msgstr "余裕がある" +msgstr "万全" #: src/faction.cpp msgctxt "Faction food" @@ -204506,17 +207476,17 @@ msgstr "訓練不足" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Crippled" -msgstr "烏合の衆" +msgstr "未熟" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Feeble" -msgstr "脆弱" +msgstr "ド素人" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Worthless" -msgstr "一銭の価値もない" +msgstr "無価値" #: src/faction.cpp msgid "Press enter to rename this camp" @@ -206548,7 +209518,7 @@ msgstr "実績「%s」を取得しました。" #: src/game.cpp #, c-format msgid "You lost the conduct \"%s\"." -msgstr "" +msgstr "「%s」の制約を破りました。" #: src/game.cpp src/options.cpp #, c-format @@ -206741,7 +209711,7 @@ msgstr "開ける" #: src/game.cpp msgctxt "action" msgid "pocket autopickup settings" -msgstr "" +msgstr "ポケット自動拾得設定" #: src/game.cpp msgctxt "action" @@ -207220,46 +210190,46 @@ msgstr "火力が強すぎて、どれほど長く燃え続けるか予測でき #: src/game.cpp msgid "It's going to go out soon without extra fuel." -msgstr "焚き木を追加しなければすぐに消えてしまいそうです。" +msgstr "焚物を追加しなければすぐに消えてしまいそうです。" #: src/game.cpp #, c-format msgid "" "Without extra fuel it might burn yet for maybe %s, but might also go out " "sooner." -msgstr "%sは燃え続けそうですが、焚き木を追加しなければすぐに消えてしまいます。" +msgstr "%sは燃え続けそうですが、焚物を追加しなければすぐに消えてしまいます。" #: src/game.cpp #, c-format msgid "" "Without extra fuel it might burn yet for between %s to %s, but might also go" " out sooner." -msgstr "%sから%sは燃え続けそうですが、焚き木を追加しなければすぐに消えてしまいます。" +msgstr "%sから%sは燃え続けそうですが、焚物を追加しなければすぐに消えてしまいます。" #: src/game.cpp msgid "" "It's quite decent and looks like it'll burn for a bit without extra fuel." -msgstr "十分な火力があり、焚き木を追加しなくても少しは燃え続けそうです。" +msgstr "十分な火力があり、焚物を追加しなくても少しは燃え続けそうです。" #: src/game.cpp msgid "It looks solid, and will burn for a few hours without extra fuel." -msgstr "十分な火力があり、焚き木を追加しなくても数時間は燃え続けそうです。" +msgstr "十分な火力があり、焚物を追加しなくても数時間は燃え続けそうです。" #: src/game.cpp msgid "" "It's very well supplied and even without extra fuel might burn for at least " "a part of a day." -msgstr "焚き木が十分にくべられており、そのままでも1日は燃え続けそうです。" +msgstr "焚物が十分にくべられており、そのままでも1日は燃え続けそうです。" #: src/game.cpp #, c-format msgid "Without extra fuel it will burn for about %s." -msgstr "焚き木を追加しなくても%sは燃え続けそうです。" +msgstr "焚物を追加しなくても%sは燃え続けそうです。" #: src/game.cpp #, c-format msgid "Without extra fuel it will burn for between %s to %s." -msgstr "焚き木を追加しなくても%sから%sは燃え続けそうです。" +msgstr "焚物を追加しなくても%sから%sは燃え続けそうです。" #: src/game.cpp msgid "You cannot interact with a vehicle while mounted." @@ -207375,16 +210345,16 @@ msgstr "視界外" #: src/game.cpp #, c-format msgid "Cover: %d%%" -msgstr "" +msgstr "遮蔽率: %d%%" #: src/game.cpp msgid "Impassable" -msgstr "" +msgstr "通行不可" #: src/game.cpp #, c-format msgid "Move cost: %d" -msgstr "" +msgstr "移動コスト: %d" #: src/game.cpp #, c-format @@ -207412,7 +210382,7 @@ msgstr "未完成のタスク: %s(%d%%)" #: src/game.cpp msgid "Vehicle: " -msgstr "" +msgstr "車両: " #: src/game.cpp msgid "You cannot see what is inside of it." @@ -207827,6 +210797,10 @@ msgstr "装填するアイテムがありません。" msgid "You aren't holding something you can reload." msgstr "装填できるものを所持していません。" +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -208271,7 +211245,7 @@ msgstr "%sが邪魔です!" #: src/game.cpp #, c-format msgid "%s Attempt to push past? You may have to fight your way back up." -msgstr "" +msgstr "%s押し退けますか?戦闘が発生する可能性があります。" #: src/game.cpp msgid "" @@ -208980,7 +211954,7 @@ msgstr "コスト" #: src/game_inventory.cpp msgid "WIELD COST" -msgstr "" +msgstr "装備コスト" #: src/game_inventory.cpp msgid "Wield item" @@ -209769,7 +212743,7 @@ msgstr "この車両は飛び辛そうです。" #: src/handle_action.cpp msgid "This vehicle cannot be flown without z levels." -msgstr "" +msgstr "この車両はZ軸拡張がないと飛行できません。" #: src/handle_action.cpp msgid "You steer the vehicle into a descent." @@ -210379,6 +213353,10 @@ msgstr "レーザー照準を無視しました!" msgid "Creature whitelisted: %s" msgstr "ホワイトリストに登録: %s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "自殺しますか?" @@ -211733,11 +214711,28 @@ msgstr "%sは見るからに危険です。あまり近寄らないようにし msgid "There is a %s there. Take down?" msgstr "%sがあります。片付けますか?" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "%sは取り外されました。" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "%sがあります。解除しますか?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "罠を解除しました!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "罠の解除に失敗しました。" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "罠の解除に失敗し、作動させてしまいました!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -211841,17 +214836,17 @@ msgstr "文盲なので、画面に表示された文章を読めません。" #: src/iexamine.cpp #, c-format msgid "Failure! No %s pumps found!" -msgstr "" +msgstr "失敗しました!%sポンプが見当たりません!" #: src/iexamine.cpp #, c-format msgid "Failure! No %s tank found!" -msgstr "" +msgstr "失敗しました!%sタンクが見当たりません!" #: src/iexamine.cpp #, c-format msgid "This station is out of %s. We apologize for the inconvenience." -msgstr "" +msgstr "当ガソリンスタンドは%sの在庫が不足しています。ご不便をお掛けして申し訳ございません。" #: src/iexamine.cpp msgid "Welcome to AutoGas!" @@ -211864,7 +214859,7 @@ msgstr "御用は何ですか?" #: src/iexamine.cpp #, c-format msgid "Buy %s." -msgstr "" +msgstr "%sの購入" #: src/iexamine.cpp msgid "Refund cash." @@ -211873,12 +214868,12 @@ msgstr "現金の払い戻し" #: src/iexamine.cpp #, c-format msgid "Current %s pump: " -msgstr "" +msgstr "現在の%sポンプ: " #: src/iexamine.cpp #, c-format msgid "Choose a %s pump." -msgstr "" +msgstr "%sポンプの変更" #: src/iexamine.cpp msgid "Your discount: " @@ -211887,7 +214882,7 @@ msgstr "割引: " #: src/iexamine.cpp #, c-format msgid "Your price per %s unit: " -msgstr "" +msgstr "%s価格(単位): " #: src/iexamine.cpp msgid "Hack console." @@ -211896,7 +214891,7 @@ msgstr "コンソールをハッキングしました。" #: src/iexamine.cpp #, c-format msgid "Please choose %s pump:" -msgstr "" +msgstr "%sポンプの選択: " #: src/iexamine.cpp msgid "Pump " @@ -211909,7 +214904,7 @@ msgstr "お金が足りません、キャッシュカードにお金を補充し #: src/iexamine.cpp #, c-format msgid "How many liters of %s to buy? Max: %d L. (0 to cancel)" -msgstr "" +msgstr "%sを何リットル購入しますか?最大: %dL(0で取消) " #: src/iexamine.cpp msgid "Glug Glug Glug" @@ -212029,7 +215024,7 @@ msgstr "患者は死亡しています。続行するには死体を除去して msgid "" "ERROR Bionic Level Assessment: FULL CYBORG. Autodoc Mk. XI can't operate. " "Please move patient to appropriate facility. Exiting." -msgstr "" +msgstr "生体レベル評価エラー: 完全機械化済。オートドクMk.XIは未対応です。患者を適切な装置に移してください。操作を終了します。" #: src/iexamine.cpp msgid "Autodoc Mk. XI. Status: Online. Please choose operation." @@ -212113,7 +215108,7 @@ msgstr "骨折箇所を固定する" #: src/iexamine.cpp msgid "Treat wounds" -msgstr "" +msgstr "傷を治療する" #: src/iexamine.cpp msgid "You don't have any bionics installed." @@ -212143,11 +215138,11 @@ msgstr "%1$sに固定が必要な四肢はありません。" #: src/iexamine.cpp msgid "You don't have any wounds that need treatment." -msgstr "" +msgstr "治療な必要な傷はありません。" #: src/iexamine.cpp msgid " doesn't have any wounds that need treatment." -msgstr "" +msgstr "に治療が必要な傷はありません。" #: src/iexamine.cpp msgid "" @@ -212155,6 +215150,7 @@ msgid "" "detected you've already taken antibiotics, it decided not to apply another " "dose right now." msgstr "" +"オートドクは身体が細菌に感染していることを検出しました。しかし、既に抗生物質を服用していることも検出したため、今すぐ再治療する必要はないと判断しました。" #: src/iexamine.cpp msgid "" @@ -212162,18 +215158,19 @@ msgid "" "also detected you've already taken antibiotics, it decided not to apply " "another dose right now." msgstr "" +"オートドクはの身体が細菌に感染していることを検出しました。しかし、既に抗生物質を服用していることも検出したため、今すぐ再治療する必要はないと判断しました。" #: src/iexamine.cpp msgid "" "The autodoc detected a bacterial infection in your body and injected " "antibiotics to treat it." -msgstr "" +msgstr "オートドクは身体が細菌に感染していることを検出し、抗生物質を注射しました。" #: src/iexamine.cpp msgid "" "The autodoc detected a bacterial infection in 's body and injected " "antibiotics to treat it." -msgstr "" +msgstr "オートドクはの身体が細菌に感染していることを検出し、抗生物質を注射しました。" #: src/iexamine.cpp src/iuse.cpp msgid "The muscle spasms start to go away." @@ -212188,28 +215185,28 @@ msgstr "発作に効く薬ではないようです。" msgid "" "The autodoc detected a bleeding on your %s and applied a hemostatic drug to " "stop it." -msgstr "" +msgstr "オートドクは%sからの出血を検出し、止血剤を塗布して治療しました。" #: src/iexamine.cpp #, c-format msgid "" "The autodoc detected a bleeding on 's %s and applied a hemostatic " "drug to stop it." -msgstr "" +msgstr "オートドクはの%sからの出血を検出し、止血剤を塗布して治療しました。" #: src/iexamine.cpp #, c-format msgid "" "The autodoc detected an open wound on your %s and applied a disinfectant to " "clean it." -msgstr "" +msgstr "オートドクは%sに傷口を検出し、消毒薬を塗布して治療しました。" #: src/iexamine.cpp #, c-format msgid "" "The autodoc detected an open wound on 's %s and applied a " "disinfectant to clean it." -msgstr "" +msgstr "オートドクはの%sに傷口を検出し、消毒薬を塗布して治療しました。" #: src/iexamine.cpp #, c-format @@ -212606,6 +215603,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr "は%sのレシピを知らないため、製作を続けられません。" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "" + #: src/init.cpp msgid "Finalizing" msgstr "最終処理中" @@ -213507,7 +216509,7 @@ msgstr "分量: " #: src/item.cpp msgid "Consume time: " -msgstr "" +msgstr "消費所要時間:" #: src/item.cpp msgid "* Consuming this item is addicting." @@ -213611,7 +216613,7 @@ msgid "" msgstr "" "この食べ物は腐敗が始まっています。食べるのは避けるべきです。" -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -214321,31 +217323,31 @@ msgstr "* この道具はCBM電力で作動します。" #: src/item.cpp msgid "It's new, and ready to burn." -msgstr "" +msgstr "まだ燃えていません。すぐに火がつきます。" #: src/item.cpp msgid "Almost new, with much material to burn." -msgstr "" +msgstr "ほとんど燃えていません。燃える素材は十分残っています。" #: src/item.cpp msgid "More than a quarter has burned away." -msgstr "" +msgstr "4分の1以上が燃え尽きました。" #: src/item.cpp msgid "More than half has burned away." -msgstr "" +msgstr "半分以上が燃え尽きました。" #: src/item.cpp msgid "Less than a quarter left to burn." -msgstr "" +msgstr "燃える素材はもう4分の1も残っていません。" #: src/item.cpp msgid "Almost completely burned out." -msgstr "" +msgstr "ほぼ完全に燃え尽きました。" #: src/item.cpp msgid "Fuel: " -msgstr "" +msgstr "焚物: " #: src/item.cpp #, c-format @@ -214375,6 +217377,8 @@ msgstr "* このアイテムは修復不可能です。" #, c-format msgid "Disassembly takes %1$s and might yield: %2$s." msgstr "" +"分解所要時間: %1$s\n" +"分解結果: %2$s" #. ~ 1 is approx. time, 2 is a list of items and tools with qualities, 3 is a #. list of items. @@ -214386,6 +217390,9 @@ msgid "" "Disassembly takes %1$s, requires %2$s and might " "yield: %3$s." msgstr "" +"分解所要時間: %1$s\n" +"必要: %2$s\n" +"分解結果:%3$s" #: src/item.cpp #, c-format @@ -215226,77 +218233,83 @@ msgstr "どの動作を実行しますか?" #: src/item_contents.cpp #, c-format msgid "Press a key to add to %s" -msgstr "" +msgstr "%s追加モード" #: src/item_contents.cpp msgid "blacklist" -msgstr "" +msgstr "ブラックリスト" #: src/item_contents.cpp msgid "whitelist" -msgstr "" +msgstr "ホワイトリスト" #: src/item_contents.cpp msgid " priority, " -msgstr "" +msgstr "優先度、" #: src/item_contents.cpp msgid " item, " -msgstr "" +msgstr "アイテム、" #: src/item_contents.cpp msgid " category, " -msgstr "" +msgstr "分類、" #: src/item_contents.cpp msgid " whitelist, " -msgstr "" +msgstr "ホワイトリスト、" #: src/item_contents.cpp msgid " blacklist" -msgstr "" +msgstr "ブラックリスト" #: src/item_contents.cpp #, c-format msgid "Enter Priority (current priority %d)" -msgstr "" +msgstr "優先度を入力(現在: %d)" #: src/item_contents.cpp msgid "item id" -msgstr "" +msgstr "アイテムID" #: src/item_contents.cpp msgid "item category" -msgstr "" +msgstr "アイテム分類" #: src/item_contents.cpp msgid "Select an item from nearby" -msgstr "" +msgstr "付近のアイテムを選択" #: src/item_contents.cpp msgid "is not a container" msgstr "は容器ではない" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "" + #: src/item_contents.cpp msgid "is not rigid" msgstr "には剛性がない" #: src/item_contents.cpp msgid "Total capacity:" -msgstr "" +msgstr "総容量:" #: src/item_contents.cpp src/item_pocket.cpp msgid " Weight: " -msgstr "" +msgstr "重量: " #: src/item_contents.cpp #, c-format msgid "%d Pockets with capacity:" -msgstr "" +msgstr "%d個のポケット:" #: src/item_contents.cpp msgid "Pocket with capacity:" -msgstr "" +msgstr "ポケット:" #: src/item_factory.cpp msgid "" @@ -215341,23 +218354,27 @@ msgid "Pocket %d:" msgstr "ポケット%d:" #: src/item_pocket.cpp -msgid "Maximum item length: " +msgid "Holds: " msgstr "" +#: src/item_pocket.cpp +msgid "Maximum item length: " +msgstr "最大長: " + #: src/item_pocket.cpp #, c-format msgid "Minimum item volume: %s" -msgstr "" +msgstr "最小容量: %s" #: src/item_pocket.cpp #, c-format msgid "Maximum item volume: %s" -msgstr "" +msgstr "最大容量: %s" #: src/item_pocket.cpp #, c-format msgid "Base moves to remove item: %d" -msgstr "" +msgstr "取出基本コスト: %d" #: src/item_pocket.cpp msgid "This pocket is rigid." @@ -215396,7 +218413,7 @@ msgstr "収納されたアイテムは元の重量の%.0f%% msgid "" "This pocket expands at %.0f%% of the rate of volume of " "items inside." -msgstr "" +msgstr "このポケットは体積が内部アイテムの%.0f%%分増加します。" #: src/item_pocket.cpp #, c-format @@ -215430,7 +218447,7 @@ msgstr "MOD以外は収納できない" #: src/item_pocket.cpp msgid "holster does not accept this item type" -msgstr "" +msgstr "ホルスターはこのアイテムを収納できません" #: src/item_pocket.cpp msgid "holster already contains an item" @@ -215502,31 +218519,31 @@ msgstr "容積が足りない" #: src/item_pocket.cpp msgid "Priority:" -msgstr "" +msgstr "優先度:" #: src/item_pocket.cpp #, c-format msgid "Item Whitelist: %s" -msgstr "" +msgstr "アイテムホワイトリスト: %s" #: src/item_pocket.cpp msgid "(empty)" -msgstr "" +msgstr "(空)" #: src/item_pocket.cpp #, c-format msgid "Item Blacklist: %s" -msgstr "" +msgstr "アイテムブラックリスト: %s" #: src/item_pocket.cpp #, c-format msgid "Category Whitelist: %s" -msgstr "" +msgstr "分類ホワイトリスト: %s" #: src/item_pocket.cpp #, c-format msgid "Category Blacklist: %s" -msgstr "" +msgstr "分類ブラックリスト: %s" #: src/itype.h msgid "click." @@ -217126,10 +220143,6 @@ msgstr "スネーク" msgid "Sokoban" msgstr "倉庫番" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "マインスイーパー" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "ライツオン!" @@ -219250,12 +222263,12 @@ msgstr[0] "%1$dの%2$sを%3$sに装填しました。" #: src/iuse_actor.cpp #, c-format msgid "You deploy the %s wrong. It is hostile!" -msgstr "" +msgstr "設定を間違えたようです。%sは敵対化しました!" #: src/iuse_actor.cpp #, c-format msgid "You deploy the %s." -msgstr "" +msgstr "%sを設置しました。" #: src/iuse_actor.cpp msgid "Place npc where?" @@ -219644,7 +222657,7 @@ msgstr "呪文: " #: src/iuse_actor.cpp msgid "You can't read." -msgstr "" +msgstr "読めません。" #: src/iuse_actor.cpp #, c-format @@ -220012,7 +223025,7 @@ msgstr "%sは%sに隣接している必要があります。" msgid "You can't place a %s there. It contains a trap already." msgstr "そこには%sを設置できません。既に罠があります。" -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "%sを作動させました!" @@ -221121,6 +224134,7 @@ msgid "" " they are kitten or not. The game ends when robot finds kitten. " "Alternatively, you may end the game by hitting %s." msgstr "" +"ゲームの目的は子猫を見つけることです。しかし様々な子猫以外の存在がこのゲームを複雑にしています。ロボットはそれが子猫であるか否か、触れなければ判別できません。ロボットが子猫を見つけたらゲームクリアです。途中で終了する場合は%sを押してください。" #: src/iuse_software_kitten.cpp msgid "Press any key to start." @@ -221129,12 +224143,12 @@ msgstr "始めるには何かキーを押して下さい。" #: src/iuse_software_kitten.cpp #, c-format msgid "robotfindskitten v22July2008 - press %s to quit." -msgstr "" +msgstr "robotfindskitten v22July2008 - %s で終了" #: src/iuse_software_kitten.cpp #, c-format msgid "Invalid command: Use direction keys or press %s to quit." -msgstr "" +msgstr "無効なコマンド:方向キーを使うか、%sを押して終了して下さい。" #: src/iuse_software_kitten.cpp msgid "You found kitten! Way to go, robot!" @@ -221764,6 +224778,15 @@ msgstr "生成" msgid "Summon" msgstr "召喚" +#: src/magic.cpp +msgid "random creature" +msgstr "" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "射程" @@ -221784,6 +224807,10 @@ msgstr "効果範囲" msgid "Spawned" msgstr "生成" +#: src/magic.cpp +msgid "Threshold" +msgstr "" + #: src/magic.cpp msgid "Recover" msgstr "回復" @@ -221836,6 +224863,15 @@ msgstr "ダメージは既に均等です。" msgid "%s wounds are closing up!" msgstr "%sの傷が塞がっていきます!" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "そこには既に車両があります。" @@ -222293,30 +225329,23 @@ msgstr "%sのオートクレーブが滅菌を完了しました。" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "%sは取り外されました。" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "罠を解除しました!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "罠の解除に失敗しました。" +msgid "Something has crawled out of the %s plants!" +msgstr "%sから何かが這い出しました!" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "罠の解除に失敗し、作動させてしまいました!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "%sから何かが這い出しました!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "%sから何かが這い出しました!" +msgid "You've spotted a %1$ss!" +msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "%sから何かが這い出しました!" +msgid " triggers a %s!" +msgstr "" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -223859,6 +226888,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "警察に指名手配されました!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -226630,7 +229672,7 @@ msgstr "見られている気がします。嫌な気分です。" #: src/monattack.cpp msgid "Your sight darkens as the visions overtake you!" -msgstr "" +msgstr "目の前が真っ暗になり、何も見えません!" #: src/monattack.cpp #, c-format @@ -227709,6 +230751,11 @@ msgstr "視認できない敵からの射撃を検出し、撃ち返しモード msgid "zombie slave" msgstr "奴隷ゾンビ" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "%sを押し退ける" + #: src/monexamine.cpp msgid "Rename" msgstr "改名する" @@ -228264,11 +231311,11 @@ msgstr "瀕死" #: src/monster.cpp msgid "Can see to your current location" -msgstr "" +msgstr "現在地から視認できます。" #: src/monster.cpp msgid "Can't see to your current location" -msgstr "" +msgstr "現在地から視認できません。" #: src/monster.cpp #, c-format @@ -229622,7 +232669,7 @@ msgstr "開始/手足の負傷" #: src/newcharacter.cpp msgid "Fungal infected player" -msgstr "" +msgstr "真菌感染" #: src/newcharacter.cpp msgid "No starting NPC" @@ -229924,11 +232971,11 @@ msgstr "%1$sが何か言っていますが聴こえません!" #: src/npc.cpp msgid "Aware of your presence" -msgstr "" +msgstr "あなたを知覚しています。" #: src/npc.cpp msgid "Unaware of you" -msgstr "" +msgstr "あなたを知覚していません。" #: src/npc.cpp msgid "Completely untrusting" @@ -231433,11 +234480,11 @@ msgstr "隣接破壊" #: src/options.cpp msgid "Pulp Adjacent Zombie Only" -msgstr "" +msgstr "隣接ゾンビのみ死体破壊" #: src/options.cpp msgid "Pulp Zombies Only" -msgstr "" +msgstr "ゾンビのみ死体破壊" #: src/options.cpp msgid "Auto mining" @@ -232437,13 +235484,13 @@ msgstr "使用したいタイルセットを選択します。" #: src/options.cpp msgid "Memory map overlay preset" -msgstr "" +msgstr "記憶マップ/描画色" #: src/options.cpp msgid "" "Specified the overlay in which the memory map is drawn. Requires restart. " "For custom overlay define gamma and RGB values for dark and light colors." -msgstr "" +msgstr "記憶マップの描画色を指定します。反映には再起動が必要です。カスタムに設定すると、暗色と明色のガンマ値とRGB値を指定できます。" #: src/options.cpp msgid "Darkened" @@ -232455,67 +235502,67 @@ msgstr "セピア" #: src/options.cpp msgid "Sepia Dark" -msgstr "" +msgstr "ダークセピア" #: src/options.cpp msgid "Blue Dark" -msgstr "" +msgstr "ダークブルー" #: src/options.cpp msgid "Custom dark color RGB overlay - RED" -msgstr "" +msgstr "暗色RGB値 - レッド" #: src/options.cpp msgid "Specify RGB value for color RED for dark color overlay." -msgstr "" +msgstr "暗色のレッドの値を指定します。" #: src/options.cpp msgid "Custom dark color RGB overlay - GREEN" -msgstr "" +msgstr "暗色RGB値 - グリーン" #: src/options.cpp msgid "Specify RGB value for color GREEN for dark color overlay." -msgstr "" +msgstr "暗色のグリーンの値を指定します。" #: src/options.cpp msgid "Custom dark color RGB overlay - BLUE" -msgstr "" +msgstr "暗色RGB値 - ブルー" #: src/options.cpp msgid "Specify RGB value for color BLUE for dark color overlay." -msgstr "" +msgstr "暗色のブルーの値を指定します。" #: src/options.cpp msgid "Custom bright color RGB overlay - RED" -msgstr "" +msgstr "明色RGB値 - レッド" #: src/options.cpp msgid "Specify RGB value for color RED for bright color overlay." -msgstr "" +msgstr "明色のレッドの値を指定します。" #: src/options.cpp msgid "Custom bright color RGB overlay - GREEN" -msgstr "" +msgstr "明色RGB値 - グリーン" #: src/options.cpp msgid "Specify RGB value for color GREEN for bright color overlay." -msgstr "" +msgstr "明色のグリーンの値を指定します。" #: src/options.cpp msgid "Custom bright color RGB overlay - BLUE" -msgstr "" +msgstr "明色RGB値 - ブルー" #: src/options.cpp msgid "Specify RGB value for color BLUE for bright color overlay." -msgstr "" +msgstr "明色のブルーの値を指定します。" #: src/options.cpp msgid "Custom gamma for overlay" -msgstr "" +msgstr "ガンマ値" #: src/options.cpp msgid "Specify gamma value for overlay." -msgstr "" +msgstr "描画色のガンマ値を指定します。" #: src/options.cpp msgid "Pixel minimap" @@ -232975,18 +236022,6 @@ msgstr "放射線で変異" msgid "If true, radiation causes the player to mutate." msgstr "Trueにすると放射線の影響で突然変異を引き起こします。" -#: src/options.cpp -msgid "Z-levels" -msgstr "Z軸拡張" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" -"trueにすると、階段を使って上階にアイテムを移動したり、雨樋をよじ登ったり、飛行機を飛ばしたりといった、垂直方向の移動に関連するいくつかの機能が有効化されます。ゲームの途中で変更すると問題が発生する可能性があります。" - #: src/options.cpp msgid "Character point pools" msgstr "ポイント割り振り" @@ -234994,7 +238029,7 @@ msgstr "%sに修理すべき故障は見当たりません。" #: src/player.cpp msgid "It is damaged, but cannot be repaired." -msgstr "" +msgstr "損傷していますが修復が可能です。" #: src/player.cpp #, c-format @@ -235292,7 +238327,7 @@ msgstr "この作業は%sスキルをレベル%d以上に上昇させるには #: src/player.cpp msgid " (empty)" -msgstr "" +msgstr "(空)" #: src/player.cpp msgid "Wield what?" @@ -235357,7 +238392,7 @@ msgstr "水泳コスト: %+d\n" #: src/player_display.cpp #, c-format msgid "Movement point cost: %+d\n" -msgstr "" +msgstr "移動コスト: %+d\n" #: src/player_display.cpp #, c-format @@ -235748,7 +238783,7 @@ msgstr "前の分類に切替" #: src/player_display.cpp msgid "Toggle skill training / Upgrade stat" -msgstr "" +msgstr "切替/スキル鍛錬・能力値上昇" #: src/player_hardcoded_effects.cpp msgid "You feel nauseous." @@ -236822,7 +239857,7 @@ msgstr[0] "%1$d個の%2$sレベル%3$d以上の工具" #, c-format msgid "%1$d tool with %2$s of %3$d or more" msgid_plural "%1$d tools with %2$s of %3$d or more" -msgstr[0] "" +msgstr[0] "%1$d個の%2$s性能%3$d以上の道具" #. ~ %1$s: tool name, %2$d: charge requirement #: src/requirements.cpp @@ -237051,15 +240086,15 @@ msgstr "限定" #: src/scores_ui.cpp msgid "achievements" -msgstr "" +msgstr "実績" #: src/scores_ui.cpp msgid "conducts" -msgstr "" +msgstr "制約" #: src/scores_ui.cpp msgid "Conducts" -msgstr "" +msgstr "制約" #: src/scores_ui.cpp #, c-format @@ -237068,18 +240103,20 @@ msgid "" "the debug menu to work around a game bug, then you can re-enable %s via the " "debug menu (\"Enable achievements\" under the \"Game\" submenu)." msgstr "" +"%sは恐らくデバッグメニュー使用が原因で無効化されています。デバッグメニューをゲームのバグ回避のみに使用した場合は、%sをデバッグメニューから再度有効化できます(サブメニュー[ゲーム]内の[有効化" +" - 実績]を選択)。" #: src/scores_ui.cpp #, c-format msgid "This game has no valid %s.\n" -msgstr "" +msgstr "有効な%sがありません。\n" #: src/scores_ui.cpp #, c-format msgid "" "Note that only %s that existed when you started this game and still exist " "now will appear here." -msgstr "" +msgstr "ゲーム開始時に存在し現在も存在する%sのみが表示されます。" #: src/scores_ui.cpp msgid "This game has no valid scores.\n" @@ -237099,7 +240136,7 @@ msgstr "実績" #: src/scores_ui.cpp msgid "CONDUCTS" -msgstr "" +msgstr "制約" #: src/scores_ui.cpp msgid "SCORES" @@ -237702,6 +240739,19 @@ msgctxt "grammatical gender list" msgid "n" msgstr "n" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" +"視認: %d\n" +"回避: %d\n" +"難易度: %d\n" +"無害: %s" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "気泡シートを踏みました!" @@ -238439,7 +241489,7 @@ msgstr "運転中は部品を取り付けられません。" msgid "" "Installing this part will mean that this vehicle is no longer flightworthy." " Continue?" -msgstr "" +msgstr "この部品を取り付けると、車両が飛行できなくなります。続けますか?" #: src/veh_interact.cpp msgid "Installing this part will make the vehicle unfoldable. Continue?" @@ -238477,11 +241527,11 @@ msgstr "この車両は修復できません\n" msgid "" "Repairing this part will mean that this vehicle is no longer flightworthy. " "Continue?" -msgstr "" +msgstr "この部品を修復すると、車両が飛行できなくなります。続けますか?" #: src/veh_interact.cpp msgid "You chose not to install this part to keep the vehicle flyable.\n" -msgstr "" +msgstr "部品の取り付けを中止しました。車両は飛行可能です。\n" #: src/veh_interact.cpp msgid "Your morale is too low to mend…" @@ -238639,7 +241689,7 @@ msgstr "運転中には何も取り外さない方が良いでしょう。" msgid "" "Removing this part will mean that this vehicle is no longer flightworthy. " "Continue?" -msgstr "" +msgstr "この部品を取り外すと、車両が飛行できなくなります。続けますか?" #: src/veh_interact.cpp msgid "The vehicle has no liquid fuel left to siphon." @@ -240872,7 +243922,7 @@ msgstr "--利用可能なMODはありません--" #: src/worldfactory.cpp msgid "--NO RESULTS FOUND--" -msgstr "" +msgstr "--結果が見つかりません--" #: src/worldfactory.cpp msgid "Saved list of active mods as default" diff --git a/lang/po/pl.po b/lang/po/pl.po index 35e0b6c2bdefd..9562b8c324906 100644 --- a/lang/po/pl.po +++ b/lang/po/pl.po @@ -7,17 +7,17 @@ # Artur Gromek , 2019 # Zgroza Zgroza , 2019 # Ewa Cichosz , 2020 -# Brett Dong , 2020 # Unibel , 2020 # Chris Bittner , 2020 # Millennium Falcon , 2020 +# Brett Dong , 2020 # Aleksander Sienkiewicz , 2020 # msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: Aleksander Sienkiewicz , 2020\n" "Language-Team: Polish (https://www.transifex.com/cataclysm-dda-translators/teams/2217/pl/)\n" @@ -1065,6 +1065,19 @@ msgstr[3] "nitrox" msgid "Mixture of oxygen and nitrogen in proportions suitable for diving." msgstr "Mieszanka tlenu i azotu w proporcjach odpowiednich do nurkowania." +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -5471,6 +5484,26 @@ msgstr "" "Silna, rozpylana amunicja owadobójcza do miotacza chemikaliów. Najlepiej " "stosować z maską lub ochroną jamy ustnej." +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -6804,7 +6837,7 @@ msgstr[3] "żółta farba" msgid "A can of yellow paint." msgstr "Puszka żółtej farby." -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "" @@ -9257,7 +9290,7 @@ msgstr[3] "" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." +"rockets will not fit. Use insert to store ammunition." msgstr "" #: lang/json/ARMOR_from_json.py @@ -9379,11 +9412,9 @@ msgstr[3] "kołczan" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." msgstr "" -"Skórzany kołczan noszony na pasie, w którym zmieści się 20 strzał. Aktywuj " -"by schować w nim strzały." #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -9397,10 +9428,8 @@ msgstr[3] "kołczan z brzozy" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." +"20 arrows or bolts. Use insert to store arrows or bolts." msgstr "" -"Duży kołczan ze zszytych ze sobą płatów kory brzozowej, noszony na biodrze, " -"który pomieści 20 strzał. Aktywuj by schować w nim strzały." #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -9414,13 +9443,10 @@ msgstr[3] "duży kołczan" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" -"Duży skórzany kołczan z metalowymi wykończeniami, zakładany na plecy, który " -"mieści 60 strzał. Historycznie wykorzystywany przez konnych łuczników, " -"rzadziej piechotę, ale oni nie walczyli z zombie. Aktywuj by schować w nim " -"strzały." #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -9434,10 +9460,8 @@ msgstr[3] "duży kołczan z brzozy" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." +"hold 60 arrows or bolts. Use insert to store arrows or bolts." msgstr "" -"Duży kołczan ze zszytych ze sobą płatów kory brzozowej, noszony na plecach, " -"który pomieści 60 strzał. Aktywuj by schować w nim strzały." #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -21713,13 +21737,10 @@ msgstr "" #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." msgstr "" -"Średnich rozmiarów walizka do przewozu ubrań i innych rzeczy w podróży, " -"zapewnia przyzwoitą ilość miejsca, ale taszczenie jej ze sobą nie jest zbyt " -"wygodne." #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -36473,6 +36494,21 @@ msgid "" "your pain at bay." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -38313,6 +38349,22 @@ msgid "" "on combining magic with EM radiation." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -44950,6 +45002,36 @@ msgstr "" "Solone czipsy z kukurydzianej tortilli z mielonym mięsem i zatopione w " "serze. Doskonałe." +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "" + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -50925,30 +51007,64 @@ msgstr "" "dla małych ptaków." #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "psie żarcie" -msgstr[1] "psie żarcie" -msgstr[2] "psie żarcie" -msgstr[3] "psie żarcie" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'wet dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." -msgstr "To żarcie dla psów. Dziwnie pachnie, ale psom wydaje się smakować." +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str_sp': 'dry dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +#. ~ Description for {'str_sp': 'wet cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "kocie żarcie" -msgstr[1] "kocie żarcie" -msgstr[2] "kocie żarcie" -msgstr[3] "kocie żarcie" +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." +msgstr "" -#. ~ Description for {'str_sp': 'cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." -msgstr "To żarcie dla kotów. Dziwnie pachnie, ale kotom wydaje się smakować." +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str_sp': 'dry cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -59132,6 +59248,38 @@ msgstr "" "Filcowe łaty, ciasno zwinięte dla łatwiejszego przechowywania. Rozłóż by " "rozpakować." +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -64284,6 +64432,66 @@ msgid "" "wound." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -66412,7 +66620,7 @@ msgstr[3] "" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "" #: lang/json/GENERIC_from_json.py @@ -66636,6 +66844,22 @@ msgid "" "anything on its own." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -68942,6 +69166,124 @@ msgid "" "somewhat warm to the touch." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -72880,6 +73222,19 @@ msgstr "" "Metalowy kran który może być przyłączony do zbiornika z wodą dla łatwego " "dostępu." +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "" + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -79709,6 +80064,38 @@ msgid "" "thrower." msgstr "" +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "" + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -80884,6 +81271,55 @@ msgid "" "able to give them back some humanity. If only they cared…" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -81161,6 +81597,25 @@ msgid "" "appears to have a mininuke inside. If this is targeting you… Run." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -83451,6 +83906,23 @@ msgstr "" "pokonywać ogromne odległości długimi skokami, łapiąc swą zdobycz swymi " "śmiercionośnymi pazurami zanim zada ostateczny cios swymi ogromnymi kłami." +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -86170,6 +86642,22 @@ msgstr[3] "" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -86274,6 +86762,81 @@ msgid "" "looking for patient to assist." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" +"Ten niegdysiejszy pies zrzucił całą skórę ujawniając pancerz połączonych " +"kości i żeber. Ta kościana zbroja pozbawiona z zewnątrz ciała wygląda na " +"poruszaną siecią niezdrowo czarnych żył i ścięgien ociekających czarną " +"mazią." + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -86406,27 +86969,6 @@ msgstr "" "Zdeformowane zwierzęce psie ciało, łykowata bestia która z łatwością " "przegoni swoich dwunożnych kolegów." -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" -"Ten niegdysiejszy pies zrzucił całą skórę ujawniając pancerz połączonych " -"kości i żeber. Ta kościana zbroja pozbawiona z zewnątrz ciała wygląda na " -"poruszaną siecią niezdrowo czarnych żył i ścięgien ociekających czarną " -"mazią." - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -86566,6 +87108,36 @@ msgstr "" "Puma, która wyglądałaby normalnie gdyby nie spuchnięte zadnie nogi i " "wybałuszone od czarnego szlamu oczy." +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -87268,6 +87840,52 @@ msgstr "" msgid "The impaler launches a barb!" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -89965,22 +90583,6 @@ msgid "" " black eyes, and a tattered sail on its back." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -89994,37 +90596,6 @@ msgstr[3] "" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "" - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -90149,22 +90720,6 @@ msgid "" "sickle-like claw." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -90226,6 +90781,400 @@ msgid "" "like a frill." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -90761,6 +91710,21 @@ msgid "" "off creatures that disturb it." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -91521,6 +92485,14 @@ msgstr "" msgid "a bird" msgstr "" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "" + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "" @@ -92394,6 +93366,17 @@ msgid "" "rune as a catalyst for recipes." msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "" @@ -92616,6 +93599,15 @@ msgstr "" msgid "Uses a little fatigue" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "" @@ -93042,6 +94034,10 @@ msgstr "" msgid "Haste" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "" @@ -97563,6 +98559,21 @@ msgstr[1] "bioniczne zapalarki" msgstr[2] "bioniczne zapalarki" msgstr[3] "bioniczne zapalarki" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -97648,7 +98659,7 @@ msgstr[3] "" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "Lekkie" @@ -100727,12 +101738,6 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -103480,16 +104485,39 @@ msgstr[1] "rzucana gaśnica" msgstr[2] "rzucana gaśnica" msgstr[3] "rzucana gaśnica" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "" + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." +msgstr "" + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" msgstr "" -"To gaśnica w formie granatu. Nie tak efektywna jak zwykła gaśnica, ale można" -" jej użyć na dystans. Jest aktywowana ogniem, więc po prostu rzuć nią w " -"płomienie." #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -111233,7 +112261,7 @@ msgid "Pheidippides was a hack" msgstr "" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "" #: lang/json/achievement_from_json.py @@ -111300,6 +112328,592 @@ msgstr "" msgid "Return to the location you started the game" msgstr "" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "Drwal" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "Doktor Medycyny" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "Traperka" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "" + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "Saper" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "Krawcowa" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "Surwiwalistka" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "Żołnierz" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "Włamywaczka" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "" + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "" @@ -111752,6 +113366,11 @@ msgstr "" msgid "canceling activity serialized with legacy code" msgstr "" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "pakiet fuzyjny" @@ -112056,6 +113675,10 @@ msgstr "rozpylane chemikalium" msgid "compressed air" msgstr "skompresowane powietrze" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "" @@ -114157,6 +115780,62 @@ msgstr "" msgid "Merciful" msgstr "" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -114790,10 +116469,6 @@ msgstr "Pomaluj Ścianę na Żółto" msgid "Take Paint Off Wall" msgstr "Zdrap Farbę ze Ściany" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "Usuń Wykładzinę" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "Połóż Czerwoną Wykładzinę" @@ -114834,6 +116509,30 @@ msgstr "" msgid "Mine Upstair" msgstr "Przekopuj w Górę" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "Rozpocznij Budowę Pojazdu" @@ -117945,7 +119644,7 @@ msgstr "Sztachnąłeś raz czy dwa." msgid "You smoked too much." msgstr "Za dużo wypaliłeś." -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "Odlot" @@ -120008,6 +121707,18 @@ msgstr "ogień" msgid "raging fire" msgstr "szalejący ogień" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "przestarzały gruz" @@ -121031,8 +122742,7 @@ msgid "" msgstr "" #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "krasz!" @@ -121204,7 +122914,7 @@ msgid "" msgstr "" #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "crunch!" @@ -121845,9 +123555,8 @@ msgstr "maszyna do ćwiczeń" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." msgstr "" #: lang/json/furniture_from_json.py @@ -121936,6 +123645,18 @@ msgid "" " to be scavanged." msgstr "" +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "" + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "bieżnia" @@ -121948,6 +123669,18 @@ msgid "" "you're probably getting enough cardio on your own." msgstr "" +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "ciężki worek treningowy" @@ -123237,10 +124970,6 @@ msgstr "" msgid "filled arc furnace" msgstr "" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "ruszt wędzarniczy" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -123999,7 +125728,8 @@ msgstr "Fałszywa spluwa strzelająca globulkami kwasu." msgid "auto" msgstr "automatyczny" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "karabin" @@ -124229,8 +125959,8 @@ msgstr "" "wynalezionego w połowie 21-go wieku. Jest niewiele więcej niż elektroniką " "oklejoną taśma montażową, pracującą na zasilaniu z UPS-a." -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "pistolet" @@ -124311,7 +126041,7 @@ msgstr "" "Wielostrzałowy pneumatyczny karabin zrobiony domowym sposobem ze złomu. Jest" " bardzo cichy i zabójczy." -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "półautomatyczny" @@ -124911,8 +126641,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" +msgid "MAS .223" +msgid_plural "MAS .223" msgstr[0] "" msgstr[1] "" msgstr[2] "" @@ -127821,8 +129551,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" msgstr[0] "" msgstr[1] "" msgstr[2] "" @@ -127830,8 +129560,8 @@ msgstr[3] "" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " @@ -127978,6 +129708,43 @@ msgstr "" "lufami strzelby. Historycznie używana przez myśliwych egomaniaków w Afryce, " "a obecnie przez ich spadkobierców egomaniaków w Nowej Anglii." +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -128591,8 +130358,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" msgstr[0] "" msgstr[1] "" msgstr[2] "" @@ -129489,6 +131256,30 @@ msgstr[3] "" msgid "Bionic one-shot subdermal .40 pistol integrated with your head." msgstr "" +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "" + #: lang/json/gun_from_json.py msgid "CRIT .5 LP" msgid_plural "CRIT .5 LPs" @@ -130386,14 +132177,6 @@ msgid "" "reliability." msgstr "" -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -132818,6 +134601,12 @@ msgstr "" "Przeszukujesz te pozostałości nieudanego eksperymentu w poszukiwaniu " "dających się wykorzystać bionicznych części" +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -134862,10 +136651,6 @@ msgstr "Napisz coś" msgid "Teleport yourself" msgstr "Teleportuj się" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "Zgaś ogień" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "Osusz/oczyść siebie" @@ -136208,6 +137993,14 @@ msgstr "Wyjdź z ekranu nowej postaci" msgid "Toggle sorting order" msgstr "Przełącz kolejność sortowania" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "Przewiń opis w górę" @@ -136608,6 +138401,10 @@ msgstr "Rozmontuj Przedmioty" msgid "Sleep" msgstr "Śpij" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "Kontroluj Pojazd" @@ -137081,12 +138878,12 @@ msgstr "Wczytaj szablon kolorów" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "Tak" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "Nie" @@ -142502,7 +144299,7 @@ msgstr "" msgid "There is always work to be done, song to be woven." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -142510,16 +144307,16 @@ msgid "" " you." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -143841,7 +145638,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "" #: lang/json/mission_def_from_json.py @@ -143850,7 +145647,7 @@ msgid "" msgstr "" #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." +msgid "Well, you're not dead… yet." msgstr "" #: lang/json/mission_def_from_json.py @@ -156013,8 +157810,7 @@ msgstr "Arachnid" msgid "Well, maybe you'll just have to make your own world wide web." msgstr "Cóż, może czas upleść sieć wielką jak kiedyś sieć internetowa." -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "Ocalony" @@ -156378,10 +158174,6 @@ msgid "" "you." msgstr "" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "Doktor Medycyny" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -156787,11 +158579,29 @@ msgid "" msgstr "" #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "Historia Ocalonego" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgid "Survivor: Confused 1" +msgstr "" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -156799,6 +158609,86 @@ msgstr "Historia Ocalonego" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "Historia Ocalonego" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "" @@ -158623,10 +160513,6 @@ msgstr "Próbuję tylko przeżyć." msgid "I'm tracking game." msgstr "Obserwuję grę." -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "Żołnierz" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "Barman" @@ -159376,10 +161262,6 @@ msgstr "Złomiarz" msgid "Laborer" msgstr "Robotnik" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "Drwal" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "Stolarz" @@ -161923,6 +163805,18 @@ msgstr "droga, studzienka" msgid "bridge" msgstr "most" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "przystanek przy drodze" @@ -177747,109 +179641,6 @@ msgstr "Nie pamiętam kiedy po raz ostatni aż tak chciało mi się pić." msgid "I'd kill for a sip of water right now." msgstr "Zabiłbym dla łyka wody." -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "" -"Tak, pewnie, nie dało się nie zauważyć, że masz ze sobą piwo! Wypijmy po " -"jednym i pogadajmy, , jak leci?" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "" -"O, z całą pewnością, co powiesz na piwko, które widzę przy tobie? Co " -"porabiasz?" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "" -"Podzielisz się piwkiem, które tam chomikujesz i możemy gadać ile dusza " -"zapragnie! Tylko żartowałem, co tam ?" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "" -"Hej , założę się że rozmowa byłaby o wiele gładsza z fajnym zimnym " -"piwkiem w garści. Jak leci?" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "" -"Jak tu sobie gadamy, to co powiesz żebyśmy otworzyli sobie po piwku i przez " -"chwilę... udawali, że świat się nie kończy?" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "" -"Hej, jasna sprawa, , i tak przyda mis się chwila przerwy, jak się " -"miewasz?" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "No pewnie, , jak leci?" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "Pewnie, ognia ze wszystkich działonów! Wszystko u ciebie OK?" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "Czemu nie? Jak leci?" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "Mi pasuje, co nowego?" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "Kilka minut mi nie zaszkodzi, jak się miewasz?" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "Jasna sprawa , wszystko w porząsiu?" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "Pewnie, leży ci coś na sercu?" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "Zawsze gotów na dobrą pogawędkę! Ale co tam, wszystko ok?" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "OK , poznajmy się bliżej, jak się miewasz?" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "Z całą pewnością, jestem cały twój? Trzymasz się tam?" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "" -"Dobry pomysł . Zapomnijmy na chwilę o świecie. Jak się miewasz?" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "A co mi tam. Jak tam życie?" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "Pewnie. No więc, jak tam pogoda, co?" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "kurde" @@ -180319,6 +182110,18 @@ msgstr "Powiedz mi, jak przeżyłeś pierwszą falę Kataklizmu?" msgid "Was it rough surviving thus far?" msgstr "Ciężko było przetrwać tak długo?" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -181054,6 +182857,301 @@ msgstr "nie będzie rozpoczynał walki jeśli może jej uniknąć." msgid " will follow normal engagement rules." msgstr "będzie podążał zwykłymi zasadami zawiązywania walki." +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "Mi pasuje, co nowego?" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "Jasna sprawa , wszystko w porząsiu?" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "Pewnie, leży ci coś na sercu?" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "Zawsze gotów na dobrą pogawędkę! Ale co tam, wszystko ok?" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -182377,6 +184475,14 @@ msgstr "" "bezłuskowej amunicji. Napis głosi: \"RivTech bezłuskowa 8x40mm. Nic się z " "nią nie równa.\"" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -182386,6 +184492,21 @@ msgid "" " reads: \"WE ARE HERE TO PROTECT YOU.\"" msgstr "" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -194260,11 +196381,11 @@ msgid "Acolyte." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" +msgid "You're back. Have you come to listen to the song?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" +msgid "You there. Quiet down. Can you hear it? The song?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -194299,8 +196420,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -194313,11 +196434,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" @@ -194335,11 +196456,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" #: lang/json/talk_topic_from_json.py @@ -194348,7 +196469,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "" @@ -194362,10 +196483,10 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" #: lang/json/talk_topic_from_json.py @@ -194375,7 +196496,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" @@ -194391,8 +196512,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" @@ -194402,9 +196523,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" #: lang/json/talk_topic_from_json.py @@ -194462,14 +196583,6 @@ msgstr "" msgid "Perhaps another time, Seer." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "" @@ -194478,10 +196591,6 @@ msgstr "" msgid "Not interested." msgstr "Nie zgłaszam zainteresowania." -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "" @@ -194498,20 +196607,13 @@ msgstr "" msgid "I'm off then." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "" @@ -194522,7 +196624,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "" #: lang/json/talk_topic_from_json.py @@ -194537,11 +196639,6 @@ msgstr "" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "" @@ -194553,24 +196650,15 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." -msgstr "" -"Nie tylko chodzące horrory i potwory zmieniły się wraz z Kataklizmem. " -"Rozpoczęło to… swego rodzaju cykl. Wszystko się powtarza. Widzimy to tylko u" -" innych, ale przytrafia się i nam, nawet tobie, również i mnie. Ile razy " -"upadłeś? Twoje ciało wyrwane z twojego ciała, pożarte. A może było to ciche " -"skomlenie śmierci. Lecz twoje kości znów się podniosły. Inne ciało, inna " -"nazwa, czasem nawet inna wiedza, ale kości, te same. Wszyscy jesteśmy " -"uwięzieni w tym samym cyklu. Po prostu zapominamy. Dlatego musimy akumulować" -" pieśń. To musi się skończyć, nawet jeśli oznacza to zniszczenie, a nie " -"przywrócenie." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" @@ -194596,6 +196684,14 @@ msgstr "Zapomnij, że pytałem." msgid "Skip it, let's get going." msgstr "Olej to, chodźmy." +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "Jakieś wskazówki na temat świata w którym teraz żyjemy?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "Porozmawiajmy o obozach frakcji." + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "" @@ -194781,7 +196877,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -194946,8 +197042,8 @@ msgstr "Cześć, ." #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -194969,7 +197065,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -195021,8 +197117,8 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." -msgstr "Nie, po prostu nie..." +msgid "No, just no…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Just let me sleep, !" @@ -195033,8 +197129,8 @@ msgid "Make it quick, I want to go back to sleep." msgstr "Tylko szybko, chcę spać." #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." -msgstr "Jeszcze kilka minut..." +msgid "Just few minutes more…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Anything to do before I go to sleep?" @@ -195079,6 +197175,68 @@ msgstr "Chcę dać ci kilka poleceń do walki." msgid "I want to set some miscellaneous rules." msgstr "Chcę ustalić różne zasady." +#: lang/json/talk_topic_from_json.py +msgid "I'd like to know a bit more about your abilities." +msgstr "Chciałbym dowiedzieć się nieco więcej o twoich umiejętnościach." + +#: lang/json/talk_topic_from_json.py +msgid "There's something I want you to do." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I just wanted to talk for a bit." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you help me understand something? (HELP/TUTORIAL)" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I'm going to go my own way for a while." +msgstr "Pójdę na razie własną drogą." + +#: lang/json/talk_topic_from_json.py +msgid "Let's go." +msgstr "Idziemy." + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what did you want to say?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Mind if we just chat for a bit about your history?" +msgstr "Masz coś przeciwko, aby porozmawiać o twojej historii?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's just chitchat for a while, I could use some relaxation." +msgstr "Po prostu pogadajmy przez chwilę, przydałby mi się relaks." + +#: lang/json/talk_topic_from_json.py +msgid "I changed my mind, wanted to ask you something else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I'm all ears, my friend." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You gonna give me orders?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What would you like?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Just say the word." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Can you teach me anything?" msgstr "Możesz mnie czegoś nauczyć?" @@ -195103,14 +197261,6 @@ msgstr "Stój tu na straży." msgid "I want to assign you to work at this camp." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." -msgstr "Porozmawiajmy o twojej obecnej aktywności." - -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "Porozmawiajmy o obozach frakcji." - #: lang/json/talk_topic_from_json.py msgid "Find a horse and mount up!" msgstr "Znajdź konia i go dosiądź!" @@ -195124,32 +197274,20 @@ msgid "Please go to this location." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." -msgstr "Chciałbym dowiedzieć się nieco więcej o twoich umiejętnościach." - -#: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" -msgstr "Jakieś wskazówki na temat świata w którym teraz żyjemy?" - -#: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" -msgstr "Masz coś przeciwko, aby porozmawiać o twojej historii?" - -#: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." -msgstr "Po prostu pogadajmy przez chwilę, przydałby mi się relaks." +msgid "I want you to build a camp here." +msgstr "Chcę zbudować tu obóz." #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." -msgstr "Powiedz mi o wydawaniu ci rozkazów (samouczek NPC)." +msgid "We need to abandon this camp." +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "Pójdę na razie własną drogą." +msgid "Show me what needs to be done at the camp." +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "Idziemy." +msgid "Let's talk about your current activity." +msgstr "Porozmawiajmy o twojej obecnej aktywności." #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." @@ -195691,10 +197829,6 @@ msgstr "" msgid "Stay at your current position." msgstr "Zostań na swojej obecnej pozycji." -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "" @@ -195767,62 +197901,6 @@ msgstr "" msgid "Sure thing, I'll make my way there." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "" -"Tak, ten letni gorąc daje mi popalić, zróbmy sobie przerwę, jak leci " -"?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "Ok, może to pozwoli mi nie zamarznąć w tą pogodę, co słychać?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -195877,8 +197955,8 @@ msgid "Hello there." msgstr "Witajcie." #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." -msgstr "Okej, żadnych gwałtownych ruchów..." +msgid "Okay, no sudden movements…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep your distance!" @@ -196238,8 +198316,8 @@ msgid "Ah, okay." msgstr "Oh, okej." #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." -msgstr "Nie, dopóki nie dostanę antybiotyków..." +msgid "Not until I get some antibiotics…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "You asked me recently; ask again later." @@ -196346,8 +198424,8 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "Nie jestem w stanie cię trenować gdy prowadzę pojazd!" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." -msgstr "Odczekaj trochę, później pokażę ci cos nowego..." +msgid "Give it some time, I'll show you something new later…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I have some reason for denying you training." @@ -196374,8 +198452,8 @@ msgid "See you around." msgstr "Widzimy się." #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." -msgstr "Naprawdę nie czuję się z tym komfortowo..." +msgid "I really don't feel comfortable doing so…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I'll give you some space." @@ -196446,8 +198524,8 @@ msgid "Thanks, see you later!" msgstr "Dziękuję, do zobaczenia!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." -msgstr "Wziąłeś coś co nie należy do ciebie..." +msgid "You picked up something that does not belong to you…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Okay, okay, this is all a misunderstanding. Sorry, I'll drop it now." @@ -196540,13 +198618,13 @@ msgid "You might be seeing more of me…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" -msgstr "Witaj ponownie. *ksss*" +msgid "Hey again. *kzzz*" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "" #: lang/json/talk_topic_from_json.py @@ -196568,7 +198646,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -196581,7 +198659,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "" @@ -196603,7 +198681,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -196619,7 +198697,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -196654,14 +198732,6 @@ msgstr "Powiedz mi jak działają obozy frakcji." msgid "Tell me how faction camps have changed." msgstr "Powiedz mi jak zmieniły się obozy frakcji." -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "Chcę zbudować tu obóz." - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "Nic takiego. Porozmawiajmy o czymś innym." @@ -196883,9 +198953,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." +"talk…" msgstr "" -"Jesteś pewien? To nie wygląda na zbyt bezpieczne miejsce na plotkowanie..." #: lang/json/talk_topic_from_json.py msgid "It's fine, we've got a moment." @@ -196907,6 +198976,50 @@ msgstr "O czym chciałeś pogadać?" msgid "Actually, never mind." msgstr "W zasadzie nieważne." +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "" @@ -196928,7 +199041,7 @@ msgid "May the earth flourish beneath our paths." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -197112,8 +199225,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" @@ -197687,7 +199800,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -198167,6 +200280,38 @@ msgstr "" msgid "Huh." msgstr "Huh." +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -198219,19 +200364,9 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" -"W końcu tak. Było cicho od kilku godzin. Byłem spragniony, ranny i " -"przerażony. Chyba tylko mój trening ocalił mnie przed szaleństwem. " -"Zdecydowałem się wyciągnąć się stamtąd i sprawdzić jak poważne są moje " -"obrażenia. to było łatwe. Bok furgonetki był rozerwany, więc okazało " -"się że w zasadzie leżę pod cienką warstwą gruzu, i furgonetką jak namiotem " -"nade mną. Nawet nie byłem poważnie ranny. Zebrałem tyle sprzętu ile mogłem i" -" wymknąłem się stamtąd. Była noc. Słyszałem odgłosy walki w innych częściach" -" miasta, więc udałem się w przeciwnym kierunku. Przebyłem kilka przecznic " -"zanim wpadłem na jakieś ... Uciekłem od nich. Uciekałem, i " -"uciekałem i jeszcze trochę uciekałem. I oto jestem." #: lang/json/talk_topic_from_json.py msgid "" @@ -198574,6 +200709,30 @@ msgstr "Biedny Brudny Dan. " msgid "Thanks for telling me that stuff. " msgstr "Dzięki, że mo o tym opowiedziałeś. " +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -198634,6 +200793,24 @@ msgid "" "died in the crash, but I am not going back to find out." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -198673,6 +200850,21 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "A jak sądzisz co się stało? Widzisz ich gdzieś tutaj?" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -198741,6 +200933,40 @@ msgid "" "pretty good life compared to those first few months." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -198753,6 +200979,50 @@ msgstr "" "zajmował się innymi pasażerami zrobiłem to co zrobiłby każdy na moim miejscu" " i spieprzyłem stamtąd." +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -198803,6 +201073,27 @@ msgstr "Wybacz. Możesz mi więcej o nich powiedzieć?" msgid "Right. Sorry." msgstr "No tak. Wybacz." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -198823,6 +201114,19 @@ msgstr "" "dni później, ale miejsce było całkowicie opuszczone. Nie mam pojęcia co " "stało się z tymi ludźmi." +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -198923,6 +201227,42 @@ msgstr "Wybacz że pytałem. " msgid "Sorry for asking. " msgstr "Wybacz że pytałem. " +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -199626,6 +201966,48 @@ msgstr "" "markecie, ale potrzebowałem żywności, więc wyprawiłem się walczyć o swoje do" " lasu. Średnio mi to wychodziło, więc cieszę się, że się zjawiłeś." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -199688,6 +202070,128 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "Dziękuję, że mi to powiedziałeś. " +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -200005,13 +202509,48 @@ msgstr "" msgid "I can respect that." msgstr "Szanuję to." +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "Dzięki za to." + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -200113,6 +202652,43 @@ msgstr "" "przepadło. Zginęło w mroku. Nie pierdol o 'zdrowiu', i nie pytaj " "więcej." +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -200474,10 +203050,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "" -"Unikanie podatków. Byłem księgowym, i pomagałem szefowi wyprowadzić masę " -"kasy na różne sprytne sposoby. Nie za sprytne jak się okazuje..." #: lang/json/talk_topic_from_json.py msgid "" @@ -200694,6 +203268,32 @@ msgstr "" "może to my jesteśmy ci cisi, którzy posiądą ziemię. Choć nie uśmiechają mi " "się nasze szanse na to." +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -200704,6 +203304,23 @@ msgstr "" "wiernych nadeszło, a ja zostałem w tyle. Więc teraz, jak sądzę, kroczę przez" " piekło na ziemi. Szkoda, że nie słuchałem na szkółce niedzielnej." +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -200971,10 +203588,6 @@ msgstr "Jak wyglądała praca dla Wolnych Kupców?" msgid "What was working for the Old Guard like?" msgstr "Jak wyglądała praca dla Starej Gwardii?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "Dzięki za to." - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "Dzięki za to. Zbierajmy się." @@ -201251,6 +203864,22 @@ msgstr "" msgid "What were you saying before that?" msgstr "O czym to mówiłeś wcześniej?" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "Hej tam." @@ -201774,7 +204403,7 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -202167,10 +204796,6 @@ msgid "" " catastrophe." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "" @@ -203673,7 +206298,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" @@ -204420,7 +207045,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -205575,12 +208200,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" #: lang/json/talk_topic_from_json.py @@ -205708,12 +208333,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" #: lang/json/talk_topic_from_json.py @@ -205777,7 +208402,7 @@ msgid "Hm? Oh, hi." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "" #: lang/json/talk_topic_from_json.py @@ -206159,8 +208784,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" #: lang/json/talk_topic_from_json.py @@ -206177,9 +208802,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -206538,8 +209163,8 @@ msgstr "" "stąd do diabła!" #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." -msgstr "Ja tu nie dowodzę, szukasz kogoś innego..." +msgid "I'm not in charge here, you're looking for someone else…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep civil or I'll bring the pain." @@ -206586,12 +209211,12 @@ msgid "Well, I'd better be going. Bye." msgstr "Pora na mnie. Do zobaczenia!" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." -msgstr "Witaj marszalu..." +msgid "Welcome marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." -msgstr "Witaj..." +msgid "Welcome…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" @@ -206840,12 +209465,12 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." -msgstr "Marszalu..." +msgid "Marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." -msgstr "Obywatelu..." +msgid "Citizen…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Can I trade for supplies?" @@ -207506,7 +210131,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -207691,15 +210316,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." +msgid "Thinking I should go hunt something soon…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "" #: lang/json/talk_topic_from_json.py @@ -207739,7 +210364,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." +"marshal…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -207808,8 +210433,8 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "Nie mam pojęcia w czym mógłbyś mi potencjalnie pomóc." #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." -msgstr "Nie ruszaj się, już się biorę za maszynkę do strzyżenia..." +msgid "Stand still while I get my clippers…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Thanks…" @@ -208237,8 +210862,8 @@ msgstr "" "spędzają na zewnątrz." #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." -msgstr "Proszę zostaw mnie w spokoju..." +msgid "Please leave me alone…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "What's wrong?" @@ -208258,18 +210883,14 @@ msgstr "To smutne." #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." +"I don't know what you could do. I've tried everything. Just give me time…" msgstr "" -"Nie wiem co mógłbyś zrobić. Próbowałem wszystkiego. Po prosty daj mi czas..." #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." +"seems like I can't keep anything down…" msgstr "" -"Ciągle choruję! Na początku myślałem, że się czymś zatrułem, ale teraz " -"wygląda na to, że nie mogę niczego utrzymać w żołądku..." #: lang/json/talk_topic_from_json.py msgid "Uhm." @@ -208398,8 +211019,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "" #: lang/json/talk_topic_from_json.py @@ -208744,7 +211365,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "" @@ -208913,7 +211534,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -209080,7 +211701,7 @@ msgid "Oh, you again." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -209088,7 +211709,7 @@ msgid "I'm busy, what is it?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "" #: lang/json/talk_topic_from_json.py @@ -213427,209 +216048,14 @@ msgid "" msgstr "" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "gleba" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "" -"To ziemia. Wygląda na zdatną do orki. Może też być wykopana w celach " -"budowlanych." - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "thump" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "" -"Spory obszar drobnego pisaku, który może być przydatny na wiele sposobów, " -"jeżeli zostanie właściwie wydobyty." - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "glina" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "" -"Pole elastycznej gliny, nadającej się do wypalania w piecu, jeżeli zostanie " -"właściwie wydobyta." - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "kopice gliny" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "splosh!" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "kopiec piasku" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "kopiec ziemi" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "" -"Obszar z górkami ziemi, niełatwy w pokonaniu pieszo. Jeżeli zbadać go " -"dokładniej, wygląda na nadający się do sadzenia nasion, itp." - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "" -"Wielka góra ziemi, która wygląda jakbyś mógł się pod nią wczołgać dla " -"ochrony." - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "dziwny uskok" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" -"Nienaturalnie człowieczo ukształtowana dziura, zdająca się być dziwnie " -"znajoma. Masz dziwne uczucie badając ją z bliska, tak jakby w jakiś sposób " -"przynależała do ciebie." - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "grób" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "" -"Ziemny grób, porośnięty trawą. Przynajmniej niektórzy zmarli faktycznie " -"spoczywają w spokoju." - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "kamienna podłoga" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "" -"Relatywnie płaski obszar z kamienia i skał. Wygląda na tyle stabilnie, by " -"móc w nim drążyć z użyciem właściwego sprzętu górniczego." - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "bruk" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." -msgstr "" -"Fragment asfaltu, powoli degradującego się od pęknięć i odwarstwień " -"spowodowanych mrozem i brakiem utrzymania." - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "żółty bruk" - -#. ~ Description for yellow pavement -#: lang/json/terrain_from_json.py -msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" -"Pasma dokładnie ułożonych żółtych linii oznaczających drogę, informujących " -"kierowców by ich nie przekraczać. Nikt już obecnie nie egzekwuje tych " -"przepisów." - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "chodnik" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "" -"Nawierzchnia utwardzona betonową wylewką, uszkodzona spękaniami od mrozu, i " -"dużymi wyszczerbieniami z braku konserwacji." - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." +msgid "overgrown floor" msgstr "" -"Nowszy fragment betonowej wylewki utwardzającej powierzchnię, z wykończeniem" -" na potrzeby estetyki, i odpornością na cykle zamarzania i topnienia." -#. ~ Description for concrete +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "" - -#. ~ Description for wooden floor -#: lang/json/terrain_from_json.py -msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -213637,40 +216063,15 @@ msgid "SMASH!" msgstr "SMASH!" #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "metalowa podłoga" - -#. ~ Description for metal floor -#: lang/json/terrain_from_json.py -msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgid "overgrown wall" msgstr "" -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "płyta linoleum" - -#. ~ Description for linoleum tile +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." msgstr "" -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "klepisko" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." -msgstr "Podłoga z drobno zmieszanej ziemi następnie ubitej i utwardzonej." - #: lang/json/terrain_from_json.py msgid "concrete floor" msgstr "betonowa podłoga" @@ -213767,6 +216168,23 @@ msgstr "" "Nieukończona budowa z prętów zbrojeniowych i wylanego betonu; podłoga nie " "jest jeszcze wygładzona a dach nie jest w pełni odlany." +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "kamienna podłoga" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "" +"Relatywnie płaski obszar z kamienia i skał. Wygląda na tyle stabilnie, by " +"móc w nim drążyć z użyciem właściwego sprzętu górniczego." + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "metalowa podłoga" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -213776,6 +216194,10 @@ msgstr "" "Wysokiej jakości podłoga w szachownicę, redukująca ryzyko pośliźnięć i " "upadków, z dopasowanym dachem." +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "thump" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "podłoga" @@ -213824,6 +216246,10 @@ msgstr "" "Podłoga z twardego drewna wzmocnionego chemicznie dla uzyskania " "antypoślizgowej powierzchni, typowa w zastosowaniach sportowych." +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "klepisko" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -213909,28 +216335,15 @@ msgid "A blue section of flooring." msgstr "" #: lang/json/terrain_from_json.py -msgid "industrial carpet" -msgstr "" - -#. ~ Description for industrial carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." +msgid "carpet" msgstr "" +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "bunker carpet" +msgid "Base carpet!" msgstr "" -#. ~ Description for bunker carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." -msgstr "" - -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "Miękki czerwony dywan." @@ -213950,6 +216363,124 @@ msgstr "Miękki zielony dywan." msgid "Soft purple carpet." msgstr "Miękki fioletowy dywan." +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "płyta linoleum" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "" + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "malowana woskowana podłoga" @@ -213987,6 +216518,37 @@ msgstr "" " drutami do domowej roboty ramy. Bardzo klimatyczne w post-apokaliptycznych " "slumsach. Obyś lubił dźwięk deszczu padającego na blachę falistą." +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "gleba" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "" +"To ziemia. Wygląda na zdatną do orki. Może też być wykopana w celach " +"budowlanych." + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "" +"Spory obszar drobnego pisaku, który może być przydatny na wiele sposobów, " +"jeżeli zostanie właściwie wydobyty." + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "mech" @@ -213996,6 +216558,32 @@ msgstr "mech" msgid "Moist spongy moss." msgstr "Wilgotny gąbczasty mech." +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "glina" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "" +"Pole elastycznej gliny, nadającej się do wypalania w piecu, jeżeli zostanie " +"właściwie wydobyta." + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "kopice gliny" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "splosh!" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "" @@ -214005,6 +216593,149 @@ msgstr "" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "kopiec piasku" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "kopiec ziemi" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "" +"Obszar z górkami ziemi, niełatwy w pokonaniu pieszo. Jeżeli zbadać go " +"dokładniej, wygląda na nadający się do sadzenia nasion, itp." + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "" +"Wielka góra ziemi, która wygląda jakbyś mógł się pod nią wczołgać dla " +"ochrony." + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "dziwny uskok" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" +"Nienaturalnie człowieczo ukształtowana dziura, zdająca się być dziwnie " +"znajoma. Masz dziwne uczucie badając ją z bliska, tak jakby w jakiś sposób " +"przynależała do ciebie." + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "grób" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "" +"Ziemny grób, porośnięty trawą. Przynajmniej niektórzy zmarli faktycznie " +"spoczywają w spokoju." + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "bruk" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr "" +"Fragment asfaltu, powoli degradującego się od pęknięć i odwarstwień " +"spowodowanych mrozem i brakiem utrzymania." + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "żółty bruk" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "" +"Pasma dokładnie ułożonych żółtych linii oznaczających drogę, informujących " +"kierowców by ich nie przekraczać. Nikt już obecnie nie egzekwuje tych " +"przepisów." + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "chodnik" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "" +"Nawierzchnia utwardzona betonową wylewką, uszkodzona spękaniami od mrozu, i " +"dużymi wyszczerbieniami z braku konserwacji." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "" +"Nowszy fragment betonowej wylewki utwardzającej powierzchnię, z wykończeniem" +" na potrzeby estetyki, i odpornością na cykle zamarzania i topnienia." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "Podłoga z drobno zmieszanej ziemi następnie ubitej i utwardzonej." + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "orzech" @@ -218058,6 +220789,78 @@ msgstr "" msgid "A ladder leading down." msgstr "" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "pochyłość w dół" @@ -218549,7 +221352,7 @@ msgstr "Clank!" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "Bang!" @@ -221245,6 +224048,15 @@ msgid "" "extending the time until the food spoils." msgstr "" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "" @@ -222093,8 +224905,9 @@ msgstr "Zamek opiera się próbom włamania, i uszkadzasz swoje narzędzie." msgid "The lock stumps your efforts to pick it." msgstr "Zamek opiera się próbom włamania." -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "" @@ -222154,6 +224967,120 @@ msgstr "" msgid "Continue trying to fall asleep and don't ask again." msgstr "" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -226818,6 +229745,29 @@ msgstr "%s (%i slotów);" msgid "Increased storage capacity by %i." msgstr "Zwiększona pojemność o %i." +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "" @@ -226987,8 +229937,9 @@ msgid "(incapacitated)" msgstr "(unieruchomiony)" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" -msgstr "(oszczędzanie paliwa WŁ)" +#, c-format +msgid "(fuel saving ON > %d %%)" +msgstr "" #: src/bionics_ui.cpp #, c-format @@ -227709,6 +230660,23 @@ msgstr " uwalnia się z sieci pajęczej!" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "Próbujesz się uwolnić z sieci pajęczej, ale nie możesz się wyrwać!" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "" + +#: src/character.cpp +msgid " frees themselves!" +msgstr "" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "Próbujesz wydostać się z dołu, ale ześlizgujesz się na dno." @@ -228582,6 +231550,10 @@ msgstr "WYJĄTKOWY_WYSIŁEK" msgid "Your body strains under the weight!" msgstr "Twoje ciało ugina się pod ciężarem!" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -232797,15 +235769,6 @@ msgid "" "Roof: %s" msgstr "" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -236777,6 +239740,10 @@ msgstr "Nie masz niczego do przeładowania." msgid "You aren't holding something you can reload." msgstr "" +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -239356,6 +242323,10 @@ msgstr "Ignorowanie namierzania laserowego!" msgid "Creature whitelisted: %s" msgstr "Stworzenie dodane do białej listy: %s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "Popełnić samobójstwo?" @@ -240744,11 +243715,28 @@ msgstr "" msgid "There is a %s there. Take down?" msgstr "Jest tam %s. Rozmontować?" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "Jest tam %s. Rozbroić?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "Rozbrajasz pułapkę!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "Nie udaje ci się rozbroić pułapki." + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "Nie udaje ci się rozbroić pułapki; uruchamiasz ją!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -241638,6 +244626,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr "" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "" + #: src/init.cpp msgid "Finalizing" msgstr "Finalizowanie" @@ -242672,7 +245665,7 @@ msgid "" "very bad idea." msgstr "" -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -244421,6 +247414,15 @@ msgstr "" msgid "is not a container" msgstr "" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + #: src/item_contents.cpp msgid "is not rigid" msgstr "" @@ -244487,6 +247489,10 @@ msgstr "" msgid "Pocket %d:" msgstr "" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "" + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "" @@ -246298,10 +249304,6 @@ msgstr "W Ą Ż" msgid "Sokoban" msgstr "Sokoban" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "Saper" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "Światła zapal!" @@ -249237,7 +252239,7 @@ msgstr "%s potrzebuje %s w pobliżu siebie." msgid "You can't place a %s there. It contains a trap already." msgstr "Nie możesz umieścić tam %s. Już tam jest pułapka." -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "Uruchamiasz %s!" @@ -251006,6 +254008,15 @@ msgstr "" msgid "Summon" msgstr "" +#: src/magic.cpp +msgid "random creature" +msgstr "" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "Zasięg" @@ -251026,6 +254037,10 @@ msgstr "" msgid "Spawned" msgstr "Zespawnowany" +#: src/magic.cpp +msgid "Threshold" +msgstr "" + #: src/magic.cpp msgid "Recover" msgstr "" @@ -251078,6 +254093,15 @@ msgstr "" msgid "%s wounds are closing up!" msgstr "" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "" @@ -251537,30 +254561,23 @@ msgstr "" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "Rozbrajasz pułapkę!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "Nie udaje ci się rozbroić pułapki." +msgid "Something has crawled out of the %s plants!" +msgstr "Coś wypełzło z %s!" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "Nie udaje ci się rozbroić pułapki; uruchamiasz ją!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "Coś wypełzło z %s!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "Coś wypełzło z %s!" +msgid "You've spotted a %1$ss!" +msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "Coś wypełzło z %s!" +msgid " triggers a %s!" +msgstr "" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -253127,6 +256144,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "Stałaś się poszukiwany przez policję!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -256899,6 +259929,11 @@ msgstr "" msgid "zombie slave" msgstr "niewolnik zombie" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "Popchnij %s" + #: src/monexamine.cpp msgid "Rename" msgstr "Zmień nazwę" @@ -262308,17 +265343,6 @@ msgstr "Mutacje popromienne" msgid "If true, radiation causes the player to mutate." msgstr "Zaznaczone: promieniowanie powoduje mutacje u graczy." -#: src/options.cpp -msgid "Z-levels" -msgstr "" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" - #: src/options.cpp msgid "Character point pools" msgstr "Pule punktów postaci" @@ -267156,6 +270180,15 @@ msgctxt "grammatical gender list" msgid "n" msgstr "n" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "Wszedłeś na folię bąbelkową!" diff --git a/lang/po/ru.po b/lang/po/ru.po index 7d1eec0f70907..5e7d060b8b4d7 100644 --- a/lang/po/ru.po +++ b/lang/po/ru.po @@ -62,15 +62,15 @@ # Alexey Mostovoy , 2020 # Антон Бурмистров <22.valiant@gmail.com>, 2020 # korick3 korick3 , 2020 -# leemuar - , 2020 # Vlasov Vitaly , 2020 +# leemuar - , 2020 # CountAlex, 2020 # msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: CountAlex, 2020\n" "Language-Team: Russian (https://www.transifex.com/cataclysm-dda-translators/teams/2217/ru/)\n" @@ -1126,6 +1126,19 @@ msgstr[3] "нитрокс" msgid "Mixture of oxygen and nitrogen in proportions suitable for diving." msgstr "Смесь кислорода и азота в подходящих для дайвинга пропорциях." +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "огнетушащий агент" +msgstr[1] "огнетушащий агент" +msgstr[2] "огнетушащий агент" +msgstr[3] "огнетушащий агент" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "Сухое химическое вещество, эффективное при тушении пожаров." + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -5698,6 +5711,32 @@ msgstr "" "Мощный инсектицид, пригодный для заполнения химического распылителя. Лучше " "использовать с какой-нибудь маской или защитой рта." +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "патрон 12.3ln" +msgstr[1] "патрона 12.3ln" +msgstr[2] "патронов 12.3ln" +msgstr[3] "патроны 12.3ln" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" +"Боеприпасы 12.3ln были представлены в Румынии на заре второго Карпатского " +"конфликта. Винтовка PA md. 71, использующая эти патроны, быстро обрела " +"популярность в странах Восточного Блока а затем и по всему миру. Благодаря " +"этому боеприпасы типа 12.3ln стали стандартным патроном в Евразийском " +"регионе. Их было легко найти и накопить перед Исходом. Вам он кажется " +"похожим на патроны .30-06 Спрингфилд, но с чуть более острым носиком." + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -7062,7 +7101,7 @@ msgstr[3] "банки жёлтой краски" msgid "A can of yellow paint." msgstr "Банка жёлтой краски." -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "красный ковёр" @@ -9752,7 +9791,7 @@ msgstr[3] "подсумки для боеприпасов" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." +"rockets will not fit. Use insert to store ammunition." msgstr "" "Небольшой подсумок, пригодный для хранения большинства типов мелких " "боеприпасов, ракеты не поместятся. Активируйте для хранения боеприпасов." @@ -9880,11 +9919,11 @@ msgstr[3] "колчаны" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." msgstr "" -"Кожаный колчан, носимый на поясе, вмещает 20 стрел. Активируйте, чтобы " -"убрать стрелы." +"Кожаный колчан, носимый на поясе, вмещает 20 стрел или болтов. Активируйте, " +"чтобы убрать стрелы или болты." #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -9898,10 +9937,10 @@ msgstr[3] "берестяные колчаны" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." +"20 arrows or bolts. Use insert to store arrows or bolts." msgstr "" -"Колчан, сплетённый из полос бересты, носимый на поясе, вмещает 20 стрел. " -"Активируйте, чтобы убрать стрелы." +"Колчан, сплетённый из полос бересты, носимый на поясе, вмещает 20 стрел или " +"болтов. Активируйте, чтобы убрать стрелы или болты." #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -9915,12 +9954,14 @@ msgstr[3] "большие колчаны" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" "Большой кожаный колчан, укреплённый металлом. Носится за спиной, вмещает 60 " -"стрел. Исторически использовался конными лучниками, реже пешими, но НИКОГДА " -"не использовался для борьбы с зомби. Активируйте, чтобы убрать стрелы." +"стрел или болтов. Исторически использовался конными лучниками, реже пешими, " +"но НИКОГДА не использовался для борьбы с зомби. Активируйте, чтобы убрать " +"стрелы или болты." #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -9934,10 +9975,10 @@ msgstr[3] "большие берестяные колчаны" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." +"hold 60 arrows or bolts. Use insert to store arrows or bolts." msgstr "" "Большой колчан, сплетённый из полос бересты и одеваемый на спину, вмещает 60" -" стрел. Активируйте, чтобы убрать стрелы." +" стрел или болтов. Активируйте, чтобы убрать стрелы или болты." #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -22815,13 +22856,13 @@ msgstr "" #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." msgstr "" -"Среднего размера чемодан, используется в основном для транспортировки одежды" -" и других вещей во время поездок, предоставляет приличную вместительность, " -"но таскать его с собой не слишком удобно." +"Среднего размера чемодан на колёсиках, используется в основном для " +"транспортировки одежды и других вещей во время поездок, предоставляет " +"приличную вместительность, но таскать его с собой не совсем комфортно." #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -38909,6 +38950,21 @@ msgstr "" "Напряжённый ритуал, напоминающий занятия атлетикой. При его помощи вы можете" " сдержать немного боли." +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "свиток Жестокого превращения" +msgstr[1] "свитка Жестокого превращения" +msgstr[2] "свитков Жестокого превращения" +msgstr[3] "свитки Жестокого превращения" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "Превращает ваших врагов в лягушек." + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -40927,6 +40983,25 @@ msgstr "" "Этот толстый лабораторный справочник полон информации о сочетании магии с " "электромагнитным излучением." +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "осколок рунической таблички" +msgstr[1] "осколка рунической таблички" +msgstr[2] "осколков рунической таблички" +msgstr[3] "осколки рунической таблички" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" +"Маленькая табличка из почерневшего камня, по-видимому, вырезанная из гораздо" +" более крупной. Золотые руны светятся на её поверхности и медленно " +"складываются в читаемые предложения, когда вы смотрите на них." + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -47774,6 +47849,40 @@ msgid "" "cheese. Delicious." msgstr "Солёные кукурузные чипсы с мясным фаршем, покрытые сыром. Вкуснятина." +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "вегетарианские начос" +msgstr[1] "вегетарианские начос" +msgstr[2] "вегетарианские начос" +msgstr[3] "вегетарианские начос" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "" +"Солёные чипсы из кукурузной тортильи, теперь с бобами. Можно добавить " +"немного сыра." + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "вегетарианские начос с сыром" +msgstr[1] "вегетарианские начос с сыром" +msgstr[2] "вегетарианские начос с сыром" +msgstr[3] "вегетарианские начос с сыром" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "" +"Солёные чипсы из кукурузной тортильи с бобами, покрытые сыром. Вкуснятина, " +"даже если вы не вегетарианец." + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -53919,30 +54028,72 @@ msgstr "" "подходит для небольших птиц." #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "собачий корм" -msgstr[1] "собачьих корма" -msgstr[2] "собачьих кормов" -msgstr[3] "собачий корм" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "влажный собачий корм" +msgstr[1] "влажный собачий корм" +msgstr[2] "влажный собачий корм" +msgstr[3] "влажный собачий корм" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'wet dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." -msgstr "Собачий корм. Пахнет странно, но собакам, похоже, нравится." +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "" +"Влажный собачий корм из консервированного мяса. Пахнет странно, но собакам, " +"похоже, нравится." #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "кошачий корм" -msgstr[1] "кошачьих корма" -msgstr[2] "кошачьих кормов" -msgstr[3] "кошачий корм" +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "сухой собачий корм" +msgstr[1] "сухой собачий корм" +msgstr[2] "сухой собачий корм" +msgstr[3] "сухой собачий корм" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'dry dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." -msgstr "Кошачий корм. Пахнет странно, но кошкам, похоже, нравится." +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" +"Сухие кусочки корма для собак с большим сроком годности. Изготовлены из " +"сушеного переработанного мяса и зерна, обогащены витаминами и минералами." + +#: lang/json/COMESTIBLE_from_json.py +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "влажный кошачий корм" +msgstr[1] "влажный кошачий корм" +msgstr[2] "влажный кошачий корм" +msgstr[3] "влажный кошачий корм" + +#. ~ Description for {'str_sp': 'wet cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." +msgstr "" +"Влажный кошачий корм из консервированного мяса. Пахнет остро, но кошкам, " +"похоже, нравится." + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "сухой кошачий корм" +msgstr[1] "сухой кошачий корм" +msgstr[2] "сухой кошачий корм" +msgstr[3] "сухой кошачий корм" + +#. ~ Description for {'str_sp': 'dry cat food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" +"Сухие кусочки корма для котов с большим сроком годности. Изготовлены из " +"сушеного переработанного мяса и зерна, обогащены витаминами и минералами." #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -62428,6 +62579,39 @@ msgstr "" "Войлочные лоскуты, крепко связанные для удобства хранения. Разберите для " "распаковки." +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "связка досок" +msgstr[1] "связки досок" +msgstr[2] "связок досок" +msgstr[3] "связки досок" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "" +"Десяток строительных досок, связанных верёвкой. Разберите для распаковки." + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "связка прочных веток" +msgstr[1] "связки прочных веток" +msgstr[2] "связок прочных веток" +msgstr[3] "связки прочных веток" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "Десяток прочных веток, связанных верёвкой. Разберите для распаковки." + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -67717,6 +67901,74 @@ msgid "" "wound." msgstr "Почти обезглавленный труп. Непонятно, что могло нанести такую рану." +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "сломанный дрон Экзоди" +msgstr[1] "сломанных дрона Экзоди" +msgstr[2] "сломанных дронов Экзоди" +msgstr[3] "сломанные дроны Экзоди" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "Сломанный дрон Экзоди. Можно разобрать на запчасти." + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "сломанный шагатель Экзоди" +msgstr[1] "сломанных шагателя Экзоди" +msgstr[2] "сломанных шагателей Экзоди" +msgstr[3] "сломанные шагатели Экзоди" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" +"Сломанный шагатель Экзоди. Всё ещё выглядит устрашающе, несмотря на " +"нерабочее состояние, возможно из-за огромного размера и массы. Можно " +"разобрать на запчасти." + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "сломанная турель Экзоди" +msgstr[1] "сломанные турели Экзоди" +msgstr[2] "сломанные турели Экзоди" +msgstr[3] "сломанные турели Экзоди" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" +"Сломанная турель Экзоди. Всё ещё выглядит устрашающе, несмотря на нерабочее " +"состояние, возможно из-за огромного размера и массы. Можно разобрать на " +"запчасти." + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "сломанный дрон Экзоди с надувным шаром" +msgstr[1] "сломанные дроны Экзоди с надувным шаром" +msgstr[2] "сломанные дроны Экзоди с надувным шаром" +msgstr[3] "сломанные дроны Экзоди с надувным шаром" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" +"Сломанный дрон с надувным шаром. Шар разорван в клочья, но ходовая часть в " +"порядке Можно разобрать на части." + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -69918,7 +70170,7 @@ msgstr[3] "микрофоны XLR" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "" "Обычный микрофон для записи или усиления голоса. На нем есть застежка для " "одежды. Имеет трехпиновый XLR разъем в основании для соединения с " @@ -70166,6 +70418,24 @@ msgstr "" "Простой механический чугунный центробежный насос. Без установки от него мало" " пользы." +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "набор фитингов" +msgstr[1] "набора фитингов" +msgstr[2] "наборов фитингов" +msgstr[3] "наборы фитингов" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "" +"Широкий ассортимент металлических фитингов - торцевые заглушки, соединения " +"труб и тому подобное. Их можно использовать в самых разных проектах." + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -72600,6 +72870,151 @@ msgstr "" "морского стекла, матовый и шероховатый с округлыми краями. Немного тёплый на" " ощупь." +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "шасси Экзоди" +msgstr[1] "шасси Экзоди" +msgstr[2] "шасси Экзоди" +msgstr[3] "шасси Экзоди" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" +"Примерно гексагональная рама с соответствующими элементами, выглядящая так, " +"будто создана в виде монолитной детали. Монтажные отверстия и крепления " +"чрезвычайно прочные, несмотря на следы серьёзного износа и многочисленные " +"метки от ремонта. Это достаточно универсальная рама, и вероятно, на её " +"основе можно создать платформу для множества различных боевых ролей." + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "шасси дрона Экзоди" +msgstr[1] "шасси дрона Экзоди" +msgstr[2] "шасси дрона Экзоди" +msgstr[3] "шасси дрона Экзоди" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" +"Небольшая, примерно гексагональная рама с соответствующими элементами, " +"выглядящая так, будто создана в виде монолитной детали. Монтажные отверстия " +"и крепления чрезвычайно прочные, несмотря на следы серьёзного износа и " +"многочисленные метки от ремонта. Это достаточно универсальная рама, и " +"вероятно, на её основе можно создать платформу для множества различных " +"боевых ролей." + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "кибернетическая нейронная матрица" +msgstr[1] "кибернетические нейронные матрицы" +msgstr[2] "кибернетических нейронных матриц" +msgstr[3] "кибернетические нейронные матрицы" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" +"Набор ёмкостей и трубок с разъемами для загрузки жидкостей, подключения " +"электричества, вводами и выводами. Эта сложная конструкция создана для " +"помещения мозга и позвоночника, а также незаменимых для их жизнеобеспечения " +"органов." + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "незнакомая электронная штуковина" +msgstr[1] "незнакомые электронные штуковины" +msgstr[2] "незнакомых электронных штуковин" +msgstr[3] "незнакомые электронные штуковины" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" +"Провода и общая форма подсказывают вам, что это компьютер, ну или какое-то " +"электронное устройство, но что именно и зачем оно нужно - вам не понятно. " +"Оно тяжелое и крепкое." + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "расписанные металлические платы" +msgstr[1] "расписанные металлические платы" +msgstr[2] "расписанные металлические платы" +msgstr[3] "расписанные металлические платы" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" +"Похоже на какую-то незнакомую электронику. Представляет из себя набор " +"похожих на медные концентрических колец. От каждого из них тянутся провода к" +" оси." + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "кибернетический сенсор" +msgstr[1] "кибернетических сенсора" +msgstr[2] "кибернетических сенсоров" +msgstr[3] "кибернетические сенсоры" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" +"Судя по большому стеклянному глазу спереди - размером примерно с тарелку - " +"это что-то вроде камеры. Ее внутреннее устройство вам совершенно непонятно, " +"оно не похоже ни на одну камеру, которую вы видели раньше" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "вращающееся устройство" +msgstr[1] "вращающихся устройства" +msgstr[2] "вращающихся устройств" +msgstr[3] "вращающиеся устройства" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" +"Вы предполагаете, что катушки медного провода и выступающий поршень - это " +"своего рода двигатель или генератор, но конструкция не похожа на то, что вы " +"видели раньше, и вы не можете понять, как заставить его работать." + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -76694,6 +77109,19 @@ msgstr "" "Металлический водопроводный кран, который можно присоединить к баку с водой " "для её использования." +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "деревянное крепление колеса" +msgstr[1] "деревянных крепления колеса" +msgstr[2] "деревянных креплений колеса" +msgstr[3] "деревянные крепления колеса" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "Кусок дерева с отверстиями для велосипедного колеса." + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -84124,6 +84552,44 @@ msgstr "" "Самодельный двухлитровый бак под давлением, из которого подаётся смесь для " "самодельного химического распылителя." +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "магазин PA Md. 71 12.3ln Экзоди" +msgstr[1] "магазина PA Md. 71 12.3ln Экзоди" +msgstr[2] "магазинов PA Md. 71 12.3ln Экзоди" +msgstr[3] "магазины PA Md. 71 12.3ln Экзоди" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" +"Маленький, узкий магазин на основе классической обоймы PA Md. 71, слегка " +"доработанные Экзоди для более удобного использования на парящих дронах. Из-" +"за небольшого размера не очень подходит для боя с ордой зомби на земле, так " +"как его неудобно перезаряжать." + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "магазин PA Md. 68 12.3ln Экзоди" +msgstr[1] "магазина PA Md. 68 12.3ln Экзоди" +msgstr[2] "магазинов PA Md. 68 12.3ln Экзоди" +msgstr[3] "магазины PA Md. 68 12.3ln Экзоди" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "" +"Неразумно тяжёлый магазин для уже и так тяжёлой боевой винтовки PA Md. 68, " +"разработанный и кастомизированный Экзоди." + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -85407,6 +85873,64 @@ msgstr "" "личности, запертой в изуродованном теле. При наличии хирургических навыков " "вы могли бы вернуть ему человечность. Если вас это волнует, конечно…" +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "дрон Экзоди" +msgstr[1] "дрона Экзоди" +msgstr[2] "дронов Экзоди" +msgstr[3] "дроны Экзоди" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "Человекоподобный робот с различными строительными инструментами." + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "шагатель Экзоди" +msgstr[1] "шагателя Экзоди" +msgstr[2] "шагателей Экзоди" +msgstr[3] "шагатели Экзоди" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" +"Огромный четвероногий робот, кажется, собранный из попавшихся частей, " +"большинство из которых вам незнакомы. Он движется тяжелой, странно изящной " +"походкой, его шаги оставляют неглубокие ямы. Он несёт при себе серьёзный " +"арсенал оружия, но, похоже, не слишком торопится нацеливаться на вас." + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "зомборг" +msgstr[1] "зомборга" +msgstr[2] "зомборгов" +msgstr[3] "зомборги" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" +"Сочетание мёртвого человека и ещё более мёртвой технологии. Мешанина плоти и" +" стали, движущаяся словно марионетка в руках сердитого ребёнка. Похоже, " +"роботизированные элементы отключились, и новые полосы плоти обернули их и " +"закрепили под странными углами. Местами из под разлагающейся плоти выступают" +" металлический скелет и пластины брони." + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -85715,6 +86239,30 @@ msgstr "" "Автоматический дрон-квадрокоптер во много раз больше обычного, по-видимому с" " ядерной мини-бомбой внутри. Если он нацелится на вас… Бегите." +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "парящий дрон-снайпер" +msgstr[1] "парящих дрона-снайпера" +msgstr[2] "парящих дронов-снайперов" +msgstr[3] "парящие дроны-снайперы" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" +"Необычное устройство, похожее на сочетание метеозонда и квадрокоптера. Под " +"грубым контейнером висит небольшая установка с интегрированной винтовкой. " +"Небольшие пропеллеры время от времени оживают, удерживая позицию устройства " +"в воздухе. Похоже, оно может долго продержаться в воздухе, пока не сядут " +"аккумуляторы." + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -88104,6 +88652,27 @@ msgstr "" " свою добычу острыми когтями, а потом наносит смертельный удар огромными " "клыками." +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "тигр" +msgstr[1] "тигра" +msgstr[2] "тигров" +msgstr[3] "тигры" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" +"Величественный тигр, крупный хищник семейства кошачьих. Естественная среда " +"обитания - Азия, хотя сейчас наиболее крупные популяции находятся в частных " +"резервациях в Соединенных Штатах. Этот сильный и быстрый хищник - один из " +"самых узнаваемых и любимых животных в мире. А еще и один из самых опасных." + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -90998,6 +91567,25 @@ msgstr[3] "громкоговорители" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "Мощный громкоговоритель, шумно повторяющий по кругу набор сообщений" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "самодельная турель" +msgstr[1] "самодельные турели" +msgstr[2] "самодельных турелей" +msgstr[3] "самодельные турели" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "" +"Здоровенная турель, похоже, собранная из частей, произведённых по незнакомой" +" вам технологии, многие из которых кажутся чужеродными. Оснащена здоровенным" +" пулеметом." + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -91120,6 +91708,87 @@ msgstr "" " У его облика поразительные детали, но от скованных движений вам правда не " "по себе. Конец света не помешал ему искать пациента, которому нужна помощь." +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "собака-скелет" +msgstr[1] "собаки-скелета" +msgstr[2] "собак-скелетов" +msgstr[3] "собаки-скелеты" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" +"Это когда-то бывшее собакой существо потеряло всю кожу, обнажая каркас рёбер" +" и костей. Эта костяная броня без следа внешней плоти скрепляется сеткой " +"гадко выглядящих чёрных вен и сухожилий, покрытых чёрной слизью." + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "баргест" +msgstr[1] "баргеста" +msgstr[2] "баргестов" +msgstr[3] "баргесты" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "" +"Большой, раздувшийся зомби-пёс, покрытый чёрной слизью. У него длинные зубы," +" а его спина бугрится мышцами и покрыта свежими ранами." + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "огромный жутень" +msgstr[1] "огромных жутня" +msgstr[2] "огромных жутней" +msgstr[3] "огромные жутни" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" +"Четвероногое собачье тело, раздувшееся до гротескных пропорций, с лапами " +"толщиной с мусорный бак и огромными щерящимся зубами." + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "костяной волк" +msgstr[1] "костяных волка" +msgstr[2] "костяных волков" +msgstr[3] "костяные волки" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" +"Четвероногое создание, покрытое сросшимися костяными пластинами, " +"напоминающее волка или собаку. Его суставы и трещины в пластинах сочатся " +"чёрной жижей." + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "волк-скелет" +msgstr[1] "волка-скелета" +msgstr[2] "волков-скелетов" +msgstr[3] "волки-скелеты" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -91271,26 +91940,6 @@ msgstr "" "Обезображенный оживший труп собаки. Поджарый зверь, способный с лёгкостью " "догнать своих двуногих друзей." -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "собака-скелет" -msgstr[1] "собаки-скелета" -msgstr[2] "собак-скелетов" -msgstr[3] "собаки-скелеты" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" -"Это когда-то бывшее собакой существо потеряло всю кожу, обнажая каркас рёбер" -" и костей. Эта костяная броня без следа внешней плоти скрепляется сеткой " -"гадко выглядящих чёрных вен и сухожилий, покрытых чёрной слизью." - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -91436,6 +92085,40 @@ msgstr "" "Более-менее нормально выглядящая пума, за исключением того, что её задние " "ноги распухли, а из глаз сочится чёрная слизь." +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "тигр-упырь" +msgstr[1] "тигра-упыря" +msgstr[2] "тигров-упырей" +msgstr[3] "тигры-упыри" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "" +"Почти нормально выглядящий тигр, что спотыкается и качается, его челюсти " +"обвисли, глаза широко открыты и блестят черным цветом." + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "масса зомби-пауков" +msgstr[1] "массы зомби-пауков" +msgstr[2] "масс зомби-пауков" +msgstr[3] "массы зомби-пауков" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "" +"Тысячи, если не миллионы пауков, скопившихся в высокую кучу и истекающих " +"липким зелёным гноем, держащие эту массу вместе и двигающие её." + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -92172,6 +92855,59 @@ msgstr "" msgid "The impaler launches a barb!" msgstr "Пронзатель выстреливает колючкой!" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "ножницеход" +msgstr[1] "ножницехода" +msgstr[2] "ножницеходов" +msgstr[3] "ножницеходы" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "" +"Возвышающийся среди руин кошмарный паук, покрытый кровью и хранящий " +"молчание, наблюдающий за умирающими окрестностями. Его тонкие костяные " +"конечности скользят между обломками с потусторонней скоростью." + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "свисающие потроха" +msgstr[1] "свисающих потрохов" +msgstr[2] "свисающих потрохов" +msgstr[3] "свисающие потроха" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" +"Огромные змеящиеся полоски плоти, свисающие с потолка, сердито молотящие по " +"всему, до чего дотягиваются." + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "пульсирующая куча" +msgstr[1] "пульсирующие кучи" +msgstr[2] "пульсирующих куч" +msgstr[3] "пульсирующие кучи" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "" +"Огромная гора сросшихся тел и мутировавшей плоти. Она неритмично и отчаянно " +"пульсирует." + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -95235,25 +95971,6 @@ msgstr "" "Огромный гниющий труп динозавра со свирепой крокодилоподобной головой, " "сочащимися черным глазами и изодранным плавником на спине." -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "теневой зомби-спинозавр" -msgstr[1] "теневых зомби-спинозавра" -msgstr[2] "теневых зомби-спинозавров" -msgstr[3] "теневые зомби-спинозавры" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" -"Жутковатая тень охватывает этого динозавра. Вы можете разглядеть силуэт " -"большого двуногого динозавра с разодранным плавником. У него длинная голова " -"и V-образная морда." - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -95267,42 +95984,6 @@ msgstr[3] "тираннозомби рекс" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "Огромная груда рваной, зловонной плоти, щерящейся огромными зубами." -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "теневой тираннозомби рекс" -msgstr[1] "теневых тираннозомби рекса" -msgstr[2] "теневых тираннозомби рексов" -msgstr[3] "теневые тираннозомби рексы" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "" -"Жутковатая тень охватывает этого динозавра. Вы можете разглядеть силуэт " -"большого двуногого динозавра с подобием ободранного оперения. У него большая" -" голова с кучей зубов в пасти." - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "скелетозавр-рекс" -msgstr[1] "скелетозавр-рекса" -msgstr[2] "скелетозавр-рексов" -msgstr[3] "скелетозавр-рексы" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "" -"Чудовище из плотных костей, щерящееся с высоты огромными бритвенными зубами," -" с которых капает чёрная слизь." - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -95448,25 +96129,6 @@ msgstr "" "ободранным оперением и черной жижей. На каждой ноге растёт большой " "серповидный коготь." -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "теневой дейноних-зомби" -msgstr[1] "теневых дейнониха-зомби" -msgstr[2] "теневых дейнонихов-зомби" -msgstr[3] "теневые дейнонихи-зомби" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" -"Жутковатая тень охватывает этого динозавра. Вы можете разглядеть силуэт " -"динозавра среднего размера с подобием ободранного оперения. На каждой ноге " -"растёт большой серповидный коготь." - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -95536,6 +96198,469 @@ msgstr "" "Средних размеров труп динозавра с острыми зубами и двумя костяными гребнями " "на его голове и полосками оторванной плоти, свисающей подобно кружевам." +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "отвратный галлимим" +msgstr[1] "отвратных галлимима" +msgstr[2] "отвратных галлимимов" +msgstr[3] "отвратные галлимимы" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" +"Покачивающийся труп средних размеров двуногого динозавра, покрытый " +"ободранным оперением и черной жижей. Всё его тело покрыто раздутыми мышцами " +"и набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "череполом" +msgstr[1] "череполома" +msgstr[2] "череполомов" +msgstr[3] "череполомы" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" +"Покачивающийся труп средних размеров двуногого динозавра, покрытый " +"ободранным оперением и черной жижей. Его круглая, массивная голова держится " +"на теле, покрытым раздутыми мышцами и набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "кампозавроломатель" +msgstr[1] "кампозавроломателя" +msgstr[2] "кампозавроломателей" +msgstr[3] "кампозавроломатели" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" +"Покачивающийся труп большого двуногого динозавра с неприятно раздутыми " +"ногами, широкими возвышающимися плечами и бритвенно острым клювом, покрытый " +"ободранным оперением и черной жижей." + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "спинозавромолотус" +msgstr[1] "спинозавромолотуса" +msgstr[2] "спинозавромолотусов" +msgstr[3] "спинозавромолотусы" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" +"Огромный гниющий труп динозавра со свирепой крокодилоподобной головой, " +"сочащимися черным глазами и изодранным плавником на спине. Его тело даже " +"больше обычного, покрыто раздувшимися мышцами и набухшими, гнойными ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "гневрекс" +msgstr[1] "гневрекса" +msgstr[2] "гневрексов" +msgstr[3] "гневрексы" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" +"Огромная груда рваной, зловонной плоти, щерящейся огромными зубами. Всё её " +"тело бугрится раздутыми мышцами и опухшими гнойными ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "альбертовальня" +msgstr[1] "альбертовальни" +msgstr[2] "альбертовальен" +msgstr[3] "альбертовальни" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" +"Массивные челюсти и хваткие когти на теле, бугрящемся раздутыми мышцами и " +"опухшими гнойными ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "трицератрак" +msgstr[1] "трицератрака" +msgstr[2] "трицератраков" +msgstr[3] "трицератраки" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" +"Массивный, похожий на носорога качающийся труп динозавра с костяным гребнем," +" из которого растут три больших рога. Из его глаз течёт нечто, похожее на " +"густые чёрные слёзы. Всё его тело покрыто раздутыми мышцами и набухшими, " +"гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "стегозавр-молот" +msgstr[1] "стегозавра-молота" +msgstr[2] "стегозавров-молотов" +msgstr[3] "стегозавры-молоты" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" +"Покачивающийся труп большого четвероногого динозавра с пластинами на спине, " +"помахивающий шипастым хвостом. Всё его тело покрыто раздутыми мышцами и " +"набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "динотанк" +msgstr[1] "динотанка" +msgstr[2] "динотанков" +msgstr[3] "динотанки" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" +"Тяжелый бронированный зомби-динозавр. Всё его тело бугрится раздутыми " +"мышцами и опухшими гнойными ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "зомби дредноут" +msgstr[1] "зомби дредноута" +msgstr[2] "зомби дредноутов" +msgstr[3] "зомби дредноуты" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" +"Покачивающийся труп массивного четвероногого динозавра с вытянутой шеей и " +"длинным, похожим на кнут хвостом. Всё его тело покрыто раздутыми мышцами и " +"набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "драконотитан" +msgstr[1] "драконотитана" +msgstr[2] "драконотитанов" +msgstr[3] "драконотитаны" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" +"Огромный зомби, покрытый чешуёй, костяными шипами и двигающийся с пугающей " +"скоростью. Его цветастые рога и костяные шипы покрывают тело, покрытое " +"вздутыми мышцами и опухшими гнойными ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "аллозавролавина" +msgstr[1] "аллозавролавины" +msgstr[2] "аллозавролавин" +msgstr[3] "аллозавролавины" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "" +"Покачивающийся труп большого хищного двуногого динозавра. Всё его тело " +"покрыто раздутыми мышцами и набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "дейнихорушитель" +msgstr[1] "дейнихорушителя" +msgstr[2] "дейнихорушителей" +msgstr[3] "дейнихорушители" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" +"Покачивающийся труп средних размеров двуногого динозавра, покрытый " +"ободранным оперением и черной жижей. На обеих ногах красуются огромные, " +"похожие на косы когти. Всё его тело покрыто раздутыми мышцами и набухшими, " +"гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "ютавудузавр" +msgstr[1] "ютавудузавра" +msgstr[2] "ютавудузавров" +msgstr[3] "ютавудузавры" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" +"Покачивающийся и мечущийся труп большого двуногого динозавра с перьями на " +"передних лапах, длинным хвостом и длинными, острыми серпообразными когтями. " +"Всё его тело покрыто раздутыми мышцами и набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "паразавролом" +msgstr[1] "паразавролома" +msgstr[2] "паразавроломов" +msgstr[3] "паразавроломы" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" +"Огромный пёстрый динозавр с тупым головным гребнем, мёртвый и бредущий с " +"пустым взглядом и раздувшимися глазами. Всё его тело покрыто раздутыми " +"мышцами и набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "крылатый ужас" +msgstr[1] "крылатых ужаса" +msgstr[2] "крылатых ужасов" +msgstr[3] "крылатые ужасы" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" +"Летающий труп оперённой рептилии ростом чуть меньше метра с короткими " +"крыльями и крупным цветастым клювом. Всё её тело покрыто раздутыми мышцами и" +" набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "крестокрушитель" +msgstr[1] "крестокрушителя" +msgstr[2] "крестокрушителей" +msgstr[3] "крестокрушители" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" +"Средних размеров труп динозавра с острыми зубами и двумя костяными гребнями " +"на его голове и полосками оторванной плоти, свисающей подобно кружевам. Всё " +"его тело покрыто раздутыми мышцами и набухшими, гноящимися ранами." + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "теневой зомби-спинозавр" +msgstr[1] "теневых зомби-спинозавра" +msgstr[2] "теневых зомби-спинозавров" +msgstr[3] "теневые зомби-спинозавры" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" +"Жутковатая тень охватывает этого динозавра. Вы можете разглядеть силуэт " +"большого двуногого динозавра с разодранным плавником. У него длинная голова " +"и V-образная морда." + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "теневой тираннозомби рекс" +msgstr[1] "теневых тираннозомби рекса" +msgstr[2] "теневых тираннозомби рексов" +msgstr[3] "теневые тираннозомби рексы" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "" +"Жутковатая тень охватывает этого динозавра. Вы можете разглядеть силуэт " +"большого двуногого динозавра с подобием ободранного оперения. У него большая" +" голова с кучей зубов в пасти." + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "теневой дейноних-зомби" +msgstr[1] "теневых дейнониха-зомби" +msgstr[2] "теневых дейнонихов-зомби" +msgstr[3] "теневые дейнонихи-зомби" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" +"Жутковатая тень охватывает этого динозавра. Вы можете разглядеть силуэт " +"динозавра среднего размера с подобием ободранного оперения. На каждой ноге " +"растёт большой серповидный коготь." + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "скелетозавр-рекс" +msgstr[1] "скелетозавр-рекса" +msgstr[2] "скелетозавр-рексов" +msgstr[3] "скелетозавр-рексы" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "" +"Чудовище из плотных костей, щерящееся с высоты огромными бритвенными зубами," +" с которых капает чёрная слизь." + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "альбертозавр-скелет" +msgstr[1] "альбертозавра-скелета" +msgstr[2] "альбертозавррв-скелетов" +msgstr[3] "альбертозавры-скелеты" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" +"Чудовище из плотных костей, щерящееся с высоты бритвенными зубами, с которых" +" капает чёрная слизь. Его костяные когти тянутся во все стороны." + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "костяной дракон" +msgstr[1] "костяных дракона" +msgstr[2] "костяных драконов" +msgstr[3] "костяные драконы" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" +"Чудовище из плотных костей, щерящееся с высоты бритвенными зубами, с которых" +" капает чёрная слизь. Эффект усиливается торчащими цветными рогами и " +"костяными шипами." + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "аллозавр-скелет" +msgstr[1] "аллозавра-скелета" +msgstr[2] "аллозавров-скелетов" +msgstr[3] "аллозавры-скелеты" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" +"Чудовище из плотных костей, щерящееся с высоты бритвенными зубами, с которых" +" капает чёрная слизь." + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "ютакостезавр" +msgstr[1] "ютакостезавра" +msgstr[2] "ютакостезавров" +msgstr[3] "ютакостезавры" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" +"Чудовище из плотных костей, щерящееся с высоты бритвенными зубами, с которых" +" капает чёрная слизь. У него длинный хвост и длинные, похожие на косы когти." + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -96166,6 +97291,23 @@ msgstr "" "Крикун — это гриб размером с человека, который издает пронзительный визг, " "чтобы отогнать существ, которые его беспокоят." +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "лягушка" +msgstr[1] "лягушки" +msgstr[2] "лягушек" +msgstr[3] "лягушки" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "" +"Подозрительно обычная американская лягушка. Лучше не подпускать к ней Ивана-" +"царевича." + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -97035,6 +98177,14 @@ msgstr "амфибия" msgid "a bird" msgstr "птица" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "инопланетный киборг" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "тяжёлые удары." + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "рептилия" @@ -97932,6 +99082,18 @@ msgstr "" "Этот ритуал создаёт маленький камешек, наполненный магией анимистов. Эту " "руну можно применять в рецептах как катализатор." +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "Выдирание дыши" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "" +"Жестоко вырывает дух из тела, подчиняя вам получающуюся в результате тень." + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "Блуждающий огонек" @@ -98162,6 +99324,15 @@ msgstr "Отладочное заклинание усталости" msgid "Uses a little fatigue" msgstr "Тратит немного усталости" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "Отладочный полиморф" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "Ну ты же хотел сбросить вес, да?" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "Отладочное заклинание ХП" @@ -98610,6 +99781,10 @@ msgstr "Удар маны" msgid "Haste" msgstr "Ускорение" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "Жестокое превращение" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "Луч маны" @@ -103399,6 +104574,22 @@ msgstr[1] "бионических зажигалки" msgstr[2] "бионических зажигалок" msgstr[3] "бионические зажигалки" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "коптильня" +msgstr[1] "коптильни" +msgstr[2] "коптилен" +msgstr[3] "коптильни" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "" +"Это crafting_pseudo_item, если у вас это есть, то что-то пошло не так." + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -103486,7 +104677,7 @@ msgstr[3] "фонари из тыквы" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "Свет" @@ -106802,13 +107993,6 @@ msgstr[1] "псевдо маслобойки" msgstr[2] "псевдо маслобоек" msgstr[3] "псевдо маслобойки" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "" -"Это crafting_pseudo_item, если у вас это есть, то что-то пошло не так." - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -109727,16 +110911,44 @@ msgstr[1] "метательных огнетушителя" msgstr[2] "метательных огнетушителей" msgstr[3] "метательные огнетушители" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "Выдернуть затычку" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "Вы выдёргиваете затычку пожарной гранаты." + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." msgstr "" "Это огнетушитель в форме гранаты. Не так эффективен, как обычный " -"огнетушитель, но его можно использовать на расстоянии. Он активируется от " -"нагрева, так что просто бросьте его в огонь." +"огнетушитель, но его можно использовать на расстоянии. Можно выдернуть " +"затычку, но он активируется от нагрева, так что просто бросьте его в огонь." + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "активированный метательный огнетушитель" +msgstr[1] "активированных метательных огнетушителя" +msgstr[2] "активированных метательных огнетушителей" +msgstr[3] "активированные метательные огнетушители" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" +msgstr "" +"Это активированная онетушащая граната, готовая взорваться в любой момент. " +"Лучше ее бросить!" #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -118004,7 +119216,7 @@ msgid "Pheidippides was a hack" msgstr "Фидиппид жульничал" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "Пробегите марафон… и еще немного." #: lang/json/achievement_from_json.py @@ -118071,6 +119283,613 @@ msgstr "Возвращение к корням" msgid "Return to the location you started the game" msgstr "Вернуться к месту, где вы начали игру" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "Растопка" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "Если дерево падает в лесу и его никто не слышит, издаёт ли оно звук?" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "Лесоруб" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "Что такое лес для человека с топором?" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "Обезлесивание" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "Если срубить деревья, найдёте волка." + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "Копатель могил" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "Именно это нам и нужно: больше трупов." + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "Расхититель могил" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "Эй, а может он там перевернулся? Тебе нужно проверить" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "Похороны" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "" +"Быть похороненным - это привилегия в мире, где миллионы никогда не будут." + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "Могильщик" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "Не оставляй никого гнить среди живых мертвецов." + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "Похоронный дом" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "Ты ведь не можешь похоронить весь мир, правда?" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "Киберпанк" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "Spiritus quidem promptus; caro vero infirma." + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "Часовой человек" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "" +"Презренною и грубою рукой. Я отомщу обеим вам жестоко. Мир содрогнется!.. Я " +"еще не знаю, Что сделаю, но сделаю такое, Что страшно станет." + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "Homo Evolutis" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "Мира людей больше нет. Да здравствует мир трансгуманизма" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "Сломан, но не повержен" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "Твоя медицинская страховка это покрывает?" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "Свободный торговец" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "Невероятные вещи за смешную цену!" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "Себя-Без-Ножа-Режу Достабль" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "" +"Мой друг-эскимос, я так дёшево отдаю тебе это снег, будто себя без ножа " +"режу." + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "Красноречивый" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "Мы ведь друзья, не так ли?" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "Подвешенный язык" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "Ходят слухи, что вы уговорили зомби-халка оставить вас в покое." + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "ХакерМен" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "В этой операционной системе есть лазейка. Везде найдётся лазейка." + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "Все еще не совсем как Кевин" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "Это не читерство. Это отладка." + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "Доктор медицины" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "Есть здесь доктор?" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "Доктор Хаус" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "Это волчанка." + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "Инженер" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "Просто дайте мне разводной ключ." + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "МакГайвер" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "Вся конструкция держится на честном слове, соплях и изоленте." + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "Зверолов" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "Хорошая ловушка не различает бобров и зомби-бобров." + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "Сапёр" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "Достаточно ошибиться всего однажды." + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "Водитель-ас" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "Не существует слишком резких поворотов." + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "Стиг" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "Формула 1 - для пенсионеров" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "Пловец" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "Как рыба в воде." + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "Майкл Фелпс" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "Быстрее чем Челюсти." + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "Сделай-Сам" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "Возьми вот это, засунь вот в то, и готово." + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "На все руки мастер" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "Если клея будет достаточно, для меня нет ничего невозможного." + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "Мастер-шеф" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "Глазированная вырезка - как два пальца." + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "Адская Кухня" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "" +"Сегодня в меню: французский луковый суп, говядина по-бургундски, крем брюле." + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "Портной" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "Игла, нитка и мечта." + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "Фешн-дизайнер" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "Мода для женщин, мужчин и мутантов." + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "Выживальщик" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "Выживание - это моя игра." + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "Беар Гриллс" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "Так ты говоришь, можно выжить на собственной моче?" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "Закон Ома" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "Громовой Ом. Два вольта зашло, один вышел. Сопротивление бесполезно." + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "Никола Тесла" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "Нельзя просто взять и не лизнуть 9-вольтовую батарейку." + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "Меткий Глаз" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "Лучше чем Леголас" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "Робин Гуд" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "Вильгельм Тель? Не слышал о таком." + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "Орлиный Глаз" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "Только я и моя цель." + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "Дедшот" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "Не беги. Умрешь уставшим." + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "Стрелок" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "Калибр решает." + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "Ракетчик" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "Отправлю тебя на Луну. По кусочкам." + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "Маленький, но смертоносный" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "Калибр не важен, когда ствол направлен на тебя." + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "Грязный Гарри" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" +"Но это - Магнум 44 калибра, самый мощный пистолет в мире, и он отстрелит " +"тебе голову начисто, так что задай себе один вопрос: повезёт ли мне? " +"Повезёт, мразь?" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "Стрелок" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "" +"Это моя винтовка. Таких винтовок много, но эта — моя. Моя винтовка — мой " +"лучший друг. Она — моя жизнь. Я должен научиться владеть ею так же, как я " +"владею своей жизнью." + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "Солдат" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" +"Без меня моя винтовка бесполезна. Без моей винтовки бесполезен я. Я должен " +"хранить её от губительной погоды и от повреждений так же, как я храню от " +"всякого вреда свои ноги и руки, свои глаза и своё сердце. Я должен хранить " +"свою винтовку чистой и готовой. Мы станем частью друг друга." + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "Два ствола - двойной кайф." + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "Когда хочется поразить цель девять раз за один выстрел." + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "Элмер Фадд" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "Как дела, док? Охотишься за кволиками?" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "Зажмурься и пали" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "Хоть одна да попадёт, это вопрос статистики." + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "Автомат делает ТРА-ТА-ТА!" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "Нам точно нужно больше патронов." + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "Yeet!" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "И не возвращайся." + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "Коби Брайант" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "Граната пошла!" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "Драчун" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "Бутылка в левой руке, ножка стула - в правой." + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "Уличный Боец" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "Главное - победа, а не стиль." + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "Отбивающий" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "С каждым ударом я всё ближе к хоум рану." + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "Каменный Век" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "" +"Дубина была первым оружием человечества. Она же скорее всего станет " +"последним, так почему бы её и не освоить." + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "Путь Меча" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" +"Когда меч покинул ножны, страсти человеческие зайдут за любые границы." + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "Миямото Мусаси" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "" +"Меч должен быть более чем оружием; он должен стать ответом на жизненные " +"вопросы." + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "Неуловимый" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "Самый сильный удар ничего не значит, если он не попал по цели." + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "Нео" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "Можешь увернуться от пули?" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "Хладная сталь" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "Пока вы веселились, я изучал клинок." + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "Джек Потрошитель" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "Что в воздухе я вижу пред собою? Кинжал! Схвачу его за рукоять." + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "Дорога на Шаолинь" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "Я ощущаю целую армию в моем кулаке." + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "Мистер Мияги" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "Быть самому оружием." + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "Взломщик" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "Монтировка? Какое варварство!" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "Замочный мастер" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "Если есть замок, найдется и ключ." + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "Периодическая таблица" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "Это что-то вроде кулинарии. Только не облизывай ложку." + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "Хайзенберг" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "Ты знаешь, кто я. Я повар. Скажи моё имя." + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "Начинающий волшебник" @@ -118534,6 +120353,11 @@ msgstr "взлом" msgid "canceling activity serialized with legacy code" msgstr "отмена активности, сериализованной легаси-кодом" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "упражнения" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "термоядерная батарея" @@ -118838,6 +120662,10 @@ msgstr "распыляемый химикат" msgid "compressed air" msgstr "сжатый воздух" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "патрон 12.3ln" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "картечные патроны" @@ -121067,6 +122895,62 @@ msgstr "Не убивать людей" msgid "Merciful" msgstr "Милосердие" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "Путь эльфа" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "Не срубать деревья" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "Homo Sapiens" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "Не устанавливать бионические импланты" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "Не устанавливать неисправные бионические импланты" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "Без мутаций" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "На рентгене чисто" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "Чистая кровь" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "Структурная целостность" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "Не ломать кости" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "Учитель, оставьте детей в покое" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "Не получать уровней навыков" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "Самовольная неграмотность" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "Не читай книг" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -121700,10 +123584,6 @@ msgstr "Покрасить стену в жёлтый" msgid "Take Paint Off Wall" msgstr "Соскрести краску со стены" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "Убрать ковёр" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "Постелить красный ковёр" @@ -121744,6 +123624,38 @@ msgstr "Построить деревянную лестницу" msgid "Mine Upstair" msgstr "Прорубить лестницу вверх" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "Построить нижнюю часть бетонной рампы" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" +"Постройка бетонной, рампы, ведущей на верхний уровень, а также примыкающей " +"на верхнем уровне рампы, ведущей вниз на этот уровень. Верхний конец рампы " +"должен располагаться в соседней клетке, чтобы можно было двигаться верх и " +"вниз между уровнями." + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "Построить верхнюю часть бетонной рампы" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" +"Постройка бетонной, рампы, ведущей на верхний уровень, а также примыкающей " +"на верхнем уровне рампы, ведущей вниз на этот уровень. Нужно строить в " +"соседней клетке с нижней частью рампы, чтобы можно было двигаться верх и " +"вниз между уровнями." + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "Начать постройку транспорта" @@ -124951,7 +126863,7 @@ msgstr "Вы сделали пару затяжек." msgid "You smoked too much." msgstr "Вы курили слишком много." -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "Кайф" @@ -127077,6 +128989,18 @@ msgstr "огонь" msgid "raging fire" msgstr "бушующий огонь" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "взвесь огнетушителя" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "облако огнетушителя" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "густое облако огнетушителя" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "старый мусор" @@ -128205,8 +130129,7 @@ msgstr "" "горит." #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "«хрясь!»" @@ -128397,7 +130320,7 @@ msgstr "" "удобство или тепло." #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "треск!" @@ -129172,14 +131095,12 @@ msgstr "тренажёр" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." msgstr "" "Комплект оборудования для тяжелой атлетики и силовых тренировок с парой " -"тяжелых грузов, прикрепленных к противоположным концам прочной трубы. Веса " -"огромны, и использование их без страховки - хороший способ серьезно поранить" -" себя." +"тяжелых грузов, прикрепленных к противоположным концам прочной трубы. Вы " +"можете подобрать необходимый вес, вручную выбрав веса." #: lang/json/furniture_from_json.py msgid "ball machine" @@ -129290,6 +131211,21 @@ msgstr "" "гребли. Без электричества его не выйдет использовать, но в нем могут быть " "полезные части, которые можно снять." +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "механический эргометр" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "" +"Тренажер с ручками и досками, имитирующими лодку с веслами. Это старая " +"модель с механической настройкой сопротивления, но она работает без " +"электричества." + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "беговая дорожка" @@ -129305,6 +131241,21 @@ msgstr "" " электричества ленту сдвинуть практически невозможно. В любом случае, вам и " "так скорее всего хватает физических нагрузок и бега." +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "гравитационная беговая дорожка" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" +"Работающий на силе тяготения конвейерный пояс с механическим управлением для" +" бега на месте. Пояс наклонён под небольшим настраиваемым углом и сдвигается" +" назад под вашим весом. " + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "большая боксёрская груша" @@ -130787,10 +132738,6 @@ msgstr "" msgid "filled arc furnace" msgstr "заполненная дуговая печь" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "коптильня" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -131646,7 +133593,8 @@ msgstr "Оружие отладки, стреляет кислотными сг msgid "auto" msgstr "авто" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "винтовка" @@ -131888,8 +133836,8 @@ msgstr "" "устройство, чуть более сложное, чем монтажная лента и электроника, он " "питается от стандартного УБП." -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "пистолеты" @@ -131971,7 +133919,7 @@ msgstr "" "Пневматическая винтовка с накачкой, собранная из подручных материалов. Она " "очень тихая и смертоносная." -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "полуавтомат" @@ -132585,12 +134533,12 @@ msgstr "" "рекламируемая как оружие самозащиты." #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" -msgstr[0] "MAS 223" -msgstr[1] "MAS 223" -msgstr[2] "MAS 223" -msgstr[3] "MAS 223" +msgid "MAS .223" +msgid_plural "MAS .223" +msgstr[0] "MAS .223" +msgstr[1] "MAS .223" +msgstr[2] "MAS .223" +msgstr[3] "MAS .223" #: lang/json/gun_from_json.py msgid "" @@ -135787,17 +137735,17 @@ msgstr "" "стальным." #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" -msgstr[0] "CZ-75" -msgstr[1] "CZ-75" -msgstr[2] "CZ-75" -msgstr[3] "CZ-75" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" +msgstr[0] "CZ-75 B" +msgstr[1] "CZ-75 B" +msgstr[2] "CZ-75 B" +msgstr[3] "CZ-75 B" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " @@ -135953,6 +137901,57 @@ msgstr "" "под 12-й калибр. Исторически использовалось охотниками-эгоманьяками в " "Африке, теперь же используется их потомками-эгоманьяками в Новой Англии." +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "боевая винтовка PA md. 68" +msgstr[1] "боевые винтовки PA md. 68" +msgstr[2] "боевых винтовок PA md. 68" +msgstr[3] "боевые винтовки PA md. 68" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" +"Самое популярное оружие под патрон 12.3ln - конечно же PA md. 71. Её " +"предшественник, md.68, многими считалась провалом: хотя она была мощной и " +"надёжной, она была слишком тяжёлой, чтобы стать хорошим пехотным оружием, и " +"при этом она была недостаточно мощной, чтобы использоваться как оружие " +"поддержки. Их было произведено достаточно, чтобы во времена зомби-" +"апокалипсиса вновь обрести популярность в качестве оружия с широко " +"доступными боеприпасами. Она идеально подходила задачам Экзоди, так как их " +"куда меньше беспокоили неудобства её использования." + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "винтовка PA md. 71 для охоты на зомби" +msgstr[1] "винтовки PA md. 71 для охоты на зомби" +msgstr[2] "винтовок PA md. 71 для охоты на зомби" +msgstr[3] "винтовки PA md. 71 для охоты на зомби" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" +"Крайне популярная румынская штурмовая винтовка, прославившаяся в третьей " +"Карпатской войне, была слегка переработана Экзоди, чтобы использоваться как " +"снайперское оружие. Она хорошо подходит для точной стрельбы по приоритетным " +"целям. Доработанный дизайн позволяет чрезвычайно быстро произвести 5 " +"выстрелов с целью нанесения серьезного урона цели и предотвращения ее " +"оживления." + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -136673,12 +138672,12 @@ msgstr "" " подойдет." #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" -msgstr[0] "самодельный дробовик" -msgstr[1] "самодельных дробовика" -msgstr[2] "самодельных дробовиков" -msgstr[3] "самодельные дробовики" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" +msgstr[0] "самодельный дробовик выживальщика" +msgstr[1] "самодельных дробовика выживальщика" +msgstr[2] "самодельных дробовиков выживальщика" +msgstr[3] "самодельные дробовики выживальщика" #: lang/json/gun_from_json.py msgid "" @@ -137631,6 +139630,31 @@ msgid "Bionic one-shot subdermal .40 pistol integrated with your head." msgstr "" "Бионическая однозарядная подкожная пушка калибра .40, встроенная в череп." +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "модифицированная Marlin 39A" +msgstr[1] "модифицированные Marlin 39A" +msgstr[2] "модифицированных Marlin 39A" +msgstr[3] "модифицированные Marlin 39A" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "Винтовка Marlin 39A, модифицированная для установки в турель." + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "модифицированный СКС" +msgstr[1] "модифицированных СКС" +msgstr[2] "модифицированных СКС" +msgstr[3] "модифицированные СКС" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "" +"Карабин Симонова, модифицированный для использования в транспортной турели." + #: lang/json/gun_from_json.py msgid "CRIT .5 LP" msgid_plural "CRIT .5 LPs" @@ -138779,14 +140803,6 @@ msgstr "" "непрост в использовании, его можно более тонко настроить для большей " "надежности." -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "ударный дробовик" -msgstr[1] "ударных дробовика" -msgstr[2] "ударных дробовиков" -msgstr[3] "ударные дробовики" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -141428,6 +143444,14 @@ msgstr "" "Вы копаетесь во внутренностях того, что осталось от этого неудавшегося " "эксперимента, пытаясь найти любую уцелевшую бионику." +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "" +"Вы обыскиваете то что осталось от этого монстра из плоти и металла в поисках" +" уцелевшего оборудования" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -144042,10 +146066,6 @@ msgstr "Написать" msgid "Teleport yourself" msgstr "Телепортироваться" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "Потушить огонь" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "Вытереться" @@ -145413,6 +147433,14 @@ msgstr "Прервать генерацию персонажа" msgid "Toggle sorting order" msgstr "Переключить режим сортировки" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "Случайная профессия" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "Случайный сценарий" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "Прокрутить описание вверх" @@ -145813,6 +147841,10 @@ msgstr "Разобрать предметы" msgid "Sleep" msgstr "Спать" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "Заниматься упражнениями" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "Управлять транспортом" @@ -146286,12 +148318,12 @@ msgstr "Загрузить цветовой шаблон" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "Да" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "Нет" @@ -152350,7 +154382,7 @@ msgstr "Собрать кости для Бриджит ЛаКруа. 8 долж msgid "There is always work to be done, song to be woven." msgstr "Ещё многое нужно сделать, ещё много песен сплести." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -152361,16 +154393,16 @@ msgstr "" "слышать и слушать песню. Ступай разделай животное и почувствуй силу меж " "кончиков пальцев. Затем принеси мне кости, и я вырежу из них для тебя." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "Превосходно. Теперь ступай же." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "Я понимаю твои сомнения. Возвращайся, когда увидишь путь." -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -153798,9 +155830,9 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "" -"Тогда увидимся… Или не увидимся, и тогда я пойму, что принял правильное " +"Тогда увидимся… Или не увидимся, и тогда я пойму, что это было правильное " "решение." #: lang/json/mission_def_from_json.py @@ -153810,8 +155842,8 @@ msgstr "" "Не умирай. Если ты спрашиваешь у меня совета — это плохой знак для тебя." #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." -msgstr "Ну, ты же ещё дёргаешься… Пока что." +msgid "Well, you're not dead… yet." +msgstr "Ну, вы же ещё не умерли… Пока." #: lang/json/mission_def_from_json.py msgid "" @@ -166683,8 +168715,7 @@ msgstr "Арахнид" msgid "Well, maybe you'll just have to make your own world wide web." msgstr "Ясно, похоже теперь вы должны создать собственную всемирную паутину." -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "Выживший" @@ -167050,10 +169081,6 @@ msgstr "" "лучше знать. Вы - Поешь-ка, маска стала вашим лицом, вы самый настоящий и вы" " — единственное, что стоит между этим миром и забвением." -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "Доктор медицины" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -167481,11 +169508,29 @@ msgstr "" "захватов." #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "История Выжившего" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgid "Survivor: Confused 1" +msgstr "Выживший: Сбитый с толку 1" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -167493,6 +169538,86 @@ msgstr "История Выжившего" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "Этот НПС может рассказать вам, как он пережил Катаклизм." +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "Выживший: Без прошлого 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "Выживший: Без прошлого 2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "Выживший: Без прошлого 3" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "Выживший: Без прошлого 4" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "Выживший: Без прошлого 5" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "Выживший: Религиозный 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "Выживший: Религиозный 2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "Выживший: Мечтатель 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "Выживший: Со свадьбы 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "Выживший: Эвакуированный 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "Выживший: Эвакуированный 2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "Выживший: Эвакуированный 3" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "Выживший: Эвакуированный 4" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "Выживший: Эвакуированный 5" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "Выживший: Эвакуированный 6" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "Выживший: Эвакуированный МЧС 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "Выживший: Брошенный 1" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "Выживший: Брошенный 2" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "Выживший: Брошенный 3" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "История Выжившего" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "Знак Провидицы" @@ -169445,10 +171570,6 @@ msgstr "Я просто пытаюсь выжить." msgid "I'm tracking game." msgstr "Я выслеживаю дичь." -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "Солдат" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "Бармен" @@ -170243,10 +172364,6 @@ msgstr "Добытчик" msgid "Laborer" msgstr "Разнорабочий" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "Лесоруб" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "Столяр" @@ -171504,11 +173621,11 @@ msgstr "гараж у заправки" #: lang/json/overmap_terrain_from_json.py msgid "dispensary" -msgstr "гомеопатическая аптека" +msgstr "пункт продажи каннабиоидов" #: lang/json/overmap_terrain_from_json.py msgid "dispensary roof" -msgstr "крыша аптеки" +msgstr "крыша пункта продажи каннабиоидов" #: lang/json/overmap_terrain_from_json.py msgid "small office" @@ -172832,6 +174949,18 @@ msgstr "дорога, люк" msgid "bridge" msgstr "мост" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "мост (эстакада)" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "край моста (земля)" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "край моста (рампа)" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "остановка" @@ -190664,106 +192793,6 @@ msgstr "Не помню, когда последний раз так хотел msgid "I'd kill for a sip of water right now." msgstr "Могу убить за глоток воды." -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "" -"Да-да, конечно, не могу не заметить, что у тебя есть пиво! Давай откупорим " -"бутылочку и поболтаем, , как дела?" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "" -"О, конечно, как насчёт одной из бутылочек пива, что я у тебя видел? Впрочем," -" как твои дела?" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "" -"Ага, поделись пивком, я видел, у тебя с собой несколько штук, и мы поболтаем" -" о чём угодно! Шучу-шучу, как жизнь?" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "" -"Эй, , болтать было бы куда приятнее с классным холодным пивком. Как " -"дела?" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "" -"Что скажешь, если мы откроем пива, поболтаем и просто… притворимся, что " -"никакого апокалипсиса нет, хотя б на минутку?" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "Передай-ка и мне, и вспомним старые добрые деньки, ." - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "Эй, конечно, , мне всё равно нужно передохнуть, как сам-то?" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "Ага, лады, , как поживаешь?" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "Без вопросов, давай потрындим! Ты как, всё нормально?" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "Чего ж нет-то? Как твои дела?" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "У меня всё норм, чё как?" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "Могу уделить пару минут, как сам-то?" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "Не вопрос, , у тебя всё хорошо?" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "Хорошо, тебе хочется выговориться и камень с души снять?" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "Всегда рад хорошенько поболтать! Но что случилось, всё нормально?" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "Что ж, , нам надо узнать друг друга получше, как держишься?" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "Я определённо не против. Как себя чувствуешь?" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "Отличная идея, . Давай ненадолго забудем про мир. Как жизнь?" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "Ай, к чёрту всё. Как у тебя дела?" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "Конечно. Итак, что думаешь про погоду, а?" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "мать твою" @@ -193256,6 +195285,19 @@ msgstr "Расскажи, как тебе удалось выжить в пер msgid "Was it rough surviving thus far?" msgstr "Было ли тяжело выжить?" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "Как мы здесь оказались? по-твоему? Что вообще случилось?" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "" +"Что вообще происходит? Ну то есть, что глобально за чертовщина творится?" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "Было что-нибудь о том, откуда вообще пришёл весь этот апокалипсис?" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -193978,6 +196020,366 @@ msgstr " будет избегать противников, если msgid " will follow normal engagement rules." msgstr " будет следовать обычным правилам встречи с противником." +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "Ага, точно, хочешь открыть по пивку?" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "О, конечно, как насчёт одной из бутылочек пива, что у тебя лежат?" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "" +"Ага, поделись пивком, я знаю, у тебя с собой несколько штук, и мы поболтаем " +"о чём угодно! Шучу-шучу." + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "" +"Эй, , болтать было бы куда приятнее с классным холодным пивком." + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "" +"Что скажешь, если мы откроем пива, поболтаем и просто… притворимся, что " +"никакого апокалипсиса нет?" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "Передай-ка и мне, и поболтаем, ." + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "Ох, эта летняя жара меня доконает, знаешь?" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "Наслаждаюсь летом." + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "Вообще неплохо было бы немного охладиться, если честно." + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "Ладно, пусть это поможет мне не замёрзнуть при такой погоде." + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "Нужно сказать, сейчас снег был бы к месту." + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "Странно, что зомби не замерзают." + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "Ну, мне не совсем хорошо… но так уж и быть." + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "Мне всё равно нужно передохнуть, как у тебя?" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "Ну, как дела?" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "Давай потрындим! Ты как, , всё нормально?" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "У меня всё норм, чё как?" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "Могу уделить пару минут, как у тебя дела?" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "Не вопрос, , у тебя всё хорошо?" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "Хорошо, тебе хочется выговориться и камень с души снять?" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "Всегда рад хорошенько поболтать! Но что случилось, всё нормально?" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "Ладно, , как поживаешь?" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "Я не против. Как себя чувствуешь?" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "Давай ненадолго забудем про мир. Как жизнь?" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "Ай, к чёрту всё. Как у тебя дела?" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "Итак, что думаешь про погоду, а?" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "Приятно, что у тебя нашлось время. Как дела в последнее время?" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "Ноги ноют последнее время, сечёшь?" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "" +"Я сегодня в отличном настроении. Не знаю почему, может просто день такой." + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" +"Я просто не могу поверить, что всё кончено. Я прокручиваю в голове те дни, " +"когда всё полетело к чёрту. Бунты. Ложь. Психи. Не возникало ощущения, что " +"всё вот так закончится." + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" +"Тебе не приходило в голову, что были проблески правды в том бреде, что " +"распространяли перед концом света? Наркотики для управления разумом, " +"биологический терроризм? Кое в чём был смысл, но большая часть - натянутая " +"ерунда. Но вот опять же, у нас ведь тут самые натуральные зомби." + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "" +"Любопытно, нужно ли мне больше или меньше посвящать время религии. " +"Понимаешь, о чём я, ?" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "" +"Думаю, надо мне навести порядок в моём снаряжении. Полный бардак. А то " +"потянусь за пистолетом и вытащу батончик сникерса, прикинь?" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "" +"Когда-нибудь приходилось задумываться, зачем мы вообще боремся? В конце " +"концов все мы всё равно станем зомби. Я не говорю, что перестану драться, но" +" чёрт, какой же в этом смысл?" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "" +"Хотелось бы мне сейчас пошмалять по зомби без всей это ерунды со страхом за " +"собственную жизнь." + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "" +"Каждый раз ,когда я закрываю глаза, снова вижу беспорядки. У тебя такое тоже" +" бывает, или так только со мной?" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "" +"Тебе никогда не кажется, что всё до апокалипсиса было просто сном, от " +"которого ты проснулся?" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "" +"Как тебе стало понятно, что наступает конец света? Для меня это было то " +"чёртово видео на YouTube, где женщина убивает ребёнка. Просто пиздец, " +"понимаешь?" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "" +"Мне интересно, осталось ли ещё правительство где-то там, сидящее в бункере." + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" +"Помнишь безумные новости, когда начался конец света? Те, что почти и не " +"показывали из-за освещения беспорядков. То есть, разве губернатор Род-" +"Айленда не объявил о выходе из Союза?" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" +"Я продолжаю видеть сны, в которых зомби всё ещё помнят, кем они были, и " +"просто заперты в своих телах, наблюдая за происходящим. Не могу нормально " +"спать из-за этого." + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "" +"Эти наркотики для контроля разума, которые они добавляют в воду, чтобы люди " +"устраивали беспорядки… думаешь, они ещё в воде?" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" +"Не могу перестать догадываться, кто же так облажался, позволив всему этому " +"произойти. Очевидно, новостям доверять нельзя - они неделями называли зомби " +"«участниками беспорядков». Так почему? Откуда всё это?" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" +"А что, если то, что говорили о китайцах, отчасти правда? Думаешь, сейчас в " +"Китае то же самое? Или может США - это карантинная зона, и где-то ещё мир " +"живёт по прежнему." + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" +"Тебе не приходилось замечать, что раны сейчас совсем по другому " +"выздоравливают? Мне удалось это заметить ещё до конца света, но сейчас это " +"особенно заметно. Раны даже не успевают толком покрыться коркой перед тем, " +"как затягиваются." + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "" +"Я до сих пор не могу понять, откуда у зомби энергия берётся. Они будто " +"вечные двигатели." + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" +"Так много вещей не складываются. Кто создал зомби? Что заставляет их " +"двигаться? Может быть слухи о наркотиках для контроля разума были всё это " +"время правдой, и кто-то нашёл способ создавать зомби с помощью биоинженерии." + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "" +"Как зомби продолжают двигаться? Что они едят? Думаешь, они когда-нибудь " +"сгниют окончательно?" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "" +"Я вот всё думаю, настанет день, когда у нас закончится туалетная бумага. И " +"что тогда?" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "" +"Тебе не кажется странным такое - типа, мы находим запертое здание, а внутри " +"оказывается одинокий зомби. Как он туда вообще попал?" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" +"Иногда я думаю, что мы все психи, не только те, кто сошёл с ума и устраивал " +"беспорядки. Никогда бы в голову не пришло, что я сотворю такое, что мне " +"приходилось делать после конца света." + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "Попадались интересные книги? Так хорошо, что у нас ещё есть книги." + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" +"Знаешь, чего мне не хватает? Кинотеатров. Как думаешь, Голливуд пережил это?" +" Может, там сейчас полно актёров-зомби, до сих пор рефлекторно играющих свои" +" сцены. Ха, такую дичь я посмотрю с удовольствием." + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "Понимаю, …" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "Это напоминает мне кое о чём…" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "Верно, верно. Скажи, а тебе в голову не приходило…" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -195644,6 +198046,16 @@ msgstr "" "безгильзовых патронов. Слоган гласит: «Безгильзовое оружие Ривтех. Остальное" " даже не сравнится.»" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" +"Реклама прачечной SUDS. На ней написан следующий текст, окружённый " +"облачками: «Тергитол по вторникам! Скидка 50% на все стирки и сушки!»" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -195658,6 +198070,27 @@ msgstr "" " угрожающим чёрным силуэтам на горизонте. Надпись гласит: «МЫ ЗДЕСЬ РАДИ " "ВАШЕЙ ЗАЩИТЫ»." +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" +"Реклама спортзала Iron Gym. На ней фотографии людей, выполняющих различные " +"упражнения, вроде бега, йоги и пауэрлифтинга. Надпись гласит: «Здесь можно " +"поднять и опустить!»" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" +"Реклама Space Time Inc. На ней изображены парящие возле космического корабля" +" астронавты на фоне Луны. Надпись гласит: «Ваш собственный кусочек Луны! " +"Всего за 29.99$ в месяц вы можете приобрести недвижимость среди звёзд!»" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -209801,12 +212234,12 @@ msgid "Acolyte." msgstr "Послушник." #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" +msgid "You're back. Have you come to listen to the song?" msgstr "Ты снова тут. Ты хочешь послушать песнь?" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" -msgstr "Ты тут. Тихо. Ты слышишь? Песнь?" +msgid "You there. Quiet down. Can you hear it? The song?" +msgstr "Эй ты. Тихо. Ты слышишь? Песнь?" #: lang/json/talk_topic_from_json.py msgid "What? What do you mean? What song?" @@ -209840,8 +212273,8 @@ msgstr "Мне пора. Береги себя, Провидица." #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "" "Вслушайся. Кости… Они поют. Ты слышишь? Слышишь песню, которую они выводят? " "Слышишь истории, которые они хранят?" @@ -209856,11 +212289,11 @@ msgstr "Э… Да, конечно. Думаю, мне пора идти." #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" "Когда всё произошло, когда случился Катаклизм, что-то… поменялось. Это видно" @@ -209884,11 +212317,11 @@ msgstr "Кто-то ещё, эээ, верит в это?" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" "Тело не восстаёт, только если разбить кости. Ты поймёшь, кем оно было, " "только если осмотришь кости. Это и есть история. Что бы ни вызвало " @@ -209902,7 +212335,7 @@ msgstr "По-моему, я понял, о чём ты, хотя я не со в #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "" "Есть и другие, кто следует этой цели. Тебе нужно им помогать, пусть нас и " @@ -209918,10 +212351,10 @@ msgstr "Цели? Так зачем ты собираешь кости?" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" "Песню можно плести по-разному. Вырезанные костяные амулеты, оружие и доспехи" " — все они хранят неимоверную силу, и в нужное время мы с собратьями соберём" @@ -209935,7 +212368,7 @@ msgstr "Завершить мир? Чего?" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" "Мы верим, что достаточная сила в одной песне способна обратить Катаклизм — " @@ -209956,8 +212389,8 @@ msgstr "Да ты чокнутая." #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" "Твой разум открыт. Открытее многих. Возможно, однажды и ты ощутишь силу " @@ -209970,9 +212403,9 @@ msgstr "Спасибо… Спасибо тебе." #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" "Меня не удивляет твой спексис. Возможно, однажды и ты услышишь " "неотвратимость песни, ощутишь её силу. Но до тех пор ты будешь Послушником, " @@ -210034,17 +212467,6 @@ msgstr "Слушаю." msgid "Perhaps another time, Seer." msgstr "Может, в другой раз, Провидица." -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" -"Если хочешь встать на путь просвещения, первым делом тебе нужно научиться " -"слышать и слушать песню. Ступай разделай животное и почувствуй силу меж " -"кончиков пальцев. Затем принеси мне кости, и я обрежу их для тебя." - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "Ну, мне хочется узнать, что будет дальше. Я в деле." @@ -210053,10 +212475,6 @@ msgstr "Ну, мне хочется узнать, что будет дальше msgid "Not interested." msgstr "Не интересует." -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "Превосходно. Теперь ступай же." - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "Считай, уже сделано. Но я хочу спросить…" @@ -210073,23 +212491,13 @@ msgstr "Не поможешь ли мне снаряжением?" msgid "I'm off then." msgstr "Тогда я иду." -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "" -"Всюду видно качающиеся трупы, но они движутся без гармонии. Их песня " -"годится, но для Послушника это бессмысленная сложность. Убедись, что режешь " -"чистое живое существо." - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "В общем, существо, которое не зомби и не монстр. Ясно." #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "" "Для тебя открыт путь просвещения. Моя помощь только помешает тебе и спутает " @@ -210102,7 +212510,7 @@ msgstr "Ясно. Очень хорошо." #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "" "У тебя мой знак, значит, у тебя есть потенциал учиться по-настоящему слушать" " песню. Да, пока что я помогу тебе своими умениями." @@ -210119,11 +212527,6 @@ msgstr "Приятно слышать. Тогда пойдём." msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "Отлично, но прямо сейчас мне нужно идти одному. Может, потом." -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "Я понимаю твои сомнения. Возвращайся, когда увидишь путь." - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "Может, в другой раз. Давай сменим тему…" @@ -210135,14 +212538,14 @@ msgstr "Ладно, но мне пора." #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" "Дело не в том, что Катаклизм принёс бродячие ужасы и чудовищ. Он начал… " "цикл, какой-то цикл. Всё повторяется. Это можно видеть только в других, но " @@ -210182,6 +212585,14 @@ msgstr "Забудь мой вопрос." msgid "Skip it, let's get going." msgstr "Забей, давай идти дальше." +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "Не дашь совет насчёт мира, в которым мы теперь живём?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "Давай поговорим о лагерях." + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "Что ты имел ввиду под этим, «в основном», пойти за мной?" @@ -210394,7 +212805,7 @@ msgstr "Расскажи, как давать тебе медицинские п #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -210600,9 +213011,9 @@ msgstr "Привет, ." #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." -msgstr "СТОЯТЬ, руки вверх! Ха, испугался?… Закона больше нет…" +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" +msgstr "СТОЯТЬ, руки вверх! Ха, страшно?… Закона больше нет…" #: lang/json/talk_topic_from_json.py msgid "What are you doing here?" @@ -210623,9 +213034,9 @@ msgstr "Мне пора." #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "" -"Я дежурил в участке, когда что-то пошло не так. Никто из остальных " +"Было моё дежурство в участке, когда что-то пошло не так. Никто из остальных " "полицейских не вернулся с последнего вызова, точнее, не вернулся человеком…" #: lang/json/talk_topic_from_json.py @@ -210683,7 +213094,7 @@ msgstr "" "иногда появляется странник, уверенный, что найдёт лучшую долю." #: lang/json/talk_topic_from_json.py -msgid "No, just no..." +msgid "No, just no…" msgstr "Нет, просто, , нет…" #: lang/json/talk_topic_from_json.py @@ -210695,7 +213106,7 @@ msgid "Make it quick, I want to go back to sleep." msgstr "Давай быстрее, мне нужно идти спать." #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." +msgid "Just few minutes more…" msgstr "Ещё пару минут…" #: lang/json/talk_topic_from_json.py @@ -210744,6 +213155,70 @@ msgstr "Я хочу дать тебе боевые команды." msgid "I want to set some miscellaneous rules." msgstr "Я хочу установить прочие правила." +#: lang/json/talk_topic_from_json.py +msgid "I'd like to know a bit more about your abilities." +msgstr "Мне б хотелось побольше узнать про твои способности." + +#: lang/json/talk_topic_from_json.py +msgid "There's something I want you to do." +msgstr "Я хочу, чтобы вы кое-что сделали." + +#: lang/json/talk_topic_from_json.py +msgid "I just wanted to talk for a bit." +msgstr "Я просто хочу немного поговорить." + +#: lang/json/talk_topic_from_json.py +msgid "Can you help me understand something? (HELP/TUTORIAL)" +msgstr "Можешь помочь мне понять кое-кто? (ПОМОЩЬ/ОБУЧЕНИЕ)" + +#: lang/json/talk_topic_from_json.py +msgid "I'm going to go my own way for a while." +msgstr "Всё, дальше я сам. Я ухожу." + +#: lang/json/talk_topic_from_json.py +msgid "Let's go." +msgstr "Пошли." + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" +msgstr "" +"*щёлк* Ты серьёзно? Это ж не мобильник. Это не может подождать, пока мы " +"рядом не окажемся?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what did you want to say?" +msgstr "Конечно, что у тебя на уме?" + +#: lang/json/talk_topic_from_json.py +msgid "Mind if we just chat for a bit about your history?" +msgstr "Не против немного поболтать про твою историю?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's just chitchat for a while, I could use some relaxation." +msgstr "Давай просто поболтаем, мне не помешает расслабиться." + +#: lang/json/talk_topic_from_json.py +msgid "I changed my mind, wanted to ask you something else." +msgstr "Проехали, хочу тебя кое о чём другом спросить." + +#: lang/json/talk_topic_from_json.py +msgid "I'm all ears, my friend." +msgstr "Внимательно слушаю, друг мой." + +#: lang/json/talk_topic_from_json.py +msgid "You gonna give me orders?" +msgstr "Будешь давать мне приказы?" + +#: lang/json/talk_topic_from_json.py +msgid "What would you like?" +msgstr "Что вы бы хотели?" + +#: lang/json/talk_topic_from_json.py +msgid "Just say the word." +msgstr "Только скажи." + #: lang/json/talk_topic_from_json.py msgid "Can you teach me anything?" msgstr "Ты можешь меня чему-нибудь научить?" @@ -210768,14 +213243,6 @@ msgstr "Охраняй эту позицию." msgid "I want to assign you to work at this camp." msgstr "Я хочу дать тебе работу в этом лагере." -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." -msgstr "Давай поговорим о твоём текущем занятии." - -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "Давай поговорим о лагерях." - #: lang/json/talk_topic_from_json.py msgid "Find a horse and mount up!" msgstr "Найди лошадь и садись верхом!" @@ -210789,32 +213256,20 @@ msgid "Please go to this location." msgstr "Пожалуйста, иди вот в это место." #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." -msgstr "Мне б хотелось побольше узнать про твои способности." - -#: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" -msgstr "Не дашь совет насчёт мира, в которым мы теперь живём?" - -#: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" -msgstr "Не против немного поболтать про твою историю?" - -#: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." -msgstr "Давай просто поболтаем, мне не помешает расслабиться." +msgid "I want you to build a camp here." +msgstr "Я хочу, чтобы ты построил здесь лагерь." #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." -msgstr "Расскажи насчёт отдавания приказов (ОБУЧЕНИЕ НПС)." +msgid "We need to abandon this camp." +msgstr "Мы бросаем этот лагерь." #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "Всё, дальше я сам. Я ухожу." +msgid "Show me what needs to be done at the camp." +msgstr "Покажи, что нужно сделать в лагере." #: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "Пошли." +msgid "Let's talk about your current activity." +msgstr "Давай поговорим о твоём текущем занятии." #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." @@ -211370,10 +213825,6 @@ msgstr "Пожалуйста, иди вот в это место…" msgid "Stay at your current position." msgstr "Оставайся на том же месте." -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "Покажи, что нужно сделать в лагере." - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "Сейчас моё занятие — ." @@ -211446,69 +213897,6 @@ msgstr "*пшшш-пшшш* принято, выдвигаюсь, приём." msgid "Sure thing, I'll make my way there." msgstr "Хорошо, я выдвигаюсь туда." -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "" -"Ох, эта летняя жара меня доконает, давай быстренько передохнём, , " -"как у тебя-то дела?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "" -"Ладно, пусть это поможет мне не замёрзнуть при такой погоде. Как дела?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "Что ж, как раз подходящее время немного отдохнуть! Как у тебя дела?" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "Блин, тут же так темно? Что случилось?" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "Ну, мне не совсем хорошо… А у тебя там всё нормально?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "" -"Конечно, и кстати, спасибо тебе, ты мне столько помогаешь! Ладно, , " -"всё нормально?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "" -"ОК, давай на минутку, о, и спасибо за помощь с тем делом, так что… Как дела?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "" -"Сейчас у нас есть минутка, я просто размышлял, уже прошёл месяц или типа " -"того с тех пор… С тех пор, как всё случилось, как ты справляешься со всем " -"этим?" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "О, ну, типа, неплохо, неплохо…" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -211563,7 +213951,7 @@ msgid "Hello there." msgstr "Привет." #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." +msgid "Okay, no sudden movements…" msgstr "Ладно, не делай резких движений…" #: lang/json/talk_topic_from_json.py @@ -211924,7 +214312,7 @@ msgid "Ah, okay." msgstr "Ну, ладно." #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." +msgid "Not until I get some antibiotics…" msgstr "Не раньше, чем я получу антибиотики…" #: lang/json/talk_topic_from_json.py @@ -212032,8 +214420,8 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "Я не могу тебя учить, когда я за рулём!" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." -msgstr "Дай мне немного времени, и я научу тебя чему-нибудь еще…" +msgid "Give it some time, I'll show you something new later…" +msgstr "Дайте мне немного времени, и я вам покажу что-то новое…" #: lang/json/talk_topic_from_json.py msgid "I have some reason for denying you training." @@ -212060,7 +214448,7 @@ msgid "See you around." msgstr "Увидимся." #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." +msgid "I really don't feel comfortable doing so…" msgstr "Мне действительно это неудобно…" #: lang/json/talk_topic_from_json.py @@ -212132,8 +214520,8 @@ msgid "Thanks, see you later!" msgstr "Спасибо, позже увидимся!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." -msgstr "Ты взял(а) кое-что чужое…" +msgid "You picked up something that does not belong to you…" +msgstr "Ты берёшь кое-что чужое…" #: lang/json/talk_topic_from_json.py msgid "Okay, okay, this is all a misunderstanding. Sorry, I'll drop it now." @@ -212228,13 +214616,13 @@ msgid "You might be seeing more of me…" msgstr "Думаю, мы ещё встретимся…" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" +msgid "Hey again. *kzzz*" msgstr "Снова привет. *жжж*" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "" "Я… Я свободен. *Жжжт* Я действительно свободен! *бжжж* Слушай, ты первый " "человек, которого я вижу за долгое время." @@ -212258,7 +214646,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "Прости, я никто. Наслаждайся свободой, наверно." #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "*жжж* Отлично! И что будет дальше?" #: lang/json/talk_topic_from_json.py @@ -212271,7 +214659,7 @@ msgstr "Наши пути расходятся. Наслаждайся своб #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "" "…Погоди. *БИИП*. Почему я должен тебе верить? *ЗЗЗТ* Ты можешь быть таким же" @@ -212299,7 +214687,7 @@ msgstr "Забудь. Наслаждайся свободой." #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" msgstr "" "Ладно, ладно, *ЖЖЖ* прости! Не делай мне больно! Что угодно, только не чип!" @@ -212316,7 +214704,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "Нет, *ты* прости, я не хотел тебя обидеть. Иди, делай что хочешь." #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "…убить… *ЗЖЗЖЗЖЗ* …тебя!" #: lang/json/talk_topic_from_json.py @@ -212351,14 +214739,6 @@ msgstr "Расскажи мне, как работают лагеря." msgid "Tell me how faction camps have changed." msgstr "Расскажи, как поменялись лагеря." -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "Я хочу, чтобы ты построил здесь лагерь." - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "Мы бросаем этот лагерь." - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "Ничего. Давай поговорим о чем-нибудь ещё." @@ -212643,8 +215023,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." -msgstr "Уверен? Непохоже, чтоб тут было особенно безопасно, чтоб поболтать…" +"talk…" +msgstr "Серьёзно? Непохоже, чтоб тут было особенно безопасно, чтоб поболтать…" #: lang/json/talk_topic_from_json.py msgid "It's fine, we've got a moment." @@ -212666,6 +215046,50 @@ msgstr "О чём ты хотел поговорить?" msgid "Actually, never mind." msgstr "Вообще-то забудь." +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr " " + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "Да, друг?" @@ -212687,7 +215111,7 @@ msgid "May the earth flourish beneath our paths." msgstr "Пусть земля цветёт под нашими путями." #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "Единство духа, разума и тела…" #: lang/json/talk_topic_from_json.py @@ -212898,13 +215322,13 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" -"Я вырос на ферме, не знаю ничего такого о призраках и гоблинах, я просто " -"провожу время за фермерством и работаю упорно. В глуши лучше, чище. Не так " -"опасно. Надеюсь." +"Моё детство прошло на ферме, не знаю ничего такого о призраках и гоблинах, я" +" просто провожу время за фермерством и работаю упорно. В глуши лучше, чище. " +"Не так опасно. Надеюсь." #: lang/json/talk_topic_from_json.py msgid "Hey, I didn't expect to live long enough to see another living human!" @@ -213506,7 +215930,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "Не обращай внимания, я уже ухожу." #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "И это, конечно же, Я! Единственный и неповторимый ПОЕШЬ-КА!" #: lang/json/talk_topic_from_json.py @@ -214019,6 +216443,53 @@ msgstr "" msgid "Huh." msgstr "Ага." +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "" +"Я едва ли понимаю, что происходит *сейчас*. Почему тебе кажется, что я " +"помню, как наступил конец света?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "" +"Ладно, хорошо. Можешь рассказать мне, что ты помнишь о событиях, которые " +"привели к нынешней ситуации?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" +"Что, ты не помнишь что ли? Ладно, извини, зря я так, времена то необычные. " +"Так, что ж, думаю, всё началось с беспорядков, верно? Мы жили себе, ходили " +"на работу там, и затем люди стали бунтовать. Не как обычные протесты, " +"вышедшие из под контроля, нет, люди просто выходили из своих домов и " +"начинали крушить всё подряд. В новостях пытались притушить истерику, но вот " +"в интернете всё разлеталось мгновенно. Не знаю, что вызвало это, говорили, " +"что какой-то токсин в воде? В любом случае, мне тогда было непонятно, как " +"всё плохо. В какой-то момент участники беспорядков начали вставать и " +"расхаживать с дырками в груди, и вот тогда началась настоящая паника. " +"Следующие несколько дней - а может и недель - прошли в тумане. Придётся тебе" +" ещё кого-то спросить, как мы дошли из той точки и до полного коллапса." + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "Спасибо за рассказ." + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -214094,19 +216565,19 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" -"Да, в какой-то момент. Несколько часов стояла тишина. Меня мучила жажда, я " -"был ранен и перепуган. От полной паники меня удерживала, наверно, только моя" -" подготовка. Я решил вылезти и посмотреть, насколько сильно я ранен. Это " -"было просто. Боковина фургона была разорвана, и я, как оказалось, " -"лежал просто под кучкой мелких обломков, а остатки фургона нависали надо " -"мной. Меня даже не очень-то задело. Я схватил столько снаряжения, сколько " -"смог, и выскользнул. Стояла ночь. Я слышал отзвуки сражения в глубине " -"города, так что пошёл в другую сторону. Я одолел несколько кварталов, и тут " -"мне встретились … Я убежал от них. Я бежал, и бежал, и бежал ещё " -"дальше. И вот теперь я здесь." +"Да, в какой-то момент. Несколько часов стояла тишина. Меня мучила жажда, " +"раны, было жутко страшно. От полной паники меня удерживала, наверно, только " +"моя подготовка. Мне пришло в голову вылезти и посмотреть, насколько сильно " +"меня ранили. Это было просто. Боковина фургона была разорвана, и я, " +"как оказалось, под кучкой мелких обломков, а остатки фургона нависали надо " +"мной. Меня даже не очень-то задело. Схватив столько снаряжения, сколько " +"вышло, я смылся оттуда. Стояла ночь. Мне было слышно звуки сражения в " +"глубине города, так что пришлось двигаться в другую сторону. Спустя " +"несколько кварталов мне встретились … Получилось убежать от них. " +"Пришлось бежать, бежать и бежать ещё дальше. И вот теперь я здесь." #: lang/json/talk_topic_from_json.py msgid "" @@ -214478,6 +216949,41 @@ msgstr "Бедняга Грязный Дэн. " msgid "Thanks for telling me that stuff. " msgstr "Спасибо, что рассказал. " +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" +"Ну так, ээ, там были жуткие беспорядки, да? Все стали агрессивными и " +"жесткими, и сказать по честному, у меня был разгар, эээ, духовного " +"путешествия большую часть, и я мало что помню. Но самое странное - никому " +"больше не было дела до других. Будто всю эмпатию из людей высосало. Мне " +"кажется, это была какая-то негативная энергия. И она же, типа, заставила " +"мёртвых восстать. И до кучи, там типа были монстры какие-то? Даже не знаю, " +"как они сюда попали." + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "Кажется, ты много знаешь, что, по твоему, всё это вызвало?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" +"Сложный вопрос, но я всё вспоминаю сон, который снился мне за год до всех " +"событий. Снилось, что огромный шар злой энергии ждал возможности высосать " +"всё хорошее с Земли и превратить нас в монстров и тому подобное. Думаю, так " +"и произошло. Всё остальное кажется совсем уж надуманным, понимаешь?" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -214546,6 +217052,38 @@ msgstr "" "своё убежище, оно падало на костяного ублюдка. Он подох при обвале, " "насколько я знаю, но я не собираюсь проверять." +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" +"Что произошло? Точно даже и не знаю. Уверен, тебе приходилось слышать о " +"беспорядках и всём таком, и что правительство не смогло с этим справиться. У" +" меня нет идей, как до такого дошло. Поначалу казалось, всё как обычно, и " +"нужно признать, начало революции меня пугало и волновало. Но у меня не " +"хватало духа присоединиться, а если подумать теперь, те, кому хватило, уже " +"мертвы. Так что приходилось отсиживаться дома, даже собрать небольшую " +"экстренную сумку. Затем в интернете появились видео, где участники " +"беспорядков встают и продолжают драться с ужасными ранами. Не знаю, сколько " +"людей смогли в это сразу поверить, но мне удалось увидеть дурной знак, и вот" +" я в эвакуационном убежище за городом. Не знаю, что происходило после этого." +" Центр эвакуации оказался разграбленным, и после мне никто не встречался. " +"Сотовая связь пропала, за исключением экстренного сообщения на следующий " +"день о том, что правительство пало. Через несколько дней отрубилось и " +"электричество." + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -214595,6 +217133,32 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "Как ты думаешь, что произошло? Видел ли ты кого-нибудь?" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" +"Ну, полагаю, тебе известно о беспорядках, армии и полиции, а ещё грёбаных " +"монстрах, что теперь ходят по земле вместе с зомби, да? Если ты спрашиваешь," +" что всё это вызвало, ну, я хз. Моя лучшая идея - правительство " +"перестаралось с чем-то, может, какое-то биологическое оружие вышло из под " +"контроля. Они столько врали с самого начала обо всём, думаю, даже всё это " +"«нападение Китая» было брехнёй. Они пытались замести какие-то следы. Что " +"касается всего прочего, может, остальной мир пытается сдержать это. " +"Приходилось даже слышать, что ядерные боеголовки рвались прямо здесь, на " +"американской земле. Для меня это может значить, что где-то ещё, в Европе " +"например, пока сдерживают то, что происходит. Может, у них даже получается. " +"Сейчас дела плохи, но до этого было куда хуже." + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -214671,6 +217235,60 @@ msgstr "" "особых проблем. Я устроил несколько убежищ, собирал ягоды и много чего ещё, " "и в целом жил отличной жизнью по сравнению с первыми месяцами." +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" +"Вау, , не знаю, с чего и начать. Беспорядки? Думаю, началось раньше." +" Ходили всякие плохие слухи за несколько недель до них. Куча реально жутких " +"преступлений, не что обычно, а прям каннибализм и прочая невообразимая жуть," +" сечёшь? Когда начались беспорядки, думаю, мне сразу стало видно, что это не" +" обычные митинги за равноправие или вроде того. Думаю, так мне и удалось " +"безопасно выбраться оттуда, у меня было время подготовиться, найти всё " +"нужное и не выбираться за покупками. Люди были абсо-блять-лютно " +"ненормальными в те дни. Очень похоже на ту пандемию несколько лет назад, " +"только полиция была на улицах и не сдерживалась, стреляя по людям так, будто" +" завтра не наступит." + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "У тебя есть мысли насчёт того, что было настоящей причиной?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" +"Не то чтобы. Правительство вешало нам на уши кучу противоречивых заявлений, " +"и определённо происходило нечто совершенно отвратительное. Я имею в виду, " +"тебе явно приходилось видеть то видео, где женщина убивает своего ребёнка, " +"да? Боже, до сих пор кошмары от этого. Не знаю даже, почему, наверное, что-" +"то в выражении её лица. Конечно, происходили и более страшные вещи, и мы " +"видели некоторые из них, но то меня до сих пор преследует. Так или иначе, им" +" не удалось сдержать беспорядки, и когда мёртвые стали восставать, было уже " +"слишком поздно. Не знаю, был ли то упадок боевого духа или ещё что, но были " +"слухи, что полиция и армия вступают в стычки между собой не реже, чем с " +"бунтующими. Что заставило мертвецов восстать к жизни? Я без понятия." + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -214683,6 +217301,73 @@ msgstr "" "пассажирами, так что я сделал то, что сделал бы каждый, и съебался нахер " "оттуда." +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "Ну не тяни, что же было дальше?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" +"Мне пришлось бежать, пока лёгкие не начали выпрыгивать из груди. Получилось " +"найти тихое местечко в лесу, под елью. С утра до меня донеслись чьи-то " +"слова, так что мне пришло в голову сходить посмотреть. Аккуратно, конечно, " +"тогда вокруг ещё было полно психов и протестующих. И вот вижу я какую-то " +"дрянь, страшнее любого зомби. Огромная жукоподбная хрень, повторяющая " +"случайные фразы, будто сломанный диктофон. Она волокла за собой несколько " +"тел, и было непонятно, мертвы ли они или просто без сознания. Честно говоря," +" не хотелось проверять, так что пришлось отсидеться в кустах, пока эту тварь" +" не перестало быть слышно." + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "Что с тобой было после?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" +"Когда прятки в кустах закончились, мне попалась в стороне от дороги старая " +"хижина. Она разваливалась, но защищала от дождя и ветра и была не на виду. " +"Пока у меня не кончились эти говённые рационные батончики, удавалось в ней " +"отсидеться. Затем, до нашей с тобой втречи, большая часть времени прошла в " +"путешествиях." + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" +"Что это, как в Назад в будущее? Как можно не знать, что произошло? Наступил " +"конец света, конечно. И началось всё не с землетрясения, птиц, змей или " +"самолётов. Началось всё с беспорядков, и им пришлось высылать полицию, а " +"затем и армию, чтобы разобраться, , с преступниками. Правительство " +"пыталось оправдать это, говоря о каком-то контроле разума, но по мне, всё " +"это было брехнёй, как и обычно - богатые засранцы ищут повод нарушить закон." +" Только в этот раз всё было куда хуже чем обычно. Были даже слухи, что они " +"бомбили городские центры, чтобы сдержать распространение - что уже перебор, " +"как по мне." + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -214734,6 +217419,36 @@ msgstr "Прости. Можешь рассказать мне ещё?" msgid "Right. Sorry." msgstr "Точно. Прости." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" +"Ладно, слушай. Не верь лжи правительства. Есть кое-что, объединяющее всё " +"происходящее: беспорядки, армию, что не может их сдержать, даже гигантских " +"монстров, что появились недавно, и которых пришлось уничтожать с помощью " +"ядерного оружия." + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "Я тебя внимательно слушаю." + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" +"Приходилось видеть Матрицу? Это она. Самая настоящая. Чтобы удерживать нас " +"внутри, создателям симуляции нужно содержать нас в достаточном уровне " +"недовольства. Думаю, их алгоритмы выдали что-то не то, заработав на полную " +"мощность, так как всё происходящее уже чересчур. И всё же же мы по прежнему " +"подключены, так что видимо, она работает." + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -214754,6 +217469,27 @@ msgstr "" "несколько дней спустя, но убежище было совершенно пусто. Без понятия, что " "стало с теми людьми." +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" +"Скажу тебе честно, довелось услышать много всего в убежище, и кое-что запало" +" в память. Всё это вышедший из под контроля научный эксперимент. Не знаю, " +"почему начались беспорядки, а мёртвые стали возвращаться к жизни, но не " +"может быть, чтобы это повсюду вышло из под контроля. Да, мне тоже пришло " +"уведомление, как и всем, мол, правительство пало, но нет никакого смысла в " +"таком быстром распространении. Думаю, мы в какой-то отрезанной зоне, и она " +"позволяют делам идти как идут, чтобы знать, чего ожидать в следующий раз. " +"Где-то там, за пределами этой зоны, дела всё ещё идут по старому." + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -214849,6 +217585,58 @@ msgstr "Извини, что спрашиваю. " msgid "Sorry for asking. " msgstr "Извини, что спрашиваю. " +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "" +"Фуф, хочешь всерьёз? Это, , правительство с нами сделало. Намеренно, " +"по крайней мере отчасти." + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "А?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" +"Точно говорю. Они врали нам бог знает сколько, не хотели, чтобы мы поняли, " +"что происходит. Наверное, сначала было с благими намерениями, чтобы сдержать" +" людей, но как-то вышло боком. Моё предположение - они пытались обмануть " +"нас, сокрыть знание, а когда не вышло, они реально добавили наркотики в воду" +" или ещё что-то такое сделали, чтоб мы отупели. И вместо того, чтоб " +"поглупеть, люди стали агрессивнее. Они пытались использовать это, чтобы " +"ввести военное положение, но не сработало, и им уже пришлось сражаться с " +"ордами людей. Только они не поняли, что их, , мозговые наркотики были" +" ещё и каким-то мутагеном, превращающим людей в зомби." + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "А что насчёт всего остального?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" +"Думаю, в основном мутации. Не знаю, чем они пользовались, но похоже, реально" +" что-то в духе изобретений безумных учёных, мне даже и в голову не " +"приходило, что такое возможно. Ещё мне любопытно, не свело ли нас всех с ума" +" то, что они добавили в воду. Может быть всё это просто галлюцинации? Это " +"мне вообще башку срывает, но я уже не знаю, во что ещё верить." + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -215681,6 +218469,62 @@ msgstr "" "леса искать пропитание. Получалось не очень-то хорошо, так что я типа рад, " "что мы встретились." +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" +"Так, выслушай меня. Прозвучит безумно, но мы тут, , имеем дело с " +"ходячими мертвецами, так что мои идеи тоже прокатят. Тебе хорошо знакома " +"греческая мифология?" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "Не очень хорошо. Какое она к этому имеет отношение?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "Ага, а что?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" +"Ладно, знаю, что прозвучит как идиотский сценарий для фильма про Индиану " +"Джонса, но думаю, кто-то нашел Ящик Пандоры или нечто очень похожее. И " +"думаю, они пытались обуздать её мощь, чтобы использовать для себя. Может " +"даже ради чего-то хорошего, как знать, энергия богов мне кажется вполне " +"экологичным источником энергии. Как бы там ни было, они облажались и открыли" +" её на всю. Не метафорически, а буквально, они выпустили всё воинство Аида " +"на Землю. Знаю, это натянуто, но как и говорили - моё объяснение прокатит с " +"учётом обстоятельств." + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "Чего? Ящик Пандоры?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" +"В легендах Пандора была в жилище богов и нашла закрытый ящик. Она решила " +"узнать, что в нём, о когда открыла, из неё вышли неописуемые ужасы и " +"болезни. Не кажется знакомым?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "Ага, и как это с чем-либо связано?" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -215747,6 +218591,189 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "Спасибо, что поделился рассказом. " +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" +"Ты о том, что вызвало все эти беспорядки и прочее? Ну, они говорили, что это" +" китайское биологическое оружие, но что-то мне не верится, что кто-то мог " +"создать оружие, способное на такое. Единственный ответ, который мне в голову" +" приходит - инопланетяне, как бы это глупо не звучало." + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "Ты думаешь? это вторжение?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" +"Ну, может и так, но мне кажется, всё это слишком неорганизованно для " +"настоящего вторжения. Я вот думаю, что-то было заперто под полярными льдами." +" Помнишь, например, как несколько лет назад в интернете обсуждали тело " +"инопланетянина, найденное во льду? В общем, помнишь или нет, но это по всем" +" новостям крутили, пока не обнаружилось, что это подделка. Вот только с тех " +"пор я видел ещё несколько инопланетян, точно таких же, как то тело из-подо " +"льда. Может то была подделка, а может и прикрытие. Так вот, может у этих " +"инопланетян был какой-то вирус. Он распространился по миру и незаметно " +"заражал всех, пока почему-то не активировался и не вызвал насилие, мутации и" +" появление монстров." + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" +"Не будем ходить во круг да около - беспорядки не обошлись и без моего " +"участия. Сложно вспомнить, что у меня тогда в голове было. Раньше " +"приходилось протестовать против полицейского насилия и всего такого, но в " +"этот раз всё было по другому. У меня не было плаката, желания скандировать и" +" маршировать, у меня была бита и желание разносить всё подряд. Никогда " +"раньше не бывало такой ярости. Беспорядки уже шли какое-то время к тому " +"моменту, и для меня всё выглядело так, будто правительство опять пытается " +"прижать людей." + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "У участников беспорядков появилась репутация законченных психов." + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "Очень немногие выбрались из беспорядков живыми." + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" +"Да уж, можешь мне не рассказывать. Бунтующие… они уже даже людьми не были, " +"не что протестующими. Мне такого не доводилось видеть. И меня это не " +"остановило. Мои действия были ничуть не лучше, чем у остальных. Разбитые " +"окна, побитые прохожие, сожжённые машины. Помню, мы сорвали броню с " +"полицейского и… неважно. Не хочу даже вспоминать." + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "Как тебе удалось выжить?" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "Что заставило тебя выбраться оттуда?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" +"В какой-то момент было словно пробуждение. Это было примерно тогда, когда " +"выпустили армейские джипы с турелями для подавления беспорядков на крыше. " +"Что хорошо показывает моё состояние на тот момент - мне даже не удаётся " +"вспомнить, попадались ли они мне до того момента. В общем, моих ушей " +"достигли звуки стрельбы, и меня как-то осенило, что я на краю толпы, " +"нападающей на тяжело вооружённый армейский блокпост. Тогда то мне и стала " +"видна опасность толпы - словно испуганные животные, а ещё зомби. Оставалось " +"только развернуться и бежать прочь." + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" +"Честно говоря, не знаю. Любопытно, пришли ли бы в себя остальные, будь у них" +" время. Не думаю, что во мне есть что-то особенное. Может, многие из них и " +"пришли, но были в глубине толпы в этот момент. Точно говорю, стоило мне " +"прийти в себя, и мне стало видно - многие смотрели на меня как на добычу. " +"Конечно, с моей стороны было мудро не оставаться там, чтобы выяснить, что " +"будет дальше." + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" +"Город мне был хорошо знаком. Мне удалось спрятаться в знакомом мне " +"заброшенном здании, залезть через разбитое окно и отсидеться внутри " +"несколько дней. У меня был запас украденной еды, так что с этим проблем не " +"было. Когда всё подутихло, пришло время смыться оттуда подальше, и вот я " +"тут." + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" +"Ну, я помню время перед беспорядками, как и любой выживший, наверное. Всё " +"было очень плохо, в новостях постоянно показывали кошмарные вещи, и из-за " +"полицейской жестокости было полно межрасовой напряженности. Затем люди стали" +" бунтовать, ничего неожиданного, но вот места, где вспыхивали беспорядки - " +"это странно. Например, в богатых загородных районах, в маленьких городках на" +" Среднем Западе, такие дела. В общем, без моего участия беспорядки не " +"обошлись, но после этого я мало что хорошо помню." + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "Без твоего участия не обошлось?" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "Может, у тебя есть своя перспектива изнутри на всё произошедшее." + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" +"Ну да, в каком-то смысле. Вроде как люди говорили, что беспорядки начались " +"из-за влияющих на рассудок наркотиков, и честно говоря, это не кажется мне " +"таким уж маловероятным. По крайней мере мои ощущения с этим совпадают, хотя " +"ощущения всё время были вполне обычные. Пока что-то не щёлкнуло, мне всё " +"казалось совершенно нормальным. Вот только это не объясняет всё остальное - " +"зомби, монстров, все они вообще никуда не вписываются. Всё, что мне " +"приходило в голову, звучит как дешёвая фантастика, вроде демонических " +"проклятий или нападения пришельцев." + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -216113,19 +219140,68 @@ msgstr "" msgid "I can respect that." msgstr "Я понимаю." +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "Мне не очень-то хочется говорить о произошедшем, понимаешь?" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "Можешь не погружаться в детали, но прошу, расскажи мне хоть что-то?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" +"Я - а, ладно. Наркотики в грунтовых водах, может какое-то биологическое " +"оружие, мне кажется. Ты в курсе, как шли дела с Китаем, их почти за всё " +"винили. Были беспорядки. Близкие мне люди участвовали в них, и боюсь, мне " +"уже не узнать, почему. Беспорядки вызвали реакцию со стороны полиции и " +"армии, и дела пошли ещё хуже. Затем появились все эти монстры и кошмары, " +"словно наступил настоящий Армагеддон, и все умерли, а затем стали " +"возвращаться как смахивающие на прошлых себя монстры. Вот тебе история. Если" +" хочется узнать больше, то поговори с кем-нибудь ещё." + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "Спасибо." + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" +"Честно… Я даже не помню. Я смутно помню свою жизнь ещё до того, как мир " +"изменился, но про сам ? Всё как в тумане. Я не знаю, как мне " +"удалось выжить, или вообще как всё произошло. Помню кое-какие фрагменты: " +"вспышки насилия, женщину, убившую своего ребёнка. Чувствую, что лучше бы и " +"не вспоминать." + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" "Честно… Я даже не помню. Я смутно помню свою жизнь ещё до того, как мир " "изменился, но про сам ? Всё как в тумане. Я не знаю, как мне " "удалось выжить, или вообще как всё произошло. Со мной, наверно, произошло " -"что-то плохое. Или я очень сильно ударился головой. Или всё сразу. Похоже, " -"всё сразу." +"что-то плохое. Или меня очень сильно ударили по голове. Или всё сразу. " +"Похоже, всё сразу. Первое, что я помню - прочтённое сообщение от системы " +"экстренного оповещения о том, что Штаты пали." #: lang/json/talk_topic_from_json.py msgid "" @@ -216245,6 +219321,59 @@ msgstr "" "Тот, кем я был, умер. Мёртв. Меня не ебёт твоё «нормально», не спрашивай " "больше, ." +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" +"Ты спрашиваешь, знаю ли я, что всё это вызвало? Это было во всех новостях. " +"Что-то про китайское биологическое оружие. Сначала было похоже на ту " +"пандемию несколько лет назад, но в этот раз формула была эффективнее. Может " +"даже чересчур. Да и неважно, вроде как им и самим досталось не меньше, и " +"никого не осталось. И поделом." + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "Можешь рассказать мне, что произошло на самом деле?" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "А что насчёт всего остального происходившего безумия?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" +"Ну, ты знаешь. Сначала бунты из-за наркотиков в грунтовых водах. Только вот " +"я думаю, мы все теперь знаем, что это был вирус. Полиция и военные сделали " +"всё возможное, чтобы успокоить беспорядки, но ни черта у них не вышло. Затем" +" вирус мутировал и стал возвращать мёртвых к жизни, словно в дешёвом кино, и" +" дела стали совсем плохи. Затем они выпустили огромных тварей, а может, " +"навели их на нас. Огромные неописуемые монстры… до сих пор мурашки от одних " +"мыслей. Однако, они были очевидно не созданы для боя, и армия быстро с ними " +"разобралась." + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" +"Что? Да ещё как! Они начали с биологического оружия и перешли к ядерному. " +"Только имеющееся оружие было куда хуже водородных бомб. Дядюшка Сэм " +"ухитрился отбиться от самого худшего, но это было его последним подвигом." + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -216623,10 +219752,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "" -"Уклонение от налогов. Я работал бухгалтером и помогал боссу по-умному " -"ворочать охрененными деньгами. Как выяснилось, недостаточно по-умному…" +"Уклонение от налогов. Я - бухгалтер, и мне приходилось помогать боссу по-" +"умному ворочать охрененными деньгами. Как выяснилось, недостаточно по-" +"умному…" #: lang/json/talk_topic_from_json.py msgid "" @@ -216862,6 +219992,44 @@ msgstr "" "увижу. Это всё, что мы с тобой можем, не так ли? Возможно, мы и есть " "кроткие, что Землю унаследуют. Хотя наши шансы мне не нравятся." +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" +". Всё же и так понятно, нет? Та… Та катастрофа, это было Вознесение. Я всё " +"ещё здесь, и я всё еще не понимаю, почему. Я буду хранить Иисуса в своём " +"сердце в грядущих временах Великой Скорби. Когда времена пройдут, я уверен, " +"Он пригласит меня в Рай. Или… или в таком духе." + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "Я говорю насчёт самих событий. Что произошло?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" +"Ох. Ладно, думаю, это прям как написано в Откровениях, если я верно помню. " +"Давненько не было шанса поговорить с моим духовником. Значит, были напасти… " +"первая несколько лет назад, та большая пандемия, после которой заговорили " +"про конец света. Затем кровавая напасть, ну насилие? Это были беспорядки. " +"Затем моря покраснели от крови - из-за всех убитых. Затем напасть огненная, " +"это я точно помню, когда везде падали бомбы, и все взрывалось в попытках " +"унять беспорядки. Затем демоны и монстры стали ходить по Земле, и мёртвые " +"восстали, и затем кроткие унаследовали Землю. Ясно как день." + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -216872,6 +220040,34 @@ msgstr "" "Вознесение прошло, а я остался. Так что теперь я буду бродить по Аду на " "Земле. Хотелось бы мне с большим рвением посещать воскресную школу." +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" +"Ну, мне кажется, это было Вознесение. Оно прошло не так, как, мне казалось, " +"должно. Мне говорили, что будет как вспышка света и пуф - никого не " +"осталось. Вместо этого всё было очень грязно и беспорядочно. Беспорядки на " +"улицах, полицейские и армия в услужении Антихристу, косящие людей налево и " +"направо - как говорил мой отец - словно зерна и плевела вместе. Затем, когда" +" наш Грех стал особенно очевиден, Господь ниспослал настоящие казни. Мёртвые" +" стали ходить, вставая после ран от пулемёта, и военные стали сражаться " +"между собой. После этого пришли сами легионы Ада. Огромные твари, хуже, чем " +"можно себе вообразить, и они просто разносили города по камешку. Затем они " +"умерли так же быстро, как и появились, и нам осталось только убегать и " +"прятаться от мертвецов. Спустя день-два стало отключаться электричество." + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -217158,10 +220354,6 @@ msgstr "Каково было работать на Свободных Торг msgid "What was working for the Old Guard like?" msgstr "Каково было работать на Старую Гвардию?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "Спасибо." - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "Спасибо. Пойдем дальше." @@ -217470,6 +220662,29 @@ msgstr "" msgid "What were you saying before that?" msgstr "О чём мы там говорили?" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" +"Скажу как есть, моё внимание было приковано к подготовке к свадьбе, а не " +"событиям того времени. Мне было известно о беспорядках, но в моём городе их " +"не было. Даже когда они стали приближаться, хотелось игнорировать их, чтобы " +"отпраздновать наш большой день. Когда появились зомби, вот тогда дела пошли " +"вразнос. Когда мне пришлось убегать со свадьбы, небеса разверзлись, и из " +"дыры посыпались зомби, словно в том фильме про день независимости. Не знаю, " +"что это было, выглядело как чёрная магия или что-то в таком духе." + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "Привет." @@ -218066,7 +221281,7 @@ msgstr "" "Убирайся с моей фермы, я не буду говорить с чмошником из правительства." #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "Продолжай…" #: lang/json/talk_topic_from_json.py @@ -218540,10 +221755,6 @@ msgstr "" "Убирайся с моей земли, правительство показало свою никчёмность этой " "катастрофой." -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "Продолжай…" - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "Расскажи о своей жене, она где-то тут?" @@ -220253,13 +223464,13 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" -"Мерзко, правда? На ощупь как лобковые волосы. Начали расти везде вскоре " -"после Катаклизма. Без понятия, в чём причина. Я не осуждаю тех, кому это, я " -"и сам это ненавижу." +"Мерзко, правда? Ощущается, как волосня на лобке. Начало расти повсюду вскоре" +" после катаклизма. Без понятия, в чём причина. Я не осуждаю, что все это " +"ненавидят, я и сам ненавижу." #: lang/json/talk_topic_from_json.py msgid "" @@ -221136,7 +224347,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -222439,12 +225650,12 @@ msgstr "Как ты тут оказался?" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" "Из-за беременности нас с Даной рано эвакуировали. Они забрали нас в " "концентрационный центр и посадили на автобус, чтобы отвезти сюда. Но вот " @@ -222610,12 +225821,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" "Долгая, долгая история. Я не отсюда, я из Западной Канады. Мне всегда " "хотелось посмотреть Новую Англию, и я была тут в отпуске, пока не… ну, ты в " @@ -222704,7 +225915,7 @@ msgid "Hm? Oh, hi." msgstr "Ммм? А, привет." #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "…Привет." #: lang/json/talk_topic_from_json.py @@ -223149,8 +226360,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" "Даже когда мы со всем разобрались, у нас не хватало кроватей на всех, и уж " "точно не хватало еды. Времена были непростые. Мы делаем что можем для тех " @@ -223174,9 +226385,9 @@ msgstr "Что за неприятность с той комнатой?" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -223551,8 +226762,8 @@ msgstr "" "Мы не потерпим здесь такую мразь, как ты. Заканчивай свои дела и убирайся." #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." -msgstr "Я здесь не за главного. Поищи кого-нибудь другого." +msgid "I'm not in charge here, you're looking for someone else…" +msgstr "Я здесь не за главного. Поищи кого-нибудь другого…" #: lang/json/talk_topic_from_json.py msgid "Keep civil or I'll bring the pain." @@ -223599,11 +226810,11 @@ msgid "Well, I'd better be going. Bye." msgstr "Мне лучше идти. Пока." #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." +msgid "Welcome marshal…" msgstr "Добро пожаловать, маршал…" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." +msgid "Welcome…" msgstr "Добро пожаловать…" #: lang/json/talk_topic_from_json.py @@ -223912,11 +227123,11 @@ msgstr "" "догадаться, людей немного пугает перспектива встречи с ордой зомби." #: lang/json/talk_topic_from_json.py -msgid "Marshal..." +msgid "Marshal…" msgstr "Маршал…" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." +msgid "Citizen…" msgstr "Гражданин…" #: lang/json/talk_topic_from_json.py @@ -224618,7 +227829,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" "В текущих условиях мы можем продать наш комплект: противогаз, костюм и снаряжение со значительной скидкой. Цена — две наших монеты.\n" "\n" @@ -224819,15 +228030,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "Теперь мне тоже это кажется странноватым." #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." -msgstr "Раздумываю, что мне скоро пора на охоту…" +msgid "Thinking I should go hunt something soon…" +msgstr "Думаю, что мне скоро пора на охоту…" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "Мне интересно, переменится ли жизнь к лучшему…" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "Э? Ничего, мне просто нравится тут отдыхать." #: lang/json/talk_topic_from_json.py @@ -224873,7 +228084,7 @@ msgstr "Веди себя вежливо, наёмник." #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." +"marshal…" msgstr "" "На дорогах полно разбойников, наверно, стоит вернуться к работе, маршал…" @@ -224951,7 +228162,7 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "Я не могу даже представить, в чём ты можешь мне помочь." #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." +msgid "Stand still while I get my clippers…" msgstr "Стой спокойно, пока я орудую своими ножницами…" #: lang/json/talk_topic_from_json.py @@ -225393,8 +228604,8 @@ msgstr "" " проводят вне аванпоста." #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." -msgstr "Пожалуйста, оставь меня одного…" +msgid "Please leave me alone…" +msgstr "Пожалуйста, оставь меня в покое…" #: lang/json/talk_topic_from_json.py msgid "What's wrong?" @@ -225415,15 +228626,14 @@ msgstr "Это печально." #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." +"I don't know what you could do. I've tried everything. Just give me time…" msgstr "" "Я не знаю, что вы можете сделать. Я всё испробовал. Просто дайте мне время…" #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." +"seems like I can't keep anything down…" msgstr "" "Я всё болею! Сначала думал, что съел что-то не то, но теперь, кажется, я " "ничего не могу удержать…" @@ -225568,11 +228778,11 @@ msgstr "Я не хочу вступать к вам, в любом случае. #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "" "Здесь? Фрукты и ягоды. Может быть, некоторое сельскохозяйственное " -"оборудование, но тебе нужны крипто-коины" +"оборудование, но тебе нужны крипто-коины." #: lang/json/talk_topic_from_json.py msgid "Ok." @@ -225989,7 +229199,7 @@ msgstr "Добро пожаловать. Вы голодны, друг мой?" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "" "Вы выглядите так, будто вам не помешает поесть. Слишком много голода в мире." @@ -226186,7 +229396,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "Для меня счастье послужить великим едокам. Я в деле." #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "Превосходно. Сделайте всё, что необходимо." #: lang/json/talk_topic_from_json.py @@ -226367,7 +229577,7 @@ msgid "Oh, you again." msgstr "А, опять ты." #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "А? *невнятно бормочет* …Ты еще кто?" #: lang/json/talk_topic_from_json.py @@ -226375,8 +229585,8 @@ msgid "I'm busy, what is it?" msgstr "Я занят, в чем дело?" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." -msgstr "И оставить мою башню и мои исследования? Я так не думаю." +msgid "And leave my tower and all my research? I think not." +msgstr "И забросить мою башню и мои исследования? Я так не думаю." #: lang/json/talk_topic_from_json.py msgid "Ah, hello again." @@ -230838,260 +234048,31 @@ msgstr "" "или найти быстрый выход из Катаклизма." #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "земля" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "" -"Это земля. Подходит для пашни. Также её можно вскапывать для различных " -"строительных проектов." - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "стук" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "" -"Большой участок песка, который можно было бы использовать самыми различными " -"способами." - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "грязь" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "Мокрая скользкая грязь." - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "глина" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "" -"Участок, содержащий глинозём, пригодный для обжига печи, если был извлечён " -"должным образом." - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "насыпь глины" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "Холмик из глинистой почвы." - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "чавк!" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "песчаная насыпь" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "Песчаный холмик." - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "земляная насыпь" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "" -"Труднопроходимая земляная насыпь, если приглядеться, почва хорошо подходит " -"для посадки семян и тому подобного." - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "Гигантский земляной холм, похоже, вы можете укрыться внутри." - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "странный провал" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" -"Неестественная дыра напоминает своей формой человеческие очертания и кажется" -" странно знакомой. У вас странное желание исследовать её поближе, будто этот" -" объект как-то связан с вами." - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "могила" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "" -"Земляная могила с растущей на ней травой. Хоть кто-то из мёртвых " -"действительно покоится с миром." - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" -"Свежая могила, покрытая камнями, либо чтобы кто-то не раскопал ее, либо " -"чтобы кто-то не раскопался наружу. Две дощечки отмечают её как место чьего-" -"то упокоения." - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "каменный пол" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "" -"Сравнительно плоская площадка горной породы и камня. Выглядит достаточно " -"стабильно, чтобы заниматься добычей с помощью соответствующего горного " -"снаряжения." - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "асфальт" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." -msgstr "" -"Участок асфальта, медленно разрушающийся от трещин, морозов и отсутствия " -"ремонтных работ." - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "жёлтый асфальт" - -#. ~ Description for yellow pavement -#: lang/json/terrain_from_json.py -msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" -"Линии дорожной разметки аккуратно нанесены жёлтой краской на асфальт, служат" -" для сообщения информации участникам дорожного движения. Никто больше эти " -"правила не соблюдает." - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "тротуар" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "" -"Край проезжей части дороги, залитый бетоном, повреждён морозом и большими " -"трещинами из-за отсутствия обслуживания." - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "" -"Более новый залитый бетоном участок дороги с поверхностной отделкой для " -"красоты и устойчивости к циклам замораживания-таяния." - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "" -"Более новый залитый бетоном участок дороги с поверхностной отделкой для " -"красоты и устойчивости к циклам замораживания-таяния. Покрыт желтой краской." - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "деревянный пол" +msgid "overgrown floor" +msgstr "заросший пол" -#. ~ Description for wooden floor +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." msgstr "" -"Пол из плотно уложенных сбитых гвоздями деревянных досок. Такие часто бывают" -" на верандах." +"Голый бетонный пол, почти полностью покрытый подергивающимися отростками " +"сероватой плоти." #: lang/json/terrain_from_json.py msgid "SMASH!" msgstr "ГРОХОТ!" #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "металлический пол" - -#. ~ Description for metal floor -#: lang/json/terrain_from_json.py -msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." -msgstr "" -"Высококачественный прочный рифлёный пол для снижения риска скольжения и " -"падения." +msgid "overgrown wall" +msgstr "заросшая стена" -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "линолеум" - -#. ~ Description for linoleum tile +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." -msgstr "" -"Участок напольного покрытия из прочного пружинистого материала. Окрашен в " -"простой белый цвет." - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "" -"Участок напольного покрытия из прочного серого пружинистого материала." - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "земляной пол" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." -msgstr "Участок пола, состоящий из хорошо перемешанной утоптанной земли." +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." +msgstr "Бетонная стена, заросшая гротескным узором вен и узловатой плоти." #: lang/json/terrain_from_json.py msgid "concrete floor" @@ -231190,6 +234171,24 @@ msgstr "" "Незаконченный ряд арматур, залитых бетоном: пол ещё не выровнен, крыша также" " не установлена." +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "каменный пол" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "" +"Сравнительно плоская площадка горной породы и камня. Выглядит достаточно " +"стабильно, чтобы заниматься добычей с помощью соответствующего горного " +"снаряжения." + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "металлический пол" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -231199,6 +234198,10 @@ msgstr "" "Высококачественный прочный рифлёный пол для снижения риска скольжения и " "падения, с аналогичной крышей." +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "стук" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "пол" @@ -231248,6 +234251,10 @@ msgstr "" "улучшения сопротивления скольжению и качению, используется в развлекательных" " видах спорта." +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "земляной пол" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -231338,32 +234345,15 @@ msgid "A blue section of flooring." msgstr "Участок синего пола." #: lang/json/terrain_from_json.py -msgid "industrial carpet" -msgstr "промышленный ковёр" +msgid "carpet" +msgstr "ковёр" -#. ~ Description for industrial carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." -msgstr "" -"Прочный износостойкий ковёр с низким ворсом нейтрального серого цвета для " -"укладки на голый бетон." - -#: lang/json/terrain_from_json.py -msgid "bunker carpet" -msgstr "ковер бункера" - -#. ~ Description for bunker carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." -msgstr "" -"Прочный негорючий ковёр с низким ворсом нейтрального кремового цвета с " -"изолирующей подкладкой." +msgid "Base carpet!" +msgstr "Базовый ковёр!" -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "Мягкий красный ковёр." @@ -231383,6 +234373,143 @@ msgstr "Мягкий зелёный ковёр." msgid "Soft purple carpet." msgstr "Мягкий пурпурный ковёр." +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "Ковёр" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "Базовый бетонный ковёр!" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "промышленный красный ковёр" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "" +"Прочный износостойкий ковёр с низким ворсом красного цвета для укладки на " +"голый бетон." + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "промышленный жёлтый ковёр" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "" +"Прочный износостойкий ковёр с низким ворсом жёлтого цвета для укладки на " +"голый бетон." + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "промышленный зелёный ковёр" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "" +"Прочный износостойкий ковёр с низким ворсом зелёного цвета для укладки на " +"голый бетон." + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "промышленный фиолетовый ковёр" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "" +"Прочный износостойкий ковёр с низким ворсом фиолетового цвета для укладки на" +" голый бетон." + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "Базовый металлический ковёр!" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "красный ковёр бункера" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "" +"Прочный негорючий ковёр с низким ворсом красного цвета с изолирующей " +"подкладкой." + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "жёлтый ковер бункера" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "" +"Прочный негорючий ковёр с низким ворсом жёлтого цвета с изолирующей " +"подкладкой." + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "зелёный ковёр бункера" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "" +"Прочный негорючий ковёр с низким ворсом зелёного цвета с изолирующей " +"подкладкой." + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "фиолетовый ковёр бункера" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "" +"Прочный негорючий ковёр с низким ворсом фиолетового цвета с изолирующей " +"подкладкой." + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "линолеум" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "" +"Участок напольного покрытия из прочного пружинистого материала. Окрашен в " +"простой белый цвет." + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "" +"Участок напольного покрытия из прочного серого пружинистого материала." + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "покрашенный восковый пол" @@ -231425,6 +234552,37 @@ msgstr "" "постапокалипсиса. Надеемся, вам понравится звон дождя по гофрированному " "металлу." +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "земля" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "" +"Это земля. Подходит для пашни. Также её можно вскапывать для различных " +"строительных проектов." + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "" +"Большой участок песка, который можно было бы использовать самыми различными " +"способами." + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "грязь" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "Мокрая скользкая грязь." + #: lang/json/terrain_from_json.py msgid "moss" msgstr "мох" @@ -231434,6 +234592,32 @@ msgstr "мох" msgid "Moist spongy moss." msgstr "Влажный губчатый мох." +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "глина" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "" +"Участок, содержащий глинозём, пригодный для обжига печи, если был извлечён " +"должным образом." + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "насыпь глины" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "Холмик из глинистой почвы." + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "чавк!" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "бумажный пол" @@ -231443,6 +234627,156 @@ msgstr "бумажный пол" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "Пол сделанный из бесформенной массы, покрытой липкой осиной слюной." +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "песчаная насыпь" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "Песчаный холмик." + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "земляная насыпь" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "" +"Труднопроходимая земляная насыпь, если приглядеться, почва хорошо подходит " +"для посадки семян и тому подобного." + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "Гигантский земляной холм, похоже, вы можете укрыться внутри." + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "странный провал" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" +"Неестественная дыра напоминает своей формой человеческие очертания и кажется" +" странно знакомой. У вас странное желание исследовать её поближе, будто этот" +" объект как-то связан с вами." + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "могила" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "" +"Земляная могила с растущей на ней травой. Хоть кто-то из мёртвых " +"действительно покоится с миром." + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" +"Свежая могила, покрытая камнями, либо чтобы кто-то не раскопал ее, либо " +"чтобы кто-то не раскопался наружу. Две дощечки отмечают её как место чьего-" +"то упокоения." + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "асфальт" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr "" +"Участок асфальта, медленно разрушающийся от трещин, морозов и отсутствия " +"ремонтных работ." + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "жёлтый асфальт" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "" +"Линии дорожной разметки аккуратно нанесены жёлтой краской на асфальт, служат" +" для сообщения информации участникам дорожного движения. Никто больше эти " +"правила не соблюдает." + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "тротуар" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "" +"Край проезжей части дороги, залитый бетоном, повреждён морозом и большими " +"трещинами из-за отсутствия обслуживания." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "" +"Более новый залитый бетоном участок дороги с поверхностной отделкой для " +"красоты и устойчивости к циклам замораживания-таяния." + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "" +"Более новый залитый бетоном участок дороги с поверхностной отделкой для " +"красоты и устойчивости к циклам замораживания-таяния. Покрыт желтой краской." + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "деревянный пол" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "" +"Пол из плотно уложенных сбитых гвоздями деревянных досок. Такие часто бывают" +" на верандах." + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "" +"Высококачественный прочный рифлёный пол для снижения риска скольжения и " +"падения." + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "Участок пола, состоящий из хорошо перемешанной утоптанной земли." + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "грецкий орех" @@ -235866,6 +239200,78 @@ msgstr "Лестница вверх." msgid "A ladder leading down." msgstr "Лестница вниз." +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "дорожная рампа вниз (верхняя часть)" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "Верхняя часть дорожной рампы, ведущей вниз." + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "дорожная рампа вниз (нижняя часть)" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "Нижняя часть дорожной рампы, ведущей вниз." + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "дорожная рампа вверх (верхняя часть)" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "Верхняя часть дорожной рампы, ведущей вверх." + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "дорожная рампа вверх (нижняя часть)" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "Нижняя часть дорожной рампы, ведущей вверх." + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "тротуар рампы вниз (верхняя часть)" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "Верхняя часть тротуара дорожной рампы, ведущей вниз." + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "тротуар рампы вниз (нижняя часть)" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "Нижняя часть тротуара дорожной рампы, ведущей вниз." + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "тротуар рампы вверх (верхняя часть)" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "Верхняя часть тротуара дорожной рампы, ведущей вверх." + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "тротуар рампы вверх (нижняя часть)" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "Нижняя часть тротуара дорожной рампы, ведущей вверх." + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "уклон вниз" @@ -236382,7 +239788,7 @@ msgstr "«Клац!»" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "«Бах!»" @@ -239178,6 +242584,16 @@ msgstr "" "Охлаждаемый бак на 60 литров. Когда включен, жидкость внутри охлаждается, " "что не дает ей быстро испортиться." +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "" +"Кусок дерева с отверстиями для велосипедного или мотоциклетного колеса." + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "деревянное крепление колеса (управляемое)" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "легкое крепление колеса (управляемое)" @@ -240059,8 +243475,9 @@ msgstr "" msgid "The lock stumps your efforts to pick it." msgstr "Замок сопротивляется вашим попыткам взломать его." -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "Во время езды верхом этого делать нельзя." @@ -240124,6 +243541,129 @@ msgstr "Продолжить пытаться уснуть." msgid "Continue trying to fall asleep and don't ask again." msgstr "Продолжить пытаться уснуть и больше не спрашивать." +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "Вы слишком устали чтобы заниматься" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "Сильная жажда не дает вам заниматься" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "Сначала освободите свои руки" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "Нельзя заниматься здесь со сломанной рукой" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "Нельзя заниматься здесь со сломанной ногой" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "Нельзя заниматься со сломанной ногой" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" +"Физические усилия определяют эффективность тренировки, но также влияют на " +"то, как быстро вы устанете." + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "Выберите интенсивность тренировки:" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" +"Легкие упражнения, сравнимые с ходьбой, только более методичные и " +"направленные." + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "Средняя" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" +"Средние по нагрузке упражнения без чрезмерного напряжения, но достаточные " +"чтобы вспотеть." + +#: src/activity_actor.cpp +msgid "Active" +msgstr "Активная" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" +"Активные упражнения с полным вовлечением. Энергично, но контролируемо. " + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" +"Очень интенсивные упражнения с максимальными усилиями. Выматывающие если " +"долго заниматься." + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "Как долго тренироваться (в минутах):" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "Вы начинаете заниматься." + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "Вы устали, поэтому закончили заниматься раньше." + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "Вы хотите пить, поэтому закончили заниматься раньше." + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr ", как вы пыхтите и сопите!" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "Вы тратите несколько секунд, чтобы перевести дыхание." + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "Вы продолжили тренировку." + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "Вы закончили заниматься." + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "Вы закончили ваш цикл занятий, продолжать тренироваться?" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "Прекратить тренировку." + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "Продолжить тренировку." + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "Продолжить тренировку и больше не спрашивать." + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -244948,6 +248488,29 @@ msgstr "%s (%i слотов);" msgid "Increased storage capacity by %i." msgstr "Энергоёмкость увеличена на %i." +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "Выберите безопасный порог уровня топлива" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "Вся энергия" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "Выше 80 %%" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "Выше 55 %%" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "Выше 30 %%" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "Установить стартовый порог мощности" @@ -245131,8 +248694,9 @@ msgid "(incapacitated)" msgstr "(без сознания)" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" -msgstr "(режим экономии топлива включён)" +#, c-format +msgid "(fuel saving ON > %d %%)" +msgstr "(режим экономии ВКЛ > %d %%)" #: src/bionics_ui.cpp #, c-format @@ -245859,6 +249423,23 @@ msgstr " освобождается от паутины!" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "Вы пытаетесь освободиться от паутины, но у вас не получается!" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "%s освобождается!" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "Вы освобождаетесь!" + +#: src/character.cpp +msgid " frees themselves!" +msgstr " освобождается!" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "Вы попытались освободиться, но не смогли!" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "Вы пытаетесь выбраться из ямы, но соскальзываете вниз." @@ -246747,6 +250328,10 @@ msgstr "EXTRA_EXERCISE" msgid "Your body strains under the weight!" msgstr "Ваше тело напряжено под такой тяжестью!" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "Ваша биология несовместима с этим лечебным предметом." + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -251054,19 +254639,6 @@ msgstr "" "Внутри: %s\n" "Крыша: %s" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" -"Заметность: %d\n" -"Сложность уклонения: %d\n" -"Сложность обезвреживания: %d\n" -"Безвредна: %s" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -255357,6 +258929,10 @@ msgstr "У вас нет ничего, что можно было бы пере msgid "You aren't holding something you can reload." msgstr "Вы не держите ничего, что можно перезарядить." +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "Вам нужно снять сумку перед тем, как взять что-либо из неё в руки." + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -257985,6 +261561,10 @@ msgstr "Вы игнорируете лазерный прицел!" msgid "Creature whitelisted: %s" msgstr "Существо внесено в белый список: %s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "Начать тренировку?" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "Совершить самоубийство?" @@ -259389,11 +262969,28 @@ msgstr "%s выглядит слишком опасно. Лучше не тро msgid "There is a %s there. Take down?" msgstr "Здесь находится %s. Снять?" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "Предмет (%s) снят." + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "Тут %s. Обезвредить?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "Вы успешно обезвредили ловушку!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "Вы не смогли обезвредить ловушку." + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "Вы не смогли обезвредить ловушку, и она сработала!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -260333,6 +263930,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr " не знает рецепт (%s) и не может продолжать работу." +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "%s - использовать для тренировки?" + #: src/init.cpp msgid "Finalizing" msgstr "Финализация" @@ -261374,7 +264976,7 @@ msgstr "" "Эта еда начала портиться. Есть её была бы очень" " плохая идея." -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -263153,6 +266755,15 @@ msgstr "Выберите предмет из находящихся рядом" msgid "is not a container" msgstr "не является контейнером" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "карман недоступен: %s" +msgstr[1] "карманы недоступны: %s" +msgstr[2] "карманы недоступны: %s" +msgstr[3] "карманы недоступны: %s" + #: src/item_contents.cpp msgid "is not rigid" msgstr "не жёсткий" @@ -263219,6 +266830,10 @@ msgstr "открыт" msgid "Pocket %d:" msgstr "Карман %d:" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "Содержит: " + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "Максимальная длина помещаемого предмета:" @@ -265079,10 +268694,6 @@ msgstr "З М Е Й К А" msgid "Sokoban" msgstr "Сокобан" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "Сапёр" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "Lights on!" @@ -268067,7 +271678,7 @@ msgstr "Для этой ловушки (%s) нужно, чтобы рядом б msgid "You can't place a %s there. It contains a trap already." msgstr "Тут уже есть ловушка, поэтому эту (%s) не получится разместить здесь." -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "Вы активируете ловушку (%s)!" @@ -269863,6 +273474,15 @@ msgstr "Порождение" msgid "Summon" msgstr "Призыв" +#: src/magic.cpp +msgid "random creature" +msgstr "случайное существо" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "Цели ниже %d ОЗ становятся: %s" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "Дальность" @@ -269883,6 +273503,10 @@ msgstr "Эффект по области" msgid "Spawned" msgstr "Порождает" +#: src/magic.cpp +msgid "Threshold" +msgstr "Порог" + #: src/magic.cpp msgid "Recover" msgstr "Восстанваливает" @@ -269938,6 +273562,15 @@ msgstr "Ваши раны равномерно распределяются." msgid "%s wounds are closing up!" msgstr "Раны (%s) затягиваются!" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "%s превращается в: %s." + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "Ваша цель сопротивляется превращению." + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "Здесь уже стоит транспорт." @@ -270404,30 +274037,23 @@ msgstr "Автоклав в транспорте (%s) завершил рабо #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "Предмет (%s) снят." - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "Вы успешно обезвредили ловушку!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "Вы не смогли обезвредить ловушку." +msgid "Something has crawled out of the %s plants!" +msgstr "Что-то вылезло из побегов (%s)!" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "Вы не смогли обезвредить ловушку, и она сработала!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "Что-то вылезло из предмета (%s)!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "Что-то вылезло из побегов (%s)!" +msgid "You've spotted a %1$ss!" +msgstr "Вы заметили: %1$s !" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "Что-то вылезло из предмета (%s)!" +msgid " triggers a %s!" +msgstr " вызывает срабатывание: %s!" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -272013,6 +275639,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "Была объявлена в розыск полицией!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "Сломанная %s." + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "Сломанная %s." + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -275987,6 +279626,11 @@ msgstr "" msgid "zombie slave" msgstr "зомби-раб" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "Толкнуть: %s" + #: src/monexamine.cpp msgid "Rename" msgstr "Переименовать" @@ -281531,21 +285175,6 @@ msgstr "Мутации от радиации" msgid "If true, radiation causes the player to mutate." msgstr "Если включено, то радиация приводит к мутации персонажа игрока." -#: src/options.cpp -msgid "Z-levels" -msgstr "Вертикальные уровни" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" -"Если включено, добавляются некоторые возможности, такие, как переноска вещей" -" по лестнице, возможность взбираться по водостокам, управление " -"авиатранспортом. Может вызвать проблемы, если будет включено после начала " -"игры." - #: src/options.cpp msgid "Character point pools" msgstr "Пулы очков персонажей" @@ -286478,6 +290107,19 @@ msgctxt "grammatical gender list" msgid "n" msgstr "n" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" +"Заметность: %d\n" +"Сложность уклонения: %d\n" +"Сложность обезвреживания: %d\n" +"Безвредна: %s" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "Вы наступили на пузырчатую плёнку!" diff --git a/lang/po/zh_CN.po b/lang/po/zh_CN.po index f2b29d3f77a8c..051327a2a6dd3 100644 --- a/lang/po/zh_CN.po +++ b/lang/po/zh_CN.po @@ -39,6 +39,7 @@ # 保周 郭 , 2020 # none none <514065589@qq.com>, 2020 # ehnuhc , 2020 +# Brett Dong , 2020 # 等离子 坦克 , 2020 # 曾泰瑋 , 2020 # Mein Führer <851000914@qq.com>, 2020 @@ -47,21 +48,20 @@ # VoidForge , 2020 # GeekDuanLian , 2020 # Silencess , 2020 +# fei li, 2020 # L rient <1972308206@qq.com>, 2020 -# fei li , 2020 # 何方神圣 何 <1366003560@qq.com>, 2020 -# cainiao , 2020 # Amans Tofu , 2020 # Aloxaf , 2020 -# Brett Dong , 2020 +# cainiao , 2020 # msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" -"Last-Translator: Brett Dong , 2020\n" +"Last-Translator: cainiao , 2020\n" "Language-Team: Chinese (China) (https://www.transifex.com/cataclysm-dda-translators/teams/2217/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -853,6 +853,16 @@ msgstr[0] "氮氧混合气" msgid "Mixture of oxygen and nitrogen in proportions suitable for diving." msgstr "将氧气和氮气以适度比例混合,用于潜水。" +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "灭火剂" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "一款能够有效灭火的干粉状化学溶剂。" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -4056,6 +4066,26 @@ msgstr "" "一些强化式杀虫剂,需填充于药剂喷罐喷洒。\n" "“最好戴上面罩或嘴部防护使用。”" +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "12.3ln 弹" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" +"罗马尼亚在第二次喀尔巴阡山冲突后引进了 12.3ln 弹。使用这种弹药的 PA md.71 " +"步枪迅速在东欧联盟以及世界各地流行起来。正因为如此,12.3ln " +"弹迅速成为欧亚大陆的标准弹药口径。因此流放族轻易地回收及储存了大量此类弹药。对你来说,它的外观和手感都非常类似于 .30-06 春田弹,但弹头稍显锋利。" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -5033,7 +5063,7 @@ msgstr[0] "黄油漆" msgid "A can of yellow paint." msgstr "一罐黄色的油漆。" -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "红地毯" @@ -6968,8 +6998,8 @@ msgstr[0] "子弹袋" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." -msgstr "一个小袋子,可以用来存储大多数的小型弹药,但是装不下火箭弹。激活它来存储弹药。" +"rockets will not fit. Use insert to store ammunition." +msgstr "一个小袋子,可以用来存储大多数的小型弹药,但是装不下火箭弹。使用它来存储弹药。" #: lang/json/ARMOR_from_json.py msgid "ammo satchel" @@ -7060,9 +7090,9 @@ msgstr[0] "箭筒" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." -msgstr "一个佩戴在腰部、可容纳20支箭的皮革箭筒。使用它以存储箭支。" +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." +msgstr "一个可佩戴在腰部、可容纳20支箭的皮革箭筒。使用它以存储箭支或弩矢。" #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -7073,8 +7103,8 @@ msgstr[0] "桦皮箭筒" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." -msgstr "一个可佩戴在腰部、可容纳20支箭的桦树皮箭筒。使用它以存储箭支。" +"20 arrows or bolts. Use insert to store arrows or bolts." +msgstr "一个可佩戴在腰部、可容纳20支箭的桦树皮箭筒。使用它以存储箭支或弩矢。" #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -7085,9 +7115,10 @@ msgstr[0] "大箭筒" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." -msgstr "一个佩戴在后背、可容纳60支箭的皮革大箭筒,有着金属镶边。使用它以存储箭矢。" +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." +msgstr "一个佩戴在后背、可容纳60支箭的皮革大箭筒,有着金属镶边。使用它以存储箭矢或弩矢。" #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -7098,8 +7129,8 @@ msgstr[0] "桦皮大箭筒" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." -msgstr "一个佩带在后背、可容纳60支箭的桦树皮大箭筒。使用它以存储箭支。" +"hold 60 arrows or bolts. Use insert to store arrows or bolts." +msgstr "一个佩带在后背、可容纳60支箭的桦树皮大箭筒。使用它以存储箭支或弩矢。" #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -16594,10 +16625,10 @@ msgstr "一个主要用于旅行期间存放衣物和杂物的巨大轮式旅行 #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." -msgstr "一个主要用于旅行期间存放衣物和杂物的中型旅行箱,提供充足的储存空间,但拉起来很累赘。" +msgstr "一个带滚轮的中型旅行箱,主要用于旅行时存放衣物和杂物,提供了充足的储存空间,但拉起来很累赘。" #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -20039,13 +20070,13 @@ msgstr "一个覆盖全身的肉眼无法看见的环境防护光环。" #: lang/json/ARMOR_from_json.py msgid "aura of repelling arc" msgid_plural "aura of repelling arcs" -msgstr[0] "电弧击退光环" +msgstr[0] "电弧光环" #. ~ Description for aura of repelling arc #: lang/json/ARMOR_from_json.py msgid "" "An invisible aura that strikes melee attackers with arcs of electricity." -msgstr "" +msgstr "一个肉眼无法看见的能向近战攻击你的敌人放出电弧的光环。" #: lang/json/BATTERY_from_json.py msgid "test battery" @@ -21690,14 +21721,14 @@ msgstr "一个安装在脊柱和脑干交汇处的炸弹。它在安装时就被 #: lang/json/BIONIC_ITEM_from_json.py lang/json/bionic_from_json.py msgid "Skullgun CBM" msgid_plural "Skullgun CBMs" -msgstr[0] "" +msgstr[0] "头骨枪CBM" #. ~ Description for {'str': 'Skullgun CBM'} #: lang/json/BIONIC_ITEM_from_json.py lang/json/bionic_from_json.py msgid "" "Concealed in your head is a single shot .40 pistol. Activate the bionic to " "fire and reload the skullgun." -msgstr "" +msgstr "你的头骨中隐藏着一只 .40 口径单发手枪。激活这个生化插件以发射并装填该手枪。" #: lang/json/BIONIC_ITEM_from_json.py msgid "Precision Solderers CBM" @@ -26306,7 +26337,7 @@ msgstr "一些爱开玩笑的人轻轻地烧焦了这边平装本反乌托邦小 msgid "" "\"It was a pleasure to burn. It was a special pleasure to see things eaten," " to see things blackened and changed.\"" -msgstr "这本书封面写着:“燃烧是一种乐趣。看到吃的东西,看到变黑变黑的东西,我感到特别高兴。”" +msgstr "这本书封面写着:“燃烧是一种乐趣。看到火焰吞噬它们,看到变黑变黑的东西,我感到特别高兴。”" #: lang/json/BOOK_from_json.py msgid "" @@ -28421,6 +28452,18 @@ msgid "" "your pain at bay." msgstr "这是一种类似于体能训练的激烈仪式,可以帮助你将一些疼痛抛之脑后。" +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "恶意变形术卷轴" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "把你的敌人变形成青蛙。" + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -29642,7 +29685,7 @@ msgstr "你可以引导魔力打开近距离内任何锁着的门。" #: lang/json/BOOK_from_json.py msgid "Scroll of Repelling Arc" msgid_plural "Scrolls of Repelling Arc" -msgstr[0] "" +msgstr[0] "电弧光环卷轴" #. ~ Description for {'str': 'Scroll of Repelling Arc', 'str_pl': 'Scrolls of #. Repelling Arc'} @@ -29650,7 +29693,7 @@ msgstr[0] "" msgid "" "You manifest an aura of crackling electricity around you to strike attackers" " with baleful lightning." -msgstr "" +msgstr "你在你周围召唤出一道噼啪作响的电弧光环,能放出可怕的闪电电击近战攻击你的敌人。" #: lang/json/BOOK_from_json.py msgid "A Technomancer's Guide to Debugging C:DDA" @@ -29929,6 +29972,19 @@ msgid "" "on combining magic with EM radiation." msgstr "这本实验室参考材料书很厚,里面充满了如何将魔法与电磁辐射结合的信息。" +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "符文石板碎片" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "一小块黑色石板碎片,显然是从一个大得多的石板上被削下来的。金色符文在它的表面闪闪发光,当你盯着它们看时,会慢慢地变成能被你读懂的句子。" + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -33238,7 +33294,7 @@ msgstr[0] "红茶" msgid "" "The beverage of gentlemen everywhere, made from applying hot water to " "oxidized leaves of the tea plant /Camellia sinensis/." -msgstr "一份供全球绅士享用的饮品,通过将滚烫的开水倒入被称作\"山茶科山茶属\"的茶树的脱氧叶子中而成。" +msgstr "一份供全球绅士享用的饮品,通过将滚烫的开水倒入被称作\"山茶科山茶属\"的茶树的发酵过的叶子中而成。" #: lang/json/COMESTIBLE_from_json.py msgid "bark tea" @@ -33293,7 +33349,7 @@ msgid "" "Made from applying hot water to leaves of the tea plant /Camellia sinensis/." " Green tea has a lighter, fresher taste than black and is traditionally " "preferred in Asian cultures." -msgstr "用热水浸泡茶树的叶子制成。绿茶比红茶口味清淡,是传统亚洲文化中的首选。" +msgstr "一道通过将滚烫的开水倒入被称作\"山茶科山茶属\"的茶树的叶子制成的饮品。绿茶比红茶口味清淡,是传统亚洲文化中的首选。" #: lang/json/COMESTIBLE_from_json.py msgid "fruit tea" @@ -34923,6 +34979,30 @@ msgid "" "cheese. Delicious." msgstr "墨西哥式调味玉米片,加了肉末,又盖上一层奶酪。这才是正宗。" +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "素食辣味玉米片" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "墨西哥式调味玉米片。这份已经加了豆子。再来点奶酪就更棒了。" + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "素食奶酪辣味玉米片" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "墨西哥式调味玉米片,加了豆子,又盖上一层奶酪。这才是正宗。" + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -39359,24 +39439,52 @@ msgid "" msgstr "一些主要由种子、青贮或一些豆类制成的鸟食,小型鸟类非常喜欢吃。" #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "狗粮" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "半湿犬粮" + +#. ~ Description for {'str_sp': 'wet dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "半湿犬粮,用罐装鲜肉制成。闻起来很奇怪,但是狗狗喜欢。" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "干犬粮" + +#. ~ Description for {'str_sp': 'dry dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "有较长保质期的干犬粮。由加工过的肉类和谷物制成,富含维生素和矿物质。" + +#: lang/json/COMESTIBLE_from_json.py +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "半湿猫粮" -#. ~ Description for {'str_sp': 'dog food'} +#. ~ Description for {'str_sp': 'wet cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." -msgstr "狗粮,闻起来很奇怪,但是狗狗喜欢。" +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." +msgstr "半湿猫粮,用罐装鲜肉制成。闻起来有点刺鼻,但是猫猫喜欢。" #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "猫食" +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "干猫粮" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'dry cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." -msgstr "猫粮,闻起来很奇怪,但是猫猫喜欢。" +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "有较长保质期的干猫粮。由加工过的肉类和谷物制成,富含维生素和矿物质。" #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -45638,6 +45746,32 @@ msgid "" "Felt patches, bundled tightly together for storage. Disassemble to unpack." msgstr "一捆被紧紧地捆在一起以存放的毛毡片,可拆解。" +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "木板捆" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "十片被绳子紧紧地捆在一起以存放的木板,可拆解。" + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "粗树枝捆" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "十根被绳子紧紧地捆在一起以存放的粗树枝,可拆解。" + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -49544,6 +49678,54 @@ msgid "" "wound." msgstr "一具头没了一半的尸体。造成这种损伤的原因不得而知。" +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "流放族工兵(损坏)" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "一台损坏的流放族工兵机器人。可以拆解得到部件。" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "流放族四足机器人(损坏)" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "一台损坏的流放族四足机器人。可能因为巨大的体积和质量的缘故,就算已经永久无法继续运作依旧看起来可怕无比。可以拆解得到部件。" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "流放族炮塔(损坏)" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "一台损坏的流放族炮塔。可能因为巨大的体积和质量的缘故,就算已经永久无法继续运作依旧看起来可怕无比。可以拆解得到部件。" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "流放族气球无人机(损坏)" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "一台损坏的流放族气球无人机。气球已被撕碎,但大部分底盘仍然完好无损。可以拆解得到部件。" + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -51219,7 +51401,7 @@ msgstr[0] "卡农麦克风" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "一个常见的用来录音或放大声音的麦克风。有一个夹子。底部有一个3针卡农接头,用于连接调幅放大器。" #: lang/json/GENERIC_from_json.py @@ -51389,6 +51571,19 @@ msgid "" "anything on its own." msgstr "一种简易铸铁机械叶轮泵。单独它自己并没有什么用。" +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "管道连接件" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "各式各样的金属管件。管帽、管接头和类似的配件。它们可以用在各种工程项目中。" + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -53178,6 +53373,109 @@ msgid "" "somewhat warm to the touch." msgstr "这是一块破碎的异界树脂块。它看起来有点像一大块海玻璃,表面磨砂,边缘圆润。摸起来有点温暖舒适。" +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "流放族机器人底盘" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" +"这个看上去略呈六角形的框架和连接在其上的底盘看起来像是一体成型建造而成的。上面的连接孔和附带装置都十分耐用,尽管已经有许多严重磨损和维修的迹象。这个底盘十分灵活,并可能被设计为用于满足各种不同作战角色的需求。" + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "流放族无人机底盘" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" +"这个看上去略呈六角形的小型框架和连接在其上的底盘看起来像是一体成型建造而成的。上面的连接孔和附带装置都十分耐用,尽管已经有许多严重磨损和维修的迹象。这个底盘十分灵活,并可能被设计为用于满足各种不同作战角色的需求。" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "生化神经矩阵" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" +"一系列容器和管道,包括供液系统、供电系统、和输入输出的信号接口,如此复杂的安排是为了使其能够容纳下大脑和脊柱,以及其他完全无法被替代的器官以保证其存活。" + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "奇特电子元件" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" +"上面的连线和它的整体形状告诉你,这应该是一台电脑,或者至少是某种电子设备,但你还完全无法理解它具体是什么以及它所能起的作用。它的整体做工沉重而坚固。" + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "蚀刻金属板" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" +"这个设备看上去像是电子设备,但你完全不了解它的原理。它是一系列紧密结合在一起的铜环,按照同心圆的方式排列着。每个环中伸出许多金属线连接到中间的一根轴上。" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "生化传感器" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" +"从位于正前方的大型玻璃眼睛来分析——有一个小餐盘那么大——你猜它可能是某种相机。但是它内部的工作原理完全让你无法理解,而且看起来也不像你以前见过的任何一台相机。" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "旋转装置" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "你通过铜线的线圈和突出的活塞来猜想它是某种电动机或发电机,但是它的设计看起来和你以前见过的完全不一样,你不知道如何让它工作。" + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -53458,7 +53756,7 @@ msgstr "这是一种大型的柔性塑料薄膜,这种塑料可能用于商业 #: lang/json/GENERIC_from_json.py msgid "rigid plastic sheet" msgid_plural "rigid plastic sheets" -msgstr[0] "" +msgstr[0] "硬塑料板" #. ~ Description for rigid plastic sheet #: lang/json/GENERIC_from_json.py @@ -53551,12 +53849,12 @@ msgid "" "An enormous beam of solid wood, very heavy and hard to lug around, but also " "very sturdy for construction. You could saw or chop it into smaller pieces," " like planks or panels." -msgstr "巨大的实木梁,很重,很难被拖动,但对于建筑来说也很坚固。你可以把它锯成小块,比如木板或中木板。" +msgstr "巨大的实木梁,很重,很难被拖动,但对于建筑来说也很坚固。你可以把它锯成小块,比如木板或木墙板。" #: lang/json/GENERIC_from_json.py msgid "wooden panel" msgid_plural "wooden panels" -msgstr[0] "中木板" +msgstr[0] "木墙板" #. ~ Description for {'str': 'wooden panel'} #: lang/json/GENERIC_from_json.py @@ -54748,14 +55046,14 @@ msgstr "一个让船只保持浮力的木板。将其安装在载具上直到它 #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "raft boat hull" msgid_plural "raft boat hulls" -msgstr[0] "" +msgstr[0] "木筏船壳" #. ~ Description for {'str': 'raft boat hull'} #: lang/json/GENERIC_from_json.py msgid "" "Logs tied together to make a vehicle float. Add boat hulls to a vehicle " "until it floats. Then attach oars or a motor to get the boat to move." -msgstr "" +msgstr "一根让船只保持浮力的原木。将其安装在载具上直到它浮在水上。继续添加桨或者引擎来移动船只。" #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "plastic boat hull" @@ -56143,6 +56441,16 @@ msgstr[0] "水龙头" msgid "A metal faucet that can be attached to a water tank for easy access." msgstr "一个金属的水龙头,可以连接到水箱上,方便随时取水。" +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "木制轮架" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "一种带有孔的木片,适合自行车车轮使用。" + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -56725,13 +57033,13 @@ msgstr "它已经给出了答案,而你还没有问任何问题。" #: lang/json/GENERIC_from_json.py msgid "woven metamaterial sheet" msgid_plural "woven metamaterial sheets" -msgstr[0] "" +msgstr[0] "超级材料织物" #. ~ Description for {'str': 'woven metamaterial sheet'} #: lang/json/GENERIC_from_json.py msgid "" "An intricately spun and carefully engineered sheet of iridescent fibers." -msgstr "" +msgstr "一片经过精心设计用十分复杂工艺制成的彩虹色纤维织物。" #: lang/json/GENERIC_from_json.py msgid "nanowire battery" @@ -56820,19 +57128,19 @@ msgstr[0] "超导电磁铁" #. ~ Description for {'str': 'super conductive electromagnet'} #: lang/json/GENERIC_from_json.py msgid "A powerful electromagnet made from a room temperature superconductor." -msgstr "" +msgstr "一个由室温超导体制成的强力电磁铁。" #: lang/json/GENERIC_from_json.py msgid "ferrofluid dynamo" msgid_plural "ferrofluid dynamos" -msgstr[0] "" +msgstr[0] "铁磁流体发电机" #. ~ Description for {'str': 'ferrofluid dynamo'} #: lang/json/GENERIC_from_json.py msgid "" "Black metallic fluid, harmonically flowing from one fractal shape to the " "next." -msgstr "" +msgstr "黑色金属流体,和谐地流动变形成一个又一个分形形状。" #: lang/json/GENERIC_from_json.py msgid "composite alloy" @@ -57472,22 +57780,22 @@ msgstr "这个装置包含了绝地武士光剑战斗的第一式:锡秋剑法 #: lang/json/GENERIC_from_json.py msgid "Shards of Granite" msgid_plural "Shards of Granite" -msgstr[0] "" +msgstr[0] "宁为玉碎" #. ~ Description for {'str_sp': 'Shards of Granite'} #: lang/json/GENERIC_from_json.py msgid "This book contains the teaching of the Stone Dragon discipline." -msgstr "" +msgstr "这本书包含了石龙流派相关的武术教学。" #: lang/json/GENERIC_from_json.py msgid "Reaping Talons" msgid_plural "Reaping Talons" -msgstr[0] "" +msgstr[0] "收割之爪" #. ~ Description for {'str_sp': 'Reaping Talons'} #: lang/json/GENERIC_from_json.py msgid "This book contains the teaching of the Tiger Claw discipline." -msgstr "" +msgstr "这本书包含了虎爪流派相关的武术教学。" #: lang/json/GENERIC_from_json.py msgid "stone shell" @@ -57511,7 +57819,7 @@ msgstr[0] "发光粉尘" msgid "" "The powdered remains of a will-o-wisps's physical form. It seems to still " "possess an otherworldly glow." -msgstr "" +msgstr "一缕鬼火遗留下来的物理形态粉末,它似乎还在散发着神奇的光芒。" #: lang/json/GENERIC_from_json.py msgid "magical reading light" @@ -57626,7 +57934,7 @@ msgstr[0] "魔力之尘" #: lang/json/GENERIC_from_json.py msgid "" "Crystalized mana in powdered form. It faintly pulses with arcane energy." -msgstr "" +msgstr "一撮粉末状的魔力结晶。它所含的奥术能量不断脉动着发出微光。" #: lang/json/GENERIC_from_json.py msgid "black dragon scale" @@ -61514,6 +61822,34 @@ msgid "" "thrower." msgstr "一种自制的加压2L罐,设计用于为自制的化学品喷射器供料。" +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "PA Md. 71 流放族 12.3ln 弹匣" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" +"一个流线型的小型弹匣,基于经典的PA MD .71 " +"弹夹造型,经过由流放族重新设计,能够更好地用在比空气还轻的无人机上。它的尺寸过小,不太适合用于与尸群的地面作战,因为装弹会比较麻烦。" + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "PA Md. 68 流放族 12.3ln 弹匣" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "一个大得过分的弹匣,适用于已经很沉重的PA Md. 68 战斗步枪,经过流放族特殊定制,并由其生产制造。" + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -62009,7 +62345,7 @@ msgid "" "A total conversion that shifts the Cataclysm towards an alien occupation " "survival scenario. THIS MOD WILL BREAK INTENDED FUNCTIONALITY OF OTHER " "MODS! USE OTHER MODS AT YOUR OWN RISK." -msgstr "" +msgstr "将大灾变转变为类似XCOM2风格的外星人入侵的全面改动类模组。不兼容其他模组,使用风险自负!" #: lang/json/MOD_INFO_from_json.py msgid "DinoMod" @@ -62494,6 +62830,48 @@ msgid "" msgstr "" "与零件、电缆融在一起的\"人\",虽然眼睛空洞,但转瞬即逝的痛苦表情能让人想起被困在这具怪诞身体里的曾经是人类。掌握足够的外科手术技巧,就可以为他们找回一些人性,但愿他们还在乎……" +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "流放族工兵" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "一台看上去以人型生物为原型的机器人,装配了各种建筑工具。" + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "流放族四足机器人" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" +"这台体型巨大的四足机器人似乎是由各类零件拼凑而成,其中大部分零件你都从未见过。它以一种沉重的,奇怪的优雅步态移动,伴随着沉重的脚步声,它在它所踏过之处留下了一串浅坑。它的体内堆满了各类武器,但似乎并不急于瞄准你。" + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "丧尸改造人" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" +"一具早已死亡的人类和更致命的技术的混合体,这具钢铁和血肉扭曲在一起的躯体就像一个愤怒的幼童手中的木偶。它的机械部件似乎已经失效关闭,而新生的肌肉包裹在它们周围,把它们牵扯拉伸向奇怪的方向。一些金属骨架和盔甲从它腐烂的肉体中突出来。" + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -62709,6 +63087,23 @@ msgid "" "appears to have a mininuke inside. If this is targeting you… Run." msgstr "一只体积数倍于普通型号的无人机,这台正在飞行的四轴无人机体内装载了一枚微型核弹。如果它瞄准了你……快跑!" +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "气球狙击无人机" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" +"这台不寻常的装置看起来像一个气象气球和一个四翼无人机的组合体。在装有部件的大箱子下面,悬挂着一个小型的铰接式装备,上面有把集成步枪。它的螺旋桨偶尔短暂地开启,而后再次关闭,使它不受气流影响,长时间保持静止。它看起来能够在空中悬浮很长一段时间才会耗尽电力。" + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -64014,7 +64409,7 @@ msgstr[0] "人类" #. ~ Description for {'str': 'human'} #: lang/json/MONSTER_from_json.py msgid "Place holder for human corpses. If you see this, it's a bug." -msgstr "" +msgstr "该物品用于人类尸体的占位符,如果你看到这个说明游戏出Bug了。" #: lang/json/MONSTER_from_json.py msgid "bat" @@ -64407,6 +64802,21 @@ msgid "" msgstr "" "东部美洲狮,大型猫科食肉动物。曾经在这一地区被认为已经灭绝,但是经过保育,在大灾变之后,成功的恢复了往日的荣光。迅捷而安静,这只捕猎者能够远距离跳扑,并用致命的爪子抓住猎物,最后用巨大的獠牙给它致命一击。" +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "老虎" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" +"一只雄伟而威严的老虎,一种大型猫科捕食性动物。它们原产于亚洲,现在美国各个私人保护区中有多个种群分布。它的速度快,力量大,是世界上最受人们认可和喜爱的动物之一。当然也是最致命的动物之一。" + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -65971,14 +66381,14 @@ msgstr "水蛭花茎秆射出了一道电弧!" #: lang/json/MONSTER_from_json.py msgid "signal tree" msgid_plural "signal trees" -msgstr[0] "" +msgstr[0] "信号树" #. ~ Description for signal tree #: lang/json/MONSTER_from_json.py msgid "" "A trunk reaches tall into the sky, its topmost branches glowing with yellow " "light. A low drum periodically shakes its vicinities." -msgstr "" +msgstr "这棵树的树干高高耸立入云,其最顶端的树枝发出黄光。它周期性地发出一阵阵低沉的鼓声震撼着四周。" #: lang/json/MONSTER_from_json.py msgid "leech pod cluster" @@ -66458,6 +66868,19 @@ msgstr[0] "扩音器" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "一台大功率扩音器,一遍又一遍地重复着响亮的信息。" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "升级改造炮塔" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "这座巨大的炮塔似乎是用各种高科技零件拼凑而成的,其中有许多看起来非常奇怪的零件。它配备了一把看起来很结实的机枪。" + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -66544,10 +66967,67 @@ msgid "" msgstr "" "安可异公司的第一款产品,一个高耸的四臂人形机器人,脸部柔和。它的面貌细节引人注目,但它的硬度让你感到非常不舒服。世界末日并没有阻止它寻找病人协助。" +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "骷髅犬" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "" +"这只曾经的犬科生物的表皮早已全部脱落,露出了内部由骨骼和肋骨融合而成的甲壳。这套缺少血肉覆盖的会行走的骨甲似乎被一团充满了闪闪发光的黑色粘液的血管和肌腱网所驱动。" + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "犬魔" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "一只体型巨大而肿胀的丧尸犬,身体表面涂满了黑色的黏液。它的牙齿更长,宽阔的后背上布满了肌肉和渗出脓液的伤口。" + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "恐怖巨犬" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "一只四条腿的丧尸犬,身体已经肿胀得十分荒唐,手臂像垃圾桶一样粗壮,巨大的牙齿暴露在外。" + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "骨板狼" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "一只全身覆盖着骨板的四足动物,骨板和躯体已经融合在一起,外形有点像狗或狼。它全身上下的关节和裂缝渗出了黑色的黏液。" + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "骷髅狼" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" -msgstr[0] "" +msgstr[0] "矛猫猎手" #. ~ Description for {'str': 'spearcat hunter'} #: lang/json/MONSTER_from_json.py @@ -66555,12 +67035,12 @@ msgid "" "This cougar's eyes ooze with dark, oily fluid, and its fur is torn, " "revealing deep festering wounds. Its claws and teeth are unnaturally long " "and sharpened into dangerous looking spikes" -msgstr "" +msgstr "这只美洲狮的眼睛渗出深色油状液体,它的皮毛被撕裂,露出了深深的溃烂的伤口。它的爪子和牙齿不自然地生长,并磨尖成危险的尖刺。" #: lang/json/MONSTER_from_json.py msgid "skeletal zombear" msgid_plural "skeletal zombears" -msgstr[0] "" +msgstr[0] "骸骨丧尸熊" #. ~ Description for {'str': 'skeletal zombear'} #: lang/json/MONSTER_from_json.py @@ -66570,11 +67050,12 @@ msgid "" " seep from its joints as it shambles aimlessly, with sickening crackling " "sounds filling the air around it." msgstr "" +"一层巨大的过度生长而成的骨化组织已经形成了致密有机的骨制盔甲并取代了这只丧尸熊表面原来早已腐烂的皮肤。大块的黑色粘液从其关节不断渗出,它毫无目的蹒跚而行,全身的关节随着移动不断发出令人作呕的咔嗒声。" #: lang/json/MONSTER_from_json.py msgid "shadowcat" msgid_plural "shadowcats" -msgstr[0] "" +msgstr[0] "幽灵猫" #. ~ Description for {'str': 'shadowcat'} #: lang/json/MONSTER_from_json.py @@ -66582,12 +67063,12 @@ msgid "" "An uncanny shadow envelops this creature, as if light itself were too " "repulsed to touch it. All you can make out is the outline of a large, " "shambling cat." -msgstr "" +msgstr "这只丧尸怪物被一层不可思议的阴影所笼罩,看上去似如光线也拒绝去接触它一般。你唯一能够分辨出来的是一个步履蹒跚的大型猫科动物轮廓。" #: lang/json/MONSTER_from_json.py msgid "acidic zombear" msgid_plural "acidic zombears" -msgstr[0] "" +msgstr[0] "酸液丧尸熊" #. ~ Description for {'str': 'acidic zombear'} #: lang/json/MONSTER_from_json.py @@ -66595,12 +67076,12 @@ msgid "" "A sickly-looking dead dead black bear with patchy fur. Its skin looks " "especially thin, with a sticky, yellow fluid flowing through the clearly " "visible veins." -msgstr "" +msgstr "一头看上去很恶心的毛皮斑驳的丧尸熊。它的皮肤看上去非常薄,你都能看到它皮肤下的血管中流动着粘粘的黄色液体。" #: lang/json/MONSTER_from_json.py msgid "antlered hammer" msgid_plural "antlered hammers" -msgstr[0] "" +msgstr[0] "鹿角锤头兽" #. ~ Description for {'str': 'antlered hammer'} #: lang/json/MONSTER_from_json.py @@ -66608,12 +67089,12 @@ msgid "" "This once great moose's eyes ooze with dark, oily fluid, and its flesh is " "torn and scarred. Its entire body bulges with distended muscles and " "swollen, festering wounds." -msgstr "" +msgstr "这只曾经体型巨大的驼鹿的眼睛渗出深色油状液体,被撕烈的血肉瘢痕累累。它全身上下布满了肿胀的肌肉和溃烂的伤口。" #: lang/json/MONSTER_from_json.py msgid "thorny bear shambler" msgid_plural "thorny bear shamblers" -msgstr[0] "" +msgstr[0] "荆棘蹒跚兽" #. ~ Description for {'str': 'thorny bear shambler'} #: lang/json/MONSTER_from_json.py @@ -66623,6 +67104,7 @@ msgid "" "Long interlocking thorns wrap the antlers, dripping with a mysterious " "silvery liquid." msgstr "" +"曾经是一只体型巨大的驼鹿,现在被长而密的毛发所覆盖,上面缠绕着荆棘藤蔓,这些藤蔓缠绕在一起包裹着它的尸体。长长的刺缠绕在鹿角上,有种神秘的银色液体从尖端滴下来。" #: lang/json/MONSTER_from_json.py msgid "jawed terror" @@ -66649,21 +67131,6 @@ msgid "" msgstr "" "一个皮毛下暴露出的肌肉组织和血管的丧尸犬。这种生物的腐烂程度更为严重,甚至可以看到暴露在外的骨头,动物本能驱使着其运动能力,它们可以很轻松地扑向敌人并且凶残地撕咬活体。" -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "骷髅犬" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "" -"这只曾经的犬科生物的表皮早已全部脱落,露出了内部由骨骼和肋骨融合而成的甲壳。这套缺少血肉覆盖的会行走的骨甲似乎被一团充满了闪闪发光的黑色粘液的血管和肌腱网所驱动。" - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -66768,6 +67235,30 @@ msgid "" "and its eyes bulge with black goo." msgstr "一条看似正常的美洲狮,但仔细观察会发现它的后腿肿了,眼睛凸起并流着黑色的粘液。" +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "幽灵虎" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "这只原本看上去很正常的老虎走起路来摇摇晃晃的,下巴松弛,眼睛睁得大大的,漆黑的眼睛正闪闪发亮。" + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "大群丧尸蜘蛛" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "成千上万,也许是数百万蜘蛛高高地堆积在一起,每只蜘蛛都在慢慢地渗出黏糊糊的绿色脓液,它们挣扎着把腐烂发臭的躯体堆在一起移动。" + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -67294,6 +67785,43 @@ msgstr "这个尸体以骇人的方式扭曲,变成了昆虫一般的形状。 msgid "The impaler launches a barb!" msgstr "坏疽穿刺者射出了一根毒刺!" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "利剪蛛" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "一团如同梦魇般的蜘蛛形状的血肉高高地矗立在废墟中,无声地守护着眼前残破的景色。它细长的骨头四肢以难以置信的速度在瓦砾中滑动。" + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "吊挂内脏" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "一大块巨大的蛇形血肉从天花板悬吊下来,疯狂地四处摔打着,四处搜寻猎物。" + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "痉挛肉块" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "一大团融合在一起的尸体和变异血肉。它不断痉挛,如同心率失常的心脏病人般绝望地搏动。" + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -69375,7 +69903,7 @@ msgstr[0] "紫绿色恐龙幼仔" #: lang/json/MONSTER_from_json.py msgid "fungal Spinosaurus zombie" msgid_plural "fungal Spinosaurus zombies" -msgstr[0] "" +msgstr[0] "真菌丧尸棘龙" #. ~ Description for {'str': 'fungal Spinosaurus zombie'} #: lang/json/MONSTER_from_json.py @@ -69384,11 +69912,12 @@ msgid "" "back, fungal tendrils now sprout from its mouth, eyes, and other orifices, " "holding together an enormous shambling mass of mold-covered flesh." msgstr "" +"曾经是一只巨大的长着鳄鱼头和背帆的食肉恐龙,但现在真菌从它的口、眼、耳和其他孔洞处喷薄而出并互相连接起来,被霉菌覆盖的巨大躯体还在蹒跚而行。" #: lang/json/MONSTER_from_json.py msgid "fungal Z-Rex" msgid_plural "fungal Z-Rexes" -msgstr[0] "" +msgstr[0] "真菌丧尸霸王龙" #. ~ Description for {'str': 'fungal Z-Rex', 'str_pl': 'fungal Z-Rexes'} #: lang/json/MONSTER_from_json.py @@ -69396,12 +69925,12 @@ msgid "" "Once monarch of the dinosaurs, fungal tendrils now sprout from its mouth, " "eyes, and other orifices, holding together an enormous shambling mass of " "mold-covered flesh." -msgstr "" +msgstr "曾经是一只食肉恐龙中的霸王,但现在真菌从它的口、眼、耳和其他孔洞处喷薄而出并互相连接起来,被霉菌覆盖的巨大躯体还在蹒跚而行。" #: lang/json/MONSTER_from_json.py msgid "fungal Deinonychus zombie" msgid_plural "fungal Deinonychus zombies" -msgstr[0] "" +msgstr[0] "真菌丧尸恐爪龙" #. ~ Description for {'str': 'fungal Deinonychus zombie'} #: lang/json/MONSTER_from_json.py @@ -69409,24 +69938,24 @@ msgid "" "Once a medium-sized feathered carnivorous dinosaur, fungal tendrils now " "sprout from its mouth, eyes, and other orifices, holding together an " "enormous shambling mass of mold-covered flesh." -msgstr "" +msgstr "曾经是一只长着羽毛的中型食肉恐龙,但现在真菌从它的口、眼、耳和其他孔洞处喷薄而出并互相连接起来,被霉菌覆盖的巨大躯体还在蹒跚而行。" #: lang/json/MONSTER_from_json.py msgid "Gallimimus zombie" msgid_plural "Gallimimus zombie" -msgstr[0] "" +msgstr[0] "丧尸似鸡龙" #. ~ Description for {'str_sp': 'Gallimimus zombie'} #: lang/json/MONSTER_from_json.py msgid "" "The shuffling corpse of a medium-sized bipedal dinosaur covered with " "tattered feathers and black putrid liquid." -msgstr "" +msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的中型两足恐龙尸体。" #: lang/json/MONSTER_from_json.py msgid "Pachy zombie" msgid_plural "Pachy zombie" -msgstr[0] "" +msgstr[0] "丧尸厚头龙" #. ~ Description for {'str_sp': 'Pachy zombie'} #: lang/json/MONSTER_from_json.py @@ -69434,12 +69963,12 @@ msgid "" "The shuffling corpse of a medium-sized bipedal dinosaur covered with " "tattered feathers and black putrid liquid. It looks like a reptilian " "ostrich with a round hard-looking domed head." -msgstr "" +msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的中型两足恐龙尸体。它看起来像一只长着坚硬圆头的蜥蜴鸵鸟。" #: lang/json/MONSTER_from_json.py msgid "Campto zombie" msgid_plural "Campto zombie" -msgstr[0] "" +msgstr[0] "丧尸弯龙" #. ~ Description for {'str_sp': 'Campto zombie'} #: lang/json/MONSTER_from_json.py @@ -69447,7 +69976,7 @@ msgid "" "The shuffling corpse of a large feathered bipedal dinosaur with strong legs," " broad shoulders and a pointed beak. Its tattered feathers are stained with" " black, sticky liquid." -msgstr "" +msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的大型两足恐龙尸体。它的两条腿很强壮,肩膀宽阔,长着尖喙。" #: lang/json/MONSTER_from_json.py msgid "Spinosaurus zombie" @@ -69461,19 +69990,6 @@ msgid "" " black eyes, and a tattered sail on its back." msgstr "一具巨大的腐烂恐龙尸体,有着凶猛的像鳄鱼一样的头,眼睛渗出黑色的液体,背上有一个破烂的帆一样的东西。" -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -69484,71 +70000,46 @@ msgstr[0] "丧尸霸王龙" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "一大坨破烂发臭的血肉,托起了它巨大的牙齿。" -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "" - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "丧尸骨霸王龙" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "巨大而密集的骨柱托举起巨大的尖牙,牙尖不断滴下黑色的黏液。" - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" -msgstr[0] "" +msgstr[0] "丧尸阿尔伯塔龙" #. ~ Description for {'str_sp': 'Albertosaurus zombie'} #: lang/json/MONSTER_from_json.py msgid "" "Massive jaws drooling black liquid lifted over grasping claws by a huge " "shuffling dinosaur corpse." -msgstr "" +msgstr "一具巨大的恐龙尸体撑起了巨大的大嘴和一对贪婪的利爪,嘴中不断滴落下黑色的液体。" #: lang/json/MONSTER_from_json.py msgid "Triceraterror" msgid_plural "Triceraterror" -msgstr[0] "" +msgstr[0] "丧尸三角龙" #. ~ Description for {'str_sp': 'Triceraterror'} #: lang/json/MONSTER_from_json.py msgid "" "A massive shambling rhino-like dinosaur corpse with a bony crest from which " "three wicked looking horns emerge. Its black eyes ooze like tears." -msgstr "" +msgstr "一具庞大的、犀牛般的蹒跚而行的恐龙尸体。头上有三个恐怖大角和一个骨质头冠。眼中流出的黑色液体如同眼泪一般滴落下来。" #: lang/json/MONSTER_from_json.py msgid "Stegosaurus zombie" msgid_plural "Stegosaurus zombie" -msgstr[0] "" +msgstr[0] "丧尸剑龙" #. ~ Description for {'str_sp': 'Stegosaurus zombie'} #: lang/json/MONSTER_from_json.py msgid "" "A large shambling quadruped dinosaur corpse dragging with the weight of the " "plates on its back, waving a much livelier looking spiked tail." -msgstr "" +msgstr "一具巨大的蹒跚而行的四足恐龙尸体,移动缓慢,背上有骨板,尾巴上有骨钉。" #: lang/json/MONSTER_from_json.py msgid "Ankylosaurus zombie" msgid_plural "Ankylosaurus zombie" -msgstr[0] "" +msgstr[0] "丧尸甲龙" #. ~ Description for {'str_sp': 'Ankylosaurus zombie'} #: lang/json/MONSTER_from_json.py @@ -69557,11 +70048,12 @@ msgid "" "armored plates and black, glistening eyes. Its tail ends in a massive " "spiked club of bone." msgstr "" +"这具巨大的恐龙尸体看上去像是一种巨大的史前犰狳,它的尾端有一个巨大的骨质狼牙棒。它体表的装甲骨板有些已经剥落了,黑色空洞的眼中有什么正在闪闪发光。" #: lang/json/MONSTER_from_json.py msgid "Apatosaurus zombie" msgid_plural "Apatosaurus zombie" -msgstr[0] "" +msgstr[0] "丧尸迷惑龙" #. ~ Description for {'str_sp': 'Apatosaurus zombie'} #: lang/json/MONSTER_from_json.py @@ -69569,12 +70061,12 @@ msgid "" "Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " "tail. The head is upright and the neck looks like it would still make a " "good strong club." -msgstr "" +msgstr "一具巨大的蹒跚而行的长颈四足恐龙尸体,尾巴非常长,像鞭子一样。它的头能够直立起来,脖子看起来像一根巨大而坚固的棍子。" #: lang/json/MONSTER_from_json.py msgid "Zombie dragon" msgid_plural "Zombie dragon" -msgstr[0] "" +msgstr[0] "丧尸角鼻龙" #. ~ Description for {'str_sp': 'Zombie dragon'} #: lang/json/MONSTER_from_json.py @@ -69582,19 +70074,19 @@ msgid "" "This zombie is enormous, scaly, studded with bony spikes, and it moves with " "horrible speed. Its colorful horns are worn and wet with filth and its " "bright scales and bone spikes have taken a beating." -msgstr "" +msgstr "一具巨大的、鳞片上布满了骨刺的恐龙尸体,它以可怕的速度移动。它五颜六色的角已经磨损,沾满了污秽,它明亮的鳞片和骨刺看上去也受过重创。" #: lang/json/MONSTER_from_json.py msgid "Allosaurus zombie" msgid_plural "Allosaurus zombie" -msgstr[0] "" +msgstr[0] "丧尸异特龙" #. ~ Description for {'str_sp': 'Allosaurus zombie'} #: lang/json/MONSTER_from_json.py msgid "" "The shambling corpse of a large predatory bipedal dinosaur, with tiger-like " "stripes on its broad, scaled back." -msgstr "" +msgstr "一具巨大的蹒跚而行的掠夺性双足恐龙尸体,宽阔的脊背上有着和老虎相似的条纹。" #: lang/json/MONSTER_from_json.py msgid "Deinonychus zombie" @@ -69609,59 +70101,46 @@ msgid "" "sickle-like claw." msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的中型两足恐龙尸体。双脚前端巨大的镰刀状利爪正不断挥舞着。" -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" -msgstr[0] "" +msgstr[0] "丧尸犹他盗龙" #. ~ Description for {'str': 'Utahraptor zombie'} #: lang/json/MONSTER_from_json.py msgid "" "The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," " a long tail, and long sharp scythe-like claws." -msgstr "" +msgstr "一具巨大的蹒跚而行的两足恐龙尸体。有着被破碎羽毛覆盖的胳膊、一个长尾巴和长长的镰刀状的爪子。" #: lang/json/MONSTER_from_json.py msgid "Parasaurolophus zombie" msgid_plural "Parasaurolophus zombie" -msgstr[0] "" +msgstr[0] "丧尸副栉龙" #. ~ Description for {'str_sp': 'Parasaurolophus zombie'} #: lang/json/MONSTER_from_json.py msgid "" "A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " "vacant and swollen." -msgstr "" +msgstr "一具巨大的、身体上有各色斑块的蹒跚而行的恐龙尸体,长着钝的头脊。它正四处游荡,黑漆漆的眼中空洞而肿胀。" #: lang/json/MONSTER_from_json.py msgid "Dimorphodon zombie" msgid_plural "Dimorphodon zombie" -msgstr[0] "" +msgstr[0] "丧尸双型齿翼龙" #. ~ Description for {'str_sp': 'Dimorphodon zombie'} #: lang/json/MONSTER_from_json.py msgid "" "The raggedly flying corpse of a feathered reptile over three feet long, " "with short wings and a big colorful beak." -msgstr "" +msgstr "一具长着破碎羽毛的蹒跚而行的爬行动物尸体,有三英尺长,长着较短的翅膀和颜色鲜艳的大嘴。" #: lang/json/MONSTER_from_json.py msgid "Dilophosaurus zombie" msgid_plural "Dilophosaurus zombie" -msgstr[0] "" +msgstr[0] "丧尸双脊龙" #. ~ Description for {'str_sp': 'Dilophosaurus zombie'} #: lang/json/MONSTER_from_json.py @@ -69669,7 +70148,338 @@ msgid "" "The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" " bony crests on its head with ragged strips of ripped flesh hanging down " "like a frill." +msgstr "一具蹒跚而行的中型恐龙尸体,牙齿很锋利,头部有两个突出的骨冠,上面撕裂的血肉像褶边一样垂落下来。" + +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "恐怖似鸡龙" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的中型两足恐龙尸体。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "恐怖厚头龙" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的中型两足恐龙尸体。它坚硬圆头下的身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "恐怖弯龙" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的大型两足恐龙尸体。它的两条腿肌肉变得肿胀,将肩膀撑得十分鼓胀,长着尖喙。" + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "恐怖棘龙" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." msgstr "" +"一具巨大的腐烂恐龙尸体,有着凶猛的像鳄鱼一样的头,眼睛渗出黑色的液体,背上有一个破烂的帆一样的东西。它的整个身体被肿胀的肌肉和溃烂的伤口撑得更加巨大。" + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "恐怖霸王龙" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "一大坨破烂发臭的血肉,托起了它巨大的牙齿。它的整个身体被肿胀的肌肉和溃烂的伤口撑得更加巨大。" + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "恐怖阿尔伯塔龙" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "一具巨大的恐龙尸体撑起了巨大的大嘴和一对贪婪的利爪,嘴中不断滴落下黑色的液体。它的整个身体被肿胀的肌肉和溃烂的伤口撑得更加巨大。" + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "恐怖三角龙" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" +"一具庞大的、犀牛般的蹒跚而行的恐龙尸体。头上有三个恐怖大角和一个骨质头冠。眼中流出的黑色液体如同眼泪一般滴落下来。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "恐怖剑龙" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "一具巨大的蹒跚而行的四足恐龙尸体,移动缓慢,背上有骨板,尾巴上有骨钉。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "恐怖甲龙" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" +"这具巨大的恐龙尸体看上去像是一种巨大的史前犰狳,它的尾端有一个巨大的骨质狼牙棒。它体表的装甲骨板有些已经剥落了,黑色空洞的眼中有什么正在闪闪发光。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "恐怖迷惑龙" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" +"一具巨大的蹒跚而行的长颈四足恐龙尸体,尾巴非常长,像鞭子一样。它的头能够直立起来,脖子看起来像一根巨大而坚固的棍子。它的整个身体被肿胀的肌肉和溃烂的伤口撑得更加巨大。" + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "恐怖角鼻龙" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" +"一具巨大的、鳞片上布满了骨刺的恐龙尸体,它以可怕的速度移动。它五颜六色的角已经磨损,沾满了污秽,它明亮的鳞片和骨刺看上去也受过重创。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "恐怖异特龙" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "一具巨大的蹒跚而行的掠夺性双足恐龙尸体,宽阔的脊背上有着和老虎相似的条纹。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "恐怖恐爪龙" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" +"一具体表覆盖着破碎羽毛和黑色腐臭液体的蹒跚而行的中型两足恐龙尸体。双脚前端巨大的镰刀状利爪正不断挥舞着。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "恐怖犹他盗龙" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" +"一具巨大的蹒跚而行的两足恐龙尸体。有着被破碎羽毛覆盖的胳膊、一个长尾巴和长长的镰刀状的爪子。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "恐怖副栉龙" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" +"一具巨大的、身体上有各色斑块的蹒跚而行的恐龙尸体,长着钝的头脊。它正四处游荡,黑漆漆的眼中空洞而肿胀。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "恐怖双型齿翼龙" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "一具长着破碎羽毛的蹒跚而行的爬行动物尸体,有三英尺长,长着较短的翅膀和颜色鲜艳的大嘴。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "恐怖双脊龙" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" +"一具蹒跚而行的中型恐龙尸体,牙齿很锋利,头部有两个突出的骨冠,上面撕裂的血肉像褶边一样垂落下来。它的整个身体被肿胀的肌肉和溃烂的伤口撑得十分鼓胀。" + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "暗影丧尸棘龙" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" +"这只丧尸恐龙被一层不可思议的阴影所笼罩,看上去似如光线也拒绝去接触它一般。你唯一能够分辨出来的是一个步履蹒跚的长着破碎背帆的巨型恐龙轮廓。头部又长又窄,有一个V形的鼻子。" + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "暗影丧尸霸王龙" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "" +"这只丧尸恐龙被一层不可思议的阴影所笼罩,看上去似如光线也拒绝去接触它一般。你唯一能够分辨出来的是一个步履蹒跚的模糊的巨型恐龙轮廓。头看起来很大,能装下很多大牙齿。" + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "暗影丧尸恐爪龙" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" +"这只丧尸恐龙被一层不可思议的阴影所笼罩,看上去似如光线也拒绝去接触它一般。你唯一能够分辨出来的是一个步履蹒跚的模糊的中型恐龙轮廓。双脚前端巨大的镰刀状利爪正不断挥舞着。" + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "骸骨霸王龙" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "巨大而密集的骨柱托举起巨大的尖牙,牙尖不断滴下黑色的黏液。" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "骸骨阿尔伯塔龙" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "巨大而密集的骨柱托举起尖牙,牙尖不断滴下黑色的黏液。它的骨爪在身前不断挥舞。" + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "骸骨角鼻龙" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "巨大而密集的骨柱托举起尖牙,牙尖不断滴下黑色的黏液。尖尖的骨刺和五颜六色的角从它的后背刺出。" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "骸骨异特龙" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "巨大而密集的骨柱托举起尖牙,牙尖不断滴下黑色的黏液。" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "骸骨犹他盗龙" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "巨大而密集的骨柱托举起尖牙,牙尖不断滴下黑色的黏液。它的骨爪在身前不断挥舞。它长着一条长长的骨尾和长长的镰刀状的爪子。" #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" @@ -70122,6 +70932,18 @@ msgid "" "off creatures that disturb it." msgstr "尖叫蘑菇怪是一种和人一样大的蘑菇,通过发出刺耳的尖叫声来驱赶打扰它的生物。" +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "牛蛙" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "一只非常普通的美国牛蛙。你最好让王子远离它。" + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -70744,6 +71566,14 @@ msgstr "两栖动物" msgid "a bird" msgstr "鸟类" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "异界改造人" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "沉闷的重击声。" + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "爬行动物" @@ -71478,19 +72308,19 @@ msgstr "这个虚拟法术用于引爆颅脑内的炸弹。极度致命。" #: lang/json/SPELL_from_json.py msgid "Skullgun Snapback" -msgstr "" +msgstr "头骨枪反震" #. ~ Description for Skullgun Snapback #: lang/json/SPELL_from_json.py msgid "" "This fake spell occurs on skullgun activation. May be fatal if done in " "critical condition." -msgstr "" +msgstr "这个虚拟法术用于模拟头骨枪的反震。在重伤时可能会致命。" #. ~ Message for SPELL 'Skullgun Snapback' #: lang/json/SPELL_from_json.py msgid "Your head snaps back from the force of the shot." -msgstr "" +msgstr "你的头被射击的威力反震了!" #: lang/json/SPELL_from_json.py msgid "psi stun" @@ -71614,6 +72444,17 @@ msgid "" "rune as a catalyst for recipes." msgstr "这仪式会创造出一块与泛灵师共鸣的小石块。你可以将符文作为催化剂用于制造其它物品。" +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "裂魂术" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "用暴力将灵魂与躯体撕裂开,并强迫所生成的暗影遵照你的意志行动。" + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "召唤鬼火" @@ -71836,6 +72677,15 @@ msgstr "调试用疲劳法术。" msgid "Uses a little fatigue" msgstr "使用一点疲劳。" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "调试用变形术" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "你想减肥,对吧?" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "调试用生命法术" @@ -72266,6 +73116,10 @@ msgstr "奥术闪电" msgid "Haste" msgstr "加速术" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "恶意变形术" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "奥术光束" @@ -72461,28 +73315,28 @@ msgstr "雾墙术" #: lang/json/SPELL_from_json.py msgid "Repelling Arc Aura" -msgstr "" +msgstr "电弧光环" #. ~ Description for Repelling Arc Aura #: lang/json/SPELL_from_json.py msgid "This is a sub-spell of the Repelling Arc spell." -msgstr "" +msgstr "这只是电弧光环附属的法术。" #. ~ description for the sound of spell 'Repelling Arc Aura' #: lang/json/SPELL_from_json.py msgid "arcing electricity!" -msgstr "" +msgstr "放电声!" #: lang/json/SPELL_from_json.py msgid "Repelling Arc" -msgstr "" +msgstr "电弧光环" #. ~ Description for Repelling Arc #: lang/json/SPELL_from_json.py msgid "" "Manifests an aura of crackling electricity around you to strike attackers " "with baleful lightning." -msgstr "" +msgstr "你在你周围召唤出一道噼啪作响的电弧光环,能放出可怕的闪电电击近战攻击你的敌人。" #: lang/json/SPELL_from_json.py msgid "Bless" @@ -74915,7 +75769,7 @@ msgstr "传说中雷神索尔的神奇腰带,至少看起来是这样的。它 #: lang/json/TOOL_ARMOR_from_json.py msgid "lesser dimensional toolbelt" msgid_plural "lesser dimensional toolbelts" -msgstr[0] "" +msgstr[0] "次级次元工具腰带" #. ~ Description for {'str': 'lesser dimensional toolbelt'} #: lang/json/TOOL_ARMOR_from_json.py @@ -74923,12 +75777,12 @@ msgid "" "A sturdy workman's belt that fits around your waist, covered in easy to " "access pouches. Like all dimensional spaces, they hold more than they " "should with a fair weight reduction." -msgstr "" +msgstr "一条结实合身的工具腰带,上面套着许多方便取用的袋子。像所有的次元袋一样,放入的物品重量会减轻。" #: lang/json/TOOL_ARMOR_from_json.py msgid "greater dimensional toolbelt" msgid_plural "greater dimensional toolbelts" -msgstr[0] "" +msgstr[0] "高级次元工具腰带" #. ~ Description for {'str': 'greater dimensional toolbelt'} #: lang/json/TOOL_ARMOR_from_json.py @@ -74936,7 +75790,7 @@ msgid "" "A heavy duty workman's belt that fits around your waist, covered in easy to " "access pouches. Like all dimensional spaces, they hold far more than they " "should with a substantial weight reduction." -msgstr "" +msgstr "一条特别结实合身的工具腰带,上面套着许多方便取用的袋子。像所有的次元袋一样,放入的物品重量会大大减轻。" #: lang/json/TOOL_ARMOR_from_json.py msgid "Belt of Weaponry" @@ -75952,6 +76806,18 @@ msgid "bionic firestarter" msgid_plural "bionic firestarters" msgstr[0] "生化生火工具" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "烟熏架" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "这是一个虚拟物品,正常不应该出现在你的游戏里。" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -76016,7 +76882,7 @@ msgstr[0] "万圣节南瓜" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "点亮" @@ -78534,12 +79400,6 @@ msgid "pseudo butter churn" msgid_plural "pseudo butter churns" msgstr[0] "虚拟黄油搅拌机" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "这是一个虚拟物品,正常不应该出现在你的游戏里。" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -80694,13 +81554,37 @@ msgid "throwable fire extinguisher" msgid_plural "throwable fire extinguishers" msgstr[0] "投掷型灭火器" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "拉开保险" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "你拉开了投掷型灭火器的保险销。" + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." -msgstr "手榴弹式的灭火器。虽然效果不如常规灭火器,但可以从远处使用它。它受热后自动激活,所以只要把它扔进火中即可。" +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." +msgstr "" +"手榴弹式的灭火器。虽然效果不如常规灭火器,但可以从远处使用它。它有个可以拉开的塑料保险销,但主要依靠受热后自动引爆,所以只要把它扔进火中即可。" + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "投掷型灭火器(无保险)" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" +msgstr "一个拔了插销的投掷型灭火器,随时都会引爆,快点扔掉吧!" #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -80893,24 +81777,24 @@ msgstr "扁平的石头绑在了木棍上,就当做铁锹用吧,虽然显然 #: lang/json/TOOL_from_json.py msgid "metal rake" msgid_plural "metal rakes" -msgstr[0] "" +msgstr[0] "金属耙子" #. ~ Description for {'str': 'metal rake'} #: lang/json/TOOL_from_json.py msgid "A sturdy metal rake, a must-have during autumn." -msgstr "" +msgstr "一把结实的金属耙子,秋季收获必备农具。" #: lang/json/TOOL_from_json.py msgid "plastic rake" msgid_plural "plastic rakes" -msgstr[0] "" +msgstr[0] "塑料耙子" #. ~ Description for {'str': 'plastic rake'} #: lang/json/TOOL_from_json.py msgid "" "A cheap plastic rake. Will break quite fast if used for anything other than" " raking leaves." -msgstr "" +msgstr "一把廉价的塑料耙子。如果把它用于除了耙树叶以外的任何用途,都会很快损坏它。" #: lang/json/TOOL_from_json.py msgid "scythe" @@ -80938,22 +81822,22 @@ msgstr "一个挖坑工具,你可以用它在你周围挖坑。" #: lang/json/TOOL_from_json.py msgid "snow shovel" msgid_plural "snow shovels" -msgstr[0] "" +msgstr[0] "雪铲" #. ~ Description for {'str': 'snow shovel'} #: lang/json/TOOL_from_json.py msgid "This is a sturdy tool used for shoving snow." -msgstr "" +msgstr "一把用来铲雪的结实铲子。" #: lang/json/TOOL_from_json.py msgid "plastic snow shovel" msgid_plural "plastic snow shovels" -msgstr[0] "" +msgstr[0] "塑料雪铲" #. ~ Description for {'str': 'plastic snow shovel'} #: lang/json/TOOL_from_json.py msgid "A cheap plastic shovel used for shoving snow." -msgstr "" +msgstr "一把用来铲雪的廉价塑料铲子。" #: lang/json/TOOL_from_json.py msgid "sickle" @@ -81666,7 +82550,7 @@ msgstr "一种便携式烧炭金工锻造工具。搭配合适当的工具,你 #: lang/json/TOOL_from_json.py msgid "Rock Forge" msgid_plural "Rock Forges" -msgstr[0] "" +msgstr[0] "石头熔炉" #: lang/json/TOOL_from_json.py msgid "metalworking chisel" @@ -81797,13 +82681,13 @@ msgstr "长颈的铝制火钳。是烹饪或金属加工制造的常用工具。 #: lang/json/TOOL_from_json.py msgid "sandpaper" msgid_plural "sheets of sandpaper" -msgstr[0] "" +msgstr[0] "砂纸" #. ~ Description for {'str': 'sandpaper', 'str_pl': 'sheets of sandpaper'} #: lang/json/TOOL_from_json.py msgid "" "A sheet of rough paper. It is commonly used in metalworking and carpentry." -msgstr "" +msgstr "一张粗糙的纸。常用于金属加工和木工。" #: lang/json/TOOL_from_json.py msgid "compressed air horn" @@ -81957,14 +82841,14 @@ msgstr "一床皮毛制成的铺盖,可以卷起来随身携带。垫在地上 #: lang/json/TOOL_from_json.py msgid "garden hose" msgid_plural "garden hoses" -msgstr[0] "" +msgstr[0] "花园软管" #. ~ Description for {'str': 'garden hose'} #: lang/json/TOOL_from_json.py msgid "" "This is a flexible garden hose. If you cut it in smaller pieces, it could " "be used for crafting, or siphoning fuel from a vehicle." -msgstr "" +msgstr "一根柔软的花园用橡胶软管。可以用来做东西,也可以用来从载具中抽油。" #: lang/json/TOOL_from_json.py msgid "grip hook" @@ -84246,7 +85130,7 @@ msgstr "这是一个可移动的砖窑,设计用来烧砖的,但也可以烧 #: lang/json/TOOL_from_json.py msgid "Kiln" msgid_plural "Kilns" -msgstr[0] "" +msgstr[0] "窑炉" #: lang/json/TOOL_from_json.py msgid "paint chipper" @@ -85224,7 +86108,7 @@ msgstr "" #: lang/json/TOOL_from_json.py msgid "complete bionic toolkit" msgid_plural "complete bionic toolkits" -msgstr[0] "" +msgstr[0] "生化插件完全工具箱" #. ~ Description for {'str': 'complete bionic toolkit'} #: lang/json/TOOL_from_json.py @@ -85233,7 +86117,7 @@ msgid "" "designed to disassemble and test the quality of industrially produced " "bionics. A highly skilled and patient engineer could use them to manually " "assemble new cybernetics." -msgstr "" +msgstr "一整套非常小的自动化工具和加密所用的数字密钥,通常用于在工厂中拆解和测试生化插件。一个经验丰富且耐心的工程师可以用它手工组装新的生化插件。" #: lang/json/TOOL_from_json.py msgid "energy saber" @@ -86772,7 +87656,7 @@ msgid "Pheidippides was a hack" msgstr "斐迪庇第斯不过如此" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "跑了一场马拉松……还多一点点。" #: lang/json/achievement_from_json.py @@ -86839,6 +87723,593 @@ msgstr "寻根之旅" msgid "Return to the location you started the game" msgstr "回到游戏起始位置" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "木头" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "一棵树在森林里倒下,如果没有人听见,那么它还会发出声音吗?" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "伐木工" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "对一个拿着斧头的人来说,森林是什么?" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "毁林人" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "如果你砍光所有树木,你就会找到狼。" + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "掘墓人" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "这正是我们需要的:更多的尸体。" + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "盗墓人" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "嘿,如果它们在里面变成丧尸了呢?你总得检查一下。" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "葬礼" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "当数十亿人死无葬身之地时,被埋葬是一种特权。" + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "送葬者" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "不要让任何人在活死人中腐烂。" + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "殡仪馆" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "你总不可能埋葬整个世界,不是吗?" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "赛博朋克" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "Spiritus quidem promptus; caro vero infirma.(心有余而力不足)" + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "发条人" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "以肮脏龌龊的匠人之手。我必对你们痛加报复……究竟做什么我现在还不知道,不过总是人间可怕之事。" + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "进化人" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "旧人类的世界已经结束。新人类的世界万岁。" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "破碎而未被打败" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "你的医保能报这个吗?" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "自由贸易者" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "不寻常的小商品,低得骨折的价格!" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "自作自受的迪布勒" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "我的因纽特朋友,我把这冰块以这么低的价格卖给你,这可真是自作自受啊。" + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "雄辩家" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "我们是朋友啊,不是吗?" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "三寸不烂之舌" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "传说你说服了一只丧尸浩克转身离开。" + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "黑客" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "这个操作系统有个后门。总会有后门的。" + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "还是比不上凯文" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "这不是作弊。这是调试。" + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "实习医生" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "观众中有医生吗?" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "豪斯医生" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "这是狼疮。" + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "工程师" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "把扳手递给我。" + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "百战天龙马盖先" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "这一切都依靠信仰,口水和一卷胶带。" + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "陷阱猎人" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "一个好的陷阱不会区分海狸和丧尸海狸。" + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "扫雷" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "一切只要走错一步。" + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "王牌司机" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "没有转不过的弯。" + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "试替哥" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "一级方程式是为周日慢车司机们准备的。" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "游泳选手" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "像一条水里的鱼。" + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "迈克尔·菲尔普斯" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "游得比大白鲨还快。" + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "动手主义者" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "拿着这个,放进那个里面,瞧好了。" + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "万能博士" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "只要给我适量的胶水,没有什么是我做不了的。" + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "大厨" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "做一道蜜汁里脊真是易如反掌。" + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "地狱厨房" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "今日菜单:法式洋葱汤,法式红酒炖牛肉和法式焦糖布丁。" + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "裁缝" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "一根针,一根线,一个梦。" + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "时装设计师" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "男性,女性和变种人时尚的定义者。" + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "生存狂" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "生存是我的游戏。" + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "贝尔·格里尔斯" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "所以你说你可以靠自己的尿液生存?" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "欧姆定律" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "雷霆欧姆。两伏特进,只有一伏特能出。抵抗是徒劳的。" + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "尼古拉·特斯拉" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "人们不会局限于品尝9V电池的滋味的。" + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "正中靶心" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "比莱格拉斯还准。" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "罗宾汉" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "威廉·退尔?没听过这号人物。" + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "鹰眼" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "只有我和我的目标。" + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "死亡射手" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "别跑了。你只会累着死去。" + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "炮兵" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "口径就是正义。" + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "火箭人" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "我要送你去月球。一块块。" + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "细小但致命" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "当你成为被枪管指着的一方时,口径无所谓。" + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "肮脏的哈里" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "但是这是一把 .44 马格南,世界上最厉害的手枪,能把你的脑袋打飞,你得问问自己:我走运吗?那么,你走运吗,混蛋?" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "步枪兵" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "这是我的步枪,无数支与其相同,但唯独这支属于我。我的步枪是我的挚友,它就是我的命,我必主宰它就如我主宰我的人生。" + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "士兵" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" +"离开了我,我的步枪将一无是处;离开了我的步枪,我将一无是处。我将保证它时刻整洁并能随时战斗,就像我一样整洁并时刻准备战斗那样。我们将彼此成为互相的一部分,我们会……" + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "双份火力,双倍快乐" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "当你想一枪击中你的目标九次的时候。" + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "爱发先生" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "出什么事了,伙计?在打兔子吗?" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "扫射并祈祷" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "总会有一发击中目标的。这是个统计学的问题。" + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "冲锋枪哒哒哒!" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "我们真的需要更多弹药。" + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "耶!" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "然后它再也没回来。" + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "科比·布莱恩特" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "扔手雷了!" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "斗殴大师" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "左手拿瓶子,右手拿椅子腿。" + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "街头霸王" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "最重要是得赢,用什么招式不重要。" + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "击球手" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "每一次挥棒落空都让我更接近下一个全垒打。" + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "石器时代" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "棍棒是人类的第一个工具。而且也很可能是最后一个工具了,为什么不掌握它呢?" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "剑之道" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "剑一出鞘,人的激情就没有止境。" + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "宫本武藏" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "剑不仅仅是一把简单的武器,它还是对生命意义问题的回答。" + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "难以捉摸" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "拳头威力再大,打不中人也不可怕。" + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "尼奥" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "但你能躲过子弹吗?" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "冷钢" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "当你在开派对的时候,我在研究刀刃。" + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "开膛手杰克" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "在我面前摇晃着,它的柄对着我的手的,不是一把刀子吗?来,让我抓住你。" + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "少林之路" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "我觉得我的拳头里有一支军队。" + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "宫城先生" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "成为你自己的武器。" + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "窃贼" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "撬棍?一点技术含量都没有。" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "开锁匠" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "如果有锁,就会有钥匙。" + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "元素周期表" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "有点像烹饪。但别舔勺子。" + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "海森堡" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "你们都知道我是谁。我就是毒师。说出我的名字。" + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "准魔法师" @@ -87293,6 +88764,11 @@ msgstr "入侵" msgid "canceling activity serialized with legacy code" msgstr "终止由旧代码生成的操作" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "锻炼" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "核聚变电池" @@ -87594,6 +89070,10 @@ msgstr "喷雾式化学药剂" msgid "compressed air" msgstr "压缩空气" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "12.3ln 弹" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "纸壳弹" @@ -89473,6 +90953,62 @@ msgstr "不杀死任何NPC。" msgid "Merciful" msgstr "仁慈" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "精灵之路" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "不砍树" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "智人" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "不安装生化插件" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "不安装故障生化插件" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "无变异" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "X-ray安检通过" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "血统纯正" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "结构完整" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "从未骨折" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "老师,放过孩子们把" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "从不提升技能等级" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "自愿当文盲" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "从不读书" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -89623,7 +91159,7 @@ msgstr "移除窗户上的胶带" #: lang/json/construction_from_json.py msgid "Board Up Window" -msgstr "用木板封死窗户" +msgstr "用木板封窗" #: lang/json/construction_from_json.py msgid "Reinforce Boarded Window" @@ -90097,10 +91633,6 @@ msgstr "墙体漆黄色" msgid "Take Paint Off Wall" msgstr "墙体除漆" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "移除地毯" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "铺红色地毯" @@ -90141,6 +91673,30 @@ msgstr "建造木楼梯" msgid "Mine Upstair" msgstr "建造上行矿梯" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "建造混凝土斜坡底部" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "建造一个通往上层的混凝土坡道,需要在上层建造对应的通往本层的坡道。坡道顶部需要与底部相邻,这样才能在两层之间来回移动。" + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "建造混凝土斜坡顶部" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "建造一个通往下层的混凝土坡道,需要在下层建造对应的通往本层的坡道。坡道顶部需要与底部相邻,这样才能在两层之间来回移动。" + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "开始车辆建造" @@ -93131,7 +94687,7 @@ msgstr "你抽了几口。" msgid "You smoked too much." msgstr "你抽得有点多。" -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "亢奋" @@ -95150,6 +96706,18 @@ msgstr "火焰" msgid "raging fire" msgstr "烈焰" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "灭火剂薄雾" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "灭火剂喷雾" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "灭火剂浓雾" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "碎石残留" @@ -96176,8 +97744,7 @@ msgid "" msgstr "一个常见的家具,用于在室内安全地生火,还有一个烟囱将烟雾排出到室外。但在点燃时单独离开也可能会导致危险。" #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "撞击声!" @@ -96346,7 +97913,7 @@ msgid "" msgstr "一大堆树叶,如果你不在乎舒适和温暖,你可以睡在上面。" #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "嘎嚓!" @@ -96995,10 +98562,9 @@ msgstr "健身器" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." -msgstr "一套沉重的用于力量训练的举重设备,一对杠铃片固定在一根结实的钢管两端。重量相当可观,在没有辅助观察者的情况下使用它们很容易对自己造成重伤。" +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." +msgstr "一套沉重的用于力量训练的举重设备,一对杠铃片固定在一根结实的钢管两端。你可以手工挑选自己所想使用的重量来调整设备。" #: lang/json/furniture_from_json.py msgid "ball machine" @@ -97088,6 +98654,18 @@ msgid "" " to be scavanged." msgstr "一台锻炼身体的机器,有一套手柄和滑板,用来模拟划船。如果没有供电,它就不能运行,但它可能有一些能回收的有用零件。" +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "机械划船机" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "一台锻炼身体的机器,有一套手柄和滑板,用来模拟划船。这台是旧型号,使用机械调整阻力,不需要供电就可以使用。" + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "跑步机" @@ -97100,6 +98678,19 @@ msgid "" "you're probably getting enough cardio on your own." msgstr "一根带控制面板的电动传送带。没有动力,想再让皮带动起来会是巨大的挑战。不管怎么说,你自己可能已经进行了足够多的有氧运动了。" +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "重力跑步机" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" +"一台带有机械控制面板的重力驱动跑步机,可以让你在原地锻炼身体。跑步机的传送带很陡峭,但倾斜角度可以手动调节,所以它能在你的体重作用下向后滚动。" + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "训练沙袋" @@ -98369,10 +99960,6 @@ msgstr "一个用于煅烧粉末状焦炭石灰混合物来制取电石的电弧 msgid "filled arc furnace" msgstr "电弧炉(满)" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "烟熏架" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -99122,7 +100709,8 @@ msgstr "射出酸液球的假枪。" msgid "auto" msgstr "自动" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "步枪" @@ -99292,8 +100880,8 @@ msgid "" "standard UPS." msgstr "一款自制的激光手枪,设计灵感源自于21世纪中期的V29激光手枪。虽然只是各类由胶带简单固定在一起电子原件,它依旧可以使用标准的UPS供能。" -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "手枪" @@ -99354,7 +100942,7 @@ msgid "" "deadly." msgstr "一把可以连续发射的气动突击步枪,采用废料自制而成。极度安静而致命。" -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "半自动" @@ -99778,9 +101366,9 @@ msgid "" msgstr "一把采用经典 AR-15 步枪设计,结构紧凑,使用7.5英寸长枪管的手枪,商业宣传上主要将它当作家庭防御武器销售。" #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" -msgstr[0] "MAS 223 步枪" +msgid "MAS .223" +msgid_plural "MAS .223" +msgstr[0] "MAS .223 步枪" #: lang/json/gun_from_json.py msgid "" @@ -102051,20 +103639,20 @@ msgstr "" "以制造廉价武器而知名,其生产的武器常常体积巨大且使用不便。Hi-Point 制造的枪械的套筒由锌合金制成,相比钢制套筒来说比较脆弱。" #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" -msgstr[0] "CZ-75 手枪" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" +msgstr[0] "CZ-75 B 手枪" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " "pistol remains wildly popular among competition shooters." msgstr "" -"CZ-75 " +"CZ-75 B " "手枪是一种由捷克斯洛伐克研制的半自动手枪。尽管是为出口至西方国家而设计,这个设计却在当时被列为了国家秘密。由于缺乏国际专利保护,全世界都开始了这种型号或衍生型号的生产和销售,而最初设计该型号的乌尔斯基·布罗德兵工厂直到二十世纪八十年代才开始境内的销售。这种手枪仍在射击比赛中被广泛使用。" #: lang/json/gun_from_json.py @@ -102172,6 +103760,40 @@ msgstr "" "一把后部装弹式双枪管组合枪,枪上方一条 .30-06 " "口径子弹带膛线枪管,下方有两根装载12号霰弹的滑膛枪管。这种枪历史上曾经在非洲被那些贪心不足的偷猎者们用来射杀大小动物,而现在则被新英格兰的那些狂妄的装逼犯们拿来装逼。" +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "PA Md. 68 战斗步枪" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" +"在所有使用 12.3ln 弹的枪械中,最受欢迎的的枪当然是PA Md. 71 步枪。作为它的前身,PA Md. 68 " +"战斗步枪被许多人认为是某种程度上的失败品:虽然它非常可靠而且威力强大,但它太重了,不是一把好的步兵武器,但又不足以成为一把好的支援武器。尽管如此,它仍然被大量制造,在随后到来的丧尸末日之中,作为一种弹药很容易获得的轻型炮塔枪,受到了人们的再次青睐。而且它完全符合流放族的需求,它们对这把枪械不灵活的使用条件不太在意。" + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "PA Md. 71 丧尸狩猎步枪" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" +"这款极受欢迎的罗马尼亚突击步枪,在第三次喀尔巴阡山战争中闻名于世,被流放族略微修改了设计,作为狙击武器使用。它非常适合用来精确狙击优先目标。改进后的设计能够非常快速地射出5连发,完全粉碎目标防止其复活。" + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -102681,15 +104303,15 @@ msgstr "" "霰弹枪是首批在商业上成功的泵动霰弹枪之一。它的\"堑壕战\"型号已经成为一个高度浪漫化的一战美国象征。它的枪套、刺刀卡口和17英寸长的刺刀,无可否认,让这把霰弹枪看上去十分骇人。现在已经没有战壕需要清理,但来个充满丧尸的城镇也足够了。" #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" -msgstr[0] "" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" +msgstr[0] "自制“四风”霰弹枪" #: lang/json/gun_from_json.py msgid "" "A crude shotgun, composed of two thick steel pipes, an end cap and a nail. " "The lack of sights make this weapon only useful at point-blank range." -msgstr "" +msgstr "一把自制的简易霰弹枪,由两根厚钢管、一个后盖和一根钉子组成。由于缺乏瞄具,这把武器只能在近距离使用。" #: lang/json/gun_from_json.py msgid "flaregun" @@ -103326,11 +104948,29 @@ msgstr "三管激光" #: lang/json/gun_from_json.py msgid "bionic skullgun" msgid_plural "bionic skullguns" -msgstr[0] "" +msgstr[0] "生化头骨枪" #: lang/json/gun_from_json.py msgid "Bionic one-shot subdermal .40 pistol integrated with your head." -msgstr "" +msgstr "通过生化插件植入你头骨的单发伸缩式手枪。" + +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "改装马林 39A 步枪" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "一把经过改装的马林 39A 步枪,可以被安装在炮塔上使用。" + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "改装 SKS 步枪" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "一把经过改装的 SKS 步枪,可以被安装在炮塔上使用。" #: lang/json/gun_from_json.py msgid "CRIT .5 LP" @@ -104109,11 +105749,6 @@ msgid "" msgstr "" "一种使用可拆卸弹匣供弹的霰弹枪,主要用户是狂热的普通爱好者。它有一条导轨、看上去相当有威慑力的黑色外观,这类霰弹枪看上去一点都不像是为竞赛设计的。它使用弹匣供弹,减少了霰弹枪为人熟知的漫长装填时间。尽管因为保养要求高而出名,但经过使用者的精心校准之后可以提高整体可靠性。" -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -105985,6 +107620,12 @@ msgid "" " experiment" msgstr "你尝试从这失败的实验体中搜寻还能再次使用的生化插件" +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "你尝试从这具血肉和金属混合的怪物中搜寻还能再次使用的零件" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -108090,10 +109731,6 @@ msgstr "书写" msgid "Teleport yourself" msgstr "传送自己" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "扑灭火焰" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "擦干/清理自己" @@ -109332,6 +110969,14 @@ msgstr "离开创建角色选单" msgid "Toggle sorting order" msgstr "切换排序顺序" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "随机生成职业" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "随机生成场景" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "向上滚动描述" @@ -109732,6 +111377,10 @@ msgstr "拆解物品" msgid "Sleep" msgstr "睡觉" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "锻炼" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "控制载具" @@ -110205,12 +111854,12 @@ msgstr "读取配色模板" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "是" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "否" @@ -110783,12 +112432,12 @@ msgstr "这里有个吸引丧尸的陷阱。" #: lang/json/map_extra_from_json.py msgid "Reed" -msgstr "" +msgstr "芦苇" #. ~ Description for {'str': 'Reed'} #: lang/json/map_extra_from_json.py msgid "Water vegetation." -msgstr "" +msgstr "一种水生植物。" #. ~ Computer name #: lang/json/mapgen_from_json.py @@ -112278,7 +113927,7 @@ msgid "" msgstr "" "你通过反复移动来变得更加难以击中。\n" "\n" -"闪避技能+1。\n" +"闪避技能 +1。\n" "持续 1 回合,可叠加 2 次。" #: lang/json/martial_art_from_json.py @@ -112376,7 +114025,7 @@ msgid "" msgstr "" "你的持续不停的舞步使你在战斗时异常灵巧。\n" "\n" -"闪避技能+1,闪避次数+1。" +"闪避技能 +1,闪避次数 +1。" #: lang/json/martial_art_from_json.py msgid "Capoeira Momentum" @@ -112394,7 +114043,7 @@ msgid "" msgstr "" "你能感受到你移动的节奏。你不仅更加难以击中,你的脚法也变得更加炫酷!\n" "\n" -"闪避技能+1。\n" +"闪避技能 +1。\n" "解锁“回旋踢”和“扫堂腿”。\n" "持续 3 回合。" @@ -112412,6 +114061,10 @@ msgid "" "+15% Bash damage.\n" "Lasts 2 turns. Stacks 3 times." msgstr "" +"你从不击空,这只是舞蹈的一部分,而最棒的部分即将开始!\n" +"\n" +"+15% 钝击伤害。\n" +"持续 2 回合。可叠加 3 次。" #: lang/json/martial_art_from_json.py msgid "Crane Kung Fu" @@ -112607,6 +114260,11 @@ msgid "" "Enables \"Combination Strike\" technique.\n" "Lasts 3 turns. Stacks 3 times." msgstr "" +"机会出现之时,你能在暴击之后连上一招更强的攻击。\n" +"\n" +"+15% 所有伤害。\n" +"解锁“组合连击”招式。\n" +"持续 3 回合。可叠加 3 次。" #: lang/json/martial_art_from_json.py msgid "Fencing" @@ -112661,10 +114319,14 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn." msgstr "" +"由于你的招架,你的下一次攻击更容易命中敌人。\n" +"\n" +"命中 +1。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Remise" -msgstr "" +msgstr "二次进攻" #. ~ Description of buff 'Remise' for martial art '{'str': 'Fencing'}' #: lang/json/martial_art_from_json.py @@ -112675,6 +114337,11 @@ msgid "" "Enables \"Compound Attack\" technique.\n" "Lasts 1 turn." msgstr "" +"你的佯攻是下一次致命一击的完美准备!\n" +"\n" +"命中 +1。\n" +"解锁“复杂进攻”招式。\n" +"持续 1 回合。" #. ~ Description for martial art '{'str': 'Fior Di Battaglia'}' #: lang/json/martial_art_from_json.py @@ -112733,7 +114400,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Defense Break" -msgstr "" +msgstr "防御反击" #. ~ Description of buff 'Defense Break' for martial art '{'str': 'Fior Di #. Battaglia'}' @@ -112744,10 +114411,14 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn. Stacks 3 times." msgstr "" +"每一个成功的阻挡都会暴露出你对手防守的漏洞。\n" +"\n" +"命中 +1。\n" +"持续 1 回合。可叠加 3 次。" #: lang/json/martial_art_from_json.py msgid "Tactical Feinting" -msgstr "" +msgstr "战术佯攻" #. ~ Description of buff 'Tactical Feinting' for martial art '{'str': 'Fior Di #. Battaglia'}' @@ -112758,6 +114429,10 @@ msgid "" "Enables \"Hook and Drag\" technique.\n" "Lasts 1 turn." msgstr "" +"他们被你的佯攻给骗了!\n" +"\n" +"解锁“勾拽”招式。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Judo" @@ -112950,7 +114625,7 @@ msgid "" msgstr "" "你就像猫一样动作敏捷,难以被抓住。\n" "\n" -"闪避技能 +1.0。" +"闪避技能 +1。" #: lang/json/martial_art_from_json.py msgid "Leopard's Stalk" @@ -113036,7 +114711,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Deflection" -msgstr "" +msgstr "偏斜格挡" #. ~ Description of buff 'Deflection' for martial art '{'str': 'Medieval #. Swordsmanship'}' @@ -113046,10 +114721,14 @@ msgid "" "Enables \"Sweeping Strike\" and \"Deathblow\" techniques.\n" "Lasts 1 turn." msgstr "" +"你偏斜格挡了敌人的攻击,现在可以反击敌人了!\n" +"\n" +"解锁“横扫攻击”和“雷霆一击”招式。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Manslayer" -msgstr "" +msgstr "杀心四起" #. ~ Description of buff 'Manslayer' for martial art '{'str': 'Medieval #. Swordsmanship'}' @@ -113059,6 +114738,10 @@ msgid "" "Enables \"Vicious Strike\" techniques.\n" "Lasts 1 turn." msgstr "" +"你的强力一击给了你结束这场战斗的机会!\n" +"\n" +"解锁“要害攻击”招式。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Muay Thai" @@ -113116,6 +114799,10 @@ msgid "" "+Bash damage increased by 25% of Strength, blocked damage decreased by 50% of Strength.\n" "Lasts 5 turns." msgstr "" +"受到攻击并不会减慢你的速度。你能比你的对手撑得更久,从而赢得这场比赛。\n" +"\n" +"钝击伤害按 力量 的 25% 增加,格挡后伤害按 力量 的 50% 降低。\n" +"持续 5 回合。" #: lang/json/martial_art_from_json.py msgid "Ninjutsu" @@ -113190,12 +114877,12 @@ msgid "" msgstr "" "忍者训练注重敏捷和灵活。\n" "\n" -"+1 闪避技能,命中率按敏捷的 20% 提升。\n" +"闪避技能 +1,命中按敏捷的 20% 提升。\n" "持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Loss of Surprise" -msgstr "" +msgstr "失去奇袭" #. ~ Description of buff 'Loss of Surprise' for martial art '{'str': #. 'Ninjutsu'}' @@ -113207,10 +114894,14 @@ msgid "" "-50% all damage.\n" "Last 3 turns." msgstr "" +"你的意图已经被人发现了!你需要过一阵子才能再次偷袭。\n" +"\n" +"-50% 所有伤害。\n" +"持续 3 回合。" #: lang/json/martial_art_from_json.py msgid "Escape Plan" -msgstr "" +msgstr "逃脱计划" #. ~ Description of buff 'Escape Plan' for martial art '{'str': 'Ninjutsu'}' #: lang/json/martial_art_from_json.py @@ -113220,6 +114911,10 @@ msgid "" "+2 Dodge attempts, +10 movement speed.\n" "Last 3 turns." msgstr "" +"你的目标已经死了。是时候逃离并计划下一次攻击了。\n" +"\n" +"闪避次数 +2,移动速度 +10。\n" +"持续 3 回合。" #: lang/json/martial_art_from_json.py msgid "Niten Ichi-Ryu" @@ -113285,9 +114980,9 @@ msgid "" msgstr "" "暗如黑夜\n" "魑魅魍魉,四面袭来\n" -"快跑!\n" +"速速逃离!\n" "\n" -"-5.0 闪避技能。\n" +"闪避技能 -5。\n" "持续 1 回合。" #: lang/json/martial_art_from_json.py @@ -113305,7 +115000,7 @@ msgid "" "Enables \"In-One Timing\".\n" "Lasts 1 turn." msgstr "" -"幸有此光\n" +"幸有此光,\n" "于此暗夜\n" "有如月洒清辉\n" "\n" @@ -113314,7 +115009,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Falling Leaf" -msgstr "" +msgstr "落叶" #. ~ Description of buff 'Falling Leaf' for martial art '{'str': 'Niten Ichi- #. Ryu'}' @@ -113327,10 +115022,16 @@ msgid "" "-1.0 Dodge skill, -1 bash damage, -1 cut damage.\n" "Lasts 1 turn. Stacks 5 times." msgstr "" +"利刃已出鞘,\n" +"然则万物随时间消逝。\n" +"唯忍得以精进此术。\n" +"\n" +"闪避技能 -1,钝击伤害 -1,斩击伤害 -1。\n" +"持续 1 回合。可堆叠 5 次。" #: lang/json/martial_art_from_json.py msgid "Stillness" -msgstr "" +msgstr "宁静" #. ~ Description of buff 'Stillness' for martial art '{'str': 'Niten Ichi- #. Ryu'}' @@ -113344,6 +115045,12 @@ msgid "" "+2 Accuracy, Dodge skill increased by 50% of Perception.\n" "Lasts 2 turns." msgstr "" +"风暴之眼,\n" +"安宁须臾,\n" +"旋即消失无踪。\n" +"\n" +"命中 +2,闪避技能按 感知 的 50% 增加。\n" +"持续2回合。" #: lang/json/martial_art_from_json.py msgid "Pankration" @@ -113518,7 +115225,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Snake's Coil" -msgstr "" +msgstr "蛇之盘绕" #. ~ Description of buff 'Snake's Coil' for martial art '{'str': 'Snake Kung #. Fu'}' @@ -113530,6 +115237,10 @@ msgid "" "+1 Accuracy, gain armor penetration equal to 50% of Perceptions.\n" "Lasts 1 turn. Stacks 3 times." msgstr "" +"每条蛇都会等待完美一击的时刻的到来。当你的对手分心时,毫无怜悯地攻击他们的弱点!\n" +"\n" +"命中 +1,护甲穿透按 感知的 50% 增加。\n" +"持续 1 回合。可叠加 3 次。" #: lang/json/martial_art_from_json.py msgid "Sōjutsu" @@ -113710,7 +115421,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Cross Hands" -msgstr "" +msgstr "十字手" #. ~ Description of buff 'Cross Hands' for martial art '{'str': 'Tai Chi'}' #: lang/json/martial_art_from_json.py @@ -113722,6 +115433,10 @@ msgid "" "Enables \"Palm Strike\" and \"Double Palm Strike\" techniques.\n" "Lasts 3 turns." msgstr "" +"通过花点时间为自己下一步招式做准备,你可以充分利用全身来攻击和防守。\n" +"\n" +"闪避技能 +1,格挡后伤害按感知的50%减少。\n" +"解锁“拗步掌”和“双按掌”招式。持续 3 回合。" #: lang/json/martial_art_from_json.py msgid "Tiger Kung Fu" @@ -113786,7 +115501,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Tiger Rampage" -msgstr "" +msgstr "虎之怒" #. ~ Description of buff 'Tiger Rampage' for martial art '{'str': 'Tiger Kung #. Fu'}' @@ -113798,6 +115513,10 @@ msgid "" "Gain Armor Penetration equal to 50% of Strength.\n" "Lasts 1 turns. Stacks 2 times." msgstr "" +"你的对手输了就是你赢了。你的下一击能够击破对手的防御。\n" +"\n" +"护甲穿透按力量的50%增加。\n" +"持续 1 回合。可叠加 2 次。" #: lang/json/martial_art_from_json.py msgid "Wing Chun" @@ -113858,11 +115577,11 @@ msgid "" msgstr "" "你对平衡和技巧有更深的理解。这让你能更好地躲开你的对手的攻击。\n" "\n" -"闪避技能按感知的 15% 增加。格挡伤害按感知的 50% 减少。" +"闪避技能按感知的 15% 增加。格挡后伤害按感知的 50% 减少。" #: lang/json/martial_art_from_json.py msgid "Biu Ji" -msgstr "" +msgstr "咏春标指" #. ~ Description of buff 'Biu Ji' for martial art '{'str': 'Wing Chun'}' #: lang/json/martial_art_from_json.py @@ -113873,6 +115592,10 @@ msgid "" "Accuracy increased by 20% of Perception, Enables \"Straight Punch (Knockback)\" and \"L-Hook (Knockback)\" techniques.\n" "Lasts 2 turns." msgstr "" +"通过完美地应用插指的招式,你可以打击对手的弱点,迫使他们后退,然后跟进一击!\n" +"\n" +"命中按感知的20%增加,解锁“直拳(击退)”和“左勾拳(击退)”招式。\n" +"持续2回合。" #: lang/json/martial_art_from_json.py msgid "Zui Quan" @@ -114005,18 +115728,18 @@ msgstr "+力量 钝击防护,+敏捷 酸液防护,+智力 电击防护,+ #: lang/json/martial_art_from_json.py msgid "Getting Angry" -msgstr "" +msgstr "我怒了" #. ~ Description of buff 'Getting Angry' for martial art '{'str': 'Debug #. Mastery'}' #: lang/json/martial_art_from_json.py msgid "" "When I get my hands on you… +2 bash damage for 2 turns. Stacks 5 times." -msgstr "" +msgstr "别让我抓住你…… +2 钝击伤害。持续 2 回合。可叠加 5 次。" #: lang/json/martial_art_from_json.py msgid "Lightning Strike" -msgstr "" +msgstr "闪电攻击" #. ~ Description of buff 'Lightning Strike' for martial art '{'str': 'Debug #. Mastery'}' @@ -114024,12 +115747,12 @@ msgstr "" msgid "" "Lightning strikes twice. +Perception electric damage for 3 turns. Stacks 2" " times." -msgstr "" +msgstr "闪电能击中两次。+感知 电击伤害。持续 3 回合。可叠加 2 次。" #. ~ Description of buff 'On Fire' for martial art '{'str': 'Debug Mastery'}' #: lang/json/martial_art_from_json.py msgid "YOU ARE ON FIRE! +5 fire damage for 5 turns." -msgstr "" +msgstr "你着火了!+5 火焰伤害。持续 5 回合。" #: lang/json/martial_art_from_json.py msgid "Bionic Combatives" @@ -114078,7 +115801,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Optimization" -msgstr "" +msgstr "优化" #. ~ Description of buff 'Optimization' for martial art '{'str': 'Bionic #. Combatives'}' @@ -114091,6 +115814,12 @@ msgid "" "+1 Accuracy, +2 all damage.\n" "Lasts 3 turns. Stacks 3 times." msgstr "" +">10 锁定目标\n" +">20 击杀目标\n" +">30 GOTO 10\n" +"\n" +"命中 +1,所有伤害 +2。\n" +"持续 3 回合。可叠加 3 次。" #: lang/json/martial_art_from_json.py msgid "Centipede Kung Fu" @@ -114135,7 +115864,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Centipede's Venom" -msgstr "" +msgstr "蜈蚣毒" #. ~ Description of buff 'Centipede's Venom' for martial art '{'str': #. 'Centipede Kung Fu'}' @@ -114146,6 +115875,10 @@ msgid "" "+2 bashing damage.\n" "Lasts 2 turns." msgstr "" +"你的毒液是你的对手永远无法忘却的长久苦痛。\n" +"\n" +"+2 钝击伤害。\n" +"持续 2 回合。" #: lang/json/martial_art_from_json.py msgid "Lizard Kung Fu" @@ -114205,8 +115938,8 @@ msgid "" msgstr "" "通过简单地攀爬、跳跃或推开附近的墙壁,你可以避开对手最严重的攻击。\n" "\n" -"紧邻墙壁时 +3.0 闪避技能。\n" -"紧邻墙壁时解锁\"壁虎之尾\"及\"壁虎墙反\"招式。" +"紧邻墙壁时闪避技能 +3。\n" +"紧邻墙壁时解锁“壁虎扫尾”及“壁虎墙反”。" #: lang/json/martial_art_from_json.py msgid "Lizard's Leap" @@ -114284,13 +116017,13 @@ msgid "" msgstr "" "向前冲,抓住你的猎物!\n" "\n" -"所有伤害 +10%。\n" +"+10% 伤害。\n" "解锁“巨螯击”。\n" "可叠加 2 次。持续 2 回合。" #: lang/json/martial_art_from_json.py msgid "Scorpion's Intimidation" -msgstr "" +msgstr "蝎之威慑" #. ~ Description of buff 'Scorpion's Intimidation' for martial art '{'str': #. 'Scorpion Kung Fu'}' @@ -114301,6 +116034,10 @@ msgid "" "+1 Dodge attempts.\n" "Lasts 1 turn." msgstr "" +"没有什么比一只被激怒的蝎子更可怕的了。你的攻击可以威吓你的敌人。\n" +"\n" +"闪避次数 +1。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Toad Kung Fu" @@ -114363,7 +116100,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Toad's Meditation" -msgstr "" +msgstr "蛤蟆冥想功" #. ~ Description of buff 'Toad's Meditation' for martial art '{'str': 'Toad #. Kung Fu'}' @@ -114374,10 +116111,14 @@ msgid "" "+3 bash, cut, and stab armor.\n" "Lasts 2 turns." msgstr "" +"通过集中注意力,你可以增强你的铁布衫的力量。\n" +"\n" +"+3 钝击/斩击/刺击防护。\n" +"持续 2 回合。" #: lang/json/martial_art_from_json.py msgid "Toad's Venom" -msgstr "" +msgstr "蛤蟆毒" #. ~ Description of buff 'Toad's Venom' for martial art '{'str': 'Toad Kung #. Fu'}' @@ -114388,6 +116129,10 @@ msgid "" "+2 bash damage.\n" "Lasts 5 turns." msgstr "" +"你的毒液只不过是你的铁布衫威力的又一课。\n" +"\n" +"+2 钝击伤害。\n" +"持续 5 回合。" #: lang/json/martial_art_from_json.py msgid "Viper Kung Fu" @@ -114444,7 +116189,7 @@ msgid "" msgstr "" "你的闪避能力使你的对手很容易受到痛苦的伤害。\n" "\n" -" 解锁\"毒蛇疯咬\"。\n" +"解锁“毒蛇疯咬”。\n" "持续 1 回合。" #: lang/json/martial_art_from_json.py @@ -114760,7 +116505,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Quicksilver Motion" -msgstr "" +msgstr "神行" #. ~ Description of buff 'Quicksilver Motion' for martial art '{'str': #. 'Diamond Mind'}' @@ -114771,10 +116516,14 @@ msgid "" "+50 Speed.\n" "Lasts 1 turn." msgstr "" +"在眨眼间,你已经移动。你的速度、反应、以及自信让你可以快速而勇敢的移动,让对手猝不及防。\n" +"\n" +"+50 速度。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Mind over Body" -msgstr "" +msgstr "精神御体" #. ~ Description of buff 'Mind over Body' for martial art '{'str': 'Diamond #. Mind'}' @@ -114785,6 +116534,10 @@ msgid "" "+1 Accuracy.\n" "Lasts 1 turn. Stacks 2 times" msgstr "" +"你的训练和精神力让你可以用专注力克服肉体的威胁。\n" +"\n" +"命中 +1。\n" +"持续 1 回合。可叠加 2 次。" #: lang/json/martial_art_from_json.py msgid "Hylian Swordsmanship" @@ -114898,7 +116651,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Charge Up" -msgstr "" +msgstr "蓄力" #. ~ Description of buff 'Charge Up' for martial art '{'str': 'Hylian #. Swordsmanship'}' @@ -114910,6 +116663,10 @@ msgid "" "+20% damage, enables \"Spin Attack\" technique.\n" "Lasts 1 turn." msgstr "" +"花点时间准备,你可以释放出一记威力强大的回旋斩!\n" +"\n" +"+20% 伤害,解锁“回旋斩”招式。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Iron Heart" @@ -115024,7 +116781,7 @@ msgstr "%s 准备好和人战斗了。" #: lang/json/martial_art_from_json.py msgid "Stamina" -msgstr "" +msgstr "持久力" #. ~ Description of buff 'Stamina' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -115035,10 +116792,14 @@ msgid "" "Gain bash, cut, stab armor equal to 50% of Strength.\n" "Lasts 3 turns." msgstr "" +"受到攻击时,你的防御会提高。\n" +"\n" +"钝击/斩击/刺击防护按力量的50%提升。\n" +"持续3回合。" #: lang/json/martial_art_from_json.py msgid "Sniper" -msgstr "" +msgstr "狙击手" #. ~ Description of buff 'Sniper' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -115049,10 +116810,14 @@ msgid "" "+50% damage.\n" "Lasts 1 turn." msgstr "" +"击中要害时,威力会变得更强。\n" +"\n" +"+50% 伤害。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Moxie" -msgstr "" +msgstr "自信过度" #. ~ Description of buff 'Moxie' for martial art '{'str': 'Pokken'}' #: lang/json/martial_art_from_json.py @@ -115063,6 +116828,10 @@ msgid "" "+50% damage.\n" "Lasts 3 turns." msgstr "" +"如果打倒对手,就会充满自信,攻击会提高。\n" +"\n" +"+50% 伤害。\n" +"持续 3 回合。" #: lang/json/martial_art_from_json.py msgid "Setting Sun" @@ -115075,7 +116844,8 @@ msgid "" "strength against them. With a quick shift in stance and carefully aimed " "attack, a Setting Sun warrior sends a charging enemy tumbling in a new " "direction." -msgstr "暮日流派教导其修习者利用敌人的力量对抗敌人。随着姿态的快速转变和精心瞄准的攻击,暮日战士能让向自己冲锋的敌人失去重心翻滚向另一个方向。" +msgstr "" +"暮日派教导门徒借力打力。随着姿态的快速转变和精心瞄准的攻击,依靠着四两拨千斤的巧劲,暮日派的武道家可以让向自己冲锋的敌人失去重心翻滚向另一个方向。" #. ~ initiate message for martial art '{'str': 'Setting Sun'}' #: lang/json/martial_art_from_json.py @@ -115090,7 +116860,7 @@ msgstr "%s 调整重心,摆出了一个新姿势。" #: lang/json/martial_art_from_json.py msgid "Baffling Defense" -msgstr "" +msgstr "千幻防御" #. ~ Description of buff 'Baffling Defense' for martial art '{'str': 'Setting #. Sun'}' @@ -115102,10 +116872,14 @@ msgid "" "Dodging Skill increased by 20% of Intelligence, enables \"Mighty Throw\" and \"Ballista Throw\" techniques.\n" "Lasts 1 turn." msgstr "" +"你单脚半蹲,手放在顶门。你的对手犹豫着,没法确定该如何攻击这种诡异的架势。\n" +"\n" +"闪避技能按智力的20%提升,解锁“暮日投”和“穿云投”。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Feigned Opening" -msgstr "" +msgstr "伪装破绽" #. ~ Description of buff 'Feigned Opening' for martial art '{'str': 'Setting #. Sun'}' @@ -115116,6 +116890,10 @@ msgid "" "+20 Speed.\n" "Lasts 1 turn." msgstr "" +"你向你的目标露出好像是致命的破绽,但却轻易地避开,并在同时让对手为轻率的进击付出代价。\n" +"\n" +"+20 速度。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Shii-Cho" @@ -115207,7 +116985,7 @@ msgstr "" #: lang/json/martial_art_from_json.py msgid "Stone Dragon" -msgstr "" +msgstr "石龙" #. ~ Description for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py @@ -115216,22 +116994,22 @@ msgid "" "Its teachings grant a martial adept the ability to splinter steel with a " "single, focused blow. Stone Dragon's defensive abilities focus on tapping " "into the enduring power of stone to turn aside attacks." -msgstr "" +msgstr "石龙流专注于力量,威力以及强壮。它传授了武技学徒在一击间破金裂石的威力。石龙的防御则注重于将对手的攻击的破坏力转嫁到大地上。" #. ~ initiate message for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py msgid "You dig your heels into the ground and steady yourself." -msgstr "" +msgstr "你将脚后跟扎入土中,稳住自己。" #. ~ initiate message for martial art '{'str': 'Stone Dragon'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s digs their heels into the ground." -msgstr "" +msgstr "%s 将脚后跟扎入土中。" #: lang/json/martial_art_from_json.py msgid "Stone Bones" -msgstr "" +msgstr "石铸身躯" #. ~ Description of buff 'Stone Bones' for martial art '{'str': 'Stone #. Dragon'}' @@ -115242,10 +117020,14 @@ msgid "" "+1 bash, cut, and stab armor.\n" "Lasts 1 turn. Stacks 5 times." msgstr "" +"你聚集你的武器打中对手时产生的能量来强化自己的防御,这使你在面对接下来的反击时立于不败之地。\n" +"\n" +"+1 钝击/斩击/刺击防护。\n" +"持续 1 回合。可叠加 5 次。" #: lang/json/martial_art_from_json.py msgid "Stonefoot Stance" -msgstr "" +msgstr "坚如磐石" #. ~ Description of buff 'Stonefoot Stance' for martial art '{'str': 'Stone #. Dragon'}' @@ -115256,10 +117038,13 @@ msgid "" "\n" "+10% damage, +2 bash, cut, and stab armor." msgstr "" +"你将重心沉向下盘,将大地之力转化为自身的抗力。然而,移动太多会破坏你的姿势。\n" +"\n" +"+10% 伤害,+2 钝击/斩击/刺击防护。" #: lang/json/martial_art_from_json.py msgid "Cracked Stone" -msgstr "" +msgstr "裂石" #. ~ Description of buff 'Cracked Stone' for martial art '{'str': 'Stone #. Dragon'}' @@ -115270,10 +117055,14 @@ msgid "" "Enables \"Shattered Stone\" buff.\n" "Lasts 1 turn." msgstr "" +"移动太多会破坏坚如磐石的效果。站稳了别动,不要破坏了你的姿势!\n" +"\n" +"解锁“碎石”。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Stattered Stone" -msgstr "" +msgstr "碎石" #. ~ Description of buff 'Stattered Stone' for martial art '{'str': 'Stone #. Dragon'}' @@ -115285,10 +117074,14 @@ msgid "" "-10% damage, -2 bash, cut, and stab armor.\n" "Lasts 4 turn." msgstr "" +"你完全无法保持坚如磐石的姿势,必须停止移动一段时间以重新获得增益。\n" +"\n" +"-10% 伤害,-2 钝击/斩击/刺击防护。\n" +"持续 4 回合。" #: lang/json/martial_art_from_json.py msgid "Iron Bones" -msgstr "" +msgstr "铁布衫" #. ~ Description of buff 'Iron Bones' for martial art '{'str': 'Stone #. Dragon'}' @@ -115299,10 +117092,14 @@ msgid "" "+5 bash, cut, and stab armor.\n" "Lasts 1 turn." msgstr "" +"每当你成功攻击敌人,你就能进入冥想状态,使你近乎无懈可击。\n" +"\n" +"+5 钝击/斩击/刺击防护。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Tiger Claw" -msgstr "" +msgstr "虎爪" #. ~ Description for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py @@ -115312,21 +117109,22 @@ msgid "" "with a furry similar to that of a barbarian, and rely on overwhelming, " "vicious assaults to defeat their enemies." msgstr "" +"虎爪流派信奉潜伏在其门徒的内心之中的狂暴怒火。在战斗中,这些战士像野兽一样咆哮,用类似于野蛮人的怒火攻击,依靠势不可挡、凶残的攻击来击败他们的敌人。" #. ~ initiate message for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py msgid "You emit a low growl as you prepare for battle." -msgstr "" +msgstr "你发出低沉的咆哮,准备好作战。" #. ~ initiate message for martial art '{'str': 'Tiger Claw'}' #: lang/json/martial_art_from_json.py #, python-format msgid "%s hunkers down like a wild animal." -msgstr "" +msgstr "%s 像一只野兽一样蹲下。" #: lang/json/martial_art_from_json.py msgid "Improved Critical" -msgstr "" +msgstr "精通重击" #. ~ Description of buff 'Improved Critical' for martial art '{'str': 'Tiger #. Claw'}' @@ -115337,10 +117135,13 @@ msgid "" "\n" "+5% critical hit chance." msgstr "" +"总是全力打击。除非你想死,否则永远不要限制自己。\n" +"\n" +"+5% 暴击几率。" #: lang/json/martial_art_from_json.py msgid "Pounching Charge" -msgstr "" +msgstr "猛扑冲锋" #. ~ Description of buff 'Pounching Charge' for martial art '{'str': 'Tiger #. Claw'}' @@ -115352,10 +117153,14 @@ msgid "" "+2 Accuracy, +10% damage.\n" "Lasts 1 turn." msgstr "" +"伴随着野兽般的咆哮,你自己投身进入了这场打斗中。先发制人,一击致命。\n" +"\n" +"命中 +2,+10% 伤害。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Cornered Predator" -msgstr "" +msgstr "落难猎手" #. ~ Description of buff 'Cornered Predator' for martial art '{'str': 'Tiger #. Claw'}' @@ -115367,10 +117172,14 @@ msgid "" "-20% move cost.\n" "Lasts 1 turn." msgstr "" +"一只走投无路的捕食者是可怕而危险的生物。你也一样。\n" +"\n" +" -20% 移动耗时。\n" +"持续 1 回合。" #: lang/json/martial_art_from_json.py msgid "Blood In The Water" -msgstr "" +msgstr "嗜血" #. ~ Description of buff 'Blood In The Water' for martial art '{'str': 'Tiger #. Claw'}' @@ -115382,10 +117191,14 @@ msgid "" "+1 Accuracy, +15% damage.\n" "Lasts 1 turn. Stacks 2 times." msgstr "" +"血腥的气味驱使着你狂怒地攻击。你想要更多。现在!\n" +"\n" +" 命中 +1,+15% 伤害。\n" +"持续 1 回合。可叠加 2 次。" #: lang/json/martial_art_from_json.py msgid "Prey on the Weak" -msgstr "" +msgstr "弱肉强食" #. ~ Description of buff 'Prey on the Weak' for martial art '{'str': 'Tiger #. Claw'}' @@ -115396,6 +117209,10 @@ msgid "" "+30 Speed.\n" "Lasts 2 turns. Stacks 2 times" msgstr "" +"你像扫过羊群的狼一样收割弱者的生命。\n" +"\n" +"+30 速度。\n" +"持续 2 回合。可叠加 2 次。" #: lang/json/material_from_json.py src/bionics.cpp msgid "Alcohol" @@ -115881,7 +117698,7 @@ msgstr "乳化水凝胶" #: lang/json/material_from_json.py msgid "pulped" -msgstr "" +msgstr "碎浆的" #: lang/json/material_from_json.py msgid "Arcane Skin" @@ -115911,7 +117728,7 @@ msgstr "收集些骨头带给布丽吉特·拉克鲁瓦。8根应该就够了。 msgid "There is always work to be done, song to be woven." msgstr "总有做不完的事,总有编不完的歌。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -115919,16 +117736,16 @@ msgid "" " you." msgstr "如果你希望踏上觉悟之路,首先你必须学会倾听和聆听这首歌。去外面杀一头生物,感受在你指尖之间的力量。然后把骨头带来,我能为你雕些东西。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "太好了。现在请出发上道吧。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "我理解你的固执。当你见证真道之后,随时可以回来。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -117152,7 +118969,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "到时候见……或者不见,然后我就知道不跟你是对的了。" #: lang/json/mission_def_from_json.py @@ -117161,7 +118978,7 @@ msgid "" msgstr "别死了就行。如果你还得找我问才知道的话,那对你来说可不是什么好消息。" #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." +msgid "Well, you're not dead… yet." msgstr "哦,你还没死呢。" #: lang/json/mission_def_from_json.py @@ -117883,7 +119700,7 @@ msgstr "黛西" #: lang/json/mission_def_from_json.py msgid "Find 10 3L jars" -msgstr "收集 20 个3L玻璃罐" +msgstr "收集 10 个3L玻璃罐" #: lang/json/mission_def_from_json.py msgid "I could use some help scavenging." @@ -117893,7 +119710,7 @@ msgstr "我需要有人帮我找点东西。" msgid "" "We could use some 3 liter jars to preserve our produce. Can you bring me 10" " large three liter jars? I'll give you some preserves in exchange." -msgstr "" +msgstr "我们需要些 3L 玻璃罐来腌制我们的作物。你能帮我找 10 个吗?作为谢礼我会给你一些腌菜。" #: lang/json/mission_def_from_json.py msgid "Thank you. It's important to preserve foods while we can." @@ -119669,84 +121486,84 @@ msgstr "好吧,我只能自己去找金子了,算我自讨没趣。" #: lang/json/mission_def_from_json.py msgid "Active Noise Control" -msgstr "" +msgstr "激活降噪程序" #. ~ Description for mission 'Active Noise Control' #: lang/json/mission_def_from_json.py msgid "" "Investigate Hub 01's radio tower, discover the source of the interference, " "and fix the problem." -msgstr "" +msgstr "调查Hub 01附近的无线电塔,寻找干扰源,并解决问题。" #: lang/json/mission_def_from_json.py msgid "" "A few days ago, I installed a radio transmitter in the nearby tower, but it " "stopped working recently. If you are willing to be my back up while I check" " it out, I'll owe you a favor." -msgstr "" +msgstr "几天前,我在附近无线电塔里安装了一台无线电发射机,但它最近停止工作了。如果你愿意在我检查时帮我一把,我会欠你一个大人情的。" #: lang/json/mission_def_from_json.py msgid "Alright, lets be off. You don't mind taking point, right?" -msgstr "" +msgstr "好吧,我们走吧。你不介意我去侦察一下,对吧?" #: lang/json/mission_def_from_json.py msgid "Well thanks for offering, I guess." -msgstr "" +msgstr "谢谢你的提议,我想还是算了吧。" #: lang/json/mission_def_from_json.py msgid "" "I'm sure we'll figure it out once there. In any case, make sure to shoot " "first." -msgstr "" +msgstr "我相信我们一到那里就会想出办法的。无论如何,一定要先开枪。" #: lang/json/mission_def_from_json.py msgid "You think we killed the culprit?" -msgstr "" +msgstr "你觉得我们解决问题了吗?" #: lang/json/mission_def_from_json.py msgid "Sure seems like it. Lets go back to the hub." -msgstr "" +msgstr "看起来问题解决了。我们快点回HUB吧。" #: lang/json/mission_def_from_json.py msgid "Sure, thanks for nothing." -msgstr "" +msgstr "好吧,算我自讨没趣。" #: lang/json/mission_def_from_json.py msgid "Return to Hub 01" -msgstr "" +msgstr "返回 HUB 01" #. ~ Description for mission 'Return to Hub 01' #: lang/json/mission_def_from_json.py msgid "Return to Hub 01." -msgstr "" +msgstr "返回 HUB 01。" #: lang/json/mission_def_from_json.py msgid "Lets go back to the Hub" -msgstr "" +msgstr "我们快点回HUB吧。" #: lang/json/mission_def_from_json.py msgid "Well…" -msgstr "" +msgstr "呃……" #: lang/json/mission_def_from_json.py msgid "You keep a map around don't you? I do, and you probably should too." -msgstr "" +msgstr "你随身不带地图的吗?我可会带,你或许也应该这么做。" #: lang/json/mission_def_from_json.py msgid "We there yet?" -msgstr "" +msgstr "我们到了吗?" #: lang/json/mission_def_from_json.py msgid "Thanks for having my back. As I said, I owe you one." -msgstr "" +msgstr "谢谢你帮我。就像我之前说的,我欠你一个人情。" #: lang/json/mission_def_from_json.py msgid "Are you lost or something?" -msgstr "" +msgstr "你迷路了还是怎么了?" #: lang/json/mission_def_from_json.py msgid "Can't believe we got lost…" -msgstr "" +msgstr "不敢相信我们迷路了……" #: lang/json/mission_def_from_json.py msgid "Make 2 Stills" @@ -121837,12 +123654,12 @@ msgstr "你将机甲的腿部电机功率设置为最高挡。" #. ~ Failure to switch to this move mode, no steed #: lang/json/move_modes_from_json.py msgid "You're too tired to run." -msgstr "你力竭了,无法奔跑。" +msgstr "你太累了,无法奔跑。" #. ~ Failure to switch to this move mode, animal steed #: lang/json/move_modes_from_json.py msgid "Your steed is too tired to go faster." -msgstr "你的马太累了,跑不动了。" +msgstr "你的坐骑太累了,无法奔跑。" #. ~ Failure to switch to this move mode, mech steed #: lang/json/move_modes_from_json.py @@ -123418,7 +125235,7 @@ msgstr "你的头上长出了一个发光器。你不能自主控制它,它可 #: lang/json/mutation_from_json.py msgid "Reflex Photophore (on)" -msgstr "" +msgstr "反射式发光器(开)" #: lang/json/mutation_from_json.py msgid "Weak Photophore" @@ -123434,12 +125251,12 @@ msgstr "从你的额头上长出一个发光器官,你可以使它发出微光 #: lang/json/mutation_from_json.py msgid "Weak Photophore (on)" -msgstr "" +msgstr "弱发光器(开)" #. ~ Description for {'str': 'Weak Photophore (on)'} #: lang/json/mutation_from_json.py msgid "Your photophore is glowing softly." -msgstr "" +msgstr "你额头上的发光器官正在发出柔弱的微光。" #: lang/json/mutation_from_json.py msgid "Photophore" @@ -123448,16 +125265,16 @@ msgstr "发光器" #. ~ Description for {'str': 'Photophore'} #: lang/json/mutation_from_json.py msgid "You can make your photophore glow brightly." -msgstr "" +msgstr "你额头上的发光器官现在能发出强光。" #: lang/json/mutation_from_json.py msgid "Photophore (on)" -msgstr "" +msgstr "发光器(开)" #. ~ Description for {'str': 'Photophore (on)'} #: lang/json/mutation_from_json.py msgid "You photophore is glowing brightly." -msgstr "" +msgstr "你额头上的发光器官正在发出强光。" #: lang/json/mutation_from_json.py msgid "Normal Human" @@ -123575,7 +125392,7 @@ msgid "" "Your wounds heal themselves quicker than usual. You heal 50% faster whilst " "asleep and 20% faster whilst awake. Your broken limbs also heal twice as " "fast." -msgstr "" +msgstr "你的伤口比平时愈合得更快。伤口在睡眠时恢复速度提升50%,在清醒时提升20%。你折断的四肢愈合速度也是正常人的两倍。" #: lang/json/mutation_from_json.py msgid "Light Eater" @@ -124206,7 +126023,7 @@ msgstr "慢速自愈" msgid "" "Your wounds heal a little slower than most. Your HP whilst asleep as well " "as your broken limbs heal at 75% the regular rate." -msgstr "" +msgstr "你的伤口愈合得比大多数人都慢。伤口在睡眠时恢复速度以及折断的四肢的愈合速度是正常人的75%。" #: lang/json/mutation_from_json.py msgid "Poor Healer" @@ -124218,7 +126035,7 @@ msgstr "自愈弱化" msgid "" "Your health recovery is severely impaired. Your HP whilst asleep as well as" " your broken limbs heal at 33% the regular rate." -msgstr "" +msgstr "你的机体自愈能力严重受损。伤口在睡眠时恢复速度以及折断的四肢的愈合速度是正常人的33%。" #: lang/json/mutation_from_json.py msgid "Imperceptive Healer" @@ -124230,7 +126047,7 @@ msgstr "自愈无效" msgid "" "Wounds are incredibly dangerous to you, as they barely heal at all. Your HP" " whilst asleep as well as your broken limbs heal at 10% the regular rate." -msgstr "" +msgstr "伤口对你来说是非常危险的,因为它们几乎无法愈合。伤口在睡眠时恢复速度以及折断的四肢的愈合速度是正常人的10%。" #: lang/json/mutation_from_json.py msgid "Far-Sighted" @@ -124946,7 +126763,7 @@ msgstr "高速自愈" msgid "" "Your wounds heal very quickly. You heal 50% faster whilst asleep and 66% " "faster whilst awake. Your broken limbs also heal 4 times faster than usual." -msgstr "" +msgstr "你的伤口很快就愈合了。伤口在睡眠时恢复速度提升50%,在清醒时提升66%。你折断的四肢愈合速度也是正常人的4倍。" #: lang/json/mutation_from_json.py msgid "Regeneration" @@ -124959,7 +126776,7 @@ msgid "" "Your flesh regenerates from wounds incredibly quickly. You heal 150% faster" " whilst asleep and 200% faster whilst awake. Your broken limbs also heal 16" " times faster than usual." -msgstr "" +msgstr "你的肉体受伤后愈合得非常快。伤口在睡眠时恢复速度提升150%,在清醒时提升200%。你折断的四肢愈合速度也是正常人的16倍。" #: lang/json/mutation_from_json.py msgid "Reptilian Healing" @@ -124970,7 +126787,7 @@ msgstr "蜥蜴再生" msgid "" "Your broken limbs mend themselves without significant difficulty. You do " "not require splints and broken limbs heal 20 times faster than usual." -msgstr "" +msgstr "你断掉的四肢可以轻易的自愈。你折断的四肢不需要夹板就能愈合,而且愈合速度是正常人的20倍。" #: lang/json/mutation_from_json.py msgid "Very Little Sleep" @@ -128384,8 +130201,7 @@ msgstr "蜘蛛人" msgid "Well, maybe you'll just have to make your own world wide web." msgstr "你已经变异为蜘蛛人,你也许可以自己搞个万维网。" -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "幸存者" @@ -128694,10 +130510,6 @@ msgid "" "you." msgstr "你是真正的美食家,有些人可能认为那只是吉祥物而已,但你知道不仅仅如此:你是美食家,面具已成为你的面孔,你真实存在,绝世而独立。" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "实习医生" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -129072,14 +130884,32 @@ msgstr "快速反应" #: lang/json/mutation_from_json.py msgid "" "You have fast reflexes, allowing you to dodge attacks and grabs more easily." -msgstr "" +msgstr "你反应很快,让你更容易闪避敌人的攻击和擒抱。" #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "幸存者故事" +msgid "Survivor: Confused 1" +msgstr "幸存者" -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -129087,6 +130917,86 @@ msgstr "幸存者故事" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "这名NPC可以告诉你他们是如何在大灾变中幸存下来的。" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "幸存者" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "幸存者故事" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "先知之印" @@ -130332,7 +132242,7 @@ msgid "" "You are a martial adept and learned one of the martial disciplines of the " "Sublime Way. You start with your choice of Desert Wind, Diamond Mind, Iron " "Heart, Setting Sun, Stone Dragon, or Tiger Claw." -msgstr "" +msgstr "你是一名武道高手,学会了至高之道的武术流派中的一种。你能够从漠风,钢魂,铁心,暮日,石龙,及虎爪流派中选择一种开始游戏。" #: lang/json/mutation_from_json.py msgid "Magus" @@ -130840,10 +132750,6 @@ msgstr "我只是在努力生存下去。" msgid "I'm tracking game." msgstr "我正在追踪猎物。" -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "士兵" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "酒保" @@ -131593,10 +133499,6 @@ msgstr "拾荒者" msgid "Laborer" msgstr "劳工" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "伐木工" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "木工师" @@ -134112,6 +136014,18 @@ msgstr "公路(下水井)" msgid "bridge" msgstr "桥梁" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "桥梁(天桥)" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "桥梁(地面)" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "桥梁(斜坡)" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "路边饮食店" @@ -139089,7 +141003,7 @@ msgstr "你受够了看到东西从天上掉下来,把士兵和幸存者从一 #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "EMT" -msgstr "" +msgstr "急救员" #. ~ Profession (male EMT) description #: lang/json/professions_from_json.py @@ -139098,12 +141012,12 @@ msgid "" "You were responding to a call with your partner before you got separated. " "Now all you have is your trusty ambulance, ready to transport patients " "through the apocalypse." -msgstr "" +msgstr "你和你的搭档在出急救现场时被分开了。现在你只有你那辆可靠的救护车陪着你,准备好把病人运过大灾变。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "EMT" -msgstr "" +msgstr "急救员" #. ~ Profession (female EMT) description #: lang/json/professions_from_json.py @@ -139112,12 +141026,12 @@ msgid "" "You were responding to a call with your partner before you got separated. " "Now all you have is your trusty ambulance, ready to transport patients " "through the apocalypse." -msgstr "" +msgstr "你和你的搭档在出急救现场时被分开了。现在你只有你那辆可靠的救护车陪着你,准备好把病人运过大灾变。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Paramedic" -msgstr "" +msgstr "急救护士" #. ~ Profession (male Paramedic) description #: lang/json/professions_from_json.py @@ -139126,12 +141040,12 @@ msgid "" "You were separated from your partner while out on a call. You managed to " "hang onto some medical supplies, but it's looking like the only life that " "needs saving now is yours." -msgstr "" +msgstr "你和你的搭档在出急救现场时被分开了。你设法保存了一些医疗用品,但看起来现在唯一需要拯救的是你的生命。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Paramedic" -msgstr "" +msgstr "急救护士" #. ~ Profession (female Paramedic) description #: lang/json/professions_from_json.py @@ -139140,12 +141054,12 @@ msgid "" "You were separated from your partner while out on a call. You managed to " "hang onto some medical supplies, but it's looking like the only life that " "needs saving now is yours." -msgstr "" +msgstr "你和你的搭档在出急救现场时被分开了。你设法保存了一些医疗用品,但看起来现在唯一需要拯救的是你的生命。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Combat Medic" -msgstr "" +msgstr "战地医生" #. ~ Profession (male Combat Medic) description #: lang/json/professions_from_json.py @@ -139154,12 +141068,12 @@ msgid "" "You were on the front-lines when everything happened, patching up the " "wounded and providing support. But they wouldn't stop coming. Now you're " "on your own." -msgstr "" +msgstr "在这一切发生时你正好在前线,为受伤的人修补伤口并提供支援。但它们源源不断向你涌来。现在你只能靠自己了。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Combat Medic" -msgstr "" +msgstr "战地医生" #. ~ Profession (female Combat Medic) description #: lang/json/professions_from_json.py @@ -139168,12 +141082,12 @@ msgid "" "You were on the front-lines when everything happened, patching up the " "wounded and providing support. But they wouldn't stop coming. Now you're " "on your own." -msgstr "" +msgstr "在这一切发生时你正好在前线,为受伤的人修补伤口并提供支援。但它们源源不断向你涌来。现在你只能靠自己了。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Heroin Addict" -msgstr "" +msgstr "白粉仔" #. ~ Profession (male Heroin Addict) description #: lang/json/professions_from_json.py @@ -139182,12 +141096,12 @@ msgid "" "The last thing you remember was meeting God behind the local Foodplace. " "Then people started eating each other. This doesn't feel like a fever " "dream." -msgstr "" +msgstr "你所记得的最后一件事是在当地美食广场后面和上帝谈心。然后人们开始互相吃。这感觉不像是一场狂热之梦。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Heroin Addict" -msgstr "" +msgstr "白粉妹" #. ~ Profession (female Heroin Addict) description #: lang/json/professions_from_json.py @@ -139196,7 +141110,7 @@ msgid "" "The last thing you remember was meeting God behind the local Foodplace. " "Then people started eating each other. This doesn't feel like a fever " "dream." -msgstr "" +msgstr "你所记得的最后一件事是在当地美食广场后面和上帝谈心。然后人们开始互相吃。这感觉不像是一场狂热之梦。" #: lang/json/professions_from_json.py msgctxt "profession_male" @@ -139380,6 +141294,7 @@ msgid "" "you in the middle of your 16 hour extended shift, and you barely managed to " "escape the building, tools in hand." msgstr "" +"你是一名在一间全无菌高安防级别的设施中制造生化插件的技术工程师。你在长达16个小时的轮班之中收到了那条最后的疏散令,而你靠手里的工具勉强逃出了那栋大楼。" #: lang/json/professions_from_json.py msgctxt "profession_female" @@ -139395,6 +141310,7 @@ msgid "" "you in the middle of your 16 hour extended shift, and you barely managed to " "escape the building, tools in hand." msgstr "" +"你是一名在一间全无菌高安防级别的设施中制造生化插件的技术工程师。你在长达16个小时的轮班之中收到了那条最后的疏散令,而你靠手里的工具勉强逃出了那栋大楼。" #: lang/json/professions_from_json.py msgctxt "profession_male" @@ -140691,7 +142607,7 @@ msgstr "随着大灾变的到来,你可能得想办法把在考试时学会的 #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Introspectionist" -msgstr "" +msgstr "内省主义者" #. ~ Profession (male Introspectionist) description #: lang/json/professions_from_json.py @@ -140700,12 +142616,12 @@ msgid "" "You segregated yourself from society because you wanted to concentrate on " "improving yourself. It was you and your best friend, but now the apocalypse" " won't leave you alone. " -msgstr "" +msgstr "你把自己与社会隔离开来,因为你想集中精力提升自我。这本是你自己最好的朋友,但现在大灾变可不会让你一个人呆着。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Introspectionist" -msgstr "" +msgstr "内省主义者" #. ~ Profession (female Introspectionist) description #: lang/json/professions_from_json.py @@ -140714,12 +142630,12 @@ msgid "" "You segregated yourself from society because you wanted to concentrate on " "improving yourself. It was you and your best friend, but now the apocalypse" " won't leave you alone. " -msgstr "" +msgstr "你把自己与社会隔离开来,因为你想集中精力提升自我。这本是你自己最好的朋友,但现在大灾变可不会让你一个人呆着。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Vengeful Preacher" -msgstr "" +msgstr "复仇传教士" #. ~ Profession (male Vengeful Preacher) description #: lang/json/professions_from_json.py @@ -140728,12 +142644,12 @@ msgid "" "You lost your faith when your spouse died of illness. You've been drinking " "yourself to death ever since. God is punishing everyone with this " "apocalypse, you are going to show them your brand of mercy." -msgstr "" +msgstr "当你的配偶因病去世时,你失去了你的信仰。从那以后你就一直喝得烂醉如泥。上帝用大灾变惩罚每一个人,而你要向它们展示你仁慈的烙印。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Vengeful Preacher" -msgstr "" +msgstr "复仇传教士" #. ~ Profession (female Vengeful Preacher) description #: lang/json/professions_from_json.py @@ -140742,12 +142658,12 @@ msgid "" "You lost your faith when your spouse died of illness. You've been drinking " "yourself to death ever since. God is punishing everyone with this " "apocalypse, you are going to show them your brand of mercy." -msgstr "" +msgstr "当你的配偶因病去世时,你失去了你的信仰。从那以后你就一直喝得烂醉如泥。上帝用大灾变惩罚每一个人,而你要向它们展示你仁慈的烙印。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Techno-Prepper" -msgstr "" +msgstr "科技法师信徒" #. ~ Profession (male Techno-Prepper) description #: lang/json/professions_from_json.py @@ -140755,12 +142671,12 @@ msgctxt "prof_desc_male" msgid "" "You've long suspected the world might suddenly turn over. With your " "training, spells, and revolver, your chances are far better than most." -msgstr "" +msgstr "你早就怀疑世界会突然终结。有了你的训练、法术和左轮手枪,你活下去的几率比大多数人都要高得多。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Techno-Prepper" -msgstr "" +msgstr "科技法师信徒" #. ~ Profession (female Techno-Prepper) description #: lang/json/professions_from_json.py @@ -140768,12 +142684,12 @@ msgctxt "prof_desc_female" msgid "" "You've long suspected the world might suddenly turn over. With your " "training, spells, and revolver, your chances are far better than most." -msgstr "" +msgstr "你早就怀疑世界会突然终结。有了你的训练、法术和左轮手枪,你活下去的几率比大多数人都要高得多。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Bionic Pseudovamp" -msgstr "" +msgstr "生化伪吸血鬼" #. ~ Profession (male Bionic Pseudovamp) description #: lang/json/professions_from_json.py @@ -140783,11 +142699,12 @@ msgid "" "augment yourself with spells and bionics into a denizen of the night. Your " "neglect to your health in your pursuit has left you pale and unlively." msgstr "" +"你一直对恐怖小说着迷,并利用你手中的财富买来各种法术和生化插件强化自己,使你成为一个暗夜的居民。你在追求抛瓦的过程中忽视了自己的健康,结果使你面色苍白,毫无生气。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Bionic Pseudovamp" -msgstr "" +msgstr "生化伪吸血鬼" #. ~ Profession (female Bionic Pseudovamp) description #: lang/json/professions_from_json.py @@ -140797,11 +142714,12 @@ msgid "" "augment yourself with spells and bionics into a denizen of the night. Your " "neglect to your health in your pursuit has left you pale and unlively." msgstr "" +"你一直对恐怖小说着迷,并利用你手中的财富买来各种法术和生化插件强化自己,使你成为一个暗夜的居民。你在追求抛瓦的过程中忽视了自己的健康,结果使你面色苍白,毫无生气。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Academy Wizard" -msgstr "" +msgstr "魔法师研究生" #. ~ Profession (male Academy Wizard) description #: lang/json/professions_from_json.py @@ -140810,12 +142728,12 @@ msgid "" "A year of enrollment in a wizard's academy has taught you patience, wisdom, " "and a handful of useful spells. With the teachers converted into the undead " "and classes cancelled, the final lesson has begun." -msgstr "" +msgstr "在魔法学院的一年里,你学会了耐心、智慧和一些有用的法术。随着教师转变成不死人,课程渐渐取消,最后一课已经开始。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Academy Wizard" -msgstr "" +msgstr "魔法师研究生" #. ~ Profession (female Academy Wizard) description #: lang/json/professions_from_json.py @@ -140824,12 +142742,12 @@ msgid "" "A year of enrollment in a wizard's academy has taught you patience, wisdom, " "and a handful of useful spells. With the teachers converted into the undead " "and classes cancelled, the final lesson has begun." -msgstr "" +msgstr "在魔法学院的一年里,你学会了耐心、智慧和一些有用的法术。随着教师转变成不死人,课程渐渐取消,最后一课已经开始。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Corrosive Rocker" -msgstr "" +msgstr "腐蚀摇滚乐手" #. ~ Profession (male Corrosive Rocker) description #: lang/json/professions_from_json.py @@ -140837,12 +142755,12 @@ msgctxt "prof_desc_male" msgid "" "Your metal career soared to new heights when you swapped special effects for" " acrid gore and spiked whips. It seems the Cataclysm is now your final tour." -msgstr "" +msgstr "当你把特效换成辛辣刺鼻的血肉和带刺的长鞭时,你的金属摇滚职业生涯飙升到了一个新的高度。看来大灾变现在是你的最后一次巡演了。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Corrosive Rocker" -msgstr "" +msgstr "腐蚀摇滚乐手" #. ~ Profession (female Corrosive Rocker) description #: lang/json/professions_from_json.py @@ -140850,12 +142768,12 @@ msgctxt "prof_desc_female" msgid "" "Your metal career soared to new heights when you swapped special effects for" " acrid gore and spiked whips. It seems the Cataclysm is now your final tour." -msgstr "" +msgstr "当你把特效换成辛辣刺鼻的血肉和带刺的长鞭时,你的金属摇滚职业生涯飙升到了一个新的高度。看来大灾变现在是你的最后一次巡演了。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Shock Officer" -msgstr "" +msgstr "电击警官" #. ~ Profession (male Shock Officer) description #: lang/json/professions_from_json.py @@ -140864,12 +142782,12 @@ msgid "" "You were enrolled in a experimental law enforcement program designed to " "decrease suspect casualties and equipment costs by substituting tasers and " "bullets for less-lethal Stormshaping." -msgstr "" +msgstr "你是一项实验性执法部门计划的参与者,目的是通过将电击枪和子弹替换为低致命性的风暴塑造者法术来减少嫌疑犯的伤亡以及设备采购成本。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Shock Officer" -msgstr "" +msgstr "电击警官" #. ~ Profession (female Shock Officer) description #: lang/json/professions_from_json.py @@ -140878,12 +142796,12 @@ msgid "" "You were enrolled in a experimental law enforcement program designed to " "decrease suspect casualties and equipment costs by substituting tasers and " "bullets for less-lethal Stormshaping." -msgstr "" +msgstr "你是一项实验性执法部门计划的参与者,目的是通过将电击枪和子弹替换为低致命性的风暴塑造者法术来减少嫌疑犯的伤亡以及设备采购成本。" #: lang/json/professions_from_json.py msgctxt "profession_male" msgid "Earthquake Brawler" -msgstr "" +msgstr "塑地拳手" #. ~ Profession (male Earthquake Brawler) description #: lang/json/professions_from_json.py @@ -140892,12 +142810,12 @@ msgid "" "You've made a name for yourself in underground magic boxing rings as an " "unstoppable punching machine. Now that all your opponents are undead, " "there's no need to hold back." -msgstr "" +msgstr "你在地下魔法拳击圈中声名显赫,被称为一台挡不住的打桩机。既然你所有的对手都变成不死人了,那也没必要留手了。" #: lang/json/professions_from_json.py msgctxt "profession_female" msgid "Earthquake Brawler" -msgstr "" +msgstr "塑地拳手" #. ~ Profession (female Earthquake Brawler) description #: lang/json/professions_from_json.py @@ -140906,7 +142824,7 @@ msgid "" "You've made a name for yourself in underground magic boxing rings as an " "unstoppable punching machine. Now that all your opponents are undead, " "there's no need to hold back." -msgstr "" +msgstr "你在地下魔法拳击圈中声名显赫,被称为一台挡不住的打桩机。既然你所有的对手都变成不死人了,那也没必要留手了。" #: lang/json/professions_from_json.py msgctxt "profession_male" @@ -142575,7 +144493,7 @@ msgstr "建造金属锻造工坊" #: lang/json/recipe_from_json.py msgid "Let's build an anvil and crucible to increase our crafting options." -msgstr "" +msgstr "让我们建造一个铁砧和熔炉来增加我们的制造物品选项。" #: lang/json/recipe_from_json.py msgid "add an anvil and crucible" @@ -149264,96 +151182,6 @@ msgstr "我都想不起上次我这么渴是什么时候了。" msgid "I'd kill for a sip of water right now." msgstr "我现在能为喝一口水而杀人。" -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "当然可以,我看到你身上带着啤酒!让我们开一瓶冰啤酒,坐下来聊一聊,,怎么样?" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "哦,当然,不如给我一瓶你带着的啤酒怎么样?怎么样,成交?" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "是的,不过你得先分我一瓶你囤的那些啤酒,然后我们接着聊!开个玩笑。你怎么样,?" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "嘿,我想聊天的时候喝点冰啤酒会更加愉快。过得如何?" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "趁我们聊天的时候,我们要不开要一瓶啤酒然后……假装世界没有毁灭,就一小会。你怎么说?" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "递一瓶给我,让我们好好谈谈从前的好日子吧,。" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "哦,当然可以,,正好我也该放松一下了,你最近怎么样?" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "哦,可以,,近况如何啊?" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "当然,让我们来吹吹逼!你还好吧?" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "为什么不呢?你还好吗?" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "我不介意,怎么了?" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "我可以抽出几分钟时间,怎么了?" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "当然,,你还好吗?" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "好吧,你有什么要说的吗?" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "我随时可以聊!怎样,你还好吗?" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "好吧,,我们是应该互相了解一下,你过得怎样?" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "当然可以,我奉陪。你还好吗? " - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "好主意,。让我们暂时忘掉这个世界吧。你过得怎样?" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "啊,我去。你最近如何了?" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "行。那么,你觉得天气如何?" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "该死" @@ -151817,6 +153645,18 @@ msgstr "和我说说你是如何在大灾变的最初阶段幸存下来的。" msgid "Was it rough surviving thus far?" msgstr "活到现在是不是非常艰难?" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "你觉得这一切是怎样到这个地步的?到底发生了什么?" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "到底怎么回事?就是说,从全局角度看,到底发生了什么?" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "你听说过这场大灾变是怎么发生的吗?" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -152532,6 +154372,303 @@ msgstr "会尽力避免交战。" msgid " will follow normal engagement rules." msgstr "会遵循正常的交战规则。" +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "当然,想为这个故事开瓶啤酒吗?" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "哦,当然,不如给我一瓶你带着的啤酒怎么样?" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "是的,不过你得先分我一瓶你囤的那些啤酒,然后我们接着聊!开个玩笑,呵呵。" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "嘿 ,我想聊天的时候喝点冰啤酒会更加愉快。" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "趁我们聊天的时候,我们要不开要一瓶啤酒然后……假装这个世界还没有毁灭。" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "递瓶酒给我,让我们好好谈谈吧,。" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "啊,炎炎夏日让我很难受,是吧?" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "享受夏天吧。" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "老实说,希望这天气能凉快一点。" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "好吧,也许这能让我不再这鬼天气里冻僵了。" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "不得不说,我可不是在看雪。" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "真奇怪,那些丧尸居然不会被冻僵。" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "呃,我感觉人很难受……但还是聊聊吧。" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "正好我也该放松一下了,你最近怎么样?" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "那么,最近过得如何?" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "当然,让我们来吹吹逼!你还好吧,?" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "我不介意,怎么了?" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "我想我还是能抽出些时间聊聊的,怎么了?" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "当然,,你还好吗?" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "好吧,你有什么要说的吗?" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "我随时可以聊!怎样,你还好吗?" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "好吧,,你过得怎样?" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "我奉陪。你还好吗?" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "让我们暂时忘掉这个世界吧。近来过得如何啊?" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "啊,我去。命运最近待你如何了?" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "呃,你觉得今天天气怎么样?" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "能抽出点时间来聊天真是太好了。你最近过得怎么样?" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "我的脚走得也有点累了,你知道吗?" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "我今天感觉超棒的。不知道为什么,也许是那种日子吧。" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "我只是不敢相信一切都终结了。我不停地回想自从一切都崩溃的那天以来的经历。暴乱。谎言。精神病。从来没有感觉到这一切会变成这样子。" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" +"你想过那些家伙在世界末日之前说的那些废话有任何真相吗?水里有精神控制药物,生物恐怖主义?也许其中有些事是真的,但似乎太牵强了。不过话说回来,我们现在要对付的是真正的丧尸。" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "我不知道自己现在是应该变得更虔诚呢,还是更不虔诚。你懂我的意思吧,?" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "我一直在想重新整理下我的装备。真是一团糟。你可不想在拿武器时不小心拔出一根麦片棒,对吧?" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "你有想过我们为什么还要这么费力生存吗?反正我们最终都会变成丧尸的。我不是说我们该停止战斗,但这一切有什么意义?" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "我希望我现在就能一枪干翻自己变成那些丧尸中的一员,这样就不用为自己的生命操心了。" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "每次闭上眼睛,我都能看到那场暴乱的画面。你明白了吗,还是只有我一个人会这样?" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "你有没有觉得大灾变发生的那些事只是你醒来之前所做的一场梦?" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "你是什么时候意识到已经世界末日的?对我来说,这就是那个该死的YouTube视频,那个女人杀孩子的视频。真该死,不是吗?" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "我想知道联邦政府是否还在某处存在着,也许躲在一个地堡里。" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "还记得一些来自世界末日的疯狂新闻吗?我是说那些被暴乱报道淹没的东西。比如,罗德岛的州长不是说已经脱离联邦了吗?" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "我一直梦到丧尸仍然记得自己作为人类时的身份,只是被困在尸体里,看着一切发生。这让我一直都没法睡一场好觉。" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "他们放在水里的那些让人们暴动的精神控制药物……你觉得会不会还在水里面呢?" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "我不禁想知道是谁搞砸了这一切。显然,我们不能相信新闻报道,他们几周以来一只声称丧尸都是“暴徒”。为什么?这一切都是从哪开始的?" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" +"如果他们告诉我们的关于中国人的说法在一定程度上是真的,你认为中国的情况是不是也和我们一样?或者美国已经变成某种隔离区,至少世界上还有一些地方没有受影响。" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "你注意到伤口不像平时那样恢复了吗?我在世界末日之前就发现了,但最近变得更明显了。割伤恢复后都几乎不会有疤痕。" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "我还是不明白这些丧尸是靠什么维持运动的。它们就像永动机。" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "这一切还有很多地方对不上。是谁创造了丧尸?是什么力量驱使它们?也许有关精神控制药物的谣言一直都是真的,而且有人找到了一种方法来改造活死人。" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "这些丧尸是怎么维持运动的?它们吃什么?你觉得它们会腐烂吗?" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "我一直在想,总有一天,我们会用完卫生纸的。然后我们该怎么办呢?" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "你不觉得奇怪吗,我们打开那幢上锁的房子,居然发现里面有只丧尸?它是怎么进到那里的?" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "有时我想知道我们是否都变成精神病了,而不仅仅是那些发疯和暴乱的人。自世界末日以来我做过不少以前从没想过自己会做的事。" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "你最近读过什么不错的书吗?我很庆幸我们至少还有些书剩下。" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "你知道我怀念什么吗?电影院。你觉得好莱坞会不会逃过一劫呢?也许有一群丧尸演员在那里,靠条件反射胡说八道拍片。哈,我可想看看那些狗玩意。" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "我懂你的意思,……" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "这让我想起了一件往事……" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "对,对。你有没有想过……" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -153780,6 +155917,15 @@ msgstr "" "这是一个Rivtech弹药的广告。它上面有一幅画了中间有弹孔的装甲钢板。旁边是一盒闪亮的无壳弹药。标题写着:“Rivtech " "8x40mm无壳,万夫莫敌。”" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" +"这是一则 SUDS 洗衣店的广告。上面的广告词被许多泡泡包围着,泡泡似乎正往上漂浮。上面写着:“Tergitol 星期二!所有洗衣干衣半价!”" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -153790,6 +155936,22 @@ msgid "" msgstr "" "这是一张宣传海报,展示了诺斯罗普公司的军事机器人。它描绘了经典的深绿色蛛型派遣者,它站在栅栏前,背对着拍摄者,模糊的机器影子从它背后冲向地平线上一个恐怖外形的黑色轮廓。海报上面写着:“我们是来保护你的。”" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "这是一则钢铁健身馆的广告。上面印着人们进行各种运动,例如跑步、瑜伽和举重的照片。上面写着:“我把东西举起又放下!”" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" +"这是太空时光公司的广告。它印着一张以月球为背景的照片,上面宇航员正绕着一艘宇宙飞船上漂浮。上面写着:“拥有属于你自己的月亮!一个月只需29.99美元,你就可以拥有宇宙中最优秀的房产!”" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -165320,7 +167482,7 @@ msgstr "无人区" #: lang/json/start_location_from_json.py msgid "Desert Island" -msgstr "" +msgstr "沙漠岛" #: lang/json/start_location_from_json.py msgid "Experiment Cell" @@ -165467,11 +167629,11 @@ msgid "Acolyte." msgstr "助手。" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" -msgstr "你又回来了。你是来这听歌的吗?" +msgid "You're back. Have you come to listen to the song?" +msgstr "你又回来了。你是来听这歌声的吗?" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" +msgid "You there. Quiet down. Can you hear it? The song?" msgstr "那里的家伙,安静点。你能听到吗?这歌声?" #: lang/json/talk_topic_from_json.py @@ -165506,8 +167668,8 @@ msgstr "我得走了。保重了,先知。" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "仔细倾听。骨头……在唱歌。你能听到吗?它们编的歌?它们说的事?" #: lang/json/talk_topic_from_json.py @@ -165520,11 +167682,11 @@ msgstr "嗯……好吧,是吧。我想我该走了。" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" "当这一切发生的时候,这场大灾变,有些东西……改变了。你能在所有的生物身上看到它,但最重要的是从骨头上。它们破碎,变形,再次复活,无限循环。活死人在四处行走。怪物互相撕扯着对方。你可以看到共鸣,原始力量的安静哼鸣,只有取走骨头,这个循环才会结束——它们的故事,它们的歌声,它们的力量,都将成为你的力量。" @@ -165543,11 +167705,11 @@ msgstr "还有其它人,呃,相信这个吗?" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" "只有当你压碎了一具尸体的骨头,它才会停止复活。只有仔细检查这些骨头,你才能知道那是什么东西。这就是故事的全部。无论什么原因导致了这种变化,它都在我们所有人的内心活动着,是这个新世界不可避免的一部分。它拥有改变的力量。当我们握住骨头,我们就拥有了力量。这就是力量的全部。在一起……它们组成了一首美丽的歌。" @@ -165557,7 +167719,7 @@ msgstr "我想我明白你的意思了,尽管我不确定我是否认同你。 #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "还有其他人也在追随这一事业。你最好帮助他们,因为尽管吾等人数不多,但吾等所承载的歌鼓舞着吾辈。" @@ -165571,10 +167733,10 @@ msgstr "原因呢?你为什么要收集这些骨头?" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" "歌可以用多种形式编排。用雕刻的骨制护身符,武器和盔甲都拥有巨大的力量,当时机来临,我和我的族人将收集大量的歌曲,并歌唱它来恢复这个世界。要么恢复,要么终结。都没有区别。" @@ -165585,7 +167747,7 @@ msgstr "终结世界?什么?" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" "我们相信,一首歌曲中足够的力量可以逆转这场灾难——或者将它加速到一个超越一切的时代,以同样的方式终结。但在目前的情况下,这两种结果都可以接受。" @@ -165602,8 +167764,8 @@ msgstr "你这个疯子。" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "你的思想很开放。比大多数人都开放。也许有一天,你也会感受到这首歌的力量,并成为吾之同侪。现在,助手,倾听,倾听,感觉这首歌。" @@ -165613,9 +167775,9 @@ msgstr "我……谢谢。" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "你的怀疑并不令我惊讶。也许有一天,你也会不可避免地听到这首歌,感受到它的力量。但在那之前,你仍将只是一名助手,通往同侪的道路已经关闭。" #: lang/json/talk_topic_from_json.py @@ -165673,14 +167835,6 @@ msgstr "洗耳恭听。" msgid "Perhaps another time, Seer." msgstr "下次再说吧,先知。" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "如果你希望踏上觉悟之路,首先你必须学会倾听和聆听这首歌。去外面杀一头生物,感受在你指尖之间的力量。然后把骨头带来,我能为你雕些东西。" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "好吧,我想我应该看看这是怎么回事。我加入了。" @@ -165689,10 +167843,6 @@ msgstr "好吧,我想我应该看看这是怎么回事。我加入了。" msgid "Not interested." msgstr "[取消]不感兴趣。" -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "太好了。现在请出发上道吧。" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "包在我身上。但我还想问问……" @@ -165709,20 +167859,13 @@ msgstr "能给点装备让我完成这个任务吗?" msgid "I'm off then." msgstr "那么我走了。" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "我们到处所见的那些步履蹒跚的尸体都在不和谐地移动。它们的歌仍可使用,但作为一名助手,这将是不必要的困难。一定要用未被污染的完整生物雕刻。" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "所以,任何不是丧尸或怪物的生物。明白了。" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "觉悟之路是需要你自己走。如果我帮助你,最终会阻碍你进步,搅乱你的歌。" @@ -165733,8 +167876,8 @@ msgstr "我明白了。好吧。" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." -msgstr "你身上有我的印记,意味着我相信你有潜力学会真正倾听这首歌。是的,我将把助你一臂之力,暂时的。" +"listen to the Song. Yes, I will lend my skills to you, for now." +msgstr "你身上有我的印记,意味着我相信你有潜力学会真正倾听这首歌。是的,我将助你一臂之力,暂时的。" #: lang/json/talk_topic_from_json.py msgid "Only those who bear my mark will prove themselves worthy of my skills." @@ -165748,11 +167891,6 @@ msgstr "听你这么说我很高兴。我们出发吧。" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "那很好,但我现在需要一个人干。以后再说吧。" -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "我理解你的固执。当你见证真道之后,随时可以回来。" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "下次再说吧。不如换个话题……" @@ -165764,16 +167902,16 @@ msgstr "好吧,但我现在得走了。" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" -"大灾变改变的不仅仅是行走的死者和怪物。它启动了……某种循环。一切都在不断重复。我们只能在别人身上看到它,但它也发生在我们身上,包括你和我。你的肉从你身上撕裂,被吞食。也可能是面对死亡的无声呻吟。但你的骨头又复活了。不同的肉体,不同的名字,有时甚至是不同的知识,但骨头,是一样的。我们都被困在同一个循环中。我们只是一直在遗忘。这就是为什么我们需要收集歌声。这就是为什么这一切必须终结,即使它意味着毁灭,而不是恢复。" +"大灾难改变的不仅仅是行走的死者和怪物。它启动了……某种循环。一切都在不断重复。我们只能在别人身上看到它,但它也发生在我们身上,包括你和我。你的肉从你身上撕裂,被吞食。也可能是面对死亡的无声呻吟。但你的骨头又复活了。不同的肉体,不同的名字,有时甚至是不同的知识,但骨头,是一样的。我们都被困在同一个循环中。我们只是一直在遗忘。这就是为什么我们需要收集歌声。这就是为什么这一切必须终结,即使它意味着毁灭,而不是恢复。" #: lang/json/talk_topic_from_json.py msgid "" @@ -165801,6 +167939,14 @@ msgstr "暂时不想问了。" msgid "Skip it, let's get going." msgstr "不必,我们出发吧。" +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "关于这个世界,还有什么建议吗?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "我们来谈谈派系营地的事情。" + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "翻译翻译,什么叫\"大体上\"愿意跟随我?" @@ -166005,7 +168151,7 @@ msgstr "告诉我怎么给你医疗用品。" #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -166209,8 +168355,8 @@ msgstr "嗨,。" #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" msgstr "站住,举起手来!哈哈,吓到你了吗,我们……已经没有法律了……" #: lang/json/talk_topic_from_json.py @@ -166232,7 +168378,7 @@ msgstr "我得走了。" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "事情发生时我在这里守着警局,其他警察在最后一次通话之后就再也没回来……至少没作为人类回来。" #: lang/json/talk_topic_from_json.py @@ -166284,8 +168430,8 @@ msgid "" msgstr "是的,还有其他一些人像我一样躲在镇里。我们有时候会做些交易……有时会有陌生人路过这,以为他们能找到比之前待得更好的地方。" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." -msgstr "不行就是不行……" +msgid "No, just no…" +msgstr "不行,就是 不行……" #: lang/json/talk_topic_from_json.py msgid "Just let me sleep, !" @@ -166296,7 +168442,7 @@ msgid "Make it quick, I want to go back to sleep." msgstr "快点,我想回去睡觉" #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." +msgid "Just few minutes more…" msgstr "再等几分钟……" #: lang/json/talk_topic_from_json.py @@ -166342,6 +168488,68 @@ msgstr "[战斗]我想给你一些作战指令。" msgid "I want to set some miscellaneous rules." msgstr "[其他]我想设定一些其他规则。" +#: lang/json/talk_topic_from_json.py +msgid "I'd like to know a bit more about your abilities." +msgstr "[查看]我想更多地了解你的能力。" + +#: lang/json/talk_topic_from_json.py +msgid "There's something I want you to do." +msgstr "我想让你做些事情。" + +#: lang/json/talk_topic_from_json.py +msgid "I just wanted to talk for a bit." +msgstr "我只想聊聊天。" + +#: lang/json/talk_topic_from_json.py +msgid "Can you help me understand something? (HELP/TUTORIAL)" +msgstr "[教程]你能教教我吗?" + +#: lang/json/talk_topic_from_json.py +msgid "I'm going to go my own way for a while." +msgstr "[解散]我们就此分开吧。" + +#: lang/json/talk_topic_from_json.py +msgid "Let's go." +msgstr "一起走吧。" + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" +msgstr "*滋滋*你是认真的吗?这可不是手机。能等到我们在同一个地方再聊吗?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what did you want to say?" +msgstr "好吧,你想要聊些什么?" + +#: lang/json/talk_topic_from_json.py +msgid "Mind if we just chat for a bit about your history?" +msgstr "可以和我聊聊你的经历吗?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's just chitchat for a while, I could use some relaxation." +msgstr "让我们聊会儿天吧,我需要放松一下。" + +#: lang/json/talk_topic_from_json.py +msgid "I changed my mind, wanted to ask you something else." +msgstr "我改变主意了,问点别的吧。" + +#: lang/json/talk_topic_from_json.py +msgid "I'm all ears, my friend." +msgstr "我洗耳恭听,我的朋友。" + +#: lang/json/talk_topic_from_json.py +msgid "You gonna give me orders?" +msgstr "你要给我下什么指令吗?" + +#: lang/json/talk_topic_from_json.py +msgid "What would you like?" +msgstr "你想要我做什么?" + +#: lang/json/talk_topic_from_json.py +msgid "Just say the word." +msgstr "只要你开口。" + #: lang/json/talk_topic_from_json.py msgid "Can you teach me anything?" msgstr "[求教]现在你能教我点东西吗?" @@ -166366,14 +168574,6 @@ msgstr "[站岗]守在这里。" msgid "I want to assign you to work at this camp." msgstr "[指派]我想派你去这个营地工作。" -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." -msgstr "我们来谈谈你当前干的活。" - -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "我们来谈谈派系营地的事情。" - #: lang/json/talk_topic_from_json.py msgid "Find a horse and mount up!" msgstr "找一匹马,然后骑上去!" @@ -166387,32 +168587,20 @@ msgid "Please go to this location." msgstr "请到这个地方。" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." -msgstr "[查看]我想更多地了解你的能力。" - -#: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" -msgstr "关于这个世界,还有什么建议吗?" - -#: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" -msgstr "可以和我聊聊你的经历吗?" - -#: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." -msgstr "让我们聊会儿天吧,我需要放松一下。" +msgid "I want you to build a camp here." +msgstr "我想让你在这里建立营地。" #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." -msgstr "[教程]告诉我怎么给你下达命令。" +msgid "We need to abandon this camp." +msgstr "[营地]我们得废弃这个营地了。" #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "[解散]我们就此分开吧。" +msgid "Show me what needs to be done at the camp." +msgstr "告诉我营地还需要些什么。" #: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "一起走吧。" +msgid "Let's talk about your current activity." +msgstr "我们来谈谈你当前干的活。" #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." @@ -166954,10 +169142,6 @@ msgstr "请到这个地方去……" msgid "Stay at your current position." msgstr "守在你现在的位置。" -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "告诉我营地还需要些什么。" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "我正在。" @@ -167030,60 +169214,6 @@ msgstr "*电流声* 收到,我会赶过去的。完毕。" msgid "Sure thing, I'll make my way there." msgstr "好的,我会赶过去的。" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "是的,炎炎夏日让我很难受,让我们休息一下,你最近如何啊, ?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "好吧,也许这能让我不再这鬼天气里冻僵了,怎么了?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "对啊,是时候休息一下了!你感觉怎么样?" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "天太黑了不是吗?怎么了?" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "我感觉很难受……你还好吗?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "当然,顺便说一下,谢谢你帮了我这么多的忙!不管怎样,你能应付吗,?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "好吧,我们聊聊。哦对了,谢谢你帮我做那件事。那么……你还好吗?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "现在我们可以稍微歇一会,我刚刚在想,这得有一个多月了吧……发生了这多事,你是怎么应付这一切的?" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "哦,那啥,还行,还行……" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -167138,7 +169268,7 @@ msgid "Hello there." msgstr "你好。" #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." +msgid "Okay, no sudden movements…" msgstr "好吧,别乱动……" #: lang/json/talk_topic_from_json.py @@ -167491,7 +169621,7 @@ msgid "Ah, okay." msgstr "啊,好吧。" #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." +msgid "Not until I get some antibiotics…" msgstr "除非你给我一点抗生素……" #: lang/json/talk_topic_from_json.py @@ -167599,7 +169729,7 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "我开车的时候没法训练你!" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." +msgid "Give it some time, I'll show you something new later…" msgstr "给我点时间,我会给你看点新玩意……" #: lang/json/talk_topic_from_json.py @@ -167627,7 +169757,7 @@ msgid "See you around." msgstr "[取消]嗯,保重吧,回头见。" #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." +msgid "I really don't feel comfortable doing so…" msgstr "这么做让我很不爽啊……" #: lang/json/talk_topic_from_json.py @@ -167699,7 +169829,7 @@ msgid "Thanks, see you later!" msgstr "谢了,请多保重!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." +msgid "You picked up something that does not belong to you…" msgstr "你拿起了不属于你的东西……" #: lang/json/talk_topic_from_json.py @@ -167793,13 +169923,13 @@ msgid "You might be seeing more of me…" msgstr "我们还会再见的……" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" -msgstr "再次问好。 *滋滋滋*" +msgid "Hey again. *kzzz*" +msgstr "又见面了。 *滋滋滋*" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "我……我自由了。 *滋滋滋* 我真的自由了! *噗滋滋滋* 看啊,你是这么长时间以来我见到的第一个活人。" #: lang/json/talk_topic_from_json.py @@ -167821,8 +169951,8 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "对不起,不要在意我是谁。我想你还是继续享受自由吧。" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" -msgstr "*嗡嗡声* 太棒了!那么现在发生了什么?" +msgid "*buzz* Great! So what happens now?" +msgstr "*噗滋滋* 太棒了!那么现在发生了什么?" #: lang/json/talk_topic_from_json.py msgid "Come with me. We can help each other out." @@ -167834,9 +169964,9 @@ msgstr "我们各自走各自的路,继续享受你的自由吧。" #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" -msgstr "……等等。*哔卟*为什么我要相信你?*滋滋匝*你可能和他们一样坏!" +msgstr "……等等。*哔卟*为什么我要相信你?*滋滋滋*你可能和他们一样坏!" #: lang/json/talk_topic_from_json.py msgid "" @@ -167856,8 +169986,8 @@ msgstr "算了,继续享受你的自由吧。" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" -msgstr "好吧,好吧,*巴兹*对不起!别再伤害我了!别插芯片要我做什么都行!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +msgstr "好吧,好吧,*噗滋滋*对不起!别再伤害我了!别插芯片要我做什么都行!" #: lang/json/talk_topic_from_json.py msgid "Follow me and do my bidding, then." @@ -167872,7 +170002,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "不,我才该道歉,我不是故意的。去做你想做的事吧。" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "……杀了…… *滋滋滋* ……你!" #: lang/json/talk_topic_from_json.py @@ -167907,14 +170037,6 @@ msgstr "告诉我派系营地是怎么样运行的。" msgid "Tell me how faction camps have changed." msgstr "告诉我派系营地有哪些变化。" -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "我想让你在这里建立营地。" - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "[营地]我们得废弃这个营地了。" - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "没什么。我们谈点其他的事情吧。" @@ -168190,7 +170312,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." +"talk…" msgstr "你是认真的吗?这里看上去可不是可以安全闲聊的地方……" #: lang/json/talk_topic_from_json.py @@ -168213,6 +170335,50 @@ msgstr "你想谈些什么?" msgid "Actually, never mind." msgstr "呃,其实没什么。" +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "何事,吾友?" @@ -168234,7 +170400,7 @@ msgid "May the earth flourish beneath our paths." msgstr "愿此地在吾等之路下欣欣向荣。" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "神智体,生而为一……" #: lang/json/talk_topic_from_json.py @@ -168422,10 +170588,10 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." -msgstr "我从小在农场长大,对鬼怪和地精什么的了解不多,但是我花了很多时间种菜而且我干活特别卖力。在乡下更好,更干净。没有那么危险。我希望。" +msgstr "我从小在农场长大,对鬼怪和地精什么的了解不多,但是我花了很多时间种菜而且我干活特别卖力。在乡下更好,更干净。没有那么危险。希望是这样吧。" #: lang/json/talk_topic_from_json.py msgid "Hey, I didn't expect to live long enough to see another living human!" @@ -169003,7 +171169,7 @@ msgid "Nevermind me, I'm just going to leave." msgstr "没事,我要走了。" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" +msgid "Indeed it is I! The one and only FOODPERSON!" msgstr "的确是我!独一无二的美食家!" #: lang/json/talk_topic_from_json.py @@ -169461,6 +171627,39 @@ msgstr "" msgid "Huh." msgstr "哈。" +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "我甚至搞不懂*现在*发生了什么。你怎么觉得我会知道世界是如何结束的呢?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "好吧,好吧。那你能不能至少告诉我迄今为止你所记得的事情吗?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" +"什么,你自己都不记得了吗?哦,抱歉,这样说对你不太公平,现在真是个奇怪的时代。好吧,好吧,我想这一切都是从那次暴乱开始的,不是吗?我们只是过着自己的生活,做着自己的工作,然后人们就开始暴动了。不像是平时那种由抗议演变成的暴乱或是啥的,人们突然就走出自己家门,开始到处打砸。新闻报道一开始试图淡化它,但他们无法阻止消息在互联网上传播。我不知道这是什么由引起的,他们说是水里的某种药物或毒素?不过,一开始我还没意识到情况有多糟糕。从某个时刻开始,有些死掉的“暴徒”开始复苏,胸膛上开着大洞还能够到处走来走去,这时真正的恐慌才开始了。接下来的几天——也许是几个星期,不太确定——对我来说完全是一团浆糊。你得问问别人我们这个世界是怎么完全崩溃的。" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "谢谢你让我知道。" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -169518,8 +171717,8 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" "最终是的。已经安静了好几个小时了。我口渴得厉害,又受伤了,而且被吓坏了。我的训练也许是唯一能让我没发疯的原因。我决定试着把自己拉出来,看看我的伤势有多严重。结果很" " " @@ -169815,6 +172014,32 @@ msgstr "可怜的家伙。" msgid "Thanks for telling me that stuff. " msgstr "谢谢你告诉我这一切。" +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" +"好吧,呃,之前发生了一些非常严重的骚乱,是吧?每个人都变得特别暴力恶毒,老实说,这次经历对我而言就像是一次精神之旅,而很多事情我都记不太清了。但最奇怪的是,甚至没有人想要*关心*对方。好像我们所有对他人的关心都被吸走一样了。我认为这是一种负能量。而这种能量带来了,呃,死者复生和其他东西。还有,呃,一些怪物?我真不太清楚它们是怎么来的。" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "你听起来似乎很懂啊,你认为是什么导致了这一切?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" +"这可是个困难的问题,但我不断回想起那个梦,在这一切开始之前一年我做过的梦。我梦见有一个充满邪恶能量的大球,它在等待着吸收地球上所有美好的想法,把我们变成怪物和那种东西?所以我想真实情况也许就是这样的。其他一切理论似乎都太牵强了,你知道吗?" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -169869,6 +172094,25 @@ msgstr "" " " "怪兽,那家伙有一辆大众越野车那么大,全身上下都是骨板。那一刻我知道自己被越级碾压了。那个大块头被尸潮里它的那些\"朋友\"给挡住了,我设法绕过它跑回了我的住处。我关上窗户,把房间完全上锁,但已经太晚了。那头巨兽跟着我,然后就开始敲墙。我抓上所有带得动的东西,逃得远远的。当我最后回头朝原来的躲藏点看时,它整个塌在了那个混蛋身上。我寻思着,那家伙应该是被砸死了,但我可不会回去找出答案。" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" +"发生了什么?我可不太确定。你肯定已经知道那场暴乱和接下来发生的一切,政府和警察完全没能控制住状况。我不知道那是什么原因造成的。一开始我以为这不过和往常一样,我不得不承认,一想到这可能会是一场革命的开始就让我既兴奋又害怕。但我还没兴奋到主动加入它,而且我想任何曾经加入的人现在应该都已经死了。我试着在家里等着,收拾了一个小求生背包,但后来互联网上开始播放暴徒们复生后带着可怕的伤口继续打斗的视频。我不知道一开始有多少人真的相信它,但我把它当作我的告警信号,直接离开了小镇,去了避难所。我不知道在那之后到底发生了什么。我所在的避难所遭到严重破坏,空无一人,我再也没有看到其他人。手机网络被完全封停了,除了有天传来的一条紧急短信说政府已经倒台了。几天后整个避难所就停电了。" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -169905,6 +172149,22 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "你觉得发生了什么?你在附近看到那些家伙了吗?" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" +"好吧,我想你知道暴乱,军队和警察,还有和丧尸一起在各处肆虐的怪物,对吧?如果你问我认为是什么导致了这一切,我不知道。我最好的猜测是政府的过度行为,也许是某种实验性的生物武器泄漏了。他们一开始就试图对发生的一切撒谎,我可不认为这一切都是“中国攻击”的鬼话。他们试图掩盖一些事情。至于真正的末日,也许世界其他国家都在试图控制它。我听说在美国本土有些真正的核弹被引爆了。在我看来,这意味着其他地方,也许是欧洲,试图控制这里发生的一切。也许他们成功了。现在也许很糟糕,但现在不像以前了。" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -169967,6 +172227,42 @@ msgstr "" "嗯,我在那里过得还不赖,但最终我开始变得有点发疯。下面总是黑乎乎的,还有点冷,而且只能靠吃捡来的垃圾食品过日子……一个灵魂只能在那种环境下活这么久。当地上开始变暖,白天时间变长之后,我决定再勇敢一点。我已经学到了很多关于" " 的知识,在那之后我就能过得很好了。我在好几个地方露营过,采集浆果之类的东西填肚子,与前几个月相比,我过着相当好的生活。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" +"哇,,我都不知道从哪里开始说起。暴乱吗?我想事情发展得要比这快。在那件事发生前的几个星期里,就已经有很多可怕的传闻了。很多可怕的罪行,不是你平常的事,而是像吃人和一些真正无法形容的烂事,你知道吗?当暴乱开始的时候,我想我已经做足了一切准备,认为这是一场不同于普通的平权暴乱或类似的事情。我想这是我能安全逃离的一部分原因,我已经提前买好了装备直接就出发了,而不是试着去购物。那时候人们简直是疯了。这很像几年前的新冠大流行,不过这次警察在街上大肆出动,四处拿枪杀人,就好像情况已经快失控了一样。" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "你知道这一切真正的起因是什么吗?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" +"完全没有头绪。政府给我们灌输了各种相互矛盾的故事,而且还发生了一些十恶不赦的事情。我是说,你不可能没看过那个女人杀死自己孩子的视频吧?天啊,它现在还会让我做噩梦。我不知道是怎么回事,光是看她脸上的那种表情。更糟糕的事情当然接连发生,现在我们都已经亲眼更糟糕的事,但那个视频还是像个梦魇一样缠着我。不管怎么说,他们都没能控制住暴乱,而当暴乱者开始变成不死人时,一切都已经太晚了。我不知道是不是士气崩溃了或者是什么,但我听到传言说,军队和警察开始像人群一样互相攻击。到底是什么让死人复活的?我一点线索也没有。" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -169976,6 +172272,55 @@ msgid "" msgstr "" "他们本来准备把我和一群被疏散者们送到一个难民中心,但我们的大巴被你所能见过的体型最大的丧尸给砸烂了。它忙着追赶其他乘客,所以我做了所有人都会做的一件事,那就是他妈的赶紧跑得越远越好。" +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "别吊我胃口了,接下来发生了什么?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" +"我一直跑,直到我觉得自己的肺快要从嘴里跳出来。我在森林里躲了一夜,靠在一棵冷杉树下。早上我听见了说话声,于是我过去调查了一下。我当时的动作特别小心,因为四周还有很多疯子和暴徒。我暗中观察到了一些东西,一些比丧尸还糟糕的怪物。一些巨大的昆虫一样的生物,说一些随机的短语,像是一台坏掉了的录音机一样。它的身后拖着几具人类尸体,我不知道他们是死了还是昏迷了。老实说,我可不想呆在那里找出答案然后等着被发现,我躲进了灌木丛,试着屏住呼吸,直到我再也听不见它所发出的声音。" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "在那之后你又去了哪里?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" +"当我确认离开灌木丛没事之后,我找到一间能让我随身脱身的旧木屋。它已经快塌了,但至少能挡挡风雨,而且给了我一处能避开他人视线的地方。我一直呆在那里,直到我把满满一背包的那些尝起来和屎一样的口粮棒吃完。然后我不得不浪迹天涯,直到我们相遇。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" +"这是什么意思,你是经历了和《回到未来》电影里那样的事吗?你怎么可能不知道发生了什么事?世界末日到了,就是这样。而且不是从地震,鸟,蛇,飞机开始的。一开始是暴乱,政府不得不派警察,随后派军队去解决那些" +" " +"罪犯。政府试图掩盖它,声称这是某种精神控制药物,但一开始在我看来和平时那些扯淡事情没什么不同,不过是些巨婴们想要找个借口违法罢了。这一次,情况变得更糟了,直到是时候逃离“道奇城”了。我听说有传言说他们甚至尝试用核弹轰炸一些城市中心试图控制它——我不得不承认,这可能有点过于硬核了。" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -170020,6 +172365,28 @@ msgstr "对不起。你能告诉我更多关于它们的信息吗?" msgid "Right. Sorry." msgstr "好吧。很抱歉。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "好吧听着。别相信任何政府说的东西。所有这些都有相同的脉络:暴乱发生,军队控制不住,最后几天时他们甚至说出现了巨型怪物,必须用核武器消灭。" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "你引起了我的注意。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" +"你看过黑客帝国吗?就和那一样。电影成真了。为了让我们被锁在这里,这个模拟世界的创造者必须确保我们能恰到好处地遭遇不幸。我认为他们用的算法可能出了点问题,进入了超速档,因为现在发生的这些事情有点让人难以置信。不过,我想我们还是被困在里面了,所以也许它还是起到了一定的作用。" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -170033,6 +172400,20 @@ msgid "" msgstr "" "嗯,我那会正在家,手机突然开始一直响警报,告诉我去一个紧急避难所。所以我就去了紧急避难所。然后紧急避难所渐渐变得拥挤起来,人们等着被送到难民中心,但是大巴却一直没有来。你一定已经知道接下来会发生什么了。一开始是恐慌,然后变成打斗。我没有留下来看看接下来会发生什么,我带着我能从锁柜里抢到的工具逃进树林里。几天后我回去了,但那地方被完全遗弃了。不知道那些人最后怎么样了。" +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" +"老实说,我在避难所听了很多故事,但我脑海里最后只剩一个了。这一切都是某种科学实验出了问题。我不知道是什么引起了暴乱和死人复生,但不可能每个地方都像这样失控。是的,我和其他人一样都收到了“政府已经沦陷”的短信,但完全这么短时间内就能扩散得这么快是完全*讲不通*的。我认为我们处于某种禁区之中,他们放任事态任意发展,了解其工作原理,这样他们下次就能更好地与之抗衡。在外面的某个地方,在这个区域之外,基本上一切照旧。" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -170107,6 +172488,45 @@ msgstr "很抱歉不该问你。" msgid "Sorry for asking. " msgstr "很抱歉不该问你。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "哇,你想听听我的第一感觉吗? 政府对我们做了这件事。他们肯定是故意的,或者至少是半故意的。" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "哦?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" +"就是这样的。他们骗了我们,天知道这些事情已经发生过多久了,因为他们不想让我们弄明白。可能一开始是为了让人们保持秩序,但不知怎么适得其反。我的猜测是他们试图愚弄我们,试图误导我们,当那不起作用的时候,他们在水里下药让我们变得愚蠢或其他什么。结果人们没变得愚蠢,反而变得暴力。然后他们试图利用这一点来实施戒严,但那没有奏效,他们最终与人群作战。只是他们没有意识到他们那" +" 精神药物是某种诱变剂,能把人变成丧尸。" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "那其他的怪物又是怎么回事?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" +"我想大概都是变异引发的吧。我不知道他们用了什么,但可真是疯狂科学家之类的狗屁玩意,我之前也觉得大部分事情都不可能发生。我也在想,是不是他们放在水里的东西让我们变得有些疯狂了。也许这一切只是幻觉?想到这让我有点吃惊,我不确定我是否相信这种理论,但我也没有其他解释了。" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -170748,6 +173168,49 @@ msgstr "" "当一切都失控的时候我很晚才被疏散。在城里被困了几天,躲在地下室里吃女童子军饼干和喝温过的麦根沙士。最后,我设法在 不被 " "抓住的情况下逃了出来。我在一家废弃的购物中心里呆了几天,但我需要食物,所以我又进了树林里自食其力。这活计我做得不太好,所以很高兴你及时出现了。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "好吧,那么,听我说完。这听起来可能有点疯狂,但我们已经要对付 行尸了,所以我觉得这个理论可以接受。你听说过希腊神话吗?" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "不太熟悉。这有什么关系?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "当然了,怎么了?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" +"好吧,好吧,我知道这听起来像是印第安纳琼斯B级片里的情节,但我想有人发现了潘多拉的盒子,真实的盒子或接近它的玩意。我认为他们试图利用它,利用它的力量来做些什么。也许原本想做件好事,谁知道呢,上帝的力量对我来说似乎应该算是一种绿色能源。不管是什么,他们把它搞砸了,然后真的放出来了。不仅仅是故事里的隐喻,而是将地狱的力量在地球上散播。是的,我知道这太牵强了,但就像我说的:我想这说得通。" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "什么?潘多拉的盒子?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "根据传说,潘多拉在众神的居所中发现了一个未打开的盒子。她决定去调查,当她打开它时,不可思议的恐怖灾难和疾病蔓延开来。听起来很熟悉吧?" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "好吧,那它和这一切有什么关系?" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -170796,6 +173259,137 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "谢谢你告诉我这一切。" +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" +"你是说是什么引起了暴乱?好吧,他们说这是中国的生物武器,但我很难相信有什么人能制造出一种能做到这一切的生物武器。我能想出的唯一答案,虽然听起来很傻,是外星人。" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "你觉得这是入侵?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" +"好吧,也许吧,但我想这太混乱了,不可能是一次真正的入侵。如果非要我猜的话,我会说极地冰层里有什么东西。比如,记得几年前网上有一件关于在冰里发现的外星人尸体的大事吗?我不知道你是否还记得,但有一段时间,这件事在新闻上铺天盖地,最后变成了一场骗局。只是,从那以后,我见过一些外星人,他们看起来*很像*那个冰住的尸体。也许这不是骗局,也许是政府掩饰了这一切。所以,也许那些外星人有某种病毒。它周游世界,悄无声息地感染着一切,直到不知何故,它激活并引发了暴乱、怪物和突变。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" +"我们就别卖关子了:一开始我参加了暴乱。我真的不记得那时候我在想什么。我以前参加过抗议警察暴行的游行,但这次不太一样。我并没有做个牌子,也没打算去那里唱歌游行,我抓起一根球棒,打算去外面搞打砸抢。我从来没有这么生气过。当时的暴乱已经持续了一段时间,在我看来,这只是政府试图再次镇压人民。" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "那些暴徒确实像是疯子。" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "没有多少人能活着走出暴乱。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" +"是的,还用你告诉我。那些暴乱的人……他们甚至不像是人类,更不像抗议者。和我从前参加过的任何一次抗议活动都不一样。但这并没有阻止我。我加入了他们,我和他们一样坏。砸碎窗户,殴打旁观者,烧毁汽车。我记得我把防暴装备从警察身上扯下来……算了。我想忘掉它。" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "你是怎么活下来的?" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "是什么让你回头的?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" +"在某个时候,我感觉自己好像醒过来了。当时他们正在摧毁那些顶部有防暴炮塔的悍马。说起当时我的心里甚至不记得自己是否曾经遇见过他们。不论怎样,我听到枪响了,我才意识到我正站在一群准备冲击全副武装军事据点的暴徒周围。从那时起,我那时才真正认清楚暴徒的模样,看到那种带着狂野眼神的动物,甚至是丧尸。我转身就跑。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" +"我真的不知道。我猜如果有足够的时间,其他人也许一样会恢复理智。我觉得我没什么特别的。也许他们中的很多人都恢复理智了,只是当时并不在人群的边缘。但我要告诉你的是,当我回过神来之后,能看到一些暴徒看着我的眼神像是看待猎物一样。我可不想留下来看看会发生什么。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" +"我对这个城市很熟悉。我跑到我所知道的一幢废弃建筑里,从一扇破窗里钻了进去,呆了几天。我在那里存了一些偷来的食物,我就自己一个人呆着。当事情开始平静下来,我就离开了,然后我就在这里了。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" +"是的,我和其他人一样,记得引发暴乱的那一系列事件。事情很糟糕,新闻上报道了一些非常可怕的罪行,而警察处理案件的方式,也像往常一样引发了种族之间的紧张关系。然后人们开始暴乱,这并不罕见,但骚乱开始的地方很奇怪。比如,中上阶层的街区,中西部的小城镇,诸如此类。不管怎么说,我参加了暴乱,在那之后我就记不太清了。" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "你参加了暴乱?" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "那么,你肯定对造成这一切的原因有所了解。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" +"我想某种程度上是吧。我听到有人把暴乱归咎于某种精神控制药物,说实话,我觉得这理论并不离谱。这就是我的感觉,虽然全程中我感觉还能控制自己。直到我猛地惊醒过来,我才意识到整件事情有多奇怪。不过,这并不能解释其他的一切:丧尸,怪物,以及那些离谱的东西。我所能想到的任何解释听起来都像是糟糕的科幻小说,像是恶魔的诅咒或者外星人的武器之类的东西。" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -171085,16 +173679,54 @@ msgstr "" msgid "I can respect that." msgstr "我可以尊重这一点。" +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "我真的不想和你谈以前的事,知道吗?" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "实在不行可以模糊地描述一下,但请你稍微讲讲好吗?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" +"我——好吧。水里被人下了药,我猜是某种生物武器。你知道我们和中国的关系,政府把所有问题都归咎于他们。人们开始变得暴力凶恶。然后发生了暴乱。我所关心的人也加入了他们,我想我永远也没法知道原因了。暴乱导致军队和警察采用强力措施,这使得暴乱更加严重。人们变得像动物一样,不仅是暴徒,而且是所有人。然后,那些怪物和梦魇就出现了,像真正的世界末日一样,每个人都死了,然后开始复生变成怪物。这就是你要的故事。如果你还想要更多,找其他人谈谈。" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "谢谢你的故事。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" +"老实说……我不记得了。我只能记得世界变成现在这个样子之前生活的一些模糊细节,但关于 " +"本身呢?全都是一团浆糊。我不知道我是怎么走到现在这一步的,也不知道这一切是怎么发生的。我想一定是我遇到些特别糟糕的事。我记得一些事情:一些暴力事件,一个女人杀了她的孩子。我宁愿我能忘掉它。" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" "老实说……我不记得了。我只能记得世界变成现在这个样子之前生活的一些模糊细节,但关于 " -"本身呢?全都是一团浆糊。我不知道我是怎么走到现在这一步的,也不知道这一切是怎么发生的。我想一定是我遇到些特别糟糕的事。或者我的头被狠狠揍了一顿。或者两者兼而有之。大概这些都发生过吧。" +"本身呢?全都是一团浆糊。我不知道我是怎么走到现在这一步的,也不知道这一切是怎么发生的。我想一定是我遇到些特别糟糕的事。或者我的头被狠狠揍了一顿。或者两者兼而有之。大概这些都发生过吧。我醒过来能记得的第一件事是在手机上看到一条已经读过的短信,上面说联邦政府已经垮台了。" #: lang/json/talk_topic_from_json.py msgid "" @@ -171186,6 +173818,46 @@ msgid "" " ask again." msgstr "听好了,我说得很清楚,如果你继续找茬,我就要发火了。曾经的我已经走了。死了。我不在乎你的\"健康\",别 再问了。" +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" +"你在问我是什么导致了这一切?新闻上到处都是。某种中国生物武器。这与几年前的新冠病毒大流行没有什么不同,但看来这次他们的配方用对了。也许太对了。反正没关系,我听说这病毒对他们也有效,把他们全都干掉了。他们活该。" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "不过,你能告诉我到底发生了什么事吗?" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "这怎么解释其他疯狂的事情呢?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" +"好吧,你知道的。首先是水里的精神控制药物引起的暴乱。但我想我们现在都能看到它其实又是一种病毒。军方和警察尽了最大的努力镇压暴乱,但它失去了控制。然后病毒发生变异,开始让死人复活,就像B级片里的情节,那狗屁玩意真的变成了现实。然后它们释放出了巨型怪物,或者它们把我们变成了怪物,我不知道。那是巨大的难以形容的怪物……一想到它们我就不寒而栗。它们显然不适合战斗,军队很快就把它们干掉了。" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" +"什么?当然能解释。他们一开始用的是生物武器,后来变成了全核武器。只不过我们现在所拥有的武器比氢弹差得多。山姆大叔设法击退了那些最可怕的怪物,但我猜那不过是他的垂死一搏。" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -171495,7 +174167,7 @@ msgstr "那是因为一件……东西。一开始是一次大胆的决定。最 #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "逃税。我是一名会计师,我用一些非常聪明的方式帮我的老板转移了一大笔钱。但聪明得还不够,结果就这样了……" #: lang/json/talk_topic_from_json.py @@ -171683,6 +174355,34 @@ msgid "" msgstr "" "我会坚持所信,一直祷告,击倒我所看见的一切地狱使者。这是我们剩下所能做的少数几件事,不是吗?我想也许我们太过懦弱,只能留下来继承这个人世。但我不太看好我们的胜算。" +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" +"很清楚,不是吗?那个……当末日来临,\"被提\"会来。而我却仍然在这里,我仍然不明白为什么,但我会把耶稣留在我的心中,经历即将到来的苦难。当一切过去之后,我相信祂会欢迎我进入天国。或者……或者其他类似的东西。" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "我的意思更多指的是实际发生的事件。到底发生了什么?" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" +"哦。好吧,如果我没记错的话,我想这是《启示录》中的预言过的事情。你知道,我有一段时间没参加牧师弥撒了。一开始是瘟疫……第一次是几年前的那次,那次新冠大流行,那时候人们就已经开始谈论末日即将来临。然后是血之灾,还是暴力?那指的是暴乱。然后海水被血染红,那是所有被警察枪杀的人的血。然后是火之灾,这个我很确定,因为当时丢了核弹和到处都有爆炸,试图控制暴乱。然后是恶魔和怪物在地上行走,死者从坟墓中复活,最后温顺的人承受地土。说得一清二楚。" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -171691,6 +174391,24 @@ msgid "" msgstr "" "和其他人一样。我背叛了上帝,现在我要付出代价。\"被提\"来了,而我被留下了。所以现在,我想我得留在这个人间地狱里四处游荡。我真希望当初我在主日学校里上能多听点课。" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" +"好吧,我想那大概就是\"被提\"吧。但这和我想的不一样啊。他们让我以为会像是一道闪光,然后“噗”的一声,所有人都不见了。相反,一切都变得又乱又脏。一开始是街上的暴乱,然后为敌基督效命的军队和警察开始枪杀人民——就像我爸常说的啥来着——像镰刀收割麦子一样?当我们真的显出我们的罪时,神带着真正的灾祸来了。死者开始复生行于地上,身上带着机枪的弹孔站起来攻击军队,军队也开始互相攻击。在那之后,地狱军团也亲自降临于世。巨大的怪物,比我能想象到的任何东西都还要可怕,它们在城市中撕碎一切。然后它们像来时一样很快消亡了,我们只好四处逃命尝试躲开亡灵。一两天后,供电也都没有了。" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -171919,10 +174637,6 @@ msgstr "为自由商会工作是什么样的?" msgid "What was working for the Old Guard like?" msgstr "为旧世守护者工作是什么样的?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "谢谢你的故事。" - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "谢谢你的故事。我们该走了。" @@ -172154,6 +174868,23 @@ msgstr "" msgid "What were you saying before that?" msgstr "你刚刚还说了什么?" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" +"实话跟你说,我更关心婚礼策划,而非时事要闻。我知道外面有暴乱发生,但他们已经出城了。即使当他们离家越来越近的时候,我尽力尝试无视他们,这样可以好好过我们大喜的日子。但是在丧尸开始出现之后,一切都变得非常奇怪了。当我从婚礼逃出来时,我发誓我看到天空裂开了,怪物从洞里飞出来,就像独立日电影里的那样。我不知道它们是什么,看起来像是黑魔法之类的。" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "嗨,那边那位。" @@ -172683,7 +175414,7 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "马上滚出我的农场,我不跟政府的走狗说话。" #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "继续……" #: lang/json/talk_topic_from_json.py @@ -173083,10 +175814,6 @@ msgid "" " catastrophe." msgstr "你最好马上离开我的地盘,这次灾难早就显示了政府的无能。" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "说吧……" - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "你老婆呢,她在这吗?" @@ -174535,7 +177262,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "真恶心,不是吗?像个野人一样。大灾变过后不久,我身上就开始到处长毛。不知道是什么引起的。我不怪他们讨厌这玩意,我也讨厌。" @@ -175279,7 +178006,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -176389,12 +179116,12 @@ msgstr "你是怎么到这里来的?" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" "达娜和我是最早撤离的一批,因为她怀了孩子。我们被带到一个集合中心,在那里坐上了一辆巴士。那巴士被一个巨大的怪物掀翻了,很多人死在那里。我们与其他几个人设法逃脱,一直走到这儿。其实我们走的并不远,不知为何那怪物并没有追我们,只是继续撕扯那辆巴士。" @@ -176526,12 +179253,12 @@ msgstr "过的和我预想的一样,只能这么说了。不过感谢你的关 #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" "说来话长。我不是这附近的人,实际上我是从加拿大西部来的。我一直想见识一下新英格兰,我在这里度假的时候,嗯,你知道的。我被疏散到了这里,但因为我不是美国公民,他们不让我下楼。我能理解他们的做法,即使我不太喜欢。说实话,我还在尝试着接受事实,接受我可能永远无法知道我的家人和乐队情况的事实。" @@ -176600,7 +179327,7 @@ msgid "Hm? Oh, hi." msgstr "哈?哦,嗨。" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "……嗨。" #: lang/json/talk_topic_from_json.py @@ -176975,8 +179702,8 @@ msgstr "是的,我不知道你做了什么来说服他们搬出去,但是我 #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" "即使我们把这一切事情都解决了,这里也没有足够的床位给每个人,而且肯定也没有足够的补给。现在我们处境艰难。我们只能提供些力所能及的帮助……至少他们有个安全的地方呆着。" @@ -176995,9 +179722,9 @@ msgstr "你们的处置室出了什么问题?" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -177327,7 +180054,7 @@ msgid "" msgstr "我们才不会把你这种废物放在眼里,有事办事,办完赶紧滚开。" #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." +msgid "I'm not in charge here, you're looking for someone else…" msgstr "我在这只是个干活的,要谈事情的话找别人去吧……" #: lang/json/talk_topic_from_json.py @@ -177375,11 +180102,11 @@ msgid "Well, I'd better be going. Bye." msgstr "好吧,我最好先走了。再见。" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." +msgid "Welcome marshal…" msgstr "欢迎您,执法官……" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." +msgid "Welcome…" msgstr "欢迎……" #: lang/json/talk_topic_from_json.py @@ -177621,11 +180348,11 @@ msgstr "" "不幸的是,没有。离开的大部分人原本就被困在楼上,他们所承担的风险已经比那些有张安全的床的人要小。地下室里只带出了几个人,当我们开始计划的时候地下室已经太拥挤了。我们希望有更多的人到农场去晒晒太阳,呼吸新鲜空气,干点苦活……但是你可能猜到了,人们更害怕被尸群袭击。" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." +msgid "Marshal…" msgstr "你好,执法官……" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." +msgid "Citizen…" msgstr "你好,公民……" #: lang/json/talk_topic_from_json.py @@ -178239,7 +180966,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" "考虑到目前的情况,我们可以打折卖给你一套我们的防护装备:防护服、防毒面具和滤芯。我们只要两枚我们的硬币。\n" "\n" @@ -178295,11 +181022,11 @@ msgstr "知道了。" #: lang/json/talk_topic_from_json.py msgid "Better keep our eyes on the road." -msgstr "" +msgstr "我们最好盯着路。" #: lang/json/talk_topic_from_json.py msgid "Better be careful around here." -msgstr "" +msgstr "这里最好小心点。" #: lang/json/talk_topic_from_json.py msgid "Yes?" @@ -178323,7 +181050,7 @@ msgstr "很高兴见到你。" #: lang/json/talk_topic_from_json.py msgid "About those jobs…" -msgstr "" +msgstr "关于那些任务……" #: lang/json/talk_topic_from_json.py msgid "Good to see you around." @@ -178335,7 +181062,7 @@ msgstr "还有什么需要吗?" #: lang/json/talk_topic_from_json.py msgid "Lets set a combat strategy" -msgstr "" +msgstr "让我们制定一个作战策略" #: lang/json/talk_topic_from_json.py msgid "" @@ -178390,7 +181117,7 @@ msgstr "你在想什么呢?" #: lang/json/talk_topic_from_json.py msgid "Want help with something?" -msgstr "" +msgstr "想要帮忙吗?" #: lang/json/talk_topic_from_json.py msgid "What do you know about our employers?" @@ -178435,15 +181162,15 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "你这么一说,确实有点奇怪。" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." +msgid "Thinking I should go hunt something soon…" msgstr "看来我有个狩猎目标了……" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." +msgid "Wondering if things will get better someday…" msgstr "也不知道情况会不会好起来……" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." +msgid "Hmm? Nothing, I guess I just like resting in this place." msgstr "嗯?没什么,我想我只是喜欢在这个地方休息。" #: lang/json/talk_topic_from_json.py @@ -178483,8 +181210,8 @@ msgstr "文明举止,佣兵。" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." -msgstr "路上的坏家伙无穷无尽,也许你应该专心工作,执法官……" +"marshal…" +msgstr "路上仍然有不少不法分子,也许你应该专心工作,执法官……" #: lang/json/talk_topic_from_json.py msgid "You see anything you want, marshal?" @@ -178552,7 +181279,7 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "眼下好像没什么需要你帮忙的。" #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." +msgid "Stand still while I get my clippers…" msgstr "请稍等,让我拿把剪刀来……" #: lang/json/talk_topic_from_json.py @@ -178931,8 +181658,8 @@ msgid "" msgstr "我自己是不怎么需要的,不过我们派出去回收载具的小队应该是需要帮手的,但他们大部分时间都在哨站外面,恐怕不太好找。" #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." -msgstr "请离我远一点……" +msgid "Please leave me alone…" +msgstr "请让我一个人静静……" #: lang/json/talk_topic_from_json.py msgid "What's wrong?" @@ -178950,14 +181677,13 @@ msgstr "那可真糟糕。" #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." -msgstr "我不知道你能做什么。什么我都试过了。也许多给我点时间就好……" +"I don't know what you could do. I've tried everything. Just give me time…" +msgstr "我不知道你还能做些什么。什么我都试过了。也许多给我点时间就好……" #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." +"seems like I can't keep anything down…" msgstr "我一直在生病!起初我猜是不是我吃坏肚子了,可现在我吃什么吐什么……" #: lang/json/talk_topic_from_json.py @@ -179082,8 +181808,8 @@ msgstr "反正我也不想加入你们那个俱乐部。" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "这里?水果和浆果。也许偶尔是农场设备,但你需要加密币。" #: lang/json/talk_topic_from_json.py @@ -179435,7 +182161,7 @@ msgstr "欢迎。你饿了吗朋友?" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "你看起来很饿,朋友。世界上有那么多的饥饿。现在是大食客们的时代。" @@ -179607,8 +182333,8 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "很高兴能为大食客效劳。算我一个。" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." -msgstr "太棒了。努力让这一切实现吧。" +msgid "Excellent. Make it happen." +msgstr "太棒了。加油干吧。" #: lang/json/talk_topic_from_json.py msgid "" @@ -179768,15 +182494,15 @@ msgid "Oh, you again." msgstr "哦,又是你。" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" -msgstr "哼?*喃喃自语*……你是谁?" +msgid "Huh? *mumble mumble* … Who are you?" +msgstr "哈?*喃喃自语*……你是谁?" #: lang/json/talk_topic_from_json.py msgid "I'm busy, what is it?" msgstr "我很忙,怎么了?" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "然后丢下我这座塔和我所有的研究?我还是不要了。" #: lang/json/talk_topic_from_json.py @@ -179923,7 +182649,7 @@ msgstr " 并指如矛,猛击 %s" #: lang/json/technique_from_json.py msgid "Lizard Tail" -msgstr "壁虎之尾" +msgstr "壁虎扫尾" #: lang/json/technique_from_json.py #, python-format @@ -182933,59 +185659,59 @@ msgstr "迅速地扫击了%s和附近的敌人" #: lang/json/technique_from_json.py msgid "Mountain Hammer" -msgstr "" +msgstr "巨山破" #: lang/json/technique_from_json.py #, python-format msgid "You crush %s with the weight of your Mountain Hammer" -msgstr "" +msgstr "你用一记巨山破砸向 %s" #: lang/json/technique_from_json.py #, python-format msgid " crushes %s with the weight of their Mountain Hammer" -msgstr "" +msgstr " 用一记巨山破砸向 %s" #: lang/json/technique_from_json.py msgid "Irrestistible Mountain Strike" -msgstr "" +msgstr "地动山摇" #: lang/json/technique_from_json.py #, python-format msgid "You smash down on %s with a Mountain Strike" -msgstr "" +msgstr "你用一记地动山摇将 %s 砸翻" #: lang/json/technique_from_json.py #, python-format msgid " smashes down on %s with a Mountain Strike" -msgstr "" +msgstr " 用一记地动山摇将 %s 砸翻" #: lang/json/technique_from_json.py msgid "Colossus Strike" -msgstr "" +msgstr "巨人冲击" #: lang/json/technique_from_json.py #, python-format msgid "You completely shatter %s with a Colossus Strike" -msgstr "" +msgstr "你用一记巨人冲击击碎了 %s" #: lang/json/technique_from_json.py #, python-format msgid " completely shatters %s with a Colossus Strike" -msgstr "" +msgstr " 用一记巨人冲击击碎了 %s" #: lang/json/technique_from_json.py msgid "Wolverine Stance" -msgstr "" +msgstr "狼獾势" #: lang/json/technique_from_json.py #, python-format msgid "The %s tries to grab you, but you thrash your way to freedom!" -msgstr "" +msgstr "%s 试图抓住你,但你奋力挣脱了。" #: lang/json/technique_from_json.py #, python-format msgid "The %s tries to grab , but they thrash their way to freedom!" -msgstr "" +msgstr "%s 试着抓住 ,但被奋力挣脱了!" #: lang/json/ter_furn_transform_messages_from_json.py msgid "The earth here does not listen to your command to move." @@ -183996,223 +186722,29 @@ msgid "" msgstr "一段金属栏杆,放置在适当的位置,以防止人员坠落或轻易离开。" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "泥土地" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "泥土地,看来土壤适合耕种。也可以开发建设项目。" - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "噗通" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "一大片优质细砂,如果开采得当,可以在很多方面发挥作用。" - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "泥地" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "一块泥泞湿滑的泥地。" - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "黏土" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "一块充满可塑性黏土的场地,如果开采得当,挺适用来烧窑。" - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "黏土堆" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "一堆黏土。" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "啪叽!" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "沙堆" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "一堆沙子。" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "土堆" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "一块开好垄的泥土地,不容易穿行。仔细检查,可以发现它很适合种植。" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "一个大土丘,看起来可以爬进去当掩蔽。" - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "古怪的裂痕" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "一个不自然的人形洞,看上去有种奇怪的熟悉感觉。你觉得自己有种想要靠近仔细观察的冲动,仿佛它本来就和你是一体的一般。" - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "墓地" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "一个泥土坟墓,上面长着一些草。至少有些死者确实安息了。" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "一座新坟,用石头盖着既防止他人挖开又防止里面的东西挖出来。有两块木板标识着某人永恒安息之地。" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "石地板" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "相对平坦的岩石区。看来稳定程度足堪采矿设备的开掘。" - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "路面" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." -msgstr " 一段铺了柏油的路面,因为裂缝、冻胀和缺乏维护而逐渐老化。" - -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "黄线路面" - -#. ~ Description for yellow pavement -#: lang/json/terrain_from_json.py -msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "禁止司机跨越的双黄线。再也没有人来执行这些规则了。" - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "人行道" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "一段现浇混凝土路面。因为缺乏维护而毁于冻胀和大裂缝。" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "一种新式的水泥浇筑块,表面处理兼顾了美观与抗冻-融循环功能。" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "一种新式的水泥浇筑块,表面处理兼顾了美观与抗冻-融循环功能。外部涂上一层黄色的油漆。" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "木地板" +msgid "overgrown floor" +msgstr "血肉覆盖的地板" -#. ~ Description for wooden floor +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." -msgstr "木质楼板,由扎紧的木板钉牢而成。常见于露台。" +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." +msgstr "一层裸露的混凝土地板,几乎完全被不断抽搐的细小灰色肉丝所覆盖。" #: lang/json/terrain_from_json.py msgid "SMASH!" msgstr "啪嗒!" #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "金属地板" +msgid "overgrown wall" +msgstr "血肉覆盖的墙" -#. ~ Description for metal floor +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." -msgstr "高质量的坚固网纹地板,可以减小滑倒的风险。" - -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "油毡地砖" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." -msgstr "用坚硬的橡胶材料制成的地板。涂上简单的白色。" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "用坚硬的、灰色的橡胶材料制成的地板。" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "泥地板" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." -msgstr "由材质细腻的土壤夯实而成的泥土地板。" +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." +msgstr "一面裸露的混凝土墙,几乎完全被奇怪血管和肉结组成的网格所覆盖。" #: lang/json/terrain_from_json.py msgid "concrete floor" @@ -184295,6 +186827,21 @@ msgid "" "smoothed and the roof isn't quite filled in yet." msgstr "未完成的钢筋水泥结构,地板尚未整平,屋顶也还没盖严实。" +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "石地板" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "相对平坦的岩石区。看来稳定程度足堪采矿设备的开掘。" + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "金属地板" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -184302,6 +186849,10 @@ msgid "" " with a matching roof." msgstr "高品质的坚固花纹地板,可降低滑倒和摔倒的风险,配有相应的屋顶。" +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "噗通" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "地板" @@ -184344,6 +186895,10 @@ msgid "" "resistance and sliding, commonly for recreational sports." msgstr "经过化学材料防滑处理过的硬木地板,通常用于休闲运动场所。" +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "泥地板" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -184426,28 +186981,15 @@ msgid "A blue section of flooring." msgstr "一块蓝色地面。" #: lang/json/terrain_from_json.py -msgid "industrial carpet" -msgstr "工业地毯" - -#. ~ Description for industrial carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." -msgstr "坚固、低绒毛、高耐久性的中性灰色地毯,用于铺设在裸露的混凝土上。" +msgid "carpet" +msgstr "地毯" +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "bunker carpet" -msgstr "地堡地毯" +msgid "Base carpet!" +msgstr "基础地毯模板。" -#. ~ Description for bunker carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." -msgstr "坚固、低绒毛、完全不可燃的中性奶油色地毯,下面有绝缘层。" - -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "柔软的红色地毯。" @@ -184467,6 +187009,124 @@ msgstr "柔软的绿色地毯。" msgid "Soft purple carpet." msgstr "柔软的紫色地毯。" +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "地毯" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "基础地毯模板。" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "工业红地毯" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "坚固、低绒毛、高耐久性的红色地毯,用于铺设在裸露的混凝土上。" + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "工业黄地毯" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "坚固、低绒毛、高耐久性的黄色地毯,用于铺设在裸露的混凝土上。" + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "工业绿地毯" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "坚固、低绒毛、高耐久性的绿色地毯,用于铺设在裸露的混凝土上。" + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "工业紫地毯" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "坚固、低绒毛、高耐久性的紫色地毯,用于铺设在裸露的混凝土上。" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "基础地毯模板。" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "地堡红地毯" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "坚固、低绒毛、完全不可燃的红色地毯,下面有绝缘层。" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "地堡黄地毯" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "坚固、低绒毛、完全不可燃的黄色地毯,下面有绝缘层。" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "地堡绿地毯" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "坚固、低绒毛、完全不可燃的绿色地毯,下面有绝缘层。" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "地堡紫地毯" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "坚固、低绒毛、完全不可燃的紫色地毯,下面有绝缘层。" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "油毡地砖" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "用坚硬的橡胶材料制成的地板。涂上简单的白色。" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "用坚硬的、灰色的橡胶材料制成的地板。" + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "染色打蜡地板" @@ -184502,6 +187162,33 @@ msgid "" msgstr "" "一个由锈迹斑斑的废金属制成的简单的屋顶和地板,被螺栓和铁丝绑在一个简易框架上。在世界末日后的棚户区非常流行。希望你喜欢雨点打在褶皱金属板上的声音。" +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "泥土地" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "泥土地,看来土壤适合耕种。也可以开发建设项目。" + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "一大片优质细砂,如果开采得当,可以在很多方面发挥作用。" + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "泥地" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "一块泥泞湿滑的泥地。" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "苔藓" @@ -184511,6 +187198,30 @@ msgstr "苔藓" msgid "Moist spongy moss." msgstr "潮湿松软的苔藓。" +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "黏土" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "一块充满可塑性黏土的场地,如果开采得当,挺适用来烧窑。" + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "黏土堆" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "一堆黏土。" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "啪叽!" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "纸地板" @@ -184520,6 +187231,131 @@ msgstr "纸地板" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "一块由纤维物质制成的地板,上面覆盖了粘乎乎的黄蜂唾液。" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "沙堆" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "一堆沙子。" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "土堆" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "一块开好垄的泥土地,不容易穿行。仔细检查,可以发现它很适合种植。" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "一个大土丘,看起来可以爬进去当掩蔽。" + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "古怪的裂痕" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "一个不自然的人形洞,看上去有种奇怪的熟悉感觉。你觉得自己有种想要靠近仔细观察的冲动,仿佛它本来就和你是一体的一般。" + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "墓地" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "一个泥土坟墓,上面长着一些草。至少有些死者确实安息了。" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "一座新坟,用石头盖着既防止他人挖开又防止里面的东西挖出来。有两块木板标识着某人永恒安息之地。" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "路面" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr " 一段铺了柏油的路面,因为裂缝、冻胀和缺乏维护而逐渐老化。" + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "黄线路面" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "禁止司机跨越的双黄线。再也没有人来执行这些规则了。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "人行道" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "一段现浇混凝土路面。因为缺乏维护而毁于冻胀和大裂缝。" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "一种新式的水泥浇筑块,表面处理兼顾了美观与抗冻-融循环功能。" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "一种新式的水泥浇筑块,表面处理兼顾了美观与抗冻-融循环功能。外部涂上一层黄色的油漆。" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "木地板" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "木质楼板,由扎紧的木板钉牢而成。常见于露台。" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "高质量的坚固网纹地板,可以减小滑倒的风险。" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "由材质细腻的土壤夯实而成的泥土地板。" + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "核桃树" @@ -186167,7 +189003,7 @@ msgstr "一台用来给奶牛挤奶的机械。" #: lang/json/terrain_from_json.py msgid "bulk tank" -msgstr "储奶罐" +msgstr "大型储罐" #. ~ Description for bulk tank #: lang/json/terrain_from_json.py @@ -188308,6 +191144,78 @@ msgstr "往上的梯子。" msgid "A ladder leading down." msgstr "向下的梯子。" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "向下斜坡(顶部)" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "一段通往下层的铺了柏油的斜坡顶部。" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "向下斜坡(底部)" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "一段通往下层的铺了柏油的斜坡底部。" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "向上斜坡(顶部)" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "一段通往上层的铺了柏油的斜坡顶部。" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "向上斜坡(底部)" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "一段通往上层的铺了柏油的斜坡底部。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "向下人行道(顶部)" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "一段通往下层的人行道顶部。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "向下人行道(底部)" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "一段通往下层的人行道底部。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "向上人行道(顶部)" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "一段通往上层的人行道顶部。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "向上人行道(底部)" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "一段通往上层的人行道底部。" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "向下斜坡" @@ -188801,7 +191709,7 @@ msgstr "嘣!" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "砰!" @@ -190610,7 +193518,7 @@ msgstr "一块木板,可以把水挡在船外。" #. ~ Description for {'str': 'raft boat hull'} #: lang/json/vehicle_part_from_json.py msgid "Logs tied together that will keep your boat out of the water." -msgstr "" +msgstr "绑在一起的原木,可以把水挡在船外。" #. ~ Description for {'str': 'plastic boat hull'} #: lang/json/vehicle_part_from_json.py @@ -191051,7 +193959,7 @@ msgstr "一种重型牵引索。当一头连接至另一辆车后,可以拉动 #: lang/json/vehicle_part_from_json.py msgid "flimsy wooden seat" -msgstr "" +msgstr "薄木椅" #. ~ Description for {'str': 'flimsy wooden seat'} #. ~ Description for {'str': 'wooden seat'} @@ -191266,6 +194174,15 @@ msgid "" "extending the time until the food spoils." msgstr "一个60升容量的冷藏罐。开启时,冷却里面的液体,延缓腐烂。" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "一种带有孔的木片,适合自行车车轮使用。" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "木制轮架(可转向)" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "轻型轮架(可转向)" @@ -192102,8 +195019,9 @@ msgstr "你想打开门锁,结果不仅失败了,还损坏了你的工具。 msgid "The lock stumps your efforts to pick it." msgstr "你想打开门锁,结果失败了。" -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "不能在骑乘时这样做。" @@ -192166,6 +195084,120 @@ msgstr "继续尝试入睡。" msgid "Continue trying to fall asleep and don't ask again." msgstr "继续尝试入睡并不再提示。" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "你太累了,无法锻炼。" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "你太渴了,无法锻炼。" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "需要空出双手。" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "你无法用已经骨折的手锻炼。" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "你无法用已经骨折的腿锻炼。" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "你无法用已经骨折的肢体锻炼。" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "锻炼强度决定了锻炼效率,也决定了体力消耗速率。" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "选择锻炼强度:" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "轻度锻炼的强度与步行相近,但更集中而且更有计划。" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "适度" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "适度锻炼不会造成过度劳累,但强度已经足够让你汗流浃背。" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "积极" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "积极锻炼使全身充分参与锻炼。运动很剧烈,但仍然在你的可控范围内。" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "高强度锻炼竭尽全力进行充分锻炼。长期来看会让你精疲力竭。" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "锻炼多久(分钟):" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "你开始进行锻炼。" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "你太累了,所以你提前结束了锻炼。" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "你太渴了,所以你提前结束了锻炼。" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "自己气喘吁吁!" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "你停下来喘了一会气。" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "你重新开始锻炼。" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "你完成了锻炼。" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "你已经完成了你的锻炼周期,继续锻炼?" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "停止锻炼。" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "继续锻炼。" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "继续锻炼并不再提示。" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -192612,7 +195644,7 @@ msgstr "你无法呼吸,呼吸停止了。" #: src/activity_handlers.cpp msgid "You're too tired to continue." -msgstr "你太疲劳了以至于无法继续。" +msgstr "你太累了,无法继续。" #: src/activity_handlers.cpp src/vehicle_move.cpp src/vehicle_use.cpp #, c-format @@ -196712,6 +199744,29 @@ msgstr "%s(%i 个空位);" msgid "Increased storage capacity by %i." msgstr "能量储备上限增加 %i。" +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "选择节能能量阈值" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "能量全满" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "高于80%%" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "高于55%%" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "高于30%%" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "选择自启能量阈值" @@ -196877,8 +199932,9 @@ msgid "(incapacitated)" msgstr "(失效)" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" -msgstr "(节能模式)" +#, c-format +msgid "(fuel saving ON > %d %%)" +msgstr "(高于%d%%时节能)" #: src/bionics_ui.cpp #, c-format @@ -196951,7 +200007,7 @@ msgstr "命中" #: src/bonuses.cpp msgid "Critical Hit Chance" -msgstr "" +msgstr "暴击几率" #: src/bonuses.cpp src/martialarts.cpp msgid "Dodge" @@ -197561,6 +200617,23 @@ msgstr " 从网中挣脱出来!" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "你尝试从网中挣脱出来,但是失败了。" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "%s 挣脱了!" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "你挣脱了出来!" + +#: src/character.cpp +msgid " frees themselves!" +msgstr " 挣脱了出来!" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "你尝试挣脱,但是失败了。" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "你试图从深坑里头爬出来,但是又滑落进去了。" @@ -197874,11 +200947,11 @@ msgstr "错误!" #: src/character.cpp src/npctalk.cpp msgid "Exhausted" -msgstr "精疲力尽" +msgstr "精疲力竭" #: src/character.cpp msgid "Dead Tired" -msgstr "精疲力尽" +msgstr "疲惫不堪" #: src/character.cpp msgid "Pain " @@ -198413,6 +201486,10 @@ msgstr "海量运动" msgid "Your body strains under the weight!" msgstr "你的身体由于负重过高而感到疼痛!" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "你的生物特性与那件医疗用品不兼容。" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -202560,19 +205637,6 @@ msgstr "" "室内:%s\n" "屋顶:%s" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" -"可见:%d\n" -"回避:%d\n" -"难度:%d\n" -"无害:%s" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -203311,7 +206375,7 @@ msgstr "害虫" #: src/faction.cpp msgctxt "Faction respect" msgid "Despicable" -msgstr "卑劣" +msgstr "卑劣不堪" #: src/faction.cpp msgctxt "Faction respect" @@ -203321,7 +206385,7 @@ msgstr "寄生虫" #: src/faction.cpp msgctxt "Faction respect" msgid "Leech" -msgstr "水蛭" +msgstr "吸血鬼" #: src/faction.cpp msgctxt "Faction respect" @@ -203356,7 +206420,7 @@ msgstr "丰衣足食" #: src/faction.cpp msgctxt "Faction wealth" msgid "Comfortable" -msgstr "舒适" +msgstr "小康之家" #: src/faction.cpp msgctxt "Faction wealth" @@ -203406,22 +206470,22 @@ msgstr "饥肠辘辘" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Legendary" -msgstr "传奇" +msgstr "举世无双" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Expert" -msgstr "所向无敌" +msgstr "所向披靡" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Veteran" -msgstr "兵强将勇" +msgstr "精兵强将" #: src/faction.cpp msgctxt "Faction combat lvl" msgid "Skilled" -msgstr "兵强马壮" +msgstr "人强马壮" #: src/faction.cpp msgctxt "Faction combat lvl" @@ -205679,7 +208743,7 @@ msgstr "开启" #: src/game.cpp msgctxt "action" msgid "pocket autopickup settings" -msgstr "" +msgstr "口袋自动拾取设置" #: src/game.cpp msgctxt "action" @@ -206764,6 +209828,10 @@ msgstr "你没有可以装填的物品。" msgid "You aren't holding something you can reload." msgstr "你并未手持任何能够装填的物品。" +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "你得先把袋子收起来,然后再试着手持物品。" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -207208,7 +210276,7 @@ msgstr "%s挡住了你!" #: src/game.cpp #, c-format msgid "%s Attempt to push past? You may have to fight your way back up." -msgstr "" +msgstr "%s 真的要挤过去吗?你可能要杀出一条血路才能回来。" #: src/game.cpp msgid "" @@ -209313,6 +212381,10 @@ msgstr "已忽略被激光瞄准!" msgid "Creature whitelisted: %s" msgstr "怪物白名单:%s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "开始锻炼?" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "确认自杀?" @@ -210665,11 +213737,28 @@ msgstr "乱动这个 %s 看起来非常危险,最好别去碰它。" msgid "There is a %s there. Take down?" msgstr "那里有一个 %s。拿下来吗?" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "%s 被拆除。" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "那里有一个 %s。是否拆除?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "你成功解除了陷阱!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "你拆解陷阱失败。" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "你拆解陷阱失败,而且你把它触发了!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -211046,7 +214135,7 @@ msgstr "断肢夹板" #: src/iexamine.cpp msgid "Treat wounds" -msgstr "" +msgstr "治疗伤势" #: src/iexamine.cpp msgid "You don't have any bionics installed." @@ -211076,37 +214165,37 @@ msgstr " 的四肢完好,不需要夹板。" #: src/iexamine.cpp msgid "You don't have any wounds that need treatment." -msgstr "" +msgstr "你没有任何需要治疗的伤口。" #: src/iexamine.cpp msgid " doesn't have any wounds that need treatment." -msgstr "" +msgstr " 没有任何需要治疗的伤口。" #: src/iexamine.cpp msgid "" "The autodoc detected a bacterial infection in your body, but as it also " "detected you've already taken antibiotics, it decided not to apply another " "dose right now." -msgstr "" +msgstr "全自动医疗仪检测到了你体内的细菌感染,但是由于它也检测到你已经服用了抗生素,所以它决定现在不再使用第二份抗生素。" #: src/iexamine.cpp msgid "" "The autodoc detected a bacterial infection in 's body, but as it " "also detected you've already taken antibiotics, it decided not to apply " "another dose right now." -msgstr "" +msgstr "全自动医疗仪检测到了 体内的细菌感染,但是由于它也检测到已经服用了抗生素,所以它决定现在不再使用第二份抗生素。" #: src/iexamine.cpp msgid "" "The autodoc detected a bacterial infection in your body and injected " "antibiotics to treat it." -msgstr "" +msgstr "全自动医疗仪检测到了你体内的细菌感染,并注射抗生素来治疗它。" #: src/iexamine.cpp msgid "" "The autodoc detected a bacterial infection in 's body and injected " "antibiotics to treat it." -msgstr "" +msgstr "全自动医疗仪检测到了 体内的细菌感染,并注射抗生素来治疗它。" #: src/iexamine.cpp src/iuse.cpp msgid "The muscle spasms start to go away." @@ -211121,28 +214210,28 @@ msgstr "药物无法缓解当前的痉挛症状。" msgid "" "The autodoc detected a bleeding on your %s and applied a hemostatic drug to " "stop it." -msgstr "" +msgstr "全自动医疗仪检测到了你的 %s 出血,并注射止血药物来阻止流血。" #: src/iexamine.cpp #, c-format msgid "" "The autodoc detected a bleeding on 's %s and applied a hemostatic " "drug to stop it." -msgstr "" +msgstr "全自动医疗仪检测到了 的 %s 出血,并注射止血药物来阻止流血。" #: src/iexamine.cpp #, c-format msgid "" "The autodoc detected an open wound on your %s and applied a disinfectant to " "clean it." -msgstr "" +msgstr "全自动医疗仪检测到了你的 %s 的开放性伤口,并使用消毒剂来清洗它。" #: src/iexamine.cpp #, c-format msgid "" "The autodoc detected an open wound on 's %s and applied a " "disinfectant to clean it." -msgstr "" +msgstr "全自动医疗仪检测到了 的 %s 的开放性伤口,并使用消毒剂来清洗它。" #: src/iexamine.cpp #, c-format @@ -211539,6 +214628,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr " 不知道 %s 的配方,无法继续制造。" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "使用 %s 锻炼?" + #: src/init.cpp msgid "Finalizing" msgstr "完成" @@ -212545,7 +215639,7 @@ msgid "" "very bad idea." msgstr "* 这份食物已经开始腐坏吃下它是个坏主意。" -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -213253,31 +216347,31 @@ msgstr "* 这件工具使用 生化能量。" #: src/item.cpp msgid "It's new, and ready to burn." -msgstr "" +msgstr "它是全新的,可以拿来烧了。" #: src/item.cpp msgid "Almost new, with much material to burn." -msgstr "" +msgstr "它几乎是全新的,还有很多材料可以烧。" #: src/item.cpp msgid "More than a quarter has burned away." -msgstr "" +msgstr "它已经烧掉了约四分之一。" #: src/item.cpp msgid "More than half has burned away." -msgstr "" +msgstr "它已经烧掉了约一半。" #: src/item.cpp msgid "Less than a quarter left to burn." -msgstr "" +msgstr "它已经烧掉了约四分之三。" #: src/item.cpp msgid "Almost completely burned out." -msgstr "" +msgstr "它几乎快烧光了。" #: src/item.cpp msgid "Fuel: " -msgstr "" +msgstr "燃料:" #: src/item.cpp #, c-format @@ -213306,7 +216400,7 @@ msgstr "* 这件物品 无法修理。" #: src/item.cpp #, c-format msgid "Disassembly takes %1$s and might yield: %2$s." -msgstr "" +msgstr "拆解 需要 %1$s 可获得:%2$s。" #. ~ 1 is approx. time, 2 is a list of items and tools with qualities, 3 is a #. list of items. @@ -213317,7 +216411,7 @@ msgstr "" msgid "" "Disassembly takes %1$s, requires %2$s and might " "yield: %3$s." -msgstr "" +msgstr "拆解 需要 %1$s 及 %2$s 可获得:%3$s" #: src/item.cpp #, c-format @@ -214156,57 +217250,63 @@ msgstr "执行哪个行动?" #: src/item_contents.cpp #, c-format msgid "Press a key to add to %s" -msgstr "" +msgstr "按键添加至%s" #: src/item_contents.cpp msgid "blacklist" -msgstr "" +msgstr "黑名单" #: src/item_contents.cpp msgid "whitelist" -msgstr "" +msgstr "白名单" #: src/item_contents.cpp msgid " priority, " -msgstr "" +msgstr "优先级," #: src/item_contents.cpp msgid " item, " -msgstr "" +msgstr "物品," #: src/item_contents.cpp msgid " category, " -msgstr "" +msgstr "类别," #: src/item_contents.cpp msgid " whitelist, " -msgstr "" +msgstr "白名单," #: src/item_contents.cpp msgid " blacklist" -msgstr "" +msgstr "黑名单" #: src/item_contents.cpp #, c-format msgid "Enter Priority (current priority %d)" -msgstr "" +msgstr "输入优先级(当前优先级 %d)" #: src/item_contents.cpp msgid "item id" -msgstr "" +msgstr "物品ID" #: src/item_contents.cpp msgid "item category" -msgstr "" +msgstr "物品类别" #: src/item_contents.cpp msgid "Select an item from nearby" -msgstr "" +msgstr "选择附近的物品" #: src/item_contents.cpp msgid "is not a container" msgstr "不是容器" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "口袋不可用因为 %s" + #: src/item_contents.cpp msgid "is not rigid" msgstr "不够坚硬" @@ -214270,6 +217370,10 @@ msgstr "开启" msgid "Pocket %d:" msgstr "口袋 %d:" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "可容纳:" + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "最大物品长度:" @@ -214432,31 +217536,31 @@ msgstr "可用容量不足" #: src/item_pocket.cpp msgid "Priority:" -msgstr "" +msgstr "优先级:" #: src/item_pocket.cpp #, c-format msgid "Item Whitelist: %s" -msgstr "" +msgstr "物品白名单:%s" #: src/item_pocket.cpp msgid "(empty)" -msgstr "" +msgstr "(空)" #: src/item_pocket.cpp #, c-format msgid "Item Blacklist: %s" -msgstr "" +msgstr "物品黑名单:%s" #: src/item_pocket.cpp #, c-format msgid "Category Whitelist: %s" -msgstr "" +msgstr "类别白名单:%s" #: src/item_pocket.cpp #, c-format msgid "Category Blacklist: %s" -msgstr "" +msgstr "类别黑名单:%s" #: src/itype.h msgid "click." @@ -216053,10 +219157,6 @@ msgstr "贪吃蛇" msgid "Sokoban" msgstr "推箱子" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "扫雷" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "灯全都亮了!" @@ -218939,7 +222039,7 @@ msgstr "%s 需要靠近 %s 使用。" msgid "You can't place a %s there. It contains a trap already." msgstr "你无法将%s放在那里。那儿已经有一个陷阱了。" -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "你触发了一个 %s!" @@ -220696,6 +223796,15 @@ msgstr "生成" msgid "Summon" msgstr "召唤" +#: src/magic.cpp +msgid "random creature" +msgstr "随机生物" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "将生命值低于 %d 的目标变形为:%s" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "有效距离" @@ -220716,6 +223825,10 @@ msgstr "有效范围" msgid "Spawned" msgstr "召唤数量" +#: src/magic.cpp +msgid "Threshold" +msgstr "变形阈值" + #: src/magic.cpp msgid "Recover" msgstr "能量恢复" @@ -220768,6 +223881,15 @@ msgstr "你的伤口被平均分配到各个身体部位。" msgid "%s wounds are closing up!" msgstr "%s 的伤口开始愈合了!" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "%s 被变形成 %s。" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "你的目标抵抗了变形效果。" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "那里已有其他载具了。" @@ -221225,30 +224347,23 @@ msgstr "%s的高压灭菌釜已经完成了灭菌程序。" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "%s 被拆除。" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "你成功解除了陷阱!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "你拆解陷阱失败。" +msgid "Something has crawled out of the %s plants!" +msgstr "从 %s 丛里爬出了一些东西!" #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "你拆解陷阱失败,而且你把它触发了!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "从 %s 里爬出了一些东西!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "从 %s 丛里爬出了一些东西!" +msgid "You've spotted a %1$ss!" +msgstr "你发现了一个 %1$s!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "从 %s 里爬出了一些东西!" +msgid " triggers a %s!" +msgstr " 触发了一个 %s!" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -222789,6 +225904,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "被警察通缉了!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "折断了 %s。" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "折断了 %s。" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -226639,6 +229767,11 @@ msgstr "\"侦测到来自未知攻击者的射击,反击模式已启动。\"" msgid "zombie slave" msgstr "丧尸奴仆" +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "推开 %s" + #: src/monexamine.cpp msgid "Rename" msgstr "重命名" @@ -229643,7 +232776,7 @@ msgstr "感 %d - %d" #: src/npctalk.cpp msgid "Dead tired" -msgstr "精疲力尽" +msgstr "疲惫不堪" #: src/npctalk.cpp msgid "Not tired" @@ -230355,11 +233488,11 @@ msgstr "捣碎附近" #: src/options.cpp msgid "Pulp Adjacent Zombie Only" -msgstr "" +msgstr "捣碎附近丧尸" #: src/options.cpp msgid "Pulp Zombies Only" -msgstr "" +msgstr "捣碎丧尸" #: src/options.cpp msgid "Auto mining" @@ -231878,17 +235011,6 @@ msgstr "辐射诱发变异" msgid "If true, radiation causes the player to mutate." msgstr "开启后,辐射将会导致玩家变异。" -#: src/options.cpp -msgid "Z-levels" -msgstr "Z轴" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "开启时,将启用数个竖直移动功能,包括搬运物品上下楼,攀爬落水管以及操纵飞行器。若在创建游戏后开启可能导致Bug。" - #: src/options.cpp msgid "Character point pools" msgstr "角色点数池" @@ -235702,7 +238824,7 @@ msgstr[0] "%1$d 个 %2$s 功能至少 %3$d 级的工具。" #, c-format msgid "%1$d tool with %2$s of %3$d or more" msgid_plural "%1$d tools with %2$s of %3$d or more" -msgstr[0] "" +msgstr[0] "%1$d 个 %2$s 功能至少 %3$d 级 的工具" #. ~ %1$s: tool name, %2$d: charge requirement #: src/requirements.cpp @@ -236083,12 +239205,12 @@ msgstr "你营养不良,无法保持你的 %s 继续运行。" #: src/suffer.cpp #, c-format msgid "You're too dehydrated to keep your %s going." -msgstr "你脱水严重,无法保持你的 %s 继续运行。" +msgstr "你太渴了,无法保持你的 %s 继续运行。" #: src/suffer.cpp #, c-format msgid "You're too exhausted to keep your %s going." -msgstr "你筋疲力尽,无法保持你的 %s 继续运行。" +msgstr "你太累了,无法保持你的 %s 继续运行。" #: src/suffer.cpp msgid "You're drowning!" @@ -236382,7 +239504,7 @@ msgstr " 伸了伸懒腰。" #: src/suffer.cpp msgid "You feel mentally tired." -msgstr "你觉得精神很疲倦。" +msgstr "你觉得头脑有点累。" #: src/suffer.cpp msgid " lets out a huge yawn." @@ -236583,6 +239705,19 @@ msgctxt "grammatical gender list" msgid "n" msgstr "n" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" +"可见:%d\n" +"回避:%d\n" +"难度:%d\n" +"无害:%s" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "你踩到了一些气泡袋!" @@ -239750,7 +242885,7 @@ msgstr "--无有效模组--" #: src/worldfactory.cpp msgid "--NO RESULTS FOUND--" -msgstr "" +msgstr "--未找到结果--" #: src/worldfactory.cpp msgid "Saved list of active mods as default" diff --git a/lang/po/zh_TW.po b/lang/po/zh_TW.po index 1f7ce57770883..24e01c7440529 100644 --- a/lang/po/zh_TW.po +++ b/lang/po/zh_TW.po @@ -19,17 +19,17 @@ # Jeremy Wu , 2020 # Hao JK , 2020 # kiddragon Chung , 2020 -# Laughing Man, 2020 -# xap, 2020 # Brett Dong , 2020 # Hsinyu Chan, 2020 +# Laughing Man, 2020 +# xap, 2020 # Yangerine Yuan , 2020 # msgid "" msgstr "" "Project-Id-Version: cataclysm-dda 0.E\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-23 10:06+0800\n" +"POT-Creation-Date: 2020-07-08 10:07+0800\n" "PO-Revision-Date: 2018-04-26 14:47+0000\n" "Last-Translator: Yangerine Yuan , 2020\n" "Language-Team: Chinese (Taiwan) (https://www.transifex.com/cataclysm-dda-translators/teams/2217/zh_TW/)\n" @@ -792,6 +792,16 @@ msgstr[0] "高氧" msgid "Mixture of oxygen and nitrogen in proportions suitable for diving." msgstr "氧氣和氮氣以特定比例混和,用於潛水。" +#: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py +msgid "extinguishing agent" +msgid_plural "extinguishing agent" +msgstr[0] "" + +#. ~ Description for {'str_sp': 'extinguishing agent'} +#: lang/json/AMMO_from_json.py +msgid "Dry chemical solution effective in extinguishing fires." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "tinder" msgid_plural "tinder" @@ -3967,6 +3977,23 @@ msgid "" "with some kind of mask or mouth protection." msgstr "用於化學藥劑噴灑器的強力噴灑式殺蟲劑彈藥。使用時最好能戴上面部的護具。" +#: lang/json/AMMO_from_json.py +msgid "12.3ln round" +msgid_plural "12.3ln rounds" +msgstr[0] "" + +#. ~ Description for {'str': '12.3ln round'} +#: lang/json/AMMO_from_json.py +msgid "" +"The 12.3ln cartridge was introduced in Romania in the wake of the second " +"Carpathian conflict. The PA md. 71 rifle using this ammunition rapidly " +"gained popularity in the Eastern Union, and from there, the world. Due to " +"this, the 12.3ln rapidly became the standard combat round in the Eurasian " +"sphere. It was easily scavenged and stockpiled by the Exodii. To you, it " +"looks and feels quite similar to a .30-06 Springfield cartridge, but with a " +"slightly sharper taper." +msgstr "" + #: lang/json/AMMO_from_json.py lang/json/ammunition_type_from_json.py msgid "paper cartridge" msgid_plural "paper cartridges" @@ -4928,7 +4955,7 @@ msgstr[0] "黃色油漆" msgid "A can of yellow paint." msgstr "一罐黃色油漆。" -#: lang/json/AMMO_from_json.py lang/json/terrain_from_json.py +#: lang/json/AMMO_from_json.py msgid "red carpet" msgid_plural "red carpets" msgstr[0] "" @@ -6842,8 +6869,8 @@ msgstr[0] "彈藥小袋" #: lang/json/ARMOR_from_json.py msgid "" "A small pouch that can be used to store most types of small ammunition, " -"rockets will not fit. Activate to store ammunition." -msgstr "一個可以用來存放大部分類型小型彈藥的小袋子,火箭是放不進去的。使用它來存取彈藥。" +"rockets will not fit. Use insert to store ammunition." +msgstr "" #: lang/json/ARMOR_from_json.py msgid "ammo satchel" @@ -6933,9 +6960,9 @@ msgstr[0] "箭筒" #. ~ Description for {'str': 'quiver'} #: lang/json/ARMOR_from_json.py msgid "" -"A leather quiver worn at the waist that can hold 20 arrows. Activate to " -"store arrows." -msgstr "一個以皮革製成的箭筒, 穿戴在腰間, 能夠裝入 20 支箭矢。使用它來裝入箭矢。" +"A leather quiver worn at the waist that can hold 20 arrows or bolts. Use " +"insert to store arrows or bolts." +msgstr "" #: lang/json/ARMOR_from_json.py msgid "birchbark quiver" @@ -6946,8 +6973,8 @@ msgstr[0] "樺皮箭筒" #: lang/json/ARMOR_from_json.py msgid "" "A quiver woven from strips of birch bark, worn at the waist, that can hold " -"20 arrows. Activate to store arrows." -msgstr "一個以樺樹皮製成的箭筒, 穿戴在腰際, 能裝入 20 支箭矢。使用它來裝入箭矢。" +"20 arrows or bolts. Use insert to store arrows or bolts." +msgstr "" #: lang/json/ARMOR_from_json.py msgid "large quiver" @@ -6958,11 +6985,10 @@ msgstr[0] "大型箭筒" #: lang/json/ARMOR_from_json.py msgid "" "A large leather quiver trimmed with metal, worn on the back, that can hold " -"60 arrows. Historically used by horse archers, rather than foot archers, " -"but neither of THEM had to fight zombies. Activate to store arrows." +"60 arrows or bolts. Historically used by horse archers, rather than foot " +"archers, but neither of THEM had to fight zombies. Use insert to store " +"arrows or bolts." msgstr "" -"一個鑲嵌了金屬的大型皮革箭筒, 穿戴在背後, 能夠裝入 60 支箭矢。歷史上是供馬弓兵使用, 而非步行的弓兵, 但這兩者都不用對抗殭屍。\"使用\" " -"它來裝入箭矢。" #: lang/json/ARMOR_from_json.py msgid "large birchbark quiver" @@ -6973,8 +6999,8 @@ msgstr[0] "大型樺皮箭筒" #: lang/json/ARMOR_from_json.py msgid "" "A large quiver woven from strips of birchbark, worn on the back, that can " -"hold 60 arrows. Activate to store arrows." -msgstr "一個以樺樹皮製成的箭筒, 穿戴在背後, 能夠裝入 60 支箭矢。使用它來裝入箭矢。" +"hold 60 arrows or bolts. Use insert to store arrows or bolts." +msgstr "" #: lang/json/ARMOR_from_json.py msgid "tac vest" @@ -16342,10 +16368,10 @@ msgstr "一個巨大的有輪子的行李箱, 主要用於運送旅行期間的 #. ~ Description for {'str': 'suitcase'} #: lang/json/ARMOR_from_json.py msgid "" -"A mid-sized suitcase used mainly for transporting clothes and other " +"A mid-sized wheeled suitcase used mainly for transporting clothes and other " "possessions during trips, provides a decent amount of storage but hauling it" " around is not exactly comfortable." -msgstr "一個中型的旅行箱, 主要用於運送旅行期間的衣服或其他財物, 能提供不錯的儲物空間, 但拖著它走並不是很舒服。" +msgstr "" #: lang/json/ARMOR_from_json.py msgid "survivor duffel bag" @@ -22405,7 +22431,7 @@ msgid "" "This cookbook is written by liver enthusiast Tamsyn Beckerleg. Inside " "you'll find a great deal of anecdotes about the near-certain ruination of " "children who refuse to eat their liver." -msgstr "" +msgstr "這本烹飪書是由肝臟愛好家 Tamsyn Beckerleg 所著。充滿著挑食不吃自己肝臟的小孩們近乎崩潰的逸事。" #: lang/json/BOOK_from_json.py msgid "Dainty Dishes Fit for a King" @@ -22419,7 +22445,7 @@ msgid "" "This cookbook contains many fanciful recipes. Some of them are even worth " "the trouble to actually prepare. Lovely pen and ink illustrations of " "overweight knights and gluttonous monks line the pages." -msgstr "" +msgstr "這本烹飪書裡有許多如夢似幻的食譜。其中有些甚至值得冒風險去煮。書頁中充滿優美的筆墨描繪著過重的騎士和貪吃的僧侶。" #: lang/json/BOOK_from_json.py msgid "Eat Your Way to a Fit Physique" @@ -22432,7 +22458,7 @@ msgstr[0] "" msgid "" "This self-help book is as dubious as its title. Worse, it is boring. It " "does, however, contain a few basic cooking instructions." -msgstr "" +msgstr "這本自助烹飪書就和他的名字一樣可疑。更糟的是,他讀起來很無聊。不過,它仍有些基礎的烹飪技巧。" #: lang/json/BOOK_from_json.py msgid "Food Fashions for Young Moderns" @@ -22447,7 +22473,7 @@ msgid "" "sophisticated flavors.\" The book exhorts the reader to defy convention and" " break the rules, and then presents a number of useful rules and conventions" " for preparing food." -msgstr "" +msgstr "一本烹飪書宣稱是給那些尋求「大膽且複雜口味」的人。這本書鼓勵讀者拋下成見和打破規則,後半部寫著一些對烹飪很有用的技巧和觀念。" #: lang/json/BOOK_from_json.py msgid "Winemaking for Beginners" @@ -23157,7 +23183,7 @@ msgid "" "Everything you could ever want to know about handloading ammunition, sealed " "with a… childproof cover. Apparently a liability thing, because the chapter" " on explosive rounds covers them in excellent detail too." -msgstr "" +msgstr "裡面有關於手工裝配子彈的所有知識, 封面有著… 18 禁的標誌。顯然這是必要的, 因為裡面有個章節詳細講述了高爆子彈。" #: lang/json/BOOK_from_json.py msgid "Rivtech design binder" @@ -23326,7 +23352,7 @@ msgstr[0] "" msgid "" "A paperback book detailing 101 home repair projects for the novice " "carpenter." -msgstr "" +msgstr "一本平裝書, 詳細介紹了新手進行居家修繕的方法。" #: lang/json/BOOK_from_json.py msgid "The Complete Home Repair Guide" @@ -23391,6 +23417,7 @@ msgid "" "additive manufacturing. If you need to know how best complete a certain " "machining operation, the answer lies somewhere in these pages." msgstr "" +"這本經典的參考書包含有關材料,計量,工具製造,齒輪,螺紋等的大量而密集的章節和表格。最新版本包含有關添加劑製造的最新技術的大量數據。如果你需要知道如何最好地完成某個加工操作,答案就在這些頁面的某處。" #: lang/json/BOOK_from_json.py msgid "Concrete Constructions" @@ -28003,6 +28030,18 @@ msgid "" "your pain at bay." msgstr "" +#: lang/json/BOOK_from_json.py +msgid "Scroll of Baleful Polymorph" +msgid_plural "Scrolls of Baleful Polymorph" +msgstr[0] "" + +#. ~ Description for {'str': 'Scroll of Baleful Polymorph', 'str_pl': 'Scrolls +#. of Baleful Polymorph'} +#. ~ Description for Baleful Polymorph +#: lang/json/BOOK_from_json.py lang/json/SPELL_from_json.py +msgid "Transform your enemies into frogs." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Scroll of Summon Zombie" msgid_plural "Scrolls of Summon Zombie" @@ -29506,6 +29545,19 @@ msgid "" "on combining magic with EM radiation." msgstr "這本實驗室參考資料書很厚,內含關於魔法與電磁輻射相結合的大量資訊。" +#: lang/json/BOOK_from_json.py +msgid "Runic Tablet shard" +msgid_plural "Runic Tablet shards" +msgstr[0] "" + +#. ~ Description for {'str': 'Runic Tablet shard'} +#: lang/json/BOOK_from_json.py +msgid "" +"A small tablet of blackened stone, apparently cut from a much larger slab. " +"Golden runes glow over its surface, and slowly shift into intelligible " +"sentences when you stare at them." +msgstr "" + #: lang/json/BOOK_from_json.py msgid "Geospatial Systems: The Lie Of Linearity" msgid_plural "copies of Geospatial Systems: The Lie Of Linearity" @@ -34431,6 +34483,30 @@ msgid "" "cheese. Delicious." msgstr "用墨西哥玉米餅製成的鹽漬玉米片, 搭配了奶酪與肉。真美味。" +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos" +msgid_plural "vegetarian nachoss" +msgstr[0] "" + +#. ~ Description for vegetarian nachos +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas, now with beans. Could probably use " +"some cheese, though." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "vegetarian nachos with cheese" +msgid_plural "vegetarian nachos with cheeses" +msgstr[0] "" + +#. ~ Description for vegetarian nachos with cheese +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Salted chips made from corn tortillas with beans and smothered in cheese. " +"Delicious, even if you're not a vegetarian." +msgstr "" + #: lang/json/COMESTIBLE_from_json.py msgid "pork stick" msgid_plural "pork sticks" @@ -36078,7 +36154,7 @@ msgid "" "Dilute hydrogen peroxide, for use as an antiseptic and for bleaching hair or" " textiles. Foams a little when in contact with organic matter, but " "otherwise harmless." -msgstr "" +msgstr "一瓶稀釋的雙氧水, 用於殺菌或者漂白頭髮和紡織品。接觸到有機物時會起泡, 除此之外是無害的。" #: lang/json/COMESTIBLE_from_json.py lang/json/GENERIC_from_json.py msgid "cigarette" @@ -36827,7 +36903,7 @@ msgstr[0] "" msgid "" "Some essential oil made from thyme, which can act as a mildly irritating " "antiseptic." -msgstr "" +msgstr "從麝香草中提取出來的油, 它可以作為有輕微刺激的消毒劑。" #: lang/json/COMESTIBLE_from_json.py msgid "rolling tobacco" @@ -37025,7 +37101,7 @@ msgstr[0] "" msgid "" "A rag soaked in antiseptic. Useful for light wounds, probably won't help " "with deep bites." -msgstr "" +msgstr "一條浸泡過消毒劑的布條。對小傷口有幫助,對被咬得很深的傷口沒用。" #: lang/json/COMESTIBLE_from_json.py msgid "antiseptic soaked cotton balls" @@ -38844,24 +38920,52 @@ msgid "" msgstr "給鳥類吃的東西。主要由種子,青貯飼料或豆類製成。它非常適合小型鳥。" #: lang/json/COMESTIBLE_from_json.py -msgid "dog food" -msgid_plural "dog food" -msgstr[0] "狗食" +msgid "wet dog food" +msgid_plural "wet dog food" +msgstr[0] "" + +#. ~ Description for {'str_sp': 'wet dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"This is wet food for dogs, made from canned fresh meats. It smells strange," +" but dogs seem to love it." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry dog food" +msgid_plural "dry dog food" +msgstr[0] "" + +#. ~ Description for {'str_sp': 'dry dog food'} +#: lang/json/COMESTIBLE_from_json.py +msgid "" +"Dry morsels of dog food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" -#. ~ Description for {'str_sp': 'dog food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for dogs. It smells strange, but dogs seem to love it." -msgstr "這是狗的食物。它聞起來很怪, 但是狗很喜歡。" +msgid "wet cat food" +msgid_plural "wet cat food" +msgstr[0] "" +#. ~ Description for {'str_sp': 'wet cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "cat food" -msgid_plural "cat food" -msgstr[0] "貓食" +msgid "" +"This is wet food for cats, made from canned fresh meats. It has a pungent " +"aroma that cats seem to love." +msgstr "" + +#: lang/json/COMESTIBLE_from_json.py +msgid "dry cat food" +msgid_plural "dry cat food" +msgstr[0] "" -#. ~ Description for {'str_sp': 'cat food'} +#. ~ Description for {'str_sp': 'dry cat food'} #: lang/json/COMESTIBLE_from_json.py -msgid "This is food for cats. It smells strange, but cats seem to love it." -msgstr "這是貓的食物。它聞起來很怪, 但是貓很喜歡。" +msgid "" +"Dry kibbles of cat food with a long shelf life. Made from dried processed " +"meats and grains, and enriched with vitamins and minerals." +msgstr "" #: lang/json/COMESTIBLE_from_json.py lang/json/terrain_from_json.py msgid "grass" @@ -45048,6 +45152,32 @@ msgid "" "Felt patches, bundled tightly together for storage. Disassemble to unpack." msgstr "將大量的毛氈補丁緊緊地捆成一束, 以便於存放。可拆解回原來的大量毛氈補丁。" +#: lang/json/GENERIC_from_json.py +msgid "bundle of planks" +msgid_plural "bundles of planks" +msgstr[0] "" + +#. ~ Description for {'str': 'bundle of planks', 'str_pl': 'bundles of +#. planks'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten construction planks securely lashed together with a rope. Disassemble " +"to unpack." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "bundle of stout branches" +msgid_plural "bundles of stout branches" +msgstr[0] "" + +#. ~ Description for {'str': 'bundle of stout branches', 'str_pl': 'bundles of +#. stout branches'} +#: lang/json/GENERIC_from_json.py +msgid "" +"Ten stout branches securely lashed together with a rope. Disassemble to " +"untie them." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "t-substrate sample" msgid_plural "t-substrate samples" @@ -48932,6 +49062,54 @@ msgid "" "wound." msgstr "一具半斬首的屍體。目前尚不清楚是什麼原因造成了這種傷口。" +#: lang/json/GENERIC_from_json.py +msgid "broken exodii worker" +msgid_plural "broken exodii workers" +msgstr[0] "" + +#. ~ Description for broken exodii worker +#: lang/json/GENERIC_from_json.py +msgid "A broken exodii worker. It's possible it could be gutted for parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii quadruped" +msgid_plural "broken exodii quadrupeds" +msgstr[0] "" + +#. ~ Description for broken exodii quadruped +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii walker. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii turret" +msgid_plural "broken exodii turrets" +msgstr[0] "" + +#. ~ Description for broken exodii turret +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken exodii turret. Still looks intimidating despite being permanently " +"inoperative, possibly due to the sheer size and mass. Could be gutted for " +"parts." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "broken exodii balloon-drone" +msgid_plural "broken exodii balloon-drones" +msgstr[0] "" + +#. ~ Description for broken exodii balloon-drone +#: lang/json/GENERIC_from_json.py +msgid "" +"A broken balloon drone. The balloon has been shredded, but most of the " +"chassis is still intact. Could be gutted for parts." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "ammo belt linkage" msgid_plural "ammo belt linkages" @@ -50601,7 +50779,7 @@ msgstr[0] "" #: lang/json/GENERIC_from_json.py msgid "" "A typical microphone used to record or amplify voice. Comes with a clip. " -"Has a 3-pin XLR connector on the bottom in order to connect to am amp." +"Has a 3-pin XLR connector on the bottom in order to connect to an amp." msgstr "" #: lang/json/GENERIC_from_json.py @@ -50771,6 +50949,19 @@ msgid "" "anything on its own." msgstr "" +#: lang/json/GENERIC_from_json.py +msgid "set of pipe fittings" +msgid_plural "sets of pipe fittings" +msgstr[0] "" + +#. ~ Description for {'str': 'set of pipe fittings', 'str_pl': 'sets of pipe +#. fittings'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A loose assortment of metal pipe fittings - end caps, pipe junctions, and " +"similar items. They can be used in a variety of projects." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "short cordage piece" msgid_plural "short cordage pieces" @@ -52514,6 +52705,103 @@ msgid "" "somewhat warm to the touch." msgstr "這是外星樹脂的碎片。它看起來有點像一塊大的海玻璃,結霜而堅韌,邊緣變圓。摸起來竟有點溫暖。" +#: lang/json/GENERIC_from_json.py +msgid "Exodii chassis" +msgid_plural "Exodii chassis" +msgstr[0] "" + +#. ~ Description for {'str_sp': 'Exodii chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This roughly hexagonal frame and associated bodywork looks like it was " +"constructed as a single monolithic piece. The fitting holes and attachments" +" are extremely durable, despite showing signs of heavy wear and repair. The" +" structure is versatile, and could probably be engineered to serve a number " +"of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "Exodii drone chassis" +msgid_plural "Exodii drone chassis" +msgstr[0] "" + +#. ~ Description for {'str_sp': 'Exodii drone chassis'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This small, roughly hexagonal frame and associated bodywork looks like it " +"was constructed as a single monolithic piece. The fitting holes and " +"attachments are extremely durable, despite showing signs of heavy wear and " +"repair. The structure is versatile, and could probably be engineered to " +"serve a number of different heavy combat roles." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic neural matrix" +msgid_plural "cybernetic neural matrices" +msgstr[0] "" + +#. ~ Description for {'str': 'cybernetic neural matrix', 'str_pl': 'cybernetic +#. neural matrices'} +#: lang/json/GENERIC_from_json.py +msgid "" +"A series of tanks and tubes with ports for fluids, electricity, and input " +"and output, this complex arrangement is made to house a brain and spine and " +"the most difficult to replace organs for keeping them alive." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "unfamiliar electronic thingy" +msgid_plural "unfamiliar electronic thingys" +msgstr[0] "" + +#. ~ Description for {'str': 'unfamiliar electronic thingy'} +#: lang/json/GENERIC_from_json.py +msgid "" +"The wiring and general shape suggest to you that this is a computer, or at " +"least some sort of electronic device, but what it is and what role it serves" +" is lost on you. It's heavy and sturdy in construction." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "inscribed metal plates" +msgid_plural "inscribed metal platess" +msgstr[0] "" + +#. ~ Description for {'str': 'inscribed metal plates'} +#: lang/json/GENERIC_from_json.py +msgid "" +"This device looks electronic, but is unfamiliar. It is a series of tightly " +"fitted coppery-looking rings, set concentrically. Wires run from each ring " +"to an axis in the middle." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "cybernetic sensor" +msgid_plural "cybernetic sensors" +msgstr[0] "" + +#. ~ Description for {'str': 'cybernetic sensor'} +#: lang/json/GENERIC_from_json.py +msgid "" +"From the large glassy eye - the size of a small dinner plate - in the front," +" you deduce this is some sort of camera. None of the inner workings make " +"any sense to you nor resemble any camera you've seen before." +msgstr "" + +#: lang/json/GENERIC_from_json.py +msgid "rotary device" +msgid_plural "rotary devices" +msgstr[0] "" + +#. ~ Description for {'str': 'rotary device'} +#: lang/json/GENERIC_from_json.py +msgid "" +"You assume from the coils of coppery wire and the protruding piston that " +"this is some sort of motor or generator, but the design doesn't look similar" +" to anything you've seen before, and you can't figure out how to get it to " +"work." +msgstr "" + #: lang/json/GENERIC_from_json.py msgid "sheet of glass" msgid_plural "sheets of glass" @@ -55476,6 +55764,16 @@ msgstr[0] "水龍頭" msgid "A metal faucet that can be attached to a water tank for easy access." msgstr "一個金屬的水龍頭, 可以連接到水箱上以便取水。" +#: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount" +msgid_plural "wooden wheel mounts" +msgstr[0] "" + +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/GENERIC_from_json.py +msgid "A piece of wood with holes suitable for a bike wheel." +msgstr "" + #: lang/json/GENERIC_from_json.py lang/json/vehicle_part_from_json.py msgid "light wheel mount" msgid_plural "light wheel mounts" @@ -60824,6 +61122,32 @@ msgid "" "thrower." msgstr "粗製的加壓 2公升鋼瓶,設計用於粗製化學藥劑噴灑器供料。" +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 71 Exodii 12.3ln magazine" +msgid_plural "PA Md. 71 Exodii 12.3ln magazines" +msgstr[0] "" + +#. ~ Description for {'str': 'PA Md. 71 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"A small, sleek magazine based on a classic PA Md. 71 clip, with some " +"redesigns by the Exodii for better use in lighter-than-air drones. Its " +"small size is less appropriate for ground-fighting of hordes of zombies, as " +"it is a bit inconvenient to reload." +msgstr "" + +#: lang/json/MAGAZINE_from_json.py +msgid "PA Md. 68 Exodii 12.3ln magazine" +msgid_plural "PA Md. 68 Exodii 12.3ln magazines" +msgstr[0] "" + +#. ~ Description for {'str': 'PA Md. 68 Exodii 12.3ln magazine'} +#: lang/json/MAGAZINE_from_json.py +msgid "" +"An unreasonably large magazine for the already heavy PA Md. 68 battle rifle," +" custom designed and manufactured by the Exodii." +msgstr "" + #: lang/json/MAGAZINE_from_json.py msgid "pressurized fuel tank" msgid_plural "pressurized fuel tanks" @@ -61797,6 +62121,46 @@ msgid "" "able to give them back some humanity. If only they cared…" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Exodii worker" +msgid_plural "Exodii workers" +msgstr[0] "" + +#. ~ Description for Exodii worker +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a mostly humanoid robot equipped with various construction tools." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Exodii quadruped" +msgid_plural "Exodii quadrupeds" +msgstr[0] "" + +#. ~ Description for Exodii quadruped +#: lang/json/MONSTER_from_json.py +msgid "" +"This enormous quadrupedal robot seems to be cobbled together from parts, " +"most of them unfamiliar to you. It moves with a heavy, oddly graceful gait," +" its footsteps leaving shallow craters behind. It bristles with an arsenal " +"of weaponry, but doesn't seem in a particular rush to target you." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "zomborg" +msgid_plural "zomborgs" +msgstr[0] "" + +#. ~ Description for zomborg +#: lang/json/MONSTER_from_json.py +msgid "" +"A mix of dead human and even deader technology, this twisted mess of steel " +"and flesh moves like a puppet in the hands of an angry toddler. Its robotic" +" components seem to have shut down, and new bands of flesh have wrapped " +"around them, tugging and pulling them in awkward directions. Bits of " +"metallic skeleton and armor plating jut from its decaying flesh." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "police bot" msgid_plural "police bots" @@ -62012,6 +62376,22 @@ msgid "" "appears to have a mininuke inside. If this is targeting you… Run." msgstr "這台四軸飛行器無人機比一般無人機大上數倍,配有迷你核彈。如果看到它飛向你... 快逃!" +#: lang/json/MONSTER_from_json.py +msgid "balloon sniper-drone" +msgid_plural "balloon sniper-drones" +msgstr[0] "" + +#. ~ Description for {'str': 'balloon sniper-drone'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This unusual contraption looks like a combination of a weather balloon and a" +" quadcopter. Beneath the crude box containing its components hangs a small " +"articulated rig wielding an integrated rifle. Its propellers flicker to " +"life briefly, then shut down again, keeping it mostly stationary despite the" +" air currents. It looks capable of hanging in the air for quite a long time" +" before running out of power." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "alpha razorclaw" msgid_plural "alpha razorclaws" @@ -63710,6 +64090,20 @@ msgid "" msgstr "" "棲息於東部的美洲獅,是一種大型的食肉目貓科動物。一度被認為在本地已經滅絕,經過了保育的工作已經成功的恢復成蓬勃發展的群體。敏捷又隱蔽,這位獵食者能夠用強而有力的跳躍猛撲到遠處的獵物,用危險的利爪抓住獵物然後用牙齒給予致命一擊。" +#: lang/json/MONSTER_from_json.py +msgid "tiger" +msgid_plural "tigers" +msgstr[0] "" + +#. ~ Description for {'str': 'tiger'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The majestic tiger, a large feline predator. Native to Asia, they are now " +"most populous in private reserves in the United States. Fast and powerful, " +"this predator is one of the most recognizable and beloved animals in the " +"world. Also one of the deadliest." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "calf" msgid_plural "calves" @@ -65735,6 +66129,19 @@ msgstr[0] "" msgid "High-powered loudspeaker, repeating loud messages over and over again." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "upcycled turret" +msgid_plural "upcycled turrets" +msgstr[0] "" + +#. ~ Description for upcycled turret +#: lang/json/MONSTER_from_json.py +msgid "" +"This hefty turret appears to be bolted together out of various scraps of " +"technology, many of them extremely foreign looking. It is equipped with a " +"hefty looking machine gun." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "eyebot" msgid_plural "eyebots" @@ -65821,6 +66228,62 @@ msgid "" "looking for patient to assist." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "skeletal dog" +msgid_plural "skeletal dogs" +msgstr[0] "骷髏犬" + +#. ~ Description for {'str': 'skeletal dog'} +#. ~ Description for {'str': 'skeletal wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This once-canine has shed all of its skin, revealing a carapace of fused " +"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " +"to be controlled by a net of veins and sinews which pulse with glistening " +"black goo." +msgstr "這個曾經是狗的生物所有的皮膚都已剝落,露出了骨頭與肋骨。雖然完全沒有血肉,骨頭間仍有血管與肌腱聯繫,伴隨著黑色黏液。" + +#: lang/json/MONSTER_from_json.py +msgid "barghest" +msgid_plural "barghests" +msgstr[0] "" + +#. ~ Description for {'str': 'barghest'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Huge swollen zombie dog, smeared black with slime. Its teeth are longer and" +" its broad back is rippling with muscles and oozing wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hulking horror" +msgid_plural "hulking horrors" +msgstr[0] "" + +#. ~ Description for {'str': 'hulking horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A four-legged canine body now grotesquely swollen, with arms as wide as a " +"trash can and massive exposed teeth." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "boneplate wolf" +msgid_plural "boneplate wolfs" +msgstr[0] "" + +#. ~ Description for {'str': 'boneplate wolf'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This is a four legged creature covered in fused bony plates, shaped somewhat" +" like a dog or wolf. Joints and cracks around its body ooze with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "skeletal wolf" +msgid_plural "skeletal wolfs" +msgstr[0] "" + #: lang/json/MONSTER_from_json.py msgid "spearcat hunter" msgid_plural "spearcat hunters" @@ -65925,20 +66388,6 @@ msgid "" "outpace its two-legged friends." msgstr "這是隻強而有力的犬科畸形生物, 向前的追擊速度比牠兩條腿的朋友更快。" -#: lang/json/MONSTER_from_json.py -msgid "skeletal dog" -msgid_plural "skeletal dogs" -msgstr[0] "骷髏犬" - -#. ~ Description for {'str': 'skeletal dog'} -#: lang/json/MONSTER_from_json.py -msgid "" -"This once-canine has shed all of its skin, revealing a carapace of fused " -"bones and ribs. Devoid entirely of flesh, this walking suit of bone seems " -"to be controlled by a net of veins and sinews which pulse with glistening " -"black goo." -msgstr "這個曾經是狗的生物所有的皮膚都已剝落,露出了骨頭與肋骨。雖然完全沒有血肉,骨頭間仍有血管與肌腱聯繫,伴隨著黑色黏液。" - #: lang/json/MONSTER_from_json.py msgid "Z-9" msgid_plural "Z-9s" @@ -66042,6 +66491,30 @@ msgid "" "and its eyes bulge with black goo." msgstr "一隻看起來普通的美洲獅, 但是它的後腳腫脹, 並且從眼睛流出黑色的黏液。" +#: lang/json/MONSTER_from_json.py +msgid "Tiger wight" +msgid_plural "Tiger wights" +msgstr[0] "" + +#. ~ Description for {'str': 'Tiger wight'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This otherwise normal looking tiger stumbles and sways, its jaws slack, its " +"eyes wide open and shining black." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "mass of zombie spiders" +msgid_plural "mass of zombie spiderss" +msgstr[0] "" + +#. ~ Description for {'str': 'mass of zombie spiders'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Thousands, maybe millions of spiders piling up high, each slowly oozing " +"sticky green pus, struggling to keep the fetid mass together and moving." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "scarred zombie" msgid_plural "scarred zombies" @@ -66558,6 +67031,43 @@ msgstr "" msgid "The impaler launches a barb!" msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "scissorlimbs" +msgid_plural "scissorlimbss" +msgstr[0] "" + +#. ~ Description for {'str': 'scissorlimbs'} +#: lang/json/MONSTER_from_json.py +msgid "" +" A nightmarish spider of gore stands tall among the ruins, and keeps silent " +"watch of the blighted landscape. Its spindly limbs of bone slip between the" +" rubble with otherworldly speed." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "hanging innards" +msgid_plural "hanging innardss" +msgstr[0] "" + +#. ~ Description for {'str': 'hanging innards'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Great snakes of flesh hang from the ceiling above, madly thrashing and " +"reaching about." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "spasming lump" +msgid_plural "spasming lumps" +msgstr[0] "" + +#. ~ Description for {'str': 'spasming lump'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A great pile of merged bodies and mutated flesh. It spasms in an arrhythmic" +" and desperate manner." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "flesh wall" msgid_plural "flesh walls" @@ -68665,19 +69175,6 @@ msgid "" " black eyes, and a tattered sail on its back." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Spinosaurus shady zombie" -msgid_plural "Spinosaurus shady zombies" -msgstr[0] "" - -#. ~ Description for {'str': 'Spinosaurus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with a tattered sail. The head is long and narrow " -"with a V-shaped snout." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Z-Rex" msgid_plural "Z-Rexes" @@ -68688,31 +69185,6 @@ msgstr[0] "" msgid "Massive piles of ragged, stinking flesh lifting enormous teeth." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Shady Z-Rex" -msgid_plural "Shady Z-Rexs" -msgstr[0] "" - -#. ~ Description for {'str': 'Shady Z-Rex'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" -" teeth would fit in it." -msgstr "" - -#: lang/json/MONSTER_from_json.py -msgid "S-Rex" -msgid_plural "S-Rexes" -msgstr[0] "" - -#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} -#: lang/json/MONSTER_from_json.py -msgid "" -"Monstrous columns of dense bone lifting enormous sharp pointed teeth " -"dripping with black goo." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Albertosaurus zombie" msgid_plural "Albertosaurus zombie" @@ -68813,19 +69285,6 @@ msgid "" "sickle-like claw." msgstr "" -#: lang/json/MONSTER_from_json.py -msgid "Deinonychus shady zombie" -msgid_plural "Deinonychus shady zombies" -msgstr[0] "" - -#. ~ Description for {'str': 'Deinonychus shady zombie'} -#: lang/json/MONSTER_from_json.py -msgid "" -"An uncanny shadow envelops this dinosaur. You can make out the outline of a" -" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " -"large sickle-like claw." -msgstr "" - #: lang/json/MONSTER_from_json.py msgid "Utahraptor zombie" msgid_plural "Utahraptor zombies" @@ -68875,6 +69334,325 @@ msgid "" "like a frill." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "Gruesome Gallimimus" +msgid_plural "Gruesome Gallimimuss" +msgstr[0] "" + +#. ~ Description for {'str': 'Gruesome Gallimimus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its entire body bulges with " +"distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skull Breaker" +msgid_plural "Skull Breakers" +msgstr[0] "" + +#. ~ Description for {'str': 'Skull Breaker'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Its round, hard-looking domed " +"head sits on a body bulging with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crusher Camp" +msgid_plural "Crusher Camps" +msgstr[0] "" + +#. ~ Description for {'str': 'Crusher Camp'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a large feathered bipedal dinosaur with grossly " +"bulging legs, massive hulking shoulders and a vicious pointed beak. Its " +"tattered feathers are stained with black, sticky liquid." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spino Sledge" +msgid_plural "Spino Sledges" +msgstr[0] "" + +#. ~ Description for {'str': 'Spino Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Enormous putrid dinosaur corpse with a ferocious crocodile-like head, oozing" +" black eyes, and a tattered sail on its back. Its body is even bigger than " +"normal, bulging with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Rage Rex" +msgid_plural "Rage Rexs" +msgstr[0] "" + +#. ~ Description for {'str': 'Rage Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive piles of ragged, stinking flesh lifting enormous teeth. Its entire " +"body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Alberta Anvil" +msgid_plural "Alberta Anvils" +msgstr[0] "" + +#. ~ Description for {'str': 'Alberta Anvil'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive jaws and grabbing claws lifting by a body bulging with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Triceratruck" +msgid_plural "Triceratrucks" +msgstr[0] "" + +#. ~ Description for {'str': 'Triceratruck'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A massive shambling rhino-like dinosaur corpse with a bony crest from which " +"three wicked looking horns emerge. Its black eyes ooze like tears. Its " +"entire body bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Stegosaurus Sledge" +msgid_plural "Stegosaurus Sledges" +msgstr[0] "" + +#. ~ Description for {'str': 'Stegosaurus Sledge'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A large shambling quadruped dinosaur corpse with plates on its back, waving " +"a spiked tail. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Dino Tank" +msgid_plural "Dino Tanks" +msgstr[0] "" + +#. ~ Description for {'str': 'Dino Tank'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Heavily armored zombie dinosaur. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Zombie Dreadnought" +msgid_plural "Zombie Dreadnoughts" +msgstr[0] "" + +#. ~ Description for {'str': 'Zombie Dreadnought'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Massive, long-necked, four-legged dinosaur corpse with a long, whip-like " +"tail. Its entire body bulges with distended muscles and swollen, festering " +"wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Draco Titan" +msgid_plural "Draco Titans" +msgstr[0] "" + +#. ~ Description for {'str': 'Draco Titan'} +#: lang/json/MONSTER_from_json.py +msgid "" +"This zombie is enormous, scaly, studded with bony spikes, and it moves with " +"horrible speed. Its colorful horns and bone spikes sit on a body bulging " +"with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Allosaurus Avalanche" +msgid_plural "Allosaurus Avalanches" +msgstr[0] "" + +#. ~ Description for {'str': 'Allosaurus Avalanche'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shambling corpse of a large predatory bipedal dinosaur. Its entire body" +" bulges with distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deino Destroyer" +msgid_plural "Deino Destroyers" +msgstr[0] "" + +#. ~ Description for {'str': 'Deino Destroyer'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium-sized bipedal dinosaur covered with " +"tattered feathers and black putrid liquid. Both feet brandish a large " +"sickle-like claw. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Hoodoo" +msgid_plural "Utah Hoodoos" +msgstr[0] "" + +#. ~ Description for {'str': 'Utah Hoodoo'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The swaying, hopping corpse of a large bipedal dinosaur with feathered arms," +" a long tail, and long sharp scythe-like claws. Its entire body bulges with" +" distended muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Parasaur Punch" +msgid_plural "Parasaur Punchs" +msgstr[0] "" + +#. ~ Description for {'str': 'Parasaur Punch'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A huge mottled dinosaur with a blunt head crest, dead and walking, eyes " +"vacant and swollen. Its entire body bulges with distended muscles and " +"swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Winged Horror" +msgid_plural "Winged Horrors" +msgstr[0] "" + +#. ~ Description for {'str': 'Winged Horror'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The flying corpse of a feathered reptile over three feet long, with short " +"wings and a big colorful beak. Its entire body bulges with distended " +"muscles and swollen, festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Crested Crusher" +msgid_plural "Crested Crushers" +msgstr[0] "" + +#. ~ Description for {'str': 'Crested Crusher'} +#: lang/json/MONSTER_from_json.py +msgid "" +"The shuffling corpse of a medium dinosaur with sharp teeth and two prominent" +" bony crests on its head with ragged strips of ripped flesh hanging down " +"like a frill. Its entire body bulges with distended muscles and swollen, " +"festering wounds." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Spinosaurus shady zombie" +msgid_plural "Spinosaurus shady zombies" +msgstr[0] "" + +#. ~ Description for {'str': 'Spinosaurus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with a tattered sail. The head is long and narrow " +"with a V-shaped snout." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Shady Z-Rex" +msgid_plural "Shady Z-Rexs" +msgstr[0] "" + +#. ~ Description for {'str': 'Shady Z-Rex'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" huge bipedal dinosaur with feathery edges. The head looks big, lots of big" +" teeth would fit in it." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Deinonychus shady zombie" +msgid_plural "Deinonychus shady zombies" +msgstr[0] "" + +#. ~ Description for {'str': 'Deinonychus shady zombie'} +#: lang/json/MONSTER_from_json.py +msgid "" +"An uncanny shadow envelops this dinosaur. You can make out the outline of a" +" medium-sized bipedal dinosaur with feathery edges. Both feet brandish a " +"large sickle-like claw." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "S-Rex" +msgid_plural "S-Rexes" +msgstr[0] "" + +#. ~ Description for {'str': 'S-Rex', 'str_pl': 'S-Rexes'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting enormous sharp pointed teeth " +"dripping with black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal Albertosaurus" +msgid_plural "Skeletal Albertosauruss" +msgstr[0] "" + +#. ~ Description for {'str': 'Skeletal Albertosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Skeletal claws reach ahead." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Bone Dragon" +msgid_plural "Bone Dragons" +msgstr[0] "" + +#. ~ Description for {'str': 'Bone Dragon'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. Spikes and colorful horns jut out to complete the effect." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Skeletal allosaurus" +msgid_plural "Skeletal allosauruss" +msgstr[0] "" + +#. ~ Description for {'str': 'Skeletal allosaurus'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo." +msgstr "" + +#: lang/json/MONSTER_from_json.py +msgid "Utah Bones" +msgid_plural "Utah Boness" +msgstr[0] "" + +#. ~ Description for {'str': 'Utah Bones'} +#: lang/json/MONSTER_from_json.py +msgid "" +"Monstrous columns of dense bone lifting sharp pointed teeth dripping with " +"black goo. There is a long tail and long sharp scythe-like claws" +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "improvised SMG turret" msgid_plural "improvised SMG turrets" @@ -69317,6 +70095,18 @@ msgid "" "off creatures that disturb it." msgstr "" +#: lang/json/MONSTER_from_json.py +msgid "frog" +msgid_plural "frogs" +msgstr[0] "" + +#. ~ Description for {'str': 'frog'} +#: lang/json/MONSTER_from_json.py +msgid "" +"A conspicuously average american bullfrog. You better keep prince charming " +"away from it." +msgstr "" + #: lang/json/MONSTER_from_json.py msgid "lemure" msgid_plural "lemures" @@ -69930,6 +70720,14 @@ msgstr "" msgid "a bird" msgstr "" +#: lang/json/SPECIES_from_json.py +msgid "an alien cyborg" +msgstr "" + +#: lang/json/SPECIES_from_json.py +msgid "heavy thuds." +msgstr "" + #: lang/json/SPECIES_from_json.py msgid "a reptile" msgstr "" @@ -70800,6 +71598,17 @@ msgid "" "rune as a catalyst for recipes." msgstr "這個儀式創造了一個與泛靈論者契合的小石子。你能將此符文用於製作時的催化劑。" +#: lang/json/SPELL_from_json.py +msgid "Soulrend" +msgstr "" + +#. ~ Description for Soulrend +#: lang/json/SPELL_from_json.py +msgid "" +"Violently tears the spirit from the body, and bounds the resulting shade to " +"your will." +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Ignus Fatuus" msgstr "" @@ -71022,6 +71831,15 @@ msgstr "" msgid "Uses a little fatigue" msgstr "" +#: lang/json/SPELL_from_json.py +msgid "Debug polymorph" +msgstr "" + +#. ~ Description for Debug polymorph +#: lang/json/SPELL_from_json.py +msgid "Well you wanted to lose weight, right?" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Debug HP Spell" msgstr "" @@ -71450,6 +72268,10 @@ msgstr "魔力之箭" msgid "Haste" msgstr "迅捷術" +#: lang/json/SPELL_from_json.py +msgid "Baleful Polymorph" +msgstr "" + #: lang/json/SPELL_from_json.py msgid "Mana Beam" msgstr "魔力射線" @@ -75125,6 +75947,18 @@ msgid "bionic firestarter" msgid_plural "bionic firestarters" msgstr[0] "生化點火器" +#: lang/json/TOOL_from_json.py lang/json/furniture_from_json.py +msgid "smoking rack" +msgid_plural "smoking racks" +msgstr[0] "" + +#. ~ Description for {'str': 'smoking rack'} +#. ~ Description for {'str': 'pseudo butter churn'} +#. ~ Description for {'str': 'pseudo atomic butter churn'} +#: lang/json/TOOL_from_json.py +msgid "This is a crafting_pseudo_item if you have it something is wrong." +msgstr "" + #: lang/json/TOOL_from_json.py msgid "cash card" msgid_plural "cash cards" @@ -75189,7 +76023,7 @@ msgstr[0] "傑克南瓜燈" #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. #. ~ Use action menu_text for {'str': 'candle'}. #. ~ Use action menu_text for {'str': 'Louisville Slaughterer'}. -#: lang/json/TOOL_from_json.py src/veh_interact.cpp +#: lang/json/TOOL_from_json.py src/activity_actor.cpp src/veh_interact.cpp msgid "Light" msgstr "燈光" @@ -77680,12 +78514,6 @@ msgid "pseudo butter churn" msgid_plural "pseudo butter churns" msgstr[0] "" -#. ~ Description for {'str': 'pseudo butter churn'} -#. ~ Description for {'str': 'pseudo atomic butter churn'} -#: lang/json/TOOL_from_json.py -msgid "This is a crafting_pseudo_item if you have it something is wrong." -msgstr "" - #: lang/json/TOOL_from_json.py msgid "electric carver (off)" msgid_plural "electric carvers (off)" @@ -79835,13 +80663,36 @@ msgid "throwable fire extinguisher" msgid_plural "throwable fire extinguishers" msgstr[0] "投擲式滅火器" +#. ~ Use action menu_text for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "Pull plug" +msgstr "" + +#. ~ Use action msg for {'str': 'throwable fire extinguisher'}. +#: lang/json/TOOL_from_json.py +msgid "You pull the plug on the extinguisher grenade." +msgstr "" + #. ~ Description for {'str': 'throwable fire extinguisher'} #: lang/json/TOOL_from_json.py msgid "" "This is a fire extinguisher in grenade form. While not as effective as a " -"regular fire extinguisher, you can use it from a distance. It is activated " -"by heat, so just throw it into the flames." -msgstr "這是一個有著手榴彈外形的滅火器, 效果雖不如常規滅火器, 但你可以從遠處使用它。它受熱後會自動啟動, 所以只要把它扔到火裡就行了。" +"regular fire extinguisher, you can use it from a distance. It has a plastic" +" plug that can be pulled, but is primarely activated by heat, so just throw " +"it into the flames." +msgstr "" + +#: lang/json/TOOL_from_json.py +msgid "active throwable fire extinguisher" +msgid_plural "active throwable fire extinguishers" +msgstr[0] "" + +#. ~ Description for {'str': 'active throwable fire extinguisher'} +#: lang/json/TOOL_from_json.py +msgid "" +"This is an active extinguisher grenade, likely to burst any second now. " +"Better throw it!" +msgstr "" #: lang/json/TOOL_from_json.py msgid "New York hook" @@ -85866,7 +86717,7 @@ msgid "Pheidippides was a hack" msgstr "" #: lang/json/achievement_from_json.py -msgid "Run a marathon…plus a little bit more." +msgid "Run a marathon… plus a little bit more." msgstr "" #: lang/json/achievement_from_json.py @@ -85933,6 +86784,592 @@ msgstr "" msgid "Return to the location you started the game" msgstr "" +#: lang/json/achievement_from_json.py +msgid "Timber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"If a tree falls in a forest and no one is around to hear it, does it make a " +"sound?" +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_from_json.py +msgid "Lumberjack" +msgstr "伐木工" + +#: lang/json/achievement_from_json.py +msgid "What is a forest for a man with an axe?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deforestation" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If you cut down the trees you will find the wolf." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Digger" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "That's exactly what we need: more dead bodies." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Grave Robber" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hey, what if they turned down there? You've gotta check." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's a privilege to be buried when billions will not be." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Undertaker" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Leave no one to rot among the living dead." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Funeral House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You cannot bury the whole world, can you?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cyberpunk" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spiritus quidem promptus; caro vero infirma." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Clockwork Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"By most mechanical and dirty hand. I shall have such revenges on you… both." +" The things I will do, what they are, yet I know not. But they will be the" +" terrors of the earth." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Homo Evolutis" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "World of man has ended. Long live the world of transhumanism." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Broken But Not Defeated" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Does your medical insurance cover that?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Free Trader" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Extraordinary gizmos for obscenely low prices!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cut-Me-Own-Throat Dibbler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"My Innuit friend, I'm selling you this ice for such a low price, that it's " +"cutting me own throat." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eloquent" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We're frends, aren't we?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Silver Tongue" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Legend has it that you convinced a zombie hulk to go away." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "HackerMan" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This OS has a back door. There is always a back door." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Still not quite like Kevin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's not cheating. It's debugging." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/mutation_from_json.py +msgid "MD" +msgstr "實習醫生" + +#: lang/json/achievement_from_json.py +msgid "Is there a doctor in the house?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dr House" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's lupus." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Engineer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Just give me my wrench." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "MacGyver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "This whole deal is holding on faith, spit and duct tape." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Trapper" +msgstr "捕獸者" + +#: lang/json/achievement_from_json.py +msgid "A good trap doesn't discriminate between beavers and zombeavers." +msgstr "" + +#: lang/json/achievement_from_json.py src/iuse.cpp +#: src/iuse_software_minesweeper.cpp +msgid "Minesweeper" +msgstr "踩地雷" + +#: lang/json/achievement_from_json.py +msgid "All it takes is one mistake." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ace Driver" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "No turn is too sharp." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "The Stig" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Formula One is for Sunday drivers." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Swimmer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Like a fish to water." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Michael Phelps" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Faster then Jaws." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Do-It-Yourselfer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Take this thing, put it in that thing, and voila." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack of All Trades" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "With a right ammount of glue, there is nothing I can't do." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Master Chef" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Glazed tenderloin is a cakewalk." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Hell's Kitchen" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Today's menu: Soupe a l'oignon, Boeuf Bourguignon and Creme brulee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Tailor" +msgstr "裁縫師" + +#: lang/json/achievement_from_json.py +msgid "A needle, a thread and a dream." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Fashion Designer" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Male, feamale and mutant fashion alike." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Survivalist" +msgstr "生存專家" + +#: lang/json/achievement_from_json.py +msgid "Survival is my game." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bear Grylls" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "So you say you can survive on your own urine?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Ohm's Law" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Thunder Ohm. Two volts enter, one volt leaves. Resistance is futile." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Nicola Tesla" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One does not simply taste a 9V battery." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bull's Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Better then Legolas." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Robin Hood" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Wilhelm Tell? Never heard of." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Eagle Eye" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Only me and my target." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Deadshot" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Don't run. You'll die tired." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Gunner" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber makes the difference." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rocket Man" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I'm sending you to the moon. In pieces." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Small But Deadly" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Caliber doesn't count when you're on the recieving side of the barrel." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Dirty Harry" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"But being this is a .44 Magnum, the most powerful handgun in the world and " +"would blow your head clean off, you've gotta ask yourself one question: Do " +"I feel lucky? Well, do ya, punk?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Rifleman" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"This is my rifle. There are many like it, but this one is mine. My rifle " +"is my best friend. It is my life. I must master it as I must master my " +"life." +msgstr "" + +#: lang/json/achievement_from_json.py lang/json/npc_class_from_json.py +#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py +msgid "Soldier" +msgstr "軍人" + +#: lang/json/achievement_from_json.py +msgid "" +"Without me, my rifle is useless. Without my rifle, I am useless. I will " +"keep my rifle clean and ready, even as I am clean and ready. We will become" +" part of each other." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Double Barrel, Double Fun" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "When you want to hit your target nine times with one shot." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elmer Fudd" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "What's up doc? Hunting wabbits?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Spray'n'Pray" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "One will hit. It's a matter of statistics." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "SMG Goes BRRRT!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "We definitely need more ammo." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Yeet!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "And never come back." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Kobe Bryant" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Frag out!" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Brawler" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Bottle in left hand, chair leg in right hand." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Street Fighter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's winning that matters, not the style." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Batter" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Every strike brings me closer to a home run." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Stone Age" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Cudgel was humanity's first tool. And it may be it's last, so why not " +"master it?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Way of the Sword" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"When the sword is once drawn, the passions of men observe no bounds of " +"moderation." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Miyamoto Musashi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"The sword has to be more than a simple weapon; it has to be an answer to " +"life's questions." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Elusive" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "A strongest of blows is nothing if it doesn't land." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Neo" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "But can you dodge a bullet?" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Cold Steel" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "While you were partying, I studied the blade." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Jack the Ripper" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "" +"Is this a dagger which I see before me, the handle toward my hand? Come, " +"let me clutch thee." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Road to Shaolin" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "I feel an army in my fist." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Mr Miyagi" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "To be your own weapon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Burglar" +msgstr "竊賊" + +#: lang/json/achievement_from_json.py +msgid "Crowbar? Such a barbarity." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Locksmith" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "If there is a lock, there is a key." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Periodic Table" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "It's somewhat like cooking. Just don't lick the spoon." +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "Heisenberg" +msgstr "" + +#: lang/json/achievement_from_json.py +msgid "You all know who I am. I'm the cook. Say my name." +msgstr "" + #: lang/json/achievement_from_json.py msgid "Would-be Wizard" msgstr "將來的巫師" @@ -86385,6 +87822,11 @@ msgstr "" msgid "canceling activity serialized with legacy code" msgstr "" +#: lang/json/activity_type_from_json.py +msgctxt "training" +msgid "working out" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "fusion cell" msgstr "核融合電池" @@ -86686,6 +88128,10 @@ msgstr "噴灑式化學物" msgid "compressed air" msgstr "壓縮空氣" +#: lang/json/ammunition_type_from_json.py +msgid "12.3ln cartridge" +msgstr "" + #: lang/json/ammunition_type_from_json.py msgid "shotcanisters" msgstr "射彈罐" @@ -88540,6 +89986,62 @@ msgstr "" msgid "Merciful" msgstr "" +#: lang/json/conduct_from_json.py +msgid "The Elven Path" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Cut no trees" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Homo Sapiens" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Install no faulty bionic implants" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "No mutations" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Clean on X-ray" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Pure Blood" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Structural Integrity" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Break no bones" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Teacher, Leave Them Kids Alone" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Gain no skill levels" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Self-Imposed Illiteracy" +msgstr "" + +#: lang/json/conduct_from_json.py +msgid "Read no books" +msgstr "" + #: lang/json/construction_category_from_json.py src/advanced_inv.cpp #: src/armor_layers.cpp src/debug_menu.cpp src/options.cpp src/scenario.cpp msgid "All" @@ -89164,10 +90666,6 @@ msgstr "牆壁漆成黃色" msgid "Take Paint Off Wall" msgstr "去除牆壁的顏色" -#: lang/json/construction_from_json.py -msgid "Remove Carpet" -msgstr "移除地毯" - #: lang/json/construction_from_json.py msgid "Carpet Floor Red" msgstr "鋪設紅色地毯" @@ -89208,6 +90706,30 @@ msgstr "建造木製樓梯" msgid "Mine Upstair" msgstr "往上採礦" +#: lang/json/construction_from_json.py +msgid "Build Low End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. The " +"high end of a ramp must be built adjacent to allow moving between z-levels " +"in both directions." +msgstr "" + +#: lang/json/construction_from_json.py +msgid "Build High End of a Concrete Ramp" +msgstr "" + +#: lang/json/construction_from_json.py +msgid "" +"Build a concrete ramp leading to the next z-level above, and the " +"corresponding ramp down leading from the z-level above to this level. It " +"must be built next to a low end of a ramp to allow moving between z-levels " +"in both directions." +msgstr "" + #: lang/json/construction_from_json.py msgid "Start Vehicle Construction" msgstr "開始車輛建造" @@ -92194,7 +93716,7 @@ msgstr "你抽了一兩口。" msgid "You smoked too much." msgstr "你抽太多菸了。" -#: lang/json/effects_from_json.py +#: lang/json/effects_from_json.py src/activity_actor.cpp msgid "High" msgstr "快感" @@ -94205,6 +95727,18 @@ msgstr "火" msgid "raging fire" msgstr "大火" +#: lang/json/field_type_from_json.py +msgid "extinguisher mist" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "extinguisher cloud" +msgstr "" + +#: lang/json/field_type_from_json.py +msgid "thick extinguisher cloud" +msgstr "" + #: lang/json/field_type_from_json.py msgid "legacy rubble" msgstr "廢墟瓦礫" @@ -95228,8 +96762,7 @@ msgid "" msgstr "" #: lang/json/furniture_from_json.py lang/json/furniture_from_json.py -#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/map.cpp src/map.cpp +#: lang/json/terrain_from_json.py lang/json/terrain_from_json.py src/map.cpp msgid "crash!" msgstr "轟隆!" @@ -95397,7 +96930,7 @@ msgid "" msgstr "一大堆葉子。如果你不關心舒適或溫暖,你可以睡在上面。" #: lang/json/furniture_from_json.py lang/json/terrain_from_json.py -#: lang/json/terrain_from_json.py src/iuse.cpp +#: src/iuse.cpp msgid "crunch!" msgstr "匡噹!" @@ -96036,9 +97569,8 @@ msgstr "健身器材" #: lang/json/furniture_from_json.py msgid "" "A heavy set of weightlifting equipment for strength training, with a pair of" -" heavy weights affixed to opposite ends of a sturdy pipe. The weights are " -"huge, and using them without a spotter would be a good way to seriously " -"injure yourself." +" heavy weights affixed to opposite ends of a sturdy pipe. You can adjust " +"the set by hand-picking the weights you wish to use." msgstr "" #: lang/json/furniture_from_json.py @@ -96127,6 +97659,18 @@ msgid "" " to be scavanged." msgstr "" +#: lang/json/furniture_from_json.py +msgid "mechanical ergometer" +msgstr "" + +#. ~ Description for mechanical ergometer +#: lang/json/furniture_from_json.py +msgid "" +"An exercise machine with a set of handles and plates meant to emulate rowing" +" a boat. This an older model with mechanical resistance adjustments, but it" +" works without power." +msgstr "" + #: lang/json/furniture_from_json.py msgid "treadmill" msgstr "跑步機" @@ -96139,6 +97683,18 @@ msgid "" "you're probably getting enough cardio on your own." msgstr "" +#: lang/json/furniture_from_json.py +msgid "gravity treadmill" +msgstr "" + +#. ~ Description for gravity treadmill +#: lang/json/furniture_from_json.py +msgid "" +"A gravity driven conveyor belt with a mechanical control panel for running " +"in place. Conveyor belt is positioned in a steep, but adjustable incline, " +"so it slides back under your weight." +msgstr "" + #: lang/json/furniture_from_json.py msgid "heavy punching bag" msgstr "重拳擊沙袋" @@ -97400,10 +98956,6 @@ msgstr "" msgid "filled arc furnace" msgstr "" -#: lang/json/furniture_from_json.py -msgid "smoking rack" -msgstr "煙燻架" - #. ~ Description for smoking rack #. ~ Description for metal smoking rack #: lang/json/furniture_from_json.py @@ -98146,7 +99698,8 @@ msgstr "能夠發射酸液球的槍。" msgid "auto" msgstr "自動" -#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gun_from_json.py lang/json/gun_from_json.py +#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py msgctxt "gun_type_type" msgid "rifle" msgstr "步槍" @@ -98313,8 +99866,8 @@ msgid "" "standard UPS." msgstr "這把雷射手槍是以 21 世紀中葉的 V29 雷射手槍為基礎而設計的,又加了一些大力膠帶跟電子零件的構造,使用標準 UPS 供電。" -#: lang/json/gun_from_json.py lang/json/gun_from_json.py -#: lang/json/gunmod_from_json.py lang/json/gunmod_from_json.py src/item.cpp +#: lang/json/gun_from_json.py lang/json/gunmod_from_json.py +#: lang/json/gunmod_from_json.py src/item.cpp msgctxt "gun_type_type" msgid "pistol" msgstr "手槍" @@ -98372,7 +99925,7 @@ msgid "" "deadly." msgstr "利用許多廢料手工製作而成的高衝程氣動步槍。相當的安靜且致命。" -#: lang/json/gun_from_json.py src/item_factory.cpp +#: lang/json/gun_from_json.py lang/json/gun_from_json.py src/item_factory.cpp msgid "semi-auto" msgstr "半自動" @@ -98794,8 +100347,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "MAS 223" -msgid_plural "MAS 223" +msgid "MAS .223" +msgid_plural "MAS .223" msgstr[0] "" #: lang/json/gun_from_json.py @@ -100965,14 +102518,14 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "CZ-75" -msgid_plural "CZ-75s" -msgstr[0] "CZ-75 手槍" +msgid "CZ 75 B" +msgid_plural "CZ 75 Bs" +msgstr[0] "" #: lang/json/gun_from_json.py msgid "" -"The CZ-75 is a semi-automatic pistol developed in Czechoslovakia, and is one" -" of the original wonder nines. Though designed for export to western " +"The CZ 75 B is a semi-automatic pistol developed in Czechoslovakia, and is " +"one of the original wonder nines. Though designed for export to western " "countries, it was declared a state secret; lack of international patent " "protection meant that many clones and variants were produced and distributed" " around the world, with Česká zbrojovka only joining in the 90's. This " @@ -101076,6 +102629,37 @@ msgid "" "by their egomaniac descendants in New England." msgstr "" +#: lang/json/gun_from_json.py +msgid "PA md. 68 Battle Rifle" +msgid_plural "PA md. 68 Battle Rifles" +msgstr[0] "" + +#: lang/json/gun_from_json.py +msgid "" +"The most popular gun to use the 12.3ln cartridge was, of course, the PA md. " +"71. Its predecessor, the md. 68, was viewed by many as a sort of failure: " +"although it was reliable and powerful, it was too heavy to be used as a good" +" infantry weapon, and not really heavy enough to be a good support gun. " +"Enough were made, though, that during the zombie apocalypse, it gained a " +"great deal of resurgent popularity as a light emplacement gun that used " +"readily available ammunition. It perfectly served the purposes of the " +"Exodii, who had far less concern about its unwieldiness." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "PA md. 71 zombie hunting rifle" +msgid_plural "PA md. 71 zombie hunting rifles" +msgstr[0] "" + +#: lang/json/gun_from_json.py +msgid "" +"This extremely popular Romanian assault rifle, made famous in the third " +"Carpachian War, has been redesigned slightly by the Exodii to serve as a " +"sniper weapon. It is well suited to precision shots against high-priority " +"targets. This modified design fires an extremely rapid 5-shot burst, with " +"the goal of shredding the target and preventing revivification." +msgstr "" + #: lang/json/gun_from_json.py msgid "flamethrower" msgid_plural "flamethrowers" @@ -101548,8 +103132,8 @@ msgid "" msgstr "" #: lang/json/gun_from_json.py -msgid "makeshift shotgun" -msgid_plural "makeshift shotguns" +msgid "four winds shotgun" +msgid_plural "four winds shotguns" msgstr[0] "" #: lang/json/gun_from_json.py @@ -102190,6 +103774,24 @@ msgstr[0] "" msgid "Bionic one-shot subdermal .40 pistol integrated with your head." msgstr "" +#: lang/json/gun_from_json.py +msgid "modified Marlin 39A" +msgid_plural "modified Marlin 39A" +msgstr[0] "" + +#: lang/json/gun_from_json.py +msgid "A Marlin 39A, modified for use in a vehicle turret." +msgstr "" + +#: lang/json/gun_from_json.py +msgid "modified SKS" +msgid_plural "modified SKSs" +msgstr[0] "" + +#: lang/json/gun_from_json.py +msgid "An SKS, modified to be suitable for use in a vehicle turret." +msgstr "" + #: lang/json/gun_from_json.py msgid "CRIT .5 LP" msgid_plural "CRIT .5 LPs" @@ -102924,11 +104526,6 @@ msgid "" "reliability." msgstr "" -#: lang/json/gun_from_json.py -msgid "slam-fire shotgun" -msgid_plural "slam-fire shotguns" -msgstr[0] "" - #: lang/json/gun_from_json.py msgid "Ichaival" msgid_plural "Ichaivals" @@ -104765,6 +106362,12 @@ msgid "" " experiment" msgstr "" +#: lang/json/harvest_from_json.py +msgid "" +"You search for any salvageable hardware in what's left of this flesh and " +"metal monster" +msgstr "" + #: lang/json/harvest_from_json.py msgid "" "You messily hack apart the hulking mass of fused, rancid flesh, taking note " @@ -105362,7 +106965,7 @@ msgid "" "In addition to the primary crafting skills, other skills may be necessary to" " create certain items. Traps, Marksmanship, and First Aid are all required " "for certain items." -msgstr "" +msgstr "除了主要的製作相關技能, 其他技能在製作特定物品時也可能用到。陷阱技能、射擊技能、以及急救技能, 都在製作特定物品時會用到。" #: lang/json/help_from_json.py msgid "" @@ -106710,10 +108313,6 @@ msgstr "寫字" msgid "Teleport yourself" msgstr "傳送自己" -#: lang/json/item_action_from_json.py -msgid "Extinguish a fire" -msgstr "滅火" - #: lang/json/item_action_from_json.py msgid "Dry/clean yourself" msgstr "抹乾/清潔 自己" @@ -107418,7 +109017,7 @@ msgstr "" msgid "" "If your vehicle consists of a single tile, this wheel is enough to allow it " "to move." -msgstr "" +msgstr "如果你的載具只有一格,這個輪子就足夠讓它移動了。" #. ~ Please leave anything in unchanged. #: lang/json/json_flag_from_json.py @@ -107636,7 +109235,7 @@ msgstr "脫掉選中的裝備" #: lang/json/keybinding_from_json.py msgid "Display keybindings menu" -msgstr "" +msgstr "顯示熱鍵設定選單" #: lang/json/keybinding_from_json.py msgid "Reset filter" @@ -107950,6 +109549,14 @@ msgstr "離開創造角色選單" msgid "Toggle sorting order" msgstr "改變排序模式" +#: lang/json/keybinding_from_json.py +msgid "Randomize profession" +msgstr "" + +#: lang/json/keybinding_from_json.py +msgid "Randomize scenario" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Scroll description up" msgstr "向上捲動描述" @@ -108350,6 +109957,10 @@ msgstr "拆解物品" msgid "Sleep" msgstr "睡覺" +#: lang/json/keybinding_from_json.py +msgid "Workout" +msgstr "" + #: lang/json/keybinding_from_json.py msgid "Control Vehicle" msgstr "控制車輛" @@ -108823,12 +110434,12 @@ msgstr "讀取顏色模板" #. ~ translation should not exceed 3 console cells #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/veh_interact.cpp +#: src/trap.cpp src/veh_interact.cpp msgid "Yes" msgstr "是" #: lang/json/keybinding_from_json.py src/editmap.cpp src/editmap.cpp -#: src/options.cpp src/options.cpp src/veh_interact.cpp +#: src/options.cpp src/trap.cpp src/veh_interact.cpp msgid "No" msgstr "否" @@ -114203,7 +115814,7 @@ msgstr "" msgid "There is always work to be done, song to be woven." msgstr "總是有工作要做,有歌要編。" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "If you wish to be set on the path to enlightenment, first you must learn to " "listen and hear the song. Go out, butcher a creature and feel the power " @@ -114211,16 +115822,16 @@ msgid "" " you." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "Excellent. Now be on your way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "I understand your reluctancy. Feel free to return when you see the way." msgstr "" -#: lang/json/mission_def_from_json.py +#: lang/json/mission_def_from_json.py lang/json/talk_topic_from_json.py msgid "" "The shambling corpses we see all around move in discord. Their song can be " "used, but for an Acolyte, this would be needlessly hard. Be sure to carve " @@ -115439,7 +117050,7 @@ msgstr "" #: lang/json/mission_def_from_json.py msgid "" -"I'll see you then…or I won't, and then I'll know I made the right decision." +"I'll see you then… or I won't, and then I'll know I made the right decision." msgstr "" #: lang/json/mission_def_from_json.py @@ -115448,7 +117059,7 @@ msgid "" msgstr "" #: lang/json/mission_def_from_json.py -msgid "Well, you're not dead…yet." +msgid "Well, you're not dead… yet." msgstr "" #: lang/json/mission_def_from_json.py @@ -115495,6 +117106,8 @@ msgid "" "collect 80 cattail stalks, and bring them back here. In exchange, I'll show" " you how to harvest the jelly." msgstr "" +"你知道香蒲可以取得膠質並用在消毒和止痛上嗎?像這樣的東西在這種狀況下可能會有幫助。我希望你拿著這個包包,前往最近的沼澤,蒐集 80 " +"個香蒲秸稈,然後帶回這裡。作為交換,我會教你怎麼採集膠質。" #: lang/json/mission_def_from_json.py msgid "" @@ -116974,7 +118587,7 @@ msgstr "" msgid "" "Lots of people used to have first aid kits in their bathrooms. I'm sure " "they can't all have been looted." -msgstr "" +msgstr "很多人會習慣在他們的浴室裡放急救箱。我確定它們不會全被拿走的。" #: lang/json/mission_def_from_json.py msgid "" @@ -118653,6 +120266,8 @@ msgid "" "prevent me from ever seeing it. I could use your help getting a few bottles" " of aspirin to start with." msgstr "" +"我現在手上只有一些繃帶和少量的急救箱… 換句話說, 我無法處理最嚴重的醫療緊急情況。我以為拾荒者會優先向我提供醫療物資, " +"但我想這方面的黑市賣家早已把物資買光。我想你首先幫我搜集幾瓶阿斯匹靈。" #: lang/json/mission_def_from_json.py msgid "Aspirin is pretty common in homes and convenience stores." @@ -126628,8 +128243,7 @@ msgstr "蛛形" msgid "Well, maybe you'll just have to make your own world wide web." msgstr "嗯, 也許你只需要製作你自己的網路。" -#: lang/json/mutation_from_json.py lang/json/mutation_from_json.py -#: lang/json/npc_from_json.py +#: lang/json/mutation_from_json.py lang/json/npc_from_json.py msgid "Survivor" msgstr "倖存者" @@ -126939,10 +128553,6 @@ msgid "" msgstr "" "你是真正的美食人,有些人可能認為美食人只是吉祥物,但你知道更多真相。你是美食人,面具已經變成你的臉,你是真實的,站在這個世界與遺忘之間的唯一事物就是你。" -#: lang/json/mutation_from_json.py -msgid "MD" -msgstr "實習醫生" - #. ~ Description for {'str': 'MD'} #: lang/json/mutation_from_json.py msgid "" @@ -127319,11 +128929,29 @@ msgid "" msgstr "" #: lang/json/mutation_from_json.py -msgid "Survivor Story" -msgstr "倖存者故事" - -#. ~ Description for {'str': 'Survivor Story'} -#. ~ Description for {'str': 'Survivor'} +msgid "Survivor: Confused 1" +msgstr "" + +#. ~ Description for {'str': 'Survivor: Confused 1'} +#. ~ Description for {'str': 'Survivor: No Past 1'} +#. ~ Description for {'str': 'Survivor: No Past 2'} +#. ~ Description for {'str': 'Survivor: No Past 3'} +#. ~ Description for {'str': 'Survivor: No Past 4'} +#. ~ Description for {'str': 'Survivor: No Past 5'} +#. ~ Description for {'str': 'Survivor: Religious 1'} +#. ~ Description for {'str': 'Survivor: Religious 2'} +#. ~ Description for {'str': 'Survivor: Dreamer 1'} +#. ~ Description for {'str': 'Survivor: Wedding 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Evacuee 2'} +#. ~ Description for {'str': 'Survivor: Evacuee 3'} +#. ~ Description for {'str': 'Survivor: Evacuee 4'} +#. ~ Description for {'str': 'Survivor: Evacuee 5'} +#. ~ Description for {'str': 'Survivor: Evacuee 6'} +#. ~ Description for {'str': 'Survivor: FEMA Evacuee 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 1'} +#. ~ Description for {'str': 'Survivor: Left for Dead 2'} +#. ~ Description for {'str': 'Survivor: Left for Dead 3'} #. ~ Description for {'str': 'Survivor Story'} #. ~ Description for {'str': 'Survivor'} #. ~ Description for {'str': 'Survivor Story'} @@ -127331,6 +128959,86 @@ msgstr "倖存者故事" msgid "This NPC could tell you about how they survived the Cataclysm" msgstr "" +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: No Past 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Religious 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Dreamer 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Wedding 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 4" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 5" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Evacuee 6" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: FEMA Evacuee 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 1" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 2" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor: Left for Dead 3" +msgstr "" + +#: lang/json/mutation_from_json.py +msgid "Survivor Story" +msgstr "倖存者故事" + #: lang/json/mutation_from_json.py msgid "Mark of the Seer" msgstr "先知的印記" @@ -129079,10 +130787,6 @@ msgstr "我只是努力活著。" msgid "I'm tracking game." msgstr "我在跟蹤遊戲。" -#: lang/json/npc_class_from_json.py lang/json/npc_from_json.py -msgid "Soldier" -msgstr "軍人" - #: lang/json/npc_class_from_json.py lang/json/npc_from_json.py msgid "Bartender" msgstr "調酒師" @@ -129832,10 +131536,6 @@ msgstr "廢料承辦員" msgid "Laborer" msgstr "勞工" -#: lang/json/npc_from_json.py -msgid "Lumberjack" -msgstr "伐木工" - #: lang/json/npc_from_json.py msgid "Woodworker" msgstr "木工" @@ -132345,6 +134045,18 @@ msgstr "人孔蓋" msgid "bridge" msgstr "橋" +#: lang/json/overmap_terrain_from_json.py +msgid "bridge (overpass)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ground)" +msgstr "" + +#: lang/json/overmap_terrain_from_json.py +msgid "bridgehead (ramp)" +msgstr "" + #: lang/json/overmap_terrain_from_json.py msgid "roadstop" msgstr "路邊小吃店" @@ -146220,7 +147932,7 @@ msgstr "" msgid "" "If you have extra antiseptic, use it to disinfect your wounds, even if they " "aren't infected. They will recover faster that way." -msgstr "" +msgstr "如果你有多餘的消毒劑,用它來消毒你的傷口,就算你沒有被感染。這樣會好得比較快。" #: lang/json/snippet_from_json.py msgid "" @@ -147299,96 +149011,6 @@ msgstr "" msgid "I'd kill for a sip of water right now." msgstr "" -#: lang/json/snippet_from_json.py -msgid "" -"Yeah sure, can't help but notice you got beer with you! Let's crack a cold " -"one and chat, , how goes it?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Oh definitely, how about one of those beers I see on you? What's up anyway?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Yeah you share those beers I see you hoarding and then we chat all you like!" -" Only joking, what's up ?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Hey , I bet a chat would be all the sweeter with a nice, cold beer " -"in hand. How's it going?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"While we chat, what say you we open a beer and just… pretend the world isn't" -" ending, just for a while?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Pass me one and let's talk about the good ol' days, ." -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Hey, sure thing, , I need a break anyway, how are you?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Yeah OK, , how's it going?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure, let's shoot the shit! You OK?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Why not? How you doing?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "I'm OK with that, what's up?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "I can spare a few minutes, how's things?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure thing , you good?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Alright, you got something to get off your chest?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Always ready for a good chat! But why, you OK?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "OK , we should get to know each other, how are you coping?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Definitely, I'm game. How you holding up?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "" -"Good idea . Let's forget the world for a while. How you doin'?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Ah, what the heck. How's life been treating you?" -msgstr "" - -#: lang/json/snippet_from_json.py -msgid "Sure. So, how about that weather ey?" -msgstr "" - #: lang/json/snippet_from_json.py msgid "darn" msgstr "縫補" @@ -149852,6 +151474,18 @@ msgstr "" msgid "Was it rough surviving thus far?" msgstr "" +#: lang/json/snippet_from_json.py +msgid "How do you think we ended up here? What even happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What's going on? Like, big picture, what the hell happened?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Have you heard anything about how the apocalypse came about?" +msgstr "" + #: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py #: lang/json/talk_topic_from_json.py msgid "Let's talk about something else." @@ -150567,6 +152201,301 @@ msgstr " 會盡量避免跟敵人交戰。" msgid " will follow normal engagement rules." msgstr " 會遵守一般的交戰守則。" +#: lang/json/snippet_from_json.py +msgid "Yeah sure, want to crack open one of them beers?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Oh definitely, how about one of those beers you got?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Yeah you share those beers I see you hoarding and then we chat all you like!" +" Only joking, heh." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Hey , I bet a chat would be all the sweeter with a nice, cold beer " +"in hand." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"While we chat, what say you we open a beer and just… pretend the world isn't" +" ending." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Pass me one and let's talk, ." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Yeah, this summer heat is hitting me hard, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Enjoying the summer." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Kinda wishing it would cool off a bit, to be honest." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK, maybe it'll stop me from freezing in this weather." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Gotta say, I'm not minding the snow." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "It's weird the zombies don't freeze." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Well, I'm feeling pretty sick… but sure." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I need a break anyway, how are you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how's it going?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's shoot the shit! You OK, ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm OK with that, what's up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I guess I can spare a few minutes, how's things?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Sure thing , you good?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Alright, you got something to get off your chest?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Always ready for a good chat! But why, you OK?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "OK , how are you coping?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I'm game. How you holding up?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Let's forget the world for a while. How you doin'?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "What the heck. How's life been treating you?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "So, how about that weather, eh?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Nice of you to make time. How's it been for you lately?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "My dogs’ve been barkin’ lately, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I feel great today. Not sure what it is, just one of those days." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I just can't believe it's over. I keep running my head back to the days it " +"all fell apart. The riots. The lies. The psychos. It never really felt " +"like it was going to go like this." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever think there's any truth to the crap they were spouting before the " +"world ended? Mind control drugs in the water, bio-terrorism? Some of it " +"would make sense, but it seems so far-fetched. Then again, we're dealing " +"with actual zombies." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wonder if I should be getting more religious now, or less. You know what " +"I'm sayin', ?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna " +"go for my weapon and accidentally pull out a granola bar, right?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever wonder why we even bother? We’re all just gonna be zombies " +"eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the" +" damn point?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I wish I could go bust a cap in one of those zombies right now, without all " +"the fuss about being scared for my life." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Every time I close my eyes, I can still see the riots. Do you get that, or " +"is it just me?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You ever feel like the whole time before the apocalypse was just a dream " +"you’re waking up from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"When do you think you realized the world was ending? For me, it was that " +"damned YouTube video with the lady killing the baby. Holy shit, you know?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I wonder if the government's still out there, holed up in some bunker." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Remember some of the crazy news from the end of the world? The stuff that " +"got drowned out by the riot coverage I mean. Like, didn't the governor of " +"Rhode Island secede from the Union or something?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I keep having dreams that zombies still remember who they were as people, " +"and are just trapped inside the bodies watching everything happen. Haven't " +"been sleeping well." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Those mind-control drugs they put in the water to make people riot… you " +"think they're still in there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I can't stop wondering who fucked up to make all this happen. Obviously we " +"can't trust the news, they claimed the zombies were \"rioters\" for weeks. " +"Why? Where did this come from?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"If what they told us about the Chinese was even partly true, do you think " +"it's like this in China? Or maybe the US is some kind of quarantine zone, " +"and at least some of the world is still out there." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Have you noticed injuries aren’t healing the same as usual? I started " +"spotting it before the world ended, but it’s become more pronounced. " +"There’s hardly even a granulation step after a cut closes." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I still don’t understand how these zombies are powered. They’re like " +"perpetual motion machines." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"So many parts of this still don't fit together. Who created the zombies? " +"What powers them? Maybe the rumours of mind control drugs were true all " +"along, and someone found a way to bioengineer living dead." +msgstr "" + +#: lang/json/snippet_from_json.py lang/json/talk_topic_from_json.py +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"How do these zombies even keep going? What are they eating? Do you think " +"they'll ever rot away?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"I been thinkin', one of these days, we're gonna run out of toilet paper. " +"What then?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Do you think it’s weird how we’ll, like, open a locked building and find a " +"lone zombie inside? How’d it even get there?" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"Sometimes I wonder if we're all psychos, not just the ones that went crazy " +"and rioted. I never would have thought I could do the things I've done " +"since the world ended." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "You read any good books lately? I'm glad we still got books." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"You know what I miss? Movie theaters. You think Hollywood survived this? " +"Maybe there's a bunch of zombie actors out there, filmin' shit out of " +"reflex. Hah, I'd watch that shit." +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "I hear you, …" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "That reminds me of something…" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "Right, right. Say, you ever thought about…" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "\n" @@ -151712,6 +153641,14 @@ msgstr "" "這是 Rivtech 牌的槍械廣告。上面畫著一個中央被炸開大洞的裝甲鋼板。還有一堆色彩鮮豔的無殼彈藥放在旁邊。標題寫著: \"用 Rivtech " "8x40mm 無殼子彈, 沒有什麼能靠近你。\"" +#: lang/json/snippet_from_json.py +#, no-python-format +msgid "" +"This is an advertisement for SUDS Laundromat. It shows words surrounded by " +"bubbles that appear to be floating upward. It reads: \"Tergitol Tuesdays! " +"50% off on all washers and driers!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a propaganda poster showing the Northrop Dispatch's military " @@ -151721,6 +153658,21 @@ msgid "" " reads: \"WE ARE HERE TO PROTECT YOU.\"" msgstr "" +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Iron Gym. It shows pictures of people " +"performing various exercises such as running, yoga and weight lifting. It " +"reads: \"I lift things up and put them down!\"" +msgstr "" + +#: lang/json/snippet_from_json.py +msgid "" +"This is an advertisement for Space Time Inc. It has pictures of astronauts " +"floating around a spaceship with the Moon in the background. It reads: " +"\"Own your own piece of the Moon! For only $29.99 a month, you can have " +"prime real estate amongst the stars!\"" +msgstr "" + #: lang/json/snippet_from_json.py msgid "" "This is a public notice from the Centers for Disease Control. Its message, " @@ -162997,12 +164949,12 @@ msgid "Acolyte." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You're back. Have you come to listen to the song?" -msgstr "你回來了。你有來聽這首歌嗎?" +msgid "You're back. Have you come to listen to the song?" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "You there. Quiet down. Can you hear it? The song?" -msgstr "你那邊。靜下來。你能聽見嗎?這首歌?" +msgid "You there. Quiet down. Can you hear it? The song?" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "What? What do you mean? What song?" @@ -163036,8 +164988,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Listen carefully. The bones… they sing. Can you hear it? The song they " -"weave? The stories they hold?" +"Listen carefully. The bones… they sing. Can you hear it? The song they " +"weave? The stories they hold?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -163050,11 +165002,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"When it all happened, the Cataclysm, something… changed. You can see it in " -"all creatures, but most of all their bones. They break, morph, rise again, " -"in an infinite cycle. Living dead walk. Monsters rip and tear each other " -"apart. You can see the resonance, the quiet hum of raw strength, and only by" -" taking the bones does the cycle end - their story, their song, their " +"When it all happened, the Cataclysm, something… changed. You can see it in " +"all creatures, but most of all their bones. They break, morph, rise again, " +"in an infinite cycle. Living dead walk. Monsters rip and tear each other " +"apart. You can see the resonance, the quiet hum of raw strength, and only " +"by taking the bones does the cycle end - their story, their song, their " "strength, become yours to use." msgstr "" @@ -163072,11 +165024,11 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Only when you crush the bones of a body does it cease to rise. Only if you " -"examine the bones can you see what was. Thus is the story. Whatever causes " -"this change is alive, moving within us all, an inevitable part of this new " -"world. It holds the power of change. When we hold the bones, we hold the " -"power. Thus the strength. Together… they form a beautiful song." +"Only when you crush the bones of a body does it cease to rise. Only if you " +"examine the bones can you see what was. Thus is the story. Whatever causes" +" this change is alive, moving within us all, an inevitable part of this new " +"world. It holds the power of change. When we hold the bones, we hold the " +"power. Thus the strength. Together… they form a beautiful song." msgstr "" #: lang/json/talk_topic_from_json.py @@ -163085,7 +165037,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"There are others who follow this cause. You'd do well to aid them, for " +"There are others who follow this cause. You'd do well to aid them, for " "though we may not be numerous, we are emboldened by the songs we carry." msgstr "" @@ -163099,10 +165051,10 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The song can be weaved in many forms. Carved bone charms, weapons and armor " -"all hold immense power, and when the time comes, me and my kindred shall " -"gather a great amount of song and sing it to restore this world. Restore it," -" or end it. Makes no difference." +"The song can be weaved in many forms. Carved bone charms, weapons and armor" +" all hold immense power, and when the time comes, me and my kindred shall " +"gather a great amount of song and sing it to restore this world. Restore " +"it, or end it. Makes no difference." msgstr "" #: lang/json/talk_topic_from_json.py @@ -163112,7 +165064,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "We believe that enough power in one song could revert the Cataclysm - or " -"accelerate it to a time beyond all, ending it all the same. But with the " +"accelerate it to a time beyond all, ending it all the same. But with the " "world looking as is, both options are preferable." msgstr "" @@ -163128,8 +165080,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your mind is open. More than most. Perhaps one day, you too will feel the " -"power of the song and become Kindred. For now, Acolyte, listen, listen and " +"Your mind is open. More than most. Perhaps one day, you too will feel the " +"power of the song and become Kindred. For now, Acolyte, listen, listen and " "feel the song." msgstr "" @@ -163139,9 +165091,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Your skepticism does not surprise me. Perhaps one day, you too will hear the" -" inevitability of the song, feel its power. But until then, you will remain " -"an Acolyte, path to the Kindred closed." +"Your skepticism does not surprise me. Perhaps one day, you too will hear " +"the inevitability of the song, feel its power. But until then, you will " +"remain an Acolyte, path to the Kindred closed." msgstr "" #: lang/json/talk_topic_from_json.py @@ -163199,14 +165151,6 @@ msgstr "" msgid "Perhaps another time, Seer." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"If you wish to be set on the path to enlightenment, first you must learn to " -"listen and hear the song. Go out, butcher a creature and feel the power " -"between your fingertips. Then bring me the bones and I shall carve them for " -"you. " -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Well, I guess I oughta see where this goes. I'm in." msgstr "" @@ -163215,10 +165159,6 @@ msgstr "" msgid "Not interested." msgstr "沒興趣。" -#: lang/json/talk_topic_from_json.py -msgid "Excellent. Now be on your way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Consider it done. But I also wanted to ask…" msgstr "" @@ -163235,20 +165175,13 @@ msgstr "" msgid "I'm off then." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"The shambling corpses we see all around move in discord. Their song can be " -"used, but for an Acolyte, this would be needlessly hard. Be sure to carve an" -" unspoiled living creature." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "So, a creature that isn't a zombie, or a monster. Got it." msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"The path to enlightenment is for you to walk. For me to aid you would " +"The path to enlightenment is for you to walk. For me to aid you would " "ultimately impede your progress and muddle your song." msgstr "" @@ -163259,7 +165192,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "You bear my mark, meaning I believe you have potential to learn to truly " -"listen to the Song. Yes, I will lend my skills to you, for now." +"listen to the Song. Yes, I will lend my skills to you, for now." msgstr "" #: lang/json/talk_topic_from_json.py @@ -163274,11 +165207,6 @@ msgstr "" msgid "That's good, but I need to go at it alone right now. Maybe later." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "" -"I understand your reluctancy. Feel free to return when you see the way." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Maybe some other time. Changing the topic…" msgstr "" @@ -163290,14 +165218,14 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's not just walking horrors and monsters that have changed with the " -"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only " -"see it in others, but it happens to us, even you and I. How many times have " -"you fallen? Your flesh rent from your body, devoured. Or perhaps it was the " -"quiet whimper of death to exposure. But your bones rose again. Different " -"flesh, different name, sometimes even different knowledge, but the bones, " -"the same. We are all trapped in the same cycle. We just keep forgetting. " -"That's why we need to amass the Song. That's why it has to end, even if it " -"means the destruction, not restoration." +"Cataclysm. It started a… cycle, of sorts. Everything repeats. We can only" +" see it in others, but it happens to us, even you and I. How many times " +"have you fallen? Your flesh rent from your body, devoured. Or perhaps it " +"was the quiet whimper of death to exposure. But your bones rose again. " +"Different flesh, different name, sometimes even different knowledge, but the" +" bones, the same. We are all trapped in the same cycle. We just keep " +"forgetting. That's why we need to amass the Song. That's why it has to " +"end, even if it means the destruction, not restoration." msgstr "" #: lang/json/talk_topic_from_json.py @@ -163324,6 +165252,14 @@ msgstr "忘掉我問的東西吧。" msgid "Skip it, let's get going." msgstr "跳過它,我們繼續。" +#: lang/json/talk_topic_from_json.py +msgid "Any hints about the world we now live in?" +msgstr "關於我們現在生活的世界有什麼提示嗎?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's talk about faction camps." +msgstr "我們來談談陣營營寨。" + #: lang/json/talk_topic_from_json.py msgid "What do you mean, \"mostly\" willing to follow my lead?" msgstr "" @@ -163483,13 +165419,13 @@ msgstr "" msgid "" "Hey, I'm a doctor! I know how to treat trauma. You give me some bandages " "or a bottle of antiseptic, I'm get you fixed when I see you hurting." -msgstr "" +msgstr "嘿,我是個醫生!你只要給我一些繃帶或一瓶消毒劑,當我看到你受傷時我就會治好你。" #: lang/json/talk_topic_from_json.py msgid "" "Yeah, I can perform first aid. You give me some bandages or a bottle of " "antiseptic, I'll treat your wounds as best I can." -msgstr "" +msgstr "嗯,我能進行急救。你給我一些繃帶或一瓶消毒劑,我會盡我所能治療你的傷口。" #: lang/json/talk_topic_from_json.py msgid "" @@ -163504,7 +165440,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I can help with some tasks if you show me where to work.\n" -" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" +" Use the zone manager (keybind 'Y') to set up sorting zones for your loot, or to draw blueprints for a building, or to define where you want to plant some crops, or where you'd like some trees cut down, or where you want a vehicle dismantled or repaired, or a good fishing spot. Then talk to me about my current activity and tell me to sort stuff, or build stuff, or cut down trees, or repair or dismantle a vehicle, or do farmwork, or catch some fish, and I'll go off and do my best to get what you want done.\n" " If I need tools, you should leave them in a loot zone near where you want me to work - axes for logging, shovels and seeds and fertilizer for farming, wrenches and hacksaws or a toolbox to take apart a vehicle. I promise to put stuff back in an unsorted loot zone when I'm finished.\n" " I can pretty much sort out our stuff without needing tools, but keep the piles of unsorted and sorted stuff kind of close together because I don't want to walk back and forth carrying junk too much." msgstr "" @@ -163667,8 +165603,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"STOP, Put your hands in the air! Ha, startled you didn't I…there is no law " -"anymore..." +"STOP, Put your hands in the air! Ha, startled you didn't I… there is no law" +" anymore…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -163690,7 +165626,7 @@ msgstr "我要走了。" #: lang/json/talk_topic_from_json.py msgid "" "I was watching the station when things went sideways. None of the other " -"officers returned from the last call, well not as humans anyway..." +"officers returned from the last call, well not as humans anyway…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -163742,8 +165678,8 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "No, just no..." -msgstr "不要, 就只是不要" +msgid "No, just no…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Just let me sleep, !" @@ -163754,8 +165690,8 @@ msgid "Make it quick, I want to go back to sleep." msgstr "快一點啦, 我想要回去睡覺了。" #: lang/json/talk_topic_from_json.py -msgid "Just few minutes more..." -msgstr "再幾分鐘就好…" +msgid "Just few minutes more…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Anything to do before I go to sleep?" @@ -163800,6 +165736,68 @@ msgstr "我想給你一些戰鬥命令。" msgid "I want to set some miscellaneous rules." msgstr "我想設定一些行動規則。" +#: lang/json/talk_topic_from_json.py +msgid "I'd like to know a bit more about your abilities." +msgstr "我想進一步了解你的能力。" + +#: lang/json/talk_topic_from_json.py +msgid "There's something I want you to do." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I just wanted to talk for a bit." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you help me understand something? (HELP/TUTORIAL)" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I'm going to go my own way for a while." +msgstr "我要暫時分開一會。" + +#: lang/json/talk_topic_from_json.py +msgid "Let's go." +msgstr "我們走。" + +#: lang/json/talk_topic_from_json.py +msgid "" +" *tshk* Are you serious? This isn't a cell phone. Can it wait until we're " +"in the same place?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what did you want to say?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Mind if we just chat for a bit about your history?" +msgstr "介意我們閒聊一下你的過去嗎?" + +#: lang/json/talk_topic_from_json.py +msgid "Let's just chitchat for a while, I could use some relaxation." +msgstr "讓我們閒聊一會兒,我可以放鬆一下。" + +#: lang/json/talk_topic_from_json.py +msgid "I changed my mind, wanted to ask you something else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I'm all ears, my friend." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You gonna give me orders?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What would you like?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Just say the word." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Can you teach me anything?" msgstr "你可以教我些東西嗎?" @@ -163824,14 +165822,6 @@ msgstr "守護這個地點。" msgid "I want to assign you to work at this camp." msgstr "我想指派你在這個營寨工作。" -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about your current activity." -msgstr "我們來談談你目前的行動。" - -#: lang/json/talk_topic_from_json.py -msgid "Let's talk about faction camps." -msgstr "我們來談談陣營營寨。" - #: lang/json/talk_topic_from_json.py msgid "Find a horse and mount up!" msgstr "找匹馬,騎上馬!" @@ -163845,32 +165835,20 @@ msgid "Please go to this location." msgstr "請到這個地點。" #: lang/json/talk_topic_from_json.py -msgid "I'd like to know a bit more about your abilities." -msgstr "我想進一步了解你的能力。" - -#: lang/json/talk_topic_from_json.py -msgid "Any hints about the world we now live in?" -msgstr "關於我們現在生活的世界有什麼提示嗎?" - -#: lang/json/talk_topic_from_json.py -msgid "Mind if we just chat for a bit about your history?" -msgstr "介意我們閒聊一下你的過去嗎?" - -#: lang/json/talk_topic_from_json.py -msgid "Let's just chitchat for a while, I could use some relaxation." -msgstr "讓我們閒聊一會兒,我可以放鬆一下。" +msgid "I want you to build a camp here." +msgstr "我要你在這裡建立一個營寨。" #: lang/json/talk_topic_from_json.py -msgid "Tell me about giving you orders (NPC TUTORIAL)." -msgstr "告訴我有關向你下命令的內容(NPC 教程)。" +msgid "We need to abandon this camp." +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "I'm going to go my own way for a while." -msgstr "我要暫時分開一會。" +msgid "Show me what needs to be done at the camp." +msgstr "告訴營寨還需要什麼。" #: lang/json/talk_topic_from_json.py -msgid "Let's go." -msgstr "我們走。" +msgid "Let's talk about your current activity." +msgstr "我們來談談你目前的行動。" #: lang/json/talk_topic_from_json.py msgid "*will not engage enemies." @@ -164412,10 +166390,6 @@ msgstr "" msgid "Stay at your current position." msgstr "留在原地。" -#: lang/json/talk_topic_from_json.py -msgid "Show me what needs to be done at the camp." -msgstr "告訴營寨還需要什麼。" - #: lang/json/talk_topic_from_json.py msgid "I'm currently ." msgstr "我目前 。" @@ -164488,60 +166462,6 @@ msgstr "* 嗤嗤* 十 - 四,我會去那裡,完畢。" msgid "Sure thing, I'll make my way there." msgstr "當然,我會去那裡。" -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Yeah, this summer heat is hitting me hard, let's take a quick break, how " -"goes it ?" -msgstr "是的,夏天的炎熱使我難受,讓我們休息一下,,如何?" - -#: lang/json/talk_topic_from_json.py -msgid "OK, maybe it'll stop me from freezing in this weather, what's up?" -msgstr "好吧,也許這能不讓我在這種天氣被凍僵,如何?" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Well, it's the time of day for a quick break surely! How are you holding " -"up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Man it's dark out isn't it? what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Well, I'm feeling pretty sick… are you doing OK though?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Definitely, by the way, thanks for helping me so much with my tasks! " -"Anyway, you coping OK, ? " -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"OK, let's take a moment, oh, and thanks for helping me with that thing, so… " -"what's up?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "" -"Now, we've got a moment, I was just thinking it's been a month or so since… " -"since all this, how are you coping with it all?" -msgstr "" - -#: lang/json/talk_topic_from_json.py -msgid "Oh you know, not bad, not bad…" -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "" msgstr "" @@ -164596,8 +166516,8 @@ msgid "Hello there." msgstr "哈囉你好。" #: lang/json/talk_topic_from_json.py -msgid "Okay, no sudden movements..." -msgstr "很好, 別突然亂動…" +msgid "Okay, no sudden movements…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep your distance!" @@ -164949,8 +166869,8 @@ msgid "Ah, okay." msgstr "啊,好的。" #: lang/json/talk_topic_from_json.py -msgid "Not until I get some antibiotics..." -msgstr "我還沒找到抗生素…" +msgid "Not until I get some antibiotics…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "You asked me recently; ask again later." @@ -165057,8 +166977,8 @@ msgid "I can't train you properly while I'm operating a vehicle!" msgstr "我在駕駛車輛時無法訓練你。" #: lang/json/talk_topic_from_json.py -msgid "Give it some time, I'll show you something new later..." -msgstr "給我點時間, 我會讓你看些新玩意…" +msgid "Give it some time, I'll show you something new later…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I have some reason for denying you training." @@ -165085,8 +167005,8 @@ msgid "See you around." msgstr "待會見。" #: lang/json/talk_topic_from_json.py -msgid "I really don't feel comfortable doing so..." -msgstr "這麼做讓我不是很舒服…" +msgid "I really don't feel comfortable doing so…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "I'll give you some space." @@ -165157,8 +167077,8 @@ msgid "Thanks, see you later!" msgstr "謝了, 待會見!" #: lang/json/talk_topic_from_json.py -msgid "You picked up something that does not belong to you..." -msgstr "你拿了不屬於你的東西..." +msgid "You picked up something that does not belong to you…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Okay, okay, this is all a misunderstanding. Sorry, I'll drop it now." @@ -165251,13 +167171,13 @@ msgid "You might be seeing more of me…" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hey again. *kzzz*" +msgid "Hey again. *kzzz*" msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first person " -"I've seen in a long time." +"I… I'm free. *Zzzt* I'm actually free! *bzzz* Look, you're the first " +"person I've seen in a long time." msgstr "" #: lang/json/talk_topic_from_json.py @@ -165279,7 +167199,7 @@ msgid "Sorry, I'm nobody. Enjoy your freedom, I guess." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "*buzz* Great! So what happens now?" +msgid "*buzz* Great! So what happens now?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -165292,7 +167212,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"...Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " +"…Wait. *BEEP* Why do I believe you? *ZZZT* You could be just as bad as " "them!" msgstr "" @@ -165314,7 +167234,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" +"Okay, okay, *BUZZ* I'm sorry! Don't hurt me again! Anything but the chip!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -165330,7 +167250,7 @@ msgid "No, *I'm* sorry, I didn't mean that. Go do what you want." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...kill… *ZTZTZT* …you!" +msgid "…kill… *ZTZTZT* …you!" msgstr "" #: lang/json/talk_topic_from_json.py @@ -165365,14 +167285,6 @@ msgstr "告訴我陣營營寨如何運作。" msgid "Tell me how faction camps have changed." msgstr "跟我說說陣營營寨有甚麼變化。" -#: lang/json/talk_topic_from_json.py -msgid "I want you to build a camp here." -msgstr "我要你在這裡建立一個營寨。" - -#: lang/json/talk_topic_from_json.py -msgid "We need to abandon this camp." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Nothing. Let's talk about something else." msgstr "沒事。 我們談點別的吧。" @@ -165601,8 +167513,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Are you sure? This doesn't seem like a particularly safe place for small " -"talk..." -msgstr "你確定嗎?這裡看起來不太安全呢,不太適合閒聊..." +"talk…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "It's fine, we've got a moment." @@ -165624,6 +167536,50 @@ msgstr "你想談什麼?" msgid "Actually, never mind." msgstr "其實,沒關係。" +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid " " +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Yes, friend?" msgstr "是的,朋友?" @@ -165645,7 +167601,7 @@ msgid "May the earth flourish beneath our paths." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Unity of spirit, of mind, and body..." +msgid "Unity of spirit, of mind, and body…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -165829,8 +167785,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"I grew up on the farm, I don't know much about ghosts and goblins, but I've" -" spent a lot of time growing food and I work hard. It's better in the " +"I grew up on the farm, I don't know much about ghosts and goblins, but I've " +"spent a lot of time growing food and I work hard. It's better in the " "country, cleaner. Not as dangerous. I hope." msgstr "" @@ -166404,8 +168360,8 @@ msgid "Nevermind me, I'm just going to leave." msgstr "別在意我,我要走了。" #: lang/json/talk_topic_from_json.py -msgid "Indeed it is I! The one and only FOODPERSON!" -msgstr "確實是我!唯一的美食人!" +msgid "Indeed it is I! The one and only FOODPERSON!" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Wow! Such an honor to meet you in person!" @@ -166848,6 +168804,38 @@ msgstr "" msgid "Huh." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I barely understand what's going on *now*. Why do you think I'd know how " +"the world ended?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"OK, fine. Can you at least tell me what you remember about the events " +"leading up to now?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What, don't you remember? No, sorry, that's not fair, it was a weird time." +" OK, well, I guess this all started with the riots, didn't it? We were " +"just leading our lives, doing our jobs, and then people started rioting. " +"Not the usual protests that turned violent or anything, either, people just " +"left their houses and started breaking shit. The news tried to downplay it " +"but they couldn't keep it off the internet. I don't know what caused it, " +"they said it was some kind of drug or toxin in the water? Still, I didn't " +"really realize how bad it was getting at first. Somewhere along the way the" +" \"rioters\" started getting up and walking around with holes in their " +"chests, and that's when the real panic took over. The next few days - or " +"weeks, not really sure - are a blur to me. You'd have to ask someone else " +"how we got from there to total collapse." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for filling me in." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was a cop. Small town sheriff. We got orders without even really knowing" @@ -166900,8 +168888,8 @@ msgid "" "tented around me. I wasn't even too badly hurt. I grabbed as much gear as " "I could, and I slipped out. It was night. I could hear fighting farther " "away in the city, so I went the other way. I made it a few blocks before I " -"ran into any ... I ran from them. I ran, and I ran, and I ran " -"some more. And here I am." +"ran into any … I ran from them. I ran, and I ran, and I ran some " +"more. And here I am." msgstr "" #: lang/json/talk_topic_from_json.py @@ -167167,6 +169155,30 @@ msgstr "" msgid "Thanks for telling me that stuff. " msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"So, like, there were some really bad riots, okay? Everyone got realy " +"violent and nasty, and to be honest, I was on a bit of a spirit journey for " +"a lot of it and I don't really remember too well. But the weirdest part is," +" nobody even *cared* about each other. It's like all our caring got sucked " +"away. I think it was some kind of negative energy thing. And also that " +"made the dead, like, come back to life and stuff. Plus, like, there were " +"some monsters? I'm not really sure how they fit in." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You seem to know a lot, what do you think caused it all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"That's a tough one, but I keep thinking back to this dream I had like, a " +"year before it all started. I dreamed there was this big ball of evil " +"energy that was just waiting to suck up all the good thoughts on the earth " +"and turn us into monsters and things? So I guess that's what I think " +"happened. Everything else just seems too far-fetched, you know?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I made it to one of those evac shelters, but it was almost worse " @@ -167216,6 +169228,24 @@ msgid "" "died in the crash, but I am not going back to find out." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"What happened? I'm not really sure. You must know about the riots and all " +"that, that the government and the police totally failed to contain. I don't" +" have a good guess what caused that. I thought it was the usual stuff at " +"first, and I gotta admit, I was sort of excited and scared it was the start " +"of a revolution. Not excited enough to join in though, and I guess anyone " +"who was is probably dead now. I tried to wait it out at home, packed a " +"little bug-out bag, but then the internet started showing videos of rioters " +"getting back up and fighting with crazy injuries. I don't know how many " +"people really believed it at first, but I took that as my sign and ditched " +"town for the evac shelter. I don't know exactly what happened after that. " +"The center I was in was heavily vandalized and empty, and I never saw anyone" +" else. The cell phone grid was locked up, except for one emergency message " +"that came through around a day later saying the government had fallen. " +"Power went out a few days later." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as most people who didn't get killed straight up during the riots. I " @@ -167249,6 +169279,21 @@ msgstr "" msgid "What do you think happened? You see them around anywhere?" msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I assume you know about the riots and the military and police and the " +"freakin' nightmare monsters walking the earth beside zombies, right? If " +"you're asking what I think caused it all, well, I dunno. My best guess it " +"was some huge government overreach, maybe some kind of experimental " +"bioweapon that got away. They tried to lie so much at the start about " +"everything that was going on, I don't think the whole 'Chinese attack' shit " +"measures up. They were trying to cover something up. As for the real end " +"times, maybe the rest of the world tried to contain it. I heard there were " +"honest-to-god nukes going off here on American soil. To me that seems like " +"somewhere else, maybe Europe, trying to get whatever is going on here " +"contained. Maybe it even worked. It's bad now but it's not like it was." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "There's nothing too special about me, I'm not sure why I survived. I got " @@ -167305,6 +169350,40 @@ msgid "" "pretty good life compared to those first few months." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woah, , I don't even know where to start. The riots? I think it " +"was going on sooner than that. There were bad murmurs going on a few weeks " +"before that happened. Lots of really scary crimes, not your usual stuff but" +" like cannibalism and some real unspeakable shit, you know? When the riots " +"started, I think I was already primed to think of it as something different " +"from a normal equality riot or anything like that. I think that's part of " +"how I got out safer, I had had some time to get some stuff and get going, " +"and didn't try to make shopping trips. People were abso-fuckin-lutely crazy" +" in those days. It was a lot like the pandemic a few years back, except the" +" police were out in the streets in force, gunning people down like it was " +"going out of style." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Do you have any idea what the actual cause was?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Not really. Government fed us all kinds of conflicting stories, and there " +"was some absolutely heinous stuff going on. I mean, you can't have missed " +"that video of the woman killing her own baby, right? God, that still gives " +"me nightmares. I don't know what it was about it, something about the look " +"on her face. Worse stuff came out of course, and now we've both seen worse " +"things with our own eyes, but that one still comes back to haunt me. " +"Anyway, they never could control the riots, and by the time the rioters " +"started turning into undead it was way too late. I don't know if morale " +"just broke or what but I heard rumours the military and police started " +"turning on each other as much as the crowds. What actually made the dead " +"come back to life though? I haven't got a clue." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "They were shipping me with a bunch of evacuees over to a refugee center, " @@ -167313,6 +169392,50 @@ msgid "" "out of there." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "Don't leave me hanging, what happened next?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I ran until I felt like my lungs were going to jump right out of my mouth. " +"I holed up in the forest for the night, under a fir tree. In the morning I " +"heard someone talking, so I went to see. I was playing it pretty careful " +"though, there were still a lot of psychos and rioters around. I snuck up on" +" some kind of thing, some monster worse than any zombie. Some huge bug " +"thing, saying random phrases like some kind of broken tape recorder. It was" +" dragging a few human bodies behind it, I couldn't tell if they were dead or" +" unconscious. Honestly I didn't wait to find out, I ducked into the bushes " +"and tried not to breath until I couldn't hear it anymore." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Where did you go from there?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Once I was okay leaving the bushes, I made my way to an old shed I could see" +" a ways off. It was falling in but it kept the rain and wind off and gave " +"me a place out of sight. I stayed there until I ran out of those ass-" +"tasting ration bars I'd filled my backpack with. Then I took on the " +"wanderin' life until we met." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What's this, some kinda Back to the Future thing? How could you not know " +"what happened? The world damn well ended, that's what. And it didn't start" +" with an earthquake, birds, snakes, or aeroplanes. It started with riots, " +"and they had to dispatch cops and then the military to take care of the " +" criminals. The government tried to pad it claiming it was some kind" +" of mind control, but I didn't see too much different from the usual " +"bullshit: entitled babies looking for an excuse to break the law. It just " +"got way worse, this time, until it was time to get out of dodge. I heard " +"rumours they were even bombing some of the urban centers to try to control " +"it - which, I have to admit, is maybe a bit too hard-core." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My Evac shelter got swarmed by some of those bees, the ones the size of " @@ -167354,6 +169477,27 @@ msgstr "" msgid "Right. Sorry." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay listen. Don't believe that government stuff. There's a common thread " +"to all of it: the riots, the military failing to contain it, even the giant " +"monsters they said were appearing in the last few days and had to be wiped " +"out with nukes." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You've got my attention." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"You ever see the Matrix? This is it. In real life. To keep us locked in " +"here, the creators of the simulation have to make sure we're just the right " +"level of miserable. I think their algorithms got messed up though, and went" +" into overdrive, because all this is a little implausible. Still, I guess " +"we're still jacked in, so maybe it's working." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Well, I was at home when the cell phone alert went off and told me to get to" @@ -167366,6 +169510,19 @@ msgid "" " No idea what happened to all those people." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I gotta be honest with you, I heard a lot of stories back at the shelter, " +"and only one of them really stuck. This is some kind of science experiment " +"gone wrong. I don't know what caused the riots and the undead in the first " +"place, but there's no way it's this out of control everywhere. Yeah, I got " +"the same 'the government has fallen' text as everyone, but it doesn't make " +"*sense* that it could be so widespread so fast. I think we're in some sort " +"of exclusion zone, where they're letting whatever is going on run its course" +" to see how it works so they can fight it better next time. Somewhere out " +"there, outside the zone, it's more or less business as usual." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "That's a tall order. I guess the short version is that I got evacuated to a" @@ -167437,6 +169594,42 @@ msgstr "" msgid "Sorry for asking. " msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Woof, you ready for a real hot take? The government did this to us." +" Intentionally, or at least sort-of intentionally." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Oh?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Damn right. They lied to us for god knows how long about what was going on " +"because they didn't want us to figure it out. It probably started as a way " +"to keep the people in line, but it backfired somehow. My guess is they " +"tried to de-educate us, tried to mislead us, and when that wasn't working " +"they tried actual drugs in the water to make us stupid or something. " +"Instead of just stupid, some people got violent. Then they tried to " +"leverage that to put in martial law, but that didn't work and they wound up " +"fighting hordes of people. Only they didn't realize their brain " +"drugs were some kind of mutagen that turn people into zombies." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What about all the other stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I think it's mostly mutation. I don't know what they used, but it's some " +"real mad science shit, I didn't think most of this was even possible. I " +"also wonder if whatever they put in the water has made us a bit crazy. " +"Maybe some of this is just a hallucination? That one blows my mind a bit, " +"I'm not sure I believe it but I got nothin' else." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I'm not from around here… You can probably tell from the accent, I'm from " @@ -168026,6 +170219,48 @@ msgid "" "woods. I wasn't doing a great job of it, so I'm kinda glad you showed up." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, so, hear me out. This might sound crazy, but we're dealing with the " +" walking dead, so I think I get a pass on that. You know your Greek " +"mythology at all?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not really. How is that relevant?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, why?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Okay, well, I know this sounds like an Indiana Jones B-plot, but I think " +"someone found Pandora's Box, the actual thing or close to it. I think they " +"tried to somehow harness it, to use the power in it for something. Maybe " +"even something good, who knows, the power of the gods seems like it would be" +" a green energy source to me. Whatever it was, they screwed it up, and " +"released it for real. Not just a metaphorical thing like in the stories, " +"but actually set the forces of Hades loose on Earth. Yeah, I know it's " +"farfetched, but like I said: I think I get a pass on that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What? Pandora's box?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"According to legend, Pandora was in the house of the gods and found an " +"unopened box. She decided to investigate, and when she opened it and " +"unthinkable horrors and diseases spilled out. Sound familiar?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Sure, what's that go to do with anything?" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I was home with the flu when the world went to shit, and when I recovered " @@ -168071,6 +170306,128 @@ msgstr "" msgid "Thanks for telling me all that. " msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"You mean what caused the riots and all that? Well, they told us it was a " +"Chinese bioweapon but I have troubles believing anyone could engineer a " +"bioweapon that could do all this. The only answer I can come up with, silly" +" though it sounds, is aliens." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You think this is an invasion?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, maybe, but I'd guess it's too disorganized to be a proper invasion. " +"If I had to guess, I'd say there was something locked in the polar ice. " +"Like, remember a few years back there was that big thing online about an " +"alien body found in the ice? I don't know if you remember but it was all " +"over the news for a while until it turned out to be a hoax. Only, since " +"then, I've seen some aliens walking around that look a *lot* like that ice " +"body. Maybe it wasn't a hoax, maybe that was a cover-up. So, maybe those " +"aliens had some kind of virus. It went around the world and infected " +"everything silently until, somehow, it activated and caused the violence and" +" monsters and mutations." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Let's not dance around it: I joined the riots, at first. I don't really " +"remember what I was thinking. I'd protested stuff like police brutality " +"before, but this was different. I didn't make a sign and go down there " +"expecting to chant and march, I grabbed a bat and went outside planning to " +"fuck shit up. I've never felt so angry before. The riots had already been " +"going on a while at that point, and to me, it just looked like the " +"government trying to squash the people again." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Those rioters had a reputation for being absolutely psycho." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Not many people made it out of the riots alive." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Yeah, you're telling me. The rioters… they weren't even like humans, let " +"alone protestors. Nothing like any protest I'd ever been in before. That " +"didn't stop me. I joined them, and I was as bad as a bunch of them. " +"Smashed windows, beat up bystanders, burnt cars. I remember ripping riot " +"gear off a cop and… nevermind. I don't want to remember that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How did you survive?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "What made you come back?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"At some point, I felt like I was waking up. It was around the time they " +"were busting out those humvees with riot control turrets on top. Says " +"something about my frame of mind that I don't even remember if I'd seen them" +" before that point. Anyway I heard the gunfire going off and just kinda " +"realized I was on the edges of a mob charging a heavily armed military " +"emplacement. That's when I started seeing the mob for what it was, seeing " +"the wild-eyed animals, even the zombies. I turned and ran." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I honestly don't know. I wonder if some of the others would have come back " +"to their senses, given time. I don't think I'm anything special. Maybe a " +"lot of them did, and just weren't on the edge of the crowd at the time. " +"I'll tell you, almost as soon as I came back to myself, I could see some of " +"the rioters looking at me like I was prey. I didn't stick around to see " +"what would happen." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I knew the city pretty well. I went for an abandoned building I knew about," +" headed through a broken window, and holed up in there for a few days. I " +"had a fair bit of stolen food and I just kept to myself. When things " +"started to quiet down, I headed out, and here I am." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"So, I remember the time leading up to the riots, same as anyone. Things " +"were bad, there were some really awful crimes being reported in the news, " +"and there was a lot of racial tension as usual from the way the cops were " +"handling it. Then people started rioting, which isn't unusual, but it was " +"weird the kind of places that the riots were starting in. Like, upper " +"middle class neighbourhoods, midwestern small towns, things like that. " +"Anyway, I joined the riots and I don't remember a lot of clear stuff after " +"that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You joined the riots?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "You must have some insights into what caused all this, then." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Kinda, I guess. I heard people blaming the riots on some kind of mind " +"control drug, and frankly I'm not sure that's far off base. That's kinda " +"what it felt like, although the whole time I really felt like myself. It " +"wasn't until I snapped out of it that I realized how weird it was. That " +"doesn't explain anything else though: the zombies, the monsters, all this " +"stuff is way off base. Anything I've tried to guess just sounds like bad " +"science fiction, like demonic curses or alien weapons kinda stuff." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "My husband made it out with me, but got eaten by one of those plant " @@ -168337,13 +170694,48 @@ msgstr "" msgid "I can respect that." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "I don't really want to talk about the time before, you know?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Keep it vague if you want, but please, can you fill me in a little?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"I - fine. Drugs in the water, some kind of bioweapon I guess. You know how" +" things were with China, they blamed it on them mostly. Made people violent" +" and ugly. There were riots. People I cared about joined them, and I guess" +" I'll never know why. Riots led to military and police action, which made " +"the riots worse. People acted like animals, not just the rioters but " +"everyone. Then came the monsters and nightmares walking the world like real" +" Armageddon, and everyone died, and started coming back as monsters " +"themselves. There's your story. If you want more, talk to someone else." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Thanks for that." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"To be honest… I don't really remember. I remember vague details of my life" +" before the world was like this, but itself? It's all a " +"blur. I think something pretty bad must have happened to me. I remember a " +"few things: snatches of violence, something about a woman killing her baby." +" I feel like I'd rather not remember." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "To be honest… I don't really remember. I remember vague details of my life" " before the world was like this, but itself? It's all a " "blur. I don't know how I got where I am now, or how any of this happened. " "I think something pretty bad must have happened to me. Or maybe I was just " -"hit in the head really hard. Or both. Both seems likely." +"hit in the head really hard. Or both. Both seems likely. First thing I " +"remember is seeing an already-read text on my phone from the emergency " +"government broadcast system, saying the United States had fallen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -168429,6 +170821,43 @@ msgid "" " ask again." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"You're asking me what I think caused all this? It was all over the news. " +"Some kind of Chinese bio-weapon. It's no different from the pandemic a few " +"years back, but this time they got the formula right. Maybe too right. " +"Doesn't matter anyway, I hear it got out on them and wiped them out too. " +"Serves em right." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "Can you tell me more about what actually went down, though?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "How does that explain all the other crazy stuff?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, you know. First there were the riots from the mind-control drugs in " +"the water. Except I think we can all see now it was actually a virus again." +" The military and the cops did their damndest to put it down but it got out" +" of hand. Then the virus mutated and started bringing the dead back to life" +" like in some kinda B-movie, and shit got really real. They let the big " +"things loose, or they set them on us, I dunno. Huge unspeakable monsters… " +"still makes me shudder to think of them. They obviously weren't built for " +"combat though, and the military took 'em down fast." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"What? Of course it does. They started with a bioweapon and then it went " +"full nuclear. Only the weapons we had now were a lot worse than H-bombs. " +"Uncle Sam managed to beat back the really nasty stuff, but I guess it was " +"with his dying breath." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Let's not talk about it, ok? It just hurts to think about. I've lost so " @@ -168722,7 +171151,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Tax evasion. I was an accountant, and I helped my boss move a hell of a lot" -" of money in some very clever ways. Not clever enough, it turns out..." +" of money in some very clever ways. Not clever enough, it turns out…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -168896,6 +171325,32 @@ msgid "" "odds." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"It's clear enough, isn't it? That… that end, was the Rapture. I'm still " +"here, and I still don't understand why, but I will keep Jesus in my heart " +"through the Tribulations to come. When they're past, I'm sure He will " +"welcome me into the Kingdom of Heaven. Or… or something along those lines." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "I meant more the actual events. What happened?" +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +"Oh. Well, I think it follows the good word in Revelations, if I remember " +"right. I haven't talked to a preacher in a bit, you know. There were the " +"plagues… the first one was the one a couple years ago, that big pandemic, " +"that was when people started talking about the end being near. Then there " +"was a plague of blood, or was it violence? That was the riots. Then the " +"seas turned red with blood, that was from all the people being shot. Then a" +" plague of fire, I remember that one for sure, that was when there were " +"bombs and things going off everywhere to try to contain the riots. And then" +" demons and monsters walked the Earth, and the dead rose from their graves, " +"and finally the meek inherited. Clear as day." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "Same as anyone. I turned away from God, and now I'm paying the price. The " @@ -168903,6 +171358,23 @@ msgid "" "Hell on Earth. I wish I'd paid more attention in Sunday School." msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"Well, I guess that was the Rapture. It didn't play out how I thought it " +"would. They made me think it was gonna be a flash of light and then *poof*," +" everyone's gone. Instead it was messy and dirty. Riots in the streets, " +"the military and police serving the Antichrist to gun down the people like -" +" what was it my dad used to say - like wheat before the chaff? Then when " +"we'd really showed our Sin, God came in with the real plagues. The dead " +"started walking, getting up with machine gun holes in them to fight the " +"military, and the military started turning on each other too. After that, " +"the legions of Hell itself came out. Huge monsters, worse than anything I'd" +" ever imagined, just tore through the cities ripping everything to shreds. " +"Then they started dying off as quick as they'd arrived, and we were left " +"trying to run and hide from the undead. A day or two later the power " +"started going out." +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "" "I lived alone, on the old family property way out of town. My husband " @@ -169116,10 +171588,6 @@ msgstr "" msgid "What was working for the Old Guard like?" msgstr "替舊日守衛工作是什麼感覺?" -#: lang/json/talk_topic_from_json.py -msgid "Thanks for that." -msgstr "" - #: lang/json/talk_topic_from_json.py msgid "Thanks for that. Let's get going." msgstr "" @@ -169331,6 +171799,22 @@ msgstr "" msgid "What were you saying before that?" msgstr "" +#: lang/json/talk_topic_from_json.py +msgid "" +"I'll be honest with you, I was paying more attention to wedding planning " +"than current events leading up to things. I knew there were riots going on," +" but they were out of town. Even when they got closer to home, I tried to " +"ignore them so we could have our big day. After the zombies started coming," +" though, well that's when stuff got really weird. When I was running from " +"the wedding I swear I saw the sky rip open and monsters fly out of the hole," +" like something out of Independence Day. I don't know what it all was, it " +"looked like black magic or something." +msgstr "" + +#: lang/json/talk_topic_from_json.py +msgid "" +msgstr "" + #: lang/json/talk_topic_from_json.py msgid "Hey there." msgstr "" @@ -169854,7 +172338,7 @@ msgid "You should get off my farm, I won't deal with a government stooge." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Go on..." +msgid "Go on…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -170251,10 +172735,6 @@ msgid "" " catastrophe." msgstr "" -#: lang/json/talk_topic_from_json.py -msgid "Go on ..." -msgstr "繼續 ..." - #: lang/json/talk_topic_from_json.py msgid "Tell me about your wife, is she around?" msgstr "告訴我關於你妻子的事,她在附近嗎?" @@ -171667,7 +174147,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " +"Gross, isn't it? Feels like pubes. I just started growing it everywhere a " "little while after the Cataclysm. No idea what caused it. I can't blame " "them for hating it, I hate it." msgstr "" @@ -172393,7 +174873,7 @@ msgid "" "Guitar's my baby. You like folk and the blues, friend? Well, that was my " "bag and I sure could please my own ear with em, anyway. Folks who's bein' " "generous might also say it pleased theirs. Problem is, I seem to be between" -" guitars right now, you know? Temporarily guitar-light, if you get my " +" guitars right now, you know? Temporarily guitar-light, if you get my " "saying. Problem is, in the run for my life, I had to use old Jasmine as a " "bit of a billy club. Had to curb some rowdy dudes on my way here. It was " "her or me, you understand? You wouldn't begrudge a man breakin' his " @@ -173455,12 +175935,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Dana and I were evacuated early, because of her pregnancy. They took us to a" -" concentration center, and then we got on a bus to come here. The bus " -"though, it was rolled over by a giant monster, and many died. We made it out" -" along with a few others, and we kept going until we made it here. It wasn't" -" much farther, and for some reason the monster didn't chase us, just kept " -"tearing at the bus." +"Dana and I were evacuated early, because of her pregnancy. They took us to " +"a concentration center, and then we got on a bus to come here. The bus " +"though, it was rolled over by a giant monster, and many died. We made it " +"out along with a few others, and we kept going until we made it here. It " +"wasn't much farther, and for some reason the monster didn't chase us, just " +"kept tearing at the bus." msgstr "" #: lang/json/talk_topic_from_json.py @@ -173588,12 +176068,12 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "It's a long, long story. I'm not from around here, I'm actually from way " -"out in Western Canada. I'd always wanted to see New England, and I was down " -"here on vacation when, well, you know. I got evacuated, but because I'm not" -" a US citizen they weren't willing to take me downstairs. I can understand " -"that, even if I don't like it much. To tell you the truth I'm still coming " -"to terms with the fact that I'll probably never know how my family and my " -"band are doing." +"out in Western Canada. I'd always wanted to see New England, and I was down" +" here on vacation when, well, you know. I got evacuated, but because I'm " +"not a US citizen they weren't willing to take me downstairs. I can " +"understand that, even if I don't like it much. To tell you the truth I'm " +"still coming to terms with the fact that I'll probably never know how my " +"family and my band are doing." msgstr "" #: lang/json/talk_topic_from_json.py @@ -173658,7 +176138,7 @@ msgid "Hm? Oh, hi." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "...Hi." +msgid "…Hi." msgstr "" #: lang/json/talk_topic_from_json.py @@ -174022,8 +176502,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Even once we got things sorted out, there weren't enough beds for everyone, " -"and definitely not enough supplies. These are harsh times. We're doing what" -" we can for those folks… at least they've got shelter." +"and definitely not enough supplies. These are harsh times. We're doing " +"what we can for those folks… at least they've got shelter." msgstr "" #: lang/json/talk_topic_from_json.py @@ -174040,9 +176520,9 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"We didn't have great organization when we first arrived. A few of the " +"We didn't have great organization when we first arrived. A few of the " "earliest arrivals set up a triage and sorting system, with the sick and " -"infirm getting set aside to wait. It's cruel, but we could see there was " +"infirm getting set aside to wait. It's cruel, but we could see there was " "only space for so many, and we didn't know what was causing people to turn " "into zombies at the time, so we were trying to quarantine out infection. A " "couple folks died in there, and it escalated. One of the first people here," @@ -174371,8 +176851,8 @@ msgid "" msgstr "我們不想容忍像垃圾一樣的你, 做完你的事, 然後滾。" #: lang/json/talk_topic_from_json.py -msgid "I'm not in charge here, you're looking for someone else..." -msgstr "我在這並不是管事的, 你應該要找別人…" +msgid "I'm not in charge here, you're looking for someone else…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Keep civil or I'll bring the pain." @@ -174419,12 +176899,12 @@ msgid "Well, I'd better be going. Bye." msgstr "我想我要走了,再見。" #: lang/json/talk_topic_from_json.py -msgid "Welcome marshal..." -msgstr "歡迎法警…" +msgid "Welcome marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Welcome..." -msgstr "歡迎…" +msgid "Welcome…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" @@ -174660,12 +177140,12 @@ msgid "" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Marshal..." -msgstr "法警…" +msgid "Marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Citizen..." -msgstr "公民…" +msgid "Citizen…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Can I trade for supplies?" @@ -175271,7 +177751,7 @@ msgstr "" msgid "" "Given the current context, we are willing to sell you a set of our protective gear: gas mask, suit and gear, at a considerable discount. We will sell it for two of our coins.\n" "\n" -"the intercom: Hmm wait, we might not have your size..." +"the intercom: Hmm wait, we might not have your size…" msgstr "" #: lang/json/talk_topic_from_json.py @@ -175459,16 +177939,16 @@ msgid "Now that you mention it, it does seem rather strange." msgstr "既然你提到它,它似乎真的很奇怪。" #: lang/json/talk_topic_from_json.py -msgid "Thinking I should go hunt something soon..." -msgstr "我想我應該盡快去獵點東西..." +msgid "Thinking I should go hunt something soon…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Wondering if things will get better someday..." -msgstr "想知道是否有一天會變得更好..." +msgid "Wondering if things will get better someday…" +msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Hmm? Nothing, I guess I just like resting in this place." -msgstr "嗯?沒什麼,我想我只是喜歡在這個地方休息。" +msgid "Hmm? Nothing, I guess I just like resting in this place." +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Have you ever noticed how… wait no, never mind." @@ -175507,8 +177987,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "Still plenty of outlaws in the roads, perhaps you should tend to your job, " -"marshal..." -msgstr "路上仍有很多不法分子,也許你該專心做好你的工作,法警..." +"marshal…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "You see anything you want, marshal?" @@ -175576,8 +178056,8 @@ msgid "I can't imagine what I'd need your assistance with." msgstr "我想不到會需要你的什麼幫助。" #: lang/json/talk_topic_from_json.py -msgid "Stand still while I get my clippers..." -msgstr "站著別動, 讓我把剪刀拿過來…" +msgid "Stand still while I get my clippers…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Thanks…" @@ -175955,8 +178435,8 @@ msgid "" msgstr "我個人並不需要。回收車輛的團隊需要更多幫手, 但他們通常都在前哨外面, 不容易碰見。" #: lang/json/talk_topic_from_json.py -msgid "Please leave me alone..." -msgstr "請離我遠一點…" +msgid "Please leave me alone…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "What's wrong?" @@ -175974,15 +178454,14 @@ msgstr "那真不幸。" #: lang/json/talk_topic_from_json.py msgid "" -"I don't know what you could do. I've tried everything. Just give me " -"time..." -msgstr "我不知道你能做些什麼。我嘗試了所有方法。給我點時間就好…" +"I don't know what you could do. I've tried everything. Just give me time…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "" "I keep getting sick! At first I thought it was something I ate but now it " -"seems like I can't keep anything down..." -msgstr "我一直在生病! 起初我還以為自己吃了壞東西, 但現在我吃什麼吐什麼…" +"seems like I can't keep anything down…" +msgstr "" #: lang/json/talk_topic_from_json.py msgid "Uhm." @@ -176103,8 +178582,8 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"Here? Fruits and berries. Maybe the occasional piece of farm equipment, but" -" you need crypto coins" +"Here? Fruits and berries. Maybe the occasional piece of farm equipment, " +"but you need crypto coins" msgstr "" #: lang/json/talk_topic_from_json.py @@ -176449,7 +178928,7 @@ msgstr "" #: lang/json/talk_topic_from_json.py msgid "" -"You look hungry friend. So much hunger in this world. This is the time of " +"You look hungry friend. So much hunger in this world. This is the time of " "the eaters." msgstr "" @@ -176618,7 +179097,7 @@ msgid "Happy to be of service to the great eaters. I'm in." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Excellent. Make it happen." +msgid "Excellent. Make it happen." msgstr "" #: lang/json/talk_topic_from_json.py @@ -176778,7 +179257,7 @@ msgid "Oh, you again." msgstr "" #: lang/json/talk_topic_from_json.py -msgid "Huh? *mumble mumble* … Who are you?" +msgid "Huh? *mumble mumble* … Who are you?" msgstr "" #: lang/json/talk_topic_from_json.py @@ -176786,7 +179265,7 @@ msgid "I'm busy, what is it?" msgstr "" #: lang/json/talk_topic_from_json.py -msgid "And leave my tower and all my research? I think not." +msgid "And leave my tower and all my research? I think not." msgstr "" #: lang/json/talk_topic_from_json.py @@ -181001,183 +183480,14 @@ msgid "" msgstr "" #: lang/json/terrain_from_json.py -msgid "dirt" -msgstr "土地" - -#. ~ Description for dirt -#: lang/json/terrain_from_json.py -msgid "" -"It's dirt. Looks like some fine soil for tillage. Could also be dug out " -"for construction projects." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "thump" -msgstr "咚" - -#. ~ Description for sand -#: lang/json/terrain_from_json.py -msgid "" -"A large area of fine sand that could be useful in a number of ways, if it " -"was extracted properly." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mud" -msgstr "泥巴" - -#. ~ Description for mud -#: lang/json/terrain_from_json.py -msgid "An area of wet, slick mud." -msgstr "濕滑的泥濘區域。" - -#: lang/json/terrain_from_json.py -msgid "clay" -msgstr "黏土" - -#. ~ Description for clay -#: lang/json/terrain_from_json.py -msgid "" -"A field full of malleable clay, suitable for kiln firing if it was extracted" -" properly." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "mound of clay" -msgstr "黏土堆" - -#. ~ Description for mound of clay -#: lang/json/terrain_from_json.py -msgid "A mound of clay soil." -msgstr "一堆黏土。" - -#: lang/json/terrain_from_json.py -msgid "splosh!" -msgstr "啪啦!" - -#: lang/json/terrain_from_json.py -msgid "mound of sand" -msgstr "沙堆" - -#. ~ Description for mound of sand -#: lang/json/terrain_from_json.py -msgid "A mound of sand." -msgstr "一堆沙子。" - -#: lang/json/terrain_from_json.py -msgid "mound of dirt" -msgstr "泥土堆" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"An area of heaped dirt, not easily traversable. If examined more closely, " -"it's quite favorable for planting seeds and the like." -msgstr "" - -#. ~ Description for mound of dirt -#: lang/json/terrain_from_json.py -msgid "" -"A giant hill of dirt that looks like you could crawl inside for shelter." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "odd fault" -msgstr "奇特的斷層" - -#. ~ Description for odd fault -#: lang/json/terrain_from_json.py -msgid "" -"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " -"strange sensation to examine it closer, as if it belongs to you somehow." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "grave" -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A dirt grave, with some grass growing on it. At least some of the dead do " -"actually rest in peace." -msgstr "" - -#. ~ Description for grave -#: lang/json/terrain_from_json.py -msgid "" -"A fresh grave, covered with stones, either to keep something from digging it" -" out or to keep one inside from digging out of it. Two planks mark this " -"place of someone's eternal rest." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "rock floor" -msgstr "岩石地板" - -#. ~ Description for rock floor -#: lang/json/terrain_from_json.py -msgid "" -"A relatively flat area of rock and stone. Looks stable enough to be mined " -"with the proper mining gear." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "pavement" -msgstr "路面" - -#. ~ Description for pavement -#: lang/json/terrain_from_json.py -msgid "" -"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" -" maintenance." +msgid "overgrown floor" msgstr "" -#: lang/json/terrain_from_json.py -msgid "yellow pavement" -msgstr "黃色路面" - -#. ~ Description for yellow pavement +#. ~ Description for overgrown floor #: lang/json/terrain_from_json.py msgid "" -"Streaks of carefully aligned yellow paint mark the road to inform drivers " -"not to cross. No one is enforcing these rules anymore." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "sidewalk" -msgstr "人行道" - -#. ~ Description for sidewalk -#: lang/json/terrain_from_json.py -msgid "" -"An area of common poured concrete, damaged by frost heaves and large cracks " -"due to lack of maintenance." -msgstr "" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles." -msgstr "" - -#. ~ Description for concrete -#: lang/json/terrain_from_json.py -msgid "" -"A newer segment of poured concrete with surface finishes for aesthetics and " -"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "wooden floor" -msgstr "木製地板" - -#. ~ Description for wooden floor -#: lang/json/terrain_from_json.py -msgid "" -"Wooden floor created from boards, packed tightly together and nailed down. " -"Common in patios." +"A bare concrete floor, almost completely covered by twitching filaments of " +"grey flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -181185,38 +183495,13 @@ msgid "SMASH!" msgstr "碰!" #: lang/json/terrain_from_json.py -msgid "metal floor" -msgstr "金屬地板" - -#. ~ Description for metal floor -#: lang/json/terrain_from_json.py -msgid "" -"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgid "overgrown wall" msgstr "" -#: lang/json/terrain_from_json.py -msgid "linoleum tile" -msgstr "油氈磚" - -#. ~ Description for linoleum tile +#. ~ Description for overgrown wall #: lang/json/terrain_from_json.py msgid "" -"A section of flooring made out of a tough, rubbery material. Colored a " -"simple white." -msgstr "" - -#. ~ Description for linoleum tile -#: lang/json/terrain_from_json.py -msgid "A section of flooring made out of a tough, gray, rubbery material." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "dirt floor" -msgstr "泥土地" - -#. ~ Description for dirt floor -#: lang/json/terrain_from_json.py -msgid "Floor consisting of finely mixed earth that has been tamped down." +"A concrete wall overgrown by a grotesque grid of veins and knotted flesh." msgstr "" #: lang/json/terrain_from_json.py @@ -181300,6 +183585,21 @@ msgid "" "smoothed and the roof isn't quite filled in yet." msgstr "" +#: lang/json/terrain_from_json.py +msgid "rock floor" +msgstr "岩石地板" + +#. ~ Description for rock floor +#: lang/json/terrain_from_json.py +msgid "" +"A relatively flat area of rock and stone. Looks stable enough to be mined " +"with the proper mining gear." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "metal floor" +msgstr "金屬地板" + #. ~ Description for metal floor #: lang/json/terrain_from_json.py msgid "" @@ -181307,6 +183607,10 @@ msgid "" " with a matching roof." msgstr "" +#: lang/json/terrain_from_json.py +msgid "thump" +msgstr "咚" + #: lang/json/terrain_from_json.py msgid "floor" msgstr "地板" @@ -181349,6 +183653,10 @@ msgid "" "resistance and sliding, commonly for recreational sports." msgstr "" +#: lang/json/terrain_from_json.py +msgid "dirt floor" +msgstr "泥土地" + #. ~ Description for dirt floor #: lang/json/terrain_from_json.py msgid "" @@ -181431,28 +183739,15 @@ msgid "A blue section of flooring." msgstr "" #: lang/json/terrain_from_json.py -msgid "industrial carpet" -msgstr "" - -#. ~ Description for industrial carpet -#: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, high-durability carpet in a neutral gray color, for laying " -"down on bare concrete." -msgstr "" - -#: lang/json/terrain_from_json.py -msgid "bunker carpet" +msgid "carpet" msgstr "" -#. ~ Description for bunker carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py -msgid "" -"Firm, low-pile, totally non-flammable carpet in a neutral cream color, with " -"an insulation layer beneath." +msgid "Base carpet!" msgstr "" -#. ~ Description for red carpet +#. ~ Description for carpet #: lang/json/terrain_from_json.py msgid "Soft red carpet." msgstr "柔軟的紅色地毯。" @@ -181472,6 +183767,124 @@ msgstr "柔軟的綠色地毯。" msgid "Soft purple carpet." msgstr "柔軟的紫色地毯。" +#: lang/json/terrain_from_json.py +msgid "Carpet" +msgstr "" + +#. ~ Description for Carpet +#: lang/json/terrain_from_json.py +msgid "Base concrete carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial red carpet" +msgstr "" + +#. ~ Description for industrial red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a red color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial yellow carpet" +msgstr "" + +#. ~ Description for industrial yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a yellow color, for laying down on" +" bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial green carpet" +msgstr "" + +#. ~ Description for industrial green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a green color, for laying down on " +"bare concrete." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "industrial purple carpet" +msgstr "" + +#. ~ Description for industrial purple carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, high-durability carpet in a purple color, for laying down on" +" bare concrete." +msgstr "" + +#. ~ Description for carpet +#: lang/json/terrain_from_json.py +msgid "Base metal carpet!" +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker red carpet" +msgstr "" + +#. ~ Description for bunker red carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a red color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker yellow carpet" +msgstr "" + +#. ~ Description for bunker yellow carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a yellow color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker green carpet" +msgstr "" + +#. ~ Description for bunker green carpet +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a green color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "bunker carpet purple" +msgstr "" + +#. ~ Description for bunker carpet purple +#: lang/json/terrain_from_json.py +msgid "" +"Firm, low-pile, totally non-flammable carpet in a purple color, with an " +"insulation layer beneath." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "linoleum tile" +msgstr "油氈磚" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "" +"A section of flooring made out of a tough, rubbery material. Colored a " +"simple white." +msgstr "" + +#. ~ Description for linoleum tile +#: lang/json/terrain_from_json.py +msgid "A section of flooring made out of a tough, gray, rubbery material." +msgstr "" + #: lang/json/terrain_from_json.py msgid "painted waxed floor" msgstr "" @@ -181506,6 +183919,33 @@ msgid "" "you like the sound of rain on corrugated metal." msgstr "" +#: lang/json/terrain_from_json.py +msgid "dirt" +msgstr "土地" + +#. ~ Description for dirt +#: lang/json/terrain_from_json.py +msgid "" +"It's dirt. Looks like some fine soil for tillage. Could also be dug out " +"for construction projects." +msgstr "" + +#. ~ Description for sand +#: lang/json/terrain_from_json.py +msgid "" +"A large area of fine sand that could be useful in a number of ways, if it " +"was extracted properly." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mud" +msgstr "泥巴" + +#. ~ Description for mud +#: lang/json/terrain_from_json.py +msgid "An area of wet, slick mud." +msgstr "濕滑的泥濘區域。" + #: lang/json/terrain_from_json.py msgid "moss" msgstr "" @@ -181515,6 +183955,30 @@ msgstr "" msgid "Moist spongy moss." msgstr "" +#: lang/json/terrain_from_json.py +msgid "clay" +msgstr "黏土" + +#. ~ Description for clay +#: lang/json/terrain_from_json.py +msgid "" +"A field full of malleable clay, suitable for kiln firing if it was extracted" +" properly." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "mound of clay" +msgstr "黏土堆" + +#. ~ Description for mound of clay +#: lang/json/terrain_from_json.py +msgid "A mound of clay soil." +msgstr "一堆黏土。" + +#: lang/json/terrain_from_json.py +msgid "splosh!" +msgstr "啪啦!" + #: lang/json/terrain_from_json.py msgid "paper floor" msgstr "" @@ -181524,6 +183988,131 @@ msgstr "" msgid "Floor made of pulpy mass, covered in sticky wasp saliva." msgstr "" +#: lang/json/terrain_from_json.py +msgid "mound of sand" +msgstr "沙堆" + +#. ~ Description for mound of sand +#: lang/json/terrain_from_json.py +msgid "A mound of sand." +msgstr "一堆沙子。" + +#: lang/json/terrain_from_json.py +msgid "mound of dirt" +msgstr "泥土堆" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"An area of heaped dirt, not easily traversable. If examined more closely, " +"it's quite favorable for planting seeds and the like." +msgstr "" + +#. ~ Description for mound of dirt +#: lang/json/terrain_from_json.py +msgid "" +"A giant hill of dirt that looks like you could crawl inside for shelter." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "odd fault" +msgstr "奇特的斷層" + +#. ~ Description for odd fault +#: lang/json/terrain_from_json.py +msgid "" +"An unnaturally humanoid-shaped hole, it seems oddly familiar. There's a " +"strange sensation to examine it closer, as if it belongs to you somehow." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "grave" +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A dirt grave, with some grass growing on it. At least some of the dead do " +"actually rest in peace." +msgstr "" + +#. ~ Description for grave +#: lang/json/terrain_from_json.py +msgid "" +"A fresh grave, covered with stones, either to keep something from digging it" +" out or to keep one inside from digging out of it. Two planks mark this " +"place of someone's eternal rest." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "pavement" +msgstr "路面" + +#. ~ Description for pavement +#: lang/json/terrain_from_json.py +msgid "" +"A segment of asphalt, slowly degrading from cracks, frost heaves and lack of" +" maintenance." +msgstr "一段瀝青,正在緩慢的碎裂中,凍結的冰塊破壞了結構並且缺乏了維護。" + +#: lang/json/terrain_from_json.py +msgid "yellow pavement" +msgstr "黃色路面" + +#. ~ Description for yellow pavement +#: lang/json/terrain_from_json.py +msgid "" +"Streaks of carefully aligned yellow paint mark the road to inform drivers " +"not to cross. No one is enforcing these rules anymore." +msgstr "漆在路上一條一條小心對齊的黃色油漆,提示駕駛不要跨越黃線。現在再也沒有人需要遵守這項規定了。" + +#: lang/json/terrain_from_json.py +msgid "sidewalk" +msgstr "人行道" + +#. ~ Description for sidewalk +#: lang/json/terrain_from_json.py +msgid "" +"An area of common poured concrete, damaged by frost heaves and large cracks " +"due to lack of maintenance." +msgstr "" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles." +msgstr "" + +#. ~ Description for concrete +#: lang/json/terrain_from_json.py +msgid "" +"A newer segment of poured concrete with surface finishes for aesthetics and " +"resistance to freeze-thaw cycles. Covered with a streak of yellow paint." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "wooden floor" +msgstr "木製地板" + +#. ~ Description for wooden floor +#: lang/json/terrain_from_json.py +msgid "" +"Wooden floor created from boards, packed tightly together and nailed down. " +"Common in patios." +msgstr "" + +#. ~ Description for metal floor +#: lang/json/terrain_from_json.py +msgid "" +"High-quality and tough checkered flooring to reduce risk of slips and falls." +msgstr "" + +#. ~ Description for dirt floor +#: lang/json/terrain_from_json.py +msgid "Floor consisting of finely mixed earth that has been tamped down." +msgstr "" + #: lang/json/terrain_from_json.py msgid "walnut tree" msgstr "核桃樹" @@ -185283,6 +187872,78 @@ msgstr "往上的梯子。" msgid "A ladder leading down." msgstr "往下的梯子。" +#: lang/json/terrain_from_json.py +msgid "road ramp down (high end)" +msgstr "" + +#. ~ Description for road ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp down (low end)" +msgstr "" + +#. ~ Description for road ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (high end)" +msgstr "" + +#. ~ Description for road ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "road ramp up (low end)" +msgstr "" + +#. ~ Description for road ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of an asphalt ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp down (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp down (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading down." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (high end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (high end) +#: lang/json/terrain_from_json.py +msgid "The upper end of a sidewalk ramp leading up." +msgstr "" + +#: lang/json/terrain_from_json.py +msgid "sidewalk ramp up (low end)" +msgstr "" + +#. ~ Description for sidewalk ramp up (low end) +#: lang/json/terrain_from_json.py +msgid "The lower end of a sidewalk ramp leading up." +msgstr "" + #: lang/json/terrain_from_json.py msgid "downward slope" msgstr "下坡" @@ -185774,7 +188435,7 @@ msgstr "鏗拉!" #. ~ Trap-vehicle collision message for trap 'shotgun trap' #: lang/json/trap_from_json.py lang/json/trap_from_json.py src/iuse.cpp -#: src/iuse.cpp src/ranged.cpp +#: src/ranged.cpp msgid "Bang!" msgstr "碰!" @@ -188226,6 +190887,15 @@ msgid "" "extending the time until the food spoils." msgstr "" +#. ~ Description for {'str': 'wooden wheel mount'} +#: lang/json/vehicle_part_from_json.py +msgid "A piece of wood with holes suitable for a bike or motorbike wheel." +msgstr "" + +#: lang/json/vehicle_part_from_json.py +msgid "wooden wheel mount (steerable)" +msgstr "" + #: lang/json/vehicle_part_from_json.py msgid "light wheel mount (steerable)" msgstr "輕型輪轂(轉向輪)" @@ -189060,8 +191730,9 @@ msgstr "這個鎖無情的嘲笑你的開鎖技術, 而你損傷了你的工具 msgid "The lock stumps your efforts to pick it." msgstr "這個鎖無情的嘲笑你的開鎖技術。" -#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iuse.cpp src/iuse.cpp -#: src/iuse.cpp src/iuse_actor.cpp src/iuse_actor.cpp +#: src/activity_actor.cpp src/game.cpp src/game.cpp src/iexamine.cpp +#: src/iuse.cpp src/iuse.cpp src/iuse.cpp src/iuse_actor.cpp +#: src/iuse_actor.cpp msgid "You cannot do that while mounted." msgstr "騎乘時無法做那個。" @@ -189121,6 +191792,120 @@ msgstr "繼續嘗試入睡。" msgid "Continue trying to fall asleep and don't ask again." msgstr "繼續嘗試入睡,不再詢問。" +#: src/activity_actor.cpp +msgid "You are too tired to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are too dehydrated to exercise." +msgstr "" + +#: src/activity_actor.cpp +msgid "Empty your hands first." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken arm." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train here with a broken leg." +msgstr "" + +#: src/activity_actor.cpp +msgid "You cannot train freely with a broken limb." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Physical effort determines workout efficiency, but also rate of exhaustion." +msgstr "" + +#: src/activity_actor.cpp +msgid "Choose training intensity:" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Light excercise comparable in intensity to walking, but more focused and " +"methodical." +msgstr "" + +#: src/activity_actor.cpp +msgid "Moderate" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Moderate excercise without excessive exertion, but with enough effort to " +"break a sweat." +msgstr "" + +#: src/activity_actor.cpp +msgid "Active" +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"Active excercise with full involvement. Strenuous, but in a controlled " +"manner." +msgstr "" + +#: src/activity_actor.cpp +msgid "" +"High intensity excercise with maximum effort and full power. Exhausting in " +"the long run." +msgstr "" + +#: src/activity_actor.cpp +msgid "Train for how long (minutes): " +msgstr "" + +#: src/activity_actor.cpp +msgid "You start your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are exhausted so you finish your workout early." +msgstr "" + +#: src/activity_actor.cpp +msgid "You are dehydrated so you finish your workout early." +msgstr "" + +#. ~ heavy breathing when excercising +#: src/activity_actor.cpp +msgid "yourself huffing and puffing!" +msgstr "" + +#: src/activity_actor.cpp +msgid "You catch your breath for few moments." +msgstr "" + +#: src/activity_actor.cpp +msgid "You get back to your training." +msgstr "" + +#: src/activity_actor.cpp +msgid "You finish your workout session." +msgstr "" + +#: src/activity_actor.cpp +msgid "You have finished your training cycle, keep training?" +msgstr "" + +#: src/activity_actor.cpp +msgid "Stop training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training." +msgstr "" + +#: src/activity_actor.cpp +msgid "Continue training and don't ask again." +msgstr "" + #. ~ Sound of a Rat mutant burrowing! #: src/activity_handlers.cpp msgid "ScratchCrunchScrabbleScurry." @@ -193654,6 +196439,29 @@ msgstr "%s (%i 插槽)。" msgid "Increased storage capacity by %i." msgstr "增加了 %i 的容量。" +#: src/bionics.cpp +msgid "Chose Safe Fuel Level Threshold" +msgstr "" + +#: src/bionics.cpp +msgid "Full Power" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 80 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 55 %%" +msgstr "" + +#: src/bionics.cpp +#, c-format +msgid "Above 30 %%" +msgstr "" + #: src/bionics.cpp msgid "Chose Start Power Level Threshold" msgstr "" @@ -193818,7 +196626,8 @@ msgid "(incapacitated)" msgstr "(嚴重傷殘)" #: src/bionics_ui.cpp -msgid "(fuel saving ON)" +#, c-format +msgid "(fuel saving ON > %d %%)" msgstr "" #: src/bionics_ui.cpp @@ -194500,6 +197309,23 @@ msgstr " 從網子中掙脫了!" msgid "You try to free yourself from the webs, but can't get loose!" msgstr "你嘗試從網子中掙脫, 但失敗了!" +#: src/character.cpp +#, c-format +msgid "The %s breaks free!" +msgstr "" + +#: src/character.cpp +msgid "You free yourself!" +msgstr "" + +#: src/character.cpp +msgid " frees themselves!" +msgstr "" + +#: src/character.cpp +msgid "You try to free yourself, but can't!" +msgstr "" + #: src/character.cpp msgid "You try to escape the pit, but slip back in." msgstr "你試著逃出坑, 但是又滑回去了。" @@ -195352,6 +198178,10 @@ msgstr "" msgid "Your body strains under the weight!" msgstr "你的身體被超重拖累!" +#: src/character.cpp src/player.cpp +msgid "Your biology is not compatible with that healing item." +msgstr "" + #: src/character.cpp #, c-format msgid "Dispose of %s" @@ -199480,19 +202310,6 @@ msgstr "" "室內:%s\n" "屋頂:%s" -#: src/editmap.cpp -#, c-format -msgid "" -"Visible: %d\n" -"Avoidance: %d\n" -"Difficulty: %d\n" -"Benign: %s" -msgstr "" -"可見:%d\n" -"避免:%d\n" -"困難:%d\n" -"良性:%s" - #: src/editmap.cpp #, c-format msgctxt "map feature id" @@ -203636,6 +206453,10 @@ msgstr "你沒東西可填裝。" msgid "You aren't holding something you can reload." msgstr "" +#: src/game.cpp +msgid "You need to put the bag away before trying to wield something from it." +msgstr "" + #: src/game.cpp #, c-format msgid "There's an angry red dot on your body, %s to brush it off." @@ -206185,6 +209006,10 @@ msgstr "忽略正被雷射瞄準!" msgid "Creature whitelisted: %s" msgstr "白名單中的生物: %s" +#: src/handle_action.cpp +msgid "Start workout?" +msgstr "" + #: src/handle_action.cpp msgid "Commit suicide?" msgstr "要自殺?" @@ -207536,11 +210361,28 @@ msgstr "%s 看起來實在太危險了。最好不要碰它。" msgid "There is a %s there. Take down?" msgstr "那裡有一個 %s, 要把它拆下來?" +#: src/iexamine.cpp +#, c-format +msgid "The %s is taken down." +msgstr "%s已被拆下。" + #: src/iexamine.cpp #, c-format msgid "There is a %s there. Disarm?" msgstr "有 %s 在那。解除嗎?" +#: src/iexamine.cpp +msgid "You disarm the trap!" +msgstr "你解除了陷阱!" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap." +msgstr "你解除陷阱失敗。" + +#: src/iexamine.cpp +msgid "You fail to disarm the trap, and you set it off!" +msgstr "你解除陷阱失敗, 並觸發了!" + #: src/iexamine.cpp #, c-format msgid "This %s can not be reloaded!" @@ -208408,6 +211250,11 @@ msgid "" " doesn't know the recipe for the %s and can't continue crafting." msgstr " 不知道 %s的製作方法,因此無法繼續製作。" +#: src/iexamine.cpp +#, c-format +msgid "Use the %s to exercise?" +msgstr "" + #: src/init.cpp msgid "Finalizing" msgstr "最終處理" @@ -209412,7 +212259,7 @@ msgid "" "very bad idea." msgstr "" -#: src/item.cpp +#: src/item.cpp src/item_pocket.cpp #, c-format msgid " round of %s" msgid_plural " rounds of %s" @@ -211072,6 +213919,12 @@ msgstr "" msgid "is not a container" msgstr "" +#: src/item_contents.cpp +#, c-format +msgid "pocket unacceptable because %s" +msgid_plural "pockets unacceptable because %s" +msgstr[0] "" + #: src/item_contents.cpp msgid "is not rigid" msgstr "" @@ -211135,6 +213988,10 @@ msgstr "" msgid "Pocket %d:" msgstr "" +#: src/item_pocket.cpp +msgid "Holds: " +msgstr "" + #: src/item_pocket.cpp msgid "Maximum item length: " msgstr "" @@ -212918,10 +215775,6 @@ msgstr "貪食蛇" msgid "Sokoban" msgstr "倉庫番" -#: src/iuse.cpp src/iuse_software_minesweeper.cpp -msgid "Minesweeper" -msgstr "踩地雷" - #: src/iuse.cpp src/iuse_software_lightson.cpp msgid "Lights on!" msgstr "開燈!" @@ -215792,7 +218645,7 @@ msgstr "%s 需要有 %s 鄰接。" msgid "You can't place a %s there. It contains a trap already." msgstr "你不能把%s放在這裡,這裡已經有陷阱了。" -#: src/iuse_actor.cpp +#: src/iuse_actor.cpp src/map.cpp #, c-format msgid "You trigger a %s!" msgstr "你觸動了 %s!" @@ -217545,6 +220398,15 @@ msgstr "產生" msgid "Summon" msgstr "召喚" +#: src/magic.cpp +msgid "random creature" +msgstr "" + +#: src/magic.cpp +#, c-format +msgid "Targets under: %dhp become a %s" +msgstr "" + #: src/magic.cpp src/veh_interact.cpp msgid "Range" msgstr "距離" @@ -217565,6 +220427,10 @@ msgstr "效果範圍" msgid "Spawned" msgstr "生成" +#: src/magic.cpp +msgid "Threshold" +msgstr "" + #: src/magic.cpp msgid "Recover" msgstr "恢復" @@ -217617,6 +220483,15 @@ msgstr "你的傷勢均分了。" msgid "%s wounds are closing up!" msgstr "%s 的傷口正在痊癒!" +#: src/magic_spell_effect.cpp +#, c-format +msgid "The %s transforms into a %s." +msgstr "" + +#: src/magic_spell_effect.cpp +msgid "Your target resists transformation." +msgstr "" + #: src/magic_spell_effect.cpp msgid "There is already a vehicle there." msgstr "" @@ -218074,30 +220949,23 @@ msgstr "%s的高壓滅菌器已經完成滅菌循環。" #: src/map.cpp #, c-format -msgid "The %s is taken down." -msgstr "%s已被拆下。" - -#: src/map.cpp -msgid "You disarm the trap!" -msgstr "你解除了陷阱!" - -#: src/map.cpp -msgid "You fail to disarm the trap." -msgstr "你解除陷阱失敗。" +msgid "Something has crawled out of the %s plants!" +msgstr "有東西從 %s 植物中爬出來了! " #: src/map.cpp -msgid "You fail to disarm the trap, and you set it off!" -msgstr "你解除陷阱失敗, 並觸發了!" +#, c-format +msgid "Something has crawled out of the %s!" +msgstr "有東西從 %s 爬出來了!" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s plants!" -msgstr "有東西從 %s 植物中爬出來了! " +msgid "You've spotted a %1$ss!" +msgstr "" #: src/map.cpp #, c-format -msgid "Something has crawled out of the %s!" -msgstr "有東西從 %s 爬出來了!" +msgid " triggers a %s!" +msgstr "" #: src/map_extras.cpp msgid "DANGER! MINEFIELD!" @@ -218524,7 +221392,7 @@ msgstr "%s 在持武時無法施展。" #: src/martialarts.cpp #, c-format msgid "The %1$s is not a valid %2$s weapon." -msgstr "" +msgstr "%1$s 並不是合適的 %2$s 武器。" #: src/martialarts.cpp msgid "Block Counter" @@ -219638,6 +222506,19 @@ msgctxt "memorial_female" msgid "Became wanted by the police!" msgstr "你成了十大通緝要犯!" +#. ~ %s is bodypart +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_male" +msgid "Broke his %s." +msgstr "" + +#: src/memorial_logger.cpp +#, c-format +msgctxt "memorial_female" +msgid "Broke her %s." +msgstr "" + #. ~ %s is bodypart #: src/memorial_logger.cpp #, c-format @@ -223476,6 +226357,11 @@ msgstr "" msgid "zombie slave" msgstr "屍奴 " +#: src/monexamine.cpp +#, c-format +msgid "Push %s" +msgstr "推 %s" + #: src/monexamine.cpp msgid "Rename" msgstr "重新命名" @@ -228695,17 +231581,6 @@ msgstr "受輻射影響突變" msgid "If true, radiation causes the player to mutate." msgstr "設定為 [是], 輻射會造成玩家的突變。" -#: src/options.cpp -msgid "Z-levels" -msgstr "" - -#: src/options.cpp -msgid "" -"If true, enables several features related to vertical movement, such as " -"hauling items up stairs, climbing downspouts, and flying aircraft. May " -"cause problems if toggled mid-game." -msgstr "" - #: src/options.cpp msgid "Character point pools" msgstr "角色點數" @@ -233401,6 +236276,19 @@ msgctxt "grammatical gender list" msgid "n" msgstr "" +#: src/trap.cpp +#, c-format +msgid "" +"Visible: %d\n" +"Avoidance: %d\n" +"Difficulty: %d\n" +"Benign: %s" +msgstr "" +"可見:%d\n" +"避免:%d\n" +"困難:%d\n" +"良性:%s" + #: src/trapfunc.cpp msgid "You step on some bubble wrap!" msgstr "你踩到了泡泡紙!" @@ -236304,7 +239192,7 @@ msgstr "多雲" #: src/weather_data.cpp msgid "Light Drizzle" -msgstr "" +msgstr "毛毛細雨" #: src/weather_data.cpp msgid "Drizzle" @@ -236456,7 +239344,7 @@ msgstr "@ %d: %s " #: src/wish.cpp #, c-format msgid "Set '%s' to…" -msgstr "" +msgstr "設定 '%s' 為…" #: src/wish.cpp msgid " (current)" diff --git a/msvc-full-features/Cataclysm-lib-vcpkg-static.vcxproj b/msvc-full-features/Cataclysm-lib-vcpkg-static.vcxproj index 66cf377f1163a..578271efa0d3e 100644 --- a/msvc-full-features/Cataclysm-lib-vcpkg-static.vcxproj +++ b/msvc-full-features/Cataclysm-lib-vcpkg-static.vcxproj @@ -1,137 +1,145 @@ - - - Debug - x64 - - - Debug - Win32 - - - Release - x64 - - - Release - Win32 - - + + + Debug + x64 + + + Debug + Win32 + + + Release + x64 + + + Release + Win32 + + 16.0 {0009BB11-11AD-4C14-A5FC-D882A942C00B} Win32Proj CataclysmLib 10.0 - x86-windows-static - x64-windows-static + x86-windows-static + x64-windows-static + + + true + true + true + true + true + x86-windows + x64-windows + $(Configuration) - - StaticLibrary - v142 - MultiByte + StaticLibrary + v142 + MultiByte - true + true - false - false + false + false + + + + + + + + + + $(ProjectName)-$(Configuration)-$(Platform) + .lib + $(SolutionDir)..\ + $(SolutionDir)$(ProjectName)\$(Configuration)\$(Platform)\ + + + true + + + false - - - - - - - - - - $(ProjectName)-$(Configuration)-$(Platform) - .lib - $(SolutionDir)..\ - $(SolutionDir)$(ProjectName)\$(Configuration)\$(Platform)\ - - - true - - - false - - - - Level1 - Use - true - false - true - false - ProgramDatabase - 4819;4146;26495;26444;26451;4068;6319;6237 - stdafx.h - /bigobj /utf-8 %(AdditionalOptions) - _SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_CONSOLE;SDL_SOUND;TILES;SDL_BUILDING_LIBRARY;LOCALIZE;USE_VCPKG;%(PreprocessorDefinitions) - stdcpp14 - ..\src;%(AdditionalIncludeDirectories) - - - Windows - true - Default - true - /LTCG:OFF %(AdditionalOptions) - winmm.lib;imm32.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;%(AdditionalDependencies) - - - prebuild.cmd - Get version string - - - true - - - - - Disabled - false - false - _DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - DebugFastLink - MultiThreaded - - - true - true - - - - - WIN32;%(PreprocessorDefinitions) - - - - - - - - - - Create - - - - - + + + Level1 + Use + true + false + true + false + ProgramDatabase + 4819;4146;26495;26444;26451;4068;6319;6237 + stdafx.h + /bigobj /utf-8 %(AdditionalOptions) + _SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_CONSOLE;SDL_SOUND;TILES;SDL_BUILDING_LIBRARY;LOCALIZE;USE_VCPKG;%(PreprocessorDefinitions) + stdcpp14 + ..\src;%(AdditionalIncludeDirectories) + + + Windows + true + Default + true + /LTCG:OFF %(AdditionalOptions) + winmm.lib;imm32.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;%(AdditionalDependencies) + + + prebuild.cmd + Get version string + + + true + + + + + Disabled + false + false + _DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + MaxSpeed + true + true + NDEBUG;%(PreprocessorDefinitions) + DebugFastLink + MultiThreaded + + + true + true + + + + + WIN32;%(PreprocessorDefinitions) + + + + + + + + + + Create + + + + + diff --git a/msvc-full-features/Cataclysm-test-vcpkg-static.vcxproj b/msvc-full-features/Cataclysm-test-vcpkg-static.vcxproj index e1bfccb6bdd0c..6591853dcfe85 100644 --- a/msvc-full-features/Cataclysm-test-vcpkg-static.vcxproj +++ b/msvc-full-features/Cataclysm-test-vcpkg-static.vcxproj @@ -27,6 +27,16 @@ x86-windows-static x64-windows-static + + true + true + true + true + true + x86-windows + x64-windows + $(Configuration) + Application @@ -138,4 +148,4 @@ - \ No newline at end of file + diff --git a/msvc-full-features/Cataclysm-vcpkg-static.sln b/msvc-full-features/Cataclysm-vcpkg-static.sln index ce23375f05220..38c183d6ab5f7 100644 --- a/msvc-full-features/Cataclysm-vcpkg-static.sln +++ b/msvc-full-features/Cataclysm-vcpkg-static.sln @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject ..\.editorconfig = ..\.editorconfig AStyleExtension-Cataclysm-DDA.cfg = AStyleExtension-Cataclysm-DDA.cfg + vcpkg.json = vcpkg.json EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cataclysm-vcpkg-static", "Cataclysm-vcpkg-static.vcxproj", "{19F0BE17-3DAF-40E8-A9D2-904A56382E54}" diff --git a/msvc-full-features/Cataclysm-vcpkg-static.vcxproj b/msvc-full-features/Cataclysm-vcpkg-static.vcxproj index b8021c0e3d405..422b2df1fcbcb 100644 --- a/msvc-full-features/Cataclysm-vcpkg-static.vcxproj +++ b/msvc-full-features/Cataclysm-vcpkg-static.vcxproj @@ -27,6 +27,16 @@ x86-windows-static x64-windows-static + + true + true + true + true + true + x86-windows + x64-windows + $(Configuration) + Application @@ -132,4 +142,4 @@ - \ No newline at end of file + diff --git a/msvc-full-features/JsonFormatter.vcxproj b/msvc-full-features/JsonFormatter.vcxproj index bf31ec6133545..7ffd9f160301e 100644 --- a/msvc-full-features/JsonFormatter.vcxproj +++ b/msvc-full-features/JsonFormatter.vcxproj @@ -27,6 +27,16 @@ x86-windows-static x64-windows-static + + true + true + true + true + true + x86-windows + x64-windows + $(Configuration) + Application diff --git a/msvc-full-features/vcpkg.json b/msvc-full-features/vcpkg.json new file mode 100644 index 0000000000000..4d441c9ec9c6f --- /dev/null +++ b/msvc-full-features/vcpkg.json @@ -0,0 +1,14 @@ +{ + "name": "cdda-vcpkg-dependencies", + "version-string": "0.E", + "dependencies": [ + "sdl2", + "sdl2-image", + { + "name": "sdl2-mixer", + "features": [ "dynamic-load", "libflac", "mpg123", "libmodplug", "libvorbis" ] + }, + "sdl2-ttf", + "gettext" + ] +} diff --git a/src/achievement.cpp b/src/achievement.cpp index e5fb30b8ce2e6..b96b914ff4815 100644 --- a/src/achievement.cpp +++ b/src/achievement.cpp @@ -15,7 +15,7 @@ // the execution flow to help clarify how it all fits together. // // * Various core game code paths generate events via the event bus. -// * The stats_traecker subscribes to the event bus, and receives these events. +// * The stats_tracker subscribes to the event bus, and receives these events. // * Events contribute to event_multisets managed by the stats_tracker. // * (In the docs, these event_multisets are described as "event streams"). // * (Optionally) event_transformations transform these event_multisets into diff --git a/src/action.cpp b/src/action.cpp index 4c0eec381e9d2..5738a3c529d94 100644 --- a/src/action.cpp +++ b/src/action.cpp @@ -296,6 +296,8 @@ std::string action_ident( action_id act ) return "ignore_enemy"; case ACTION_WHITELIST_ENEMY: return "whitelist_enemy"; + case ACTION_WORKOUT: + return "workout"; case ACTION_SAVE: return "save"; case ACTION_QUICKSAVE: @@ -591,20 +593,21 @@ int hotkey_for_action( action_id action, const bool restrict_to_printable ) bool can_butcher_at( const tripoint &p ) { + Character &player_character = get_player_character(); // TODO: unify this with game::butcher - const int factor = g->u.max_quality( qual_BUTCHER ); - const int factorD = g->u.max_quality( qual_CUT_FINE ); + const int factor = player_character.max_quality( qual_BUTCHER ); + const int factorD = player_character.max_quality( qual_CUT_FINE ); map_stack items = get_map().i_at( p ); bool has_item = false; bool has_corpse = false; - const inventory &crafting_inv = g->u.crafting_inventory(); + const inventory &crafting_inv = player_character.crafting_inventory(); for( item &items_it : items ) { if( items_it.is_corpse() ) { if( factor != INT_MIN || factorD != INT_MIN ) { has_corpse = true; } - } else if( g->u.can_disassemble( items_it, crafting_inv ).success() ) { + } else if( player_character.can_disassemble( items_it, crafting_inv ).success() ) { has_item = true; } } @@ -613,13 +616,15 @@ bool can_butcher_at( const tripoint &p ) bool can_move_vertical_at( const tripoint &p, int movez ) { + Character &player_character = get_player_character(); map &here = get_map(); // TODO: unify this with game::move_vertical if( here.has_flag( flag_SWIMMABLE, p ) && here.has_flag( TFLAG_DEEP_WATER, p ) ) { if( movez == -1 ) { - return !g->u.is_underwater() && !g->u.worn_with_flag( flag_FLOTATION ); + return !player_character.is_underwater() && !player_character.worn_with_flag( flag_FLOTATION ); } else { - return g->u.swim_speed() < 500 || g->u.is_wearing( itype_id( "swim_fins" ) ); + return player_character.swim_speed() < 500 || + player_character.is_wearing( itype_id( "swim_fins" ) ); } } @@ -652,12 +657,11 @@ bool can_examine_at( const tripoint &p ) } Creature *c = g->critter_at( p ); - if( c != nullptr && p != g->u.pos() ) { + if( c != nullptr && !c->is_avatar() ) { return true; } - const trap &tr = here.tr_at( p ); - return tr.can_see( p, g->u ); + return here.can_see_trap_at( p, get_player_character() ); } static bool can_pickup_at( const tripoint &p ) @@ -675,15 +679,16 @@ static bool can_pickup_at( const tripoint &p ) bool can_interact_at( action_id action, const tripoint &p ) { map &here = get_map(); + tripoint player_pos = get_player_character().pos(); switch( action ) { case ACTION_OPEN: - return here.open_door( p, !here.is_outside( g->u.pos() ), true ); + return here.open_door( p, !here.is_outside( player_pos ), true ); case ACTION_CLOSE: { const optional_vpart_position vp = here.veh_at( p ); return ( vp && vp->vehicle().next_part_to_close( vp->part_index(), - veh_pointer_or_null( here.veh_at( g->u.pos() ) ) != &vp->vehicle() ) >= 0 ) || - here.close_door( p, !here.is_outside( g->u.pos() ), true ); + veh_pointer_or_null( here.veh_at( player_pos ) ) != &vp->vehicle() ) >= 0 ) || + here.close_door( p, !here.is_outside( player_pos ), true ); } case ACTION_BUTCHER: return can_butcher_at( p ); @@ -718,38 +723,39 @@ action_id handle_action_menu() // Weight >= 200: Special action only available right now std::map action_weightings; + Character &player_character = get_player_character(); // Check if we're in a potential combat situation, if so, sort a few actions to the top. - if( !g->u.get_hostile_creatures( 60 ).empty() ) { + if( !player_character.get_hostile_creatures( 60 ).empty() ) { // Only prioritize movement options if we're not driving. - if( !g->u.controlling_vehicle ) { + if( !player_character.controlling_vehicle ) { action_weightings[ACTION_CYCLE_MOVE] = 400; } // Only prioritize fire weapon options if we're wielding a ranged weapon. - if( g->u.weapon.is_gun() || g->u.weapon.has_flag( flag_REACH_ATTACK ) ) { + if( player_character.weapon.is_gun() || player_character.weapon.has_flag( flag_REACH_ATTACK ) ) { action_weightings[ACTION_FIRE] = 350; } } // If we're already running, make it simple to toggle running to off. - if( g->u.is_running() ) { + if( player_character.is_running() ) { action_weightings[ACTION_TOGGLE_RUN] = 300; } // If we're already crouching, make it simple to toggle crouching to off. - if( g->u.is_crouching() ) { + if( player_character.is_crouching() ) { action_weightings[ACTION_TOGGLE_CROUCH] = 300; } map &here = get_map(); // Check if we're on a vehicle, if so, vehicle controls should be top. - if( here.veh_at( g->u.pos() ) ) { + if( here.veh_at( player_character.pos() ) ) { // Make it 300 to prioritize it before examining the vehicle. action_weightings[ACTION_CONTROL_VEHICLE] = 300; } // Check if we can perform one of our actions on nearby terrain. If so, // display that action at the top of the list. - for( const tripoint &pos : here.points_in_radius( g->u.pos(), 1 ) ) { - if( pos != g->u.pos() ) { + for( const tripoint &pos : here.points_in_radius( player_character.pos(), 1 ) ) { + if( pos != player_character.pos() ) { // Check for actions that work on nearby tiles if( can_interact_at( ACTION_OPEN, pos ) ) { action_weightings[ACTION_OPEN] = 200; @@ -928,6 +934,7 @@ action_id handle_action_menu() } else if( category == _( "Misc" ) ) { REGISTER_ACTION( ACTION_WAIT ); REGISTER_ACTION( ACTION_SLEEP ); + REGISTER_ACTION( ACTION_WORKOUT ); REGISTER_ACTION( ACTION_BIONICS ); REGISTER_ACTION( ACTION_MUTATIONS ); REGISTER_ACTION( ACTION_CONTROL_VEHICLE ); @@ -1038,11 +1045,12 @@ cata::optional choose_direction( const std::string &message, const boo ui_manager::redraw(); action = ctxt.handle_input(); if( const cata::optional vec = ctxt.get_direction( action ) ) { + FacingDirection &facing = get_player_character().facing; // Make player's sprite face left/right if interacting with something to the left or right if( vec->x > 0 ) { - g->u.facing = FacingDirection::RIGHT; + facing = FacingDirection::RIGHT; } else if( vec->x < 0 ) { - g->u.facing = FacingDirection::LEFT; + facing = FacingDirection::LEFT; } return vec; } else if( action == "pause" ) { @@ -1061,7 +1069,7 @@ cata::optional choose_direction( const std::string &message, const boo cata::optional choose_adjacent( const std::string &message, const bool allow_vertical ) { const cata::optional dir = choose_direction( message, allow_vertical ); - return dir ? *dir + g->u.pos() : dir; + return dir ? *dir + get_player_character().pos() : dir; } cata::optional choose_adjacent_highlight( const std::string &message, @@ -1078,9 +1086,10 @@ cata::optional choose_adjacent_highlight( const std::string &message, const bool allow_vertical ) { std::vector valid; + avatar &player_character = get_avatar(); map &here = get_map(); if( allowed ) { - for( const tripoint &pos : here.points_in_radius( g->u.pos(), 1 ) ) { + for( const tripoint &pos : here.points_in_radius( player_character.pos(), 1 ) ) { if( allowed( pos ) ) { valid.emplace_back( pos ); } @@ -1099,8 +1108,8 @@ cata::optional choose_adjacent_highlight( const std::string &message, if( !valid.empty() ) { hilite_cb = make_shared_fast( [&]() { for( const tripoint &pos : valid ) { - here.drawsq( g->w_terrain, g->u, pos, - true, true, g->u.pos() + g->u.view_offset ); + here.drawsq( g->w_terrain, player_character, pos, + true, true, player_character.pos() + player_character.view_offset ); } } ); g->add_draw_callback( hilite_cb ); diff --git a/src/action.h b/src/action.h index ad6b004fe8452..db4a3e0bcd4ec 100644 --- a/src/action.h +++ b/src/action.h @@ -219,6 +219,8 @@ enum action_id : int { ACTION_IGNORE_ENEMY, /** Whitelist the enemy that triggered safemode */ ACTION_WHITELIST_ENEMY, + /** Open workout menu */ + ACTION_WORKOUT, /** Save the game and quit */ ACTION_SAVE, /** Quicksave the game */ diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 3cfe572ba1f88..5f98da78dbefa 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -21,6 +21,7 @@ #include "line.h" #include "map.h" #include "map_iterator.h" +#include "morale_types.h" #include "npc.h" #include "options.h" #include "output.h" @@ -47,6 +48,7 @@ static const skill_id skill_mechanics( "mechanics" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); +static const std::string flag_MAG_DESTROY( "MAG_DESTROY" ); static const std::string flag_PERFECT_LOCKPICK( "PERFECT_LOCKPICK" ); static const std::string flag_RELOAD_AND_SHOOT( "RELOAD_AND_SHOOT" ); @@ -89,7 +91,7 @@ std::string enum_to_string( WS data ) aim_activity_actor::aim_activity_actor() { - initial_view_offset = g->u.view_offset; + initial_view_offset = get_avatar().view_offset; } aim_activity_actor aim_activity_actor::use_wielded() @@ -135,7 +137,7 @@ void aim_activity_actor::do_turn( player_activity &act, Character &who ) aborted = true; return; } - avatar &you = g->u; + avatar &you = get_avatar(); item *weapon = get_weapon(); if( !weapon || !avatar_action::can_fire_weapon( you, get_map(), *weapon ) ) { @@ -240,10 +242,12 @@ std::unique_ptr aim_activity_actor::deserialize( JsonIn &jsin ) item *aim_activity_actor::get_weapon() { switch( weapon_source ) { - case WeaponSource::Wielded: + case WeaponSource::Wielded: { + Character &player_character = get_player_character(); // Check for lost gun (e.g. yanked by zombie technician) // TODO: check that this is the same gun that was used to start aiming - return g->u.weapon.is_null() ? nullptr : &g->u.weapon; + return player_character.weapon.is_null() ? nullptr : &player_character.weapon; + } case WeaponSource::Bionic: case WeaponSource::Mutation: // TODO: check if the player lost relevant bionic/mutation @@ -256,10 +260,11 @@ item *aim_activity_actor::get_weapon() void aim_activity_actor::restore_view() { - bool changed_z = g->u.view_offset.z != initial_view_offset.z; - g->u.view_offset = initial_view_offset; + avatar &player_character = get_avatar(); + bool changed_z = player_character.view_offset.z != initial_view_offset.z; + player_character.view_offset = initial_view_offset; if( changed_z ) { - get_map().invalidate_map_cache( g->u.view_offset.z ); + get_map().invalidate_map_cache( player_character.view_offset.z ); g->invalidate_main_ui_adaptor(); } } @@ -267,7 +272,7 @@ void aim_activity_actor::restore_view() bool aim_activity_actor::load_RAS_weapon() { // TODO: use activity for fetching ammo and loading weapon - player &you = g->u; + player &you = get_avatar(); item *weapon = get_weapon(); gun_mode gun = weapon->gun_current_mode(); const auto ammo_location_is_valid = [&]() -> bool { @@ -312,7 +317,7 @@ bool aim_activity_actor::load_RAS_weapon() void aim_activity_actor::unload_RAS_weapon() { // Unload reload-and-shoot weapons to avoid leaving bows pre-loaded with arrows - avatar &you = g->u; + avatar &you = get_avatar(); item *weapon = get_weapon(); if( !weapon ) { return; @@ -324,7 +329,7 @@ void aim_activity_actor::unload_RAS_weapon() // Note: this code works only for avatar item_location loc = item_location( you, gun.target ); - g->unload( loc ); + you.unload( loc, true ); // Give back time for unloading as essentially nothing has been done. if( first_turn ) { @@ -389,7 +394,7 @@ void dig_activity_actor::finish( player_activity &act, Character &who ) calendar::turn ) ); } - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const int helpersize = get_avatar().get_num_crafting_helpers( 3 ); who.mod_stored_nutr( 5 - helpersize ); who.mod_thirst( 5 - helpersize ); who.mod_fatigue( 10 - ( helpersize * 2 ) ); @@ -401,6 +406,8 @@ void dig_activity_actor::finish( player_activity &act, Character &who ) } act.set_to_null(); + + here.maybe_trigger_trap( location, who, true ); } void dig_activity_actor::serialize( JsonOut &jsout ) const @@ -459,7 +466,7 @@ void dig_channel_activity_actor::finish( player_activity &act, Character &who ) calendar::turn ) ); } - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const int helpersize = get_avatar().get_num_crafting_helpers( 3 ); who.mod_stored_nutr( 5 - helpersize ); who.mod_thirst( 5 - helpersize ); who.mod_fatigue( 10 - ( helpersize * 2 ) ); @@ -467,6 +474,8 @@ void dig_channel_activity_actor::finish( player_activity &act, Character &who ) here.ter( location ).obj().name() ); act.set_to_null(); + + here.maybe_trigger_trap( location, who, true ); } void dig_channel_activity_actor::serialize( JsonOut &jsout ) const @@ -1128,19 +1137,22 @@ std::unique_ptr open_gate_activity_actor::deserialize( JsonIn &j void consume_activity_actor::start( player_activity &act, Character &guy ) { int moves; + Character &player_character = get_player_character(); if( consume_location ) { - const auto ret = g->u.will_eat( *consume_location, true ); + const auto ret = player_character.will_eat( *consume_location, true ); if( !ret.success() ) { consume_menu_selections = std::vector(); + consume_menu_filter = std::string(); return; } else { force = true; } moves = to_moves( guy.get_consume_time( *consume_location ) ); } else if( !consume_item.is_null() ) { - const auto ret = g->u.will_eat( consume_item, true ); + const auto ret = player_character.will_eat( consume_item, true ); if( !ret.success() ) { consume_menu_selections = std::vector(); + consume_menu_filter = std::string(); return; } else { force = true; @@ -1162,22 +1174,34 @@ void consume_activity_actor::finish( player_activity &act, Character & ) // too late; we've already consumed). act.interruptable = false; + avatar &player_character = get_avatar(); if( consume_location ) { - g->u.consume( consume_location, force ); + player_character.consume( consume_location, force ); } else if( !consume_item.is_null() ) { - g->u.consume( consume_item, force ); + player_character.consume( consume_item, force ); } else { debugmsg( "Item location/name to be consumed should not be null." ); } - if( g->u.get_value( "THIEF_MODE_KEEP" ) != "YES" ) { - g->u.set_value( "THIEF_MODE", "THIEF_ASK" ); + if( player_character.get_value( "THIEF_MODE_KEEP" ) != "YES" ) { + player_character.set_value( "THIEF_MODE", "THIEF_ASK" ); } //setting act to null clears these so back them up std::vector temp_selections = consume_menu_selections; - act.set_to_null(); - if( !temp_selections.empty() ) { - g->u.assign_activity( ACT_EAT_MENU ); - g->u.activity.values = temp_selections; + const std::string temp_filter = consume_menu_filter; + if( act.id() == activity_id( "ACT_CONSUME" ) ) { + act.set_to_null(); + } + if( !temp_selections.empty() || !temp_filter.empty() ) { + if( act.is_null() ) { + player_character.assign_activity( ACT_EAT_MENU ); + player_character.activity.values = temp_selections; + player_character.activity.str_values = { temp_filter }; + } else { + player_activity eat_menu( ACT_EAT_MENU ); + eat_menu.values = temp_selections; + eat_menu.str_values = { temp_filter }; + player_character.backlog.push_back( eat_menu ); + } } } @@ -1188,6 +1212,7 @@ void consume_activity_actor::serialize( JsonOut &jsout ) const jsout.member( "consume_location", consume_location ); jsout.member( "consume_item", consume_item ); jsout.member( "consume_menu_selections", consume_menu_selections ); + jsout.member( "consume_menu_filter", consume_menu_filter ); jsout.member( "force", force ); jsout.end_object(); @@ -1203,6 +1228,7 @@ std::unique_ptr consume_activity_actor::deserialize( JsonIn &jsi data.read( "consume_location", actor.consume_location ); data.read( "consume_item", actor.consume_item ); data.read( "consume_menu_selections", actor.consume_menu_selections ); + data.read( "consume_menu_filter", actor.consume_menu_filter ); data.read( "force", actor.force ); return actor.clone(); @@ -1293,6 +1319,310 @@ std::unique_ptr try_sleep_activity_actor::deserialize( JsonIn &j return actor.clone(); } +void unload_mag_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_left = moves_total; + act.moves_total = moves_total; +} + +void unload_mag_activity_actor::finish( player_activity &act, Character &who ) +{ + act.set_to_null(); + unload( who, target ); +} + +void unload_mag_activity_actor::unload( Character &who, item_location &target ) +{ + int qty = 0; + item &it = *target.get_item(); + + std::vector remove_contained; + for( item *contained : it.contents.all_items_top() ) { + if( who.as_player()->add_or_drop_with_msg( *contained, true ) ) { + qty += contained->charges; + remove_contained.push_back( contained ); + } + } + // remove the ammo leads in the belt + for( item *remove : remove_contained ) { + it.remove_item( *remove ); + } + + // remove the belt linkage + if( it.is_ammo_belt() ) { + if( it.type->magazine->linkage ) { + item link( *it.type->magazine->linkage, calendar::turn, qty ); + who.as_player()->add_or_drop_with_msg( link, true ); + } + who.add_msg_if_player( _( "You disassemble your %s." ), it.tname() ); + } else { + who.add_msg_if_player( _( "You unload your %s." ), it.tname() ); + } + + if( it.has_flag( flag_MAG_DESTROY ) && it.ammo_remaining() == 0 ) { + target.remove_item(); + } +} + +void unload_mag_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "moves_total", moves_total ); + jsout.member( "target", target ); + + jsout.end_object(); +} + +std::unique_ptr unload_mag_activity_actor::deserialize( JsonIn &jsin ) +{ + unload_mag_activity_actor actor = unload_mag_activity_actor( 0, item_location::nowhere ); + + JsonObject data = jsin.get_object(); + + data.read( "moves_total", actor.moves_total ); + data.read( "target", actor.target ); + + return actor.clone(); +} + +void workout_activity_actor::start( player_activity &act, Character &who ) +{ + if( who.get_fatigue() > fatigue_levels::DEAD_TIRED ) { + who.add_msg_if_player( _( "You are too tired to exercise." ) ); + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + if( who.get_thirst() > 240 ) { + who.add_msg_if_player( _( "You are too dehydrated to exercise." ) ); + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + if( who.is_armed() ) { + who.add_msg_if_player( _( "Empty your hands first." ) ); + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + map &here = get_map(); + // free training requires all limbs intact, but specialized workout machines + // train upper or lower parts of body only and may permit workout with + // broken limbs as long as they are not involved by the machine + bool hand_equipment = here.has_flag_furn( "WORKOUT_ARMS", location ); + bool leg_equipment = here.has_flag_furn( "WORKOUT_LEGS", location ); + static const bodypart_id arm_l = bodypart_id( "arm_l" ); + static const bodypart_id arm_r = bodypart_id( "arm_r" ); + static const bodypart_id leg_l = bodypart_id( "leg_l" ); + static const bodypart_id leg_r = bodypart_id( "leg_r" ); + if( hand_equipment && ( ( who.is_limb_broken( arm_l ) ) || + who.is_limb_broken( arm_r ) ) ) { + who.add_msg_if_player( _( "You cannot train here with a broken arm." ) ); + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + if( leg_equipment && ( ( who.is_limb_broken( leg_l ) ) || + who.is_limb_broken( leg_r ) ) ) { + who.add_msg_if_player( _( "You cannot train here with a broken leg." ) ); + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + if( !hand_equipment && !leg_equipment && + ( who.is_limb_broken( arm_l ) || + who.is_limb_broken( arm_r ) || + who.is_limb_broken( leg_l ) || + who.is_limb_broken( leg_r ) ) ) { + who.add_msg_if_player( _( "You cannot train freely with a broken limb." ) ); + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + uilist workout_query; + workout_query.desc_enabled = true; + workout_query.text = + _( "Physical effort determines workout efficiency, but also rate of exhaustion." ); + workout_query.title = _( "Choose training intensity:" ); + workout_query.addentry_desc( 1, true, 'l', _( "Light" ), + _( "Light excercise comparable in intensity to walking, but more focused and methodical." ) ); + workout_query.addentry_desc( 2, true, 'm', _( "Moderate" ), + _( "Moderate excercise without excessive exertion, but with enough effort to break a sweat." ) ); + workout_query.addentry_desc( 3, true, 'a', _( "Active" ), + _( "Active excercise with full involvement. Strenuous, but in a controlled manner." ) ); + workout_query.addentry_desc( 4, true, 'h', _( "High" ), + _( "High intensity excercise with maximum effort and full power. Exhausting in the long run." ) ); + workout_query.query(); + switch( workout_query.ret ) { + case UILIST_CANCEL: + act.set_to_null(); + act_id = activity_id::NULL_ID(); + return; + case 4: + act_id = activity_id( "ACT_WORKOUT_HARD" ); + intensity_modifier = 4; + break; + case 3: + act_id = activity_id( "ACT_WORKOUT_ACTIVE" ); + intensity_modifier = 3; + break; + case 2: + act_id = activity_id( "ACT_WORKOUT_MODERATE" ); + intensity_modifier = 2; + break; + case 1: + default: + act_id = activity_id( "ACT_WORKOUT_LIGHT" ); + intensity_modifier = 1; + break; + } + int length; + query_int( length, _( "Train for how long (minutes): " ) ); + if( length > 0 ) { + duration = length * 1_minutes; + } else { + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return; + } + act.moves_total = to_moves( duration ); + act.moves_left = act.moves_total; + if( who.male ) { + sfx::play_activity_sound( "plmove", "fatigue_m_med", sfx::get_heard_volume( location ) ); + } else { + sfx::play_activity_sound( "plmove", "fatigue_f_med", sfx::get_heard_volume( location ) ); + } + who.add_msg_if_player( _( "You start your workout session." ) ); +} + +void workout_activity_actor::do_turn( player_activity &act, Character &who ) +{ + if( who.get_fatigue() > fatigue_levels::DEAD_TIRED ) { + who.add_msg_if_player( _( "You are exhausted so you finish your workout early." ) ); + act.set_to_null(); + return; + } + if( who.get_thirst() > 240 ) { + who.add_msg_if_player( _( "You are dehydrated so you finish your workout early." ) ); + act.set_to_null(); + return; + } + if( !rest_mode && who.get_stamina() > who.get_stamina_max() / 3 ) { + who.mod_stamina( -25 - intensity_modifier ); + if( one_in( 180 / intensity_modifier ) ) { + who.mod_fatigue( 1 ); + who.mod_thirst( 1 ); + } + if( calendar::once_every( 16_minutes / intensity_modifier ) ) { + //~ heavy breathing when excercising + std::string huff = _( "yourself huffing and puffing!" ); + sounds::sound( location + tripoint_east, 2 * intensity_modifier, sounds::sound_t::speech, huff, + true ); + } + // morale bonus kicks in gradually after 5 minutes of exercise + if( calendar::once_every( 2_minutes ) && + ( ( elapsed + act.moves_total - act.moves_left ) / 100 * 1_turns ) > 5_minutes ) { + who.add_morale( MORALE_FEELING_GOOD, intensity_modifier, 20, 6_hours, 30_minutes ); + } + if( calendar::once_every( 2_minutes ) ) { + who.add_msg_if_player( m_debug, who.activity_level_str() ); + who.add_msg_if_player( m_debug, act.id().c_str() ); + } + } else if( !rest_mode ) { + rest_mode = true; + who.add_msg_if_player( _( "You catch your breath for few moments." ) ); + } else if( who.get_stamina() >= who.get_stamina_max() ) { + rest_mode = false; + who.add_msg_if_player( _( "You get back to your training." ) ); + } +} + +void workout_activity_actor::finish( player_activity &act, Character &who ) +{ + if( !query_keep_training( act, who ) ) { + act.set_to_null(); + who.add_msg_if_player( _( "You finish your workout session." ) ); + } +} + +void workout_activity_actor::canceled( player_activity &/*act*/, Character &/*who*/ ) +{ + stop_time = calendar::turn; +} + +bool workout_activity_actor::query_keep_training( player_activity &act, Character &who ) +{ + if( disable_query || !who.is_avatar() ) { + elapsed += act.moves_total - act.moves_left; + act.moves_total = to_moves( 60_minutes ); + act.moves_left = act.moves_total; + return true; + } + int length; + uilist workout_query; + workout_query.text = _( "You have finished your training cycle, keep training?" ); + workout_query.addentry( 1, true, 'S', _( "Stop training." ) ); + workout_query.addentry( 2, true, 'c', _( "Continue training." ) ); + workout_query.addentry( 3, true, 'C', _( "Continue training and don't ask again." ) ); + workout_query.query(); + switch( workout_query.ret ) { + case UILIST_CANCEL: + case 1: + act_id = activity_id::NULL_ID(); + act.set_to_null(); + return false; + case 3: + disable_query = true; + elapsed += act.moves_total - act.moves_left; + act.moves_total = to_moves( 60_minutes ); + act.moves_left = act.moves_total; + return true; + case 2: + default: + query_int( length, _( "Train for how long (minutes): " ) ); + elapsed += act.moves_total - act.moves_left; + act.moves_total = to_moves( length * 1_minutes ); + act.moves_left = act.moves_total; + return true; + break; + } +} + +void workout_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "disable_query", disable_query ); + jsout.member( "act_id", act_id ); + jsout.member( "duration", duration ); + jsout.member( "location", location ); + jsout.member( "stop_time", stop_time ); + jsout.member( "elapsed", elapsed ); + jsout.member( "intensity_modifier", intensity_modifier ); + jsout.member( "rest_mode", rest_mode ); + + jsout.end_object(); +} + +std::unique_ptr workout_activity_actor::deserialize( JsonIn &jsin ) +{ + workout_activity_actor actor = workout_activity_actor( tripoint_zero ); + + JsonObject data = jsin.get_object(); + + data.read( "disable_query", actor.disable_query ); + data.read( "act_id", actor.act_id ); + data.read( "duration", actor.duration ); + data.read( "location", actor.location ); + data.read( "stop_time", actor.stop_time ); + data.read( "elapsed", actor.elapsed ); + data.read( "intensity_modifier", actor.intensity_modifier ); + data.read( "rest_mode", actor.rest_mode ); + + return actor.clone(); +} + namespace activity_actors { @@ -1311,6 +1641,11 @@ deserialize_functions = { { activity_id( "ACT_OPEN_GATE" ), &open_gate_activity_actor::deserialize }, { activity_id( "ACT_PICKUP" ), &pickup_activity_actor::deserialize }, { activity_id( "ACT_TRY_SLEEP" ), &try_sleep_activity_actor::deserialize }, + { activity_id( "ACT_UNLOAD_MAG" ), &unload_mag_activity_actor::deserialize }, + { activity_id( "ACT_WORKOUT_HARD" ), &workout_activity_actor::deserialize }, + { activity_id( "ACT_WORKOUT_ACTIVE" ), &workout_activity_actor::deserialize }, + { activity_id( "ACT_WORKOUT_MODERATE" ), &workout_activity_actor::deserialize }, + { activity_id( "ACT_WORKOUT_LIGHT" ), &workout_activity_actor::deserialize }, }; } // namespace activity_actors diff --git a/src/activity_actor.h b/src/activity_actor.h index e8eeff6d42169..d8406d5ad2ff5 100644 --- a/src/activity_actor.h +++ b/src/activity_actor.h @@ -7,6 +7,7 @@ #include #include +#include "activity_type.h" #include "clone_ptr.h" #include "item_location.h" #include "item.h" @@ -514,6 +515,7 @@ class consume_activity_actor : public activity_actor item_location consume_location; item consume_item; std::vector consume_menu_selections; + std::string consume_menu_filter; bool force = false; /** * @pre @p other is a consume_activity_actor @@ -525,8 +527,10 @@ class consume_activity_actor : public activity_actor } public: consume_activity_actor( const item_location &consume_location, - std::vector consume_menu_selections ) : - consume_location( consume_location ), consume_menu_selections( consume_menu_selections ) {} + std::vector consume_menu_selections, + const std::string &consume_menu_filter ) : + consume_location( consume_location ), consume_menu_selections( consume_menu_selections ), + consume_menu_filter( consume_menu_filter ) {} consume_activity_actor( const item_location &consume_location ) : consume_location( consume_location ), consume_menu_selections( std::vector() ) {} @@ -581,6 +585,78 @@ class try_sleep_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class unload_mag_activity_actor : public activity_actor +{ + private: + int moves_total; + item_location target; + public: + unload_mag_activity_actor( int moves_total, const item_location &target ) : + moves_total( moves_total ), target( target ) {} + activity_id get_type() const override { + return activity_id( "ACT_UNLOAD_MAG" ); + } + + bool can_resume_with_internal( const activity_actor &other, const Character & ) const override { + const unload_mag_activity_actor &act = static_cast( other ); + return target == act.target; + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + /** Unloads the magazine instantly. Can be called without an activity. May destroy the item. */ + static void unload( Character &who, item_location &target ); + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + +class workout_activity_actor : public activity_actor +{ + private: + bool disable_query = false; // disables query, continue as long as possible + bool rest_mode = false; // work or rest during training session + time_duration duration; + tripoint location; + time_point stop_time; // can resume if time apart is not above + activity_id act_id = activity_id( "ACT_WORKOUT_LIGHT" ); // variable activities + int intensity_modifier = 1; + int elapsed = 0; + + public: + workout_activity_actor( const tripoint &loc ) : location( loc ) {} + + // can assume different sub-activities + activity_id get_type() const override { + return act_id; + } + + bool can_resume_with_internal( const activity_actor &other, const Character & ) const override { + const workout_activity_actor &w_actor = static_cast( other ); + return ( location == w_actor.location && calendar::turn - stop_time <= 10_minutes ); + } + + void start( player_activity &act, Character &who ) override; + void do_turn( player_activity &act, Character &who ) override; + void finish( player_activity &act, Character &who ) override; + void canceled( player_activity &/*act*/, Character &/*who*/ ) override; + + bool query_keep_training( player_activity &act, Character &who ); + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + namespace activity_actors { diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 09886602274db..9801c0c2deb54 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -187,7 +187,6 @@ static const activity_id ACT_TOOLMOD_ADD( "ACT_TOOLMOD_ADD" ); static const activity_id ACT_TRAIN( "ACT_TRAIN" ); static const activity_id ACT_TRAVELLING( "ACT_TRAVELLING" ); static const activity_id ACT_TREE_COMMUNION( "ACT_TREE_COMMUNION" ); -static const activity_id ACT_UNLOAD_MAG( "ACT_UNLOAD_MAG" ); static const activity_id ACT_VEHICLE( "ACT_VEHICLE" ); static const activity_id ACT_VEHICLE_DECONSTRUCTION( "ACT_VEHICLE_DECONSTRUCTION" ); static const activity_id ACT_VEHICLE_REPAIR( "ACT_VEHICLE_REPAIR" ); @@ -276,7 +275,6 @@ static const std::string flag_GIBBED( "GIBBED" ); static const std::string flag_HIDDEN_HALLU( "HIDDEN_HALLU" ); static const std::string flag_HIDDEN_ITEM( "HIDDEN_ITEM" ); static const std::string flag_HIDDEN_POISON( "HIDDEN_POISON" ); -static const std::string flag_MAG_DESTROY( "MAG_DESTROY" ); static const std::string flag_MESSY( "MESSY" ); static const std::string flag_PLANTABLE( "PLANTABLE" ); static const std::string flag_PULPED( "PULPED" ); @@ -288,6 +286,7 @@ static const std::string flag_SKINNED( "SKINNED" ); static const std::string flag_SPEEDLOADER( "SPEEDLOADER" ); static const std::string flag_SUPPORTS_ROOF( "SUPPORTS_ROOF" ); static const std::string flag_TREE( "TREE" ); +static const std::string flag_USES_BIONIC_POWER( "USES_BIONIC_POWER" ); using namespace activity_handlers; @@ -416,7 +415,6 @@ activity_handlers::finish_functions = { { ACT_PLAY_WITH_PET, play_with_pet_finish }, { ACT_SHAVE, shaving_finish }, { ACT_HAIRCUT, haircut_finish }, - { ACT_UNLOAD_MAG, unload_mag_finish }, { ACT_ROBOT_CONTROL, robot_control_finish }, { ACT_MIND_SPLICER, mind_splicer_finish }, { ACT_SPELLCASTING, spellcasting_finish }, @@ -1718,7 +1716,7 @@ void activity_handlers::firstaid_finish( player_activity *act, player *p ) // TODO: Store the patient somehow, retrieve here player &patient = *p; - const hp_part healed = static_cast( act->values[0] ); + const bodypart_id healed = bodypart_id( act->str_values[0] ); const int charges_consumed = actor->finish_using( *p, patient, *used_tool, healed ); p->consume_charges( it, charges_consumed ); @@ -1771,7 +1769,8 @@ void activity_handlers::forage_finish( player_activity *act, player *p ) debugmsg( "Invalid season" ); } - here.ter_set( here.getlocal( act->placement ), next_ter ); + const tripoint bush_pos = here.getlocal( act->placement ); + here.ter_set( bush_pos, next_ter ); // Survival gives a bigger boost, and Perception is leveled a bit. // Both survival and perception affect time to forage @@ -1809,6 +1808,8 @@ void activity_handlers::forage_finish( player_activity *act, player *p ) iexamine::practice_survival_while_foraging( p ); act->set_to_null(); + + here.maybe_trigger_trap( bush_pos, *p, true ); } void activity_handlers::generic_game_do_turn( player_activity * /*act*/, player *p ) @@ -2038,35 +2039,32 @@ void activity_handlers::reload_finish( player_activity *act, player *p ) } item &reloadable = *act->targets[ 0 ]; - item &ammo = *act->targets[1]; + item &ammo = *act->targets[ 1 ]; + std::string reloadable_name = reloadable.tname(); std::string ammo_name = ammo.tname(); const int qty = act->index; - const bool is_speedloader = ammo.has_flag( flag_SPEEDLOADER ); - const bool ammo_is_filthy = ammo.is_filthy(); if( !reloadable.reload( *p, std::move( act->targets[ 1 ] ), qty ) ) { - add_msg( m_info, _( "Can't reload the %s." ), reloadable.tname() ); + add_msg( m_info, _( "Can't reload the %s." ), reloadable_name ); return; } - std::string msg = _( "You reload the %s." ); - - if( ammo_is_filthy ) { + if( ammo.is_filthy() ) { reloadable.set_flag( "FILTHY" ); } if( reloadable.get_var( "dirt", 0 ) > 7800 ) { - msg = - _( "You manage to loosen some debris and make your %s somewhat operational." ); + add_msg( m_neutral, _( "You manage to loosen some debris and make your %s somewhat operational." ), + reloadable_name ); reloadable.set_var( "dirt", ( reloadable.get_var( "dirt", 0 ) - rng( 790, 2750 ) ) ); } if( reloadable.is_gun() ) { p->recoil = MAX_RECOIL; - if( reloadable.has_flag( flag_RELOAD_ONE ) && !is_speedloader ) { + if( reloadable.has_flag( flag_RELOAD_ONE ) && !ammo.has_flag( flag_SPEEDLOADER ) ) { for( int i = 0; i != qty; ++i ) { - msg = _( "You insert one %2$s into the %1$s." ); + add_msg( m_neutral, _( "You insert one %2$s into the %1$s." ), reloadable_name, ammo_name ); } } if( reloadable.type->gun->reload_noise_volume > 0 ) { @@ -2076,9 +2074,10 @@ void activity_handlers::reload_finish( player_activity *act, player *p ) sounds::sound_t::activity, reloadable.type->gun->reload_noise ); } } else if( reloadable.is_watertight_container() ) { - msg = _( "You refill the %s." ); + add_msg( m_neutral, _( "You refill the %s." ), reloadable_name ); + } else { + add_msg( m_neutral, _( "You reload the %1$s with %2$s." ), reloadable_name, ammo_name ); } - add_msg( m_neutral, msg, reloadable.tname(), ammo_name ); } void activity_handlers::start_fire_finish( player_activity *act, player *p ) @@ -2284,7 +2283,7 @@ void activity_handlers::vibe_do_turn( player_activity *act, player *p ) //Deduct 1 battery charge for every minute in use, or vibrator is much less effective item &vibrator_item = *act->targets.front(); - if( p->encumb( bp_mouth ) >= 30 ) { + if( p->encumb( bodypart_id( "mouth" ) ) >= 30 ) { act->moves_left = 0; add_msg( m_bad, _( "You have trouble breathing, and stop." ) ); } @@ -2546,7 +2545,10 @@ struct weldrig_hack { item &get_item() { if( veh != nullptr && part >= 0 ) { - pseudo.charges = veh->drain( itype_battery, 1000 - pseudo.charges ); + item pseudo_magazine( pseudo.magazine_default() ); + pseudo.put_in( pseudo_magazine, item_pocket::pocket_type::MAGAZINE_WELL ); + pseudo.ammo_set( itype_battery, veh->drain( itype_battery, + pseudo.ammo_capacity( ammotype( "battery" ) ) ) ); return pseudo; } @@ -2560,8 +2562,7 @@ struct weldrig_hack { return; } - veh->charge_battery( pseudo.charges ); - pseudo.charges = 0; + veh->charge_battery( pseudo.ammo_remaining() ); } ~weldrig_hack() { @@ -2670,7 +2671,6 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p ) } const item &fix = *act->targets[1]; - if( repeat == repeat_type::INIT ) { const int level = p->get_skill_level( actor->used_skill ); repair_item_actor::repair_type action_type = actor->default_action( fix, level ); @@ -2687,15 +2687,23 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p ) repair_item_actor::action_description( action_type ), fix.tname() ); ammotype current_ammo; - if( used_tool->ammo_current().is_null() ) { - current_ammo = item_controller->find_template( used_tool->ammo_default() )->ammo->type; + std::string ammo_name; + if( used_tool->has_flag( flag_USES_BIONIC_POWER ) ) { + ammo_name = _( "bionic power" ); + } else { - current_ammo = item_controller->find_template( used_tool->ammo_current() )->ammo->type; + if( used_tool->ammo_current().is_null() ) { + current_ammo = item_controller->find_template( used_tool->ammo_default() )->ammo->type; + } else { + current_ammo = item_controller->find_template( used_tool->ammo_current() )->ammo->type; + } + + ammo_name = item::nname( used_tool->ammo_current() ); } title += string_format( _( "Charges: %s/%s %s (%s per use)\n" ), used_tool->ammo_remaining(), used_tool->ammo_capacity( current_ammo ), - item::nname( used_tool->ammo_current() ), + ammo_name, used_tool->ammo_required() ); title += string_format( _( "Skill used: %s (%s)\n" ), actor->used_skill.obj().name(), level ); @@ -2726,7 +2734,6 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p ) } } while( repeat == repeat_type::INIT ); } - // Otherwise keep retrying act->moves_left = actor->move_cost; } @@ -2900,6 +2907,8 @@ void activity_handlers::clear_rubble_finish( player_activity *act, player *p ) here.furn_set( pos, f_null ); act->set_to_null(); + + here.maybe_trigger_trap( pos, *p, true ); } void activity_handlers::meditate_finish( player_activity *act, player *p ) @@ -2993,7 +3002,7 @@ void activity_handlers::travel_do_turn( player_activity *act, player *p ) tripoint sm_tri = here.getlocal( sm_to_ms_copy( omt_to_sm_copy( p->omt_path.back() ) ) ); tripoint centre_sub = sm_tri + point( SEEX, SEEY ); if( !here.passable( centre_sub ) ) { - tripoint_range candidates = here.points_in_radius( centre_sub, 2 ); + tripoint_range candidates = here.points_in_radius( centre_sub, 2 ); for( const tripoint &elem : candidates ) { if( here.passable( elem ) ) { centre_sub = elem; @@ -3663,9 +3672,9 @@ void activity_handlers::craft_do_turn( player_activity *act, player *p ) // Base moves for batch size with no speed modifier or assistants // Must ensure >= 1 so we don't divide by 0; - const double base_total_moves = std::max( 1, rec.batch_time( craft->charges, 1.0f, 0 ) ); + const double base_total_moves = std::max( 1, rec.batch_time( *p, craft->charges, 1.0f, 0 ) ); // Current expected total moves, includes crafting speed modifiers and assistants - const double cur_total_moves = std::max( 1, rec.batch_time( craft->charges, crafting_speed, + const double cur_total_moves = std::max( 1, rec.batch_time( *p, craft->charges, crafting_speed, assistants ) ); // Delta progress in moves adjusted for current crafting speed const double delta_progress = p->get_moves() * base_total_moves / cur_total_moves; @@ -4095,41 +4104,6 @@ void activity_handlers::haircut_finish( player_activity *act, player *p ) act->set_to_null(); } -void activity_handlers::unload_mag_finish( player_activity *act, player *p ) -{ - int qty = 0; - item &it = *act->targets[ 0 ]; - - std::vector remove_contained; - for( item *contained : it.contents.all_items_top() ) { - if( p->add_or_drop_with_msg( *contained, true ) ) { - qty += contained->charges; - remove_contained.push_back( contained ); - } - } - // remove the ammo leads in the belt - for( item *remove : remove_contained ) { - it.remove_item( *remove ); - } - - // remove the belt linkage - if( it.is_ammo_belt() ) { - if( it.type->magazine->linkage ) { - item link( *it.type->magazine->linkage, calendar::turn, qty ); - p->add_or_drop_with_msg( link, true ); - } - add_msg( _( "You disassemble your %s." ), it.tname() ); - } else { - add_msg( _( "You unload your %s." ), it.tname() ); - } - - if( it.has_flag( flag_MAG_DESTROY ) && it.ammo_remaining() == 0 ) { - act->targets[ 0 ].remove_item(); - } - - act->set_to_null(); -} - std::vector get_sorted_tiles_by_distance( const tripoint &abspos, const std::unordered_set &tiles ) { diff --git a/src/activity_handlers.h b/src/activity_handlers.h index fb59c19eb404b..b6309241fcf18 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -235,7 +235,6 @@ void fill_pit_finish( player_activity *act, player *p ); void play_with_pet_finish( player_activity *act, player *p ); void shaving_finish( player_activity *act, player *p ); void haircut_finish( player_activity *act, player *p ); -void unload_mag_finish( player_activity *act, player *p ); void robot_control_finish( player_activity *act, player *p ); void mind_splicer_finish( player_activity *act, player *p ); void spellcasting_finish( player_activity *act, player *p ); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index e43ba65f52b61..0fbd1e36f82d9 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1727,7 +1727,7 @@ static bool construction_activity( player &p, const zone_data * /*zone*/, const pc.id = built_chosen.id; map &here = get_map(); // Set the trap that has the examine function - if( here.tr_at( src_loc ).loadid == tr_null ) { + if( here.tr_at( src_loc ).is_null() ) { here.trap_set( src_loc, tr_unfinished_construction ); } // Use up the components @@ -3014,7 +3014,7 @@ int get_auto_consume_moves( player &p, const bool food ) void try_fuel_fire( player_activity &act, player &p, const bool starting_fire ) { const tripoint pos = p.pos(); - std::vector adjacent = closest_tripoints_first( pos, PICKUP_RANGE ); + std::vector adjacent = closest_points_first( pos, PICKUP_RANGE ); adjacent.erase( adjacent.begin() ); cata::optional best_fire = starting_fire ? act.placement : find_best_fire( adjacent, diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index eb177cf3e2a92..0339993e8eb2f 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -108,7 +108,7 @@ advanced_inventory::~advanced_inventory() } // Only refresh if we exited manually, otherwise we're going to be right back if( exit ) { - g->u.check_item_encumbrance_flag(); + get_player_character().check_item_encumbrance_flag(); } } @@ -127,6 +127,15 @@ void advanced_inventory::load_settings() aim_exit aim_code = static_cast( save_state->exit_code ); panes[left].load_settings( save_state->saved_area, squares, aim_code == aim_exit::re_entry ); panes[right].load_settings( save_state->saved_area_right, squares, aim_code == aim_exit::re_entry ); + // In-vehicle flags are set dynamically inside advanced_inventory_pane::load_settings, + // which means the flags may end up the same even if the areas are also the same. To + // avoid this, we use the saved in-vehicle flags instead. + if( panes[left].get_area() == panes[right].get_area() ) { + panes[left].set_area( squares[panes[left].get_area()], save_state->pane.in_vehicle ); + // Use the negated in-vehicle flag of the left pane to ensure different + // in-vehicle flags. + panes[right].set_area( squares[panes[right].get_area()], !save_state->pane.in_vehicle ); + } save_state->exit_code = aim_exit::none; } @@ -195,6 +204,11 @@ void advanced_inventory::init() src = ( save_state->active_left ) ? left : right; dest = ( save_state->active_left ) ? right : left; + + //sanity check, badly initialized values may cause problem in move_all_items( see assert() ) + if( panes[src].get_area() == AIM_ALL && panes[dest].get_area() == AIM_ALL ) { + panes[dest].set_area( AIM_INVENTORY ); + } } void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool active ) @@ -209,12 +223,13 @@ void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool nc_color norm = active ? c_white : c_dark_gray; + Character &player_character = get_player_character(); //print inventory's current and total weight + volume if( pane.get_area() == AIM_INVENTORY || pane.get_area() == AIM_WORN ) { - const double weight_carried = convert_weight( g->u.weight_carried() ); - const double weight_capacity = convert_weight( g->u.weight_capacity() ); - std::string volume_carried = format_volume( g->u.volume_carried() ); - std::string volume_capacity = format_volume( g->u.volume_capacity() ); + const double weight_carried = convert_weight( player_character.weight_carried() ); + const double weight_capacity = convert_weight( player_character.weight_capacity() ); + std::string volume_carried = format_volume( player_character.volume_carried() ); + std::string volume_capacity = format_volume( player_character.volume_capacity() ); // align right, so calculate formatted head length const std::string formatted_head = string_format( "%.1f/%.1f %s %s/%s %s", weight_carried, weight_capacity, weight_units(), @@ -225,7 +240,8 @@ void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool nc_color color = weight_carried > weight_capacity ? c_red : c_light_green; mvwprintz( window, point( hrightcol, 4 ), color, "%.1f", weight_carried ); wprintz( window, c_light_gray, "/%.1f %s ", weight_capacity, weight_units() ); - color = g->u.volume_carried().value() > g->u.volume_capacity().value() ? c_red : c_light_green; + color = player_character.volume_carried().value() > player_character.volume_capacity().value() ? + c_red : c_light_green; wprintz( window, color, volume_carried ); wprintz( window, c_light_gray, "/%s %s", volume_capacity, volume_units_abbr() ); } else { @@ -248,9 +264,9 @@ void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool maxvolume = get_map().max_volume( s.pos ); } formatted_head = string_format( "%3.1f %s %s/%s %s", - convert_weight( s.weight ), + convert_weight( pane.in_vehicle() ? s.weight_veh : s.weight ), weight_units(), - format_volume( s.volume ), + format_volume( pane.in_vehicle() ? s.volume_veh : s.volume ), format_volume( maxvolume ), volume_units_abbr() ); } @@ -333,7 +349,7 @@ void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool std::string item_name; std::string stolen_string; bool stolen = false; - if( !it.is_owned_by( g->u, true ) ) { + if( !it.is_owned_by( player_character, true ) ) { stolen_string = "!"; stolen = true; } @@ -592,8 +608,8 @@ void advanced_inventory::recalc_pane( side p ) if( s.can_store_in_vehicle() && !( same && there.in_vehicle() ) ) { bool do_vehicle = there.get_area() == s.id ? !there.in_vehicle() : true; pane.add_items_from_area( s, do_vehicle ); - alls.volume += s.volume; - alls.weight += s.weight; + alls.volume += s.volume_veh; + alls.weight += s.weight_veh; } // Add map items @@ -704,6 +720,7 @@ bool advanced_inventory::move_all_items( bool nested_call ) advanced_inventory_pane &spane = panes[src]; advanced_inventory_pane &dpane = panes[dest]; + Character &player_character = get_player_character(); // AIM_ALL source area routine if( spane.get_area() == AIM_ALL ) { // move all to `AIM_WORN' doesn't make sense (see `MAX_WORN_PER_TYPE') @@ -775,7 +792,7 @@ bool advanced_inventory::move_all_items( bool nested_call ) // restore the pane to its former glory panes[src] = shadow; // make it auto loop back, if not already doing so - if( !done && !g->u.activity ) { + if( !done && !player_character.activity ) { do_return_entry(); } return true; @@ -839,33 +856,31 @@ bool advanced_inventory::move_all_items( bool nested_call ) drop_locations dropped_favorite; if( spane.get_area() == AIM_INVENTORY ) { - for( size_t index = 0; index < g->u.inv.size(); ++index ) { - const std::list &stack = g->u.inv.const_stack( index ); - const item &it = stack.front(); - item_location indexed_item( g->u, const_cast( &it ) ); - - if( !spane.is_filtered( it ) ) { - int count; - if( it.count_by_charges() ) { - count = it.charges; - } else { - count = stack.size(); + //add all solid top level items + for( item &cloth : player_character.worn ) { + for( item *it : cloth.contents.all_items_top() ) { + if( !it->made_of_from_type( phase_id::SOLID ) ) { + continue; } - if( it.is_favorite ) { - dropped_favorite.emplace_back( indexed_item, count ); - } else { - dropped.emplace_back( indexed_item, count ); + if( !spane.is_filtered( *it ) ) { + if( it->is_favorite ) { + dropped_favorite.emplace_back( item_location( item_location( player_character, &cloth ), it ), + it->count() ); + } else { + dropped.emplace_back( item_location( item_location( player_character, &cloth ), it ), it->count() ); + } } } + } } else if( spane.get_area() == AIM_WORN ) { // do this in reverse, to account for vector item removal messing with future indices - auto iter = g->u.worn.rbegin(); - for( size_t idx = 0; idx < g->u.worn.size(); ++idx, ++iter ) { + auto iter = player_character.worn.rbegin(); + for( size_t idx = 0; idx < player_character.worn.size(); ++idx, ++iter ) { item &it = *iter; if( !spane.is_filtered( it ) ) { - item_location loc( g->u, &it ); + item_location loc( player_character, &it ); if( it.is_favorite ) { dropped_favorite.emplace_back( loc, it.count() ); } else { @@ -881,10 +896,10 @@ bool advanced_inventory::move_all_items( bool nested_call ) dropped = dropped_favorite; } - g->u.drop( dropped, g->u.pos() + darea.off ); + player_character.drop( dropped, player_character.pos() + darea.off ); } else { if( dpane.get_area() == AIM_INVENTORY || dpane.get_area() == AIM_WORN ) { - g->u.activity.coords.push_back( g->u.pos() ); + player_character.activity.coords.push_back( player_character.pos() ); std::vector target_items; std::vector quantities; item_stack::iterator stack_begin, stack_end; @@ -923,16 +938,17 @@ bool advanced_inventory::move_all_items( bool nested_call ) if( filtered_any_bucket ) { add_msg( m_info, _( "Skipping filled buckets to avoid spilling their contents." ) ); } - g->u.assign_activity( player_activity( pickup_activity_actor( - target_items, - quantities, - cata::optional( g->u.pos() ) - ) ) ); + player_character.assign_activity( player_activity( pickup_activity_actor( + target_items, + quantities, + cata::optional( player_character.pos() ) + ) ) ); } else { // Vehicle and map destinations are handled the same. // Check first if the destination area still have enough room for moving all. - if( !is_processing() && sarea.volume > darea.free_volume( dpane.in_vehicle() ) && + const units::volume &src_volume = spane.in_vehicle() ? sarea.volume_veh : sarea.volume; + if( !is_processing() && src_volume > darea.free_volume( dpane.in_vehicle() ) && !query_yn( _( "There isn't enough room, do you really want to move all?" ) ) ) { return false; } @@ -980,12 +996,12 @@ bool advanced_inventory::move_all_items( bool nested_call ) add_msg( m_info, _( "Skipping filled buckets to avoid spilling their contents." ) ); } - g->u.assign_activity( player_activity( move_items_activity_actor( - target_items, - quantities, - dpane.in_vehicle(), - relative_destination - ) ) ); + player_character.assign_activity( player_activity( move_items_activity_actor( + target_items, + quantities, + dpane.in_vehicle(), + relative_destination + ) ) ); } } @@ -1082,7 +1098,7 @@ void advanced_inventory::redraw_sidebar() right_print( head, 0, +3, c_white, string_format( _( "< [%s] keybindings >" ), ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); - if( g->u.has_watch() ) { + if( get_player_character().has_watch() ) { const std::string time = to_string_time_of_day( calendar::turn ); mvwprintz( head, point( 2, 0 ), c_white, time ); } @@ -1149,27 +1165,31 @@ void advanced_inventory::start_activity( const aim_location destarea, const aim_ const bool by_charges = sitem->items.front()->count_by_charges(); + Character &player_character = get_player_character(); if( destarea == AIM_WORN ) { - g->u.assign_activity( ACT_WEAR ); + player_character.assign_activity( ACT_WEAR ); if( by_charges ) { if( from_vehicle ) { - g->u.activity.targets.emplace_back( vehicle_cursor( *squares[srcarea].veh, squares[srcarea].vstor ), - sitem->items.front() ); + player_character.activity.targets.emplace_back( vehicle_cursor( *squares[srcarea].veh, + squares[srcarea].vstor ), + sitem->items.front() ); } else { - g->u.activity.targets.emplace_back( map_cursor( squares[srcarea].pos ), sitem->items.front() ); + player_character.activity.targets.emplace_back( map_cursor( squares[srcarea].pos ), + sitem->items.front() ); } - g->u.activity.values.push_back( amount_to_move ); + player_character.activity.values.push_back( amount_to_move ); } else { for( std::vector::iterator it = sitem->items.begin(); amount_to_move > 0 && it != sitem->items.end(); ++it ) { if( from_vehicle ) { - g->u.activity.targets.emplace_back( vehicle_cursor( *squares[srcarea].veh, squares[srcarea].vstor ), - *it ); + player_character.activity.targets.emplace_back( vehicle_cursor( *squares[srcarea].veh, + squares[srcarea].vstor ), + *it ); } else { - g->u.activity.targets.emplace_back( map_cursor( squares[srcarea].pos ), *it ); + player_character.activity.targets.emplace_back( map_cursor( squares[srcarea].pos ), *it ); } - g->u.activity.values.push_back( 0 ); + player_character.activity.values.push_back( 0 ); --amount_to_move; } } @@ -1200,21 +1220,21 @@ void advanced_inventory::start_activity( const aim_location destarea, const aim_ } if( destarea == AIM_INVENTORY ) { - g->u.assign_activity( player_activity( pickup_activity_actor( - target_items, - quantities, - from_vehicle ? cata::nullopt : cata::optional( g->u.pos() ) - ) ) ); + player_character.assign_activity( player_activity( pickup_activity_actor( + target_items, + quantities, + from_vehicle ? cata::nullopt : cata::optional( player_character.pos() ) + ) ) ); } else { // Stash the destination const tripoint relative_destination = squares[destarea].off; - g->u.assign_activity( player_activity( move_items_activity_actor( - target_items, - quantities, - to_vehicle, - relative_destination - ) ) ); + player_character.assign_activity( player_activity( move_items_activity_actor( + target_items, + quantities, + to_vehicle, + relative_destination + ) ) ); } } } @@ -1251,6 +1271,7 @@ bool advanced_inventory::action_move_item( advanced_inv_listitem *sitem, if( !query_charges( destarea, *sitem, action, amount_to_move ) ) { return false; } + avatar &player_character = get_avatar(); // This makes sure that all item references in the advanced_inventory_pane::items vector // are recalculated, even when they might not have changed, but they could (e.g. items // taken from inventory, but unable to put into the cargo trunk go back into the inventory, @@ -1267,10 +1288,10 @@ bool advanced_inventory::action_move_item( advanced_inv_listitem *sitem, // make sure advanced inventory is reopened after activity completion. do_return_entry(); - g->u.assign_activity( ACT_WEAR ); + player_character.assign_activity( ACT_WEAR ); - g->u.activity.targets.emplace_back( g->u, sitem->items.front() ); - g->u.activity.values.push_back( amount_to_move ); + player_character.activity.targets.emplace_back( player_character, sitem->items.front() ); + player_character.activity.values.push_back( amount_to_move ); // exit so that the activity can be carried out exit = true; @@ -1285,30 +1306,47 @@ bool advanced_inventory::action_move_item( advanced_inv_listitem *sitem, if( srcarea == AIM_WORN && destarea == AIM_INVENTORY ) { // this is ok because worn items are never stacked (can't move more than 1). - g->u.takeoff( idx ); + player_character.takeoff( idx ); // exit so that the action can be carried out exit = true; } else { // important if item is worn - if( g->u.can_unwield( *sitem->items.front() ).success() ) { - g->u.assign_activity( ACT_DROP ); - g->u.activity.placement = squares[destarea].off; + if( player_character.can_unwield( *sitem->items.front() ).success() ) { + player_character.assign_activity( ACT_DROP ); + player_character.activity.placement = squares[destarea].off; // incase there is vehicle cargo space at dest but the player wants to drop to ground if( !to_vehicle ) { - g->u.activity.str_values.push_back( "force_ground" ); + player_character.activity.str_values.push_back( "force_ground" ); } - g->u.activity.targets.push_back( item_location( g->u, sitem->items.front() ) ); - g->u.activity.values.push_back( amount_to_move ); + int remaining_amount = amount_to_move; + for( item *itm : sitem->items ) { + if( remaining_amount <= 0 ) { + break; + } + player_character.activity.targets.emplace_back( player_character, itm ); + const int move_amount = itm->count_by_charges() ? + std::min( remaining_amount, itm->charges ) : 1; + player_character.activity.values.emplace_back( move_amount ); + remaining_amount -= move_amount; + } // exit so that the activity can be carried out exit = true; } } } else { - if( destarea == AIM_INVENTORY && !g->u.can_stash( *sitem->items.front() ) ) { + bool can_stash = false; + if( sitem->items.front()->count_by_charges() ) { + item dummy = *sitem->items.front(); + dummy.charges = amount_to_move; + can_stash = player_character.can_stash( dummy ); + } else { + can_stash = player_character.can_stash( *sitem->items.front() ); + } + if( destarea == AIM_INVENTORY && !can_stash ) { popup( _( "You have no space for %s" ), sitem->items.front()->tname() ); return false; } @@ -1338,8 +1376,9 @@ void advanced_inventory::action_examine( advanced_inv_listitem *sitem, const auto info_startx = [this]() -> int { return colstart + ( src == advanced_inventory::side::left ? w_width / 2 : 0 ); }; + avatar &player_character = get_avatar(); if( spane.get_area() == AIM_INVENTORY || spane.get_area() == AIM_WORN ) { - item_location loc( g->u, sitem->items.front() ); + item_location loc( player_character, sitem->items.front() ); // Setup a "return to AIM" activity. If examining the item creates a new activity // (e.g. reading, reloading, activating), the new activity will be put on top of // "return to AIM". Once the new activity is finished, "return to AIM" comes back @@ -1347,17 +1386,21 @@ void advanced_inventory::action_examine( advanced_inv_listitem *sitem, // If examining the item did not create a new activity, we have to remove // "return to AIM". do_return_entry(); - assert( g->u.has_activity( ACT_ADV_INVENTORY ) ); + assert( player_character.has_activity( ACT_ADV_INVENTORY ) ); + // `inventory_item_menu` may call functions that move items, so we should + // always recalculate during this period to ensure all item references are valid + always_recalc = true; ret = g->inventory_item_menu( loc, info_startx, info_width, src == advanced_inventory::side::left ? game::LEFT_OF_INFO : game::RIGHT_OF_INFO ); - if( !g->u.has_activity( ACT_ADV_INVENTORY ) ) { + always_recalc = false; + if( !player_character.has_activity( ACT_ADV_INVENTORY ) ) { exit = true; } else { - g->u.cancel_activity(); + player_character.cancel_activity(); } // Might have changed a stack (activated an item, repaired an item, etc.) if( spane.get_area() == AIM_INVENTORY ) { - g->u.inv.restack( g->u ); + player_character.inv.restack( player_character ); } recalc = true; } else { @@ -1384,7 +1427,8 @@ void advanced_inventory::display() { init(); - g->u.inv.restack( g->u ); + avatar &player_character = get_avatar(); + player_character.inv.restack( player_character ); input_context ctxt{ register_ctxt() }; @@ -1432,6 +1476,10 @@ void advanced_inventory::display() ui->mark_resize(); ui->on_redraw( [&]( const ui_adaptor & ) { + if( always_recalc ) { + recalc = true; + } + redraw_pane( advanced_inventory::side::left ); redraw_pane( advanced_inventory::side::right ); redraw_sidebar(); @@ -1447,7 +1495,7 @@ void advanced_inventory::display() } while( !exit ) { - if( g->u.moves < 0 ) { + if( player_character.moves < 0 ) { do_return_entry(); return; } @@ -1776,11 +1824,12 @@ bool advanced_inventory::query_charges( aim_location destarea, const advanced_in amount = std::min( cntmax, amount ); } } + Character &player_character = get_player_character(); // Inventory has a weight capacity, map and vehicle don't have that if( destarea == AIM_INVENTORY || destarea == AIM_WORN ) { const units::mass unitweight = it.weight() / ( by_charges ? it.charges : 1 ); - const units::mass max_weight = g->u.has_trait( trait_DEBUG_STORAGE ) ? - units::mass_max : g->u.weight_capacity() * 4 - g->u.weight_carried(); + const units::mass max_weight = player_character.has_trait( trait_DEBUG_STORAGE ) ? + units::mass_max : player_character.weight_capacity() * 4 - player_character.weight_carried(); if( unitweight > 0_gram && unitweight * amount > max_weight ) { const int weightmax = max_weight / unitweight; if( weightmax <= 0 ) { @@ -1794,7 +1843,7 @@ bool advanced_inventory::query_charges( aim_location destarea, const advanced_in if( destarea == AIM_WORN ) { const auto &id = sitem.items.front()->typeId(); // how many slots are available for the item? - const int slots_available = MAX_WORN_PER_TYPE - g->u.amount_worn( id ); + const int slots_available = MAX_WORN_PER_TYPE - player_character.amount_worn( id ); // base the amount to equip on amount of slots available amount = std::min( slots_available, input_amount ); } @@ -1858,8 +1907,9 @@ void advanced_inventory::draw_minimap() static const std::array sides = {{left, right}}; // get the center of the window tripoint pc = {getmaxx( minimap ) / 2, getmaxy( minimap ) / 2, 0}; + Character &player_character = get_player_character(); // draw the 3x3 tiles centered around player - get_map().draw( minimap, g->u.pos() ); + get_map().draw( minimap, player_character.pos() ); for( auto s : sides ) { char sym = get_minimap_sym( s ); if( sym == '\0' ) { @@ -1885,7 +1935,7 @@ void advanced_inventory::draw_minimap() } if( !invert_left || !invert_right ) { - g->u.draw( minimap, g->u.pos(), invert_left || invert_right ); + player_character.draw( minimap, player_character.pos(), invert_left || invert_right ); } } @@ -1930,10 +1980,11 @@ void advanced_inventory::swap_panes() void advanced_inventory::do_return_entry() { + Character &player_character = get_player_character(); // only save pane settings save_settings( true ); - g->u.assign_activity( ACT_ADV_INVENTORY ); - g->u.activity.auto_resume = true; + player_character.assign_activity( ACT_ADV_INVENTORY ); + player_character.activity.auto_resume = true; save_state->exit_code = aim_exit::re_entry; } diff --git a/src/advanced_inv.h b/src/advanced_inv.h index 29baf1e1da147..28267a33c9774 100644 --- a/src/advanced_inv.h +++ b/src/advanced_inv.h @@ -81,6 +81,7 @@ class advanced_inventory int colstart = 0; bool recalc = false; + bool always_recalc = false; /** * Which panels is active (item moved from there). */ diff --git a/src/advanced_inv_area.cpp b/src/advanced_inv_area.cpp index ee86e9714d993..a75b5dfc5dc34 100644 --- a/src/advanced_inv_area.cpp +++ b/src/advanced_inv_area.cpp @@ -65,8 +65,10 @@ void advanced_inv_area::init() vstor = -1; // must update in main function volume = 0_ml; + volume_veh = 0_ml; // must update in main function weight = 0_gram; + weight_veh = 0_gram; map &here = get_map(); switch( id ) { case AIM_INVENTORY: diff --git a/src/advanced_inv_area.h b/src/advanced_inv_area.h index 744544c279c71..41294e996faa8 100644 --- a/src/advanced_inv_area.h +++ b/src/advanced_inv_area.h @@ -68,7 +68,9 @@ class advanced_inv_area std::string flags; // total volume and weight of items currently there units::volume volume; + units::volume volume_veh; units::mass weight; + units::mass weight_veh; // maximal count / volume of items there. int max_size = 0; // appears as part of the legend at the top right diff --git a/src/advanced_inv_listitem.cpp b/src/advanced_inv_listitem.cpp index 77ebbd5139a94..b1b52c32286d3 100644 --- a/src/advanced_inv_listitem.cpp +++ b/src/advanced_inv_listitem.cpp @@ -16,7 +16,7 @@ advanced_inv_listitem::advanced_inv_listitem( item *an_item, int index, int coun , stacks( count ) , volume( an_item->volume() * stacks ) , weight( an_item->weight() * stacks ) - , cat( &an_item->get_category() ) + , cat( &an_item->get_category_of_contents() ) , from_vehicle( from_vehicle ) { items.push_back( an_item ); @@ -35,7 +35,7 @@ advanced_inv_listitem::advanced_inv_listitem( const std::vector &list, i stacks( list.size() ), volume( list.front()->volume() * stacks ), weight( list.front()->weight() * stacks ), - cat( &list.front()->get_category() ), + cat( &list.front()->get_category_of_contents() ), from_vehicle( from_vehicle ) { assert( stacks >= 1 ); diff --git a/src/advanced_inv_pane.cpp b/src/advanced_inv_pane.cpp index 60534b6f88f56..622d7ba586229 100644 --- a/src/advanced_inv_pane.cpp +++ b/src/advanced_inv_pane.cpp @@ -129,8 +129,6 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, bool vehicle_override ) { assert( square.id != AIM_ALL ); - square.volume = 0_ml; - square.weight = 0_gram; if( !square.canputitems() ) { return; } @@ -139,8 +137,12 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, // Existing items are *not* cleared on purpose, this might be called // several times in case all surrounding squares are to be shown. if( square.id == AIM_INVENTORY ) { + square.volume = 0_ml; + square.weight = 0_gram; items = u.get_AIM_inventory( *this, square ); } else if( square.id == AIM_WORN ) { + square.volume = 0_ml; + square.weight = 0_gram; auto iter = u.worn.begin(); for( size_t i = 0; i < u.worn.size(); ++i, ++iter ) { advanced_inv_listitem it( &*iter, i, 1, square.id, false ); @@ -152,6 +154,8 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, items.push_back( it ); } } else if( square.id == AIM_CONTAINER ) { + square.volume = 0_ml; + square.weight = 0_gram; item *cont = square.get_container( in_vehicle() ); if( cont != nullptr ) { if( !cont->is_container_empty() ) { @@ -166,6 +170,13 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, } } else { bool is_in_vehicle = square.can_store_in_vehicle() && ( in_vehicle() || vehicle_override ); + if( is_in_vehicle ) { + square.volume_veh = 0_ml; + square.weight_veh = 0_gram; + } else { + square.volume = 0_ml; + square.weight = 0_gram; + } const advanced_inv_area::itemstack &stacks = is_in_vehicle ? square.i_stacked( square.veh->get_items( square.vstor ) ) : square.i_stacked( m.i_at( square.pos ) ); @@ -175,8 +186,13 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, if( is_filtered( *it.items.front() ) ) { continue; } - square.volume += it.volume; - square.weight += it.weight; + if( is_in_vehicle ) { + square.volume_veh += it.volume; + square.weight_veh += it.weight; + } else { + square.volume += it.volume; + square.weight += it.weight; + } items.push_back( it ); } } diff --git a/src/animation.cpp b/src/animation.cpp index 9a43828fb16e5..42d3bb5bfeceb 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -84,7 +84,7 @@ class bullet_animation : public basic_animation bool is_point_visible( const tripoint &p, int margin = 0 ) { - return g->is_in_viewport( p, margin ) && g->u.sees( p ); + return g->is_in_viewport( p, margin ) && get_player_character().sees( p ); } bool is_radius_visible( const tripoint ¢er, int radius ) @@ -303,20 +303,21 @@ void explosion_handler::draw_custom_explosion( const tripoint &, // Start by getting rid of everything except current z-level std::map neighbors; + avatar &player_character = get_avatar(); #if defined(TILES) if( !use_tiles ) { for( const auto &pr : all_area ) { - const tripoint relative_point = relative_view_pos( g->u, pr.first ); + const tripoint relative_point = relative_view_pos( player_character, pr.first ); if( relative_point.z == 0 ) { neighbors[pr.first] = explosion_tile{ N_NO_NEIGHBORS, pr.second }; } } } else { // In tiles mode, the coordinates have to be absolute - const tripoint view_center = relative_view_pos( g->u, g->u.pos() ); + const tripoint view_center = relative_view_pos( player_character, player_character.pos() ); for( const auto &pr : all_area ) { // Relative point is only used for z level check - const tripoint relative_point = relative_view_pos( g->u, pr.first ); + const tripoint relative_point = relative_view_pos( player_character, pr.first ); if( relative_point.z == view_center.z ) { neighbors[pr.first] = explosion_tile{ N_NO_NEIGHBORS, pr.second }; } @@ -324,7 +325,7 @@ void explosion_handler::draw_custom_explosion( const tripoint &, } #else for( const auto &pr : all_area ) { - const tripoint relative_point = relative_view_pos( g->u, pr.first ); + const tripoint relative_point = relative_view_pos( player_character, pr.first ); if( relative_point.z == 0 ) { neighbors[pr.first] = explosion_tile{ N_NO_NEIGHBORS, pr.second }; } @@ -439,7 +440,8 @@ void draw_bullet_curses( map &m, const tripoint &t, const char bullet, const tri return; } - const tripoint vp = g->u.pos() + g->u.view_offset; + avatar &player_character = get_avatar(); + const tripoint vp = player_character.pos() + player_character.view_offset; if( vp.z != t.z ) { return; @@ -447,7 +449,7 @@ void draw_bullet_curses( map &m, const tripoint &t, const char bullet, const tri shared_ptr_fast bullet_cb = make_shared_fast( [&]() { if( p != nullptr && p->z == vp.z ) { - m.drawsq( g->w_terrain, g->u, *p, false, true, vp ); + m.drawsq( g->w_terrain, player_character, *p, false, true, vp ); } mvwputch( g->w_terrain, t.xy() - vp.xy() + point( POSX, POSY ), c_red, bullet ); } ); @@ -628,7 +630,7 @@ void draw_line_curses( game &g, const tripoint ¢er, const std::vector &points ) { + map &here = get_map(); for( const tripoint &p : points ) { - g.m.drawsq( g.w_terrain, g.u, p, true, true ); + here.drawsq( g.w_terrain, g.u, p, true, true ); } const tripoint p = points.empty() ? tripoint {POSX, POSY, 0} : @@ -733,36 +736,7 @@ void game::draw_weather( const weather_printable &w ) return; } - static const std::string weather_acid_drop {"weather_acid_drop"}; - static const std::string weather_rain_drop {"weather_rain_drop"}; - static const std::string weather_snowflake {"weather_snowflake"}; - - std::string weather_name; - switch( w.wtype ) { - // Acid weathers; uses acid droplet tile, fallthrough intended - case WEATHER_ACID_DRIZZLE: - case WEATHER_ACID_RAIN: - weather_name = weather_acid_drop; - break; - // Normal rainy weathers; uses normal raindrop tile, fallthrough intended - case WEATHER_LIGHT_DRIZZLE: - case WEATHER_DRIZZLE: - case WEATHER_RAINY: - case WEATHER_THUNDER: - case WEATHER_LIGHTNING: - weather_name = weather_rain_drop; - break; - // Snowy weathers; uses snowflake tile, fallthrough intended - case WEATHER_FLURRIES: - case WEATHER_SNOW: - case WEATHER_SNOWSTORM: - weather_name = weather_snowflake; - break; - default: - break; - } - - tilecontext->init_draw_weather( w, std::move( weather_name ) ); + tilecontext->init_draw_weather( w, w.wtype->tiles_animation ); } #else void game::draw_weather( const weather_printable &w ) diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index f3fc57eab24a2..69494835eacaf 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -48,7 +48,7 @@ namespace { std::string clothing_layer( const item &worn_item ); std::vector clothing_properties( - const item &worn_item, int width, const Character & ); + const item &worn_item, int width, const Character &, const bodypart_id &bp ); std::vector clothing_protection( const item &worn_item, int width ); std::vector clothing_flags_description( const item &worn_item ); @@ -169,7 +169,8 @@ void draw_mid_pane( const catacurses::window &w_sort_middle, // NOLINTNEXTLINE(cata-use-named-point-constants) size_t i = fold_and_print( w_sort_middle, point( 1, 0 ), win_width - 1, c_white, worn_item_it->type_name( 1 ) ) - 1; - std::vector props = clothing_properties( *worn_item_it, win_width - 3, c ); + std::vector props = clothing_properties( *worn_item_it, win_width - 3, c, + bodypart_id( tabindex ) ); nc_color color = c_light_gray; for( std::string &iter : props ) { print_colored_text( w_sort_middle, point( 2, ++i ), color, c_light_gray, iter ); @@ -289,7 +290,7 @@ std::string clothing_layer( const item &worn_item ) } std::vector clothing_properties( - const item &worn_item, const int width, const Character &c ) + const item &worn_item, const int width, const Character &c, const bodypart_id &bp ) { std::vector props; props.reserve( 5 ); @@ -297,9 +298,9 @@ std::vector clothing_properties( const std::string space = " "; props.push_back( string_format( "[%s]", _( "Properties" ) ) ); props.push_back( name_and_value( space + _( "Coverage:" ), - string_format( "%3d", worn_item.get_coverage() ), width ) ); + string_format( "%3d", worn_item.get_coverage( bp ) ), width ) ); props.push_back( name_and_value( space + _( "Encumbrance:" ), - string_format( "%3d", worn_item.get_encumber( c ) ), + string_format( "%3d", worn_item.get_encumber( c, bp ) ), width ) ); props.push_back( name_and_value( space + _( "Warmth:" ), string_format( "%3d", worn_item.get_warmth() ), width ) ); @@ -398,7 +399,7 @@ static std::vector items_cover_bp( const Character &c, int b for( auto elem_it = c.worn.begin(); elem_it != c.worn.end(); ++elem_it ) { if( elem_it->covers( convert_bp( static_cast( bp ) ).id() ) ) { s.push_back( { get_item_penalties( elem_it, c, bp ), - elem_it->get_encumber( c ), + elem_it->get_encumber( c, convert_bp( static_cast( bp ) ).id() ), elem_it->tname() } ); } @@ -742,7 +743,7 @@ void player::sort_armor() } worn.splice( to, worn, tmp_worn[selected] ); selected = leftListIndex; - reset_encumbrance(); + calc_encumbrance(); } }; @@ -817,7 +818,7 @@ void player::sort_armor() } ); std::copy( worn_copy.begin(), worn_copy.end(), worn.begin() ); - reset_encumbrance(); + calc_encumbrance(); } else if( action == "EQUIP_ARMOR" ) { // filter inventory for all items that are armor/clothing item_location loc = game_menus::inv::wear( *this ); diff --git a/src/artifact.cpp b/src/artifact.cpp index 351490a4eda79..9746a4f6cff6d 100644 --- a/src/artifact.cpp +++ b/src/artifact.cpp @@ -833,10 +833,7 @@ itype_id new_artifact() def.melee[DT_BASH] = info.melee_bash; def.melee[DT_CUT] = info.melee_cut; def.m_to_hit = info.melee_hit; - def.armor->covers = info.covers; - def.armor->encumber = info.encumb; - def.armor->max_encumber = info.max_encumb; - def.armor->coverage = info.coverage; + def.armor->data.push_back( { info.encumb, info.max_encumb, info.coverage, info.covers } ); def.armor->thickness = info.thickness; def.armor->env_resist = info.env_resist; def.armor->warmth = info.warmth; @@ -861,13 +858,7 @@ itype_id new_artifact() def.weight = 1_gram; } - def.armor->encumber += modinfo.encumb; - - if( modinfo.coverage > 0 || def.armor->coverage > std::abs( modinfo.coverage ) ) { - def.armor->coverage += modinfo.coverage; - } else { - def.armor->coverage = 0; - } + def.armor->data.push_back( { modinfo.encumb, modinfo.max_encumb, modinfo.coverage, modinfo.covers } ); if( modinfo.thickness > 0 || def.armor->thickness > std::abs( modinfo.thickness ) ) { def.armor->thickness += modinfo.thickness; @@ -1278,11 +1269,12 @@ void it_artifact_armor::deserialize( const JsonObject &jo ) m_to_hit = jo.get_int( "m_to_hit" ); item_tags = jo.get_tags( "item_flags" ); - jo.read( "covers", armor->covers ); - armor->encumber = jo.get_int( "encumber" ); // Old saves don't have max_encumber, so set it to base encumbrance value - armor->max_encumber = jo.get_int( "max_encumber", armor->encumber ); - armor->coverage = jo.get_int( "coverage" ); + armor->data.push_back( { jo.get_int( "encumber" ), jo.get_int( "max_encumber", jo.get_int( "encumber" ) ), jo.get_int( "coverage" ), {} } ); + + // A horrible solution to the required change here, but it works for now + jo.read( "covers", armor->data[0].covers ); + armor->thickness = jo.get_int( "material_thickness" ); armor->env_resist = jo.get_int( "env_resist" ); armor->warmth = jo.get_int( "warmth" ); @@ -1417,10 +1409,13 @@ void it_artifact_armor::serialize( JsonOut &json ) const json.member( "techniques", techniques ); // armor data - json.member( "covers", armor->covers ); - json.member( "encumber", armor->encumber ); - json.member( "max_encumber", armor->max_encumber ); - json.member( "coverage", armor->coverage ); + armor_portion_data tempData; + json.member( "encumber", tempData.encumber ); + json.member( "max_encumber", tempData.max_encumber ); + json.member( "coverage", tempData.coverage ); + json.member( "covers", tempData.covers ); + armor->data.push_back( tempData ); + json.member( "material_thickness", armor->thickness ); json.member( "env_resist", armor->env_resist ); json.member( "warmth", armor->warmth ); diff --git a/src/ascii_art.cpp b/src/ascii_art.cpp index a2fb9a66736b8..f39b5aaf88018 100644 --- a/src/ascii_art.cpp +++ b/src/ascii_art.cpp @@ -3,7 +3,7 @@ #include "assign.h" #include "generic_factory.h" -static const int ascii_art_width = 42; +static const int ascii_art_width = 41; namespace { diff --git a/src/auto_pickup.cpp b/src/auto_pickup.cpp index ca2777e160844..7d8a4a917653e 100644 --- a/src/auto_pickup.cpp +++ b/src/auto_pickup.cpp @@ -6,8 +6,8 @@ #include #include -#include "avatar.h" #include "cata_utility.h" +#include "character.h" #include "color.h" #include "cursesdef.h" #include "debug.h" @@ -77,6 +77,7 @@ void user_interface::show() int iLine = 0; int iColumn = 1; int iStartPos = 0; + Character &player_character = get_player_character(); ui.on_redraw( [&]( const ui_adaptor & ) { // Redraw the border @@ -99,7 +100,7 @@ void user_interface::show() tmpx += shortcut_print( w_header, point( tmpx, 0 ), c_white, c_light_green, _( "ove" ) ) + 2; tmpx += shortcut_print( w_header, point( tmpx, 0 ), c_white, c_light_green, _( "nable" ) ) + 2; tmpx += shortcut_print( w_header, point( tmpx, 0 ), c_white, c_light_green, _( "isable" ) ) + 2; - if( !g->u.name.empty() ) { + if( !player_character.name.empty() ) { shortcut_print( w_header, point( tmpx, 0 ), c_white, c_light_green, _( "est" ) ); } tmpx = 0; @@ -363,7 +364,7 @@ void user_interface::show() iLine--; iColumn = 1; } - } else if( action == "TEST_RULE" && currentPageNonEmpty && !g->u.name.empty() ) { + } else if( action == "TEST_RULE" && currentPageNonEmpty && !player_character.name.empty() ) { cur_rules[iLine].test_pattern(); } else if( action == "SWITCH_AUTO_PICKUP_OPTION" ) { // TODO: Now that NPCs use this function, it could be used for them too @@ -389,9 +390,10 @@ void player_settings::show() { user_interface ui; + Character &player_character = get_player_character(); ui.title = _( " AUTO PICKUP MANAGER " ); ui.tabs.emplace_back( _( "[]" ), global_rules ); - if( !g->u.name.empty() ) { + if( !player_character.name.empty() ) { ui.tabs.emplace_back( _( "[]" ), character_rules ); } ui.is_autopickup = true; @@ -403,7 +405,7 @@ void player_settings::show() } save_global(); - if( !g->u.name.empty() ) { + if( !player_character.name.empty() ) { save_character(); } invalidate(); diff --git a/src/avatar.cpp b/src/avatar.cpp index 22ebcce09c737..592ad58f0e619 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -62,6 +62,8 @@ #include "stomach.h" #include "string_formatter.h" #include "string_id.h" +#include "talker.h" +#include "talker_avatar.h" #include "translations.h" #include "type_id.h" #include "ui.h" @@ -131,6 +133,7 @@ avatar::avatar() show_map_memory = true; active_mission = nullptr; grab_type = object_type::NONE; + calorie_diary.push_front( daily_calories{} ); } void avatar::toggle_map_memory() @@ -414,6 +417,12 @@ bool avatar::read( item &it, const bool continuous ) } return false; } + + if( it.get_use( "learn_spell" ) ) { + it.get_use( "learn_spell" )->call( *this, it, it.active, pos() ); + return true; + } + const int time_taken = time_to_read( it, *reader ); add_msg( m_debug, "avatar::read: time_taken = %d", time_taken ); @@ -1270,7 +1279,8 @@ void avatar::reset_stats() // Dodge-related effects mod_dodge_bonus( mabuff_dodge_bonus() - - ( encumb( bp_leg_l ) + encumb( bp_leg_r ) ) / 20.0f - encumb( bp_torso ) / 10.0f ); + ( encumb( bodypart_id( "leg_l" ) ) + encumb( bodypart_id( "leg_r" ) ) ) / 20.0f - encumb( + bodypart_id( "torso" ) ) / 10.0f ); // Whiskers don't work so well if they're covered if( has_trait( trait_WHISKERS ) && !wearing_something_on( bodypart_id( "mouth" ) ) ) { mod_dodge_bonus( 1 ); @@ -1631,6 +1641,43 @@ bool avatar::invoke_item( item *used, const std::string &method ) return Character::invoke_item( used, method ); } +void avatar::advance_daily_calories() +{ + calorie_diary.push_front( daily_calories{} ); + if( calorie_diary.size() > 30 ) { + calorie_diary.pop_back(); + } +} + +void avatar::add_spent_calories( int cal ) +{ + calorie_diary.front().spent += cal; +} + +void avatar::add_gained_calories( int cal ) +{ + calorie_diary.front().gained += cal; +} + +std::string avatar::total_daily_calories_string() const +{ + std::string ret = " gained spent total\n"; + int num_day = 1; + for( const daily_calories &day : calorie_diary ) { + ret += string_format( "%2d %6d %6d %6d\n", num_day++, day.gained, day.spent, day.total() ); + } + return ret; +} + +std::unique_ptr get_talker_for( avatar &me ) +{ + return std::make_unique( &me ); +} +std::unique_ptr get_talker_for( avatar *me ) +{ + return std::make_unique( me ); +} + points_left::points_left() { limit = MULTI_POOL; diff --git a/src/avatar.h b/src/avatar.h index 1f43441b5eac9..76a25872284a0 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -29,6 +29,7 @@ class JsonOut; class mission; class monster; class npc; +class talker; namespace debug_menu { @@ -139,6 +140,10 @@ class avatar : public player */ void on_mission_finished( mission &cur_mission ); + // Dialogue and bartering--see npctalk.cpp + void talk_to( std::unique_ptr talk_with, bool text_only = false, + bool radio_contact = false ); + /** * Helper function for player::read. * @@ -224,6 +229,35 @@ class avatar : public player return mon_visible; } + struct daily_calories { + int spent; + int gained; + int total() const { + return gained - spent; + } + + void serialize( JsonOut &json ) const { + json.start_object(); + + json.member( "spent", spent ); + json.member( "gained", gained ); + + json.end_object(); + }; + void deserialize( JsonIn &jsin ) { + JsonObject data = jsin.get_object(); + + data.read( "spent", spent ); + data.read( "gained", gained ); + }; + }; + // called once a day; adds a new daily_calories to the + // front of the list and pops off the back if there are more than 30 + void advance_daily_calories(); + void add_spent_calories( int cal ) override; + void add_gained_calories( int cal ) override; + std::string total_daily_calories_string() const; + private: map_memory player_map_memory; bool show_map_memory; @@ -249,6 +283,11 @@ class avatar : public player * The currently active mission, or null if no mission is currently in progress. */ mission *active_mission; + /** + * The amont of calories spent and gained per day for the last 30 days. + * the back is popped off and a new one added to the front at midnight each day + */ + std::list calorie_diary; // Items the player has identified. std::unordered_set items_identified; @@ -266,6 +305,8 @@ class avatar : public player }; avatar &get_avatar(); +std::unique_ptr get_talker_for( avatar &me ); +std::unique_ptr get_talker_for( avatar *me ); struct points_left { int stat_points; diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 20ee21ace8e63..9b45f0cc58393 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -118,6 +118,14 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) // Well that sure was easy return true; } + bool via_ramp = false; + if( m.has_flag( TFLAG_RAMP_UP, dest_loc ) ) { + dest_loc.z += 1; + via_ramp = true; + } else if( m.has_flag( TFLAG_RAMP_DOWN, dest_loc ) ) { + dest_loc.z -= 1; + via_ramp = true; + } if( m.has_flag( TFLAG_MINEABLE, dest_loc ) && g->mostseen == 0 && get_option( "AUTO_FEATURES" ) && get_option( "AUTO_MINING" ) && @@ -212,11 +220,6 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) } } - if( d.z == 0 && ramp_move( you, m, dest_loc ) ) { - // TODO: Make it work nice with automove (if it doesn't do so already?) - return false; - } - if( you.has_effect( effect_amigara ) ) { int curdist = INT_MAX; int newdist = INT_MAX; @@ -377,7 +380,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) add_msg( m_info, _( "%s to dive underwater." ), press_x( ACTION_MOVE_DOWN ) ); } - avatar_action::swim( get_map(), g->u, dest_loc ); + avatar_action::swim( get_map(), get_avatar(), dest_loc ); } g->on_move_effects(); @@ -397,7 +400,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) } return true; } - if( g->walk_move( dest_loc ) ) { + if( g->walk_move( dest_loc, via_ramp ) ) { return true; } if( g->phasing_move( dest_loc ) ) { @@ -689,7 +692,7 @@ static bool gunmode_checks_weapon( avatar &you, const map &m, std::vectoru.mounted_creature.get(); + monster *mons = get_player_character().mounted_creature.get(); if( !mons->type->mech_weapon.is_empty() ) { is_mech_weapon = true; } @@ -838,7 +841,7 @@ void avatar_action::fire_wielded_weapon( avatar &you ) you.assign_activity( aim_activity_actor::use_wielded(), false ); } -void avatar_action::fire_ranged_mutation( avatar &you, const item &fake_gun ) +void avatar_action::fire_ranged_mutation( Character &you, const item &fake_gun ) { you.assign_activity( aim_activity_actor::use_mutation( fake_gun ), false ); } @@ -933,23 +936,29 @@ bool avatar_action::eat_here( avatar &you ) void avatar_action::eat( avatar &you ) { item_location loc = game_menus::inv::consume( you ); - avatar_action::eat( you, loc, you.activity.values ); + std::string filter; + if( !you.activity.str_values.empty() ) { + filter = you.activity.str_values.back(); + } + avatar_action::eat( you, loc, you.activity.values, filter ); } void avatar_action::eat( avatar &you, const item_location &loc ) { - avatar_action::eat( you, loc, std::vector() ); + avatar_action::eat( you, loc, std::vector(), std::string() ); } void avatar_action::eat( avatar &you, const item_location &loc, - std::vector consume_menu_selections ) + std::vector consume_menu_selections, + const std::string &consume_menu_filter ) { if( !loc ) { you.cancel_activity(); add_msg( _( "Never mind." ) ); return; } - you.assign_activity( player_activity( consume_activity_actor( loc, consume_menu_selections ) ) ); + you.assign_activity( player_activity( consume_activity_actor( loc, consume_menu_selections, + consume_menu_filter ) ) ); } void avatar_action::plthrow( avatar &you, item_location loc, @@ -960,7 +969,7 @@ void avatar_action::plthrow( avatar &you, item_location loc, return; } if( you.is_mounted() ) { - monster *mons = g->u.mounted_creature.get(); + monster *mons = get_player_character().mounted_creature.get(); if( mons->has_flag( MF_RIDEABLE_MECH ) ) { if( !mons->check_mech_powered() ) { add_msg( m_bad, _( "Your %s refuses to move as its batteries have been drained." ), @@ -1049,7 +1058,7 @@ void avatar_action::plthrow( avatar &you, item_location loc, you.weapon.mod_charges( -1 ); thrown.charges = 1; } else { - you.i_rem( -1 ); + you.remove_weapon(); } you.throw_item( trajectory.back(), thrown, blind_throw_from_pos ); g->reenter_fullscreen(); diff --git a/src/avatar_action.h b/src/avatar_action.h index fbed8231365f9..9c88f775cbef8 100644 --- a/src/avatar_action.h +++ b/src/avatar_action.h @@ -6,12 +6,13 @@ #include "point.h" #include "units.h" +class aim_activity_actor; class avatar; +class Character; class item; class item_location; class map; class turret_data; -class aim_activity_actor; namespace avatar_action { @@ -19,7 +20,8 @@ namespace avatar_action /** Eat food or fuel 'E' (or 'a') */ void eat( avatar &you ); void eat( avatar &you, const item_location &loc ); -void eat( avatar &you, const item_location &loc, std::vector consume_menu_selections ); +void eat( avatar &you, const item_location &loc, std::vector consume_menu_selections, + const std::string &consume_menu_filter ); // special rules for eating: grazing etc // returns false if no rules are needed bool eat_here( avatar &you ); @@ -53,7 +55,7 @@ bool can_fire_weapon( avatar &you, const map &m, const item &weapon ); void fire_wielded_weapon( avatar &you ); /** Stores fake gun specified by the mutation and starts interactive aiming */ -void fire_ranged_mutation( avatar &you, const item &fake_gun ); +void fire_ranged_mutation( Character &you, const item &fake_gun ); /** Stores fake gun specified by the bionic and starts interactive aiming */ void fire_ranged_bionic( avatar &you, const item &fake_gun, const units::energy &cost_per_shot ); diff --git a/src/ballistics.cpp b/src/ballistics.cpp index 5a8e7793a6216..f03aa4e8fc7f1 100644 --- a/src/ballistics.cpp +++ b/src/ballistics.cpp @@ -8,8 +8,8 @@ #include #include -#include "avatar.h" #include "calendar.h" +#include "character.h" #include "creature.h" #include "damage.h" #include "debug.h" @@ -49,10 +49,11 @@ static void drop_or_embed_projectile( const dealt_projectile_attack &attack ) } const tripoint &pt = attack.end_point; + Character &player_character = get_player_character(); if( effects.count( "SHATTER_SELF" ) ) { // Drop the contents, not the thrown item - if( g->u.sees( pt ) ) { + if( player_character.sees( pt ) ) { add_msg( _( "The %s shatters!" ), drop_item.tname() ); } @@ -70,7 +71,7 @@ static void drop_or_embed_projectile( const dealt_projectile_attack &attack ) if( effects.count( "BURST" ) ) { // Drop the contents, not the thrown item - if( g->u.sees( pt ) ) { + if( player_character.sees( pt ) ) { add_msg( _( "The %s bursts!" ), drop_item.tname() ); } @@ -107,7 +108,7 @@ static void drop_or_embed_projectile( const dealt_projectile_attack &attack ) if( embed ) { mon->add_item( dropped_item ); - if( g->u.sees( *mon ) ) { + if( player_character.sees( *mon ) ) { add_msg( _( "The %1$s embeds in %2$s!" ), dropped_item.tname(), mon->disp_name() ); } } else { @@ -138,7 +139,7 @@ static void drop_or_embed_projectile( const dealt_projectile_attack &attack ) } const trap &tr = here.tr_at( pt ); if( tr.triggered_by_item( dropped_item ) ) { - tr.trigger( pt, nullptr, &dropped_item ); + tr.trigger( pt, dropped_item ); } } } diff --git a/src/basecamp.cpp b/src/basecamp.cpp index 02031287c8751..5b73156bf110e 100644 --- a/src/basecamp.cpp +++ b/src/basecamp.cpp @@ -223,7 +223,7 @@ std::string basecamp::om_upgrade_description( const std::string &bldg, bool trun comp = string_format( _( "Notes:\n%s\n\nSkills used: %s\n%s\n" ), making.description, making.required_all_skills_string(), comp ); if( !trunc ) { - time_duration base_time = making.batch_duration(); + time_duration base_time = making.batch_duration( get_player_character() ); comp += string_format( _( "Risk: None\nTime: %s\n" ), to_string( base_camps::to_workdays( base_time ) ) ); } @@ -711,8 +711,10 @@ basecamp_action_components::basecamp_action_components( bool basecamp_action_components::choose_components() { const auto filter = is_crafting_component; + avatar &player_character = get_avatar(); const requirement_data *req = - making_.deduped_requirements().select_alternative( g->u, base_._inv, filter, batch_size_ ); + making_.deduped_requirements().select_alternative( player_character, base_._inv, filter, + batch_size_ ); if( !req ) { return false; } @@ -722,8 +724,8 @@ bool basecamp_action_components::choose_components() } for( const auto &it : req->get_components() ) { comp_selection is = - g->u.select_item_component( it, batch_size_, base_._inv, true, filter, - !base_.by_radio ); + player_character.select_item_component( it, batch_size_, base_._inv, true, filter, + !base_.by_radio ); if( is.use_from == usage_from::cancel ) { return false; } @@ -732,8 +734,8 @@ bool basecamp_action_components::choose_components() // this may consume pseudo-resources from fake items for( const auto &it : req->get_tools() ) { comp_selection ts = - g->u.select_tool_component( it, batch_size_, base_._inv, DEFAULT_HOTKEYS, true, - !base_.by_radio ); + player_character.select_tool_component( it, batch_size_, base_._inv, DEFAULT_HOTKEYS, true, + !base_.by_radio ); if( ts.use_from == usage_from::cancel ) { return false; } @@ -751,13 +753,15 @@ void basecamp_action_components::consume_components() target_map = map_.get(); } const tripoint &origin = target_map->getlocal( base_.get_dumping_spot() ); + avatar &player_character = get_avatar(); for( const comp_selection &sel : item_selections_ ) { - g->u.consume_items( *target_map, sel, batch_size_, is_crafting_component, origin, - basecamp::inv_range ); + player_character.consume_items( *target_map, sel, batch_size_, is_crafting_component, origin, + basecamp::inv_range ); } // this may consume pseudo-resources from fake items for( const comp_selection &sel : tool_selections_ ) { - g->u.consume_tools( *target_map, sel, batch_size_, origin, basecamp::inv_range, &base_ ); + player_character.consume_tools( *target_map, sel, batch_size_, origin, basecamp::inv_range, + &base_ ); } // go back and consume the actual resources for( basecamp_resource &bcp_r : base_.resources ) { diff --git a/src/behavior.cpp b/src/behavior.cpp index 92e18fcf4c7a8..ef301ed09572b 100644 --- a/src/behavior.cpp +++ b/src/behavior.cpp @@ -36,7 +36,7 @@ behavior_return node_t::tick( const oracle_t *subject ) const { if( children.empty() ) { status_t result = status_t::running; - for( std::pair< predicate_type, std::string > predicate_pair : conditions ) { + for( const std::pair< predicate_type, std::string > &predicate_pair : conditions ) { result = predicate_pair.first( subject, predicate_pair.second ); if( result != status_t::running ) { break; @@ -46,7 +46,7 @@ behavior_return node_t::tick( const oracle_t *subject ) const } else { assert( strategy != nullptr ); status_t result = status_t::running; - for( std::pair< predicate_type, std::string > predicate_pair : conditions ) { + for( const std::pair< predicate_type, std::string > &predicate_pair : conditions ) { result = predicate_pair.first( subject, predicate_pair.second ); if( result != status_t::running ) { break; diff --git a/src/bionics.cpp b/src/bionics.cpp index 1f8bdd8a35aea..3737a80ea7810 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -64,6 +64,7 @@ #include "point.h" #include "projectile.h" #include "requirements.h" +#include "ret_val.h" #include "rng.h" #include "sounds.h" #include "string_formatter.h" @@ -506,7 +507,7 @@ void npc::check_or_use_weapon_cbm( const bionic_id &cbm_id ) if( is_armed() ) { stow_item( weapon ); } - if( g->u.sees( pos() ) ) { + if( get_player_character().sees( pos() ) ) { add_msg( m_info, _( "%s activates their %s." ), disp_name(), bio.info().name ); } @@ -601,6 +602,15 @@ bool Character::activate_bionic( int b, bool eff_only, bool *close_bionics_ui ) avatar_action::fire_ranged_bionic( g->u, item( bio.info().fake_item ), bio.info().power_activate ); } else if( bio.info().has_flag( flag_BIO_WEAPON ) ) { if( weapon.has_flag( flag_NO_UNWIELD ) ) { + cata::optional active_bio_weapon_index = active_bionic_weapon_index(); + if( active_bio_weapon_index && deactivate_bionic( *active_bio_weapon_index, eff_only ) ) { + // restore state and try again + refund_power(); + bio.powered = false; + // note: deep recursion is not possible, as `deactivate_bionic` won't return true second time + return activate_bionic( b, eff_only, close_bionics_ui ); + } + add_msg_if_player( m_info, _( "Deactivate your %s first!" ), weapon.tname() ); refund_power(); bio.powered = false; @@ -644,7 +654,7 @@ bool Character::activate_bionic( int b, bool eff_only, bool *close_bionics_ui ) } else if( bio.id == bio_evap ) { add_msg_activate(); const w_point weatherPoint = *g->weather.weather_precise; - int humidity = get_local_humidity( weatherPoint.humidity, g->weather.weather, + int humidity = get_local_humidity( weatherPoint.humidity, get_weather().weather_id, g->is_sheltered( g->u.pos() ) ); // thirst units = 5 mL int water_available = std::lround( humidity * 3.0 / 100.0 ); @@ -1011,7 +1021,7 @@ bool Character::activate_bionic( int b, bool eff_only, bool *close_bionics_ui ) const w_point weatherPoint = *g->weather.weather_precise; add_msg_if_player( m_info, _( "Relative Humidity: %s." ), print_humidity( - get_local_humidity( weatherPoint.humidity, g->weather.weather, + get_local_humidity( weatherPoint.humidity, get_weather().weather_id, g->is_sheltered( g->u.pos() ) ) ) ); add_msg_if_player( m_info, _( "Pressure: %s." ), print_pressure( static_cast( weatherPoint.pressure ) ) ); @@ -1117,7 +1127,7 @@ bool Character::activate_bionic( int b, bool eff_only, bool *close_bionics_ui ) } // Recalculate stats (strength, mods from pain etc.) that could have been affected - reset_encumbrance(); + calc_encumbrance(); reset(); // Also reset crafting inventory cache if this bionic spawned a fake item @@ -1128,39 +1138,71 @@ bool Character::activate_bionic( int b, bool eff_only, bool *close_bionics_ui ) return true; } -bool Character::deactivate_bionic( int b, bool eff_only ) +cata::optional Character::active_bionic_weapon_index() const { - bionic &bio = ( *my_bionics )[b]; + if( weapon.is_null() ) { + return cata::nullopt; + } - if( bio.incapacitated_time > 0_turns ) { - add_msg( m_info, _( "Your %s is shorting out and can't be deactivated." ), - bio.info().name ); - return false; + for( int i = 0; i < static_cast( my_bionics->size() ); i++ ) { + const bionic &bio = ( *my_bionics )[ i ]; + if( bio.powered && bio.info().has_flag( flag_BIO_WEAPON ) && + weapon.typeId() == bio.info().fake_item ) { + return i; + } } - if( bio.info().is_remote_fueled ) { - reset_remote_fuel(); + return cata::nullopt; +} + +ret_val Character::can_deactivate_bionic( int b, bool eff_only ) const +{ + bionic &bio = ( *my_bionics )[b]; + + if( bio.incapacitated_time > 0_turns ) { + return ret_val::make_failure( _( "Your %s is shorting out and can't be deactivated." ), + bio.info().name ); } - // Just do the effect, no stat changing or messages if( !eff_only ) { if( !bio.powered ) { // It's already off! - return false; + return ret_val::make_failure(); } if( !bio.info().has_flag( flag_BIO_TOGGLED ) ) { // It's a fire-and-forget bionic, we can't turn it off but have to wait for //it to run out of charge - add_msg_if_player( m_info, _( "You can't deactivate your %s manually!" ), - bio.info().name ); - return false; + return ret_val::make_failure( _( "You can't deactivate your %s manually!" ), + bio.info().name ); } if( get_power_level() < bio.info().power_deactivate ) { - add_msg( m_info, _( "You don't have the power to deactivate your %s." ), - bio.info().name ); - return false; + return ret_val::make_failure( _( "You don't have the power to deactivate your %s." ), + bio.info().name ); + } + } + + return ret_val::make_success(); +} + +bool Character::deactivate_bionic( int b, bool eff_only ) +{ + const auto can_deactivate = can_deactivate_bionic( b, eff_only ); + + if( !can_deactivate.success() ) { + if( !can_deactivate.str().empty() ) { + add_msg( m_info, can_deactivate.str() ); } + return false; + } + + bionic &bio = ( *my_bionics )[b]; + if( bio.info().is_remote_fueled ) { + reset_remote_fuel(); + } + + // Just do the effect, no stat changing or messages + if( !eff_only ) { //We can actually deactivate now, do deactivation-y things mod_power_level( -bio.info().power_deactivate ); bio.powered = false; @@ -1195,7 +1237,7 @@ bool Character::deactivate_bionic( int b, bool eff_only ) } // Recalculate stats (strength, mods from pain etc.) that could have been affected - reset_encumbrance(); + calc_encumbrance(); reset(); if( !bio.id->enchantments.empty() ) { recalculate_enchantment_cache(); @@ -1274,8 +1316,11 @@ bool Character::burn_fuel( int b, bool start ) } if( !bio.has_flag( flag_SAFE_FUEL_OFF ) && - get_power_level() + units::from_kilojoule( fuel_energy ) * effective_efficiency - > get_max_power_level() ) { + ( ( get_power_level() + units::from_kilojoule( fuel_energy ) * effective_efficiency > + get_max_power_level() ) || + ( ( ( get_power_level() + units::from_kilojoule( fuel_energy ) * effective_efficiency ) > + ( get_max_power_level() * bio.get_safe_fuel_thresh() ) ) + ) ) ) { if( is_metabolism_powered ) { add_msg_player_or_npc( m_info, _( "Your %s turns off to not waste calories." ), _( "'s %s turns off to not waste calories." ), @@ -1303,7 +1348,7 @@ bool Character::burn_fuel( int b, bool start ) mod_power_level( power_gain ); } else if( is_perpetual_fuel ) { if( fuel == fuel_type_sun_light && g->is_in_sunlight( pos() ) ) { - const weather_type &wtype = current_weather( pos() ); + const weather_type_id &wtype = current_weather( pos() ); const float tick_sunlight = incident_sunlight( wtype, calendar::turn ); const double intensity = tick_sunlight / default_daylight_level(); mod_power_level( units::from_kilojoule( fuel_energy ) * intensity * effective_efficiency ); @@ -1540,7 +1585,7 @@ float Character::get_effective_efficiency( int b, float fuel_efficiency ) if( i.covers( elem.first ) && !i.has_flag( flag_ALLOWS_NATURAL_ATTACKS ) && !i.has_flag( flag_SEMITANGIBLE ) && !i.has_flag( flag_PERSONAL ) && !i.has_flag( flag_AURA ) ) { - coverage += i.get_coverage(); + coverage += i.get_coverage( elem.first.id() ); } } } @@ -1680,29 +1725,25 @@ void Character::process_bionic( int b ) const int hp_cur = part.second.get_hp_cur(); if( hp_cur > 0 && hp_cur < part.second.get_hp_max() ) { damaged_hp_parts.push_back( part.first.id() ); - // only healed and non-hp parts will have a chance of bleeding removal - bleeding_bp_parts.remove( part.first.id() ); + } + } + for( const bodypart_id &i : bleeding_bp_parts ) { + // effectively reduces by 1 intensity level + if( get_stored_kcal() >= 15 ) { + get_effect( effect_bleed, i->token ).mod_duration( -get_effect( effect_bleed, + i->token ).get_int_dur_factor() ); + mod_stored_kcal( -15 ); + } else { + bleeding_bp_parts.clear(); + break; } } if( calendar::once_every( 60_turns ) ) { - bool try_to_heal_bleeding = true; if( get_stored_kcal() >= 5 && !damaged_hp_parts.empty() ) { const bodypart_id part_to_heal = damaged_hp_parts[ rng( 0, damaged_hp_parts.size() - 1 ) ]; heal( part_to_heal, 1 ); mod_stored_kcal( -5 ); - int hp_percent = static_cast( get_part_hp_cur( part_to_heal ) ) / get_part_hp_max( - part_to_heal ) * 100; - if( has_effect( effect_bleed, part_to_heal->token ) && rng( 0, 100 ) < hp_percent ) { - remove_effect( effect_bleed, part_to_heal->token ); - try_to_heal_bleeding = false; - } } - - // if no bleed was removed, try to remove it on some other part - if( try_to_heal_bleeding && !bleeding_bp_parts.empty() && rng( 0, 1 ) == 1 ) { - remove_effect( effect_bleed, bleeding_bp_parts.front()->token ); - } - } if( !damaged_hp_parts.empty() || !bleeding_bp_parts.empty() ) { mod_power_level( -40_J ); @@ -1734,8 +1775,8 @@ void Character::process_bionic( int b ) // Aero-Evaporator provides water at 60 watts with 2 L / kWh efficiency // which is 10 mL per 5 minutes. Humidity can modify the amount gained. if( calendar::once_every( 5_minutes ) ) { - const w_point weatherPoint = *g->weather.weather_precise; - int humidity = get_local_humidity( weatherPoint.humidity, g->weather.weather, + const w_point weatherPoint = *get_weather().weather_precise; + int humidity = get_local_humidity( weatherPoint.humidity, get_weather().weather_id, g->is_sheltered( g->u.pos() ) ); // in thirst units = 5 mL water int water_available = std::lround( humidity * 3.0 / 100.0 ); @@ -2701,7 +2742,7 @@ void Character::add_bionic( const bionic_id &b ) } } - reset_encumbrance(); + calc_encumbrance(); recalc_sight_limits(); if( !b->enchantments.empty() ) { recalculate_enchantment_cache(); @@ -2738,7 +2779,7 @@ void Character::remove_bionic( const bionic_id &b ) } *my_bionics = new_my_bionics; - reset_encumbrance(); + calc_encumbrance(); recalc_sight_limits(); if( !b->enchantments.empty() ) { recalculate_enchantment_cache(); @@ -2836,8 +2877,42 @@ void bionic::toggle_safe_fuel_mod() } if( !has_flag( flag_SAFE_FUEL_OFF ) ) { set_flag( flag_SAFE_FUEL_OFF ); + set_safe_fuel_thresh( 2.0 ); } else { - remove_flag( flag_SAFE_FUEL_OFF ); + uilist tmenu; + tmenu.text = _( "Chose Safe Fuel Level Threshold" ); + tmenu.addentry( 1, true, 'o', _( "Full Power" ) ); + if( get_auto_start_thresh() < 0.80 ) { + tmenu.addentry( 2, true, 't', _( "Above 80 %%" ) ); + } + if( get_auto_start_thresh() < 0.55 ) { + tmenu.addentry( 3, true, 'f', _( "Above 55 %%" ) ); + } + if( get_auto_start_thresh() < 0.30 ) { + tmenu.addentry( 4, true, 's', _( "Above 30 %%" ) ); + } + tmenu.query(); + + switch( tmenu.ret ) { + case 1: + remove_flag( flag_SAFE_FUEL_OFF ); + set_safe_fuel_thresh( 1.0 ); + break; + case 2: + remove_flag( flag_SAFE_FUEL_OFF ); + set_safe_fuel_thresh( 0.80 ); + break; + case 3: + remove_flag( flag_SAFE_FUEL_OFF ); + set_safe_fuel_thresh( 0.55 ); + break; + case 4: + remove_flag( flag_SAFE_FUEL_OFF ); + set_safe_fuel_thresh( 0.30 ); + break; + default: + break; + } } } @@ -2850,9 +2925,15 @@ void bionic::toggle_auto_start_mod() uilist tmenu; tmenu.text = _( "Chose Start Power Level Threshold" ); tmenu.addentry( 1, true, 'o', _( "No Power Left" ) ); - tmenu.addentry( 2, true, 't', _( "Below 25 %%" ) ); - tmenu.addentry( 3, true, 'f', _( "Below 50 %%" ) ); - tmenu.addentry( 4, true, 's', _( "Below 75 %%" ) ); + if( get_safe_fuel_thresh() > 0.25 ) { + tmenu.addentry( 2, true, 't', _( "Below 25 %%" ) ); + } + if( get_safe_fuel_thresh() > 0.50 ) { + tmenu.addentry( 3, true, 'f', _( "Below 50 %%" ) ); + } + if( get_safe_fuel_thresh() > 0.75 ) { + tmenu.addentry( 4, true, 's', _( "Below 75 %%" ) ); + } tmenu.query(); switch( tmenu.ret ) { @@ -2891,6 +2972,21 @@ bool bionic::is_auto_start_on() const return get_auto_start_thresh() > -1.0; } +float bionic::get_safe_fuel_thresh() const +{ + return safe_fuel_threshold; +} + +bool bionic::is_safe_fuel_on() const +{ + return get_safe_fuel_thresh() < 2.0; +} + +void bionic::set_safe_fuel_thresh( float val ) +{ + safe_fuel_threshold = val; +} + void bionic::serialize( JsonOut &json ) const { json.start_object(); @@ -2907,6 +3003,9 @@ void bionic::serialize( JsonOut &json ) const if( is_auto_start_on() ) { json.member( "auto_start_threshold", auto_start_threshold ); } + if( is_safe_fuel_on() ) { + json.member( "safe_fuel_threshold", safe_fuel_threshold ); + } json.end_object(); } @@ -2930,6 +3029,9 @@ void bionic::deserialize( JsonIn &jsin ) if( jo.has_float( "auto_start_threshold" ) ) { auto_start_threshold = jo.get_float( "auto_start_threshold" ); } + if( jo.has_float( "safe_fuel_threshold" ) ) { + safe_fuel_threshold = jo.get_float( "safe_fuel_threshold" ); + } if( jo.has_array( "bionic_tags" ) ) { for( const std::string line : jo.get_array( "bionic_tags" ) ) { bionic_tags.insert( line ); diff --git a/src/bionics.h b/src/bionics.h index cbbc564606469..b8dd19c7d3a80 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -181,6 +181,9 @@ struct bionic { float get_auto_start_thresh() const; bool is_auto_start_on() const; + void set_safe_fuel_thresh( float val ); + float get_safe_fuel_thresh() const; + bool is_safe_fuel_on() const; bool activate_spell( Character &caster ); void serialize( JsonOut &json ) const; @@ -189,6 +192,7 @@ struct bionic { // generic bionic specific flags cata::flat_set bionic_tags; float auto_start_threshold = -1.0; + float safe_fuel_threshold = -1.0; }; // A simpler wrapper to allow forward declarations of it. std::vector can not diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 25f2f09cb55ec..5bac6b8558d13 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -194,7 +194,10 @@ static std::string build_bionic_poweronly_string( const bionic &bio ) } if( !bio.has_flag( flag_SAFE_FUEL_OFF ) && ( !bio.info().fuel_opts.empty() || bio.info().is_remote_fueled ) ) { - properties.push_back( _( "(fuel saving ON)" ) ); + //properties.push_back( _( "(fuel saving ON)" ) ); + const std::string label = string_format( _( "(fuel saving ON > %d %%)" ), + static_cast( bio.get_safe_fuel_thresh() * 100 ) ); + properties.push_back( label ); } if( bio.is_auto_start_on() && ( !bio.info().fuel_opts.empty() || bio.info().is_remote_fueled ) ) { const std::string label = string_format( _( "(auto start < %d %%)" ), @@ -275,7 +278,7 @@ static void draw_connectors( const catacurses::window &win, const point &start, for( const std::pair, size_t> &elem : bio_id->occupied_bodyparts ) { auto pos = bp_to_pos.find( elem.first ); if( pos != bp_to_pos.end() ) { - pos_and_num.emplace_back( pos->second + LIST_START_Y, elem.second ); + pos_and_num.emplace_back( static_cast( pos->second ) + LIST_START_Y, elem.second ); } } if( pos_and_num.empty() || !get_option < bool >( "CBM_SLOTS_ENABLED" ) ) { diff --git a/src/bodypart.cpp b/src/bodypart.cpp index cda9a32201a7b..a14ea79334a33 100644 --- a/src/bodypart.cpp +++ b/src/bodypart.cpp @@ -52,25 +52,6 @@ std::string enum_to_string( side data ) abort(); } -template<> -std::string enum_to_string( hp_part data ) -{ - switch( data ) { - // *INDENT-OFF* - case hp_part::hp_head: return "head"; - case hp_part::hp_torso: return "torso"; - case hp_part::hp_arm_l: return "arm_l"; - case hp_part::hp_arm_r: return "arm_r"; - case hp_part::hp_leg_l: return "leg_l"; - case hp_part::hp_leg_r: return "leg_r"; - // *INDENT-ON* - case hp_part::num_hp_parts: - break; - } - debugmsg( "Invalid hp_part" ); - abort(); -} - } // namespace io namespace @@ -80,6 +61,28 @@ generic_factory body_part_factory( "body part" ); } // namespace +bool is_legacy_bodypart_id( const std::string &id ) +{ + static const std::vector legacy_body_parts = { + "TORSO", + "HEAD", + "EYES", + "MOUTH", + "ARM_L", + "ARM_R", + "HAND_L", + "HAND_R", + "LEG_L", + "LEG_R", + "FOOT_L", + "FOOT_R", + "NUM_BP", + }; + + return std::find( legacy_body_parts.begin(), legacy_body_parts.end(), + id ) != legacy_body_parts.end(); +} + static body_part legacy_id_to_enum( const std::string &legacy_id ) { static const std::unordered_map body_parts = { @@ -220,6 +223,8 @@ void body_part_type::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "base_hp", base_hp ); optional( jo, was_loaded, "stat_hp_mods", hp_mods ); + optional( jo, was_loaded, "is_limb", is_limb, false ); + mandatory( jo, was_loaded, "legacy_id", legacy_id ); token = legacy_id_to_enum( legacy_id ); @@ -425,6 +430,11 @@ int bodypart::get_damage_disinfected() const return damage_disinfected; } +encumbrance_data bodypart::get_encumbrance_data() const +{ + return encumb_data; +} + void bodypart::set_hp_cur( int set ) { hp_cur = set; @@ -450,6 +460,11 @@ void bodypart::set_damage_disinfected( int set ) damage_disinfected = set; } +void bodypart::set_encumbrance_data( encumbrance_data set ) +{ + encumb_data = set; +} + void bodypart::mod_hp_cur( int mod ) { hp_cur += mod; diff --git a/src/bodypart.h b/src/bodypart.h index 500d733bc8e5d..d0dff3c1f6f35 100644 --- a/src/bodypart.h +++ b/src/bodypart.h @@ -8,6 +8,7 @@ #include #include +#include "enums.h" #include "flat_set.h" #include "int_id.h" #include "string_id.h" @@ -129,6 +130,8 @@ struct body_part_type { int base_hp = 60; stat_hp_mods hp_mods; + bool is_limb = false; + void load( const JsonObject &jo, const std::string &src ); void finalize(); void check() const; @@ -149,6 +152,46 @@ struct body_part_type { int bionic_slots_ = 0; }; +struct layer_details { + + std::vector pieces; + int max = 0; + int total = 0; + + void reset(); + int layer( int encumbrance ); + + bool operator ==( const layer_details &rhs ) const { + return max == rhs.max && + total == rhs.total && + pieces == rhs.pieces; + } +}; + +struct encumbrance_data { + int encumbrance = 0; + int armor_encumbrance = 0; + int layer_penalty = 0; + + std::array( layer_level::NUM_LAYER_LEVELS )> + layer_penalty_details; + + void layer( const layer_level level, const int encumbrance ) { + layer_penalty += layer_penalty_details[static_cast( level )].layer( encumbrance ); + } + + void reset() { + *this = encumbrance_data(); + } + + bool operator ==( const encumbrance_data &rhs ) const { + return encumbrance == rhs.encumbrance && + armor_encumbrance == rhs.armor_encumbrance && + layer_penalty == rhs.layer_penalty && + layer_penalty_details == rhs.layer_penalty_details; + } +}; + class bodypart { private: @@ -158,10 +201,11 @@ class bodypart int hp_max; int healed_total = 0; - /** Not used yet*/ int damage_bandaged = 0; int damage_disinfected = 0; + encumbrance_data encumb_data; + public: bodypart(): id( bodypart_str_id( "num_bp" ) ), hp_cur( 0 ), hp_max( 0 ) {} bodypart( bodypart_str_id id ): id( id ), hp_cur( id->base_hp ), hp_max( id->base_hp ) {} @@ -177,12 +221,16 @@ class bodypart int get_damage_bandaged() const; int get_damage_disinfected() const; + encumbrance_data get_encumbrance_data() const; + void set_hp_cur( int set ); void set_hp_max( int set ); void set_healed_total( int set ); void set_damage_bandaged( int set ); void set_damage_disinfected( int set ); + void set_encumbrance_data( encumbrance_data set ); + void mod_hp_cur( int mod ); void mod_hp_max( int mod ); void mod_healed_total( int mod ); @@ -235,6 +283,14 @@ class body_part_set return parts.size(); } + cata::flat_set::iterator begin() const { + return parts.begin(); + } + + cata::flat_set::iterator end() const { + return parts.end(); + } + template void serialize( Stream &s ) const { s.write( parts ); @@ -245,6 +301,9 @@ class body_part_set } }; +// Returns if passed string is legacy bodypart (i.e "TORSO", not "torso") +bool is_legacy_bodypart_id( const std::string &id ); + /** Returns the new id for old token */ const bodypart_str_id &convert_bp( body_part bp ); diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index d058232b725ff..219f8781167d0 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -1029,11 +1029,12 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int const int min_row = 0; const int max_row = s.y; + avatar &player_character = get_avatar(); //limit the render area to maximum view range (121x121 square centered on player) - const int min_visible_x = g->u.posx() % SEEX; - const int min_visible_y = g->u.posy() % SEEY; - const int max_visible_x = ( g->u.posx() % SEEX ) + ( MAPSIZE - 1 ) * SEEX; - const int max_visible_y = ( g->u.posy() % SEEY ) + ( MAPSIZE - 1 ) * SEEY; + const int min_visible_x = player_character.posx() % SEEX; + const int min_visible_y = player_character.posy() % SEEY; + const int max_visible_x = ( player_character.posx() % SEEX ) + ( MAPSIZE - 1 ) * SEEX; + const int max_visible_y = ( player_character.posy() % SEEY ) + ( MAPSIZE - 1 ) * SEEY; const auto &ch = here.access_cache( center.z ); @@ -1044,7 +1045,7 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int } //retrieve night vision goggle status once per draw - auto vision_cache = g->u.get_vision_modes(); + auto vision_cache = player_character.get_vision_modes(); nv_goggles_activated = vision_cache[NV_GOGGLES]; // check that the creature for which we'll draw the visibility map is still alive at that point @@ -1239,7 +1240,8 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int const Creature *critter = g->critter_at( pos, true ); if( has_draw_override( pos ) || has_memory_at( pos ) || - ( critter && ( g->u.sees_with_infrared( *critter ) || g->u.sees_with_specials( *critter ) ) ) ) { + ( critter && ( player_character.sees_with_infrared( *critter ) || + player_character.sees_with_specials( *critter ) ) ) ) { invisible[0] = true; } else { @@ -1405,16 +1407,17 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int draw_highlight(); void_highlight(); } - } else if( g->u.view_offset != tripoint_zero && !g->u.in_vehicle ) { + } else if( player_character.view_offset != tripoint_zero && !player_character.in_vehicle ) { // check to see if player is located at ter draw_from_id_string( "cursor", C_NONE, empty_string, tripoint( g->ter_view_p.xy(), center.z ), 0, 0, lit_level::LIT, false ); } - if( g->u.controlling_vehicle ) { + if( player_character.controlling_vehicle ) { if( cata::optional indicator_offset = g->get_veh_dir_indicator_location( true ) ) { - draw_from_id_string( "cursor", C_NONE, empty_string, indicator_offset->xy() + tripoint( g->u.posx(), - g->u.posy(), center.z ), + draw_from_id_string( "cursor", C_NONE, empty_string, + indicator_offset->xy() + tripoint( player_character.posx(), + player_character.posy(), center.z ), 0, 0, lit_level::LIT, false ); } } @@ -1850,7 +1853,7 @@ bool cata_tiles::draw_from_id_string( std::string id, TILE_CATEGORY category, default: // player if( id.substr( 7 ) == "player_" ) { - seed = g->u.name[0]; + seed = get_player_character().name[0]; break; } // NPC @@ -2112,7 +2115,7 @@ bool cata_tiles::draw_terrain_below( const tripoint &p, const lit_level, int &, const auto low_override = draw_below_override.find( p ); const bool low_overridden = low_override != draw_below_override.end(); if( low_overridden ? !low_override->second : ( invisible[0] || - !here.need_draw_lower_floor( p ) ) ) { + here.dont_draw_lower_floor( p ) ) ) { return false; } @@ -2206,7 +2209,7 @@ bool cata_tiles::draw_terrain( const tripoint &p, const lit_level ll, int &heigh } const std::string &tname = t.id().str(); if( here.check_seen_cache( p ) ) { - g->u.memorize_tile( here.getabs( p ), tname, subtile, rotation ); + get_avatar().memorize_tile( here.getabs( p ), tname, subtile, rotation ); } // draw the actual terrain if there's no override if( !neighborhood_overridden ) { @@ -2247,8 +2250,9 @@ bool cata_tiles::draw_terrain( const tripoint &p, const lit_level ll, int &heigh bool cata_tiles::has_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); return !t.tile.empty(); } return false; @@ -2256,8 +2260,9 @@ bool cata_tiles::has_memory_at( const tripoint &p ) const bool cata_tiles::has_terrain_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 2 ) == "t_" ) { return true; } @@ -2267,8 +2272,9 @@ bool cata_tiles::has_terrain_memory_at( const tripoint &p ) const bool cata_tiles::has_furniture_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 2 ) == "f_" ) { return true; } @@ -2278,8 +2284,9 @@ bool cata_tiles::has_furniture_memory_at( const tripoint &p ) const bool cata_tiles::has_trap_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 3 ) == "tr_" ) { return true; } @@ -2289,8 +2296,9 @@ bool cata_tiles::has_trap_memory_at( const tripoint &p ) const bool cata_tiles::has_vpart_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 3 ) == "vp_" ) { return true; } @@ -2300,8 +2308,9 @@ bool cata_tiles::has_vpart_memory_at( const tripoint &p ) const memorized_terrain_tile cata_tiles::get_terrain_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 2 ) == "t_" ) { return t; } @@ -2311,8 +2320,9 @@ memorized_terrain_tile cata_tiles::get_terrain_memory_at( const tripoint &p ) co memorized_terrain_tile cata_tiles::get_furniture_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 2 ) == "f_" ) { return t; } @@ -2322,8 +2332,9 @@ memorized_terrain_tile cata_tiles::get_furniture_memory_at( const tripoint &p ) memorized_terrain_tile cata_tiles::get_trap_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 3 ) == "tr_" ) { return t; } @@ -2333,8 +2344,9 @@ memorized_terrain_tile cata_tiles::get_trap_memory_at( const tripoint &p ) const memorized_terrain_tile cata_tiles::get_vpart_memory_at( const tripoint &p ) const { - if( g->u.should_show_map_memory() ) { - const memorized_terrain_tile t = g->u.get_memorized_tile( get_map().getabs( p ) ); + avatar &player_character = get_avatar(); + if( player_character.should_show_map_memory() ) { + const memorized_terrain_tile t = player_character.get_memorized_tile( get_map().getabs( p ) ); if( t.tile.substr( 0, 3 ) == "vp_" ) { return t; } @@ -2345,6 +2357,7 @@ memorized_terrain_tile cata_tiles::get_vpart_memory_at( const tripoint &p ) cons bool cata_tiles::draw_furniture( const tripoint &p, const lit_level ll, int &height_3d, const bool ( &invisible )[5] ) { + avatar &player_character = get_avatar(); const auto override = furniture_override.find( p ); const bool overridden = override != furniture_override.end(); bool neighborhood_overridden = overridden; @@ -2371,7 +2384,7 @@ bool cata_tiles::draw_furniture( const tripoint &p, const lit_level ll, int &hei get_tile_values( f.to_i(), neighborhood, subtile, rotation ); const std::string &fname = f.id().str(); if( here.check_seen_cache( p ) ) { - g->u.memorize_tile( here.getabs( p ), fname, subtile, rotation ); + player_character.memorize_tile( here.getabs( p ), fname, subtile, rotation ); } // draw the actual furniture if there's no override if( !neighborhood_overridden ) { @@ -2431,10 +2444,11 @@ bool cata_tiles::draw_trap( const tripoint &p, const lit_level ll, int &height_3 } } + avatar &player_character = get_avatar(); map &here = get_map(); // first memorize the actual trap - const trap_id &tr = here.tr_at( p ).loadid; - if( tr && !invisible[0] && tr.obj().can_see( p, g->u ) ) { + const trap &tr = here.tr_at( p ); + if( !tr.is_null() && !invisible[0] && tr.can_see( p, player_character ) ) { const int neighborhood[4] = { static_cast( here.tr_at( p + point_south ).loadid ), static_cast( here.tr_at( p + point_east ).loadid ), @@ -2443,10 +2457,10 @@ bool cata_tiles::draw_trap( const tripoint &p, const lit_level ll, int &height_3 }; int subtile = 0; int rotation = 0; - get_tile_values( tr.to_i(), neighborhood, subtile, rotation ); - const std::string trname = tr.id().str(); + get_tile_values( tr.loadid.to_i(), neighborhood, subtile, rotation ); + const std::string trname = tr.loadid.id().str(); if( here.check_seen_cache( p ) ) { - g->u.memorize_tile( here.getabs( p ), trname, subtile, rotation ); + player_character.memorize_tile( here.getabs( p ), trname, subtile, rotation ); } // draw the actual trap if there's no override if( !neighborhood_overridden ) { @@ -2454,9 +2468,10 @@ bool cata_tiles::draw_trap( const tripoint &p, const lit_level ll, int &height_3 nv_goggles_activated, height_3d ); } } - if( overridden || ( !invisible[0] && neighborhood_overridden && tr.obj().can_see( p, g->u ) ) ) { + if( overridden || ( !invisible[0] && neighborhood_overridden && + tr.can_see( p, player_character ) ) ) { // and then draw the override trap - const trap_id &tr2 = overridden ? override->second : tr; + const trap_id &tr2 = overridden ? override->second : tr.loadid; if( tr2 ) { // both the current and neighboring overrides may change the appearance // of the tile, so always re-calculate it. @@ -2550,7 +2565,7 @@ bool cata_tiles::draw_field_or_item( const tripoint &p, const lit_level ll, int mon_id = std::get<1>( it_override->second ); hilite = std::get<2>( it_override->second ); it_type = item::find_type( it_id ); - } else if( !invisible[0] && here.sees_some_items( p, g->u ) ) { + } else if( !invisible[0] && here.sees_some_items( p, get_player_character() ) ) { const maptile &tile = here.maptile_at( p ); const item &itm = tile.get_uppermost_item(); const mtype *const mon = itm.get_mtype(); @@ -2584,7 +2599,7 @@ bool cata_tiles::draw_vpart_below( const tripoint &p, const lit_level /*ll*/, in const auto low_override = draw_below_override.find( p ); const bool low_overridden = low_override != draw_below_override.end(); if( low_overridden ? !low_override->second : ( invisible[0] || - !get_map().need_draw_lower_floor( p ) ) ) { + get_map().dont_draw_lower_floor( p ) ) ) { return false; } tripoint pbelow( p.xy(), p.z - 1 ); @@ -2612,9 +2627,10 @@ bool cata_tiles::draw_vpart( const tripoint &p, lit_level ll, int &height_3d, const int subtile = part_mod == 1 ? open_ : part_mod == 2 ? broken : 0; const int rotation = veh.face.dir(); const std::string vpname = "vp_" + vp_id.str(); - if( !veh.forward_velocity() && !veh.player_in_control( g->u ) && + avatar &player_character = get_avatar(); + if( !veh.forward_velocity() && !veh.player_in_control( player_character ) && here.check_seen_cache( p ) ) { - g->u.memorize_tile( here.getabs( p ), vpname, subtile, rotation ); + player_character.memorize_tile( here.getabs( p ), vpname, subtile, rotation ); } if( !overridden ) { const cata::optional cargopart = vp.part_with_feature( "CARGO", true ); @@ -2661,7 +2677,7 @@ bool cata_tiles::draw_critter_at_below( const tripoint &p, const lit_level, int const auto low_override = draw_below_override.find( p ); const bool low_overridden = low_override != draw_below_override.end(); if( low_overridden ? !low_override->second : ( invisible[0] || - !get_map().need_draw_lower_floor( p ) ) ) { + get_map().dont_draw_lower_floor( p ) ) ) { return false; } @@ -2674,11 +2690,13 @@ bool cata_tiles::draw_critter_at_below( const tripoint &p, const lit_level, int return false; } + Character &player_character = get_player_character(); // Check if the player can actually see the critter. We don't care if // it's via infrared or not, just whether or not they're seen. If not, // we can bail. - if( !g->u.sees( *critter ) && !( g->u.sees_with_infrared( *critter ) || - g->u.sees_with_specials( *critter ) ) ) { + if( !player_character.sees( *critter ) && + !( player_character.sees_with_infrared( *critter ) || + player_character.sees_with_specials( *critter ) ) ) { return false; } @@ -2715,6 +2733,7 @@ bool cata_tiles::draw_critter_at( const tripoint &p, lit_level ll, int &height_3 bool is_player; bool sees_player; Creature::Attitude attitude; + Character &player_character = get_player_character(); const auto override = monster_override.find( p ); if( override != monster_override.end() ) { const mtype_id id = std::get<0>( override->second ); @@ -2736,8 +2755,9 @@ bool cata_tiles::draw_critter_at( const tripoint &p, lit_level ll, int &height_3 } const Creature &critter = *pcritter; - if( !g->u.sees( critter ) ) { - if( g->u.sees_with_infrared( critter ) || g->u.sees_with_specials( critter ) ) { + if( !player_character.sees( critter ) ) { + if( player_character.sees_with_infrared( critter ) || + player_character.sees_with_specials( critter ) ) { return draw_from_id_string( "infrared_creature", C_NONE, empty_string, p, 0, 0, lit_level::LIT, false, height_3d ); } @@ -2780,7 +2800,7 @@ bool cata_tiles::draw_critter_at( const tripoint &p, lit_level ll, int &height_3 } result = draw_from_id_string( chosen_id, ent_category, ent_subcategory, p, subtile, rot_facing, ll, false, height_3d ); - sees_player = m->sees( g->u ); + sees_player = m->sees( player_character ); attitude = m->attitude_to( g-> u ); } } @@ -2798,7 +2818,8 @@ bool cata_tiles::draw_critter_at( const tripoint &p, lit_level ll, int &height_3 } else { // invisible const Creature *critter = g->critter_at( p, true ); - if( critter && ( g->u.sees_with_infrared( *critter ) || g->u.sees_with_specials( *critter ) ) ) { + if( critter && ( player_character.sees_with_infrared( *critter ) || + player_character.sees_with_specials( *critter ) ) ) { // try drawing infrared creature if invisible and not overridden // return directly without drawing overlay return draw_from_id_string( "infrared_creature", C_NONE, empty_string, p, 0, 0, @@ -2852,7 +2873,8 @@ bool cata_tiles::draw_zombie_revival_indicators( const tripoint &pos, const lit_ { map &here = get_map(); if( tileset_ptr->find_tile_type( ZOMBIE_REVIVAL_INDICATOR ) && !invisible[0] && - item_override.find( pos ) == item_override.end() && here.could_see_items( pos, g->u ) ) { + item_override.find( pos ) == item_override.end() && + here.could_see_items( pos, get_player_character() ) ) { for( item &i : here.i_at( pos ) ) { if( i.can_revive() ) { return draw_from_id_string( ZOMBIE_REVIVAL_INDICATOR, C_NONE, empty_string, pos, 0, 0, @@ -3265,7 +3287,7 @@ void cata_tiles::draw_line() return; } static std::string line_overlay = "animation_line"; - if( !is_target_line || g->u.sees( line_pos ) ) { + if( !is_target_line || get_player_character().sees( line_pos ) ) { for( auto it = line_trajectory.begin(); it != line_trajectory.end() - 1; ++it ) { draw_from_id_string( line_overlay, *it, 0, 0, lit_level::LIT, false ); } @@ -3303,6 +3325,7 @@ void cata_tiles::draw_weather_frame() void cata_tiles::draw_sct_frame( std::multimap &overlay_strings ) { const bool use_font = get_option( "ANIMATION_SCT_USE_FONT" ); + Character &player_character = get_player_character(); for( auto iter = SCT.vSCT.begin(); iter != SCT.vSCT.end(); ++iter ) { const point iD( iter->getPosX(), iter->getPosY() ); @@ -3331,7 +3354,7 @@ void cata_tiles::draw_sct_frame( std::multimap &overlay_s if( tileset_ptr->find_tile_type( generic_id ) ) { draw_from_id_string( generic_id, C_NONE, empty_string, - iD + tripoint( iOffsetX, iOffsetY, g->u.pos().z ), 0, 0, lit_level::LIT, false ); + iD + tripoint( iOffsetX, iOffsetY, player_character.pos().z ), 0, 0, lit_level::LIT, false ); } if( tile_iso ) { @@ -3346,10 +3369,11 @@ void cata_tiles::draw_sct_frame( std::multimap &overlay_s void cata_tiles::draw_zones_frame() { + Character &player_character = get_player_character(); for( int iY = zone_start.y; iY <= zone_end.y; ++ iY ) { for( int iX = zone_start.x; iX <= zone_end.x; ++iX ) { draw_from_id_string( "highlight", C_NONE, empty_string, - zone_offset.xy() + tripoint( iX, iY, g->u.pos().z ), + zone_offset.xy() + tripoint( iX, iY, player_character.pos().z ), 0, 0, lit_level::LIT, false ); } } diff --git a/src/cata_variant.cpp b/src/cata_variant.cpp index d8725ffffe294..d715ff572ce6c 100644 --- a/src/cata_variant.cpp +++ b/src/cata_variant.cpp @@ -18,7 +18,6 @@ std::string enum_to_string( cata_variant_type type ) case cata_variant_type::chrono_seconds: return "chrono_seconds"; case cata_variant_type::debug_menu_index: return "debug_menu_index"; case cata_variant_type::efftype_id: return "efftype_id"; - case cata_variant_type::hp_part: return "hp_part"; case cata_variant_type::int_: return "int"; case cata_variant_type::itype_id: return "itype_id"; case cata_variant_type::matype_id: return "matype_id"; diff --git a/src/cata_variant.h b/src/cata_variant.h index d3b020f05bcc3..9fbbd39cee4bc 100644 --- a/src/cata_variant.h +++ b/src/cata_variant.h @@ -24,7 +24,6 @@ template struct enum_traits; enum body_part : int; enum class mutagen_technique : int; -enum hp_part : int; namespace debug_menu { @@ -45,7 +44,6 @@ enum class cata_variant_type : int { chrono_seconds, debug_menu_index, efftype_id, - hp_part, int_, itype_id, matype_id, @@ -167,7 +165,7 @@ struct convert_enum { }; // These are the specializations of convert for each value type. -static_assert( static_cast( cata_variant_type::num_types ) == 30, +static_assert( static_cast( cata_variant_type::num_types ) == 29, "This assert is a reminder to add conversion support for any new types to the " "below specializations" ); @@ -230,9 +228,6 @@ struct convert : convert_string_id struct convert : convert_string_id {}; -template<> -struct convert : convert_enum {}; - template<> struct convert { using type = int; diff --git a/src/character.cpp b/src/character.cpp index 2f1ee1dcd74f2..861be980d2be2 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -63,6 +63,8 @@ #include "overmapbuffer.h" #include "pathfinding.h" #include "player.h" +#include "recipe_dictionary.h" +#include "proficiency.h" #include "ret_val.h" #include "rng.h" #include "scent_map.h" @@ -147,6 +149,7 @@ static const efftype_id effect_hunger_near_starving( "hunger_near_starving" ); static const efftype_id effect_hunger_satisfied( "hunger_satisfied" ); static const efftype_id effect_hunger_starving( "hunger_starving" ); static const efftype_id effect_hunger_very_hungry( "hunger_very_hungry" ); +static const efftype_id effect_hypovolemia( "hypovolemia" ); static const efftype_id effect_in_pit( "in_pit" ); static const efftype_id effect_infected( "infected" ); static const efftype_id effect_jetinjector( "jetinjector" ); @@ -190,6 +193,7 @@ static const itype_id itype_UPS_off( "UPS_off" ); static const skill_id skill_archery( "archery" ); static const skill_id skill_dodge( "dodge" ); +static const skill_id skill_firstaid( "firstaid" ); static const skill_id skill_pistol( "pistol" ); static const skill_id skill_rifle( "rifle" ); static const skill_id skill_shotgun( "shotgun" ); @@ -209,6 +213,8 @@ static const trait_id trait_BADBACK( "BADBACK" ); static const trait_id trait_DEBUG_NODMG( "DEBUG_NODMG" ); static const trait_id trait_HUGE( "HUGE" ); static const trait_id trait_HUGE_OK( "HUGE_OK" ); +static const trait_id trait_PACIFIST( "PACIFIST" ); +static const trait_id trait_SAVANT( "SAVANT" ); static const trait_id trait_SMALL2( "SMALL2" ); static const trait_id trait_SMALL_OK( "SMALL_OK" ); static const trait_id trait_SQUEAMISH( "SQUEAMISH" ); @@ -360,6 +366,7 @@ static const std::string flag_SEMITANGIBLE( "SEMITANGIBLE" ); static const std::string flag_SKINTIGHT( "SKINTIGHT" ); static const std::string flag_SPEEDLOADER( "SPEEDLOADER" ); static const std::string flag_SPLINT( "SPLINT" ); +static const std::string flag_TOURNIQUET( "TOURNIQUET" ); static const std::string flag_STURDY( "STURDY" ); static const std::string flag_SWIMMABLE( "SWIMMABLE" ); static const std::string flag_SWIM_GOGGLES( "SWIM_GOGGLES" ); @@ -369,6 +376,8 @@ static const std::string flag_USE_UPS( "USE_UPS" ); static const mtype_id mon_player_blob( "mon_player_blob" ); static const mtype_id mon_shadow_snake( "mon_shadow_snake" ); +static const vitamin_id vitamin_blood( "blood" ); + namespace io { @@ -401,8 +410,6 @@ Character &get_player_character() Character::Character() : visitable(), - damage_bandaged( {{ 0 }} ), - damage_disinfected( {{ 0 }} ), cached_time( calendar::before_time_starts ), id( -1 ), next_climate_control_check( calendar::before_time_starts ), @@ -440,7 +447,6 @@ Character::Character() : healthy_calories = 55000; stored_calories = healthy_calories; initialize_stomach_contents(); - healed_total = { { 0, 0, 0, 0, 0, 0 } }; name.clear(); custom_profession.clear(); @@ -594,7 +600,7 @@ int Character::effective_dispersion( int dispersion ) const /** @EFFECT_PER penalizes sight dispersion when low. */ dispersion += ranged_per_mod(); - dispersion += encumb( bp_eyes ) / 2; + dispersion += encumb( bodypart_id( "eyes" ) ) / 2; return std::max( dispersion, 0 ); } @@ -663,7 +669,7 @@ double Character::aim_speed_dex_modifier() const double Character::aim_speed_encumbrance_modifier() const { - return ( encumb( bp_hand_l ) + encumb( bp_hand_r ) ) / 10.0; + return ( encumb( bodypart_id( "hand_l" ) ) + encumb( bodypart_id( "hand_r" ) ) ) / 10.0; } double Character::aim_cap_from_volume( const item &gun ) const @@ -945,9 +951,10 @@ int Character::swim_speed() const ret -= hand_bonus_mult * ( 60 + str_cur * 5 ); } /** @EFFECT_SWIMMING increases swim speed */ - ret += ( 50 - get_skill_level( skill_swimming ) * 2 ) * ( ( encumb( bp_leg_l ) + encumb( - bp_leg_r ) ) / 10 ); - ret += ( 80 - get_skill_level( skill_swimming ) * 3 ) * ( encumb( bp_torso ) / 10 ); + ret += ( 50 - get_skill_level( skill_swimming ) * 2 ) * ( ( encumb( bodypart_id( "leg_l" ) ) + + encumb( + bodypart_id( "leg_r" ) ) ) / 10 ); + ret += ( 80 - get_skill_level( skill_swimming ) * 3 ) * ( encumb( bodypart_id( "torso" ) ) / 10 ); if( get_skill_level( skill_swimming ) < 10 ) { for( auto &i : worn ) { ret += i.volume() / 125_ml * ( 10 - get_skill_level( skill_swimming ) ); @@ -1075,12 +1082,13 @@ void Character::mount_creature( monster &z ) mounted_creature = mons; mons->mounted_player = this; if( is_avatar() ) { - if( g->u.is_hauling() ) { - g->u.stop_hauling(); + avatar &player_character = get_avatar(); + if( player_character.is_hauling() ) { + player_character.stop_hauling(); } - if( g->u.get_grab_type() != object_type::NONE ) { + if( player_character.get_grab_type() != object_type::NONE ) { add_msg( m_warning, _( "You let go of the grabbed object." ) ); - g->u.grab( object_type::NONE ); + player_character.grab( object_type::NONE ); } g->place_player( pnt ); } else { @@ -1248,15 +1256,17 @@ void Character::forced_dismount() add_msg( m_debug, "Forced_dismount could not find a square to deposit player" ); } if( is_avatar() ) { - if( g->u.get_grab_type() != object_type::NONE ) { + avatar &player_character = get_avatar(); + if( player_character.get_grab_type() != object_type::NONE ) { add_msg( m_warning, _( "You let go of the grabbed object." ) ); - g->u.grab( object_type::NONE ); + player_character.grab( object_type::NONE ); } set_movement_mode( move_mode_id( "walk" ) ); - if( g->u.is_auto_moving() || g->u.has_destination() || g->u.has_destination_activity() ) { - g->u.clear_destination(); + if( player_character.is_auto_moving() || player_character.has_destination() || + player_character.has_destination_activity() ) { + player_character.clear_destination(); } - g->update_map( g->u ); + g->update_map( player_character ); } if( activity ) { cancel_activity(); @@ -1281,9 +1291,10 @@ void Character::dismount() if( critter->has_flag( MF_RIDEABLE_MECH ) && !critter->type->mech_weapon.is_empty() ) { remove_item( weapon ); } - if( is_avatar() && g->u.get_grab_type() != object_type::NONE ) { + avatar &player_character = get_avatar(); + if( is_avatar() && player_character.get_grab_type() != object_type::NONE ) { add_msg( m_warning, _( "You let go of the grabbed object." ) ); - g->u.grab( object_type::NONE ); + player_character.grab( object_type::NONE ); } critter->remove_effect( effect_ridden ); critter->add_effect( effect_controlled, 5_turns ); @@ -1295,6 +1306,21 @@ void Character::dismount() } } +void Character::handle_skill_warning( const skill_id &id, bool force_warning ) +{ + //remind the player intermittently that no skill gain takes place + if( is_player() && ( force_warning || one_in( 5 ) ) ) { + SkillLevel &level = get_skill_level_object( id ); + + const Skill &skill = id.obj(); + std::string skill_name = skill.name(); + int curLevel = level.level(); + + add_msg( m_info, _( "This task is too simple to train your %s beyond %d." ), + skill_name, curLevel ); + } +} + /** Returns true if the character has two functioning arms */ bool Character::has_two_arms() const { @@ -1761,6 +1787,11 @@ void Character::recalc_hp() get_fat_to_hp() ); } +int Character::get_part_hp_max( const bodypart_id &id ) const +{ + return enchantment_cache.modify_value( enchant_vals::mod::MAX_HP, Creature::get_part_hp_max( id ) ); +} + // This must be called when any of the following change: // - effects // - bionics @@ -1801,6 +1832,8 @@ void Character::recalc_sight_limits() sight_max = 10; } + sight_max = enchantment_cache.modify_value( enchant_vals::mod::SIGHT_RANGE, sight_max ); + // Debug-only NV, by vache's request if( has_trait( trait_DEBUG_NIGHTVISION ) ) { vision_mode_cache.set( DEBUG_NIGHTVISION ); @@ -1879,7 +1912,7 @@ float Character::get_vision_threshold( float light_level ) const LIGHT_AMBIENT_MINIMAL ) / ( LIGHT_AMBIENT_LIT - LIGHT_AMBIENT_MINIMAL ) ); - float range = get_per() / 3.0f - encumb( bp_eyes ) / 10.0f; + float range = get_per() / 3.0f - encumb( bodypart_id( "eyes" ) ) / 10.0f; if( vision_mode_cache[NV_GOGGLES] || vision_mode_cache[NIGHTVISION_3] || vision_mode_cache[FULL_ELFA_VISION] || vision_mode_cache[CEPH_VISION] ) { range += 10; @@ -1917,7 +1950,7 @@ void Character::check_item_encumbrance_flag() } if( update_required ) { - reset_encumbrance(); + calc_encumbrance(); } } @@ -2032,6 +2065,118 @@ bionic_id Character::get_most_efficient_bionic( const std::vector &bi return bio; } +void Character::practice( const skill_id &id, int amount, int cap, bool suppress_warning ) +{ + SkillLevel &level = get_skill_level_object( id ); + const Skill &skill = id.obj(); + if( !level.can_train() && !in_sleep_state() ) { + // If leveling is disabled, don't train, don't drain focus, don't print anything + // Leaving as a skill method rather than global for possible future skill cap setting + return; + } + + const auto highest_skill = [&]() { + std::pair result( skill_id::NULL_ID(), -1 ); + for( const auto &pair : *_skills ) { + const SkillLevel &lobj = pair.second; + if( lobj.level() > result.second ) { + result = std::make_pair( pair.first, lobj.level() ); + } + } + return result.first; + }; + + const bool isSavant = has_trait( trait_SAVANT ); + const skill_id savantSkill = isSavant ? highest_skill() : skill_id::NULL_ID(); + + amount = adjust_for_focus( amount ); + + if( has_trait( trait_PACIFIST ) && skill.is_combat_skill() ) { + if( !one_in( 3 ) ) { + amount = 0; + } + } + if( has_trait_flag( "PRED2" ) && skill.is_combat_skill() ) { + if( one_in( 3 ) ) { + amount *= 2; + } + } + if( has_trait_flag( "PRED3" ) && skill.is_combat_skill() ) { + amount *= 2; + } + + if( has_trait_flag( "PRED4" ) && skill.is_combat_skill() ) { + amount *= 3; + } + + if( isSavant && id != savantSkill ) { + amount /= 2; + } + + if( amount > 0 && get_skill_level( id ) > cap ) { //blunt grinding cap implementation for crafting + amount = 0; + if( !suppress_warning ) { + handle_skill_warning( id, false ); + } + } + if( amount > 0 && level.isTraining() ) { + int oldLevel = get_skill_level( id ); + get_skill_level_object( id ).train( amount ); + int newLevel = get_skill_level( id ); + std::string skill_name = skill.name(); + if( newLevel > oldLevel ) { + g->events().send( getID(), id, newLevel ); + } + if( is_player() && newLevel > oldLevel ) { + add_msg( m_good, _( "Your skill in %s has increased to %d!" ), skill_name, newLevel ); + } + if( is_player() && newLevel > cap ) { + //inform player immediately that the current recipe can't be used to train further + add_msg( m_info, _( "You feel that %s tasks of this level are becoming trivial." ), + skill_name ); + } + + int chance_to_drop = focus_pool; + focus_pool -= chance_to_drop / 100; + // Apex Predators don't think about much other than killing. + // They don't lose Focus when practicing combat skills. + if( ( rng( 1, 100 ) <= ( chance_to_drop % 100 ) ) && ( !( has_trait_flag( "PRED4" ) && + skill.is_combat_skill() ) ) ) { + focus_pool--; + } + } + + get_skill_level_object( id ).practice(); +} + +// Returned values range from 1.0 (unimpeded vision) to 11.0 (totally blind). +// 1.0 is LIGHT_AMBIENT_LIT or brighter +// 4.0 is a dark clear night, barely bright enough for reading and crafting +// 6.0 is LIGHT_AMBIENT_DIM +// 7.3 is LIGHT_AMBIENT_MINIMAL, a dark cloudy night, unlit indoors +// 11.0 is zero light or blindness +float Character::fine_detail_vision_mod( const tripoint &p ) const +{ + // PER_SLIME_OK implies you can get enough eyes around the bile + // that you can generally see. There still will be the haze, but + // it's annoying rather than limiting. + if( is_blind() || + ( ( has_effect( effect_boomered ) || has_effect( effect_darkness ) ) && + !has_trait( trait_PER_SLIME_OK ) ) ) { + return 11.0; + } + // Scale linearly as light level approaches LIGHT_AMBIENT_LIT. + // If we're actually a source of light, assume we can direct it where we need it. + // Therefore give a hefty bonus relative to ambient light. + float own_light = std::max( 1.0f, LIGHT_AMBIENT_LIT - active_light() - 2.0f ); + + // Same calculation as above, but with a result 3 lower. + float ambient_light = std::max( 1.0f, + LIGHT_AMBIENT_LIT - get_map().ambient_light_at( p == tripoint_zero ? pos() : p ) + 1.0f ); + + return std::min( own_light, ambient_light ); +} + units::energy Character::get_power_level() const { return power_level; @@ -2039,12 +2184,12 @@ units::energy Character::get_power_level() const units::energy Character::get_max_power_level() const { - return max_power_level; + return enchantment_cache.modify_value( enchant_vals::mod::BIONIC_POWER, max_power_level ); } void Character::set_power_level( const units::energy &npower ) { - power_level = std::min( npower, max_power_level ); + power_level = std::min( npower, get_max_power_level() ); } void Character::set_max_power_level( const units::energy &npower_max ) @@ -2056,15 +2201,15 @@ void Character::mod_power_level( const units::energy &npower ) { // units::energy is an int, so avoid overflow by converting it to a int64_t, then adding them // If the result is greater than the max power level, set power to max - int64_t power = static_cast( units::to_millijoule( power_level ) ) + + int64_t power = static_cast( units::to_millijoule( get_power_level() ) ) + static_cast( units::to_millijoule( npower ) ); units::energy new_power; - if( power > units::to_millijoule( max_power_level ) ) { - new_power = max_power_level; + if( power > units::to_millijoule( get_max_power_level() ) ) { + new_power = get_max_power_level(); } else { - new_power = power_level + npower; + new_power = get_power_level() + npower; } - power_level = clamp( new_power, 0_kJ, max_power_level ); + set_power_level( clamp( new_power, 0_kJ, get_max_power_level() ) ); } void Character::mod_max_power_level( const units::energy &npower_max ) @@ -2074,22 +2219,22 @@ void Character::mod_max_power_level( const units::energy &npower_max ) bool Character::is_max_power() const { - return power_level >= max_power_level; + return get_power_level() >= get_max_power_level(); } bool Character::has_power() const { - return power_level > 0_kJ; + return get_power_level() > 0_kJ; } bool Character::has_max_power() const { - return max_power_level > 0_kJ; + return get_max_power_level() > 0_kJ; } bool Character::enough_power_for( const bionic_id &bid ) const { - return power_level >= bid->power_activate; + return get_power_level() >= bid->power_activate; } std::vector Character::get_fuel_available( const bionic_id &bio ) const @@ -2206,7 +2351,8 @@ int Character::get_standard_stamina_cost( item *thrown_item ) //If the item is thrown, override with the thrown item instead. const int weight_cost = ( thrown_item == nullptr ) ? this->weapon.weight() / ( 16_gram ) : thrown_item->weight() / ( 16_gram ); - const int encumbrance_cost = this->encumb( bp_arm_l ) + this->encumb( bp_arm_r ); + const int encumbrance_cost = this->encumb( bodypart_id( "arm_l" ) ) + this->encumb( + bodypart_id( "arm_r" ) ); return ( weight_cost + encumbrance_cost + 50 ) * -1; } @@ -2222,8 +2368,7 @@ cata::optional::iterator> Character::wear_item( const item &to_w } const bool was_deaf = is_deaf(); - const bool supertinymouse = g->u.has_trait( trait_SMALL2 ) || - g->u.has_trait( trait_SMALL_OK ); + const bool supertinymouse = has_trait( trait_SMALL2 ) || has_trait( trait_SMALL_OK ); last_item = to_wear.typeId(); std::list::iterator position = position_to_wear_new_item( to_wear ); @@ -2239,7 +2384,7 @@ cata::optional::iterator> Character::wear_item( const item &to_w moves -= item_wear_cost( to_wear ); for( const bodypart_id &bp : get_all_body_parts() ) { - if( to_wear.covers( bp ) && encumb( bp->token ) >= 40 ) { + if( to_wear.covers( bp ) && encumb( bp ) >= 40 ) { add_msg_if_player( m_warning, bp == bodypart_id( "eyes" ) ? _( "Your %s are very encumbered! %s" ) : _( "Your %s is very encumbered! %s" ), @@ -2258,7 +2403,7 @@ cata::optional::iterator> Character::wear_item( const item &to_w _( "This %s is too small to wear comfortably! Maybe it could be refitted." ), to_wear.tname() ); } - } else if( is_npc() && g->u.sees( *this ) ) { + } else if( is_npc() && get_player_character().sees( *this ) ) { add_msg_if_npc( _( " puts on their %s." ), to_wear.tname() ); } @@ -2268,7 +2413,7 @@ cata::optional::iterator> Character::wear_item( const item &to_w inv.update_cache_with_item( *new_item_it ); recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); return new_item_it; } @@ -2320,11 +2465,11 @@ std::vector Character::nearby( const item_pocket *Character::best_pocket( const item &it, const item *avoid ) { item_pocket *ret = nullptr; - if( &weapon != avoid ) { + if( &weapon != &it && &weapon != avoid ) { ret = weapon.best_pocket( it ); } for( item &worn_it : worn ) { - if( &worn_it == avoid ) { + if( &worn_it == &it || &worn_it == avoid ) { continue; } item_pocket *internal_pocket = worn_it.best_pocket( it ); @@ -2454,10 +2599,6 @@ std::vector Character::all_items_loc() std::vector Character::top_items_loc() { std::vector ret; - if( has_weapon() ) { - item_location weap_loc( *this, &weapon ); - ret.push_back( weap_loc ); - } for( item &worn_it : worn ) { item_location worn_loc( *this, &worn_it ); ret.push_back( worn_loc ); @@ -2530,22 +2671,6 @@ int Character::get_item_position( const item *it ) const return inv.position_by_item( it ); } -item Character::i_rem( int pos ) -{ - item tmp; - if( pos == -1 ) { - return remove_weapon(); - } else if( pos < -1 && pos > worn_position_to_index( worn.size() ) ) { - auto iter = worn.begin(); - std::advance( iter, worn_position_to_index( pos ) ); - tmp = *iter; - tmp.on_takeoff( *this ); - worn.erase( iter ); - return tmp; - } - return inv.remove_item( pos ); -} - item Character::i_rem( const item *it ) { auto tmp = remove_items_with( [&it]( const item & i ) { @@ -2558,9 +2683,9 @@ item Character::i_rem( const item *it ) return tmp.front(); } -void Character::i_rem_keep_contents( const int idx ) +void Character::i_rem_keep_contents( const item *const it ) { - i_rem( idx ).spill_contents( pos() ); + i_rem( it ).spill_contents( pos() ); } bool Character::i_add_or_drop( item &it, int qty ) @@ -2872,45 +2997,55 @@ units::mass Character::weight_carried_with_tweaks( const item_tweaks &tweaks ) c units::mass ret = 0_gram; for( auto &i : worn ) { if( !without.count( &i ) ) { + for( auto j : i.contents.all_items_ptr( item_pocket::pocket_type::CONTAINER ) ) { + if( j->count_by_charges() ) { + ret -= get_selected_stack_weight( j, without ); + } else if( without.count( j ) ) { + ret -= j->weight(); + } + } ret += i.weight(); } } - // Items in inventory - const inventory &i = tweaks.replace_inv ? tweaks.replace_inv->get() : inv; - ret += i.weight_without( without ); - // Wielded item units::mass weaponweight = 0_gram; - auto weapon_it = without.find( &weapon ); - if( weapon_it == without.end() ) { - weaponweight = weapon.weight(); - } else { - int subtract_count = ( *weapon_it ).second; - if( weapon.count_by_charges() ) { - item copy = weapon; - copy.charges -= subtract_count; - if( copy.charges < 0 ) { - debugmsg( "Trying to remove more charges than the wielded item has" ); - copy.charges = 0; + if( !without.count( &weapon ) ) { + weaponweight += weapon.weight(); + for( auto i : weapon.contents.all_items_ptr( item_pocket::pocket_type::CONTAINER ) ) { + if( i->count_by_charges() ) { + weaponweight -= get_selected_stack_weight( i, without ); + } else if( without.count( i ) ) { + weaponweight -= i->weight(); } - weaponweight = copy.weight(); - } else if( subtract_count > 1 ) { - debugmsg( "Trying to remove more than one wielded item" ); } + } else if( weapon.count_by_charges() ) { + weaponweight += weapon.weight() - get_selected_stack_weight( &weapon, without ); } + // Exclude wielded item if using lifting tool - if( weaponweight + ret > weight_capacity() ) { - if( g->new_game || best_nearby_lifting_assist() < weaponweight ) { - ret += weaponweight; - } - } else { + if( ( weaponweight + ret <= weight_capacity() ) || ( g->new_game || + best_nearby_lifting_assist() < weaponweight ) ) { ret += weaponweight; } return ret; } +units::mass Character::get_selected_stack_weight( const item *i, + const std::map &without ) const +{ + auto stack = without.find( i ); + if( stack != without.end() ) { + int selected = stack->second; + item copy = *i; + copy.charges = selected; + return copy.weight(); + } + + return 0_gram; +} + units::volume Character::volume_carried_with_tweaks( const std::vector> &locations ) const @@ -2924,8 +3059,50 @@ units::volume Character::volume_carried_with_tweaks( const units::volume Character::volume_carried_with_tweaks( const item_tweaks &tweaks ) const { - const inventory &i = tweaks.replace_inv ? tweaks.replace_inv->get() : inv; - return tweaks.without_items ? i.volume_without( *tweaks.without_items ) : i.volume(); + const std::map empty; + const std::map &without = tweaks.without_items ? tweaks.without_items->get() : + empty; + + // Worn items + units::volume ret = 0_ml; + for( auto &i : worn ) { + if( !without.count( &i ) ) { + for( auto j : i.contents.all_items_top( item_pocket::pocket_type::CONTAINER ) ) { + if( j->count_by_charges() ) { + ret += j->volume() - get_selected_stack_volume( j, without ); + } else if( !without.count( j ) ) { + ret += j->volume(); + } + } + } + } + + // Wielded item + if( !without.count( &weapon ) ) { + for( auto i : weapon.contents.all_items_top( item_pocket::pocket_type::CONTAINER ) ) { + if( i->count_by_charges() ) { + ret += i->volume() - get_selected_stack_volume( i, without ); + } else if( !without.count( i ) ) { + ret += i->volume(); + } + } + } + + return ret; +} + +units::volume Character::get_selected_stack_volume( const item *i, + const std::map &without ) const +{ + auto stack = without.find( i ); + if( stack != without.end() ) { + int selected = stack->second; + item copy = *i; + copy.charges = selected; + return copy.volume(); + } + + return 0_ml; } units::mass Character::weight_capacity() const @@ -2959,6 +3136,8 @@ units::mass Character::weight_capacity() const ret += 22500_gram; } + ret = enchantment_cache.modify_value( enchant_vals::mod::CARRY_WEIGHT, ret ); + if( ret < 0_gram ) { ret = 0_gram; } @@ -3075,6 +3254,30 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons } } + if( it.has_flag( flag_TOURNIQUET ) ) { + bool need_tourniquet = false; + for( const bodypart_id &bp : get_all_body_parts() ) { + if( !it.covers( bp ) ) { + continue; + } + effect e = get_effect( effect_bleed, bp->token ); + if( !e.is_null() && e.get_intensity() > e.get_max_intensity() / 4 && + !worn_with_flag( flag_TOURNIQUET, bp ) ) { + need_tourniquet = true; + break; + } + } + if( !need_tourniquet ) { + std::string msg; + if( is_player() ) { + msg = _( "You don't need a tourniquet to stop the bleeding." ); + } else { + msg = string_format( _( "%s doesn't need a tourniquet to stop the bleeding." ), name ); + } + return ret_val::make_failure( msg ); + } + } + if( it.has_flag( flag_RESTRICT_HANDS ) && !has_two_arms() ) { return ret_val::make_failure( ( is_player() ? _( "You don't have enough arms to wear that." ) : string_format( _( "%s doesn't have enough arms to wear that." ), name ) ) ); @@ -3164,7 +3367,7 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons if( it.covers( bodypart_id( "head" ) ) && !it.has_flag( flag_SEMITANGIBLE ) && ( it.has_flag( flag_SKINTIGHT ) || it.has_flag( flag_HELMET_COMPAT ) ) && - ( head_cloth_encumbrance() + it.get_encumber( *this ) > 40 ) ) { + ( head_cloth_encumbrance() + it.get_encumber( *this, bodypart_id( "head" ) ) > 40 ) ) { return ret_val::make_failure( ( is_player() ? _( "You can't wear that much on your head!" ) : string_format( _( "%s can't wear that much on their head!" ), name ) ) ); } @@ -3175,7 +3378,12 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons ret_val Character::can_unwield( const item &it ) const { if( it.has_flag( "NO_UNWIELD" ) ) { - return ret_val::make_failure( _( "You cannot unwield your %s." ), it.tname() ); + cata::optional wi; + // check if "it" is currently wielded fake bionic weapon that can be deactivated + if( !( is_wielding( it ) && ( wi = active_bionic_weapon_index() ) && + can_deactivate_bionic( *wi ).success() ) ) { + return ret_val::make_failure( _( "You cannot unwield your %s." ), it.tname() ); + } } return ret_val::make_success(); @@ -3620,25 +3828,22 @@ bool Character::has_nv() return nv; } -void Character::reset_encumbrance() -{ - encumbrance_cache_dirty = true; -} - -std::array Character::calc_encumbrance() const +void Character::calc_encumbrance() { - return calc_encumbrance( item() ); + calc_encumbrance( item() ); } -std::array Character::calc_encumbrance( const item &new_item ) const +void Character::calc_encumbrance( const item &new_item ) { - std::array enc; - + std::map enc; item_encumb( enc, new_item ); mut_cbm_encumb( enc ); - return enc; + for( const std::pair &elem : enc ) { + set_part_encumbrance_data( elem.first, elem.second ); + } + } units::mass Character::get_weight() const @@ -3657,29 +3862,6 @@ units::mass Character::get_weight() const return ret; } -std::array Character::get_encumbrance() const -{ - if( encumbrance_cache_dirty ) { - encumbrance_cache = calc_encumbrance(); - encumbrance_cache_dirty = false; - } - return encumbrance_cache; -} - -std::array Character::get_encumbrance( const item &new_item ) const -{ - return calc_encumbrance( new_item ); -} - -int Character::extraEncumbrance( const layer_level level, const int bp ) const -{ - if( encumbrance_cache_dirty ) { - encumbrance_cache = calc_encumbrance(); - encumbrance_cache_dirty = false; - } - return encumbrance_cache[bp].layer_penalty_details[static_cast( level )].total; -} - bool Character::change_side( item &it, bool interactive ) { if( !it.swap_side() ) { @@ -3699,7 +3881,7 @@ bool Character::change_side( item &it, bool interactive ) } mod_moves( -250 ); - reset_encumbrance(); + calc_encumbrance(); return true; } @@ -3718,45 +3900,42 @@ bool Character::change_side( item_location &loc, bool interactive ) return change_side( *loc, interactive ); } -static void layer_item( std::array &vals, - const item &it, - std::array &highest_layer_so_far, - bool power_armor, const Character &c ) +static void layer_item( std::map &vals, const item &it, + std::map &highest_layer_so_far, bool power_armor, const Character &c ) { - const auto item_layer = it.get_layer(); - int encumber_val = it.get_encumber( c ); - // For the purposes of layering penalty, set a min of 2 and a max of 10 per item. - int layering_encumbrance = std::min( 10, std::max( 2, encumber_val ) ); - - /* - * Setting layering_encumbrance to 0 at this point makes the item cease to exist - * for the purposes of the layer penalty system. (normally an item has a minimum - * layering_encumbrance of 2 ) - */ - if( it.has_flag( "SEMITANGIBLE" ) ) { - encumber_val = 0; - layering_encumbrance = 0; - } - - const int armorenc = !power_armor || !it.is_power_armor() ? - encumber_val : std::max( 0, encumber_val - 40 ); - body_part_set covered_parts = it.get_covered_body_parts(); for( const bodypart_id &bp : c.get_all_body_parts() ) { if( !covered_parts.test( bp.id() ) ) { continue; } - highest_layer_so_far[bp->token] = - std::max( highest_layer_so_far[bp->token], item_layer ); + + const auto item_layer = it.get_layer(); + int encumber_val = it.get_encumber( c, bp.id() ); + int layering_encumbrance = clamp( encumber_val, 2, 10 ); + + /* + * Setting layering_encumbrance to 0 at this point makes the item cease to exist + * for the purposes of the layer penalty system. (normally an item has a minimum + * layering_encumbrance of 2 ) + */ + if( it.has_flag( "SEMITANGIBLE" ) ) { + encumber_val = 0; + layering_encumbrance = 0; + } + + const int armorenc = !power_armor || !it.is_power_armor() ? + encumber_val : std::max( 0, encumber_val - 40 ); + + highest_layer_so_far[bp] = std::max( highest_layer_so_far[bp], item_layer ); // Apply layering penalty to this layer, as well as any layer worn // within it that would normally be worn outside of it. for( layer_level penalty_layer = item_layer; - penalty_layer <= highest_layer_so_far[bp->token]; ++penalty_layer ) { - vals[bp->token].layer( penalty_layer, layering_encumbrance ); + penalty_layer <= highest_layer_so_far[bp]; ++penalty_layer ) { + vals[bp].layer( penalty_layer, layering_encumbrance ); } - vals[bp->token].armor_encumbrance += armorenc; + vals[bp].armor_encumbrance += armorenc; } } @@ -3864,7 +4043,7 @@ int Character::get_wind_resistance( const bodypart_id &bp ) const penalty = 1; // 99% effective } - coverage = std::max( 0, i.get_coverage() - penalty ); + coverage = std::max( 0, i.get_coverage( bp ) - penalty ); totalExposed *= ( 1.0 - coverage / 100.0 ); // Coverage is between 0 and 1? } } @@ -3941,12 +4120,12 @@ std::list::iterator Character::position_to_wear_new_item( const item &new_ * This is currently handled by each of these articles of clothing * being on a different layer and/or body part, therefore accumulating no encumbrance. */ -void Character::item_encumb( std::array &vals, +void Character::item_encumb( std::map &vals, const item &new_item ) const { // reset all layer data - vals = std::array(); + vals = std::map(); // Figure out where new_item would be worn std::list::const_iterator new_item_position = worn.end(); @@ -3959,8 +4138,7 @@ void Character::item_encumb( std::array &vals, // Track highest layer observed so far so we can penalize out-of-order // items - std::array highest_layer_so_far; - std::fill( highest_layer_so_far.begin(), highest_layer_so_far.end(), layer_level::PERSONAL ); + std::map highest_layer_so_far; const bool power_armored = is_wearing_active_power_armor(); for( auto w_it = worn.begin(); w_it != worn.end(); ++w_it ) { @@ -3975,7 +4153,7 @@ void Character::item_encumb( std::array &vals, } // make sure values are sane - for( const body_part bp : all_body_parts ) { + for( const bodypart_id &bp : get_all_body_parts() ) { encumbrance_data &elem = vals[bp]; elem.armor_encumbrance = std::max( 0, elem.armor_encumbrance ); @@ -3985,44 +4163,40 @@ void Character::item_encumb( std::array &vals, } } -int Character::encumb( body_part bp ) const +int Character::encumb( const bodypart_id &bp ) const { - if( encumbrance_cache_dirty ) { - encumbrance_cache = calc_encumbrance(); - encumbrance_cache_dirty = false; - } - return encumbrance_cache[bp].encumbrance; + return get_part_encumbrance_data( bp ).encumbrance; } -static void apply_mut_encumbrance( std::array &vals, +static void apply_mut_encumbrance( std::map &vals, const trait_id &mut, const body_part_set &oversize ) { for( const std::pair &enc : mut->encumbrance_always ) { - vals[enc.first->token].encumbrance += enc.second; + vals[enc.first.id()].encumbrance += enc.second; } for( const std::pair &enc : mut->encumbrance_covered ) { if( !oversize.test( enc.first ) ) { - vals[enc.first->token].encumbrance += enc.second; + vals[enc.first.id()].encumbrance += enc.second; } } } -void Character::mut_cbm_encumb( std::array &vals ) const +void Character::mut_cbm_encumb( std::map &vals ) const { for( const bionic_id &bid : get_bionics() ) { for( const std::pair &element : bid->encumbrance ) { - vals[element.first->token].encumbrance += element.second; + vals[element.first.id()].encumbrance += element.second; } } if( has_active_bionic( bio_shock_absorber ) ) { - for( auto &val : vals ) { - val.encumbrance += 3; // Slight encumbrance to all parts except eyes + for( std::pair &val : vals ) { + val.second.encumbrance += 3; // Slight encumbrance to all parts except eyes } - vals[bp_eyes].encumbrance -= 3; + vals[bodypart_id( "eyes" )].encumbrance -= 3; } // Lower penalty for bps covered only by XL armor @@ -4295,6 +4469,11 @@ int Character::get_stored_kcal() const void Character::mod_stored_kcal( int nkcal ) { + if( nkcal > 0 ) { + add_gained_calories( nkcal ); + } else { + add_spent_calories( -nkcal ); + } set_stored_kcal( stored_calories + nkcal ); } @@ -4587,25 +4766,23 @@ void Character::regen( int rate_multiplier ) } // include healing effects - for( int i = 0; i < num_hp_parts; i++ ) { - const bodypart_id &bp = convert_bp( hp_to_bp( static_cast( i ) ) ).id(); + for( const bodypart_id &bp : get_all_body_parts( true ) ) { float healing = healing_rate_medicine( rest, bp ) * to_turns( 5_minutes ); - int healing_apply = roll_remainder( healing ); - healed_bp( i, healing_apply ); + mod_part_healed_total( bp, healing_apply ); heal( bp, healing_apply ); - if( damage_bandaged[i] > 0 ) { - damage_bandaged[i] -= healing_apply; - if( damage_bandaged[i] <= 0 ) { - damage_bandaged[i] = 0; + if( get_part_damage_bandaged( bp ) > 0 ) { + mod_part_damage_bandaged( bp, -healing_apply ); + if( get_part_damage_bandaged( bp ) <= 0 ) { + set_part_damage_bandaged( bp, 0 ); remove_effect( effect_bandaged, bp->token ); add_msg_if_player( _( "Bandaged wounds on your %s healed." ), body_part_name( bp ) ); } } - if( damage_disinfected[i] > 0 ) { - damage_disinfected[i] -= healing_apply; - if( damage_disinfected[i] <= 0 ) { - damage_disinfected[i] = 0; + if( get_part_damage_disinfected( bp ) > 0 ) { + mod_part_damage_disinfected( bp, -healing_apply ); + if( get_part_damage_disinfected( bp ) <= 0 ) { + set_part_damage_disinfected( bp, 0 ); remove_effect( effect_disinfected, bp->token ); add_msg_if_player( _( "Disinfected wounds on your %s healed." ), body_part_name( bp ) ); } @@ -4613,12 +4790,12 @@ void Character::regen( int rate_multiplier ) // remove effects if the limb was healed by other way if( has_effect( effect_bandaged, bp->token ) && ( get_part( bp )->is_at_max_hp() ) ) { - damage_bandaged[i] = 0; + set_part_damage_bandaged( bp, 0 ); remove_effect( effect_bandaged, bp->token ); add_msg_if_player( _( "Bandaged wounds on your %s healed." ), body_part_name( bp ) ); } if( has_effect( effect_disinfected, bp->token ) && ( get_part( bp )->is_at_max_hp() ) ) { - damage_disinfected[i] = 0; + set_part_damage_disinfected( bp, 0 ); remove_effect( effect_disinfected, bp->token ); add_msg_if_player( _( "Disinfected wounds on your %s healed." ), body_part_name( bp ) ); } @@ -4725,6 +4902,12 @@ void Character::update_body( const time_point &from, const time_point &to ) for( const auto &v : vitamin::all() ) { const time_duration rate = vitamin_rate( v.first ); + + // No blood volume regeneration if body lacks fluids + if( v.first == vitamin_blood && has_effect( effect_hypovolemia ) && get_thirst() > 240 ) { + continue; + } + if( rate > 0_turns ) { int qty = ticks_between( from, to, rate ); if( qty > 0 ) { @@ -4740,6 +4923,10 @@ void Character::update_body( const time_point &from, const time_point &to ) } } + if( is_avatar() && ticks_between( from, to, 24_hours ) > 0 ) { + as_avatar()->advance_daily_calories(); + } + do_skill_rust(); } @@ -5101,6 +5288,9 @@ needs_rates Character::calc_needs_rates() const rates.thirst *= 0.25f; } + rates.fatigue = enchantment_cache.modify_value( enchant_vals::mod::FATIGUE, rates.fatigue ); + rates.thirst = enchantment_cache.modify_value( enchant_vals::mod::THIRST, rates.thirst ); + return rates; } @@ -5455,9 +5645,11 @@ void Character::update_bodytemp() -1.5f * get_fatigue() ) ); // Sunlight - const int sunlight_warmth = g->is_in_sunlight( pos() ) ? ( g->weather.weather == WEATHER_SUNNY ? - 1000 : - 500 ) : 0; + const int sunlight_warmth = g->is_in_sunlight( pos() ) ? + ( get_weather().weather_id->sun_intensity == + sun_intensity_type::high ? + 1000 : + 500 ) : 0; const int best_fire = get_heat_radiation( pos(), true ); const int lying_warmth = use_floor_warmth ? floor_warmth( pos() ) : 0; @@ -5498,8 +5690,7 @@ void Character::update_bodytemp() bp ) / 100.0 ) ); // Calculate windchill int windchill = get_local_windchill( player_local_temp, - get_local_humidity( weather.humidity, g->weather.weather, - sheltered ), + get_local_humidity( weather.humidity, get_weather().weather_id, sheltered ), bp_windpower ); // If you're standing in water, air temperature is replaced by water temperature. No wind. // Convert to 0.01C @@ -6076,10 +6267,10 @@ float Character::get_hit_base() const return get_dex() / 4.0f; } -hp_part Character::body_window( const std::string &menu_header, - bool show_all, bool precise, - int normal_bonus, int head_bonus, int torso_bonus, - float bleed, float bite, float infect, float bandage_power, float disinfectant_power ) const +bodypart_id Character::body_window( const std::string &menu_header, + bool show_all, bool precise, + int normal_bonus, int head_bonus, int torso_bonus, + int bleed, float bite, float infect, float bandage_power, float disinfectant_power ) const { /* This struct establishes some kind of connection between the hp_part (which can be healed and * have HP) and the body_part. Note that there are more body_parts than hp_parts. For example: @@ -6087,24 +6278,23 @@ hp_part Character::body_window( const std::string &menu_header, struct healable_bp { mutable bool allowed; bodypart_id bp; - hp_part hp; std::string name; // Translated name as it appears in the menu. int bonus; }; /* The array of the menu entries show to the player. The entries are displayed in this order, * it may be changed here. */ - std::array parts = { { - { false, bodypart_id( "head" ), hp_head, _( "Head" ), head_bonus }, - { false, bodypart_id( "torso" ), hp_torso, _( "Torso" ), torso_bonus }, - { false, bodypart_id( "arm_l" ), hp_arm_l, _( "Left Arm" ), normal_bonus }, - { false, bodypart_id( "arm_r" ), hp_arm_r, _( "Right Arm" ), normal_bonus }, - { false, bodypart_id( "leg_l" ), hp_leg_l, _( "Left Leg" ), normal_bonus }, - { false, bodypart_id( "leg_r" ), hp_leg_r, _( "Right Leg" ), normal_bonus }, + std::array parts = { { + { false, bodypart_id( "head" ), _( "Head" ), head_bonus }, + { false, bodypart_id( "torso" ), _( "Torso" ), torso_bonus }, + { false, bodypart_id( "arm_l" ), _( "Left Arm" ), normal_bonus }, + { false, bodypart_id( "arm_r" ), _( "Right Arm" ), normal_bonus }, + { false, bodypart_id( "leg_l" ), _( "Left Leg" ), normal_bonus }, + { false, bodypart_id( "leg_r" ), _( "Right Leg" ), normal_bonus }, } }; int max_bp_name_len = 0; - for( const auto &e : parts ) { + for( const healable_bp &e : parts ) { max_bp_name_len = std::max( max_bp_name_len, utf8_width( e.name ) ); } @@ -6116,14 +6306,14 @@ hp_part Character::body_window( const std::string &menu_header, bool is_valid_choice = false; for( size_t i = 0; i < parts.size(); i++ ) { - const auto &e = parts[i]; + const healable_bp &e = parts[i]; const bodypart_id &bp = e.bp; const body_part bp_token = bp->token; const int maximal_hp = get_part_hp_max( bp ); const int current_hp = get_part_hp_cur( bp ); // This will c_light_gray if the part does not have any effects cured by the item/effect // (e.g. it cures only bites, but the part does not have a bite effect) - const nc_color state_col = limb_color( bp, bleed > 0.0f, bite > 0.0f, infect > 0.0f ); + const nc_color state_col = limb_color( bp, bleed > 0, bite > 0.0f, infect > 0.0f ); const bool has_curable_effect = state_col != c_light_gray; // The same as in the main UI sidebar. Independent of the capability of the healing item/effect! const nc_color all_state_col = limb_color( bp, true, true, true ); @@ -6203,11 +6393,13 @@ hp_part Character::body_window( const std::string &menu_header, if( bleeding ) { desc += colorize( string_format( "%s: %s", get_effect( effect_bleed, bp_token ).get_speed_name(), get_effect( effect_bleed, bp_token ).disp_short_desc() ), c_red ) + "\n"; - if( bleed > 0.0f ) { - desc += colorize( string_format( _( "Chance to stop: %d %%" ), - static_cast( bleed * 100 ) ), c_light_green ) + "\n"; + if( bleed > 0 ) { + int percent = static_cast( bleed * 100 / get_effect_int( effect_bleed, bp_token ) ); + percent = std::min( percent, 100 ); + desc += colorize( string_format( _( "Expected reduction of bleeding by: %d %%" ), percent ), + c_light_green ) + "\n"; } else { - desc += colorize( _( "This will not stop the bleeding." ), + desc += colorize( _( "This will not affect the bleeding." ), c_yellow ) + "\n"; } } @@ -6289,9 +6481,9 @@ hp_part Character::body_window( const std::string &menu_header, bmenu.query(); if( bmenu.ret >= 0 && static_cast( bmenu.ret ) < parts.size() && parts[bmenu.ret].allowed ) { - return parts[bmenu.ret].hp; + return parts[bmenu.ret].bp; } else { - return num_hp_parts; + return bodypart_id( "num_bp" ); } } @@ -6303,7 +6495,8 @@ nc_color Character::limb_color( const bodypart_id &bp, bool bleed, bool bite, bo const body_part bp_token = bp->token; int color_bit = 0; nc_color i_color = c_light_gray; - if( bleed && has_effect( effect_bleed, bp_token ) ) { + const int intense = get_effect_int( effect_bleed, bp_token ); + if( bleed && intense > 0 ) { color_bit += 1; } if( bite && has_effect( effect_bite, bp_token ) ) { @@ -6314,7 +6507,13 @@ nc_color Character::limb_color( const bodypart_id &bp, bool bleed, bool bite, bo } switch( color_bit ) { case 1: - i_color = c_red; + if( intense < 11 ) { + i_color = c_light_red; + } else if( intense < 21 ) { + i_color = c_red; + } else { + i_color = c_red_red; + } break; case 10: i_color = c_blue; @@ -6323,10 +6522,18 @@ nc_color Character::limb_color( const bodypart_id &bp, bool bleed, bool bite, bo i_color = c_green; break; case 11: - i_color = c_magenta; + if( intense < 21 ) { + i_color = c_magenta; + } else { + i_color = c_magenta_red; + } break; case 101: - i_color = c_yellow; + if( intense < 21 ) { + i_color = c_yellow; + } else { + i_color = c_yellow_red; + } break; } @@ -6635,7 +6842,7 @@ float Character::active_light() const if( i.covers( elem.first.id() ) && !i.has_flag( flag_ALLOWS_NATURAL_ATTACKS ) && !i.has_flag( flag_SEMITANGIBLE ) && !i.has_flag( flag_PERSONAL ) && !i.has_flag( flag_AURA ) ) { - coverage += i.get_coverage(); + coverage += i.get_coverage( elem.first.id() ); } } curr_lum += elem.second * ( 1 - ( coverage / 100.0f ) ); @@ -6877,52 +7084,6 @@ float Character::rest_quality() const return has_effect( effect_sleep ) ? 1.0f : 0.0f; } -hp_part Character::bp_to_hp( const body_part bp ) -{ - switch( bp ) { - case bp_head: - case bp_eyes: - case bp_mouth: - return hp_head; - case bp_torso: - return hp_torso; - case bp_arm_l: - case bp_hand_l: - return hp_arm_l; - case bp_arm_r: - case bp_hand_r: - return hp_arm_r; - case bp_leg_l: - case bp_foot_l: - return hp_leg_l; - case bp_leg_r: - case bp_foot_r: - return hp_leg_r; - default: - return num_hp_parts; - } -} - -body_part Character::hp_to_bp( const hp_part hpart ) -{ - switch( hpart ) { - case hp_head: - return bp_head; - case hp_torso: - return bp_torso; - case hp_arm_l: - return bp_arm_l; - case hp_arm_r: - return bp_arm_r; - case hp_leg_l: - return bp_leg_l; - case hp_leg_r: - return bp_leg_r; - default: - return num_bp; - } -} - std::string Character::extended_description() const { std::string ss; @@ -7113,7 +7274,7 @@ float Character::healing_rate( float at_rest_quality ) const final_rate *= 1.0f + primary_hp_mod; } - return final_rate; + return enchantment_cache.modify_value( enchant_vals::mod::REGEN_HP, final_rate ); } float Character::healing_rate_medicine( float at_rest_quality, const bodypart_id &bp ) const @@ -7337,9 +7498,10 @@ int Character::get_bmr() const Values are for males, and average! */ const int equation_constant = 5; - return std::ceil( metabolic_rate_base() * activity_level * ( units::to_gram - ( bodyweight() / 100.0 ) + - ( 6.25 * height() ) - ( 5 * age() ) + equation_constant ) ); + const double base_bmr_calc = metabolic_rate_base() * activity_level * ( units::to_gram + ( bodyweight() / 100.0 ) + + ( 6.25 * height() ) - ( 5 * age() ) + equation_constant ); + return std::ceil( enchantment_cache.modify_value( enchant_vals::mod::METABOLISM, base_bmr_calc ) ); } void Character::increase_activity_level( float new_level ) @@ -7558,6 +7720,7 @@ int Character::get_stamina_max() const static const std::string max_stamina_modifier( "max_stamina_modifier" ); int maxStamina = get_option< int >( player_max_stamina ); maxStamina *= Character::mutation_value( max_stamina_modifier ); + maxStamina = enchantment_cache.modify_value( enchant_vals::mod::MAX_STAMINA, maxStamina ); return maxStamina; } @@ -7633,7 +7796,9 @@ void Character::update_stamina( int turns ) mutation_value( stamina_regen_modifier ) + ( mutation_value( "max_stamina_modifier" ) - 1.0f ) ); // But mouth encumbrance interferes, even with mutated stamina. stamina_recovery += stamina_multiplier * std::max( 1.0f, - base_regen_rate - ( encumb( bp_mouth ) / 5.0f ) ); + base_regen_rate - ( encumb( bodypart_id( "mouth" ) ) / 5.0f ) ); + stamina_recovery = enchantment_cache.modify_value( enchant_vals::mod::REGEN_STAMINA, + stamina_recovery ); // TODO: recovering stamina causes hunger/thirst/fatigue. // TODO: Tiredness slowing recovery @@ -7707,7 +7872,6 @@ bool Character::invoke_item( item *used, const std::string &method, const tripoi return false; } // Prevent accessing the item as it may have been deleted by the invoked iuse function. - if( used->is_tool() || actually_used->is_medication() ) { return consume_charges( *actually_used, charges_used ); } else if( used->is_bionic() || used->is_deployable() || method == "place_trap" ) { @@ -7750,7 +7914,7 @@ bool Character::dispose_item( item_location &&obj, const std::string &prompt ) } moves -= item_handling_cost( *obj ); - this->i_add( *obj ); + this->i_add( *obj, true, &*obj ); obj.remove_item(); return true; } @@ -7909,9 +8073,9 @@ int Character::item_handling_cost( const item &it, bool penalties, int base_cost // For single handed items use the least encumbered hand if( it.is_two_handed( *this ) ) { - mv += encumb( bp_hand_l ) + encumb( bp_hand_r ); + mv += encumb( bodypart_id( "hand_l" ) ) + encumb( bodypart_id( "hand_r" ) ); } else { - mv += std::min( encumb( bp_hand_l ), encumb( bp_hand_r ) ); + mv += std::min( encumb( bodypart_id( "hand_l" ) ), encumb( bodypart_id( "hand_r" ) ) ); } return std::max( mv, 0 ); @@ -7963,7 +8127,7 @@ int Character::item_wear_cost( const item &it ) const break; } - mv *= std::max( it.get_encumber( *this ) / 10.0, 1.0 ); + mv *= std::max( it.get_avg_encumber( *this ) / 10.0, 1.0 ); return mv; } @@ -8038,7 +8202,7 @@ int Character::get_shout_volume() const // Balanced around whisper for wearing bondage mask // and noise ~= 10 (door smashing) for wearing dust mask for character with strength = 8 /** @EFFECT_STR increases shouting volume */ - const int penalty = encumb( bp_mouth ) * 3 / 2; + const int penalty = encumb( bodypart_id( "mouth" ) ) * 3 / 2; int noise = base + str_cur * shout_multiplier - penalty; // Minimum noise volume possible after all reductions. @@ -8049,6 +8213,8 @@ int Character::get_shout_volume() const noise = std::max( minimum_noise, noise ); } + noise = enchantment_cache.modify_value( enchant_vals::mod::SHOUT_NOISE, noise ); + // Screaming underwater is not good for oxygen and harder to do overall if( underwater ) { noise = std::max( minimum_noise, noise / 2 ); @@ -8106,7 +8272,7 @@ void Character::shout( std::string msg, bool order ) } } - const int penalty = encumb( bp_mouth ) * 3 / 2; + const int penalty = encumb( bodypart_id( "mouth" ) ) * 3 / 2; // TODO: indistinct noise descriptions should be handled in the sounds code if( noise <= minimum_noise ) { add_msg_if_player( m_warning, @@ -8168,33 +8334,36 @@ tripoint Character::adjacent_tile() const // Don't consider player position continue; } + if( g->critter_at( p ) != nullptr ) { + continue; + } + if( here.impassable( p ) ) { + continue; + } const trap &curtrap = here.tr_at( p ); - if( g->critter_at( p ) == nullptr && here.passable( p ) && - ( curtrap.is_null() || curtrap.is_benign() ) ) { - // Only consider tile if unoccupied, passable and has no traps - dangerous_fields = 0; - auto &tmpfld = here.field_at( p ); - for( auto &fld : tmpfld ) { - const field_entry &cur = fld.second; - if( cur.is_dangerous() ) { - dangerous_fields++; - } + // If we don't known a trap here, the spot "appears" to be good, so consider it. + // Same if we know a benign trap (as it's not dangerous). + if( curtrap.can_see( p, *this ) && !curtrap.is_benign() ) { + continue; + } + // Only consider tile if unoccupied, passable and has no traps + dangerous_fields = 0; + auto &tmpfld = here.field_at( p ); + for( auto &fld : tmpfld ) { + const field_entry &cur = fld.second; + if( cur.is_dangerous() ) { + dangerous_fields++; } + } - if( dangerous_fields == 0 ) { - ret.push_back( p ); - } + if( dangerous_fields == 0 ) { + ret.push_back( p ); } } return random_entry( ret, pos() ); // player position if no valid adjacent tiles } -void Character::healed_bp( int bp, int amount ) -{ - healed_total[bp] += amount; -} - void Character::set_fac_id( const std::string &my_fac_id ) { fac_id = faction_id( my_fac_id ); @@ -8530,11 +8699,11 @@ void Character::absorb_hit( const bodypart_id &bp, damage_instance &dam ) } if( !destroy ) { - destroy = armor_absorb( elem, armor ); + destroy = armor_absorb( elem, armor, bp ); } if( destroy ) { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { SCT.add( point( posx(), posy() ), direction::NORTH, remove_color_tags( pre_damage_name ), m_neutral, _( "destroyed" ), m_info ); } @@ -8576,9 +8745,9 @@ void Character::absorb_hit( const bodypart_id &bp, damage_instance &dam ) } } -bool Character::armor_absorb( damage_unit &du, item &armor ) +bool Character::armor_absorb( damage_unit &du, item &armor, const bodypart_id &bp ) { - if( rng( 1, 100 ) > armor.get_coverage() ) { + if( rng( 1, 100 ) > armor.get_coverage( bp ) ) { return false; } @@ -8678,6 +8847,95 @@ void Character::did_hit( Creature &target ) enchantment_cache.cast_hit_you( *this, target ); } +ret_val Character::can_wield( const item &it ) const +{ + if( it.made_of_from_type( phase_id::LIQUID ) ) { + return ret_val::make_failure( _( "Can't wield spilt liquids." ) ); + } + + if( get_working_arm_count() <= 0 ) { + return ret_val::make_failure( + _( "You need at least one arm to even consider wielding something." ) ); + } + + if( is_armed() && !can_unwield( weapon ).success() ) { + return ret_val::make_failure( _( "The %s is preventing you from wielding the %s." ), + weapname(), it.tname() ); + } + + if( it.is_two_handed( *this ) && ( !has_two_arms() || worn_with_flag( "RESTRICT_HANDS" ) ) ) { + if( worn_with_flag( "RESTRICT_HANDS" ) ) { + return ret_val::make_failure( + _( "Something you are wearing hinders the use of both hands." ) ); + } else if( it.has_flag( "ALWAYS_TWOHAND" ) ) { + return ret_val::make_failure( _( "The %s can't be wielded with only one arm." ), + it.tname() ); + } else { + return ret_val::make_failure( _( "You are too weak to wield %s with only one arm." ), + it.tname() ); + } + } + + return ret_val::make_success(); +} + +bool Character::unwield() +{ + if( weapon.is_null() ) { + return true; + } + + if( !can_unwield( weapon ).success() ) { + return false; + } + + // currently the only way to unwield NO_UNWIELD weapon is if it's a bionic that can be deactivated + if( weapon.has_flag( "NO_UNWIELD" ) ) { + cata::optional wi = active_bionic_weapon_index(); + return wi && deactivate_bionic( *wi ); + } + + const std::string query = string_format( _( "Stop wielding %s?" ), weapon.tname() ); + + if( !dispose_item( item_location( *this, &weapon ), query ) ) { + return false; + } + + inv.unsort(); + + return true; +} + +std::string Character::weapname() const +{ + if( weapon.is_gun() ) { + std::string gunmode; + // only required for empty mags and empty guns + std::string mag_ammo; + if( weapon.gun_all_modes().size() > 1 ) { + gunmode = weapon.gun_current_mode().tname(); + } + + if( weapon.ammo_remaining() == 0 ) { + if( weapon.magazine_current() != nullptr ) { + const item *mag = weapon.magazine_current(); + mag_ammo = string_format( " (0/%d)", + mag->ammo_capacity( item( mag->ammo_default() ).ammo_type() ) ); + } else { + mag_ammo = _( " (empty)" ); + } + } + + return string_format( "%s%s%s", gunmode, weapon.display_name(), mag_ammo ); + + } else if( !is_armed() ) { + return _( "fists" ); + + } else { + return weapon.tname(); + } +} + void Character::on_hit( Creature *source, bodypart_id /*bp_hit*/, float /*difficulty*/, dealt_projectile_attack const *const /*proj*/ ) { @@ -8751,7 +9009,7 @@ dealt_damage_instance Character::deal_damage( Creature *source, bodypart_id bp, int dam = dealt_dams.total_damage(); // TODO: Pre or post blit hit tile onto "this"'s location here - if( dam > 0 && g->u.sees( pos() ) ) { + if( dam > 0 && get_player_character().sees( pos() ) ) { g->draw_hit_player( *this, dam ); if( is_player() && source ) { @@ -8787,11 +9045,12 @@ dealt_damage_instance Character::deal_damage( Creature *source, bodypart_id bp, } } + Character &player_character = get_player_character(); //Acid blood effects. - bool u_see = g->u.sees( *this ); + bool u_see = player_character.sees( *this ); int cut_dam = dealt_dams.type_damage( DT_CUT ); if( source && has_trait( trait_ACIDBLOOD ) && !one_in( 3 ) && - ( dam >= 4 || cut_dam > 0 ) && ( rl_dist( g->u.pos(), source->pos() ) <= 1 ) ) { + ( dam >= 4 || cut_dam > 0 ) && ( rl_dist( player_character.pos(), source->pos() ) <= 1 ) ) { if( is_player() ) { add_msg( m_good, _( "Your acidic blood splashes %s in mid-attack!" ), source->disp_name() ); @@ -8861,7 +9120,7 @@ dealt_damage_instance Character::deal_damage( Creature *source, bodypart_id bp, int sum_cover = 0; for( const item &i : worn ) { if( i.covers( bp ) && i.is_filthy() ) { - sum_cover += i.get_coverage(); + sum_cover += i.get_coverage( bp ); } } @@ -8955,8 +9214,7 @@ void Character::hurtall( int dam, Creature *source, bool disturb /*= true*/ ) int Character::hitall( int dam, int vary, Creature *source ) { int damage_taken = 0; - for( int i = 0; i < num_hp_parts; i++ ) { - const bodypart_id bp = convert_bp( hp_to_bp( static_cast( i ) ) ).id(); + for( const bodypart_id &bp : get_all_body_parts( true ) ) { int ddam = vary ? dam * rng( 100 - vary, 100 ) / 100 : dam; int cut = 0; auto damage = damage_instance::physical( ddam, cut, 0 ); @@ -9079,8 +9337,8 @@ void Character::blossoms() void Character::update_vitamins( const vitamin_id &vit ) { - if( is_npc() ) { - return; // NPCs cannot develop vitamin diseases + if( is_npc() && vit->type() != vitamin_type::COUNTER ) { + return; // NPCs cannot develop vitamin diseases, bypass for special } efftype_id def = vit.obj().deficiency(); @@ -9195,7 +9453,7 @@ int Character::head_cloth_encumbrance() const const item *worn_item = &i; if( i.covers( bodypart_id( "head" ) ) && !i.has_flag( flag_SEMITANGIBLE ) && ( worn_item->has_flag( flag_HELMET_COMPAT ) || worn_item->has_flag( flag_SKINTIGHT ) ) ) { - ret += worn_item->get_encumber( *this ); + ret += worn_item->get_encumber( *this, bodypart_id( "head" ) ); } } return ret; @@ -9312,6 +9570,38 @@ units::volume Character::volume_capacity() const return volume_capacity; } +units::volume Character::volume_capacity_with_tweaks( const + std::vector> + &locations ) const +{ + std::map dropping; + for( const std::pair &location_pair : locations ) { + dropping.emplace( location_pair.first.get_item(), location_pair.second ); + } + return volume_capacity_with_tweaks( { dropping } ); +} + +units::volume Character::volume_capacity_with_tweaks( const item_tweaks &tweaks ) const +{ + const std::map empty; + const std::map &without = tweaks.without_items ? tweaks.without_items->get() : + empty; + + units::volume volume_capacity = 0_ml; + + if( !without.count( &weapon ) ) { + volume_capacity += weapon.contents.total_container_capacity(); + } + + for( auto &i : worn ) { + if( !without.count( &i ) ) { + volume_capacity += i.contents.total_container_capacity(); + } + } + + return volume_capacity; +} + units::volume Character::volume_carried() const { return volume_capacity() - free_space(); @@ -9723,12 +10013,12 @@ int Character::bonus_item_warmth( const bodypart_id &bp ) const } // If the player's head is not encumbered, check if hood can be put up - if( bp == bodypart_id( "head" ) && encumb( bp_head ) < 10 ) { + if( bp == bodypart_id( "head" ) && encumb( bodypart_id( "head" ) ) < 10 ) { ret += bestwarmth( worn, "HOOD" ); } // If the player's mouth is not encumbered, check if collar can be put up - if( bp == bodypart_id( "mouth" ) && encumb( bp_mouth ) < 10 ) { + if( bp == bodypart_id( "mouth" ) && encumb( bodypart_id( "mouth" ) ) < 10 ) { ret += bestwarmth( worn, "COLLAR" ); } @@ -10462,8 +10752,8 @@ int Character::run_cost( int base_cost, bool diag ) const } movecost += - ( ( encumb( bp_foot_l ) + encumb( bp_foot_r ) ) * 2.5 + - ( encumb( bp_leg_l ) + encumb( bp_leg_r ) ) * 1.5 ) / 10; + ( ( encumb( bodypart_id( "foot_l" ) ) + encumb( bodypart_id( "foot_r" ) ) ) * 2.5 + + ( encumb( bodypart_id( "leg_l" ) ) + encumb( bodypart_id( "leg_r" ) ) ) * 1.5 ) / 10; // ROOTS3 does slow you down as your roots are probing around for nutrients, // whether you want them to or not. ROOTS1 is just too squiggly without shoes @@ -10666,7 +10956,7 @@ bool Character::can_hear( const tripoint &source, const int volume ) const } const int dist = rl_dist( source, pos() ); const float volume_multiplier = hearing_ability(); - return ( volume - weather::sound_attn( g->weather.weather ) ) * volume_multiplier >= dist; + return ( volume - get_weather().weather_id->sound_attn ) * volume_multiplier >= dist; } float Character::hearing_ability() const @@ -10797,6 +11087,11 @@ Creature::Attitude Character::attitude_to( const Creature &other ) const return Attitude::NEUTRAL; } +npc_attitude Character::get_attitude() const +{ + return NPCATT_NULL; +} + bool Character::sees( const tripoint &t, bool, int ) const { const int wanted_range = rl_dist( pos(), t ); @@ -10960,10 +11255,25 @@ int Character::intimidation() const if( has_effect( effect_drunk ) ) { ret -= 4; } - + ret = enchantment_cache.modify_value( enchant_vals::mod::SOCIAL_INTIMIDATE, ret ); return ret; } +bool Character::has_proficiency( const proficiency_id &prof ) const +{ + return _proficiencies.count( prof ); +} + +void Character::add_proficiency( const proficiency_id &prof ) +{ + _proficiencies.insert( prof ); +} + +const std::set &Character::proficiencies() const +{ + return _proficiencies; +} + bool Character::defer_move( const tripoint &next ) { // next must be adjacent to current pos diff --git a/src/character.h b/src/character.h index 39bef0767288f..9c7a81ccbab6a 100644 --- a/src/character.h +++ b/src/character.h @@ -55,6 +55,7 @@ class JsonObject; class JsonOut; class SkillLevel; class SkillLevelMap; +class basecamp; class bionic_collection; class faction; class player; @@ -65,11 +66,15 @@ struct construction; struct dealt_projectile_attack; struct islot_comestible; struct itype; +class recipe_subset; struct mutation_branch; struct needs_rates; struct pathfinding_settings; struct points_left; template struct enum_traits; +enum npc_attitude : int; + +static const std::string DEFAULT_HOTKEYS( "1234567890abcdefghijklmnopqrstuvwxyz" ); using drop_location = std::pair; using drop_locations = std::list; @@ -226,46 +231,6 @@ enum class rechargeable_cbm : int { other }; -struct layer_details { - - std::vector pieces; - int max = 0; - int total = 0; - - void reset(); - int layer( int encumbrance ); - - bool operator ==( const layer_details &rhs ) const { - return max == rhs.max && - total == rhs.total && - pieces == rhs.pieces; - } -}; - -struct encumbrance_data { - int encumbrance = 0; - int armor_encumbrance = 0; - int layer_penalty = 0; - - std::array( layer_level::NUM_LAYER_LEVELS )> - layer_penalty_details; - - void layer( const layer_level level, const int encumbrance ) { - layer_penalty += layer_penalty_details[static_cast( level )].layer( encumbrance ); - } - - void reset() { - *this = encumbrance_data(); - } - - bool operator ==( const encumbrance_data &rhs ) const { - return encumbrance == rhs.encumbrance && - armor_encumbrance == rhs.armor_encumbrance && - layer_penalty == rhs.layer_penalty && - layer_penalty_details == rhs.layer_penalty_details; - } -}; - struct aim_type { std::string name; std::string action; @@ -345,6 +310,8 @@ class Character : public Creature, public visitable bool in_species( const species_id &spec ) const override; // Turned to false for simulating NPCs on distant missions so they don't drop all their gear in sight bool death_drops; + // Is currently in control of a vehicle + bool controlling_vehicle = false; enum class comfort_level : int { impossible = -999, @@ -583,19 +550,11 @@ class Character : public Creature, public visitable /** Handles stat and bonus reset. */ void reset() override; - /** Recalculates encumbrance cache. */ - void reset_encumbrance(); /** Returns ENC provided by armor, etc. */ - int encumb( body_part bp ) const; + int encumb( const bodypart_id &bp ) const; /** Returns body weight plus weight of inventory and worn/wielded items */ units::mass get_weight() const override; - /** Get encumbrance for all body parts. */ - std::array get_encumbrance() const; - /** Get encumbrance for all body parts as if `new_item` was also worn. */ - std::array get_encumbrance( const item &new_item ) const; - /** Get encumbrance penalty per layer & body part */ - int extraEncumbrance( layer_level level, int bp ) const; /** Returns true if the character is wearing power armor */ bool is_wearing_power_armor( bool *hasHelmet = nullptr ) const; @@ -667,6 +626,7 @@ class Character : public Creature, public visitable /** Recalculates HP after a change to max strength */ void recalc_hp(); + int get_part_hp_max( const bodypart_id &id ) const; /** Modifies the player's sight values * Must be called when any of the following change: * This must be called when any of the following change: @@ -777,6 +737,22 @@ class Character : public Creature, public visitable std::vector &targets ); public: + /** This handles giving xp for a skill */ + void practice( const skill_id &id, int amount, int cap = 99, bool suppress_warning = false ); + /** This handles warning the player that there current activity will not give them xp */ + void handle_skill_warning( const skill_id &id, bool force_warning = false ); + + /** + * Check player capable of wielding an item. + * @param it Thing to be wielded + */ + ret_val can_wield( const item &it ) const; + + bool unwield(); + + /** Get the formatted name of the currently wielded item (if any) with current gun mode (if gun) */ + std::string weapname() const; + // any side effects that might happen when the Character is hit void on_hit( Creature *source, bodypart_id /*bp_hit*/, float /*difficulty*/, dealt_projectile_attack const * /*proj*/ ) override; @@ -806,7 +782,7 @@ class Character : public Creature, public visitable * Reduces and mutates du, prints messages about armor taking damage. * @return true if the armor was completely destroyed (and the item must be deleted). */ - bool armor_absorb( damage_unit &du, item &armor ); + bool armor_absorb( damage_unit &du, item &armor, const bodypart_id &bp ); /** * Check for passive bionics that provide armor, and returns the armor bonus * This is called from player::passive_absorb_hit @@ -850,11 +826,6 @@ class Character : public Creature, public visitable void activate_mutation( const trait_id &mutation ); void deactivate_mutation( const trait_id &mut ); - /** Converts a body_part to an hp_part */ - static hp_part bp_to_hp( body_part bp ); - /** Converts an hp_part to a body_part */ - static body_part hp_to_bp( hp_part hpart ); - bool can_mount( const monster &critter ) const; void mount_creature( monster &z ); bool is_mounted() const; @@ -884,7 +855,7 @@ class Character : public Creature, public visitable void on_hurt( Creature *source, bool disturb = true ); /** Heals a body_part for dam */ void heal_bp( bodypart_id bp, int dam ) override; - /** Heals an hp_part for dam */ + /** Heals an part for dam */ void heal( const bodypart_id &healed, int dam ); /** Heals all body parts for dam */ void healall( int dam ); @@ -907,10 +878,10 @@ class Character : public Creature, public visitable * bandage_power - quality of bandage * disinfectant_power - quality of disinfectant */ - hp_part body_window( const std::string &menu_header, - bool show_all, bool precise, - int normal_bonus, int head_bonus, int torso_bonus, - float bleed, float bite, float infect, float bandage_power, float disinfectant_power ) const; + bodypart_id body_window( const std::string &menu_header, + bool show_all, bool precise, + int normal_bonus, int head_bonus, int torso_bonus, + int bleed, float bite, float infect, float bandage_power, float disinfectant_power ) const; // Returns color which this limb would have in healing menus nc_color limb_color( const bodypart_id &bp, bool bleed, bool bite, bool infect ) const; @@ -978,13 +949,8 @@ class Character : public Creature, public visitable /** Applies stat mods to character. */ void apply_mods( const trait_id &mut, bool add_remove ); - /** Recalculate encumbrance for all body parts. */ - std::array calc_encumbrance() const; - /** Recalculate encumbrance for all body parts as if `new_item` was also worn. */ - std::array calc_encumbrance( const item &new_item ) const; - /** Applies encumbrance from mutations and bionics only */ - void mut_cbm_encumb( std::array &vals ) const; + void mut_cbm_encumb( std::map &vals ) const; /** Return the position in the worn list where new_item would be * put by default */ @@ -993,12 +959,16 @@ class Character : public Creature, public visitable /** Applies encumbrance from items only * If new_item is not null, then calculate under the asumption that it * is added to existing work items. */ - void item_encumb( std::array &vals, - const item &new_item ) const; + void item_encumb( std::map &vals, const item &new_item ) const; std::array, num_bp> mut_drench; public: + /** Recalculate encumbrance for all body parts. */ + void calc_encumbrance(); + /** Recalculate encumbrance for all body parts as if `new_item` was also worn. */ + void calc_encumbrance( const item &new_item ); + // recalculates enchantment cache by iterating through all held, worn, and wielded items void recalculate_enchantment_cache(); // gets add and mult value from enchantment cache @@ -1123,6 +1093,12 @@ class Character : public Creature, public visitable /** Handles bionic effects over time of the entered bionic */ void process_bionic( int b ); + /** finds the index of the bionic that corresponds to the currently wielded fake item + * i.e. bionic is `BIONIC_WEAPON` and weapon.typeId() == bio.info().fake_item */ + cata::optional active_bionic_weapon_index() const; + /** Checks if bionic can be deactivated (e.g. it's not incapacitaded and power level is sufficient) + * returns either success or failure with log message */ + ret_val can_deactivate_bionic( int b, bool eff_only = false ) const; /** Handles bionic deactivation effects of the entered bionic, returns if anything * deactivated */ bool deactivate_bionic( int b, bool eff_only = false ); @@ -1319,7 +1295,7 @@ class Character : public Creature, public visitable // returns a list of all item_location the character has, including items contained in other items. // only for CONTAINER pocket type; does not look for magazines std::vector all_items_loc(); - // Returns list of all the top level item_lodation the character has. Includes worn and held items. + // Returns list of all the top level item_lodation the character has. Includes worn items but excludes items held on hand. std::vector top_items_loc(); /** Return the item pointer of the item with given invlet, return nullptr if * the player does not have such an item with that invlet. Don't use this on npcs. @@ -1369,14 +1345,6 @@ class Character : public Creature, public visitable bool pour_into( vehicle &veh, item &liquid ); /**@}*/ - /** - * Remove a specific item from player possession. The item is compared - * by pointer. Contents of the item are removed as well. - * @param pos The item position of the item to be removed. The item *must* - * exists, use @ref has_item to check this. - * @return A copy of the removed item. - */ - item i_rem( int pos ); /** * Remove a specific item from player possession. The item is compared * by pointer. Contents of the item are removed as well. @@ -1385,7 +1353,7 @@ class Character : public Creature, public visitable * @return A copy of the removed item. */ item i_rem( const item *it ); - void i_rem_keep_contents( int idx ); + void i_rem_keep_contents( const item *it ); /** Sets invlet and adds to inventory if possible, drops otherwise, returns true if either succeeded. * An optional qty can be provided (and will perform better than separate calls). */ bool i_add_or_drop( item &it, int qty = 1 ); @@ -1479,14 +1447,24 @@ class Character : public Creature, public visitable units::mass weight_carried_with_tweaks( const item_tweaks &tweaks ) const; units::mass weight_carried_with_tweaks( const std::vector> &locations ) const; + units::mass get_selected_stack_weight( const item *i, + const std::map &without ) const; units::volume volume_carried_with_tweaks( const item_tweaks &tweaks ) const; units::volume volume_carried_with_tweaks( const std::vector> - &locations ) - const; + &locations ) const; + units::volume get_selected_stack_volume( const item *i, + const std::map &without ) const; units::mass weight_capacity() const override; units::volume volume_capacity() const; + units::volume volume_capacity_with_tweaks( const item_tweaks &tweaks ) const; + units::volume volume_capacity_with_tweaks( const std::vector> + &locations ) const; units::volume free_space() const; + + /** Note that we've read a book at least once. **/ + virtual bool has_identified( const itype_id &item_id ) const = 0; + bool can_pickVolume( const item &it, bool safe = false ) const; bool can_pickWeight( const item &it, bool safe = true ) const; /** @@ -1588,6 +1566,12 @@ class Character : public Creature, public visitable /** Returns a value used when attempting to intimidate NPC's */ int intimidation() const; + // --------------- Proficiency Stuff ---------------- + // (bit short at the moment) + bool has_proficiency( const proficiency_id &prof ) const; + void add_proficiency( const proficiency_id &prof ); + const std::set &proficiencies() const; + // --------------- Other Stuff --------------- /** return the calendar::turn the character expired */ @@ -1702,7 +1686,6 @@ class Character : public Creature, public visitable bool male = false; std::list worn; - std::array damage_bandaged, damage_disinfected; bool nv_cached = false; // Means player sit inside vehicle on the tile he is now bool in_vehicle = false; @@ -1828,6 +1811,10 @@ class Character : public Creature, public visitable float get_bmi() const; // returns amount of calories burned in a day given various metabolic factors int get_bmr() const; + // add spent calories to calorie diary (if avatar) + virtual void add_spent_calories( int /* cal */ ) {}; + // add gained calories to calorie diary (if avatar) + virtual void add_gained_calories( int /* gained */ ) {}; // Reset age and height to defaults for consistent test results void reset_chargen_attributes(); // age in years, determined at character creation @@ -1924,11 +1911,6 @@ class Character : public Creature, public visitable void shout( std::string msg = "", bool order = false ); /** Handles Character vomiting effects */ void vomit(); - // adds total healing to the bodypart. this is only a counter. - void healed_bp( int bp, int amount ); - - // the amount healed per bodypart per day - std::array healed_total; std::map mutation_category_level; @@ -2092,8 +2074,8 @@ class Character : public Creature, public visitable /** Used to apply stimulation modifications from food and medication **/ void modify_stimulation( const islot_comestible &comest ); /** Used to apply fatigue modifications from food and medication **/ - void modify_fatigue( const islot_comestible &comest ); /** Used to apply radiation from food and medication **/ + void modify_fatigue( const islot_comestible &comest ); void modify_radiation( const islot_comestible &comest ); /** Used to apply addiction modifications from food and medication **/ void modify_addiction( const islot_comestible &comest ); @@ -2180,6 +2162,163 @@ class Character : public Creature, public visitable int radius = PICKUP_RANGE, bool clear_path = true ); void invalidate_crafting_inventory(); + + /** Returns a value from 1.0 to 5.0 that acts as a multiplier + * for the time taken to perform tasks that require detail vision, + * above 4.0 means these activities cannot be performed. + * takes pos as a parameter so that remote spots can be judged + * if they will potentially have enough light when player gets there */ + float fine_detail_vision_mod( const tripoint &p = tripoint_zero ) const; + + // ---- CRAFTING ---- + void make_craft_with_command( const recipe_id &id_to_make, int batch_size, bool is_long = false, + const tripoint &loc = tripoint_zero ); + pimpl last_craft; + + recipe_id lastrecipe; + int last_batch; + itype_id lastconsumed; //used in crafting.cpp and construction.cpp + + // Checks crafting inventory for books providing the requested recipe. + // Then checks nearby NPCs who could provide it too. + // Returns -1 to indicate recipe not found, otherwise difficulty to learn. + int has_recipe( const recipe *r, const inventory &crafting_inv, + const std::vector &helpers ) const; + bool knows_recipe( const recipe *rec ) const; + void learn_recipe( const recipe *rec ); + int exceeds_recipe_requirements( const recipe &rec ) const; + bool has_recipe_requirements( const recipe &rec ) const; + bool can_decomp_learn( const recipe &rec ) const; + + bool studied_all_recipes( const itype &book ) const; + + /** Returns all known recipes. */ + const recipe_subset &get_learned_recipes() const; + /** Returns all recipes that are known from the books (either in inventory or nearby). */ + recipe_subset get_recipes_from_books( const inventory &crafting_inv ) const; + /** + * Returns all available recipes (from books and npc companions) + * @param crafting_inv Current available items to craft + * @param helpers List of NPCs that could help with crafting. + */ + recipe_subset get_available_recipes( const inventory &crafting_inv, + const std::vector *helpers = nullptr ) const; + /** + * Returns the set of book types in crafting_inv that provide the + * given recipe. + * @param crafting_inv Current available items that may contain readable books + * @param r Recipe to search for in the available books + */ + std::set get_books_for_recipe( const inventory &crafting_inv, + const recipe *r ) const; + + // crafting.cpp + float morale_crafting_speed_multiplier( const recipe &rec ) const; + float lighting_craft_speed_multiplier( const recipe &rec ) const; + float crafting_speed_multiplier( const recipe &rec, bool in_progress = false ) const; + /** For use with in progress crafts */ + float crafting_speed_multiplier( const item &craft, const tripoint &loc ) const; + int available_assistant_count( const recipe &rec ) const; + /** + * Time to craft not including speed multiplier + */ + int base_time_to_craft( const recipe &rec, int batch_size = 1 ) const; + /** + * Expected time to craft a recipe, with assumption that multipliers stay constant. + */ + int expected_time_to_craft( const recipe &rec, int batch_size = 1, bool in_progress = false ) const; + std::vector get_eligible_containers_for_crafting() const; + bool check_eligible_containers_for_crafting( const recipe &rec, int batch_size = 1 ) const; + bool can_make( const recipe *r, int batch_size = 1 ); // have components? + /** + * Returns true if the player can start crafting the recipe with the given batch size + * The player is not required to have enough tool charges to finish crafting, only to + * complete the first step (total / 20 + total % 20 charges) + */ + bool can_start_craft( const recipe *rec, recipe_filter_flags, int batch_size = 1 ); + bool making_would_work( const recipe_id &id_to_make, int batch_size ); + + /** + * Start various types of crafts + * @param loc the location of the workbench. tripoint_zero indicates crafting from inventory. + */ + void craft( const tripoint &loc = tripoint_zero ); + void recraft( const tripoint &loc = tripoint_zero ); + void long_craft( const tripoint &loc = tripoint_zero ); + void make_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); + void make_all_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); + /** consume components and create an active, in progress craft containing them */ + void start_craft( craft_command &command, const tripoint &loc ); + /** + * Calculate a value representing the success of the player at crafting the given recipe, + * taking player skill, recipe difficulty, npc helpers, and player mutations into account. + * @param making the recipe for which to calculate + * @return a value >= 0.0 with >= 1.0 representing unequivocal success + */ + double crafting_success_roll( const recipe &making ) const; + void complete_craft( item &craft, const tripoint &loc = tripoint_zero ); + /** + * Check if the player meets the requirements to continue the in progress craft and if + * unable to continue print messages explaining the reason. + * If the craft is missing components due to messing up, prompt to consume new ones to + * allow the craft to be continued. + * @param craft the currently in progress craft + * @return if the craft can be continued + */ + bool can_continue_craft( item &craft ); + /** Returns nearby NPCs ready and willing to help with crafting. */ + std::vector get_crafting_helpers() const; + int get_num_crafting_helpers( int max ) const; + /** + * Handle skill gain for player and followers during crafting + * @param craft the currently in progress craft + * @param multiplier what factor to multiply the base skill gain by. This is used to apply + * multiple steps of incremental skill gain simultaneously if needed. + */ + void craft_skill_gain( const item &craft, const int &multiplier ); + /** + * Check if the player can disassemble an item using the current crafting inventory + * @param obj Object to check for disassembly + * @param inv current crafting inventory + */ + ret_val can_disassemble( const item &obj, const inventory &inv ) const; + + bool disassemble(); + bool disassemble( item_location target, bool interactive = true ); + void disassemble_all( bool one_pass ); // Disassemble all items on the tile + void complete_disassemble(); + void complete_disassemble( item_location &target, const recipe &dis ); + + const requirement_data *select_requirements( + const std::vector &, int batch, const inventory &, + const std::function &filter ) const; + comp_selection + select_item_component( const std::vector &components, + int batch, inventory &map_inv, bool can_cancel = false, + const std::function &filter = return_true, bool player_inv = true ); + std::list consume_items( const comp_selection &is, int batch, + const std::function &filter = return_true ); + std::list consume_items( map &m, const comp_selection &is, int batch, + const std::function &filter = return_true, + const tripoint &origin = tripoint_zero, int radius = PICKUP_RANGE ); + std::list consume_items( const std::vector &components, int batch = 1, + const std::function &filter = return_true ); + comp_selection + select_tool_component( const std::vector &tools, int batch, inventory &map_inv, + const std::string &hotkeys = DEFAULT_HOTKEYS, + bool can_cancel = false, bool player_inv = true, + std::function charges_required_modifier = []( int i ) { + return i; + } ); + /** Consume tools for the next multiplier * 5% progress of the craft */ + bool craft_consume_tools( item &craft, int mulitplier, bool start_craft ); + void consume_tools( const comp_selection &tool, int batch ); + void consume_tools( map &m, const comp_selection &tool, int batch, + const tripoint &origin = tripoint_zero, int radius = PICKUP_RANGE, + basecamp *bcp = nullptr ); + void consume_tools( const std::vector &tools, int batch = 1, + const std::string &hotkeys = DEFAULT_HOTKEYS ); + /** Checks permanent morale for consistency and recovers it when an inconsistency is found. */ void check_and_recover_morale(); @@ -2209,6 +2348,8 @@ class Character : public Creature, public visitable float hearing_ability() const; using trap_map = std::map; + // Use @ref trap::can_see to check whether a character knows about a + // specific trap - it will consider visibile and known traps. bool knows_trap( const tripoint &pos ) const; void add_known_trap( const tripoint &pos, const trap &t ); /** Define color for displaying the body temperature */ @@ -2219,6 +2360,7 @@ class Character : public Creature, public visitable // see Creature::sees bool sees( const Creature &critter ) const override; Attitude attitude_to( const Creature &other ) const override; + virtual npc_attitude get_attitude() const; // used in debugging all health int get_lowest_hp() const; @@ -2288,8 +2430,6 @@ class Character : public Creature, public visitable trap_map known_traps; mutable std::map cached_info; - mutable std::array encumbrance_cache; - mutable bool encumbrance_cache_dirty = true; bool bio_soporific_powered_at_last_sleep_check = false; /** last time we checked for sleep */ time_point last_sleep_check = calendar::turn_zero; @@ -2317,6 +2457,8 @@ class Character : public Creature, public visitable // --------------- Values --------------- pimpl _skills; + std::set _proficiencies; + // Cached vision values. std::bitset vision_mode_cache; int sight_max = 0; @@ -2365,6 +2507,7 @@ class Character : public Creature, public visitable void suffer_from_artifacts(); void suffer_from_stimulants( int current_stim ); void suffer_without_sleep( int sleep_deprivation ); + void suffer_from_tourniquet(); /** * Check whether the other creature is in range and can be seen by this creature. * @param critter Creature to check for visibility @@ -2412,6 +2555,12 @@ class Character : public Creature, public visitable inventory cached_crafting_inventory; protected: + /** Subset of learned recipes. Needs to be mutable for lazy initialization. */ + mutable pimpl learned_recipes; + + /** Stamp of skills. @ref learned_recipes are valid only with this set of skills. */ + mutable decltype( _skills ) valid_autolearn_skills; + /** Amount of time the player has spent in each overmap tile. */ std::unordered_map overmap_time; diff --git a/src/character_crafting.cpp b/src/character_crafting.cpp new file mode 100644 index 0000000000000..6535bfa108f33 --- /dev/null +++ b/src/character_crafting.cpp @@ -0,0 +1,143 @@ +#include "character.h" + +#include "itype.h" +#include "recipe_dictionary.h" +#include "recipe.h" +#include "skill.h" +#include "player.h" +#include "npc.h" + +int Character::has_recipe( const recipe *r, const inventory &crafting_inv, + const std::vector &helpers ) const +{ + if( !r->skill_used ) { + return 0; + } + + if( knows_recipe( r ) ) { + return r->difficulty; + } + + const auto available = get_available_recipes( crafting_inv, &helpers ); + return available.contains( r ) ? available.get_custom_difficulty( r ) : -1; +} + +bool Character::knows_recipe( const recipe *rec ) const +{ + return get_learned_recipes().contains( rec ); +} + +void Character::learn_recipe( const recipe *const rec ) +{ + if( rec->never_learn ) { + return; + } + learned_recipes->include( rec ); +} + +int Character::exceeds_recipe_requirements( const recipe &rec ) const +{ + return get_all_skills().exceeds_recipe_requirements( rec ); +} + +bool Character::has_recipe_requirements( const recipe &rec ) const +{ + return get_all_skills().has_recipe_requirements( rec ); +} + +bool Character::can_decomp_learn( const recipe &rec ) const +{ + return !rec.learn_by_disassembly.empty() && + meets_skill_requirements( rec.learn_by_disassembly ); +} + +bool Character::studied_all_recipes( const itype &book ) const +{ + if( !book.book ) { + return true; + } + for( auto &elem : book.book->recipes ) { + if( !knows_recipe( elem.recipe ) ) { + return false; + } + } + return true; +} +const recipe_subset &Character::get_learned_recipes() const +{ + // Cache validity check + if( *_skills != *valid_autolearn_skills ) { + for( const auto &r : recipe_dict.all_autolearn() ) { + if( meets_skill_requirements( r->autolearn_requirements ) ) { + learned_recipes->include( r ); + } + } + *valid_autolearn_skills = *_skills; // Reassign the validity stamp + } + + return *learned_recipes; +} + +recipe_subset Character::get_recipes_from_books( const inventory &crafting_inv ) const +{ + recipe_subset res; + + for( const auto &stack : crafting_inv.const_slice() ) { + const item &candidate = stack->front(); + + for( std::pair recipe_entry : + candidate.get_available_recipes( *this ) ) { + res.include( recipe_entry.first, recipe_entry.second ); + } + } + + return res; +} + +recipe_subset Character::get_available_recipes( const inventory &crafting_inv, + const std::vector *helpers ) const +{ + recipe_subset res( get_learned_recipes() ); + + res.include( get_recipes_from_books( crafting_inv ) ); + + if( helpers != nullptr ) { + for( npc *np : *helpers ) { + // Directly form the helper's inventory + res.include( get_recipes_from_books( np->inv ) ); + // Being told what to do + res.include_if( np->get_learned_recipes(), [ this ]( const recipe & r ) { + return get_skill_level( r.skill_used ) >= static_cast( r.difficulty * + 0.8f ); // Skilled enough to understand + } ); + } + } + + return res; +} + +std::set Character::get_books_for_recipe( const inventory &crafting_inv, + const recipe *r ) const +{ + std::set book_ids; + const int skill_level = get_skill_level( r->skill_used ); + for( auto &book_lvl : r->booksets ) { + itype_id book_id = book_lvl.first; + int required_skill_level = book_lvl.second; + // NPCs don't need to identify books + if( !has_identified( book_id ) ) { + continue; + } + + if( skill_level >= required_skill_level && crafting_inv.amount_of( book_id ) > 0 ) { + book_ids.insert( book_id ); + } + } + return book_ids; +} + +int Character::get_num_crafting_helpers( int max ) const +{ + std::vector helpers = get_crafting_helpers(); + return std::min( max, static_cast( helpers.size() ) ); +} diff --git a/src/clothing_mod.cpp b/src/clothing_mod.cpp index 98a57dba61f29..c4b06b23977a3 100644 --- a/src/clothing_mod.cpp +++ b/src/clothing_mod.cpp @@ -94,7 +94,7 @@ void clothing_mod::load( const JsonObject &jo, const std::string & ) float clothing_mod::get_mod_val( const clothing_mod_type &type, const item &it ) const { const int thickness = it.get_thickness(); - const int coverage = it.get_coverage(); + const int coverage = it.get_avg_coverage(); float result = 0.0f; for( const mod_value &mv : mod_values ) { if( mv.type == type ) { diff --git a/src/clzones.cpp b/src/clzones.cpp index 90f102b9b9758..620bfad839580 100644 --- a/src/clzones.cpp +++ b/src/clzones.cpp @@ -248,15 +248,15 @@ loot_options::query_loot_result loot_options::query_loot() plot_options::query_seed_result plot_options::query_seed() { - player &p = g->u; + Character &player_character = get_player_character(); - std::vector seed_inv = p.items_with( []( const item & itm ) { + std::vector seed_inv = player_character.items_with( []( const item & itm ) { return itm.is_seed(); } ); auto &mgr = zone_manager::get_manager(); map &here = get_map(); const std::unordered_set &zone_src_set = mgr.get_near( zone_type_id( "LOOT_SEEDS" ), - here.getabs( p.pos() ), 60 ); + here.getabs( player_character.pos() ), 60 ); for( const tripoint &elem : zone_src_set ) { tripoint elem_loc = here.getlocal( elem ); for( item &it : here.i_at( elem_loc ) ) { @@ -573,7 +573,8 @@ void zone_manager::cache_data() auto &cache = area_cache[type_hash]; // Draw marked area - for( const tripoint &p : tripoint_range( elem.get_start_point(), elem.get_end_point() ) ) { + for( const tripoint &p : tripoint_range( elem.get_start_point(), + elem.get_end_point() ) ) { cache.insert( p ); } } @@ -594,7 +595,8 @@ void zone_manager::cache_vzones() // TODO: looks very similar to the above cache_data - maybe merge it? // Draw marked area - for( const tripoint &p : tripoint_range( elem->get_start_point(), elem->get_end_point() ) ) { + for( const tripoint &p : tripoint_range( elem->get_start_point(), + elem->get_end_point() ) ) { cache.insert( p ); } } @@ -805,7 +807,7 @@ cata::optional zone_manager::get_nearest( const zone_type_id &type, co zone_type_id zone_manager::get_near_zone_type_for_item( const item &it, const tripoint &where, int range ) const { - const item_category &cat = it.get_category(); + const item_category &cat = it.get_category_of_contents(); if( has_near( zone_type_id( "LOOT_CUSTOM" ), where, range ) ) { if( !get_near( zone_type_id( "LOOT_CUSTOM" ), where, range, &it ).empty() ) { diff --git a/src/computer_session.cpp b/src/computer_session.cpp index 6af7043ee2527..1b47e817320ab 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -109,6 +109,7 @@ void computer_session::use() refresh(); } ); + avatar &player_character = get_avatar(); // Login print_line( _( "Logging into %s…" ), comp.name ); if( comp.security > 0 ) { @@ -130,7 +131,7 @@ void computer_session::use() return; case ynq::yes: - if( !hack_attempt( g->u ) ) { + if( !hack_attempt( player_character ) ) { if( comp.failures.empty() ) { query_any( _( "Maximum login attempts exceeded. Press any key…" ) ); reset_terminal(); @@ -161,7 +162,12 @@ void computer_session::use() computer_menu.fselected = sel; for( size_t i = 0; i < options_size; i++ ) { - computer_menu.addentry( i, true, MENU_AUTOASSIGN, comp.options[i].name ); + bool activatable = can_activate( comp.options[i].action ); + std::string action_name = comp.options[i].name; + if( !activatable ) { + action_name = string_format( _( "%s (UNAVAILABLE)" ), action_name ); + } + computer_menu.addentry( i, activatable, MENU_AUTOASSIGN, action_name ); } ui_manager::redraw(); @@ -177,7 +183,7 @@ void computer_session::use() if( current.security + comp.alerts > 0 ) { print_error( _( "Password required." ) ); if( query_bool( _( "Hack into system?" ) ) ) { - if( !hack_attempt( g->u, current.security ) ) { + if( !hack_attempt( player_character, current.security ) ) { activate_random_failure(); reset_terminal(); return; @@ -233,7 +239,8 @@ static item *pick_usb() return it.typeId() == itype_usb_drive; }; - item_location loc = game_menus::inv::titled_filter_menu( filter, g->u, _( "Choose drive:" ) ); + item_location loc = game_menus::inv::titled_filter_menu( filter, get_avatar(), + _( "Choose drive:" ) ); if( loc ) { return &*loc; } @@ -242,12 +249,14 @@ static item *pick_usb() static void remove_submap_turrets() { + Character &player_character = get_player_character(); map &here = get_map(); for( monster &critter : g->all_monsters() ) { // Check 1) same overmap coords, 2) turret, 3) hostile - if( ms_to_omt_copy( here.getabs( critter.pos() ) ) == ms_to_omt_copy( here.getabs( g->u.pos() ) ) && + if( ms_to_omt_copy( here.getabs( critter.pos() ) ) == ms_to_omt_copy( here.getabs( + player_character.pos() ) ) && critter.has_flag( MF_CONSOLE_DESPAWN ) && - critter.attitude_to( g->u ) == Creature::Attitude::HOSTILE ) { + critter.attitude_to( player_character ) == Creature::Attitude::HOSTILE ) { g->remove_zombie( critter ); } } @@ -305,12 +314,57 @@ computer_session::computer_action_functions = { { COMPACT_UNLOCK_DISARM, &computer_session::action_unlock_disarm }, }; +bool computer_session::can_activate( computer_action action ) +{ + switch( action ) { + case COMPACT_LOCK: + return get_map().has_nearby_ter( get_player_character().pos(), t_door_metal_c, 8 ); + break; + + case COMPACT_RELEASE: + case COMPACT_RELEASE_DISARM: + return get_map().has_nearby_ter( get_player_character().pos(), t_reinforced_glass, 25 ); + break; + + case COMPACT_RELEASE_BIONICS: + return get_map().has_nearby_ter( get_player_character().pos(), t_reinforced_glass, 3 ); + break; + + case COMPACT_TERMINATE: { + map &here = get_map(); + for( const tripoint &p : here.points_on_zlevel() ) { + monster *const mon = g->critter_at( p ); + if( !mon ) { + continue; + } + if( ( here.ter( p + tripoint_north ) == t_reinforced_glass && + here.ter( p + tripoint_south ) == t_concrete_wall ) || + ( here.ter( p + tripoint_south ) == t_reinforced_glass && + here.ter( p + tripoint_north ) == t_concrete_wall ) ) { + return true; + } + } + return false; + break; + } + + case COMPACT_UNLOCK: + case COMPACT_UNLOCK_DISARM: + return get_map().has_nearby_ter( get_player_character().pos(), t_door_metal_locked, 8 ); + break; + + default: + return true; + break; + } +} + void computer_session::activate_function( computer_action action ) { const auto it = computer_action_functions.find( action ); if( it != computer_action_functions.end() ) { // Token move cost for any action, if an action takes longer decrement moves further. - g->u.moves -= 30; + get_player_character().moves -= 30; ( this->*( it->second ) )(); } } @@ -323,7 +377,8 @@ void computer_session::action_open_disarm() void computer_session::action_open() { - get_map().translate_radius( t_door_metal_locked, t_floor, 25.0, g->u.pos(), true ); + get_map().translate_radius( t_door_metal_locked, t_floor, 25.0, get_player_character().pos(), + true ); query_any( _( "Doors opened. Press any key…" ) ); } @@ -334,7 +389,8 @@ void computer_session::action_open() // player position to determine which terrain tiles to edit. void computer_session::action_lock() { - get_map().translate_radius( t_door_metal_c, t_door_metal_locked, 8.0, g->u.pos(), true ); + get_map().translate_radius( t_door_metal_c, t_door_metal_locked, 8.0, get_player_character().pos(), + true ); query_any( _( "Lock enabled. Press any key…" ) ); } @@ -346,21 +402,22 @@ void computer_session::action_unlock_disarm() void computer_session::action_unlock() { - get_map().translate_radius( t_door_metal_locked, t_door_metal_c, 8.0, g->u.pos(), true ); + get_map().translate_radius( t_door_metal_locked, t_door_metal_c, 8.0, get_player_character().pos(), + true ); query_any( _( "Lock disabled. Press any key…" ) ); } //Toll is required for the church computer/mechanism to function void computer_session::action_toll() { - sounds::sound( g->u.pos(), 120, sounds::sound_t::music, + sounds::sound( get_player_character().pos(), 120, sounds::sound_t::music, //~ the sound of a church bell ringing _( "Bohm… Bohm… Bohm…" ), true, "environment", "church_bells" ); } void computer_session::action_sample() { - g->u.moves -= 30; + get_player_character().moves -= 30; map &here = get_map(); for( const tripoint &p : here.points_on_zlevel() ) { if( here.ter( p ) != t_sewage_pump ) { @@ -394,9 +451,12 @@ void computer_session::action_sample() void computer_session::action_release() { g->events().send(); - sounds::sound( g->u.pos(), 40, sounds::sound_t::alarm, _( "an alarm sound!" ), false, "environment", + Character &player_character = get_player_character(); + sounds::sound( player_character.pos(), 40, sounds::sound_t::alarm, _( "an alarm sound!" ), false, + "environment", "alarm" ); - get_map().translate_radius( t_reinforced_glass, t_thconc_floor, 25.0, g->u.pos(), true ); + get_map().translate_radius( t_reinforced_glass, t_thconc_floor, 25.0, player_character.pos(), + true ); query_any( _( "Containment shields opened. Press any key…" ) ); } @@ -408,15 +468,18 @@ void computer_session::action_release_disarm() void computer_session::action_release_bionics() { - sounds::sound( g->u.pos(), 40, sounds::sound_t::alarm, _( "an alarm sound!" ), false, "environment", + Character &player_character = get_player_character(); + sounds::sound( player_character.pos(), 40, sounds::sound_t::alarm, _( "an alarm sound!" ), false, + "environment", "alarm" ); - get_map().translate_radius( t_reinforced_glass, t_thconc_floor, 3.0, g->u.pos(), true ); + get_map().translate_radius( t_reinforced_glass, t_thconc_floor, 3.0, player_character.pos(), true ); query_any( _( "Containment shields opened. Press any key…" ) ); } void computer_session::action_terminate() { g->events().send(); + Character &player_character = get_player_character(); map &here = get_map(); for( const tripoint &p : here.points_on_zlevel() ) { monster *const mon = g->critter_at( p ); @@ -427,7 +490,7 @@ void computer_session::action_terminate() here.ter( p + tripoint_south ) == t_concrete_wall ) || ( here.ter( p + tripoint_south ) == t_reinforced_glass && here.ter( p + tripoint_north ) == t_concrete_wall ) ) { - mon->die( &g->u ); + mon->die( &player_character ); } } query_any( _( "Subjects terminated. Press any key…" ) ); @@ -460,14 +523,15 @@ void computer_session::action_cascade() return; } g->events().send(); + tripoint player_pos = get_player_character().pos(); map &here = get_map(); std::vector cascade_points; - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 10 ) ) { + for( const tripoint &dest : here.points_in_radius( player_pos, 10 ) ) { if( here.ter( dest ) == t_radio_tower ) { cascade_points.push_back( dest ); } } - explosion_handler::resonance_cascade( random_entry( cascade_points, g->u.pos() ) ); + explosion_handler::resonance_cascade( random_entry( cascade_points, player_pos ) ); } void computer_session::action_research() @@ -479,7 +543,7 @@ void computer_session::action_research() if( !log.has_value() ) { log = to_translation( "No data found." ); } else { - g->u.moves -= 70; + get_player_character().moves -= 70; } print_text( "%s", log.value() ); @@ -497,7 +561,7 @@ void computer_session::action_research() void computer_session::action_radio_archive() { - g->u.moves -= 300; + get_player_character().moves -= 300; sfx::fade_audio_channel( sfx::channel::radio, 100 ); sfx::play_ambient_variant_sound( "radio", "inaudible_chatter", 100, sfx::channel::radio, 2000 ); @@ -514,8 +578,9 @@ void computer_session::action_radio_archive() void computer_session::action_maps() { - g->u.moves -= 30; - const tripoint center = g->u.global_omt_location(); + Character &player_character = get_player_character(); + player_character.moves -= 30; + const tripoint center = player_character.global_omt_location(); overmap_buffer.reveal( center.xy(), 40, 0 ); query_any( _( "Surface map data downloaded. Local anomalous-access error logged. Press any key…" ) ); @@ -525,8 +590,9 @@ void computer_session::action_maps() void computer_session::action_map_sewer() { - g->u.moves -= 30; - const tripoint center = g->u.global_omt_location(); + Character &player_character = get_player_character(); + player_character.moves -= 30; + const tripoint center = player_character.global_omt_location(); for( int i = -60; i <= 60; i++ ) { for( int j = -60; j <= 60; j++ ) { point offset( i, j ); @@ -543,8 +609,9 @@ void computer_session::action_map_sewer() void computer_session::action_map_subway() { - g->u.moves -= 30; - const tripoint center = g->u.global_omt_location(); + Character &player_character = get_player_character(); + player_character.moves -= 30; + const tripoint center = player_character.global_omt_location(); for( int i = -60; i <= 60; i++ ) { for( int j = -60; j <= 60; j++ ) { point offset( i, j ); @@ -576,7 +643,7 @@ void computer_session::action_miss_disarm() void computer_session::action_list_bionics() { - g->u.moves -= 30; + get_player_character().moves -= 30; std::vector names; int more = 0; map &here = get_map(); @@ -622,7 +689,8 @@ void computer_session::action_elevator_on() void computer_session::action_amigara_log() { - g->u.moves -= 30; + Character &player_character = get_player_character(); + player_character.moves -= 30; reset_terminal(); print_line( _( "NEPower Mine(%d:%d) Log" ), g->get_levx(), g->get_levy() ); print_text( "%s", SNIPPET.random_from_category( "amigara1" ).value_or( translation() ) ); @@ -630,7 +698,7 @@ void computer_session::action_amigara_log() if( !query_bool( _( "Continue reading?" ) ) ) { return; } - g->u.moves -= 30; + player_character.moves -= 30; reset_terminal(); print_line( _( "NEPower Mine(%d:%d) Log" ), g->get_levx(), g->get_levy() ); print_text( "%s", SNIPPET.random_from_category( "amigara2" ).value_or( translation() ) ); @@ -638,7 +706,7 @@ void computer_session::action_amigara_log() if( !query_bool( _( "Continue reading?" ) ) ) { return; } - g->u.moves -= 30; + player_character.moves -= 30; reset_terminal(); print_line( _( "NEPower Mine(%d:%d) Log" ), g->get_levx(), g->get_levy() ); print_text( "%s", SNIPPET.random_from_category( "amigara3" ).value_or( translation() ) ); @@ -659,7 +727,7 @@ void computer_session::action_amigara_log() if( !query_bool( _( "Continue reading?" ) ) ) { return; } - g->u.moves -= 30; + player_character.moves -= 30; reset_terminal(); print_line( _( "SITE %d%d%d\n" "PERTINENT FOREMAN LOGS WILL BE PREPENDED TO NOTES" ), @@ -676,8 +744,9 @@ void computer_session::action_amigara_log() void computer_session::action_amigara_start() { g->timed_events.add( timed_event_type::AMIGARA, calendar::turn + 1_minutes ); - if( !g->u.has_artifact_with( AEP_PSYSHIELD ) ) { - g->u.add_effect( effect_amigara, 2_minutes ); + Character &player_character = get_player_character(); + if( !player_character.has_artifact_with( AEP_PSYSHIELD ) ) { + player_character.add_effect( effect_amigara, 2_minutes ); } // Disable this action to prevent further amigara events, which would lead to // further amigara monster, which would lead to further artifacts. @@ -686,7 +755,7 @@ void computer_session::action_amigara_start() void computer_session::action_complete_disable_external_power() { - for( auto miss : g->u.get_active_missions() ) { + for( auto miss : get_avatar().get_active_missions() ) { static const mission_type_id commo_2 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_2" ); if( miss->mission_id() == commo_2 ) { print_error( _( "--ACCESS GRANTED--" ) ); @@ -702,15 +771,16 @@ void computer_session::action_complete_disable_external_power() void computer_session::action_repeater_mod() { - if( g->u.has_amount( itype_radio_repeater_mod, 1 ) ) { - for( auto miss : g->u.get_active_missions() ) { + avatar &player_character = get_avatar(); + if( player_character.has_amount( itype_radio_repeater_mod, 1 ) ) { + for( auto miss : player_character.get_active_missions() ) { static const mission_type_id commo_3 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_3" ), commo_4 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_4" ); if( miss->mission_id() == commo_3 || miss->mission_id() == commo_4 ) { miss->step_complete( 1 ); print_error( _( "Repeater mod installed…" ) ); print_error( _( "Mission Complete!" ) ); - g->u.use_amount( itype_radio_repeater_mod, 1 ); + player_character.use_amount( itype_radio_repeater_mod, 1 ); query_any(); comp.options.clear(); activate_failure( COMPFAIL_SHUTDOWN ); @@ -731,7 +801,7 @@ void computer_session::action_download_software() debugmsg( _( "Computer couldn't find its mission!" ) ); return; } - g->u.moves -= 30; + get_player_character().moves -= 30; item software( miss->get_item_id(), 0 ); software.mission_id = comp.mission_id; usb->contents.clear_items(); @@ -745,9 +815,10 @@ void computer_session::action_download_software() void computer_session::action_blood_anal() { - g->u.moves -= 70; + Character &player_character = get_player_character(); + player_character.moves -= 70; map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 2 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 2 ) ) { if( here.ter( dest ) == t_centrifuge ) { map_stack items = here.i_at( dest ); if( items.empty() ) { @@ -791,9 +862,10 @@ void computer_session::action_blood_anal() void computer_session::action_data_anal() { - g->u.moves -= 30; + Character &player_character = get_player_character(); + player_character.moves -= 30; map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 2 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 2 ) ) { if( here.ter( dest ) == t_floor_blue ) { print_error( _( "PROCESSING DATA" ) ); map_stack items = here.i_at( dest ); @@ -811,7 +883,7 @@ void computer_session::action_data_anal() if( items.only_item().typeId() == itype_black_box ) { print_line( _( "Memory Bank: Military Hexron Encryption\nPrinting Transcript\n" ) ); item transcript( "black_box_transcript", calendar::turn ); - here.add_item_or_charges( g->u.pos(), transcript ); + here.add_item_or_charges( player_character.pos(), transcript ); } else { print_line( _( "Memory Bank: Unencrypted\nNothing of interest.\n" ) ); } @@ -949,10 +1021,11 @@ void computer_session::action_srcf_seal() void computer_session::action_srcf_elevator() { - if( !g->u.has_amount( itype_sarcophagus_access_code, 1 ) ) { + Character &player_character = get_player_character(); + if( !player_character.has_amount( itype_sarcophagus_access_code, 1 ) ) { print_error( _( "Access code required!" ) ); } else { - g->u.use_amount( itype_sarcophagus_access_code, 1 ); + player_character.use_amount( itype_sarcophagus_access_code, 1 ); reset_terminal(); print_line( _( "\nPower: Backup Only\nRadiation Level: Very Dangerous\nOperational: Overridden\n\n" ) ); @@ -969,17 +1042,18 @@ void computer_session::action_srcf_elevator() //irradiates food at t_rad_platform, adds radiation void computer_session::action_irradiator() { - g->u.moves -= 30; + Character &player_character = get_player_character(); + player_character.moves -= 30; bool error = false; bool platform_exists = false; map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 10 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 10 ) ) { if( here.ter( dest ) == t_rad_platform ) { platform_exists = true; if( here.i_at( dest ).empty() ) { print_error( _( "ERROR: Processing platform empty." ) ); } else { - g->u.moves -= 300; + player_character.moves -= 300; for( auto it = here.i_at( dest ).begin(); it != here.i_at( dest ).end(); ++it ) { // actual food processing itype_id irradiated_type( "irradiated_" + it->typeId().str() ); @@ -996,7 +1070,8 @@ void computer_session::action_irradiator() print_error( _( " >> Radiation spike detected!\n" ) ); print_error( _( "WARNING [912]: Catastrophic malfunction! Contamination detected!" ) ); print_error( _( "EMERGENCY PROCEDURE [1]: Evacuate. Evacuate. Evacuate.\n" ) ); - sounds::sound( g->u.pos(), 30, sounds::sound_t::alarm, _( "an alarm sound!" ), false, "environment", + sounds::sound( player_character.pos(), 30, sounds::sound_t::alarm, _( "an alarm sound!" ), false, + "environment", "alarm" ); here.i_rem( dest, it ); here.make_rubble( dest ); @@ -1008,9 +1083,9 @@ void computer_session::action_irradiator() dest ) > 0 ? rl_dist( radorigin, dest ) : 1 ) ); } if( here.pl_sees( dest, 10 ) ) { - g->u.irradiate( rng_float( 50, 250 ) / rl_dist( g->u.pos(), dest ) ); + player_character.irradiate( rng_float( 50, 250 ) / rl_dist( player_character.pos(), dest ) ); } else { - g->u.irradiate( rng_float( 20, 100 ) / rl_dist( g->u.pos(), dest ) ); + player_character.irradiate( rng_float( 20, 100 ) / rl_dist( player_character.pos(), dest ) ); } query_any( _( "EMERGENCY SHUTDOWN! Press any key…" ) ); error = true; @@ -1025,7 +1100,7 @@ void computer_session::action_irradiator() } // if unshielded, rad source irradiates player directly, reduced by distance to source if( here.pl_sees( dest, 10 ) ) { - g->u.irradiate( rng_float( 5, 25 ) / rl_dist( g->u.pos(), dest ) ); + player_character.irradiate( rng_float( 5, 25 ) / rl_dist( player_character.pos(), dest ) ); } } if( !error && platform_exists ) { @@ -1047,7 +1122,8 @@ void computer_session::action_irradiator() // geiger counter for irradiator, primary measurement at t_rad_platform, secondary at player loacation void computer_session::action_geiger() { - g->u.moves -= 30; + Character &player_character = get_player_character(); + player_character.moves -= 30; tripoint platform; bool source_exists = false; int sum_rads = 0; @@ -1055,7 +1131,7 @@ void computer_session::action_geiger() int tiles_counted = 0; map &here = get_map(); print_error( _( "RADIATION MEASUREMENTS:" ) ); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 10 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 10 ) ) { if( here.ter( dest ) == t_rad_platform ) { source_exists = true; platform = dest; @@ -1078,8 +1154,9 @@ void computer_session::action_geiger() print_error( _( "GEIGER COUNTER @ ZONE:… MAX %s mSv/h." ), peak_rad ); print_newline(); } - print_error( _( "GEIGER COUNTER @ CONSOLE:… %s mSv/h." ), here.get_radiation( g->u.pos() ) ); - print_error( _( "PERSONAL DOSIMETRY:… %s mSv." ), g->u.get_rad() ); + print_error( _( "GEIGER COUNTER @ CONSOLE:… %s mSv/h." ), + here.get_radiation( player_character.pos() ) ); + print_error( _( "PERSONAL DOSIMETRY:… %s mSv." ), player_character.get_rad() ); print_newline(); query_any( _( "Press any key…" ) ); } @@ -1088,7 +1165,8 @@ void computer_session::action_geiger() // ensure only bay of each type in range void computer_session::action_conveyor() { - g->u.moves -= 300; + Character &player_character = get_player_character(); + player_character.moves -= 300; tripoint loading; // red tile = loading bay tripoint unloading; // green tile = unloading bay tripoint platform; // radiation platform = middle point @@ -1096,7 +1174,7 @@ void computer_session::action_conveyor() bool u_exists = false; bool p_exists = false; map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 10 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 10 ) ) { if( here.ter( dest ) == t_rad_platform ) { platform = dest; p_exists = true; @@ -1141,9 +1219,10 @@ void computer_session::action_conveyor() // toggles reinforced glass shutters open->closed and closed->open depending on their current state void computer_session::action_shutters() { - g->u.moves -= 300; + Character &player_character = get_player_character(); + player_character.moves -= 300; get_map().translate_radius( t_reinforced_glass_shutter_open, t_reinforced_glass_shutter, 8.0, - g->u.pos(), + player_character.pos(), true, true ); query_any( _( "Toggling shutters. Press any key…" ) ); } @@ -1151,12 +1230,13 @@ void computer_session::action_shutters() // extract radiation source material from irradiator void computer_session::action_extract_rad_source() { + Character &player_character = get_player_character(); if( query_yn( _( "Operation irreversible. Extract radioactive material?" ) ) ) { - g->u.moves -= 300; + player_character.moves -= 300; tripoint platform; bool p_exists = false; map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 10 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 10 ) ) { if( here.ter( dest ) == t_rad_platform ) { platform = dest; p_exists = true; @@ -1164,7 +1244,7 @@ void computer_session::action_extract_rad_source() } if( p_exists ) { here.spawn_item( platform, itype_cobalt_60, rng( 8, 15 ) ); - here.translate_radius( t_rad_platform, t_concrete, 8.0, g->u.pos(), true ); + here.translate_radius( t_rad_platform, t_concrete, 8.0, player_character.pos(), true ); comp.remove_option( COMPACT_IRRADIATOR ); comp.remove_option( COMPACT_EXTRACT_RAD_SOURCE ); query_any( _( "Extraction sequence complete… Press any key." ) ); @@ -1177,11 +1257,12 @@ void computer_session::action_extract_rad_source() // remove shock vent fields; check for existing plutonium generators in radius void computer_session::action_deactivate_shock_vent() { - g->u.moves -= 30; + Character &player_character = get_player_character(); + player_character.moves -= 30; bool has_vent = false; bool has_generator = false; map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 10 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 10 ) ) { if( here.get_field( dest, fd_shock_vent ) != nullptr ) { has_vent = true; } @@ -1243,9 +1324,9 @@ void computer_session::failure_shutdown() { bool found_tile = false; map &here = get_map(); - for( const tripoint &p : here.points_in_radius( g->u.pos(), 1 ) ) { + for( const tripoint &p : here.points_in_radius( get_player_character().pos(), 1 ) ) { if( here.has_flag( flag_CONSOLE, p ) ) { - here.ter_set( p, t_console_broken ); + here.furn_set( p, furn_str_id( "f_console_broken" ) ); add_msg( m_bad, _( "The console shuts down." ) ); found_tile = true; } @@ -1255,7 +1336,7 @@ void computer_session::failure_shutdown() } for( const tripoint &p : here.points_on_zlevel() ) { if( here.has_flag( flag_CONSOLE, p ) ) { - here.ter_set( p, t_console_broken ); + here.furn_set( p, furn_str_id( "f_console_broken" ) ); add_msg( m_bad, _( "The console shuts down." ) ); } } @@ -1263,19 +1344,22 @@ void computer_session::failure_shutdown() void computer_session::failure_alarm() { - g->events().send( g->u.getID() ); - sounds::sound( g->u.pos(), 60, sounds::sound_t::alarm, _( "an alarm sound!" ), false, "environment", + Character &player_character = get_player_character(); + g->events().send( player_character.getID() ); + sounds::sound( player_character.pos(), 60, sounds::sound_t::alarm, _( "an alarm sound!" ), false, + "environment", "alarm" ); if( g->get_levz() > 0 && !g->timed_events.queued( timed_event_type::WANTED ) ) { g->timed_events.add( timed_event_type::WANTED, calendar::turn + 30_minutes, 0, - g->u.global_sm_location() ); + player_character.global_sm_location() ); } } void computer_session::failure_manhacks() { int num_robots = rng( 4, 8 ); - const tripoint_range range = get_map().points_in_radius( g->u.pos(), 3 ); + const tripoint_range range = + get_map().points_in_radius( get_player_character().pos(), 3 ); for( int i = 0; i < num_robots; i++ ) { if( g->place_critter_within( mon_manhack, range ) ) { add_msg( m_warning, _( "Manhacks drop from compartments in the ceiling." ) ); @@ -1286,7 +1370,8 @@ void computer_session::failure_manhacks() void computer_session::failure_secubots() { int num_robots = 1; - const tripoint_range range = get_map().points_in_radius( g->u.pos(), 3 ); + const tripoint_range range = + get_map().points_in_radius( get_player_character().pos(), 3 ); for( int i = 0; i < num_robots; i++ ) { if( g->place_critter_within( mon_secubot, range ) ) { add_msg( m_warning, _( "Secubots emerge from compartments in the floor." ) ); @@ -1297,11 +1382,12 @@ void computer_session::failure_secubots() void computer_session::failure_damage() { add_msg( m_neutral, _( "The console shocks you." ) ); - if( g->u.is_elec_immune() ) { + Character &player_character = get_player_character(); + if( player_character.is_elec_immune() ) { add_msg( m_good, _( "You're protected from electric shocks." ) ); } else { add_msg( m_bad, _( "Your body is damaged by the electric shock!" ) ); - g->u.hurtall( rng( 1, 10 ), nullptr ); + player_character.hurtall( rng( 1, 10 ), nullptr ); } } @@ -1351,7 +1437,7 @@ void computer_session::failure_pump_leak() void computer_session::failure_amigara() { g->timed_events.add( timed_event_type::AMIGARA, calendar::turn + 30_seconds ); - g->u.add_effect( effect_amigara, 2_minutes ); + get_player_character().add_effect( effect_amigara, 2_minutes ); explosion_handler::explosion( tripoint( rng( 0, MAPSIZE_X ), rng( 0, MAPSIZE_Y ), g->get_levz() ), 10, 0.7, false, 10 ); @@ -1365,7 +1451,7 @@ void computer_session::failure_destroy_blood() { print_error( _( "ERROR: Disruptive Spin" ) ); map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 2 ) ) { + for( const tripoint &dest : here.points_in_radius( get_player_character().pos(), 2 ) ) { if( here.ter( dest ) == t_centrifuge ) { map_stack items = here.i_at( dest ); if( items.empty() ) { @@ -1391,7 +1477,7 @@ void computer_session::failure_destroy_data() { print_error( _( "ERROR: ACCESSING DATA MALFUNCTION" ) ); map &here = get_map(); - for( const tripoint &p : here.points_in_radius( g->u.pos(), 2 ) ) { + for( const tripoint &p : here.points_in_radius( get_player_character().pos(), 2 ) ) { if( here.ter( p ) == t_floor_blue ) { map_stack items = here.i_at( p ); if( items.empty() ) { @@ -1418,9 +1504,10 @@ void computer_session::action_emerg_ref_center() const mission_type_id &mission_type = mission_type_id( "MISSION_REACH_REFUGEE_CENTER" ); tripoint mission_target; + avatar &player_character = get_avatar(); // Check completed missions too, so people can't repeatedly get the mission. - const std::vector completed_missions = g->u.get_completed_missions(); - std::vector missions = g->u.get_active_missions(); + const std::vector completed_missions = player_character.get_completed_missions(); + std::vector missions = player_character.get_active_missions(); missions.insert( missions.end(), completed_missions.begin(), completed_missions.end() ); const bool has_mission = std::any_of( missions.begin(), missions.end(), [ &mission_type, @@ -1435,7 +1522,7 @@ void computer_session::action_emerg_ref_center() if( !has_mission ) { const auto mission = mission::reserve_new( mission_type, character_id() ); - mission->assign( g->u ); + mission->assign( player_character ); mission_target = mission->get_target(); } @@ -1447,8 +1534,8 @@ void computer_session::action_emerg_ref_center() "4PM AT 555-0164.\n" "\n" "IF YOU WOULD LIKE TO SPEAK WITH SOMEONE IN PERSON OR WOULD LIKE\n" - "TO WRITE US A LETTER PLEASE SEND IT TO…\n" ), rl_dist( g->u.pos(), mission_target ), - direction_name_short( direction_from( g->u.pos(), mission_target ) ) ); + "TO WRITE US A LETTER PLEASE SEND IT TO…\n" ), rl_dist( player_character.pos(), mission_target ), + direction_name_short( direction_from( player_character.pos(), mission_target ) ) ); query_any( _( "Press any key to continue…" ) ); reset_terminal(); diff --git a/src/computer_session.h b/src/computer_session.h index f4db88ec18f42..33e068b88e5a6 100644 --- a/src/computer_session.h +++ b/src/computer_session.h @@ -34,6 +34,13 @@ class computer_session * the main system security. */ bool hack_attempt( player &p, int Security = -1 ); + /** + * Checks whether the specified action can be activated (has any effect) + * @return True for actions that either have an effect or require no special conditions, + otherwise false (e.g. false for COMPACT_UNLOCK if no locked doors are in range). + */ + bool can_activate( computer_action action ); + // Called by use() void activate_function( computer_action action ); // ...but we can also choose a specific failure. diff --git a/src/condition.cpp b/src/condition.cpp index 030844864de4b..46e93270b7fcc 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -37,6 +37,7 @@ #include "point.h" #include "recipe_groups.h" #include "string_id.h" +#include "talker.h" #include "type_id.h" #include "vehicle.h" #include "vpart_position.h" @@ -50,7 +51,7 @@ static const efftype_id effect_currently_busy( "currently_busy" ); std::string get_talk_varname( const JsonObject &jo, const std::string &member, bool check_value ) { if( !jo.has_string( "type" ) || !jo.has_string( "context" ) || - ( check_value && !jo.has_string( "value" ) ) ) { + ( check_value && !( jo.has_string( "value" ) || jo.has_member( "time" ) ) ) ) { jo.throw_error( "invalid " + member + " condition in " + jo.str() ); } const std::string &var_basename = jo.get_string( member ); @@ -95,10 +96,7 @@ void conditional_t::set_has_any_trait( const JsonObject &jo, const std::strin traits_to_check.emplace_back( f ); } condition = [traits_to_check, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); for( const auto &trait : traits_to_check ) { if( actor->has_trait( trait ) ) { return true; @@ -113,11 +111,7 @@ void conditional_t::set_has_trait( const JsonObject &jo, const std::string &m { const std::string &trait_to_check = jo.get_string( member ); condition = [trait_to_check, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->has_trait( trait_id( trait_to_check ) ); + return d.actor( is_npc )->has_trait( trait_id( trait_to_check ) ); }; } @@ -127,10 +121,7 @@ void conditional_t::set_has_trait_flag( const JsonObject &jo, const std::stri { const std::string &trait_flag_to_check = jo.get_string( member ); condition = [trait_flag_to_check, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); if( trait_flag_to_check == "MUTATION_THRESHOLD" ) { return actor->crossed_threshold(); } @@ -142,15 +133,7 @@ template void conditional_t::set_has_activity( bool is_npc ) { condition = [is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - return d.beta->has_activity(); - } else { - if( !actor->activity.is_null() ) { - return true; - } - } - return false; + return d.actor( is_npc )->has_activity(); }; } @@ -158,7 +141,7 @@ template void conditional_t::set_is_riding( bool is_npc ) { condition = [is_npc]( const T & d ) { - return ( is_npc ? d.beta : d.alpha )->is_mounted(); + return d.actor( is_npc )->is_mounted(); }; } @@ -167,7 +150,7 @@ void conditional_t::set_npc_has_class( const JsonObject &jo ) { const std::string &class_to_check = jo.get_string( "npc_has_class" ); condition = [class_to_check]( const T & d ) { - return d.beta->myclass == npc_class_id( class_to_check ); + return d.beta->is_myclass( npc_class_id( class_to_check ) ); }; } @@ -176,7 +159,7 @@ void conditional_t::set_u_has_mission( const JsonObject &jo ) { const std::string &mission = jo.get_string( "u_has_mission" ); condition = [mission]( const T & ) { - for( auto miss_it : g->u.get_active_missions() ) { + for( auto miss_it : get_avatar().get_active_missions() ) { if( miss_it->mission_id() == mission_type_id( mission ) ) { return true; } @@ -191,11 +174,7 @@ void conditional_t::set_has_strength( const JsonObject &jo, const std::string { const int min_strength = jo.get_int( member ); condition = [min_strength, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->str_cur >= min_strength; + return d.actor( is_npc )->str_cur() >= min_strength; }; } @@ -205,11 +184,7 @@ void conditional_t::set_has_dexterity( const JsonObject &jo, const std::strin { const int min_dexterity = jo.get_int( member ); condition = [min_dexterity, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->dex_cur >= min_dexterity; + return d.actor( is_npc )->dex_cur() >= min_dexterity; }; } @@ -219,11 +194,7 @@ void conditional_t::set_has_intelligence( const JsonObject &jo, const std::st { const int min_intelligence = jo.get_int( member ); condition = [min_intelligence, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->int_cur >= min_intelligence; + return d.actor( is_npc )->int_cur() >= min_intelligence; }; } @@ -233,11 +204,7 @@ void conditional_t::set_has_perception( const JsonObject &jo, const std::stri { const int min_perception = jo.get_int( member ); condition = [min_perception, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->per_cur >= min_perception; + return d.actor( is_npc )->per_cur() >= min_perception; }; } @@ -247,11 +214,7 @@ void conditional_t::set_is_wearing( const JsonObject &jo, const std::string & { const itype_id item_id( jo.get_string( member ) ); condition = [item_id, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->is_wearing( item_id ); + return d.actor( is_npc )->is_wearing( item_id ); }; } @@ -260,10 +223,7 @@ void conditional_t::set_has_item( const JsonObject &jo, const std::string &me { const itype_id item_id( jo.get_string( member ) ); condition = [item_id, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); return actor->charges_of( item_id ) > 0 || actor->has_amount( item_id, 1 ); }; } @@ -280,10 +240,7 @@ void conditional_t::set_has_items( const JsonObject &jo, const std::string &m const itype_id item_id( has_items.get_string( "item" ) ); int count = has_items.get_int( "count" ); condition = [item_id, count, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); return actor->has_charges( item_id, count ) || actor->has_amount( item_id, count ); }; } @@ -304,10 +261,7 @@ void conditional_t::set_has_item_category( const JsonObject &jo, const std::s } condition = [category_id, count, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); const auto items_with = actor->items_with( [category_id]( const item & it ) { return it.get_category().get_id() == category_id; } ); @@ -321,10 +275,7 @@ void conditional_t::set_has_bionics( const JsonObject &jo, const std::string { const std::string bionics_id = jo.get_string( member ); condition = [bionics_id, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); if( bionics_id == "ANY" ) { return actor->num_bionics() > 0 || actor->has_max_power(); } @@ -338,11 +289,7 @@ void conditional_t::set_has_effect( const JsonObject &jo, const std::string & { const std::string &effect_id = jo.get_string( member ); condition = [effect_id, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->has_effect( efftype_id( effect_id ) ); + return d.actor( is_npc )->has_effect( efftype_id( effect_id ) ); }; } @@ -361,10 +308,7 @@ void conditional_t::set_need( const JsonObject &jo, const std::string &member } } condition = [need, amount, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); return ( actor->get_fatigue() > amount && need == "fatigue" ) || ( actor->get_hunger() > amount && need == "hunger" ) || ( actor->get_thirst() > amount && need == "thirst" ); @@ -377,11 +321,7 @@ void conditional_t::set_at_om_location( const JsonObject &jo, const std::stri { const std::string &location = jo.get_string( member ); condition = [location, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - const tripoint omt_pos = actor->global_omt_location(); + const tripoint omt_pos = d.actor( is_npc )->global_omt_location(); const oter_id &omt_ref = overmap_buffer.ter( omt_pos ); if( location == "FACTION_CAMP_ANY" ) { @@ -405,11 +345,12 @@ template void conditional_t::set_has_var( const JsonObject &jo, const std::string &member, bool is_npc ) { const std::string var_name = get_talk_varname( jo, member, false ); - const std::string &value = jo.get_string( "value" ); - condition = [var_name, value, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); + const std::string &value = jo.has_member( "value" ) ? jo.get_string( "value" ) : std::string(); + const bool time_check = jo.has_member( "time" ) && jo.get_bool( "time" ); + condition = [var_name, value, time_check, is_npc]( const T & d ) { + const talker *actor = d.actor( is_npc ); + if( time_check ) { + return !actor->get_value( var_name ).empty(); } return actor->get_value( var_name ) == value; }; @@ -423,13 +364,8 @@ void conditional_t::set_compare_var( const JsonObject &jo, const std::string const std::string &op = jo.get_string( "op" ); const int value = jo.get_int( "value" ); condition = [var_name, op, value, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - int stored_value = 0; - const std::string &var = actor->get_value( var_name ); + const std::string &var = d.actor( is_npc )->get_value( var_name ); if( !var.empty() ) { stored_value = std::stoi( var ); } @@ -457,6 +393,48 @@ void conditional_t::set_compare_var( const JsonObject &jo, const std::string }; } +template +void conditional_t::set_compare_time_since_var( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const std::string var_name = get_talk_varname( jo, member, false ); + const std::string &op = jo.get_string( "op" ); + const int value = to_turns( read_from_json_string( *jo.get_raw( "time" ), + time_duration::units ) ); + condition = [var_name, op, value, is_npc]( const T & d ) { + int stored_value = 0; + const std::string &var = d.actor( is_npc )->get_value( var_name ); + if( var.empty() ) { + return false; + } else { + stored_value = std::stoi( var ); + } + stored_value += value; + int now = to_turn( calendar::turn ); + + if( op == "==" ) { + return stored_value == now; + + } else if( op == "!=" ) { + return stored_value != now; + + } else if( op == "<=" ) { + return now <= stored_value; + + } else if( op == ">=" ) { + return now >= stored_value; + + } else if( op == "<" ) { + return now < stored_value; + + } else if( op == ">" ) { + return now > stored_value; + } + + return false; + }; +} + template void conditional_t::set_npc_role_nearby( const JsonObject &jo ) { @@ -484,7 +462,7 @@ void conditional_t::set_u_has_cash( const JsonObject &jo ) { const int min_cash = jo.get_int( "u_has_cash" ); condition = [min_cash]( const T & d ) { - return d.alpha->cash >= min_cash; + return d.alpha->cash() >= min_cash; }; } @@ -493,7 +471,7 @@ void conditional_t::set_u_are_owed( const JsonObject &jo ) { const int min_debt = jo.get_int( "u_are_owed" ); condition = [min_debt]( const T & d ) { - return d.beta->op_of_u.owed >= min_debt; + return d.beta->debt() >= min_debt; }; } @@ -502,11 +480,7 @@ void conditional_t::set_npc_aim_rule( const JsonObject &jo ) { const std::string &setting = jo.get_string( "npc_aim_rule" ); condition = [setting]( const T & d ) { - auto rule = aim_rule_strs.find( setting ); - if( rule != aim_rule_strs.end() ) { - return d.beta->rules.aim == rule->second; - } - return false; + return d.beta->has_ai_rule( "aim_rule", setting ); }; } @@ -515,11 +489,7 @@ void conditional_t::set_npc_engagement_rule( const JsonObject &jo ) { const std::string &setting = jo.get_string( "npc_engagement_rule" ); condition = [setting]( const T & d ) { - auto rule = combat_engagement_strs.find( setting ); - if( rule != combat_engagement_strs.end() ) { - return d.beta->rules.engagement == rule->second; - } - return false; + return d.beta->has_ai_rule( "engagement_rule", setting ); }; } @@ -528,11 +498,7 @@ void conditional_t::set_npc_cbm_reserve_rule( const JsonObject &jo ) { const std::string &setting = jo.get_string( "npc_cbm_reserve_rule" ); condition = [setting]( const T & d ) { - auto rule = cbm_reserve_strs.find( setting ); - if( rule != cbm_reserve_strs.end() ) { - return d.beta->rules.cbm_reserve == rule->second; - } - return false; + return d.beta->has_ai_rule( "cbm_reserve_rule", setting ); }; } @@ -541,11 +507,7 @@ void conditional_t::set_npc_cbm_recharge_rule( const JsonObject &jo ) { const std::string &setting = jo.get_string( "npc_cbm_recharge_rule" ); condition = [setting]( const T & d ) { - auto rule = cbm_recharge_strs.find( setting ); - if( rule != cbm_recharge_strs.end() ) { - return d.beta->rules.cbm_recharge == rule->second; - } - return false; + return d.beta->has_ai_rule( "cbm_recharge_rule", setting ); }; } @@ -554,11 +516,7 @@ void conditional_t::set_npc_rule( const JsonObject &jo ) { std::string rule = jo.get_string( "npc_rule" ); condition = [rule]( const T & d ) { - auto flag = ally_rule_strs.find( rule ); - if( flag != ally_rule_strs.end() ) { - return d.beta->rules.has_flag( flag->second.rule ); - } - return false; + return d.beta->has_ai_rule( "ally_rule", rule ); }; } @@ -567,11 +525,7 @@ void conditional_t::set_npc_override( const JsonObject &jo ) { std::string rule = jo.get_string( "npc_override" ); condition = [rule]( const T & d ) { - auto flag = ally_rule_strs.find( rule ); - if( flag != ally_rule_strs.end() ) { - return d.beta->rules.has_override_enable( flag->second.rule ); - } - return false; + return d.beta->has_ai_rule( "ally_override", rule ); }; } @@ -602,7 +556,7 @@ void conditional_t::set_mission_goal( const JsonObject &jo ) { std::string mission_goal_str = jo.get_string( "mission_goal" ); condition = [mission_goal_str]( const T & d ) { - mission *miss = d.beta->chatbin.mission_selected; + mission *miss = d.beta->selected_mission(); if( !miss ) { return false; } @@ -615,11 +569,7 @@ template void conditional_t::set_is_gender( bool is_male, bool is_npc ) { condition = [is_male, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->male == is_male; + return d.actor( is_npc )->is_male() == is_male; }; } @@ -651,7 +601,7 @@ template void conditional_t::set_no_available_mission() { condition = []( const T & d ) { - return d.beta->chatbin.missions.empty(); + return d.beta->available_missions().empty(); }; } @@ -659,7 +609,7 @@ template void conditional_t::set_has_available_mission() { condition = []( const T & d ) { - return d.beta->chatbin.missions.size() == 1; + return d.beta->available_missions().size() == 1; }; } @@ -667,7 +617,7 @@ template void conditional_t::set_has_many_available_missions() { condition = []( const T & d ) { - return d.beta->chatbin.missions.size() >= 2; + return d.beta->available_missions().size() >= 2; }; } @@ -675,11 +625,8 @@ template void conditional_t::set_mission_complete() { condition = []( const T & d ) { - mission *miss = d.beta->chatbin.mission_selected; - if( !miss ) { - return false; - } - return miss->is_complete( d.beta->getID() ); + mission *miss = d.beta->selected_mission(); + return miss && miss->is_complete( d.beta->getID() ); }; } @@ -687,11 +634,8 @@ template void conditional_t::set_mission_incomplete() { condition = []( const T & d ) { - mission *miss = d.beta->chatbin.mission_selected; - if( !miss ) { - return false; - } - return !miss->is_complete( d.beta->getID() ); + mission *miss = d.beta->selected_mission(); + return miss && !miss->is_complete( d.beta->getID() ); }; } @@ -715,7 +659,7 @@ template void conditional_t::set_npc_friend() { condition = []( const T & d ) { - return d.beta->is_friendly( g->u ); + return d.beta->is_friendly( get_player_character() ); }; } @@ -743,6 +687,14 @@ void conditional_t::set_npc_train_styles() }; } +template +void conditional_t::set_npc_train_spells() +{ + condition = []( const T & d ) { + return !d.beta->spells_offered_to( *d.alpha ).empty(); + }; +} + template void conditional_t::set_at_safe_space() { @@ -755,11 +707,8 @@ template void conditional_t::set_can_stow_weapon( bool is_npc ) { condition = [is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return !actor->unarmed_attack() && actor->can_pickVolume( actor->weapon ); + const talker *actor = d.actor( is_npc ); + return !actor->unarmed_attack() && actor->can_stash_weapon(); }; } @@ -767,11 +716,7 @@ template void conditional_t::set_has_weapon( bool is_npc ) { condition = [is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return !actor->unarmed_attack(); + return !d.actor( is_npc )->unarmed_attack(); }; } @@ -779,12 +724,9 @@ template void conditional_t::set_is_driving( bool is_npc ) { condition = [is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } + const talker *actor = d.actor( is_npc ); if( const optional_vpart_position vp = get_map().veh_at( actor->pos() ) ) { - return vp->vehicle().is_moving() && vp->vehicle().player_in_control( *actor ); + return vp->vehicle().is_moving() && actor->is_in_control_of( vp->vehicle() ); } return false; }; @@ -794,15 +736,7 @@ template void conditional_t::set_has_stolen_item( bool /*is_npc*/ ) { condition = []( const T & d ) { - player *actor = d.alpha; - npc &p = *d.beta; - bool found_in_inv = false; - for( auto &elem : actor->inv_dump() ) { - if( elem->is_old_owner( p, true ) ) { - found_in_inv = true; - } - } - return found_in_inv; + return d.alpha->has_stolen_item( *d.beta ); }; } @@ -818,8 +752,8 @@ template void conditional_t::set_is_outside() { condition = []( const T & d ) { - map &here = get_map(); - const tripoint pos = here.getabs( d.beta->pos() ); + const map &here = get_map(); + const tripoint &pos = here.getabs( d.beta->pos() ); return !here.has_flag( TFLAG_INDOORS, pos ); }; } @@ -828,7 +762,7 @@ template void conditional_t::set_u_has_camp() { condition = []( const T & ) { - return !g->u.camps.empty(); + return !get_player_character().camps.empty(); }; } @@ -836,7 +770,7 @@ template void conditional_t::set_has_pickup_list() { condition = []( const T & d ) { - return !d.beta->rules.pickup_whitelist->empty(); + return d.beta->has_ai_rule( "pickup_rule", "any" ); }; } @@ -868,11 +802,7 @@ void conditional_t::set_has_skill( const JsonObject &jo, const std::string &m const skill_id skill( has_skill.get_string( "skill" ) ); int level = has_skill.get_int( "level" ); condition = [skill, level, is_npc]( const T & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - return actor->get_skill_level( skill ) >= level; + return d.actor( is_npc )->get_skill_level( skill ) >= level; }; } } @@ -881,10 +811,10 @@ template void conditional_t::set_u_know_recipe( const JsonObject &jo, const std::string &member ) { const std::string &known_recipe_id = jo.get_string( member ); - condition = [known_recipe_id]( const T & d ) { - player *actor = d.alpha; - const recipe &r = recipe_id( known_recipe_id ).obj(); - return actor->knows_recipe( &r ); + condition = [known_recipe_id]( const T & ) { + const recipe &rep = recipe_id( known_recipe_id ).obj(); + // should be a talker function but recipes aren't in Character:: yet + return g->u.knows_recipe( &rep ); }; } @@ -892,7 +822,7 @@ template void conditional_t::set_mission_has_generic_rewards() { condition = []( const T & d ) { - mission *miss = d.beta->chatbin.mission_selected; + mission *miss = d.beta->selected_mission(); if( miss == nullptr ) { debugmsg( "mission_has_generic_rewards: mission_selected == nullptr" ); return true; @@ -1041,6 +971,10 @@ conditional_t::conditional_t( const JsonObject &jo ) set_compare_var( jo, "u_compare_var" ); } else if( jo.has_string( "npc_compare_var" ) ) { set_compare_var( jo, "npc_compare_var", is_npc ); + } else if( jo.has_string( "u_compare_time_since_var" ) ) { + set_compare_time_since_var( jo, "u_compare_time_since_var" ); + } else if( jo.has_string( "npc_compare_time_since_var" ) ) { + set_compare_time_since_var( jo, "npc_compare_time_since_var", is_npc ); } else if( jo.has_string( "npc_role_nearby" ) ) { set_npc_role_nearby( jo ); } else if( jo.has_int( "npc_allies" ) ) { @@ -1132,6 +1066,8 @@ conditional_t::conditional_t( const std::string &type ) set_npc_train_skills(); } else if( type == "npc_train_styles" ) { set_npc_train_styles(); + } else if( type == "npc_train_spells" ) { + set_npc_train_spells(); } else if( type == "at_safe_space" ) { set_at_safe_space(); } else if( type == "u_can_stow_weapon" ) { diff --git a/src/condition.h b/src/condition.h index baa2b77058eef..1460457222ff0 100644 --- a/src/condition.h +++ b/src/condition.h @@ -20,7 +20,7 @@ const std::unordered_set simple_string_conds = { { "has_no_available_mission", "has_available_mission", "has_many_available_missions", "mission_complete", "mission_incomplete", "mission_has_generic_rewards", "npc_available", "npc_following", "npc_friend", "npc_hostile", - "npc_train_skills", "npc_train_styles", + "npc_train_skills", "npc_train_styles", "npc_train_spells", "at_safe_space", "is_day", "npc_has_activity", "is_outside", "u_has_camp", "u_can_stow_weapon", "npc_can_stow_weapon", "u_has_weapon", "npc_has_weapon", "u_driving", "npc_driving", @@ -40,7 +40,8 @@ const std::unordered_set complex_conds = { { "npc_aim_rule", "npc_engagement_rule", "npc_rule", "npc_override", "npc_cbm_reserve_rule", "npc_cbm_recharge_rule", "days_since_cataclysm", "is_season", "mission_goal", "u_has_var", "npc_has_var", - "u_has_skill", "npc_has_skill", "u_know_recipe", "u_compare_var", "npc_compare_var" + "u_has_skill", "npc_has_skill", "u_know_recipe", "u_compare_var", "npc_compare_var", + "u_compare_time_since_var", "npc_compare_time_since_var" } }; } // namespace dialogue_data @@ -75,6 +76,8 @@ struct conditional_t { void set_has_trait_flag( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_compare_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_compare_time_since_var( const JsonObject &jo, const std::string &member, + bool is_npc = false ); void set_has_activity( bool is_npc = false ); void set_is_riding( bool is_npc = false ); void set_npc_has_class( const JsonObject &jo ); @@ -118,6 +121,7 @@ struct conditional_t { void set_npc_hostile(); void set_npc_train_skills(); void set_npc_train_styles(); + void set_npc_train_spells(); void set_at_safe_space(); void set_can_stow_weapon( bool is_npc = false ); void set_has_weapon( bool is_npc = false ); diff --git a/src/construction.cpp b/src/construction.cpp index 6c2cfe62de99c..754bd2438b414 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -107,6 +107,8 @@ bool check_empty_up_OK( const tripoint & ); // tile is empty and below OVERMAP_H bool check_up_OK( const tripoint & ); // tile is below OVERMAP_HEIGHT bool check_down_OK( const tripoint & ); // tile is above OVERMAP_DEPTH bool check_no_trap( const tripoint & ); +bool check_ramp_low( const tripoint & ); +bool check_ramp_high( const tripoint & ); // Special actions to be run post-terrain-mod static void done_nothing( const tripoint & ) {} @@ -123,6 +125,8 @@ void done_window_curtains( const tripoint & ); void done_extract_maybe_revert_to_dirt( const tripoint & ); void done_mark_firewood( const tripoint & ); void done_mark_practice_target( const tripoint & ); +void done_ramp_low( const tripoint & ); +void done_ramp_high( const tripoint & ); void failure_standard( const tripoint & ); void failure_deconstruct( const tripoint & ); @@ -159,8 +163,9 @@ static bool has_pre_terrain( const construction &con, const tripoint &p ) static bool has_pre_terrain( const construction &con ) { - for( const tripoint &p : get_map().points_in_radius( g->u.pos(), 1 ) ) { - if( p != g->u.pos() && has_pre_terrain( con, p ) ) { + tripoint avatar_pos = get_player_character().pos(); + for( const tripoint &p : get_map().points_in_radius( avatar_pos, 1 ) ) { + if( p != avatar_pos && has_pre_terrain( con, p ) ) { return true; } } @@ -203,9 +208,11 @@ static void load_available_constructions( std::vector &available, debugmsg( "load_available_constructions called before finalization" ); return; } + avatar &player_character = get_avatar(); for( auto &it : constructions ) { if( it.on_display && ( !hide_unconstructable || - ( can_construct( it ) && player_can_build( g->u, g->u.crafting_inventory(), it ) ) ) ) { + ( can_construct( it ) && + player_can_build( player_character, player_character.crafting_inventory(), it ) ) ) ) { bool already_have_it = false; for( auto &avail_it : available ) { if( avail_it == it.description ) { @@ -240,12 +247,13 @@ static void draw_grid( const catacurses::window &w, const int list_width ) static nc_color construction_color( const std::string &con_name, bool highlight ) { nc_color col = c_dark_gray; - if( g->u.has_trait( trait_DEBUG_HS ) ) { + Character &player_character = get_player_character(); + if( player_character.has_trait( trait_DEBUG_HS ) ) { col = c_white; } else if( can_construct( con_name ) ) { construction *con_first = nullptr; std::vector cons = constructions_by_desc( con_name ); - const inventory &total_inv = g->u.crafting_inventory(); + const inventory &total_inv = player_character.crafting_inventory(); for( auto &con : cons ) { if( con->requirements->can_make_with_inventory( total_inv, is_crafting_component ) ) { con_first = con; @@ -255,7 +263,7 @@ static nc_color construction_color( const std::string &con_name, bool highlight if( con_first != nullptr ) { col = c_white; for( const auto &pr : con_first->required_skills ) { - int s_lvl = g->u.get_skill_level( pr.first ); + int s_lvl = player_character.get_skill_level( pr.first ); if( s_lvl < pr.second ) { col = c_red; } else if( s_lvl < pr.second * 1.25 ) { @@ -325,7 +333,8 @@ construction_id construction_menu( const bool blueprint ) std::vector construct_buffer_breakpoints; int total_project_breakpoints = 0; int current_construct_breakpoint = 0; - const inventory &total_inv = g->u.crafting_inventory(); + avatar &player_character = get_avatar(); + const inventory &total_inv = player_character.crafting_inventory(); input_context ctxt( "CONSTRUCTION" ); ctxt.register_action( "UP", to_translation( "Move cursor up" ) ); @@ -443,9 +452,9 @@ construction_id construction_menu( const bool blueprint ) } else { std::string current_line = _( "Required skills: " ) + enumerate_as_string( current_con->required_skills.begin(), current_con->required_skills.end(), - []( const std::pair &skill ) { + [&player_character]( const std::pair &skill ) { nc_color col; - int s_lvl = g->u.get_skill_level( skill.first ); + int s_lvl = player_character.get_skill_level( skill.first ); if( s_lvl < skill.second ) { col = c_red; } else if( s_lvl < skill.second * 1.25 ) { @@ -767,8 +776,8 @@ construction_id construction_menu( const bool blueprint ) continue; } if( !blueprint ) { - if( player_can_build( g->u, total_inv, constructs[select] ) ) { - if( !player_can_see_to_build( g->u, constructs[select] ) ) { + if( player_can_build( player_character, total_inv, constructs[select] ) ) { + if( !player_can_see_to_build( player_character, constructs[select] ) ) { add_msg( m_info, _( "It is too dark to construct right now." ) ); } else { ui.reset(); @@ -877,8 +886,9 @@ bool can_construct( const construction &con, const tripoint &p ) bool can_construct( const construction &con ) { - for( const tripoint &p : get_map().points_in_radius( g->u.pos(), 1 ) ) { - if( p != g->u.pos() && can_construct( con, p ) ) { + tripoint avatar_pos = get_player_character().pos(); + for( const tripoint &p : get_map().points_in_radius( avatar_pos, 1 ) ) { + if( p != avatar_pos && can_construct( con, p ) ) { return true; } } @@ -887,14 +897,16 @@ bool can_construct( const construction &con ) void place_construction( const std::string &desc ) { - const inventory &total_inv = g->u.crafting_inventory(); + avatar &player_character = get_avatar(); + const inventory &total_inv = player_character.crafting_inventory(); std::vector cons = constructions_by_desc( desc ); std::map valid; map &here = get_map(); - for( const tripoint &p : here.points_in_radius( g->u.pos(), 1 ) ) { + for( const tripoint &p : here.points_in_radius( player_character.pos(), 1 ) ) { for( const auto *con : cons ) { - if( p != g->u.pos() && can_construct( *con, p ) && player_can_build( g->u, total_inv, *con ) ) { + if( p != player_character.pos() && can_construct( *con, p ) && + player_can_build( player_character, total_inv, *con ) ) { valid[ p ] = con; } } @@ -903,8 +915,8 @@ void place_construction( const std::string &desc ) shared_ptr_fast draw_valid = make_shared_fast( [&]() { map &here = get_map(); for( auto &elem : valid ) { - here.drawsq( g->w_terrain, g->u, elem.first, true, false, - g->u.pos() + g->u.view_offset ); + here.drawsq( g->w_terrain, player_character, elem.first, true, false, + player_character.pos() + player_character.view_offset ); } } ); g->add_draw_callback( draw_valid ); @@ -937,21 +949,21 @@ void place_construction( const std::string &desc ) // Special handling for constructions that take place on existing traps. // Basically just don't add the unfinished construction trap. // TODO: handle this cleaner, instead of adding a special case to pit iexamine. - if( here.tr_at( pnt ).loadid == tr_null ) { + if( here.tr_at( pnt ).is_null() ) { here.trap_set( pnt, tr_unfinished_construction ); } // Use up the components for( const auto &it : con.requirements->get_components() ) { - std::list tmp = g->u.consume_items( it, 1, is_crafting_component ); + std::list tmp = player_character.consume_items( it, 1, is_crafting_component ); used.splice( used.end(), tmp ); } pc.components = used; here.partial_con_set( pnt, pc ); for( const auto &it : con.requirements->get_tools() ) { - g->u.consume_tools( it ); + player_character.consume_tools( it ); } - g->u.assign_activity( ACT_BUILD ); - g->u.activity.placement = here.getabs( pnt ); + player_character.assign_activity( ACT_BUILD ); + player_character.activity.placement = here.getabs( pnt ); } void complete_construction( player *p ) @@ -965,7 +977,7 @@ void complete_construction( player *p ) partial_con *pc = here.partial_con_at( terp ); if( !pc ) { debugmsg( "No partial construction found at activity placement in complete_construction()" ); - if( here.tr_at( terp ).loadid == tr_unfinished_construction ) { + if( here.tr_at( terp ) == tr_unfinished_construction ) { here.remove_trap( terp ); } if( p->is_npc() ) { @@ -988,7 +1000,7 @@ void complete_construction( player *p ) // Friendly NPCs gain exp from assisting or watching... // TODO: NPCs watching other NPCs do stuff and learning from it if( p->is_player() ) { - for( auto &elem : g->u.get_crafting_helpers() ) { + for( auto &elem : get_avatar().get_crafting_helpers() ) { if( elem->meets_skill_requirements( built ) ) { add_msg( m_info, _( "%s assists you with the work…" ), elem->name ); } else { @@ -999,7 +1011,7 @@ void complete_construction( player *p ) award_xp( *elem ); } } - if( here.tr_at( terp ).loadid == tr_unfinished_construction ) { + if( here.tr_at( terp ) == tr_unfinished_construction ) { here.remove_trap( terp ); } here.partial_con_remove( terp ); @@ -1055,6 +1067,8 @@ void complete_construction( player *p ) bool construct::check_empty( const tripoint &p ) { map &here = get_map(); + // @TODO should check for *visible* traps only. But calling code must + // first know how to handle constructing on top of an invisible trap! return ( here.has_flag( flag_FLAT, p ) && !here.has_furn( p ) && g->is_empty( p ) && here.tr_at( p ).is_null() && here.i_at( p ).empty() && !here.veh_at( p ) ); @@ -1118,24 +1132,44 @@ bool construct::check_no_trap( const tripoint &p ) return get_map().tr_at( p ).is_null(); } +bool construct::check_ramp_high( const tripoint &p ) +{ + if( check_up_OK( p ) && check_up_OK( p + tripoint_above ) ) { + for( const point &car_d : four_cardinal_directions ) { + // check adjacent points on the z-level above for a completed down ramp + if( get_map().has_flag( TFLAG_RAMP_DOWN, p + car_d + tripoint_above ) ) { + return true; + } + } + } + return false; +} + +bool construct::check_ramp_low( const tripoint &p ) +{ + return check_up_OK( p ) && check_up_OK( p + tripoint_above ); +} + void construct::done_trunk_plank( const tripoint &/*p*/ ) { int num_logs = rng( 2, 3 ); + Character &player_character = get_player_character(); for( int i = 0; i < num_logs; ++i ) { - iuse::cut_log_into_planks( g->u ); + iuse::cut_log_into_planks( player_character ); } } void construct::done_grave( const tripoint &p ) { + Character &player_character = get_player_character(); map &here = get_map(); map_stack its = here.i_at( p ); for( item it : its ) { if( it.is_corpse() ) { if( it.get_corpse_name().empty() ) { if( it.get_mtype()->has_flag( MF_HUMAN ) ) { - if( g->u.has_trait( trait_SPIRITUAL ) ) { - g->u.add_morale( MORALE_FUNERAL, 50, 75, 1_days, 1_hours ); + if( player_character.has_trait( trait_SPIRITUAL ) ) { + player_character.add_morale( MORALE_FUNERAL, 50, 75, 1_days, 1_hours ); add_msg( m_good, _( "You feel relieved after providing last rites for this human being, whose name is lost in the Cataclysm." ) ); } else { @@ -1143,8 +1177,8 @@ void construct::done_grave( const tripoint &p ) } } } else { - if( g->u.has_trait( trait_SPIRITUAL ) ) { - g->u.add_morale( MORALE_FUNERAL, 50, 75, 1_days, 1_hours ); + if( player_character.has_trait( trait_SPIRITUAL ) ) { + player_character.add_morale( MORALE_FUNERAL, 50, 75, 1_days, 1_hours ); add_msg( m_good, _( "You feel sadness, but also relief after providing last rites for %s, whose name you will keep in your memory." ), it.get_corpse_name() ); @@ -1155,11 +1189,12 @@ void construct::done_grave( const tripoint &p ) } } g->events().send( - g->u.getID(), it.get_mtype()->id, it.get_corpse_name() ); + player_character.getID(), it.get_mtype()->id, it.get_corpse_name() ); } } - if( g->u.has_quality( qual_CUT ) ) { - iuse::handle_ground_graffiti( g->u, nullptr, _( "Inscribe something on the grave?" ), p ); + if( player_character.has_quality( qual_CUT ) ) { + iuse::handle_ground_graffiti( player_character, nullptr, _( "Inscribe something on the grave?" ), + p ); } else { add_msg( m_neutral, _( "Unfortunately you don't have anything sharp to place an inscription on the grave." ) ); @@ -1208,7 +1243,7 @@ void construct::done_vehicle( const tripoint &p ) return; } veh->name = name; - veh->install_part( point_zero, vpart_from_item( g->u.lastconsumed ) ); + veh->install_part( point_zero, vpart_from_item( get_avatar().lastconsumed ) ); // Update the vehicle cache immediately, // or the vehicle will be invisible for the first couple of turns. @@ -1225,6 +1260,21 @@ void construct::done_deconstruct( const tripoint &p ) add_msg( m_info, _( "That %s can not be disassembled!" ), f.name() ); return; } + if( f.id.id() == furn_str_id( "f_console_broken" ) ) { + if( g->u.get_skill_level( skill_electronics ) >= 1 ) { + g->u.practice( skill_electronics, 20, 4 ); + } + } + if( f.id.id() == furn_str_id( "f_console" ) ) { + if( g->u.get_skill_level( skill_electronics ) >= 1 ) { + g->u.practice( skill_electronics, 40, 8 ); + } + } + if( f.id.id() == furn_str_id( "f_machinery_electronic" ) ) { + if( g->u.get_skill_level( skill_electronics ) >= 1 ) { + g->u.practice( skill_electronics, 40, 8 ); + } + } if( f.deconstruct.furn_set.str().empty() ) { here.furn_set( p, f_null ); } else { @@ -1252,14 +1302,15 @@ void construct::done_deconstruct( const tripoint &p ) } done_deconstruct( top ); } + avatar &player_character = get_avatar(); if( t.id.id() == t_console_broken ) { - if( g->u.get_skill_level( skill_electronics ) >= 1 ) { - g->u.practice( skill_electronics, 20, 4 ); + if( player_character.get_skill_level( skill_electronics ) >= 1 ) { + player_character.practice( skill_electronics, 20, 4 ); } } if( t.id.id() == t_console ) { - if( g->u.get_skill_level( skill_electronics ) >= 1 ) { - g->u.practice( skill_electronics, 40, 8 ); + if( player_character.get_skill_level( skill_electronics ) >= 1 ) { + player_character.practice( skill_electronics, 40, 8 ); } } here.ter_set( p, t.deconstruct.ter_set ); @@ -1273,9 +1324,10 @@ static void unroll_digging( const int numer_of_2x4s ) // refund components! item rope( "rope_30" ); map &here = get_map(); - here.add_item_or_charges( g->u.pos(), rope ); + tripoint avatar_pos = get_player_character().pos(); + here.add_item_or_charges( avatar_pos, rope ); // presuming 2x4 to conserve lumber. - here.spawn_item( g->u.pos(), itype_2x4, numer_of_2x4s ); + here.spawn_item( avatar_pos, itype_2x4, numer_of_2x4s ); } void construct::done_digormine_stair( const tripoint &p, bool dig ) @@ -1287,13 +1339,15 @@ void construct::done_digormine_stair( const tripoint &p, bool dig ) tmpmap.load( tripoint( pos_sm.xy(), pos_sm.z - 1 ), false ); const tripoint local_tmp = tmpmap.getlocal( abs_pos ); - bool dig_muts = g->u.has_trait( trait_PAINRESIST_TROGLO ) || g->u.has_trait( trait_STOCKY_TROGLO ); + Character &player_character = get_player_character(); + bool dig_muts = player_character.has_trait( trait_PAINRESIST_TROGLO ) || + player_character.has_trait( trait_STOCKY_TROGLO ); int no_mut_penalty = dig_muts ? 10 : 0; int mine_penalty = dig ? 0 : 10; - g->u.mod_stored_nutr( 5 + mine_penalty + no_mut_penalty ); - g->u.mod_thirst( 5 + mine_penalty + no_mut_penalty ); - g->u.mod_fatigue( 10 + mine_penalty + no_mut_penalty ); + player_character.mod_stored_nutr( 5 + mine_penalty + no_mut_penalty ); + player_character.mod_thirst( 5 + mine_penalty + no_mut_penalty ); + player_character.mod_fatigue( 10 + mine_penalty + no_mut_penalty ); if( tmpmap.ter( local_tmp ) == t_lava ) { if( !( query_yn( _( "The rock feels much warmer than normal. Proceed?" ) ) ) ) { @@ -1357,12 +1411,14 @@ void construct::done_mine_upstair( const tripoint &p ) return; } - bool dig_muts = g->u.has_trait( trait_PAINRESIST_TROGLO ) || g->u.has_trait( trait_STOCKY_TROGLO ); + Character &player_character = get_player_character(); + bool dig_muts = player_character.has_trait( trait_PAINRESIST_TROGLO ) || + player_character.has_trait( trait_STOCKY_TROGLO ); int no_mut_penalty = dig_muts ? 15 : 0; - g->u.mod_stored_nutr( 20 + no_mut_penalty ); - g->u.mod_thirst( 20 + no_mut_penalty ); - g->u.mod_fatigue( 25 + no_mut_penalty ); + player_character.mod_stored_nutr( 20 + no_mut_penalty ); + player_character.mod_thirst( 20 + no_mut_penalty ); + player_character.mod_fatigue( 25 + no_mut_penalty ); add_msg( _( "You drill out a passage, heading for the surface." ) ); here.ter_set( p.xy(), t_stairs_up ); // There's the bottom half @@ -1380,13 +1436,13 @@ void construct::done_wood_stairs( const tripoint &p ) void construct::done_window_curtains( const tripoint & ) { map &here = get_map(); + tripoint avatar_pos = get_player_character().pos(); // copied from iexamine::curtains - here.spawn_item( g->u.pos(), itype_nail, 1, 4 ); - here.spawn_item( g->u.pos(), itype_sheet, 2 ); - here.spawn_item( g->u.pos(), itype_stick ); - here.spawn_item( g->u.pos(), itype_string_36 ); - g->u.add_msg_if_player( - _( "After boarding up the window the curtains and curtain rod are left." ) ); + here.spawn_item( avatar_pos, itype_nail, 1, 4 ); + here.spawn_item( avatar_pos, itype_sheet, 2 ); + here.spawn_item( avatar_pos, itype_stick ); + here.spawn_item( avatar_pos, itype_string_36 ); + add_msg( _( "After boarding up the window the curtains and curtain rod are left." ) ); } void construct::done_extract_maybe_revert_to_dirt( const tripoint &p ) @@ -1416,6 +1472,18 @@ void construct::done_mark_practice_target( const tripoint &p ) get_map().trap_set( p, tr_practice_target ); } +void construct::done_ramp_low( const tripoint &p ) +{ + const tripoint top = p + tripoint_above; + get_map().ter_set( top, ter_id( "t_ramp_down_low" ) ); +} + +void construct::done_ramp_high( const tripoint &p ) +{ + const tripoint top = p + tripoint_above; + get_map().ter_set( top, ter_id( "t_ramp_down_high" ) ); +} + void construct::failure_standard( const tripoint & ) { add_msg( m_info, _( "You cannot build there!" ) ); @@ -1519,7 +1587,9 @@ void load_construction( const JsonObject &jo ) { "check_empty_up_OK", construct::check_empty_up_OK }, { "check_up_OK", construct::check_up_OK }, { "check_down_OK", construct::check_down_OK }, - { "check_no_trap", construct::check_no_trap } + { "check_no_trap", construct::check_no_trap }, + { "check_ramp_low", construct::check_ramp_low }, + { "check_ramp_high", construct::check_ramp_high } } }; static const std::map> post_special_map = {{ @@ -1535,7 +1605,9 @@ void load_construction( const JsonObject &jo ) { "done_window_curtains", construct::done_window_curtains }, { "done_extract_maybe_revert_to_dirt", construct::done_extract_maybe_revert_to_dirt }, { "done_mark_firewood", construct::done_mark_firewood }, - { "done_mark_practice_target", construct::done_mark_practice_target } + { "done_mark_practice_target", construct::done_mark_practice_target }, + { "done_ramp_low", construct::done_ramp_low }, + { "done_ramp_high", construct::done_ramp_high } } }; std::map> explain_fail_map; @@ -1637,7 +1709,7 @@ int construction::adjusted_time() const int final_time = time; int assistants = 0; - for( auto &elem : g->u.get_crafting_helpers() ) { + for( auto &elem : get_avatar().get_crafting_helpers() ) { if( elem->meets_skill_requirements( *this ) ) { assistants++; } diff --git a/src/consumption.cpp b/src/consumption.cpp index 2e313ed0d7406..d2d950e370eee 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -538,11 +538,15 @@ time_duration Character::vitamin_rate( const vitamin_id &vit ) const int Character::vitamin_mod( const vitamin_id &vit, int qty, bool capped ) { - auto it = vitamin_levels.find( vit ); - if( it == vitamin_levels.end() ) { + if( !vit.is_valid() ) { + debugmsg( "Vitamin with id %s does not exist, and cannot be modified", vit.str() ); return 0; } - const auto &v = it->first.obj(); + // What's going on here? Emplace returns either an iterator to the inserted + // item or, if it already exists, an iterator to the (unchanged) extant item + // (Okay, technically it returns a pair, the iterator is what we want) + auto it = vitamin_levels.emplace( vit, 0 ).first; + const vitamin &v = *it->first; if( qty > 0 ) { // Accumulations can never occur from food sources @@ -1436,7 +1440,7 @@ bool Character::feed_furnace_with( item &it ) return false; } if( it.is_favorite && - !g->u.query_yn( _( "Are you sure you want to eat your favorited %s?" ), it.tname() ) ) { + !get_avatar().query_yn( _( "Are you sure you want to eat your favorited %s?" ), it.tname() ) ) { return false; } diff --git a/src/coordinates.h b/src/coordinates.h index 3aaff85dc9e5d..b4abca602e448 100644 --- a/src/coordinates.h +++ b/src/coordinates.h @@ -8,6 +8,482 @@ #include "enums.h" #include "game_constants.h" #include "point.h" +#include "debug.h" + +namespace coords +{ + +enum class scale { + map_square, + submap, + overmap_terrain, + segment, + overmap, + vehicle +}; + +constexpr scale ms = scale::map_square; +constexpr scale sm = scale::submap; +constexpr scale omt = scale::overmap_terrain; +constexpr scale seg = scale::segment; +constexpr scale om = scale::overmap; + +constexpr int map_squares_per( scale s ) +{ + static_assert( SEEX == SEEY, "we assume submaps are square" ); + static_assert( OMAPX == OMAPY, "we assume overmaps are square" ); + + switch( s ) { + case scale::map_square: + return 1; + case scale::submap: + return SEEX; + case scale::overmap_terrain: + return SEEX * 2; + case scale::segment: + return SEG_SIZE * map_squares_per( scale::overmap_terrain ); + case scale::overmap: + return OMAPX * map_squares_per( scale::overmap_terrain ); + default: + constexpr_fatal( 0, "Requested scale of %d", s ); + } +} + +enum class origin { + relative, // this is a special origin that can be added to any other + abs, // the global absolute origin for the entire game + submap, // from corner of submap + overmap_terrain, // from corner of overmap_terrain + overmap, // from corner of overmap +}; + +constexpr origin origin_from_scale( scale s ) +{ + switch( s ) { + case scale::submap: + return origin::submap; + case scale::overmap_terrain: + return origin::overmap_terrain; + case scale::overmap: + return origin::overmap; + default: + constexpr_fatal( origin::abs, "Requested origin for scale %d", s ); + } +} + +// A generic coordinate-type-safe point. +// Point should be the underlying representation type (either point or +// tripoint). +// Scale and Origin define the coordinate system for the point. +template +class coord_point +{ + public: + static constexpr int dimension = Point::dimension; + + constexpr coord_point() = default; + explicit constexpr coord_point( const Point &p ) : + raw_( p ) + {} + template + constexpr coord_point( T x, T y ) : raw_( x, y ) {} + template + constexpr coord_point( T x, T y, T z ) : raw_( x, y, z ) {} + template + constexpr coord_point( const coord_point &xy, T z ) : + raw_( xy.raw(), z ) + {} + + constexpr Point &raw() { + return raw_; + } + constexpr const Point &raw() const { + return raw_; + } + + constexpr auto &x() { + return raw_.x; + } + constexpr auto x() const { + return raw_.x; + } + constexpr auto &y() { + return raw_.y; + } + constexpr auto y() const { + return raw_.y; + } + constexpr auto xy() const { + return coord_point( raw_.xy() ); + } + constexpr auto &z() { + return raw_.z; + } + constexpr auto z() const { + return raw_.z; + } + + std::string to_string() const { + return raw_.to_string(); + } + + void serialize( JsonOut &jsout ) const { + raw().serialize( jsout ); + } + void deserialize( JsonIn &jsin ) { + raw().deserialize( jsin ); + } + + coord_point &operator+=( const coord_point &r ) { + raw_ += r.raw(); + return *this; + } + + coord_point &operator-=( const coord_point &r ) { + raw_ -= r.raw(); + return *this; + } + + coord_point &operator+=( const point &r ) { + raw_ += r; + return *this; + } + + coord_point &operator-=( const point &r ) { + raw_ -= r; + return *this; + } + + coord_point &operator+=( const tripoint &r ) { + raw_ += r; + return *this; + } + + coord_point &operator-=( const tripoint &r ) { + raw_ -= r; + return *this; + } + + friend inline coord_point operator+( const coord_point &l, const point &r ) { + return coord_point( l.raw() + r ); + } + + friend inline coord_point operator+( const coord_point &l, const tripoint &r ) { + return coord_point( l.raw() + r ); + } + + friend inline coord_point operator-( const coord_point &l, const point &r ) { + return coord_point( l.raw() - r ); + } + + friend inline coord_point operator-( const coord_point &l, const tripoint &r ) { + return coord_point( l.raw() - r ); + } + private: + Point raw_; +}; + +template +constexpr inline bool operator==( const coord_point &l, + const coord_point &r ) +{ + return l.raw() == r.raw(); +} + +template +constexpr inline bool operator!=( const coord_point &l, + const coord_point &r ) +{ + return l.raw() != r.raw(); +} + +template +constexpr inline bool operator<( const coord_point &l, + const coord_point &r ) +{ + return l.raw() < r.raw(); +} + +template +constexpr inline auto operator+( + const coord_point &l, + const coord_point &r ) +{ + using PointResult = decltype( PointL() + PointR() ); + return coord_point( l.raw() + r.raw() ); +} + +template < typename PointL, typename PointR, origin OriginR, scale Scale, + // enable_if to prevent ambiguity with above when both args are + // relative + typename = std::enable_if_t < OriginR != origin::relative >> +constexpr inline auto operator+( + const coord_point &l, + const coord_point &r ) +{ + using PointResult = decltype( PointL() + PointR() ); + return coord_point( l.raw() + r.raw() ); +} + +template +constexpr inline auto operator-( + const coord_point &l, + const coord_point &r ) +{ + using PointResult = decltype( PointL() + PointR() ); + return coord_point( l.raw() - r.raw() ); +} + +template < typename PointL, typename PointR, origin Origin, scale Scale, + // enable_if to prevent ambiguity with above when both args are + // relative + typename = std::enable_if_t < Origin != origin::relative >> +constexpr inline auto operator-( + const coord_point &l, + const coord_point &r ) +{ + using PointResult = decltype( PointL() + PointR() ); + return coord_point( l.raw() - r.raw() ); +} + +// Only relative points can be multiplied by a constant +template +constexpr inline coord_point operator*( + int l, const coord_point &r ) +{ + return coord_point( l * r.raw() ); +} + +template +constexpr inline coord_point operator*( + const coord_point &r, int l ) +{ + return coord_point( r.raw() * l ); +} + +template +inline std::ostream &operator<<( std::ostream &os, const coord_point &p ) +{ + return os << p.raw(); +} + +template +struct project_to_impl; + +template +struct project_to_impl { + template + coord_point operator()( + const coord_point &src ) { + return coord_point( multiply_xy( src.raw(), ScaleUp ) ); + } +}; + +template +struct project_to_impl<0, ScaleDown, ResultScale> { + template + coord_point operator()( + const coord_point &src ) { + return coord_point( + divide_xy_round_to_minus_infinity( src.raw(), ScaleDown ) ); + } +}; + +template +inline coord_point project_to( + const coord_point &src ) +{ + constexpr int scale_down = map_squares_per( ResultScale ) / map_squares_per( SourceScale ); + constexpr int scale_up = map_squares_per( SourceScale ) / map_squares_per( ResultScale ); + return project_to_impl()( src ); +} + +template +struct quotient_remainder_helper { + constexpr static origin RemainderOrigin = origin_from_scale( CoarseScale ); + using quotient_type = coord_point; + using quotient_type_tripoint = coord_point; + using remainder_type = coord_point; + using remainder_type_tripoint = coord_point; +}; + +template +struct quotient_remainder_point { + using helper = quotient_remainder_helper; + using quotient_type = typename helper::quotient_type; + using remainder_type = typename helper::remainder_type; + + quotient_type quotient; + remainder_type remainder; + + // For assigning to std::tie( q, r ); + operator std::tuple() { + return std::tie( quotient, remainder ); + } +}; + +template +struct quotient_remainder_tripoint { + using helper = quotient_remainder_helper; + using quotient_type = typename helper::quotient_type; + using quotient_type_tripoint = typename helper::quotient_type_tripoint; + using remainder_type = typename helper::remainder_type; + using remainder_type_tripoint = typename helper::remainder_type_tripoint; + + // Annoyingly, for the conversion operators below to work correctly, we + // need to have point and tripoint version of both quotient and remainder + // ready here, so that we can take references to any of them. + // Luckily the entire lifetime of this struct should be pretty short, so + // the compiler can do its magic to remove the overhead of initializing the + // ones that don't actually get used. + quotient_type quotient; + remainder_type remainder; + quotient_type_tripoint quotient_tripoint; + remainder_type_tripoint remainder_tripoint; + + // For assigning to std::tie( q, r ); + // Exactly one of the two resulting types should be a tripoint, so that the + // z-coordinate doesn't get duplicated. + operator std::tuple() { + return std::tie( quotient_tripoint, remainder ); + } + operator std::tuple() { + return std::tie( quotient, remainder_tripoint ); + } +}; + +// project_remain returns a helper struct, intended to be used with std::tie +// to pull out the two components of the result. +// For exmaple, when splitting a point: +// point_abs_sm val; +// point_abs_om quotient; +// point_om_sm remainder; +// std::tie( quotient, remainder ) = project_remain( val ); +// If passing a tripoint to project_remain, you must choose exactly one of the +// quotient or remainder to get the z coordinate. Both of these should work: +// tripoint_abs_sm val; +// tripoint_abs_om quotient; +// point_om_sm remainder; +// std::tie( quotient, remainder ) = project_remain( val ); +// +// point_abs_om quotient; +// tripoint_om_sm remainder; +// std::tie( quotient, remainder ) = project_remain( val ); +template +inline quotient_remainder_point project_remain( + const coord_point &src ) +{ + constexpr int ScaleDown = map_squares_per( ResultScale ) / map_squares_per( SourceScale ); + static_assert( ScaleDown > 0, "You can only project to coarser coordinate systems" ); + constexpr static origin RemainderOrigin = origin_from_scale( ResultScale ); + coord_point quotient( + divide_xy_round_to_minus_infinity( src.raw(), ScaleDown ) ); + coord_point remainder( + src.raw() - quotient.raw() * ScaleDown ); + + return { quotient, remainder }; +} + +template +inline quotient_remainder_tripoint project_remain( + const coord_point &src ) +{ + quotient_remainder_point point_result = + project_remain( src.xy() ); + return { point_result.quotient, point_result.remainder, + { point_result.quotient, src.z() }, { point_result.remainder, src.z() } }; +} + +template +inline auto project_combine( + const coord_point &coarse, + const coord_point &fine ) +{ + static_assert( origin_from_scale( CoarseScale ) == FineOrigin, + "given point types are not compatible for combination" ); + static_assert( PointL::dimension != 3 || PointR::dimension != 3, + "two tripoints should not be combined; it's unclear how to handle z" ); + using PointResult = decltype( PointL() + PointR() ); + const coord_point refined_coarse = + project_to( coarse ); + return coord_point( refined_coarse.raw() + fine.raw() ); +} + +} // namespace coords + +namespace std +{ + +template +struct hash> { + std::size_t operator()( const coords::coord_point &p ) const { + const hash h{}; + return h( p.raw() ); + } +}; + +} // namespace std + +/** Typedefs for point types with coordinate mnemonics. + * + * Each name is of the form (tri)point__ where tells you the + * context in which the point has meaning, and tells you what one unit + * of the point means. + * + * For example: + * point_omt_ms is the position of a map square within an overmap terrain. + * tripoint_rel_sm is a relative tripoint submap offset. + */ +/*@{*/ +using point_rel_ms = coords::coord_point; +using point_abs_ms = coords::coord_point; +using point_sm_ms = coords::coord_point; +using point_omt_ms = coords::coord_point; +using point_abs_sm = coords::coord_point; +using point_omt_sm = coords::coord_point; +using point_om_sm = coords::coord_point; +using point_abs_omt = coords::coord_point; +using point_om_omt = coords::coord_point; +using point_abs_seg = coords::coord_point; +using point_abs_om = coords::coord_point; + +using tripoint_rel_ms = coords::coord_point; +using tripoint_abs_ms = coords::coord_point; +using tripoint_sm_ms = coords::coord_point; +using tripoint_omt_ms = coords::coord_point; +using tripoint_abs_sm = coords::coord_point; +using tripoint_om_sm = coords::coord_point; +using tripoint_abs_omt = coords::coord_point; +using tripoint_abs_seg = coords::coord_point; +using tripoint_abs_om = coords::coord_point; +/*@}*/ + +using coords::project_to; +using coords::project_remain; +using coords::project_combine; + +template +std::vector> + closest_points_first( const coords::coord_point &loc, + int min_dist, int max_dist ) +{ + std::vector raw_result = closest_points_first( loc.raw(), min_dist, max_dist ); + std::vector> result; + result.reserve( raw_result.size() ); + std::transform( raw_result.begin(), raw_result.end(), std::back_inserter( result ), + []( const Point & p ) { + return coords::coord_point( p ); + } ); + return result; +} +template +std::vector> + closest_points_first( const coords::coord_point &loc, + int max_dist ) +{ + return closest_points_first( loc, 0, max_dist ); +} /* find appropriate subdivided coordinates for absolute tile coordinate. * This is less obvious than one might think, for negative coordinates, so this diff --git a/src/craft_command.cpp b/src/craft_command.cpp index dccb358556af3..5ab051b448607 100644 --- a/src/craft_command.cpp +++ b/src/craft_command.cpp @@ -127,6 +127,9 @@ void craft_command::execute( const tripoint &new_loc ) "Start crafting anyway?" ), rec->result_name() ) ) { return; } + } else if( !rec->character_has_required_proficiencies( *crafter ) ) { + popup( _( "You don't have the required proficiencies to craft this!" ) ); + return; } else { debugmsg( "Tried to start craft without sufficient charges" ); return; diff --git a/src/craft_command.h b/src/craft_command.h index a99e223670faa..f05f6e1362fde 100644 --- a/src/craft_command.h +++ b/src/craft_command.h @@ -14,7 +14,7 @@ class JsonIn; class JsonOut; class inventory; class item; -class player; +class Character; template struct enum_traits; /** @@ -66,7 +66,7 @@ class craft_command public: /** Instantiates an empty craft_command, which can't be executed. */ craft_command() = default; - craft_command( const recipe *to_make, int batch_size, bool is_long, player *crafter, + craft_command( const recipe *to_make, int batch_size, bool is_long, Character *crafter, const tripoint &loc = tripoint_zero ) : rec( to_make ), batch_size( batch_size ), longcraft( is_long ), crafter( crafter ), loc( loc ) {} @@ -101,7 +101,7 @@ class craft_command */ bool longcraft = false; // This is mainly here for maintainability reasons. - player *crafter; + Character *crafter; recipe_filter_flags flags = recipe_filter_flags::none; diff --git a/src/crafting.cpp b/src/crafting.cpp index a47f4c21cd3b4..8a3f3606d6afb 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -107,7 +107,7 @@ static const std::string flag_VARSIZE( "VARSIZE" ); class basecamp; -static bool crafting_allowed( const player &p, const recipe &rec ) +static bool crafting_allowed( const Character &p, const recipe &rec ) { if( p.morale_crafting_speed_multiplier( rec ) <= 0.0f ) { add_msg( m_info, _( "Your morale is too low to craft such a difficult thing…" ) ); @@ -126,7 +126,7 @@ static bool crafting_allowed( const player &p, const recipe &rec ) return true; } -float player::lighting_craft_speed_multiplier( const recipe &rec ) const +float Character::lighting_craft_speed_multiplier( const recipe &rec ) const { // negative is bright, 0 is just bright enough, positive is dark, +7.0f is pitch black float darkness = fine_detail_vision_mod() - 4.0f; @@ -154,7 +154,7 @@ float player::lighting_craft_speed_multiplier( const recipe &rec ) const return 0.0f; // it's dark and you could craft this if you had more skill } -float player::morale_crafting_speed_multiplier( const recipe &rec ) const +float Character::morale_crafting_speed_multiplier( const recipe &rec ) const { int morale = get_morale_level(); if( morale >= 0 ) { @@ -241,7 +241,7 @@ static float workbench_crafting_speed_multiplier( const item &craft, const tripo return multiplier; } -float player::crafting_speed_multiplier( const recipe &rec, bool in_progress ) const +float Character::crafting_speed_multiplier( const recipe &rec, bool in_progress ) const { const float result = morale_crafting_speed_multiplier( rec ) * lighting_craft_speed_multiplier( rec ); @@ -257,7 +257,7 @@ float player::crafting_speed_multiplier( const recipe &rec, bool in_progress ) c return result; } -float player::crafting_speed_multiplier( const item &craft, const tripoint &loc ) const +float Character::crafting_speed_multiplier( const item &craft, const tripoint &loc ) const { if( !craft.is_craft() ) { debugmsg( "Can't calculate crafting speed multiplier of non-craft '%s'", craft.tname() ); @@ -314,7 +314,7 @@ bool Character::has_morale_to_craft() const return get_morale_level() >= -50; } -void player::craft( const tripoint &loc ) +void Character::craft( const tripoint &loc ) { int batch_size = 0; const recipe *rec = select_crafting_recipe( batch_size ); @@ -325,7 +325,7 @@ void player::craft( const tripoint &loc ) } } -void player::recraft( const tripoint &loc ) +void Character::recraft( const tripoint &loc ) { if( lastrecipe.str().empty() ) { popup( _( "Craft something first" ) ); @@ -334,7 +334,7 @@ void player::recraft( const tripoint &loc ) } } -void player::long_craft( const tripoint &loc ) +void Character::long_craft( const tripoint &loc ) { int batch_size = 0; const recipe *rec = select_crafting_recipe( batch_size ); @@ -345,7 +345,7 @@ void player::long_craft( const tripoint &loc ) } } -bool player::making_would_work( const recipe_id &id_to_make, int batch_size ) +bool Character::making_would_work( const recipe_id &id_to_make, int batch_size ) { const auto &making = *id_to_make; if( !( making && crafting_allowed( *this, making ) ) ) { @@ -363,9 +363,9 @@ bool player::making_would_work( const recipe_id &id_to_make, int batch_size ) return check_eligible_containers_for_crafting( making, batch_size ); } -int player::available_assistant_count( const recipe &rec ) const +int Character::available_assistant_count( const recipe &rec ) const +// NPCs around you should assist in batch production if they have the skills { - // NPCs around you should assist in batch production if they have the skills // TODO: Cache them in activity, include them in modifier calculations const auto helpers = get_crafting_helpers(); return std::count_if( helpers.begin(), helpers.end(), @@ -374,20 +374,20 @@ int player::available_assistant_count( const recipe &rec ) const } ); } -int player::base_time_to_craft( const recipe &rec, int batch_size ) const +int Character::base_time_to_craft( const recipe &rec, int batch_size ) const { const size_t assistants = available_assistant_count( rec ); - return rec.batch_time( batch_size, 1.0f, assistants ); + return rec.batch_time( *this, batch_size, 1.0f, assistants ); } -int player::expected_time_to_craft( const recipe &rec, int batch_size, bool in_progress ) const +int Character::expected_time_to_craft( const recipe &rec, int batch_size, bool in_progress ) const { const size_t assistants = available_assistant_count( rec ); float modifier = crafting_speed_multiplier( rec, in_progress ); - return rec.batch_time( batch_size, modifier, assistants ); + return rec.batch_time( *this, batch_size, modifier, assistants ); } -bool player::check_eligible_containers_for_crafting( const recipe &rec, int batch_size ) const +bool Character::check_eligible_containers_for_crafting( const recipe &rec, int batch_size ) const { std::vector conts = get_eligible_containers_for_crafting(); const std::vector res = rec.create_results( batch_size ); @@ -450,7 +450,7 @@ static bool is_container_eligible_for_crafting( const item &cont, bool allow_buc return false; } -std::vector player::get_eligible_containers_for_crafting() const +std::vector Character::get_eligible_containers_for_crafting() const { std::vector conts; @@ -472,7 +472,7 @@ std::vector player::get_eligible_containers_for_crafting() const map &here = get_map(); // get all potential containers within PICKUP_RANGE tiles including vehicles - for( const tripoint &loc : closest_tripoints_first( pos(), PICKUP_RANGE ) ) { + for( const tripoint &loc : closest_points_first( pos(), PICKUP_RANGE ) ) { // can not reach this -> can not access its contents if( pos() != loc && !here.clear_path( pos(), loc, PICKUP_RANGE, 1, 100 ) ) { continue; @@ -498,7 +498,7 @@ std::vector player::get_eligible_containers_for_crafting() const return conts; } -bool player::can_make( const recipe *r, int batch_size ) +bool Character::can_make( const recipe *r, int batch_size ) { const inventory &crafting_inv = crafting_inventory(); @@ -506,16 +506,24 @@ bool player::can_make( const recipe *r, int batch_size ) return false; } + if( !r->character_has_required_proficiencies( *this ) ) { + return false; + } + return r->deduped_requirements().can_make_with_inventory( crafting_inv, r->get_component_filter(), batch_size ); } -bool player::can_start_craft( const recipe *rec, recipe_filter_flags flags, int batch_size ) +bool Character::can_start_craft( const recipe *rec, recipe_filter_flags flags, int batch_size ) { if( !rec ) { return false; } + if( !rec->character_has_required_proficiencies( *this ) ) { + return false; + } + const inventory &inv = crafting_inventory(); return rec->deduped_requirements().can_make_with_inventory( inv, rec->get_component_filter( flags ), batch_size, craft_flags::start_only ); @@ -573,18 +581,18 @@ void Character::invalidate_crafting_inventory() cached_time = calendar::before_time_starts; } -void player::make_craft( const recipe_id &id_to_make, int batch_size, const tripoint &loc ) +void Character::make_craft( const recipe_id &id_to_make, int batch_size, const tripoint &loc ) { make_craft_with_command( id_to_make, batch_size, false, loc ); } -void player::make_all_craft( const recipe_id &id_to_make, int batch_size, const tripoint &loc ) +void Character::make_all_craft( const recipe_id &id_to_make, int batch_size, const tripoint &loc ) { make_craft_with_command( id_to_make, batch_size, true, loc ); } -void player::make_craft_with_command( const recipe_id &id_to_make, int batch_size, bool is_long, - const tripoint &loc ) +void Character::make_craft_with_command( const recipe_id &id_to_make, int batch_size, bool is_long, + const tripoint &loc ) { const auto &recipe_to_make = *id_to_make; @@ -622,7 +630,7 @@ static void set_components( std::list &components, const std::list & } } -static cata::optional wield_craft( player &p, item &craft ) +static cata::optional wield_craft( Character &p, item &craft ) { if( p.wield( craft ) ) { if( p.weapon.invlet ) { @@ -635,7 +643,7 @@ static cata::optional wield_craft( player &p, item &craft ) return cata::nullopt; } -static item *set_item_inventory( player &p, item &newit ) +static item *set_item_inventory( Character &p, item &newit ) { item *ret_val = nullptr; if( newit.made_of( phase_id::LIQUID ) ) { @@ -663,7 +671,7 @@ static item *set_item_inventory( player &p, item &newit ) static item_location set_item_map( const tripoint &loc, item &newit ) { // Includes loc - for( const tripoint &tile : closest_tripoints_first( loc, 2 ) ) { + for( const tripoint &tile : closest_points_first( loc, 2 ) ) { // Pass false to disallow overflow, null_item_reference indicates failure. item *it_on_map = &get_map().add_item_or_charges( tile, newit, false ); if( it_on_map != &null_item_reference() ) { @@ -677,7 +685,7 @@ static item_location set_item_map( const tripoint &loc, item &newit ) /** * Set an item on the map or in a vehicle and return the new location */ -static item_location set_item_map_or_vehicle( const player &p, const tripoint &loc, item &newit ) +static item_location set_item_map_or_vehicle( const Character &p, const tripoint &loc, item &newit ) { map &here = get_map(); if( const cata::optional vp = here.veh_at( loc ).part_with_feature( "CARGO", @@ -718,7 +726,7 @@ static item_location set_item_map_or_vehicle( const player &p, const tripoint &l } } -void player::start_craft( craft_command &command, const tripoint &loc ) +void Character::start_craft( craft_command &command, const tripoint &loc ) { if( command.empty() ) { debugmsg( "Attempted to start craft with empty command" ); @@ -733,7 +741,7 @@ void player::start_craft( craft_command &command, const tripoint &loc ) // In case we were wearing something just consumed if( !craft.components.empty() ) { - reset_encumbrance(); + calc_encumbrance(); } item_location craft_in_world; @@ -786,8 +794,9 @@ void player::start_craft( craft_command &command, const tripoint &loc ) uilist amenu; amenu.text = string_format( pgettext( "in progress craft", "What to do with the %s?" ), craft.display_name() ); - amenu.addentry( WIELD_CRAFT, !weapon.has_flag( flag_NO_UNWIELD ), '1', - _( "Dispose of your wielded %s and start working." ), weapon.tname() ); + + amenu.addentry( WIELD_CRAFT, can_unwield( weapon ).success(), + '1', _( "Dispose of your wielded %s and start working." ), weapon.tname() ); amenu.addentry( DROP_CRAFT, true, '2', _( "Put it down and start working." ) ); const bool can_stash = can_pickVolume( craft ) && can_pickWeight( craft, !get_option( "DANGEROUS_PICKUPS" ) ); @@ -801,7 +810,7 @@ void player::start_craft( craft_command &command, const tripoint &loc ) if( cata::optional it_loc = wield_craft( *this, craft ) ) { craft_in_world = *it_loc; } else { - // This almost certianly shouldn't happen + // This almost certainly shouldn't happen put_into_vehicle_or_drop( *this, item_drop_reason::tumbling, {craft} ); } break; @@ -840,7 +849,7 @@ void player::start_craft( craft_command &command, const tripoint &loc ) craft.tname() ); } -void player::craft_skill_gain( const item &craft, const int &multiplier ) +void Character::craft_skill_gain( const item &craft, const int &multiplier ) { if( !craft.is_craft() ) { debugmsg( "craft_skill_check() called on non-craft '%s.' Aborting.", craft.tname() ); @@ -885,7 +894,7 @@ void player::craft_skill_gain( const item &craft, const int &multiplier ) } } -double player::crafting_success_roll( const recipe &making ) const +double Character::crafting_success_roll( const recipe &making ) const { int secondary_dice = 0; int secondary_difficulty = 0; @@ -957,7 +966,14 @@ double player::crafting_success_roll( const recipe &making ) const return 2; } - return skill_roll / diff_roll; + float prof_multiplier = 1.0f; + for( const recipe_proficiency &recip : making.proficiencies ) { + if( !recip.required && !has_proficiency( recip.id ) ) { + prof_multiplier *= recip.fail_multiplier; + } + } + + return ( skill_roll / diff_roll ) * prof_multiplier; } int item::get_next_failure_point() const @@ -969,7 +985,7 @@ int item::get_next_failure_point() const return craft_data_->next_failure_point >= 0 ? craft_data_->next_failure_point : INT_MAX; } -void item::set_next_failure_point( const player &crafter ) +void item::set_next_failure_point( const Character &crafter ) { if( !is_craft() ) { debugmsg( "set_next_failure_point() called on non-craft '%s.' Aborting.", tname() ); @@ -982,7 +998,7 @@ void item::set_next_failure_point( const player &crafter ) craft_data_->next_failure_point = item_counter + failure_point_delta; } -static void destroy_random_component( item &craft, const player &crafter ) +static void destroy_random_component( item &craft, const Character &crafter ) { if( craft.components.empty() ) { debugmsg( "destroy_random_component() called on craft with no components! Aborting" ); @@ -995,7 +1011,7 @@ static void destroy_random_component( item &craft, const player &crafter ) _( " messes up and destroys the %s" ), destroyed.tname() ); } -bool item::handle_craft_failure( player &crafter ) +bool item::handle_craft_failure( Character &crafter ) { if( !is_craft() ) { debugmsg( "handle_craft_failure() called on non-craft '%s.' Aborting.", tname() ); @@ -1084,7 +1100,7 @@ void item::inherit_flags( const std::list &parents, const recipe &making ) } } -void player::complete_craft( item &craft, const tripoint &loc ) +void Character::complete_craft( item &craft, const tripoint &loc ) { if( !craft.is_craft() ) { debugmsg( "complete_craft() called on non-craft '%s.' Aborting.", craft.tname() ); @@ -1130,7 +1146,7 @@ void player::complete_craft( item &craft, const tripoint &loc ) std::max( get_skill_level( making.skill_used ), 1 ) * std::max( get_int(), 1 ); const double time_to_learn = 1000 * 8 * std::pow( difficulty, 4 ) / learning_speed; - if( x_in_y( making.time, time_to_learn ) ) { + if( x_in_y( making.time_to_craft_moves( *this ), time_to_learn ) ) { learn_recipe( &making ); add_msg( m_good, _( "You memorized the recipe for %s!" ), making.result_name() ); @@ -1252,7 +1268,7 @@ void player::complete_craft( item &craft, const tripoint &loc ) inv.restack( *this ); } -bool player::can_continue_craft( item &craft ) +bool Character::can_continue_craft( item &craft ) { if( !craft.is_craft() ) { debugmsg( "complete_craft() called on non-craft '%s.' Aborting.", craft.tname() ); @@ -1263,6 +1279,10 @@ bool player::can_continue_craft( item &craft ) const requirement_data continue_reqs = craft.get_continue_reqs(); + if( !rec.character_has_required_proficiencies( *this ) ) { + return false; + } + // Avoid building an inventory from the map if we don't have to, as it is expensive if( !continue_reqs.is_empty() ) { @@ -1368,7 +1388,7 @@ bool player::can_continue_craft( item &craft ) return true; } -const requirement_data *player::select_requirements( +const requirement_data *Character::select_requirements( const std::vector &alternatives, int batch, const inventory &inv, const std::function &filter ) const { @@ -1401,7 +1421,8 @@ const requirement_data *player::select_requirements( } /* selection of component if a recipe requirement has multiple options (e.g. 'duct tap' or 'welder') */ -comp_selection player::select_item_component( const std::vector &components, +comp_selection Character::select_item_component( const std::vector + &components, int batch, inventory &map_inv, bool can_cancel, const std::function &filter, bool player_inv ) { @@ -1573,7 +1594,7 @@ comp_selection player::select_item_component( const std::vector player::consume_items( const comp_selection &is, int batch, - const std::function &filter ) +std::list Character::consume_items( const comp_selection &is, int batch, + const std::function &filter ) { return consume_items( get_map(), is, batch, filter, pos(), PICKUP_RANGE ); } -std::list player::consume_items( map &m, const comp_selection &is, int batch, - const std::function &filter, - const tripoint &origin, int radius ) +std::list Character::consume_items( map &m, const comp_selection &is, int batch, + const std::function &filter, + const tripoint &origin, int radius ) { std::list ret; @@ -1650,8 +1671,8 @@ std::list player::consume_items( map &m, const comp_selection & /* This call is in-efficient when doing it for multiple items with the same map inventory. In that case, consider using select_item_component with 1 pre-created map inventory, and then passing the results to consume_items */ -std::list player::consume_items( const std::vector &components, int batch, - const std::function &filter ) +std::list Character::consume_items( const std::vector &components, int batch, + const std::function &filter ) { inventory map_inv; map_inv.form_from_map( pos(), PICKUP_RANGE, this ); @@ -1660,9 +1681,10 @@ std::list player::consume_items( const std::vector &components, } comp_selection -player::select_tool_component( const std::vector &tools, int batch, inventory &map_inv, - const std::string &hotkeys, bool can_cancel, bool player_inv, - const std::function charges_required_modifier ) +Character::select_tool_component( const std::vector &tools, int batch, + inventory &map_inv, + const std::string &hotkeys, bool can_cancel, bool player_inv, + const std::function charges_required_modifier ) { comp_selection selected; @@ -1775,7 +1797,7 @@ player::select_tool_component( const std::vector &tools, int batch, i return selected; } -bool player::craft_consume_tools( item &craft, int mulitplier, bool start_craft ) +bool Character::craft_consume_tools( item &craft, int mulitplier, bool start_craft ) { if( !craft.is_craft() ) { debugmsg( "craft_consume_tools() called on non-craft '%s.' Aborting.", craft.tname() ); @@ -1862,14 +1884,14 @@ bool player::craft_consume_tools( item &craft, int mulitplier, bool start_craft return true; } -void player::consume_tools( const comp_selection &tool, int batch ) +void Character::consume_tools( const comp_selection &tool, int batch ) { consume_tools( get_map(), tool, batch, pos(), PICKUP_RANGE ); } /* we use this if we selected the tool earlier */ -void player::consume_tools( map &m, const comp_selection &tool, int batch, - const tripoint &origin, int radius, basecamp *bcp ) +void Character::consume_tools( map &m, const comp_selection &tool, int batch, + const tripoint &origin, int radius, basecamp *bcp ) { if( has_trait( trait_DEBUG_HS ) ) { return; @@ -1890,15 +1912,15 @@ void player::consume_tools( map &m, const comp_selection &tool, int b /* This call is in-efficient when doing it for multiple items with the same map inventory. In that case, consider using select_tool_component with 1 pre-created map inventory, and then passing the results to consume_tools */ -void player::consume_tools( const std::vector &tools, int batch, - const std::string &hotkeys ) +void Character::consume_tools( const std::vector &tools, int batch, + const std::string &hotkeys ) { inventory map_inv; map_inv.form_from_map( pos(), PICKUP_RANGE, this ); consume_tools( select_tool_component( tools, batch, map_inv, hotkeys ), batch ); } -ret_val player::can_disassemble( const item &obj, const inventory &inv ) const +ret_val Character::can_disassemble( const item &obj, const inventory &inv ) const { if( !obj.is_disassemblable() ) { return ret_val::make_failure( _( "You cannot disassemble this." ) ); @@ -1971,12 +1993,12 @@ ret_val player::can_disassemble( const item &obj, const inventory &inv ) c return ret_val::make_success(); } -bool player::disassemble() +bool Character::disassemble() { return disassemble( game_menus::inv::disassemble( *this ), false ); } -bool player::disassemble( item_location target, bool interactive ) +bool Character::disassemble( item_location target, bool interactive ) { if( !target ) { add_msg( _( "Never mind." ) ); @@ -1993,8 +2015,9 @@ bool player::disassemble( item_location target, bool interactive ) return false; } + avatar &player_character = get_avatar(); const auto &r = recipe_dictionary::get_uncraft( obj.typeId() ); - if( !obj.is_owned_by( g->u, true ) ) { + if( !obj.is_owned_by( player_character, true ) ) { if( !query_yn( _( "Disassembling the %s may anger the people who own it, continue?" ), obj.tname() ) ) { return false; @@ -2002,15 +2025,15 @@ bool player::disassemble( item_location target, bool interactive ) if( obj.get_owner() ) { std::vector witnesses; for( npc &elem : g->all_npcs() ) { - if( rl_dist( elem.pos(), g->u.pos() ) < MAX_VIEW_DISTANCE && elem.get_faction() && - obj.is_owned_by( elem ) && elem.sees( g->u.pos() ) ) { + if( rl_dist( elem.pos(), player_character.pos() ) < MAX_VIEW_DISTANCE && elem.get_faction() && + obj.is_owned_by( elem ) && elem.sees( player_character.pos() ) ) { elem.say( "", 7 ); npc *npc_to_add = &elem; witnesses.push_back( npc_to_add ); } } if( !witnesses.empty() ) { - if( g->u.add_faction_warning( obj.get_owner() ) ) { + if( player_character.add_faction_warning( obj.get_owner() ) ) { for( npc *elem : witnesses ) { elem->make_angry(); } @@ -2055,12 +2078,12 @@ bool player::disassemble( item_location target, bool interactive ) if( activity.id() != ACT_DISASSEMBLE ) { if( num_dis != 0 ) { - assign_activity( ACT_DISASSEMBLE, r.time * num_dis ); + assign_activity( ACT_DISASSEMBLE, r.time_to_craft_moves( *this ) * num_dis ); } else { - assign_activity( ACT_DISASSEMBLE, r.time ); + assign_activity( ACT_DISASSEMBLE, r.time_to_craft_moves( *this ) ); } } else if( activity.moves_left <= 0 ) { - activity.moves_left = r.time; + activity.moves_left = r.time_to_craft_moves( *this ); } // index is used as a bool that indicates if we want recursive uncraft. @@ -2073,7 +2096,7 @@ bool player::disassemble( item_location target, bool interactive ) return true; } -void player::disassemble_all( bool one_pass ) +void Character::disassemble_all( bool one_pass ) { // Reset all the activity values assign_activity( ACT_DISASSEMBLE, 0 ); @@ -2096,7 +2119,7 @@ void player::disassemble_all( bool one_pass ) } } -void player::complete_disassemble() +void Character::complete_disassemble() { // Cancel the activity if we have bad (possibly legacy) values if( activity.targets.empty() || !activity.targets.back() || @@ -2144,10 +2167,10 @@ void player::complete_disassemble() return; } - activity.moves_left = next_recipe.time; + activity.moves_left = next_recipe.time_to_craft_moves( *this ); } -void player::complete_disassemble( item_location &target, const recipe &dis ) +void Character::complete_disassemble( item_location &target, const recipe &dis ) { // Get the proper recipe - the one for disassembly, not assembly const auto dis_requirements = dis.disassembly_requirements(); @@ -2276,7 +2299,7 @@ void player::complete_disassemble( item_location &target, const recipe &dis ) item act_item = newit; if( act_item.has_temperature() ) { - act_item.set_item_temperature( temp_to_kelvin( g->weather.get_temperature( loc ) ) ); + act_item.set_item_temperature( temp_to_kelvin( get_weather().get_temperature( loc ) ) ); } // Refitted clothing disassembles into refitted components (when applicable) @@ -2324,7 +2347,7 @@ void player::complete_disassemble( item_location &target, const recipe &dis ) } } -void remove_ammo( std::list &dis_items, player &p ) +void remove_ammo( std::list &dis_items, Character &p ) { for( auto &dis_item : dis_items ) { remove_ammo( dis_item, p ); @@ -2341,7 +2364,7 @@ void drop_or_handle( const item &newit, Character &p ) } } -void remove_ammo( item &dis_item, player &p ) +void remove_ammo( item &dis_item, Character &p ) { dis_item.remove_items_with( [&p]( const item & it ) { if( it.is_irremovable() ) { @@ -2371,7 +2394,7 @@ void remove_ammo( item &dis_item, player &p ) } } -std::vector player::get_crafting_helpers() const +std::vector Character::get_crafting_helpers() const { return g->get_npcs_if( [this]( const npc & guy ) { // NPCs can help craft if awake, taking orders, within pickup range and have clear path diff --git a/src/crafting.h b/src/crafting.h index e21c4a4297faa..0b03d28eb56b2 100644 --- a/src/crafting.h +++ b/src/crafting.h @@ -20,9 +20,9 @@ inline constexpr craft_flags operator&( craft_flags l, craft_flags r ) // removes any (removable) ammo from the item and stores it in the // players inventory. -void remove_ammo( item &dis_item, player &p ); +void remove_ammo( item &dis_item, Character &p ); // same as above but for each item in the list -void remove_ammo( std::list &dis_items, player &p ); +void remove_ammo( std::list &dis_items, Character &p ); void drop_or_handle( const item &newit, Character &p ); #endif // CATA_SRC_CRAFTING_H diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 5eb59cb3ad566..56a4d109054b8 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -241,8 +241,9 @@ const recipe *select_crafting_recipe( int &batch_size ) auto all_items_filter = r->get_component_filter( recipe_filter_flags::none ); auto no_rotten_filter = r->get_component_filter( recipe_filter_flags::no_rotten ); const deduped_requirement_data &req = r->deduped_requirements(); + has_proficiencies = r->character_has_required_proficiencies( get_player_character() ); can_craft = req.can_make_with_inventory( - inv, all_items_filter, batch_size, craft_flags::start_only ); + inv, all_items_filter, batch_size, craft_flags::start_only ) && has_proficiencies; can_craft_non_rotten = req.can_make_with_inventory( inv, no_rotten_filter, batch_size, craft_flags::start_only ); const requirement_data &simple_req = r->simple_requirements(); @@ -252,6 +253,7 @@ const recipe *select_crafting_recipe( int &batch_size ) bool can_craft; bool can_craft_non_rotten; bool apparently_craftable; + bool has_proficiencies; nc_color selected_color() const { return can_craft ? can_craft_non_rotten ? h_white : h_brown : h_dark_gray; @@ -496,6 +498,9 @@ const recipe *select_crafting_recipe( int &batch_size ) _( "Other skills: %s" ), current[line]->required_skills_string( &g->u, false, false ) ); + ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, _( "Proficiencies Required: %s" ), + current[line]->required_proficiencies_string( get_player_character() ) ); + const int expected_turns = g->u.expected_time_to_craft( *current[line], count ) / to_moves( 1_turns ); ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, @@ -512,23 +517,29 @@ const recipe *select_crafting_recipe( int &batch_size ) current[line]->has_flag( flag_BLIND_EASY ) ? _( "Easy" ) : current[line]->has_flag( flag_BLIND_HARD ) ? _( "Hard" ) : _( "Impossible" ) ) ); - if( available[line].can_craft && !available[line].can_craft_non_rotten ) { + const bool can_craft_this = available[line].can_craft; + if( can_craft_this && !available[line].can_craft_non_rotten ) { ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, _( "Will use rotten ingredients" ) ); } const bool too_complex = current[line]->deduped_requirements().is_too_complex(); - if( available[line].can_craft && too_complex ) { + if( can_craft_this && too_complex ) { ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, _( "Due to the complex overlapping requirements, this " "recipe may appear to be craftable " "when it is not." ) ); } - if( !available[line].can_craft && available[line].apparently_craftable ) { + if( !can_craft_this && available[line].apparently_craftable && available[line].has_proficiencies ) { ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, _( "Cannot be crafted because the same item is needed " "for multiple components" ) ); } + if( !can_craft_this && !available[line].has_proficiencies ) { + ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, + _( "Cannot be crafted because you lack" + " the required proficiencies." ) ); + } ypos += print_items( *current[line], w_data, point( xpos, ypos ), col, batch ? line + 1 : 1 ); } diff --git a/src/creature.cpp b/src/creature.cpp index bc01e992e99ec..ec758074aab4d 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -48,6 +48,7 @@ static const anatomy_id anatomy_human_anatomy( "human_anatomy" ); +static const efftype_id effect_bleed( "bleed" ); static const efftype_id effect_blind( "blind" ); static const efftype_id effect_bounced( "bounced" ); static const efftype_id effect_downed( "downed" ); @@ -315,7 +316,7 @@ bool Creature::sees( const tripoint &t, bool is_avatar, int range_mod ) const static bool overlaps_vehicle( const std::set &veh_area, const tripoint &pos, const int area ) { - for( const tripoint &tmp : tripoint_range( pos - tripoint( area, area, 0 ), + for( const tripoint &tmp : tripoint_range( pos - tripoint( area, area, 0 ), pos + tripoint( area - 1, area - 1, 0 ) ) ) { if( veh_area.count( tmp ) > 0 ) { return true; @@ -902,6 +903,16 @@ void Creature::deal_damage_handle_type( const damage_unit &du, bodypart_id bp, i div = 3.0f; break; + case DT_CUT: + case DT_STAB: + case DT_BULLET: + // these are bleed inducing damage types + if( is_avatar() || is_npc() ) { + as_character()->make_bleed( bp, 1_minutes * rng( 1, adjusted_damage ) ); + } else { + add_effect( effect_bleed, 1_minutes * rng( 1, adjusted_damage ), bp->token ); + } + default: break; } @@ -1519,6 +1530,21 @@ int Creature::get_part_healed_total( const bodypart_id &id ) const return get_part( id ).get_healed_total(); } +int Creature::get_part_damage_disinfected( const bodypart_id &id ) const +{ + return get_part( id ).get_damage_disinfected(); +} + +int Creature::get_part_damage_bandaged( const bodypart_id &id ) const +{ + return get_part( id ).get_damage_bandaged(); +} + +encumbrance_data Creature::get_part_encumbrance_data( const bodypart_id &id ) const +{ + return get_part( id ).get_encumbrance_data(); +} + void Creature::set_part_hp_cur( const bodypart_id &id, int set ) { get_part( id )->set_hp_cur( set ); @@ -1534,6 +1560,21 @@ void Creature::set_part_healed_total( const bodypart_id &id, int set ) get_part( id )->set_healed_total( set ); } +void Creature::set_part_damage_disinfected( const bodypart_id &id, int set ) +{ + get_part( id )->set_damage_disinfected( set ); +} + +void Creature::set_part_damage_bandaged( const bodypart_id &id, int set ) +{ + get_part( id )->set_damage_bandaged( set ); +} + +void Creature::set_part_encumbrance_data( const bodypart_id &id, encumbrance_data set ) +{ + get_part( id )->set_encumbrance_data( set ); +} + void Creature::mod_part_hp_cur( const bodypart_id &id, int mod ) { get_part( id )->mod_hp_cur( mod ); @@ -1549,6 +1590,16 @@ void Creature::mod_part_healed_total( const bodypart_id &id, int mod ) get_part( id )->mod_healed_total( mod ); } +void Creature::mod_part_damage_disinfected( const bodypart_id &id, int mod ) +{ + get_part( id )->mod_damage_disinfected( mod ); +} + +void Creature::mod_part_damage_bandaged( const bodypart_id &id, int mod ) +{ + get_part( id )->mod_damage_bandaged( mod ); +} + void Creature::set_all_parts_hp_cur( const int set ) { for( std::pair &elem : body ) { @@ -1873,7 +1924,7 @@ void Creature::process_damage_over_time() const int dmg_amount = DoT->amount; if( dmg_amount < 0 ) { heal_bp( bp.id(), -dmg_amount ); - } else { + } else if( dmg_amount > 0 ) { deal_damage( nullptr, bp.id(), damage_instance( DoT->type, dmg_amount ) ); } } diff --git a/src/creature.h b/src/creature.h index e19c3ff4a3e09..cd622e94ea74e 100644 --- a/src/creature.h +++ b/src/creature.h @@ -43,7 +43,6 @@ struct point; enum damage_type : int; enum m_flag : int; -enum hp_part : int; struct damage_instance; struct damage_unit; struct dealt_damage_instance; @@ -618,13 +617,24 @@ class Creature int get_part_hp_max( const bodypart_id &id ) const; int get_part_healed_total( const bodypart_id &id ) const; + int get_part_damage_disinfected( const bodypart_id &id ) const; + int get_part_damage_bandaged( const bodypart_id &id ) const; + + encumbrance_data get_part_encumbrance_data( const bodypart_id &id )const; void set_part_hp_cur( const bodypart_id &id, int set ); void set_part_hp_max( const bodypart_id &id, int set ); void set_part_healed_total( const bodypart_id &id, int set ); + void set_part_damage_disinfected( const bodypart_id &id, int set ); + void set_part_damage_bandaged( const bodypart_id &id, int set ); + + void set_part_encumbrance_data( const bodypart_id &id, encumbrance_data set ); + void mod_part_hp_cur( const bodypart_id &id, int mod ); void mod_part_hp_max( const bodypart_id &id, int mod ); void mod_part_healed_total( const bodypart_id &id, int mod ); + void mod_part_damage_disinfected( const bodypart_id &id, int mod ); + void mod_part_damage_bandaged( const bodypart_id &id, int mod ); void set_all_parts_hp_cur( int set ); diff --git a/src/debug.h b/src/debug.h index 4f8ab2ffc385a..f6d4834ed7199 100644 --- a/src/debug.h +++ b/src/debug.h @@ -80,6 +80,21 @@ inline void realDebugmsg( const char *const filename, const char *const line, std::forward( args )... ) ); } +// A fatal error for use in constexpr functions +// This exists for compatibility reasons. On gcc 5.3 we need a +// different implementation that is messier. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371 +// Pass a placeholder return value to be used on gcc 5.3 (it won't +// actually be returned, it's just needed for the type), and then +// args as if to debugmsg for the remaining args. +#if defined(__GNUC__) && __GNUC__ < 6 +#define constexpr_fatal(ret, ...) \ + do { return false ? ( ret ) : ( abort(), ( ret ) ); } while(false) +#else +#define constexpr_fatal(ret, ...) \ + do { debugmsg(__VA_ARGS__); abort(); } while(false) +#endif + /** * Used to generate game report information. */ diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 48e78acf531f8..e9e94f7298e26 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -89,6 +89,7 @@ #include "ui.h" #include "ui_manager.h" #include "units.h" +#include "vehicle.h" #include "veh_type.h" #include "vitamin.h" #include "vpart_position.h" @@ -102,8 +103,6 @@ static const mtype_id mon_generator( "mon_generator" ); static const trait_id trait_ASTHMA( "ASTHMA" ); -class vehicle; - extern std::map> > nested_mapgen; @@ -145,6 +144,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::DISPLAY_HORDES: return "DISPLAY_HORDES"; case debug_menu::debug_menu_index::TEST_IT_GROUP: return "TEST_IT_GROUP"; case debug_menu::debug_menu_index::DAMAGE_SELF: return "DAMAGE_SELF"; + case debug_menu::debug_menu_index::BLEED_SELF: return "BLEED_SELF"; case debug_menu::debug_menu_index::SHOW_SOUND: return "SHOW_SOUND"; case debug_menu::debug_menu_index::DISPLAY_WEATHER: return "DISPLAY_WEATHER"; case debug_menu::debug_menu_index::DISPLAY_SCENTS: return "DISPLAY_SCENTS"; @@ -177,6 +177,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::LEVEL_SPELLS: return "LEVEL_SPELLS"; case debug_menu::debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: return "TEST_MAP_EXTRA_DISTRIBUTION"; case debug_menu::debug_menu_index::NESTED_MAPGEN: return "NESTED_MAPGEN"; + case debug_menu::debug_menu_index::VEHICLE_BATTERY_CHARGE: return "VEHICLE_BATTERY_CHARGE"; // *INDENT-ON* case debug_menu::debug_menu_index::last: break; @@ -212,6 +213,7 @@ static int player_uilist() { uilist_entry( debug_menu_index::UNLOCK_RECIPES, true, 'r', _( "Unlock all recipes" ) ) }, { uilist_entry( debug_menu_index::EDIT_PLAYER, true, 'p', _( "Edit player/NPC" ) ) }, { uilist_entry( debug_menu_index::DAMAGE_SELF, true, 'd', _( "Damage self" ) ) }, + { uilist_entry( debug_menu_index::BLEED_SELF, true, 'b', _( "Bleed self" ) ) }, { uilist_entry( debug_menu_index::SET_AUTOMOVE, true, 'a', _( "Set automove route" ) ) }, }; if( !spell_type::get_all().empty() ) { @@ -275,6 +277,15 @@ static int game_uilist() return uilist( _( "Game…" ), uilist_initializer ); } +static int vehicle_uilist() +{ + std::vector uilist_initializer = { + { uilist_entry( debug_menu_index::VEHICLE_BATTERY_CHARGE, true, 'b', _( "Change [b]attery charge" ) ) }, + }; + + return uilist( _( "Vehicle…" ), uilist_initializer ); +} + static int teleport_uilist() { const std::vector uilist_initializer = { @@ -336,6 +347,7 @@ static cata::optional debug_menu_uilist( bool display_all_entr { uilist_entry( 6, true, 'g', _( "Game…" ) ) }, { uilist_entry( 2, true, 's', _( "Spawning…" ) ) }, { uilist_entry( 3, true, 'p', _( "Player…" ) ) }, + { uilist_entry( 7, true, 'v', _( "Vehicle…" ) ) }, { uilist_entry( 4, true, 't', _( "Teleport…" ) ) }, { uilist_entry( 5, true, 'm', _( "Map…" ) ) }, }; @@ -375,6 +387,9 @@ static cata::optional debug_menu_uilist( bool display_all_entr case 6: action = game_uilist(); break; + case 7: + action = vehicle_uilist(); + break; default: return cata::nullopt; @@ -390,11 +405,12 @@ static cata::optional debug_menu_uilist( bool display_all_entr void teleport_short() { const cata::optional where = g->look_around(); - if( !where || *where == g->u.pos() ) { + Character &player_character = get_player_character(); + if( !where || *where == player_character.pos() ) { return; } g->place_player( *where ); - const tripoint new_pos( g->u.pos() ); + const tripoint new_pos( player_character.pos() ); add_msg( _( "You teleport to point (%d,%d,%d)." ), new_pos.x, new_pos.y, new_pos.z ); } @@ -415,12 +431,13 @@ void teleport_overmap() return; } + Character &player_character = get_player_character(); const tripoint offset( OMAPX * dir_->x, OMAPY * dir_->y, dir_->z ); - const tripoint where( g->u.global_omt_location() + offset ); + const tripoint where( player_character.global_omt_location() + offset ); g->place_player_overmap( where ); - const tripoint new_pos( omt_to_om_copy( g->u.global_omt_location() ) ); + const tripoint new_pos( omt_to_om_copy( player_character.global_omt_location() ) ); add_msg( _( "You teleport to overmap (%d,%d,%d)." ), new_pos.x, new_pos.y, new_pos.z ); } @@ -465,8 +482,9 @@ void character_edit_menu() std::vector< tripoint > locations; uilist charmenu; int charnum = 0; + avatar &player_character = get_avatar(); charmenu.addentry( charnum++, true, MENU_AUTOASSIGN, "%s", _( "You" ) ); - locations.emplace_back( g->u.pos() ); + locations.emplace_back( player_character.pos() ); for( const npc &guy : g->all_npcs() ) { charmenu.addentry( charnum++, true, MENU_AUTOASSIGN, guy.name ); locations.emplace_back( guy.pos() ); @@ -482,7 +500,7 @@ void character_edit_menu() const size_t index = charmenu.ret; // The NPC is also required for "Add mission", so has to be in this scope npc *np = g->critter_at( locations[index], false ); - player &p = np ? static_cast( *np ) : static_cast( g->u ); + player &p = np ? *np->as_player() : *player_character.as_player(); uilist nmenu; if( np != nullptr ) { @@ -608,7 +626,7 @@ void character_edit_menu() p.remove_weapon(); break; case D_ITEM_WORN: { - item_location loc = game_menus::inv::titled_menu( g->u, _( "Make target equip" ) ); + item_location loc = game_menus::inv::titled_menu( player_character, _( "Make target equip" ) ); if( !loc ) { break; } @@ -900,7 +918,7 @@ void character_edit_menu() if( p.is_mounted() ) { p.mounted_creature->setpos( *newpos ); } - g->update_map( g->u ); + g->update_map( player_character ); } } } @@ -1040,20 +1058,21 @@ void mission_debug::edit_player() uilist mmenu; mmenu.text = _( "Select mission to edit" ); + avatar &player_character = get_avatar(); add_header( mmenu, _( "Active missions:" ) ); - for( mission *m : g->u.active_missions ) { + for( mission *m : player_character.active_missions ) { mmenu.addentry( all_missions.size(), true, MENU_AUTOASSIGN, "%s", m->type->id.c_str() ); all_missions.emplace_back( m ); } add_header( mmenu, _( "Completed missions:" ) ); - for( mission *m : g->u.completed_missions ) { + for( mission *m : player_character.completed_missions ) { mmenu.addentry( all_missions.size(), true, MENU_AUTOASSIGN, "%s", m->type->id.c_str() ); all_missions.emplace_back( m ); } add_header( mmenu, _( "Failed missions:" ) ); - for( mission *m : g->u.failed_missions ) { + for( mission *m : player_character.failed_missions ) { mmenu.addentry( all_missions.size(), true, MENU_AUTOASSIGN, "%s", m->type->id.c_str() ); all_missions.emplace_back( m ); } @@ -1076,18 +1095,19 @@ static bool remove_from_vec( std::vector &vec, mission *m ) void mission_debug::remove_mission( mission &m ) { - if( remove_from_vec( g->u.active_missions, &m ) ) { + avatar &player_character = get_avatar(); + if( remove_from_vec( player_character.active_missions, &m ) ) { add_msg( _( "Removing from active_missions" ) ); } - if( remove_from_vec( g->u.completed_missions, &m ) ) { + if( remove_from_vec( player_character.completed_missions, &m ) ) { add_msg( _( "Removing from completed_missions" ) ); } - if( remove_from_vec( g->u.failed_missions, &m ) ) { + if( remove_from_vec( player_character.failed_missions, &m ) ) { add_msg( _( "Removing from failed_missions" ) ); } - if( g->u.active_mission == &m ) { - g->u.active_mission = nullptr; + if( player_character.active_mission == &m ) { + player_character.active_mission = nullptr; add_msg( _( "Unsetting active mission" ) ); } @@ -1198,11 +1218,11 @@ void debug() g->events().send( *action ); - avatar &u = g->u; + avatar &player_character = get_avatar(); map &here = get_map(); switch( *action ) { case debug_menu_index::WISH: - debug_menu::wishitem( &u ); + debug_menu::wishitem( &player_character ); break; case debug_menu_index::SHORT_TELEPORT: @@ -1230,9 +1250,10 @@ void debug() shared_ptr_fast temp = make_shared_fast(); temp->normalize(); temp->randomize(); - temp->spawn_at_precise( { g->get_levx(), g->get_levy() }, u.pos() + point( -4, -4 ) ); + temp->spawn_at_precise( { g->get_levx(), g->get_levy() }, player_character.pos() + point( -4, + -4 ) ); overmap_buffer.insert_npc( temp ); - temp->form_opinion( u ); + temp->form_opinion( player_character ); temp->mission = NPC_MISSION_NULL; temp->add_new_mission( mission::reserve_random( ORIGIN_ANY_NPC, temp->global_omt_location(), temp->getID() ) ); @@ -1258,6 +1279,7 @@ void debug() std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { return a.second != b.second ? a.second > b.second : a.first < b.first; } ); + popup( player_character.total_daily_calories_string() ); for( auto &m_flag_stat : sorted ) { mfus += string_format( "%s;%d\n", io::enum_to_string( m_flag_stat.first ), m_flag_stat.second ); @@ -1267,15 +1289,13 @@ void debug() popup_top( "Monster flag usage statistics were dumped to debug.log and cleared." ); std::string s = _( "Location %d:%d in %d:%d, %s\n" ); - s += _( "Current turn: %d.\n%s\n" ); + s += _( "Current turn: %d.\n" ); s += ngettext( "%d creature exists.\n", "%d creatures exist.\n", g->num_creatures() ); popup_top( s.c_str(), - u.posx(), g->u.posy(), g->get_levx(), g->get_levy(), - overmap_buffer.ter( g->u.global_omt_location() )->get_name(), + player_character.posx(), player_character.posy(), g->get_levx(), g->get_levy(), + overmap_buffer.ter( player_character.global_omt_location() )->get_name(), to_turns( calendar::turn - calendar::turn_zero ), - get_option( "RANDOM_NPC" ) ? _( "NPCs are going to spawn." ) : - _( "NPCs are NOT going to spawn." ), g->num_creatures() ); for( const npc &guy : g->all_npcs() ) { tripoint t = guy.global_sm_location(); @@ -1283,21 +1303,24 @@ void debug() t.y, guy.posx(), guy.posy() ); } - add_msg( m_info, _( "(you: %d:%d)" ), u.posx(), u.posy() ); + add_msg( m_info, _( "(you: %d:%d)" ), player_character.posx(), player_character.posy() ); std::string stom = _( "Stomach Contents: %d ml / %d ml kCal: %d, Water: %d ml" ); - add_msg( m_info, stom.c_str(), units::to_milliliter( u.stomach.contains() ), - units::to_milliliter( u.stomach.capacity( u ) ), u.stomach.get_calories(), - units::to_milliliter( u.stomach.get_water() ), u.get_hunger() ); + add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.stomach.contains() ), + units::to_milliliter( player_character.stomach.capacity( player_character ) ), + player_character.stomach.get_calories(), + units::to_milliliter( player_character.stomach.get_water() ), player_character.get_hunger() ); stom = _( "Guts Contents: %d ml / %d ml kCal: %d, Water: %d ml\nHunger: %d, Thirst: %d, kCal: %d / %d" ); - add_msg( m_info, stom.c_str(), units::to_milliliter( u.guts.contains() ), - units::to_milliliter( u.guts.capacity( u ) ), u.guts.get_calories(), - units::to_milliliter( u.guts.get_water() ), u.get_hunger(), u.get_thirst(), u.get_stored_kcal(), - u.get_healthy_kcal() ); - add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), u.get_bmi(), u.get_bmr() ); - add_msg( m_info, _( "Player activity level: %s" ), u.activity_level_str() ); + add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.guts.contains() ), + units::to_milliliter( player_character.guts.capacity( player_character ) ), + player_character.guts.get_calories(), units::to_milliliter( player_character.guts.get_water() ), + player_character.get_hunger(), player_character.get_thirst(), player_character.get_stored_kcal(), + player_character.get_healthy_kcal() ); + add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), player_character.get_bmi(), + player_character.get_bmr() ); + add_msg( m_info, _( "Player activity level: %s" ), player_character.activity_level_str() ); if( get_option( "STATS_THROUGH_KILLS" ) ) { - add_msg( m_info, _( "Kill xp: %d" ), u.kill_xp() ); + add_msg( m_info, _( "Kill xp: %d" ), player_character.kill_xp() ); } g->invalidate_main_ui_adaptor(); g->disp_NPCs(); @@ -1311,11 +1334,11 @@ void debug() break; case debug_menu_index::MUTATE: - debug_menu::wishmutate( &u ); + debug_menu::wishmutate( &player_character ); break; case debug_menu_index::SPAWN_VEHICLE: - if( here.veh_at( u.pos() ) ) { + if( here.veh_at( player_character.pos() ) ) { dbg( D_ERROR ) << "game:load: There's already vehicle here"; debugmsg( "There's already vehicle here" ); } else { @@ -1341,18 +1364,27 @@ void debug() if( veh_menu.ret >= 0 && veh_menu.ret < static_cast( veh_strings.size() ) ) { // Didn't cancel const vproto_id &selected_opt = veh_strings[veh_menu.ret].second; - // TODO: Allow picking this when add_vehicle has 3d argument - tripoint dest = u.pos(); - vehicle *veh = here.add_vehicle( selected_opt, dest, -90, 100, 0 ); - if( veh != nullptr ) { - here.board_vehicle( dest, &u ); + tripoint dest = player_character.pos(); + uilist veh_cond_menu; + veh_cond_menu.text = _( "Vehicle condition" ); + veh_cond_menu.addentry( 0, true, MENU_AUTOASSIGN, _( "Light damage" ) ); + veh_cond_menu.addentry( 1, true, MENU_AUTOASSIGN, _( "Undamaged" ) ); + veh_cond_menu.addentry( 2, true, MENU_AUTOASSIGN, _( "Disabled (tires or engine)" ) ); + veh_cond_menu.query(); + + if( veh_cond_menu.ret >= 0 && veh_cond_menu.ret < 3 ) { + // TODO: Allow picking this when add_vehicle has 3d argument + vehicle *veh = here.add_vehicle( selected_opt, dest, -90, 100, veh_cond_menu.ret - 1 ); + if( veh != nullptr ) { + here.board_vehicle( dest, &player_character ); + } } } } break; case debug_menu_index::CHANGE_SKILLS: { - debug_menu::wishskill( &u ); + debug_menu::wishskill( &player_character ); } break; @@ -1361,7 +1393,7 @@ void debug() add_msg( _( "Your eyes blink rapidly as knowledge floods your brain." ) ); for( auto &style : all_martialart_types() ) { if( style != matype_id( "style_none" ) ) { - u.martial_arts_data.add_martialart( style ); + player_character.martial_arts_data.add_martialart( style ); } } add_msg( m_good, _( "You now know a lot more than just 10 styles of kung fu." ) ); @@ -1371,7 +1403,7 @@ void debug() add_msg( m_info, _( "Recipe debug." ) ); add_msg( _( "Your eyes blink rapidly as knowledge floods your brain." ) ); for( const auto &e : recipe_dict ) { - u.learn_recipe( &e.second ); + player_character.learn_recipe( &e.second ); } add_msg( m_good, _( "You know how to craft that now." ) ); } @@ -1386,12 +1418,12 @@ void debug() artifact_natural_property prop = static_cast( rng( ARTPROP_NULL + 1, ARTPROP_MAX - 1 ) ); here.create_anomaly( *center, prop ); - here.spawn_natural_artifact( *center, prop ); + here.spawn_artifact( *center, relic_procgen_id( "alien_reality" ) ); } break; case debug_menu_index::SPAWN_CLAIRVOYANCE: - u.i_add( item( architects_cube(), calendar::turn ) ); + player_character.i_add( item( architects_cube(), calendar::turn ) ); break; case debug_menu_index::MAP_EDITOR: @@ -1403,15 +1435,16 @@ void debug() weather_menu.text = _( "Select new weather pattern:" ); weather_menu.addentry( 0, true, MENU_AUTOASSIGN, g->weather.weather_override == WEATHER_NULL ? _( "Keep normal weather patterns" ) : _( "Disable weather forcing" ) ); - for( int weather_id = 1; weather_id < NUM_WEATHER_TYPES; weather_id++ ) { - weather_menu.addentry( weather_id, true, MENU_AUTOASSIGN, - weather::name( static_cast( weather_id ) ) ); + for( size_t i = 0; i < weather_types::get_all().size(); i++ ) { + weather_menu.addentry( i, true, MENU_AUTOASSIGN, + weather_types::get_all()[i].name ); } weather_menu.query(); - if( weather_menu.ret >= 0 && weather_menu.ret < NUM_WEATHER_TYPES ) { - weather_type selected_weather = static_cast( weather_menu.ret ); + if( weather_menu.ret >= 0 && + static_cast( weather_menu.ret ) < weather_types::get_all().size() ) { + const weather_type_id selected_weather = weather_types::get_all()[weather_menu.ret].id; g->weather.weather_override = selected_weather; g->weather.set_nextweather( calendar::turn ); } @@ -1481,12 +1514,12 @@ void debug() // Damage Self case debug_menu_index::DAMAGE_SELF: { - const int torso_hp = u.get_part_hp_cur( bodypart_id( "torso" ) ); - const int head_hp = u.get_part_hp_cur( bodypart_id( "head" ) ); - const int arm_l_hp = u.get_part_hp_cur( bodypart_id( "arm_l" ) ); - const int arm_r_hp = u.get_part_hp_cur( bodypart_id( "arm_r" ) ); - const int leg_l_hp = u.get_part_hp_cur( bodypart_id( "leg_l" ) ); - const int leg_r_hp = u.get_part_hp_cur( bodypart_id( "leg_r" ) ); + const int torso_hp = player_character.get_part_hp_cur( bodypart_id( "torso" ) ); + const int head_hp = player_character.get_part_hp_cur( bodypart_id( "head" ) ); + const int arm_l_hp = player_character.get_part_hp_cur( bodypart_id( "arm_l" ) ); + const int arm_r_hp = player_character.get_part_hp_cur( bodypart_id( "arm_r" ) ); + const int leg_l_hp = player_character.get_part_hp_cur( bodypart_id( "leg_l" ) ); + const int leg_r_hp = player_character.get_part_hp_cur( bodypart_id( "leg_r" ) ); uilist smenu; smenu.addentry( 0, true, 'q', "%s: %d", _( "Torso" ), torso_hp ); smenu.addentry( 1, true, 'w', "%s: %d", _( "Head" ), head_hp ); @@ -1520,8 +1553,48 @@ void debug() break; } if( query_int( dbg_damage, _( "Damage self for how much? hp: %s" ), part.id().c_str() ) ) { - u.apply_damage( nullptr, part, dbg_damage ); - u.die( nullptr ); + player_character.apply_damage( nullptr, part, dbg_damage ); + player_character.die( nullptr ); + } + } + break; + + // Add bleeding + case debug_menu_index::BLEED_SELF: { + uilist smenu; + smenu.addentry( 0, true, 'q', _( "Torso" ) ); + smenu.addentry( 1, true, 'w', _( "Head" ) ); + smenu.addentry( 2, true, 'a', _( "Left arm" ) ); + smenu.addentry( 3, true, 's', _( "Right arm" ) ); + smenu.addentry( 4, true, 'z', _( "Left leg" ) ); + smenu.addentry( 5, true, 'x', _( "Right leg" ) ); + smenu.query(); + bodypart_id part; + int intensity = 0; + switch( smenu.ret ) { + case 0: + part = bodypart_id( "torso" ); + break; + case 1: + part = bodypart_id( "head" ); + break; + case 2: + part = bodypart_id( "arm_l" ); + break; + case 3: + part = bodypart_id( "arm_r" ); + break; + case 4: + part = bodypart_id( "leg_l" ); + break; + case 5: + part = bodypart_id( "leg_r" ); + break; + default: + break; + } + if( query_int( intensity, _( "Add bleeding duration in minutes, equal to intensity:" ) ) ) { + player_character.make_bleed( part, 1_minutes * intensity ); } } break; @@ -1532,7 +1605,7 @@ void debug() shared_ptr_fast sound_cb = make_shared_fast( [&]() { const point offset { - u.view_offset.xy() + point( POSX - u.posx(), POSY - u.posy() ) + player_character.view_offset.xy() + point( POSX - player_character.posx(), POSY - player_character.posy() ) }; for( const auto &sound : sounds_to_draw.first ) { mvwputch( g->w_terrain, offset + sound.xy(), c_yellow, '?' ); @@ -1644,20 +1717,21 @@ void debug() break; case debug_menu_index::SET_AUTOMOVE: { const cata::optional dest = g->look_around(); - if( !dest || *dest == u.pos() ) { + if( !dest || *dest == player_character.pos() ) { break; } - auto rt = here.route( u.pos(), *dest, u.get_pathfinding_settings(), u.get_path_avoid() ); + auto rt = here.route( player_character.pos(), *dest, player_character.get_pathfinding_settings(), + player_character.get_path_avoid() ); if( !rt.empty() ) { - u.set_destination( rt ); + player_character.set_destination( rt ); } else { popup( "Couldn't find path" ); } } break; case debug_menu_index::SHOW_MUT_CAT: - for( const auto &elem : u.mutation_category_level ) { + for( const auto &elem : player_character.mutation_category_level ) { add_msg( "%s: %d", elem.first.c_str(), elem.second ); } break; @@ -1736,7 +1810,7 @@ void debug() << std::endl; count++; } - std::cout << "Player faction is " << g->u.get_faction()->id.str() << std::endl; + std::cout << "Player faction is " << player_character.get_faction()->id.str() << std::endl; break; } case debug_menu_index::PRINT_NPC_MAGIC: { @@ -1763,7 +1837,7 @@ void debug() case debug_menu_index::QUIT_NOSAVE: if( query_yn( _( "Quit without saving? This may cause issues such as duplicated or missing items and vehicles!" ) ) ) { - u.moves = 0; + player_character.moves = 0; g->uquit = QUIT_NOSAVED; } break; @@ -1784,7 +1858,8 @@ void debug() std::time_t time = std::time( nullptr ); std::stringstream date_buffer; date_buffer << std::put_time( std::gmtime( &time ), "%F_%H-%M-%S_%z" ); - const auto tmp_file_name = string_format( "[%s]_%s.png", g->u.get_name(), date_buffer.str() ); + const auto tmp_file_name = string_format( "[%s]_%s.png", player_character.get_name(), + date_buffer.str() ); std::string file_name = ensure_valid_file_name( tmp_file_name ); auto current_file_path = map_directory.str() + file_name; @@ -1823,14 +1898,14 @@ void debug() add_msg( m_bad, _( "There are no spells to learn. You must install a mod that adds some." ) ); } else { for( const spell_type &learn : spell_type::get_all() ) { - g->u.magic.learn_spell( &learn, g->u, true ); + player_character.magic.learn_spell( &learn, player_character, true ); } add_msg( m_good, _( "You have become an Archwizardpriest! What will you do with your newfound power?" ) ); } break; case debug_menu_index::LEVEL_SPELLS: { - std::vector spells = g->u.magic.get_spells(); + std::vector spells = player_character.magic.get_spells(); if( spells.empty() ) { add_msg( m_bad, _( "Try learning some spells first." ) ); return; @@ -1873,6 +1948,32 @@ void debug() case debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: MapExtras::debug_spawn_test(); break; + + case debug_menu_index::VEHICLE_BATTERY_CHARGE: { + + optional_vpart_position v_part_pos = here.veh_at( player_character.pos() ); + if( !v_part_pos ) { + add_msg( m_bad, _( "There's no vehicle there." ) ); + break; + } + + int amount = 0; + string_input_popup popup; + popup + .title( _( "By how much? (in kJ, negative to discharge)" ) ) + .width( 30 ) + .edit( amount ); + if( !popup.canceled() ) { + vehicle &veh = v_part_pos->vehicle(); + if( amount >= 0 ) { + veh.charge_battery( amount, false ); + } else { + veh.discharge_battery( -amount, false ); + } + } + break; + } + case debug_menu_index::last: return; } diff --git a/src/debug_menu.h b/src/debug_menu.h index e5451397611e2..9f3bbb30a667a 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -44,6 +44,7 @@ enum class debug_menu_index : int { DISPLAY_HORDES, TEST_IT_GROUP, DAMAGE_SELF, + BLEED_SELF, SHOW_SOUND, DISPLAY_WEATHER, DISPLAY_SCENTS, @@ -76,6 +77,7 @@ enum class debug_menu_index : int { LEVEL_SPELLS, TEST_MAP_EXTRA_DISTRIBUTION, NESTED_MAPGEN, + VEHICLE_BATTERY_CHARGE, last }; diff --git a/src/descriptions.cpp b/src/descriptions.cpp index 01210d004a48a..d8b7e9ffbecb6 100644 --- a/src/descriptions.cpp +++ b/src/descriptions.cpp @@ -155,7 +155,7 @@ std::string map_data_common_t::extended_description() const if( has_any_harvest ) { ss << "--" << std::endl; - int player_skill = get_avatar().get_skill_level( skill_survival ); + int player_skill = get_player_character().get_skill_level( skill_survival ); ss << _( "You could harvest the following things from it:" ) << std::endl; // Group them by identical ids to avoid repeating same blocks of data // First, invert the mapping: season->id to id->seasons diff --git a/src/dialogue.h b/src/dialogue.h index 401c02459990b..a317292b107e7 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -12,12 +12,12 @@ #include "dialogue_win.h" #include "json.h" #include "npc.h" -#include "player.h" #include "translations.h" #include "type_id.h" class martialart; class mission; +class talker; struct dialogue; enum talk_trial_type : unsigned char { @@ -219,15 +219,13 @@ struct talk_response { struct dialogue { /** - * The player character that speaks (always g->u). - * TODO: make it a reference, not a pointer. + * The talker that speaks (almost certainly representing the avatar, ie get_avatar() ) */ - player *alpha = nullptr; + std::unique_ptr alpha; /** - * The NPC we talk to. Never null. - * TODO: make it a reference, not a pointer. + * The talker responded to alpha, usually a talker_npc. */ - npc *beta = nullptr; + std::unique_ptr beta; /** * If true, we are done talking and the dialog ends. */ @@ -240,6 +238,9 @@ struct dialogue { talk_topic opt( dialogue_window &d_win, const std::string &npc_name, const talk_topic &topic ); dialogue() = default; + talker *actor( const bool is_beta ) const { + return ( is_beta ? beta : alpha ).get(); + } mutable itype_id cur_item; mutable std::string reason; diff --git a/src/dump.cpp b/src/dump.cpp index 703bb07d5a825..24f3baaaf5cb0 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -8,8 +8,8 @@ #include #include -#include "avatar.h" #include "bodypart.h" +#include "character.h" #include "compatibility.h" // needed for the workaround for the std::to_string bug in some compilers #include "damage.h" #include "flat_set.h" @@ -106,13 +106,14 @@ bool game::dump_stats( const std::string &what, dump_mode mode, header = { "Name", "Encumber (fit)", "Warmth", "Weight", "Coverage", "Bash", "Cut", "Bullet", "Acid", "Fire" }; - auto dump = [&rows]( const item & obj ) { + body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() ); + auto dump = [&rows, &bp]( const item & obj ) { std::vector r; r.push_back( obj.tname( 1, false ) ); - r.push_back( to_string( obj.get_encumber( g->u ) ) ); + r.push_back( to_string( obj.get_encumber( get_player_character(), convert_bp( bp ).id() ) ) ); r.push_back( to_string( obj.get_warmth() ) ); r.push_back( to_string( to_gram( obj.weight() ) ) ); - r.push_back( to_string( obj.get_coverage() ) ); + r.push_back( to_string( obj.get_coverage( convert_bp( bp ).id() ) ) ); r.push_back( to_string( obj.bash_resist() ) ); r.push_back( to_string( obj.cut_resist() ) ); r.push_back( to_string( obj.bullet_resist() ) ); @@ -121,8 +122,6 @@ bool game::dump_stats( const std::string &what, dump_mode mode, rows.push_back( r ); }; - body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() ); - for( const itype *e : item_controller->all() ) { if( e->armor ) { item obj( e ); @@ -161,7 +160,7 @@ bool game::dump_stats( const std::string &what, dump_mode mode, for( const itype *e : item_controller->all() ) { item food( e, calendar::turn, item::solitary_tag {} ); - if( food.is_food() && g->u.can_eat( food ).success() ) { + if( food.is_food() && get_player_character().can_eat( food ).success() ) { dump( food ); } } @@ -223,7 +222,7 @@ bool game::dump_stats( const std::string &what, dump_mode mode, dump( test_npcs[ "S1" ], gun ); - if( gun.type->gun->barrel_length > 0_ml ) { + if( gun.type->gun->barrel_volume > 0_ml ) { gun.put_in( item( "barrel_small" ), item_pocket::pocket_type::MOD ); dump( test_npcs[ "S1" ], gun ); } diff --git a/src/editmap.cpp b/src/editmap.cpp index 1612f7a3fdf34..4852877175a8a 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -463,7 +463,7 @@ void editmap::uber_draw_ter( const catacurses::window &w, map *m ) if( refresh_mplans ) { hilights["mplan"].points.clear(); } - for( const tripoint &p : tripoint_range( start, end ) ) { + for( const tripoint &p : tripoint_range( start, end ) ) { int sym = game_map ? '%' : ' '; if( p.x >= 0 && p.x < msize && p.y >= 0 && p.y < msize ) { if( game_map ) { @@ -777,7 +777,7 @@ void editmap::update_view_with_help( const std::string &txt, const std::string & } const trap &cur_trap = here.tr_at( target ); - if( cur_trap.loadid != tr_null ) { + if( !cur_trap.is_null() ) { mvwprintz( w_info, point( 1, off ), cur_trap.color, _( "trap: %s (%d)" ), cur_trap.name(), cur_trap.loadid.to_i() ); off++; // 11 @@ -959,9 +959,7 @@ std::string describe( const furn_t &type ) template<> std::string describe( const trap &type ) { - return string_format( _( "Visible: %d\nAvoidance: %d\nDifficulty: %d\nBenign: %s" ), - type.get_visibility(), type.get_avoidance(), type.get_difficulty(), - type.is_benign() ? _( "Yes" ) : _( "No" ) ); + return type.debug_describe(); } template diff --git a/src/effect.cpp b/src/effect.cpp index e72a4c2c0eab4..3687844dd2f86 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -1419,3 +1419,22 @@ std::string texitify_healing_power( const int power ) } return ""; } +std::string texitify_bandage_power( const int power ) +{ + if( power < 5 ) { + return colorize( _( "miniscule" ), c_red ); + } else if( power < 10 ) { + return colorize( _( "small" ), c_light_red ); + } else if( power < 15 ) { + return colorize( _( "moderate" ), c_yellow ); + } else if( power < 20 ) { + return colorize( _( "good" ), c_light_green ); + } else if( power < 30 ) { + return colorize( _( "excellent" ), c_light_green ); + } else if( power < 51 ) { + return colorize( _( "outstanding" ), c_green ); + } else { + debugmsg( "Converted value out of bounds." ); + } + return ""; +} diff --git a/src/effect.h b/src/effect.h index e7e1748c366ed..dde40ad1c6727 100644 --- a/src/effect.h +++ b/src/effect.h @@ -295,6 +295,7 @@ void reset_effect_types(); std::string texitify_base_healing_power( int power ); std::string texitify_healing_power( int power ); +std::string texitify_bandage_power( int power ); // Inheritance here allows forward declaration of the map in class Creature. // Storing body_part as an int to make things easier for hash and JSON diff --git a/src/enums.h b/src/enums.h index 2d050befa1919..d4fb6f1e12bcf 100644 --- a/src/enums.h +++ b/src/enums.h @@ -271,6 +271,11 @@ enum class layer_level : int { NUM_LAYER_LEVELS }; +template<> +struct enum_traits { + static constexpr layer_level last = layer_level::NUM_LAYER_LEVELS; +}; + inline layer_level &operator++( layer_level &l ) { l = static_cast( static_cast( l ) + 1 ); diff --git a/src/event.cpp b/src/event.cpp index 28af426937a7e..2c632e43ecddc 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -43,6 +43,9 @@ std::string enum_to_string( event_type data ) case event_type::destroys_triffid_grove: return "destroys_triffid_grove"; case event_type::dies_from_asthma_attack: return "dies_from_asthma_attack"; case event_type::dies_from_drug_overdose: return "dies_from_drug_overdose"; + case event_type::dies_from_bleeding: return "dies_from_bleeding"; + case event_type::dies_from_hypovolemia: return "dies_from_hypovolemia"; + case event_type::dies_from_redcells_loss: return "dies_from_redcells_loss"; case event_type::dies_of_infection: return "dies_of_infection"; case event_type::dies_of_starvation: return "dies_of_starvation"; case event_type::dies_of_thirst: return "dies_of_thirst"; @@ -107,7 +110,7 @@ DEFINE_EVENT_HELPER_FIELDS( event_spec_empty ) DEFINE_EVENT_HELPER_FIELDS( event_spec_character ) DEFINE_EVENT_HELPER_FIELDS( event_spec_character_item ) -static_assert( static_cast( event_type::num_event_types ) == 75, +static_assert( static_cast( event_type::num_event_types ) == 78, "This static_assert is a reminder to add a definition below when you add a new " "event_type. If your event_spec specialization inherits from another struct for " "its fields definition then you probably don't need a definition here." ); diff --git a/src/event.h b/src/event.h index f61ce0a215db2..219e141dda260 100644 --- a/src/event.h +++ b/src/event.h @@ -58,6 +58,9 @@ enum class event_type : int { destroys_triffid_grove, dies_from_asthma_attack, dies_from_drug_overdose, + dies_from_bleeding, + dies_from_hypovolemia, + dies_from_redcells_loss, dies_of_infection, dies_of_starvation, dies_of_thirst, @@ -158,7 +161,7 @@ struct event_spec_character_item { }; }; -static_assert( static_cast( event_type::num_event_types ) == 75, +static_assert( static_cast( event_type::num_event_types ) == 78, "This static_assert is to remind you to add a specialization for your new " "event_type below" ); @@ -385,6 +388,15 @@ struct event_spec { }; }; +template<> +struct event_spec : event_spec_character {}; + +template<> +struct event_spec : event_spec_character {}; + +template<> +struct event_spec : event_spec_character {}; + template<> struct event_spec : event_spec_character {}; diff --git a/src/explosion.cpp b/src/explosion.cpp index 440c5ed6a29ea..899427a111fd0 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -14,7 +14,6 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" #include "cata_utility.h" @@ -44,7 +43,6 @@ #include "mtype.h" #include "npc.h" #include "optional.h" -#include "player.h" #include "point.h" #include "projectile.h" #include "rng.h" @@ -275,7 +273,7 @@ static void do_blast( const tripoint &p, const float power, explosion_colors[pt] = col; } - draw_custom_explosion( g->u.pos(), explosion_colors ); + draw_custom_explosion( get_player_character().pos(), explosion_colors ); for( const tripoint &pt : closed ) { const float force = power * std::pow( distance_factor, dist_map.at( pt ) ); @@ -315,7 +313,7 @@ static void do_blast( const tripoint &p, const float power, add_msg( m_debug, "Blast hits %s with force %.1f", critter->disp_name(), force ); - player *pl = dynamic_cast( critter ); + Character *pl = critter->as_character(); if( pl == nullptr ) { // TODO: player's fault? const double dmg = std::max( force - critter->get_armor_bash( bodypart_id( "torso" ) ) / 2.0, 0.0 ); @@ -387,7 +385,7 @@ static std::vector shrapnel( const tripoint &src, int power, // TODO: Calculate range based on max effective range for projectiles. // Basically bisect between 0 and map diameter using shrapnel_calc(). // Need to update shadowcasting to support limiting range without adjusting initial distance. - const tripoint_range area = here.points_on_zlevel( src.z ); + const tripoint_range area = here.points_on_zlevel( src.z ); here.build_obstacle_cache( area.min(), area.max() + tripoint_south_east, obstacle_cache ); @@ -402,6 +400,7 @@ static std::vector shrapnel( const tripoint &src, int power, update_fragment_cloud, accumulate_fragment_cloud> ( visited_cache, obstacle_cache, src.xy(), 0, initial_cloud ); + Character &player_character = get_player_character(); // Now visited_caches are populated with density and velocity of fragments. for( const tripoint &target : area ) { fragment_cloud &cloud = visited_cache[target.x][target.y]; @@ -444,7 +443,7 @@ static std::vector shrapnel( const tripoint &src, int power, } } int total_hits = damaging_hits + non_damaging_hits; - if( total_hits > 0 && g->u.sees( *critter ) ) { + if( total_hits > 0 && player_character.sees( *critter ) ) { // Building a phrase to summarize the fragment effects. // Target, Number of impacts, total amount of damage, proportion of deflected fragments. std::map impact_count_descriptions = { @@ -554,28 +553,31 @@ void explosion( const tripoint &p, const explosion_data &ex ) void flashbang( const tripoint &p, bool player_immune ) { draw_explosion( p, 8, c_white ); - int dist = rl_dist( g->u.pos(), p ); + Character &player_character = get_player_character(); + int dist = rl_dist( player_character.pos(), p ); map &here = get_map(); if( dist <= 8 && !player_immune ) { - if( !g->u.has_bionic( bio_ears ) && !g->u.is_wearing( itype_rm13_armor_on ) ) { - g->u.add_effect( effect_deaf, time_duration::from_turns( 40 - dist * 4 ) ); + if( !player_character.has_bionic( bio_ears ) && + !player_character.is_wearing( itype_rm13_armor_on ) ) { + player_character.add_effect( effect_deaf, time_duration::from_turns( 40 - dist * 4 ) ); } - if( here.sees( g->u.pos(), p, 8 ) ) { + if( here.sees( player_character.pos(), p, 8 ) ) { int flash_mod = 0; - if( g->u.has_trait( trait_PER_SLIME ) ) { + if( player_character.has_trait( trait_PER_SLIME ) ) { if( one_in( 2 ) ) { flash_mod = 3; // Yay, you weren't looking! } - } else if( g->u.has_trait( trait_PER_SLIME_OK ) ) { + } else if( player_character.has_trait( trait_PER_SLIME_OK ) ) { flash_mod = 8; // Just retract those and extrude fresh eyes - } else if( g->u.has_bionic( bio_sunglasses ) || - g->u.is_wearing( itype_rm13_armor_on ) ) { + } else if( player_character.has_bionic( bio_sunglasses ) || + player_character.is_wearing( itype_rm13_armor_on ) ) { flash_mod = 6; - } else if( g->u.worn_with_flag( flag_BLIND ) || g->u.worn_with_flag( flag_FLASH_PROTECTION ) ) { + } else if( player_character.worn_with_flag( flag_BLIND ) || + player_character.worn_with_flag( flag_FLASH_PROTECTION ) ) { flash_mod = 3; // Not really proper flash protection, but better than nothing } - g->u.add_env_effect( effect_blind, bp_eyes, ( 12 - flash_mod - dist ) / 2, - time_duration::from_turns( 10 - dist ) ); + player_character.add_env_effect( effect_blind, bp_eyes, ( 12 - flash_mod - dist ) / 2, + time_duration::from_turns( 10 - dist ) ); } } for( monster &critter : g->all_monsters() ) { @@ -617,7 +619,7 @@ void shockwave( const tripoint &p, int radius, int force, int stun, int dam_mult g->knockback( p, critter.pos(), force, stun, dam_mult ); } } - // TODO: combine the two loops and the case for g->u using all_creatures() + // TODO: combine the two loops and the case for avatar using all_creatures() for( npc &guy : g->all_npcs() ) { if( guy.posz() != p.z ) { continue; @@ -627,11 +629,13 @@ void shockwave( const tripoint &p, int radius, int force, int stun, int dam_mult g->knockback( p, guy.pos(), force, stun, dam_mult ); } } - if( rl_dist( g->u.pos(), p ) <= radius && !ignore_player && - ( !g->u.has_trait( trait_LEG_TENT_BRACE ) || g->u.footwear_factor() == 1 || - ( g->u.footwear_factor() == .5 && one_in( 2 ) ) ) ) { + Character &player_character = get_player_character(); + if( rl_dist( player_character.pos(), p ) <= radius && !ignore_player && + ( !player_character.has_trait( trait_LEG_TENT_BRACE ) || + player_character.footwear_factor() == 1 || + ( player_character.footwear_factor() == .5 && one_in( 2 ) ) ) ) { add_msg( m_bad, _( "You're caught in the shockwave!" ) ); - g->knockback( p, g->u.pos(), force, stun, dam_mult ); + g->knockback( p, player_character.pos(), force, stun, dam_mult ); } } @@ -651,13 +655,14 @@ void emp_blast( const tripoint &p ) { // TODO: Implement z part point p2( p.xy() ); - const bool sight = g->u.sees( p ); + Character &player_character = get_player_character(); + const bool sight = player_character.sees( p ); map &here = get_map(); if( here.has_flag( "CONSOLE", p2 ) ) { if( sight ) { add_msg( _( "The %s is rendered non-functional!" ), here.tername( p2 ) ); } - here.ter_set( p2, t_console_broken ); + here.furn_set( p2, furn_str_id( "f_machinery_electronic" ) ); return; } // TODO: More terrain effects. @@ -744,21 +749,21 @@ void emp_blast( const tripoint &p ) add_msg( _( "The %s is unaffected by the EMP blast." ), critter.name() ); } } - if( g->u.posx() == p2.x && g->u.posy() == p2.y ) { - if( g->u.get_power_level() > 0_kJ ) { + if( player_character.posx() == p2.x && player_character.posy() == p2.y ) { + if( player_character.get_power_level() > 0_kJ ) { add_msg( m_bad, _( "The EMP blast drains your power." ) ); - int max_drain = ( g->u.get_power_level() > 1000_kJ ? 1000 : units::to_kilojoule( - g->u.get_power_level() ) ); - g->u.mod_power_level( units::from_kilojoule( -rng( 1 + max_drain / 3, max_drain ) ) ); + int max_drain = ( player_character.get_power_level() > 1000_kJ ? 1000 : units::to_kilojoule( + player_character.get_power_level() ) ); + player_character.mod_power_level( units::from_kilojoule( -rng( 1 + max_drain / 3, max_drain ) ) ); } // TODO: More effects? //e-handcuffs effects - if( g->u.weapon.typeId() == itype_e_handcuffs && g->u.weapon.charges > 0 ) { - g->u.weapon.item_tags.erase( "NO_UNWIELD" ); - g->u.weapon.charges = 0; - g->u.weapon.active = false; + if( player_character.weapon.typeId() == itype_e_handcuffs && player_character.weapon.charges > 0 ) { + player_character.weapon.item_tags.erase( "NO_UNWIELD" ); + player_character.weapon.charges = 0; + player_character.weapon.active = false; add_msg( m_good, _( "The %s on your wrists spark briefly, then release your hands!" ), - g->u.weapon.tname() ); + player_character.weapon.tname() ); } } // Drain any items of their battery charge @@ -772,12 +777,14 @@ void emp_blast( const tripoint &p ) void resonance_cascade( const tripoint &p ) { - const time_duration maxglow = time_duration::from_turns( 100 - 5 * trig_dist( p, g->u.pos() ) ); + Character &player_character = get_player_character(); + const time_duration maxglow = time_duration::from_turns( 100 - 5 * trig_dist( p, + player_character.pos() ) ); MonsterGroupResult spawn_details; if( maxglow > 0_turns ) { const time_duration minglow = std::max( 0_turns, time_duration::from_turns( 60 - 5 * trig_dist( p, - g->u.pos() ) ) ); - g->u.add_effect( effect_teleglow, rng( minglow, maxglow ) * 100 ); + player_character.pos() ) ) ); + player_character.add_effect( effect_teleglow, rng( minglow, maxglow ) * 100 ); } int startx = ( p.x < 8 ? 0 : p.x - 8 ), endx = ( p.x + 8 >= SEEX * 3 ? SEEX * 3 - 1 : p.x + 8 ); int starty = ( p.y < 8 ? 0 : p.y - 8 ), endy = ( p.y + 8 >= SEEY * 3 ? SEEY * 3 - 1 : p.y + 8 ); diff --git a/src/faction.cpp b/src/faction.cpp index 2b4b99502ab02..d135375e5a66b 100644 --- a/src/faction.cpp +++ b/src/faction.cpp @@ -30,6 +30,7 @@ #include "point.h" #include "skill.h" #include "string_formatter.h" +#include "talker.h" #include "translations.h" #include "type_id.h" #include "ui_manager.h" @@ -899,7 +900,7 @@ void faction_manager::display() const popup( _( "%s returns from their mission" ), guy->disp_name() ); } else { if( tab == tab_mode::TAB_FOLLOWERS && guy && ( interactable || radio_interactable ) ) { - guy->talk_to_u( false, radio_interactable ); + g->u.talk_to( get_talker_for( *guy ), false, radio_interactable ); } else if( tab == tab_mode::TAB_MYFACTION && camp ) { camp->query_new_name(); } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 26a529b2d9992..eefe9587cd31e 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -1595,7 +1595,8 @@ void basecamp::start_upgrade( const std::string &bldg, const point &dir, return; } - time_duration work_days = base_camps::to_workdays( making.batch_duration() ); + time_duration work_days = base_camps::to_workdays( making.batch_duration( + get_player_character() ) ); npc_ptr comp = nullptr; if( making.required_skills.empty() ) { if( making.skill_used.is_valid() ) { @@ -2151,7 +2152,7 @@ void basecamp::start_fortifications( std::string &bldg_exp ) return; } trips += 2; - build_time += making.batch_duration(); + build_time += making.batch_duration( get_player_character() ); dist += rl_dist( fort_om.xy(), omt_pos.xy() ); travel_time += companion_travel_time_calc( fort_om, omt_pos, 0_minutes, 2 ); } @@ -2252,7 +2253,8 @@ void basecamp::start_crafting( const std::string &cur_id, const point &cur_dir, return; } - time_duration work_days = base_camps::to_workdays( making.batch_duration( batch_size ) ); + time_duration work_days = base_camps::to_workdays( making.batch_duration( get_player_character(), + batch_size ) ); npc_ptr comp = start_mission( miss_id + cur_dir_id, work_days, true, _( "begins to work…" ), false, {}, making.required_skills ); @@ -2609,7 +2611,8 @@ bool basecamp::upgrade_return( const point &dir, const std::string &miss, const tripoint upos = e->second.pos; const recipe &making = recipe_id( bldg ).obj(); - time_duration work_days = base_camps::to_workdays( making.batch_duration() ); + time_duration work_days = base_camps::to_workdays( making.batch_duration( + get_player_character() ) ); npc_ptr comp = companion_choose_return( miss, work_days ); if( comp == nullptr ) { @@ -3041,7 +3044,7 @@ int basecamp::recipe_batch_max( const recipe &making ) const for( size_t batch_size = 1000; batch_size > 0; batch_size /= 10 ) { for( int iter = 0; iter < max_checks; iter++ ) { time_duration work_days = base_camps::to_workdays( making.batch_duration( - max_batch + batch_size ) ); + get_player_character(), max_batch + batch_size ) ); int food_req = time_to_food( work_days ); bool can_make = making.deduped_requirements().can_make_with_inventory( _inv, making.get_component_filter(), max_batch + batch_size ); @@ -3676,7 +3679,7 @@ std::string basecamp::craft_description( const recipe_id &itm ) } comp = string_format( _( "Skill used: %s\nDifficulty: %d\n%s\nTime: %s\n" ), making.skill_used.obj().name(), making.difficulty, comp, - to_string( base_camps::to_workdays( making.batch_duration() ) ) ); + to_string( base_camps::to_workdays( making.batch_duration( get_player_character() ) ) ) ); return comp; } diff --git a/src/game.cpp b/src/game.cpp index 16ddae9681fd8..b43a66ffea612 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -141,6 +141,7 @@ #include "string_id.h" #include "string_input_popup.h" #include "submap.h" +#include "talker.h" #include "tileray.h" #include "timed_event.h" #include "translations.h" @@ -249,6 +250,8 @@ static const trait_id trait_PARKOUR( "PARKOUR" ); static const trait_id trait_VINES2( "VINES2" ); static const trait_id trait_VINES3( "VINES3" ); static const trait_id trait_THICKSKIN( "THICKSKIN" ); +static const trait_id trait_NPC_STATIC_NPC( "NPC_STATIC_NPC" ); +static const trait_id trait_NPC_STARTING_NPC( "NPC_STARTING_NPC" ); static const trap_str_id tr_unfinished_construction( "tr_unfinished_construction" ); @@ -275,8 +278,8 @@ bool is_valid_in_w_terrain( const point &p ) static void achievement_attained( const achievement *a, bool achievements_enabled ) { if( achievements_enabled ) { - g->u.add_msg_if_player( m_good, _( "You completed the achievement \"%s\"." ), - a->name() ); + add_msg( m_good, _( "You completed the achievement \"%s\"." ), + a->name() ); } g->events().send( a->id, achievements_enabled ); } @@ -287,7 +290,7 @@ static void achievement_failed( const achievement *a, bool achievements_enabled return; } if( achievements_enabled ) { - g->u.add_msg_if_player( m_bad, _( "You lost the conduct \"%s\"." ), a->name() ); + add_msg( m_bad, _( "You lost the conduct \"%s\"." ), a->name() ); } g->events().send( a->id, achievements_enabled ); } @@ -574,7 +577,7 @@ void game::setup() load_world_modfiles( ui ); - m = map( get_option( "ZLEVELS" ) ); + m = map( true ); next_npc_id = character_id( 1 ); next_mission_id = 1; @@ -587,7 +590,7 @@ void game::setup() calendar::set_eternal_season( ::get_option( "ETERNAL_SEASON" ) ); calendar::set_season_length( ::get_option( "SEASON_LENGTH" ) ); - weather.weather = WEATHER_CLEAR; // Start with some nice weather... + weather.weather_id = WEATHER_CLEAR; // Weather shift in 30 weather.nextweather = calendar::start_of_cataclysm + time_duration::from_hours( get_option( "INITIAL_TIME" ) ) + 30_minutes; @@ -704,10 +707,8 @@ bool game::start_game() get_auto_notes_settings().clear(); get_auto_notes_settings().default_initialize(); - //Put some NPCs in there! - if( get_option( "STARTING_NPC" ) == "always" || - ( get_option( "STARTING_NPC" ) == "scenario" && - !g->scen->has_flag( "LONE_START" ) ) ) { + // spawn the starting NPC, assuming it's not disallowed by the scenario + if( !g->scen->has_flag( "LONE_START" ) ) { create_starting_npcs(); } //Load NPCs. Set nearby npcs to active. @@ -787,7 +788,7 @@ bool game::start_game() } } for( auto &e : u.inv_dump() ) { - e->set_owner( g->u ); + e->set_owner( get_player_character() ); } // Now that we're done handling coordinates, ensure the player's submap is in the center of the map update_map( u ); @@ -946,11 +947,6 @@ const kill_tracker &game::get_kill_tracker() const void game::create_starting_npcs() { - if( !get_option( "STATIC_NPC" ) || - get_option( "STARTING_NPC" ) == "never" ) { - return; //Do not generate a starting npc. - } - //We don't want more than one starting npc per starting location const int radius = 1; if( !overmap_buffer.get_npcs_near_player( radius ).empty() ) { @@ -1090,7 +1086,7 @@ bool game::cleanup_at_end() point( iOffsetX, iOffsetY ) ); draw_border( w_rip ); - sfx::do_player_death_hurt( g->u, true ); + sfx::do_player_death_hurt( get_player_character(), true ); sfx::fade_audio_group( sfx::group::weather, 2000 ); sfx::fade_audio_group( sfx::group::time_of_day, 2000 ); sfx::fade_audio_group( sfx::group::context_themes, 2000 ); @@ -1573,8 +1569,7 @@ bool game::do_turn() } if( get_levz() >= 0 && !u.is_underwater() ) { - do_rain( weather.weather ); - weather::effect( weather.weather )(); + handle_weather_effects( weather.weather_id ); } const bool player_is_sleeping = u.has_effect( effect_sleep ); @@ -1801,6 +1796,7 @@ int get_heat_radiation( const tripoint &location, bool direct ) // Stored as intensity-distance pairs int temp_mod = 0; int best_fire = 0; + Character &player_character = get_player_character(); map &here = get_map(); for( const tripoint &dest : here.points_in_radius( location, 6 ) ) { int heat_intensity = 0; @@ -1810,14 +1806,14 @@ int get_heat_radiation( const tripoint &location, bool direct ) int ffire = maptile_field_intensity( mt, fd_fire ); if( ffire > 0 ) { heat_intensity = ffire; - } else if( here.tr_at( dest ).loadid == tr_lava ) { + } else if( here.tr_at( dest ) == tr_lava ) { heat_intensity = 3; } if( heat_intensity == 0 ) { // No heat source here continue; } - if( g->u.pos() == location ) { + if( player_character.pos() == location ) { if( !here.pl_line_of_sight( dest, -1 ) ) { continue; } @@ -1843,8 +1839,7 @@ int get_convection_temperature( const tripoint &location ) int temp_mod = 0; map &here = get_map(); // Directly on lava tiles - int lava_mod = here.tr_at( location ).loadid == tr_lava ? - fd_fire.obj().get_convection_temperature_mod() : 0; + int lava_mod = here.tr_at( location ) == tr_lava ? fd_fire->get_convection_temperature_mod() : 0; // Modifier from fields for( auto fd : here.field_at( location ) ) { // Nullify lava modifier when there is open fire @@ -2001,6 +1996,7 @@ static void handle_contents_changed( const item_location &acted_item ) } item_location parent = acted_item; item_pocket *pocket = nullptr; + Character &player_character = get_player_character(); do { item_location child = parent; parent = parent.parent_item(); @@ -2016,7 +2012,7 @@ static void handle_contents_changed( const item_location &acted_item ) pocket->on_contents_changed(); if( pocket->will_spill() ) { - pocket->handle_liquid_or_spill( g->u ); + pocket->handle_liquid_or_spill( player_character ); } } while( parent.where() == item_location::type::container ); } @@ -2312,7 +2308,7 @@ int game::inventory_item_menu( item_location locThisItem, handle_contents_changed( locThisItem ); break; case 'U': - unload( locThisItem ); + u.unload( locThisItem ); handle_contents_changed( locThisItem ); break; case 'r': @@ -2580,6 +2576,7 @@ input_context get_default_mode_input_context() ctxt.register_action( "autoattack" ); ctxt.register_action( "ignore_enemy" ); ctxt.register_action( "whitelist_enemy" ); + ctxt.register_action( "workout" ); ctxt.register_action( "save" ); ctxt.register_action( "quicksave" ); #if !defined(RELEASE) @@ -2937,7 +2934,7 @@ bool game::load( const save_t &name ) validate_linked_vehicles(); update_map( u ); for( auto &e : u.inv_dump() ) { - e->set_owner( g->u ); + e->set_owner( get_player_character() ); } // legacy, needs to be here as we access the map. if( !u.getID().is_valid() ) { @@ -3124,7 +3121,7 @@ bool game::save_player_data() }, _( "player map memory" ) ); const bool saved_log = write_to_file( playerfile + SAVE_EXTENSION_LOG, [&]( std::ostream & fout ) { - fout << memorial().dump(); + memorial().save( fout ); }, _( "player memorial" ) ); #if defined(__ANDROID__) const bool saved_shortcuts = write_to_file( playerfile + SAVE_EXTENSION_SHORTCUTS, [&]( @@ -3263,11 +3260,15 @@ void game::write_memorial_file( std::string sLastWords ) std::strftime( buffer, suffix_len, "%Y-%m-%d-%H-%M-%S", std::localtime( &t ) ); memorial_file_path << buffer; - memorial_file_path << ".txt"; + const std::string text_path_string = memorial_file_path.str() + ".txt"; + const std::string json_path_string = memorial_file_path.str() + ".json"; + + write_to_file( text_path_string, [&]( std::ostream & fout ) { + memorial().write_text_memorial( fout, sLastWords ); + }, _( "player memorial" ) ); - const std::string path_string = memorial_file_path.str(); - write_to_file( memorial_file_path.str(), [&]( std::ostream & fout ) { - memorial().write( fout, sLastWords ); + write_to_file( json_path_string, [&]( std::ostream & fout ) { + memorial().write_json_memorial( fout ); }, _( "player memorial" ) ); } @@ -3311,7 +3312,7 @@ void game::display_faction_epilogues() struct npc_dist_to_player { const tripoint ppos{}; - npc_dist_to_player() : ppos( g->u.global_omt_location() ) { } + npc_dist_to_player() : ppos( get_player_character().global_omt_location() ) { } // Operator overload required to leverage sort API. bool operator()( const shared_ptr_fast &a, const shared_ptr_fast &b ) const { @@ -3326,7 +3327,8 @@ void game::disp_NPCs() { const tripoint ppos = u.global_omt_location(); const tripoint &lpos = u.pos(); - std::vector> npcs = overmap_buffer.get_npcs_near_player( 100 ); + const int scan_range = 120; + std::vector> npcs = overmap_buffer.get_npcs_near_player( scan_range ); std::sort( npcs.begin(), npcs.end(), npc_dist_to_player() ); catacurses::window w; @@ -3346,13 +3348,22 @@ void game::disp_NPCs() mvwprintz( w, point( 0, 1 ), c_white, _( "Your local position: %d, %d, %d" ), lpos.x, lpos.y, lpos.z ); size_t i; + int static_npc_count = 0; + for( i = 0; i < npcs.size(); i++ ) { + if( + npcs[i]->has_trait( trait_NPC_STARTING_NPC ) || npcs[i]->has_trait( trait_NPC_STATIC_NPC ) ) { + static_npc_count++; + } + } + mvwprintz( w, point( 0, 2 ), c_white, _( "Total NPCs within %d OMTs: %d. %d are static NPCs." ), + scan_range, npcs.size(), static_npc_count ); for( i = 0; i < 20 && i < npcs.size(); i++ ) { const tripoint apos = npcs[i]->global_omt_location(); - mvwprintz( w, point( 0, i + 3 ), c_white, "%s: %d, %d, %d", npcs[i]->name, + mvwprintz( w, point( 0, i + 4 ), c_white, "%s: %d, %d, %d", npcs[i]->name, apos.x, apos.y, apos.z ); } for( const monster &m : all_monsters() ) { - mvwprintz( w, point( 0, i + 3 ), c_white, "%s: %d, %d, %d", m.name(), + mvwprintz( w, point( 0, i + 4 ), c_white, "%s: %d, %d, %d", m.name(), m.posx(), m.posy(), m.posz() ); ++i; } @@ -3517,8 +3528,10 @@ static shared_ptr_fast create_zone_callback( } } if( zone_blink && zone_start && zone_end ) { - const point offset2( g->u.view_offset.xy() + point( g->u.posx() - getmaxx( g->w_terrain ) / 2, - g->u.posy() - getmaxy( g->w_terrain ) / 2 ) ); + avatar &player_character = get_avatar(); + const point offset2( player_character.view_offset.xy() + + point( player_character.posx() - getmaxx( g->w_terrain ) / 2, + player_character.posy() - getmaxy( g->w_terrain ) / 2 ) ); tripoint offset; #if defined(TILES) @@ -3724,7 +3737,7 @@ void game::draw_ter( const tripoint ¢er, const bool looking, const bool draw draw_veh_dir_indicator( true ); } // Place the cursor over the player as is expected by screen readers. - wmove( w_terrain, -center.xy() + g->u.pos().xy() + point( POSX, POSY ) ); + wmove( w_terrain, -center.xy() + get_player_character().pos().xy() + point( POSX, POSY ) ); } cata::optional game::get_veh_dir_indicator_location( bool next ) const @@ -3934,7 +3947,9 @@ void game::draw_minimap() } } - const int sight_points = g->u.overmap_sight_range( g->light_level( g->u.posz() ) ); + Character &player_character = get_player_character(); + const int sight_points = player_character.overmap_sight_range( g->light_level( + player_character.posz() ) ); for( int i = -3; i <= 3; i++ ) { for( int j = -3; j <= 3; j++ ) { if( i > -3 && i < 3 && j > -3 && j < 3 ) { @@ -3948,7 +3963,7 @@ void game::draw_minimap() omx, omy, get_levz() }; if( overmap_buffer.seen( omp ) - && g->u.overmap_los( cur_pos, sight_points ) ) { + && player_character.overmap_los( cur_pos, sight_points ) ) { mvwputch( w_minimap, point( i + 3, j + 3 ), c_green, overmap_buffer.get_horde_size( omp ) > HORDE_VISIBILITY_SIZE * 2 ? 'Z' : 'z' ); } @@ -3981,7 +3996,7 @@ float game::natural_light_level( const int zlev ) const ret = default_daylight_level(); } - ret += weather::light_modifier( weather.weather ); + ret += get_weather().weather_id->light_modifier; // Artifact light level changes here. Even though some of these only have an effect // aboveground it is cheaper performance wise to simply iterate through the entire @@ -4373,7 +4388,7 @@ void game::mon_info_update( ) if( ( !safemode_empty && safemode_state == rule_state::BLACKLISTED ) || ( safemode_empty && ( MATT_ATTACK == matt || MATT_FOLLOW == matt ) ) ) { - if( index < 8 && critter.sees( g->u ) ) { + if( index < 8 && critter.sees( get_player_character() ) ) { dangerous[index] = true; } @@ -5037,7 +5052,7 @@ static bool can_place_monster( const monster &mon, const tripoint &p ) } static cata::optional choose_where_to_place_monster( const monster &mon, - const tripoint_range &range ) + const tripoint_range &range ) { return random_point( range, [&]( const tripoint & p ) { return can_place_monster( mon, p ); @@ -5085,7 +5100,7 @@ monster *game::place_critter_around( const shared_ptr_fast &mon, return critter_tracker->add( mon ) ? mon.get() : nullptr; } -monster *game::place_critter_within( const mtype_id &id, const tripoint_range &range ) +monster *game::place_critter_within( const mtype_id &id, const tripoint_range &range ) { // TODO: change this into an assert, it must never happen. if( id.is_null() ) { @@ -5095,7 +5110,7 @@ monster *game::place_critter_within( const mtype_id &id, const tripoint_range &r } monster *game::place_critter_within( const shared_ptr_fast &mon, - const tripoint_range &range ) + const tripoint_range &range ) { const cata::optional where = choose_where_to_place_monster( *mon, range ); if( !where ) { @@ -5107,7 +5122,8 @@ monster *game::place_critter_within( const shared_ptr_fast &mon, size_t game::num_creatures() const { - return critter_tracker->size() + active_npc.size() + 1; // 1 == g->u + // Plus one for the player. + return critter_tracker->size() + active_npc.size() + 1; } bool game::update_zombie_pos( const monster &critter, const tripoint &pos ) @@ -5125,6 +5141,25 @@ void game::clear_zombies() critter_tracker->clear(); } +bool game::find_nearby_spawn_point( const Character &target, const mtype_id &mt, int min_radius, + int max_radius, tripoint &point ) +{ + tripoint target_point; + //find a legal outdoor place to spawn based on the specified radius, + //we just try a bunch of random points and use the first one that works, it none do then no spawn + for( int attempts = 0; attempts < 15; attempts++ ) { + target_point = target.pos() + tripoint( rng( -max_radius, max_radius ), + rng( -max_radius, max_radius ), 0 ); + if( can_place_monster( mt->id, target_point ) && + get_map().is_outside( target_point ) && + rl_dist( target_point, get_player_character().pos() ) > min_radius ) { + point = target_point; + return true; + } + } + return false; +} + /** * Attempts to spawn a hallucination at given location. * Returns false if the hallucination couldn't be spawned for whatever reason, such as @@ -5147,7 +5182,16 @@ bool game::spawn_hallucination( const tripoint &p ) } } - const mtype_id &mt = MonsterGenerator::generator().get_valid_hallucination(); + return spawn_hallucination( p, MonsterGenerator::generator().get_valid_hallucination() ); +} +/** + * Attempts to spawn a hallucination at given location. + * Returns false if the hallucination couldn't be spawned for whatever reason, such as + * a monster already in the target square. + * @return Whether or not a hallucination was successfully spawned. + */ +bool game::spawn_hallucination( const tripoint &p, const mtype_id &mt ) +{ const shared_ptr_fast phantasm = make_shared_fast( mt ); phantasm->hallucination = true; phantasm->spawn( p ); @@ -5238,8 +5282,8 @@ bool game::is_empty( const tripoint &p ) bool game::is_in_sunlight( const tripoint &p ) { - return ( m.is_outside( p ) && light_level( p.z ) >= 40 && - ( weather.weather == WEATHER_CLEAR || weather.weather == WEATHER_SUNNY ) ); + return ( m.is_outside( p ) && light_level( p.z ) >= 40 && !is_night( calendar::turn ) && + get_weather().weather_id->sun_intensity >= sun_intensity_type::normal ); } bool game::is_sheltered( const tripoint &p ) @@ -5312,7 +5356,7 @@ void game::save_cyborg( item *cyborg, const tripoint &couch_pos, player &install difficulty - 4 * assist_bonus ), installer ); int success = chance_of_success - rng( 1, 100 ); - if( !g->u.query_yn( + if( !get_avatar().query_yn( _( "WARNING: %i percent chance of SEVERE damage to all body parts! Continue anyway?" ), 100 - static_cast( chance_of_success ) ) ) { return; @@ -5575,7 +5619,7 @@ void game::control_vehicle() int num_valid_controls = 0; cata::optional vehicle_position; cata::optional vehicle_controls; - for( const tripoint elem : m.points_in_radius( g->u.pos(), 1 ) ) { + for( const tripoint elem : m.points_in_radius( get_player_character().pos(), 1 ) ) { if( const optional_vpart_position vp = m.veh_at( elem ) ) { const cata::optional controls = vp.value().part_with_feature( "CONTROLS", true ); if( controls ) { @@ -5665,7 +5709,7 @@ bool game::npc_menu( npc &who ) const int choice = amenu.ret; if( choice == talk ) { - who.talk_to_u(); + u.talk_to( get_talker_for( who ) ); } else if( choice == swap_pos ) { if( !prompt_dangerous_tile( who.pos() ) ) { return true; @@ -5776,7 +5820,7 @@ static std::string get_fire_fuel_string( const tripoint &examp ) } time_duration fire_age = fire->get_field_age(); // half-life inclusion - int mod = 5 - g->u.get_skill_level( skill_survival ); + int mod = 5 - get_player_character().get_skill_level( skill_survival ); mod = std::max( mod, 0 ); if( fire_age >= 0_turns ) { if( mod >= 4 ) { // = survival level 0-1 @@ -5907,11 +5951,8 @@ void game::examine( const tripoint &examp ) none = false; } - if( !m.tr_at( examp ).is_null() && !u.is_mounted() ) { - iexamine::trap( u, examp ); - } else if( !m.tr_at( examp ).is_null() && u.is_mounted() ) { - add_msg( m_warning, _( "You cannot do that while mounted." ) ); - } + // trap::iexamine will handle the invisible traps. + m.tr_at( examp ).examine( examp ); // In case of teleport trap or somesuch if( player_pos != u.pos() ) { @@ -6294,7 +6335,7 @@ void game::print_trap_info( const tripoint &lp, const catacurses::window &w_look if( tr.can_see( lp, u ) ) { partial_con *pc = m.partial_con_at( lp ); std::string tr_name; - if( pc && tr.loadid == tr_unfinished_construction ) { + if( pc && tr == tr_unfinished_construction ) { const construction &built = pc->id.obj(); tr_name = string_format( _( "Unfinished task: %s, %d%% complete" ), built.description, pc->counter / 100000 ); @@ -6730,8 +6771,8 @@ void game::zones_manager() break; } - mgr.add( name, id, g->u.get_faction()->id, false, true, position->first, - position->second, options ); + mgr.add( name, id, get_player_character().get_faction()->id, false, true, + position->first, position->second, options ); zones = get_zones(); active_index = zone_cnt - 1; @@ -7224,7 +7265,7 @@ std::vector game::find_nearby_items( int iRadius ) return ret; } - for( auto &points_p_it : closest_tripoints_first( u.pos(), iRadius ) ) { + for( auto &points_p_it : closest_points_first( u.pos(), iRadius ) ) { if( points_p_it.y >= u.posy() - iRadius && points_p_it.y <= u.posy() + iRadius && u.sees( points_p_it ) && m.sees_some_items( points_p_it, u ) ) { @@ -7253,7 +7294,8 @@ std::vector game::find_nearby_items( int iRadius ) void draw_trail( const tripoint &start, const tripoint &end, const bool bDrawX ) { std::vector pts; - tripoint center = g->u.pos() + g->u.view_offset; + avatar &player_character = get_avatar(); + tripoint center = player_character.pos() + player_character.view_offset; if( start != end ) { //Draw trail pts = line_to( start, end, 0, 0 ); @@ -7273,8 +7315,8 @@ void draw_trail( const tripoint &start, const tripoint &end, const bool bDrawX ) if( pts.empty() ) { mvwputch( g->w_terrain, point( POSX, POSY ), c_white, sym ); } else { - mvwputch( g->w_terrain, pts.back().xy() - g->u.view_offset.xy() + - point( POSX - g->u.posx(), POSY - g->u.posy() ), + mvwputch( g->w_terrain, pts.back().xy() - player_character.view_offset.xy() + + point( POSX - player_character.posx(), POSY - player_character.posy() ), c_white, sym ); } } @@ -7287,7 +7329,7 @@ void game::draw_trail_to_square( const tripoint &t, bool bDrawX ) static void centerlistview( const tripoint &active_item_position, int ui_width ) { - player &u = g->u; + player &u = get_avatar(); if( get_option( "SHIFT_LIST_ITEM_VIEW" ) != "false" ) { u.view_offset.z = active_item_position.z; if( get_option( "SHIFT_LIST_ITEM_VIEW" ) == "centered" ) { @@ -8083,7 +8125,7 @@ game::vmenu_ret game::list_monsters( const std::vector &monster_list const auto critter = monster_list[iCurMon]; const bool selected = iCurMon == iActive; ++iCurMon; - if( critter->sees( g->u ) ) { + if( critter->sees( u ) ) { mvwprintz( w_monsters, point( 0, y ), c_yellow, "!" ); } bool is_npc = false; @@ -8377,8 +8419,8 @@ static void add_disassemblables( uilist &menu, const auto &msg = string_format( pgettext( "butchery menu", "%s (%d)" ), it.tname(), stack.second ); menu.addentry_col( menu_index++, true, hotkey, msg, - to_string_clipped( time_duration::from_turns( recipe_dictionary::get_uncraft( - it.typeId() ).time / 100 ) ) ); + to_string_clipped( recipe_dictionary::get_uncraft( + it.typeId() ).time_to_craft( get_player_character() ) ) ); hotkey = -1; } } @@ -8387,25 +8429,26 @@ static void add_disassemblables( uilist &menu, // Butchery sub-menu and time calculation static void butcher_submenu( const std::vector &corpses, int corpse = -1 ) { + avatar &player_character = get_avatar(); auto cut_time = [&]( butcher_type bt ) { int time_to_cut = 0; if( corpse != -1 ) { - time_to_cut = butcher_time_to_cut( g->u, *corpses[corpse], bt ); + time_to_cut = butcher_time_to_cut( player_character, *corpses[corpse], bt ); } else { for( const map_stack::iterator &it : corpses ) { - time_to_cut += butcher_time_to_cut( g->u, *it, bt ); + time_to_cut += butcher_time_to_cut( player_character, *it, bt ); } } return to_string_clipped( time_duration::from_turns( time_to_cut / 100 ) ); }; - const bool enough_light = g->u.fine_detail_vision_mod() <= 4; + const bool enough_light = player_character.fine_detail_vision_mod() <= 4; - const int factor = g->u.max_quality( quality_id( "BUTCHER" ) ); + const int factor = player_character.max_quality( quality_id( "BUTCHER" ) ); const std::string msgFactor = factor > INT_MIN ? string_format( _( "Your best tool has %d butchering." ), factor ) : _( "You have no butchering tool." ); - const int factorD = g->u.max_quality( quality_id( "CUT_FINE" ) ); + const int factorD = player_character.max_quality( quality_id( "CUT_FINE" ) ); const std::string msgFactorD = factorD > INT_MIN ? string_format( _( "Your best tool has %d fine cutting." ), factorD ) : _( "You have no fine cutting tool." ); @@ -8506,25 +8549,25 @@ static void butcher_submenu( const std::vector &corpses, in smenu.query(); switch( smenu.ret ) { case static_cast( butcher_type::QUICK ): - g->u.assign_activity( activity_id( "ACT_BUTCHER" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_BUTCHER" ), 0, true ); break; case static_cast( butcher_type::FULL ): - g->u.assign_activity( activity_id( "ACT_BUTCHER_FULL" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_BUTCHER_FULL" ), 0, true ); break; case static_cast( butcher_type::FIELD_DRESS ): - g->u.assign_activity( activity_id( "ACT_FIELD_DRESS" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_FIELD_DRESS" ), 0, true ); break; case static_cast( butcher_type::SKIN ): - g->u.assign_activity( activity_id( "ACT_SKIN" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_SKIN" ), 0, true ); break; case static_cast( butcher_type::QUARTER ): - g->u.assign_activity( activity_id( "ACT_QUARTER" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_QUARTER" ), 0, true ); break; case static_cast( butcher_type::DISMEMBER ): - g->u.assign_activity( activity_id( "ACT_DISMEMBER" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_DISMEMBER" ), 0, true ); break; case static_cast( butcher_type::DISSECT ): - g->u.assign_activity( activity_id( "ACT_DISSECT" ), 0, true ); + player_character.assign_activity( activity_id( "ACT_DISSECT" ), 0, true ); break; default: return; @@ -8680,7 +8723,8 @@ void game::butcher() int time_to_disassemble = 0; int time_to_disassemble_all = 0; for( const auto &stack : disassembly_stacks ) { - const int time = recipe_dictionary::get_uncraft( stack.first->typeId() ).time; + const int time = recipe_dictionary::get_uncraft( stack.first->typeId() ).time_to_craft_moves( + get_player_character() ); time_to_disassemble += time; time_to_disassemble_all += time * stack.second; } @@ -8949,11 +8993,11 @@ void game::reload_weapon( bool try_everything ) vehicle *veh = veh_pointer_or_null( m.veh_at( u.pos() ) ); turret_data turret; if( veh && ( turret = veh->turret_query( u.pos() ) ) && turret.can_reload() ) { - item::reload_option opt = g->u.select_ammo( *turret.base(), true ); + item::reload_option opt = u.select_ammo( *turret.base(), true ); if( opt ) { - g->u.assign_activity( activity_id( "ACT_RELOAD" ), opt.moves(), opt.qty() ); - g->u.activity.targets.emplace_back( turret.base() ); - g->u.activity.targets.push_back( std::move( opt.ammo ) ); + u.assign_activity( activity_id( "ACT_RELOAD" ), opt.moves(), opt.qty() ); + u.activity.targets.emplace_back( turret.base() ); + u.activity.targets.push_back( std::move( opt.ammo ) ); } return; } @@ -8961,11 +9005,6 @@ void game::reload_weapon( bool try_everything ) reload_item(); } -bool game::unload( item_location &loc ) -{ - return u.unload( loc ); -} - void game::wield( item_location loc ) { if( !loc ) { @@ -9016,7 +9055,7 @@ void game::wield( item_location loc ) item to_wield = *loc.get_item(); item_location::type location_type = loc.where(); tripoint pos = loc.position(); - const int obtain_cost = loc.obtain_cost( g->u ); + const int obtain_cost = loc.obtain_cost( u ); int worn_index = INT_MIN; if( u.is_worn( *loc.get_item() ) ) { auto ret = u.can_takeoff( *loc.get_item() ); @@ -9034,7 +9073,7 @@ void game::wield( item_location loc ) switch( location_type ) { case item_location::type::container: // this will not cause things to spill, as it is inside another item - loc = loc.obtain( g->u ); + loc = loc.obtain( u ); wield( loc ); break; case item_location::type::character: @@ -9218,8 +9257,7 @@ bool game::prompt_dangerous_tile( const tripoint &dest_loc ) const !query_yn( _( "Really step into %s?" ), enumerate_as_string( harmful_stuff ) ) ) { return false; } - if( !harmful_stuff.empty() && u.is_mounted() && - m.tr_at( dest_loc ).loadid == tr_ledge ) { + if( !harmful_stuff.empty() && u.is_mounted() && m.tr_at( dest_loc ) == tr_ledge ) { add_msg( m_warning, _( "Your %s refuses to move over that ledge!" ), u.mounted_creature->get_name() ); return false; @@ -9244,7 +9282,7 @@ std::vector game::get_dangerous_tile( const tripoint &dest_loc ) co true ) ); // HACK: Hack for now, later ledge should stop being a trap // Note: in non-z-level mode, ledges obey different rules and so should be handled as regular traps - if( tr.loadid == tr_ledge && m.has_zlevels() ) { + if( tr == tr_ledge && m.has_zlevels() ) { if( !boardable ) { harmful_stuff.emplace_back( tr.name() ); } @@ -9276,7 +9314,7 @@ std::vector game::get_dangerous_tile( const tripoint &dest_loc ) co return harmful_stuff; } -bool game::walk_move( const tripoint &dest_loc ) +bool game::walk_move( const tripoint &dest_loc, const bool via_ramp ) { if( m.has_flag_ter( TFLAG_SMALL_PASSAGE, dest_loc ) ) { if( u.get_size() > creature_size::medium ) { @@ -9419,7 +9457,8 @@ bool game::walk_move( const tripoint &dest_loc ) multiplier *= 3; } - const int mcost = m.combined_movecost( u.pos(), dest_loc, grabbed_vehicle, modifier ) * multiplier; + const int mcost = m.combined_movecost( u.pos(), dest_loc, grabbed_vehicle, modifier, + via_ramp ) * multiplier; if( grabbed_move( dest_loc - u.pos() ) ) { return true; } else if( mcost == 0 ) { @@ -9967,14 +10006,14 @@ void game::place_player_overmap( const tripoint &om_dest ) place_player( player_pos ); } -bool game::phasing_move( const tripoint &dest_loc ) +bool game::phasing_move( const tripoint &dest_loc, const bool via_ramp ) { if( !u.has_active_bionic( bionic_id( "bio_probability_travel" ) ) || u.get_power_level() < 250_kJ ) { return false; } - if( dest_loc.z != u.posz() ) { + if( dest_loc.z != u.posz() && !via_ramp ) { // No vertical phasing yet return false; } @@ -10067,6 +10106,10 @@ bool game::grabbed_furn_move( const tripoint &dp ) !m.veh_at( fdest ) && ( !has_floor || m.tr_at( fdest ).is_null() ) ); + // @TODO: it should be possible to move over invisible traps. This should probably + // trigger the trap. + // The current check (no move if trap) allows a player to detect invisible traps by + // attempting to move stuff onto it. const furn_t furntype = m.furn( fpos ).obj(); const int src_items = m.i_at( fpos ).size(); @@ -10389,7 +10432,7 @@ void game::fling_creature( Creature *c, const int &dir, float flvel, bool contro // Fall down to the ground - always on the last reached tile if( !m.has_flag( "SWIMMABLE", c->pos() ) ) { - const trap_id trap_under_creature = m.tr_at( c->pos() ).loadid; + const trap &trap_under_creature = m.tr_at( c->pos() ); // Didn't smash into a wall or a floor so only take the fall damage if( thru && trap_under_creature == tr_ledge ) { m.creature_on_trap( *c, false ); @@ -10430,7 +10473,7 @@ static cata::optional point_selection_menu( const std::vectoru.pos(); + const tripoint &upos = get_player_character().pos(); uilist pmenu; pmenu.title = _( "Climb where?" ); int num = 0; @@ -10681,7 +10724,7 @@ void game::vertical_move( int movez, bool force, bool peeking ) remove_zombie( critter ); } } - auto mons = critter_tracker->find( g->u.pos() ); + auto mons = critter_tracker->find( u.pos() ); if( mons != nullptr ) { critter_tracker->remove( *mons ); } @@ -10704,7 +10747,8 @@ void game::vertical_move( int movez, bool force, bool peeking ) if( ladder && !critter.climbs() ) { continue; } - if( critter.attack_target() == &g->u || ( !critter.has_effect( effect_ridden ) && + Creature *target = critter.attack_target(); + if( ( target && target->is_avatar() ) || ( !critter.has_effect( effect_ridden ) && critter.has_effect( effect_pet ) && critter.friendly == -1 && !critter.has_effect( effect_tied ) ) ) { monsters_following.push_back( &critter ); @@ -10725,7 +10769,7 @@ void game::vertical_move( int movez, bool force, bool peeking ) m.unboard_vehicle( np->pos() ); } } - const tripoint old_pos = g->u.pos(); + const tripoint old_pos = u.pos(); const tripoint old_abs_pos = m.getabs( old_pos ); point submap_shift; vertical_shift( z_after ); @@ -10735,12 +10779,12 @@ void game::vertical_move( int movez, bool force, bool peeking ) if( u.is_mounted() ) { if( stored_mount ) { assert( !m.has_zlevels() ); - stored_mount->spawn( g->u.pos() ); + stored_mount->spawn( u.pos() ); if( critter_tracker->add( stored_mount ) ) { u.mounted_creature = stored_mount; } } else { - u.mounted_creature->setpos( g->u.pos() ); + u.mounted_creature->setpos( u.pos() ); } } // if an NPC or monster is on the stiars when player ascends/descends @@ -10791,7 +10835,7 @@ void game::vertical_move( int movez, bool force, bool peeking ) } if( !npcs_to_bring.empty() ) { // Would look nicer randomly scrambled - std::vector candidates = closest_tripoints_first( u.pos(), 1 ); + std::vector candidates = closest_points_first( u.pos(), 1 ); candidates.erase( std::remove_if( candidates.begin(), candidates.end(), [this]( const tripoint & c ) { return !is_empty( c ); @@ -10800,6 +10844,8 @@ void game::vertical_move( int movez, bool force, bool peeking ) for( const auto &np : npcs_to_bring ) { const auto found = std::find_if( candidates.begin(), candidates.end(), [this, np]( const tripoint & c ) { + // @TODO NPC should appear on top of invisible traps (and trigger them), + // instead of magically choosing tiles without dangerous traps. return !np->is_dangerous_fields( m.field_at( c ) ) && m.tr_at( c ).is_benign(); } ); if( found != candidates.end() ) { @@ -10820,9 +10866,9 @@ void game::vertical_move( int movez, bool force, bool peeking ) // This ugly check is here because of stair teleport bullshit // TODO: Remove stair teleport bullshit - if( rl_dist( g->u.pos(), old_pos ) <= 1 ) { + if( rl_dist( u.pos(), old_pos ) <= 1 ) { for( monster *m : monsters_following ) { - m->set_dest( g->u.pos() ); + m->set_dest( u.pos() ); } } @@ -11115,7 +11161,7 @@ void game::vertical_notes( int z_before, int z_after ) } } -point game::update_map( player &p ) +point game::update_map( Character &p ) { point p2( p.posx(), p.posy() ); return update_map( p2.x, p2.y ); @@ -11518,20 +11564,31 @@ void game::perhaps_add_random_npc() return; } // Create a new NPC? - // Only allow NPCs on 0 z-level, otherwise they can bug out due to lack of spots - if( !get_option( "RANDOM_NPC" ) || ( !m.has_zlevels() && get_levz() != 0 ) ) { + + double spawn_time = get_option( "NPC_SPAWNTIME" ); + if( spawn_time == 0.0 ) { return; } - float density = get_option( "NPC_DENSITY" ); - static constexpr int density_search_radius = 60; - const float npc_num = overmap_buffer.get_npcs_near_player( density_search_radius ).size(); - if( npc_num > 0.0 ) { + // spawn algorithm is a chance per hour, but the config is specified in average days + // actual chance per hour is (100 / 24 ) / days + static constexpr double days_to_rate_factor = 100.0 / 24; + double spawn_rate = days_to_rate_factor / spawn_time; + static constexpr int radius_spawn_range = 90; + std::vector> npcs = overmap_buffer.get_npcs_near_player( radius_spawn_range ); + size_t npc_num = npcs.size(); + for( auto &npc : npcs ) { + if( npc->has_trait( trait_NPC_STATIC_NPC ) || npc->has_trait( trait_NPC_STARTING_NPC ) ) { + npc_num--; + } + } + + if( npc_num > 0 ) { // 100%, 80%, 64%, 52%, 41%, 33%... - density *= std::pow( 0.8f, npc_num ); + spawn_rate *= std::pow( 0.8f, npc_num ); } - if( !x_in_y( density, 100 ) ) { + if( !x_in_y( spawn_rate, 100 ) ) { return; } bool spawn_allowed = false; @@ -11541,7 +11598,6 @@ void game::perhaps_add_random_npc() if( counter >= 10 ) { return; } - static constexpr int radius_spawn_range = 120; const tripoint u_omt = u.global_omt_location(); spawn_point = u_omt + point( rng( -radius_spawn_range, radius_spawn_range ), rng( -radius_spawn_range, radius_spawn_range ) ); @@ -11563,6 +11619,7 @@ void game::perhaps_add_random_npc() faction_id( "no_faction" ) ); tmp->set_fac( new_solo_fac ? new_solo_fac->id : faction_id( "no_faction" ) ); // adds the npc to the correct overmap. + // Only spawn random NPCs on z-level 0 tripoint submap_spawn = omt_to_sm_copy( spawn_point ); tmp->spawn_at_sm( tripoint( submap_spawn.xy(), 0 ) ); overmap_buffer.insert_npc( tmp ); @@ -11643,7 +11700,7 @@ void game::display_visibility() uilist creature_menu; int num_creatures = 0; creature_menu.addentry( num_creatures++, true, MENU_AUTOASSIGN, "%s", _( "You" ) ); - locations.emplace_back( g->u.pos() ); // add player first. + locations.emplace_back( get_player_character().pos() ); // add player first. for( const Creature &critter : g->all_creatures() ) { if( critter.is_player() ) { continue; @@ -11824,7 +11881,7 @@ void game::process_artifact( item &it, player &p ) case ARTC_PORTAL: for( const tripoint &dest : m.points_in_radius( p.pos(), 1 ) ) { m.remove_field( dest, fd_fatigue ); - if( m.tr_at( dest ).loadid == tr_portal ) { + if( m.tr_at( dest ) == tr_portal ) { add_msg( m_good, _( "The portal collapses!" ) ); m.remove_trap( dest ); it.charges++; @@ -11966,7 +12023,7 @@ void game::process_artifact( item &it, player &p ) //Check if an artifact's extra charge requirements are currently met bool check_art_charge_req( item &it ) { - player &p = g->u; + avatar &p = get_avatar(); bool reqsmet = true; const bool worn = p.is_worn( it ); const bool wielded = ( &it == &p.weapon ); @@ -11991,7 +12048,7 @@ bool check_art_charge_req( item &it ) bp == bodypart_id( "hand_l" ) ) ) ) { reqsmet = true; for( const item &i : p.worn ) { - if( i.covers( bp ) && ( &it != &i ) && i.get_coverage() > 50 ) { + if( i.covers( bp ) && ( &it != &i ) && i.get_coverage( bp ) > 50 ) { reqsmet = false; break; //This one's no good, check the next body part } @@ -12264,7 +12321,7 @@ void game::add_artifact_dreams( ) { //If player is sleeping, get a dream from a carried artifact //Don't need to check that player is sleeping here, that's done before calling - std::list art_items = g->u.get_artifact_items(); + std::list art_items = get_avatar().get_artifact_items(); std::vector valid_arts; std::vector> valid_dreams; // Tracking separately so we only need to check its req once @@ -12332,7 +12389,7 @@ std::vector game::allies() { return get_npcs_if( [&]( const npc & guy ) { if( !guy.is_hallucination() ) { - return guy.is_ally( g->u ); + return guy.is_ally( get_player_character() ); } else { return false; } @@ -12392,7 +12449,7 @@ bool game::non_dead_range::iterator::valid() if( critter->is_npc() ) { return !static_cast( critter )->is_dead(); } - return true; // must be g->u + return true; // must be the avatar } game::monster_range::monster_range( game &game_ref ) diff --git a/src/game.h b/src/game.h index 509b4218ef7dc..0d0638a09330d 100644 --- a/src/game.h +++ b/src/game.h @@ -88,7 +88,6 @@ enum safe_mode_type { }; enum body_part : int; -enum weather_type : int; enum action_id : int; struct special_game; @@ -106,6 +105,7 @@ class player; class save_t; class scenario; class stats_tracker; +template class tripoint_range; class vehicle; struct WORLD; @@ -149,6 +149,10 @@ class game friend class editmap; friend class advanced_inventory; friend class main_menu; + friend map &get_map(); + friend Character &get_player_character(); + friend avatar &get_avatar(); + friend weather_manager &get_weather(); public: game(); ~game(); @@ -335,9 +339,9 @@ class game monster *place_critter_around( const mtype_id &id, const tripoint ¢er, int radius ); monster *place_critter_around( const shared_ptr_fast &mon, const tripoint ¢er, int radius ); - monster *place_critter_within( const mtype_id &id, const tripoint_range &range ); + monster *place_critter_within( const mtype_id &id, const tripoint_range &range ); monster *place_critter_within( const shared_ptr_fast &mon, - const tripoint_range &range ); + const tripoint_range &range ); /** @} */ /** * Returns the approximate number of creatures in the reality bubble. @@ -352,6 +356,11 @@ class game void clear_zombies(); /** Spawns a hallucination at a determined position. */ bool spawn_hallucination( const tripoint &p ); + /** Spawns a hallucination at a determined position of a given monster. */ + bool spawn_hallucination( const tripoint &p, const mtype_id &mt ); + /** Finds somewhere to spawn a monster. */ + bool find_nearby_spawn_point( const Character &target, const mtype_id &mt, int min_radius, + int max_radius, tripoint &point ); /** Swaps positions of two creatures */ bool swap_critters( Creature &, Creature & ); @@ -554,7 +563,7 @@ class game Creature *is_hostile_very_close(); // Handles shifting coordinates transparently when moving between submaps. // Helper to make calling with a player pointer less verbose. - point update_map( player &p ); + point update_map( Character &p ); point update_map( int &x, int &y ); void update_overmap_seen(); // Update which overmap tiles we can see @@ -741,9 +750,9 @@ class game bool npc_menu( npc &who ); // Handle phasing through walls, returns true if it handled the move - bool phasing_move( const tripoint &dest ); + bool phasing_move( const tripoint &dest, bool via_ramp = false ); // Regular movement. Returns false if it failed for any reason - bool walk_move( const tripoint &dest ); + bool walk_move( const tripoint &dest, bool via_ramp = false ); void on_move_effects(); private: // Game-start procedures @@ -816,8 +825,6 @@ class game point place_player( const tripoint &dest ); void place_player_overmap( const tripoint &om_dest ); - bool unload( item_location &loc ); // Unload a gun/tool 'U' - unsigned int get_seed() const; /** If invoked, NPCs will be reloaded before next turn. */ @@ -964,9 +971,8 @@ class game pimpl memorial_logger_ptr; pimpl spell_events_ptr; - public: - /** Make map a reference here, to avoid map.h in game.h */ map &m; + public: avatar &u; scent_map &scent; timed_event_manager &timed_events; diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index b0ace9e77847a..008d66446436d 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -120,7 +120,7 @@ static item_location_filter convert_filter( const item_filter &filter ) }; } -static item_location inv_internal( player &u, const inventory_selector_preset &preset, +static item_location inv_internal( Character &u, const inventory_selector_preset &preset, const std::string &title, int radius, const std::string &none_message, const std::string &hint = std::string() ) @@ -292,12 +292,12 @@ class armor_inventory_preset: public inventory_selector_preset armor_inventory_preset( player &pl, const std::string &color_in ) : p( pl ), color( color_in ) { append_cell( [ this ]( const item_location & loc ) { - return get_number_string( loc->get_encumber( p ) ); - }, _( "ENCUMBRANCE" ) ); + return get_number_string( loc->get_avg_encumber( p ) ); + }, _( "AVG ENCUMBRANCE" ) ); append_cell( [ this ]( const item_location & loc ) { - return string_format( "<%s>%d%%", color, loc->get_coverage() ); - }, _( "COVERAGE" ) ); + return string_format( "<%s>%d%%", color, loc->get_avg_coverage() ); + }, _( "AVG COVERAGE" ) ); append_cell( [ this ]( const item_location & loc ) { return get_number_string( loc->get_warmth() ); @@ -426,7 +426,7 @@ item_location game_menus::inv::container_for( avatar &you, const item &liquid, i class pickup_inventory_preset : public inventory_selector_preset { public: - pickup_inventory_preset( const player &p ) : p( p ) {} + pickup_inventory_preset( const Character &p ) : p( p ) {} std::string get_denial( const item_location &loc ) const override { if( !p.has_item( *loc ) ) { @@ -443,13 +443,13 @@ class pickup_inventory_preset : public inventory_selector_preset } private: - const player &p; + const Character &p; }; class disassemble_inventory_preset : public pickup_inventory_preset { public: - disassemble_inventory_preset( const player &p, const inventory &inv ) : + disassemble_inventory_preset( const Character &p, const inventory &inv ) : pickup_inventory_preset( p ), p( p ), inv( inv ) { check_components = true; @@ -468,7 +468,7 @@ class disassemble_inventory_preset : public pickup_inventory_preset }, _( "YIELD" ) ); append_cell( [ this ]( const item_location & loc ) { - return to_string_clipped( time_duration::from_turns( get_recipe( loc ).time / 100 ) ); + return to_string_clipped( get_recipe( loc ).time_to_craft( get_player_character() ) ); }, _( "TIME" ) ); } @@ -490,11 +490,11 @@ class disassemble_inventory_preset : public pickup_inventory_preset } private: - const player &p; + const Character &p; const inventory &inv; }; -item_location game_menus::inv::disassemble( player &p ) +item_location game_menus::inv::disassemble( Character &p ) { return inv_internal( p, disassemble_inventory_preset( p, p.crafting_inventory() ), _( "Disassemble item" ), 1, @@ -1306,7 +1306,7 @@ void game_menus::inv::insert_items( avatar &you, item_location &holster ) item item_copy( it ); item_copy.charges = holstered_item.second; if( holster->can_contain( item_copy ) ) { - holster->put_in( it, item_pocket::pocket_type::CONTAINER ); + holster->put_in( item_copy, item_pocket::pocket_type::CONTAINER ); it.charges -= holstered_item.second; success = true; } diff --git a/src/game_inventory.h b/src/game_inventory.h index ce5d6ae2b4b1d..3353a73a8b5d2 100644 --- a/src/game_inventory.h +++ b/src/game_inventory.h @@ -86,7 +86,7 @@ item_location consume_meds( player &p ); /** Choosing a container for liquid. */ item_location container_for( avatar &you, const item &liquid, int radius = 0 ); /** Item disassembling menu. */ -item_location disassemble( player &p ); +item_location disassemble( Character &p ); /** Gunmod installation menu. */ item_location gun_to_modify( player &p, const item &gunmod ); /** Book reading menu. */ diff --git a/src/gamemode_defense.cpp b/src/gamemode_defense.cpp index e7e35b6207640..94dbc7c2b9078 100644 --- a/src/gamemode_defense.cpp +++ b/src/gamemode_defense.cpp @@ -62,7 +62,7 @@ std::string caravan_category_name( caravan_category cat ); std::vector caravan_items( caravan_category cat ); std::set monflags_to_add; -int caravan_price( player &u, int price ); +int caravan_price( Character &u, int price ); void draw_caravan_borders( const catacurses::window &w, int current_window ); void draw_caravan_categories( const catacurses::window &w, int category_selected, @@ -96,13 +96,14 @@ bool defense_game::init() { calendar::turn = calendar::turn_zero + 12_hours; // Start at noon g->weather.temperature = 65; - if( !g->u.create( character_type::CUSTOM ) ) { + avatar &player_character = get_avatar(); + if( !player_character.create( character_type::CUSTOM ) ) { return false; } - g->u.str_cur = g->u.str_max; - g->u.per_cur = g->u.per_max; - g->u.int_cur = g->u.int_max; - g->u.dex_cur = g->u.dex_max; + player_character.str_cur = player_character.str_max; + player_character.per_cur = player_character.per_max; + player_character.int_cur = player_character.int_max; + player_character.dex_cur = player_character.dex_max; init_mtypes(); init_constructions(); current_wave = 0; @@ -119,7 +120,7 @@ bool defense_game::init() allow_save = false; init_to_style( DEFENSE_EASY ); setup(); - g->u.cash = initial_cash; + player_character.cash = initial_cash; // TODO: support multiple defense games? clean up old defense game defloc_pos = tripoint( 50, 50, 0 ); init_map(); @@ -129,14 +130,15 @@ bool defense_game::init() void defense_game::per_turn() { + Character &player_character = get_player_character(); if( !thirst ) { - g->u.set_thirst( 0 ); + player_character.set_thirst( 0 ); } if( !hunger ) { - g->u.set_hunger( 0 ); + player_character.set_hunger( 0 ); } if( !sleep ) { - g->u.set_fatigue( 0 ); + player_character.set_fatigue( 0 ); } if( calendar::once_every( time_between_waves ) ) { current_wave++; @@ -171,11 +173,13 @@ void defense_game::pre_action( action_id &act ) case ACTION_MOVE_BACK_LEFT: case ACTION_MOVE_LEFT: case ACTION_MOVE_FORTH_LEFT: { + Character &player_character = get_player_character(); const point delta = get_delta_from_movement_action( act, iso_rotate::yes ); - if( ( delta.y < 0 && g->u.posy() == HALF_MAPSIZE_Y && g->get_levy() <= 93 ) - || ( delta.y > 0 && g->u.posy() == HALF_MAPSIZE_Y + SEEY - 1 && g->get_levy() >= 98 ) - || ( delta.x < 0 && g->u.posx() == HALF_MAPSIZE_X && g->get_levx() <= 93 ) - || ( delta.x > 0 && g->u.posx() == HALF_MAPSIZE_X + SEEX - 1 && g->get_levx() >= 98 ) ) { + if( ( delta.y < 0 && player_character.posy() == HALF_MAPSIZE_Y && g->get_levy() <= 93 ) + || ( delta.y > 0 && player_character.posy() == HALF_MAPSIZE_Y + SEEY - 1 && g->get_levy() >= 98 ) + || ( delta.x < 0 && player_character.posx() == HALF_MAPSIZE_X && g->get_levx() <= 93 ) + || ( delta.x > 0 && player_character.posx() == HALF_MAPSIZE_X + SEEX - 1 && + g->get_levx() >= 98 ) ) { action_error_message = string_format( _( "You cannot leave the %s behind!" ), defense_location_name( location ) ); } @@ -291,11 +295,13 @@ void defense_game::init_map() } g->load_map( omt_to_sm_copy( defloc_pos ) ); - g->u.setx( SEEX ); - g->u.sety( SEEY ); + Character &player_character = get_player_character(); + player_character.setx( SEEX ); + player_character.sety( SEEY ); - g->update_map( g-> u ); - monster *const generator = g->place_critter_around( mtype_id( "mon_generator" ), g->u.pos(), 2 ); + g->update_map( player_character ); + monster *const generator = g->place_critter_around( mtype_id( "mon_generator" ), + player_character.pos(), 2 ); assert( generator ); generator->friendly = -1; } @@ -890,8 +896,9 @@ void defense_game::caravan() int current_window = 0; + Character &player_character = get_player_character(); ui.on_redraw( [&]( const ui_adaptor & ) { - draw_caravan_categories( w, category_selected, total_price, g->u.cash ); + draw_caravan_categories( w, category_selected, total_price, player_character.cash ); draw_caravan_items( w, &( items[category_selected] ), &( item_count[category_selected] ), offset, item_selected ); draw_caravan_borders( w, current_window ); @@ -969,7 +976,7 @@ void defense_game::caravan() if( current_window == 1 && !items[category_selected].empty() ) { item_count[category_selected][item_selected]++; itype_id tmp_itm = items[category_selected][item_selected]; - total_price += caravan_price( g->u, item( tmp_itm, 0 ).price( false ) ); + total_price += caravan_price( player_character, item( tmp_itm, 0 ).price( false ) ); if( category_selected == CARAVAN_CART ) { // Find the item in its category for( int i = 1; i < NUM_CARAVAN_CATEGORIES; i++ ) { for( size_t j = 0; j < items[i].size(); j++ ) { @@ -997,7 +1004,7 @@ void defense_game::caravan() item_count[category_selected][item_selected] > 0 ) { item_count[category_selected][item_selected]--; itype_id tmp_itm = items[category_selected][item_selected]; - total_price -= caravan_price( g->u, item( tmp_itm, 0 ).price( false ) ); + total_price -= caravan_price( player_character, item( tmp_itm, 0 ).price( false ) ); if( category_selected == CARAVAN_CART ) { // Find the item in its category for( int i = 1; i < NUM_CARAVAN_CATEGORIES; i++ ) { for( size_t j = 0; j < items[i].size(); j++ ) { @@ -1028,7 +1035,7 @@ void defense_game::caravan() done = true; } } else if( action == "CONFIRM" ) { - if( total_price > g->u.cash ) { + if( total_price > player_character.cash ) { popup( _( "You can't afford those items!" ) ); } else if( ( items[0].empty() && query_yn( _( "Really buy nothing?" ) ) ) || ( !items[0].empty() && @@ -1036,7 +1043,7 @@ void defense_game::caravan() "Buy %d items, leaving you with %s?", items[0].size() ), items[0].size(), - format_money( static_cast( g->u.cash ) - static_cast( total_price ) ) ) ) ) { + format_money( static_cast( player_character.cash ) - static_cast( total_price ) ) ) ) ) { done = true; } } // "switch" on (action) @@ -1044,7 +1051,7 @@ void defense_game::caravan() } // while (!done) if( !cancel ) { - g->u.cash -= total_price; + player_character.cash -= total_price; bool dropped_some = false; for( size_t i = 0; i < items[0].size(); i++ ) { item tmp( items[0][i] ); @@ -1057,11 +1064,11 @@ void defense_game::caravan() } for( int j = 0; j < item_count[0][i]; j++ ) { - if( g->u.can_pickVolume( tmp ) && g->u.can_pickWeight( tmp ) ) { - g->u.i_add( tmp ); + if( player_character.can_pickVolume( tmp ) && player_character.can_pickWeight( tmp ) ) { + player_character.i_add( tmp ); } else { // Could fit it in the inventory! dropped_some = true; - get_map().add_item_or_charges( g->u.pos(), tmp ); + get_map().add_item_or_charges( player_character.pos(), tmp ); } } } @@ -1242,6 +1249,7 @@ void draw_caravan_items( const catacurses::window &w, std::vector *ite for( int i = 1; i <= FULL_SCREEN_HEIGHT - 2; i++ ) { mvwprintz( w, point( 40, i ), c_black, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); } + Character &player_character = get_player_character(); // Finally, print the item list on the right for( int i = offset; i <= offset + FULL_SCREEN_HEIGHT - 2 && i < static_cast( items->size() ); i++ ) { @@ -1249,15 +1257,15 @@ void draw_caravan_items( const catacurses::window &w, std::vector *ite item::nname( ( *items )[i], ( *counts )[i] ) ); wprintz( w, c_white, " x %2d", ( *counts )[i] ); if( ( *counts )[i] > 0 ) { - int price = caravan_price( g->u, item( ( *items )[i], - 0 ).price( false ) * ( *counts )[i] ); - wprintz( w, ( price > g->u.cash ? c_red : c_green ), " (%s)", format_money( price ) ); + int price = caravan_price( player_character, item( ( *items )[i], + 0 ).price( false ) * ( *counts )[i] ); + wprintz( w, ( price > player_character.cash ? c_red : c_green ), " (%s)", format_money( price ) ); } } wnoutrefresh( w ); } -int caravan_price( player &u, int price ) +int caravan_price( Character &u, int price ) { ///\EFFECT_BARTER reduces caravan prices, 5% per point, up to 50% if( u.get_skill_level( skill_barter ) > 10 ) { @@ -1268,10 +1276,11 @@ int caravan_price( player &u, int price ) void defense_game::spawn_wave() { + Character &player_character = get_player_character(); add_msg( m_info, "********" ); int diff = initial_difficulty + current_wave * wave_difficulty; bool themed_wave = one_in( SPECIAL_WAVE_CHANCE ); // All a single monster type - g->u.cash += cash_per_wave + ( current_wave - 1 ) * cash_increase; + player_character.cash += cash_per_wave + ( current_wave - 1 ) * cash_increase; std::vector valid = pick_monster_wave(); while( diff > 0 ) { // Clear out any monsters that exceed our remaining difficulty @@ -1346,6 +1355,7 @@ std::vector defense_game::pick_monster_wave() void defense_game::spawn_wave_monster( const mtype_id &type ) { + tripoint player_pos = get_player_character().pos(); for( int tries = 0; tries < 1000; tries++ ) { point pnt; if( location == DEFLOC_HOSPITAL || location == DEFLOC_MALL ) { @@ -1367,7 +1377,7 @@ void defense_game::spawn_wave_monster( const mtype_id &type ) continue; } monster &tmp = *mon; - tmp.wander_pos = g->u.pos(); + tmp.wander_pos = player_pos; tmp.wandf = 150; // We want to kill! tmp.anger = 100; diff --git a/src/gamemode_tutorial.cpp b/src/gamemode_tutorial.cpp index 20ee208fdd855..d8942a8db5f2d 100644 --- a/src/gamemode_tutorial.cpp +++ b/src/gamemode_tutorial.cpp @@ -115,18 +115,19 @@ bool tutorial_game::init() g->weather.temperature = 65; // We use a Z-factor of 10 so that we don't plop down tutorial rooms in the // middle of the "real" game world - g->u.normalize(); - g->u.str_cur = g->u.str_max; - g->u.per_cur = g->u.per_max; - g->u.int_cur = g->u.int_max; - g->u.dex_cur = g->u.dex_max; + avatar &player_character = get_avatar(); + player_character.normalize(); + player_character.str_cur = player_character.str_max; + player_character.per_cur = player_character.per_max; + player_character.int_cur = player_character.int_max; + player_character.dex_cur = player_character.dex_max; - g->u.set_all_parts_hp_to_max(); + player_character.set_all_parts_hp_to_max(); const oter_id rock( "rock" ); //~ default name for the tutorial - g->u.name = _( "John Smith" ); - g->u.prof = profession::generic(); + player_character.name = _( "John Smith" ); + player_character.prof = profession::generic(); // overmap terrain coordinates const tripoint lp( 50, 50, 0 ); auto &starting_om = overmap_buffer.get( point_zero ); @@ -142,18 +143,18 @@ bool tutorial_game::init() starting_om.ter_set( lp + tripoint_below, oter_id( "tutorial" ) ); starting_om.clear_mon_groups(); - g->u.toggle_trait( trait_QUICK ); + player_character.toggle_trait( trait_QUICK ); item lighter( "lighter", 0 ); lighter.invlet = 'e'; - g->u.inv.add_item( lighter, true, false ); - g->u.set_skill_level( skill_gun, 5 ); - g->u.set_skill_level( skill_melee, 5 ); + player_character.inv.add_item( lighter, true, false ); + player_character.set_skill_level( skill_gun, 5 ); + player_character.set_skill_level( skill_melee, 5 ); g->load_map( omt_to_sm_copy( lp ) ); - g->u.setx( 2 ); - g->u.sety( 4 ); + player_character.setx( 2 ); + player_character.sety( 4 ); // This shifts the view to center the players pos - g->update_map( g->u ); + g->update_map( player_character ); return true; } @@ -164,25 +165,26 @@ void tutorial_game::per_turn() add_message( tut_lesson::LESSON_MOVE ); add_message( tut_lesson::LESSON_LOOK ); - if( g->light_level( g->u.posz() ) == 1 ) { - if( g->u.has_amount( itype_flashlight, 1 ) ) { + Character &player_character = get_player_character(); + if( g->light_level( player_character.posz() ) == 1 ) { + if( player_character.has_amount( itype_flashlight, 1 ) ) { add_message( tut_lesson::LESSON_DARK ); } else { add_message( tut_lesson::LESSON_DARK_NO_FLASH ); } } - if( g->u.get_pain() > 0 ) { + if( player_character.get_pain() > 0 ) { add_message( tut_lesson::LESSON_PAIN ); } - if( g->u.recoil >= MAX_RECOIL ) { + if( player_character.recoil >= MAX_RECOIL ) { add_message( tut_lesson::LESSON_RECOIL ); } map &here = get_map(); if( !tutorials_seen[tut_lesson::LESSON_BUTCHER] ) { - for( const item &it : here.i_at( point( g->u.posx(), g->u.posy() ) ) ) { + for( const item &it : here.i_at( player_character.pos().xy() ) ) { if( it.is_corpse() ) { add_message( tut_lesson::LESSON_BUTCHER ); break; @@ -190,7 +192,7 @@ void tutorial_game::per_turn() } } - for( const tripoint &p : here.points_in_radius( g->u.pos(), 1 ) ) { + for( const tripoint &p : here.points_in_radius( player_character.pos(), 1 ) ) { if( here.ter( p ) == t_door_o ) { add_message( tut_lesson::LESSON_OPEN ); break; @@ -212,7 +214,7 @@ void tutorial_game::per_turn() } } - if( !here.i_at( point( g->u.posx(), g->u.posy() ) ).empty() ) { + if( !here.i_at( point( player_character.posx(), player_character.posy() ) ).empty() ) { add_message( tut_lesson::LESSON_PICKUP ); } } @@ -233,12 +235,13 @@ void tutorial_game::pre_action( action_id &act ) void tutorial_game::post_action( action_id act ) { + Character &player_character = get_player_character(); switch( act ) { case ACTION_RELOAD_WEAPON: - if( g->u.weapon.is_gun() && !tutorials_seen[tut_lesson::LESSON_GUN_FIRE] ) { - g->place_critter_at( mon_zombie, tripoint( g->u.posx(), g->u.posy() - 6, g->u.posz() ) ); - g->place_critter_at( mon_zombie, tripoint( g->u.posx() + 2, g->u.posy() - 5, g->u.posz() ) ); - g->place_critter_at( mon_zombie, tripoint( g->u.posx() - 2, g->u.posy() - 5, g->u.posz() ) ); + if( player_character.weapon.is_gun() && !tutorials_seen[tut_lesson::LESSON_GUN_FIRE] ) { + g->place_critter_at( mon_zombie, player_character.pos() + tripoint( 0, -6, 0 ) ); + g->place_critter_at( mon_zombie, player_character.pos() + tripoint( 2, -5, 0 ) ); + g->place_critter_at( mon_zombie, player_character.pos() + tripoint( -2, -5, 0 ) ); add_message( tut_lesson::LESSON_GUN_FIRE ); } break; @@ -252,11 +255,11 @@ void tutorial_game::post_action( action_id act ) break; case ACTION_USE: { - if( g->u.has_amount( itype_grenade_act, 1 ) ) { + if( player_character.has_amount( itype_grenade_act, 1 ) ) { add_message( tut_lesson::LESSON_ACT_GRENADE ); } map &here = get_map(); - for( const tripoint &dest : here.points_in_radius( g->u.pos(), 1 ) ) { + for( const tripoint &dest : here.points_in_radius( player_character.pos(), 1 ) ) { if( here.tr_at( dest ).id == trap_str_id( "tr_bubblewrap" ) ) { add_message( tut_lesson::LESSON_ACT_BUBBLEWRAP ); } @@ -265,19 +268,19 @@ void tutorial_game::post_action( action_id act ) break; case ACTION_EAT: - if( g->u.last_item == itype_codeine ) { + if( player_character.last_item == itype_codeine ) { add_message( tut_lesson::LESSON_TOOK_PAINKILLER ); - } else if( g->u.last_item == itype_cig ) { + } else if( player_character.last_item == itype_cig ) { add_message( tut_lesson::LESSON_TOOK_CIG ); - } else if( g->u.last_item == itype_water ) { + } else if( player_character.last_item == itype_water ) { add_message( tut_lesson::LESSON_DRANK_WATER ); } break; case ACTION_WEAR: { - item it( g->u.last_item, 0 ); + item it( player_character.last_item, 0 ); if( it.is_armor() ) { - if( it.get_coverage() >= 2 || it.get_thickness() >= 2 ) { + if( it.get_avg_coverage() >= 2 || it.get_thickness() >= 2 ) { add_message( tut_lesson::LESSON_WORE_ARMOR ); } if( it.get_env_resist() >= 2 ) { @@ -288,7 +291,7 @@ void tutorial_game::post_action( action_id act ) break; case ACTION_WIELD: - if( g->u.weapon.is_gun() ) { + if( player_character.weapon.is_gun() ) { add_message( tut_lesson::LESSON_GUN_LOAD ); } break; @@ -297,7 +300,7 @@ void tutorial_game::post_action( action_id act ) add_message( tut_lesson::LESSON_INTERACT ); /* fallthrough */ case ACTION_PICKUP: { - item it( g->u.last_item, 0 ); + item it( player_character.last_item, 0 ); if( it.is_armor() ) { add_message( tut_lesson::LESSON_GOT_ARMOR ); } else if( it.is_gun() ) { diff --git a/src/gates.cpp b/src/gates.cpp index 71a0e178799a9..091f654fbf926 100644 --- a/src/gates.cpp +++ b/src/gates.cpp @@ -218,7 +218,7 @@ void gates::open_gate( const tripoint &pos ) } } - if( g->u.sees( pos ) ) { + if( get_player_character().sees( pos ) ) { if( open ) { add_msg( gate.open_message ); } else if( close ) { @@ -277,7 +277,7 @@ void doors::close_door( map &m, Character &who, const tripoint &closep ) const int inside_closable = veh->next_part_to_close( vpart ); const int openable = veh->next_part_to_open( vpart ); if( closable >= 0 ) { - if( !veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( !veh->handle_potential_theft( get_avatar() ) ) { return; } veh->close( closable ); diff --git a/src/grab.cpp b/src/grab.cpp index ffa5a942f3d76..a4526ad0c4564 100644 --- a/src/grab.cpp +++ b/src/grab.cpp @@ -27,7 +27,7 @@ bool game::grabbed_veh_move( const tripoint &dp ) } vehicle *grabbed_vehicle = &grabbed_vehicle_vp->vehicle(); if( !grabbed_vehicle || - !grabbed_vehicle->handle_potential_theft( dynamic_cast( g->u ) ) ) { + !grabbed_vehicle->handle_potential_theft( get_avatar() ) ) { return false; } const int grabbed_part = grabbed_vehicle_vp->part_index(); @@ -185,7 +185,10 @@ bool game::grabbed_veh_move( const tripoint &dp ) m.displace_vehicle( *grabbed_vehicle, final_dp_veh ); - if( !grabbed_vehicle ) { + if( grabbed_vehicle ) { + m.level_vehicle( *grabbed_vehicle ); + grabbed_vehicle->check_falling_or_floating(); + } else { debugmsg( "Grabbed vehicle disappeared" ); return false; } diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 14bf87009ea8d..9996e79e2b363 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -110,10 +110,11 @@ static const bionic_id bio_remote( "bio_remote" ); static const trait_id trait_HIBERNATE( "HIBERNATE" ); static const trait_id trait_PROF_CHURL( "PROF_CHURL" ); -static const trait_id trait_PROF_HELI_PILOT( "PROF_HELI_PILOT" ); static const trait_id trait_SHELL2( "SHELL2" ); static const trait_id trait_WAYFARER( "WAYFARER" ); +static const proficiency_id proficiency_prof_helicopter_pilot( "prof_helicopter_pilot" ); + static const std::string flag_LITCIG( "LITCIG" ); static const std::string flag_LOCKED( "LOCKED" ); static const std::string flag_MAGIC_FOCUS( "MAGIC_FOCUS" ); @@ -221,7 +222,7 @@ input_context game::get_player_input( std::string &action ) } //x% of the Viewport, only shown on visible areas - const auto weather_info = get_weather_animation( weather.weather ); + const auto weather_info = weather.weather_id->weather_animation; point offset( u.view_offset.xy() + point( -getmaxx( w_terrain ) / 2 + u.posx(), -getmaxy( w_terrain ) / 2 + u.posy() ) ); @@ -243,7 +244,7 @@ input_context game::get_player_input( std::string &action ) weather_printable wPrint; wPrint.colGlyph = weather_info.color; wPrint.cGlyph = weather_info.glyph; - wPrint.wtype = weather.weather; + wPrint.wtype = weather.weather_id; wPrint.vdrops.clear(); ctxt.set_timeout( 125 ); @@ -346,13 +347,13 @@ input_context game::get_player_input( std::string &action ) inline static void rcdrive( const point &d ) { - player &u = g->u; + Character &player_character = get_player_character(); map &here = get_map(); - std::stringstream car_location_string( u.get_value( "remote_controlling" ) ); + std::stringstream car_location_string( player_character.get_value( "remote_controlling" ) ); if( car_location_string.str().empty() ) { //no turned radio car found - u.add_msg_if_player( m_warning, _( "No radio car connected." ) ); + add_msg( m_warning, _( "No radio car connected." ) ); return; } tripoint c; @@ -366,8 +367,8 @@ inline static void rcdrive( const point &d ) } } if( rc_pair == rc_pairs.end() ) { - u.add_msg_if_player( m_warning, _( "No radio car connected." ) ); - u.remove_value( "remote_controlling" ); + add_msg( m_warning, _( "No radio car connected." ) ); + player_character.remove_value( "remote_controlling" ); return; } item *rc_car = rc_pair->second; @@ -382,11 +383,11 @@ inline static void rcdrive( const point &d ) tripoint src( c ); //~ Sound of moving a remote controlled car sounds::sound( src, 6, sounds::sound_t::movement, _( "zzz…" ), true, "misc", "rc_car_drives" ); - u.moves -= 50; + player_character.moves -= 50; here.i_rem( src, rc_car ); car_location_string.clear(); car_location_string << dest.x << ' ' << dest.y << ' ' << dest.z; - u.set_value( "remote_controlling", car_location_string.str() ); + player_character.set_value( "remote_controlling", car_location_string.str() ); return; } } @@ -396,13 +397,13 @@ static void pldrive( const tripoint &p ) if( !g->check_safe_mode_allowed() ) { return; } - player &u = g->u; vehicle *veh = g->remoteveh(); bool remote = true; int part = -1; + Character &player_character = get_player_character(); map &here = get_map(); if( !veh ) { - if( const optional_vpart_position vp = here.veh_at( u.pos() ) ) { + if( const optional_vpart_position vp = here.veh_at( player_character.pos() ) ) { veh = &vp->vehicle(); part = vp->part_index(); } @@ -411,7 +412,7 @@ static void pldrive( const tripoint &p ) if( !veh ) { dbg( D_ERROR ) << "game::pldrive: can't find vehicle! Drive mode is now off."; debugmsg( "game::pldrive error: can't find vehicle! Drive mode is now off." ); - u.in_vehicle = false; + player_character.in_vehicle = false; return; } if( !remote ) { @@ -422,11 +423,11 @@ static void pldrive( const tripoint &p ) veh->has_harnessed_animal(); if( !has_controls && !has_animal_controls ) { add_msg( m_info, _( "You can't drive the vehicle from here. You need controls!" ) ); - u.controlling_vehicle = false; + player_character.controlling_vehicle = false; return; } else if( !has_controls && has_animal_controls && !has_animal ) { add_msg( m_info, _( "You can't drive this vehicle without an animal to pull it." ) ); - u.controlling_vehicle = false; + player_character.controlling_vehicle = false; return; } } else { @@ -436,28 +437,28 @@ static void pldrive( const tripoint &p ) } } if( p.z != 0 ) { - if( !u.has_trait( trait_PROF_HELI_PILOT ) ) { - u.add_msg_if_player( m_info, _( "You have no idea how to make the vehicle fly." ) ); + if( !player_character.has_proficiency( proficiency_prof_helicopter_pilot ) ) { + player_character.add_msg_if_player( m_info, _( "You have no idea how to make the vehicle fly." ) ); return; } if( !veh->is_flyable() ) { - u.add_msg_if_player( m_info, _( "This vehicle doesn't look very airworthy." ) ); + player_character.add_msg_if_player( m_info, _( "This vehicle doesn't look very airworthy." ) ); return; } if( !here.has_zlevels() ) { - u.add_msg_if_player( m_info, _( "This vehicle cannot be flown without z levels." ) ); + player_character.add_msg_if_player( m_info, _( "This vehicle cannot be flown without z levels." ) ); return; } } if( p.z == -1 ) { - if( veh->check_heli_descend( u ) ) { - u.add_msg_if_player( m_info, _( "You steer the vehicle into a descent." ) ); + if( veh->check_heli_descend( player_character ) ) { + player_character.add_msg_if_player( m_info, _( "You steer the vehicle into a descent." ) ); } else { return; } } else if( p.z == 1 ) { - if( veh->check_heli_ascend( u ) ) { - u.add_msg_if_player( m_info, _( "You steer the vehicle into an ascent." ) ); + if( veh->check_heli_ascend( player_character ) ) { + player_character.add_msg_if_player( m_info, _( "You steer the vehicle into an ascent." ) ); } else { return; } @@ -472,7 +473,7 @@ inline static void pldrive( point d ) static void open() { - player &u = g->u; + avatar &player_character = get_avatar(); const cata::optional openp_ = choose_adjacent_highlight( _( "Open where?" ), pgettext( "no door, gate, curtain, etc.", "There is nothing that can be opened nearby." ), ACTION_OPEN, false ); @@ -483,17 +484,17 @@ static void open() const tripoint openp = *openp_; map &here = get_map(); - u.moves -= 100; + player_character.moves -= 100; if( const optional_vpart_position vp = here.veh_at( openp ) ) { vehicle *const veh = &vp->vehicle(); int openable = veh->next_part_to_open( vp->part_index() ); if( openable >= 0 ) { - const vehicle *player_veh = veh_pointer_or_null( here.veh_at( u.pos() ) ); + const vehicle *player_veh = veh_pointer_or_null( here.veh_at( player_character.pos() ) ); bool outside = !player_veh || player_veh != veh; if( !outside ) { - if( !veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { - u.moves += 100; + if( !veh->handle_potential_theft( player_character ) ) { + player_character.moves += 100; return; } else { veh->open( openable ); @@ -507,10 +508,10 @@ static void open() if( outside_openable == -1 ) { const std::string name = veh->part_info( openable ).name(); add_msg( m_info, _( "That %s can only opened from the inside." ), name ); - u.moves += 100; + player_character.moves += 100; } else { - if( !veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { - u.moves += 100; + if( !veh->handle_potential_theft( player_character ) ) { + player_character.moves += 100; return; } else { veh->open_all_at( openable ); @@ -524,12 +525,12 @@ static void open() const std::string name = already_open->info().name(); add_msg( m_info, _( "That %s is already open." ), name ); } - u.moves += 100; + player_character.moves += 100; } return; } - bool didit = here.open_door( openp, !here.is_outside( u.pos() ) ); + bool didit = here.open_door( openp, !here.is_outside( player_character.pos() ) ); if( !didit ) { const ter_str_id tid = here.ter( openp ).id(); @@ -540,11 +541,11 @@ static void open() } else if( tid.obj().close ) { // if the following message appears unexpectedly, the prior check was for t_door_o add_msg( m_info, _( "That door is already open." ) ); - u.moves += 100; + player_character.moves += 100; return; } add_msg( m_info, _( "No door there." ) ); - u.moves += 100; + player_character.moves += 100; } } @@ -553,13 +554,14 @@ static void close() if( const cata::optional pnt = choose_adjacent_highlight( _( "Close where?" ), pgettext( "no door, gate, etc.", "There is nothing that can be closed nearby." ), ACTION_CLOSE, false ) ) { - doors::close_door( get_map(), g->u, *pnt ); + doors::close_door( get_map(), get_player_character(), *pnt ); } } static void handbrake() { - const optional_vpart_position vp = get_map().veh_at( g->u.pos() ); + Character &player_character = get_player_character(); + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); if( !vp ) { return; } @@ -579,13 +581,13 @@ static void handbrake() veh->velocity = sgn * ( std::abs( veh->velocity ) - braking_power ); } } - g->u.moves = 0; + player_character.moves = 0; } // Establish or release a grab on a vehicle static void grab() { - avatar &you = g->u; + avatar &you = get_avatar(); map &here = get_map(); if( you.get_grab_type() != object_type::NONE ) { @@ -612,7 +614,7 @@ static void grab() return; } if( const optional_vpart_position vp = here.veh_at( grabp ) ) { - if( !vp->vehicle().handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( !vp->vehicle().handle_potential_theft( you ) ) { return; } you.grab( object_type::VEHICLE, grabp - you.pos() ); @@ -635,32 +637,32 @@ static void grab() static void haul() { - player &u = g->u; + Character &player_character = get_player_character(); map &here = get_map(); - if( u.is_hauling() ) { - u.stop_hauling(); + if( player_character.is_hauling() ) { + player_character.stop_hauling(); } else { - if( here.veh_at( u.pos() ) ) { + if( here.veh_at( player_character.pos() ) ) { add_msg( m_info, _( "You cannot haul inside vehicles." ) ); - } else if( here.has_flag( TFLAG_DEEP_WATER, u.pos() ) ) { + } else if( here.has_flag( TFLAG_DEEP_WATER, player_character.pos() ) ) { add_msg( m_info, _( "You cannot haul while in deep water." ) ); - } else if( !here.can_put_items( u.pos() ) ) { + } else if( !here.can_put_items( player_character.pos() ) ) { add_msg( m_info, _( "You cannot haul items here." ) ); - } else if( !here.has_items( u.pos() ) ) { + } else if( !here.has_items( player_character.pos() ) ) { add_msg( m_info, _( "There are no items to haul here." ) ); } else { - u.start_hauling(); + player_character.start_hauling(); } } } static void smash() { - player &u = g->u; + avatar &player_character = get_avatar(); map &here = get_map(); - if( u.is_mounted() ) { - auto mons = u.mounted_creature.get(); + if( player_character.is_mounted() ) { + auto mons = player_character.mounted_creature.get(); if( mons->has_flag( MF_RIDEABLE_MECH ) ) { if( !mons->check_mech_powered() ) { add_msg( m_bad, _( "Your %s refuses to move as its batteries have been drained." ), @@ -669,18 +671,19 @@ static void smash() } } } - const int move_cost = !u.is_armed() ? 80 : u.weapon.attack_time() * 0.8; + const int move_cost = !player_character.is_armed() ? 80 : player_character.weapon.attack_time() * + 0.8; bool didit = false; bool mech_smash = false; int smashskill; ///\EFFECT_STR increases smashing capability - if( u.is_mounted() ) { - auto mon = u.mounted_creature.get(); - smashskill = u.str_cur + mon->mech_str_addition() + mon->type->melee_dice * + if( player_character.is_mounted() ) { + auto mon = player_character.mounted_creature.get(); + smashskill = player_character.str_cur + mon->mech_str_addition() + mon->type->melee_dice * mon->type->melee_sides; mech_smash = true; } else { - smashskill = u.str_cur + u.weapon.damage_melee( DT_BASH ); + smashskill = player_character.str_cur + player_character.weapon.damage_melee( DT_BASH ); } const bool allow_floor_bash = debug_mode; // Should later become "true" @@ -691,17 +694,17 @@ static void smash() tripoint smashp = *smashp_; bool smash_floor = false; - if( smashp.z != u.posz() ) { - if( smashp.z > u.posz() ) { + if( smashp.z != player_character.posz() ) { + if( smashp.z > player_character.posz() ) { // TODO: Knock on the ceiling return; } - smashp.z = u.posz(); + smashp.z = player_character.posz(); smash_floor = true; } - if( u.is_mounted() ) { - monster *crit = u.mounted_creature.get(); + if( player_character.is_mounted() ) { + monster *crit = player_character.mounted_creature.get(); if( crit->has_flag( MF_RIDEABLE_MECH ) ) { crit->use_mech_power( -3 ); } @@ -719,7 +722,7 @@ static void smash() "field" ); here.remove_field( smashp, fd_to_smsh.first ); here.spawn_items( smashp, item_group::items_from( bash_info.drop_group, calendar::turn ) ); - u.mod_moves( - bash_info.fd_bash_move_cost ); + player_character.mod_moves( - bash_info.fd_bash_move_cost ); add_msg( m_info, bash_info.field_bash_msg_success.translated() ); return; } else { @@ -734,14 +737,14 @@ static void smash() if( maybe_corpse.is_corpse() && maybe_corpse.damage() < maybe_corpse.max_damage() && maybe_corpse.can_revive() ) { // do activity forever. ACT_PULP stops itself - u.assign_activity( ACT_PULP, calendar::INDEFINITELY_LONG, 0 ); - u.activity.placement = here.getabs( smashp ); + player_character.assign_activity( ACT_PULP, calendar::INDEFINITELY_LONG, 0 ); + player_character.activity.placement = here.getabs( smashp ); return; // don't smash terrain if we've smashed a corpse } } vehicle *veh = veh_pointer_or_null( here.veh_at( smashp ) ); if( veh != nullptr ) { - if( !veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( !veh->handle_potential_theft( player_character ) ) { return; } } @@ -752,57 +755,59 @@ static void smash() didit = here.bash( smashp, smashskill, false, false, smash_floor ).did_bash; if( didit ) { if( !mech_smash ) { - u.increase_activity_level( MODERATE_EXERCISE ); - u.handle_melee_wear( u.weapon ); + player_character.increase_activity_level( MODERATE_EXERCISE ); + player_character.handle_melee_wear( player_character.weapon ); - const int mod_sta = 2 * u.get_standard_stamina_cost(); - u.mod_stamina( mod_sta ); + const int mod_sta = 2 * player_character.get_standard_stamina_cost(); + player_character.mod_stamina( mod_sta ); - if( u.get_skill_level( skill_melee ) == 0 ) { - u.practice( skill_melee, rng( 0, 1 ) * rng( 0, 1 ) ); + if( player_character.get_skill_level( skill_melee ) == 0 ) { + player_character.practice( skill_melee, rng( 0, 1 ) * rng( 0, 1 ) ); } - const int vol = u.weapon.volume() / units::legacy_volume_factor; - if( u.weapon.made_of( material_id( "glass" ) ) && + const int vol = player_character.weapon.volume() / units::legacy_volume_factor; + if( player_character.weapon.made_of( material_id( "glass" ) ) && rng( 0, vol + 3 ) < vol ) { - add_msg( m_bad, _( "Your %s shatters!" ), u.weapon.tname() ); - u.weapon.spill_contents( u.pos() ); - sounds::sound( u.pos(), 24, sounds::sound_t::combat, "CRACK!", true, "smash", "glass" ); - u.deal_damage( nullptr, bodypart_id( "hand_r" ), damage_instance( DT_CUT, rng( 0, vol ) ) ); + add_msg( m_bad, _( "Your %s shatters!" ), player_character.weapon.tname() ); + player_character.weapon.spill_contents( player_character.pos() ); + sounds::sound( player_character.pos(), 24, sounds::sound_t::combat, "CRACK!", true, "smash", + "glass" ); + player_character.deal_damage( nullptr, bodypart_id( "hand_r" ), damage_instance( DT_CUT, rng( 0, + vol ) ) ); if( vol > 20 ) { // Hurt left arm too, if it was big - u.deal_damage( nullptr, bodypart_id( "hand_l" ), damage_instance( DT_CUT, rng( 0, - static_cast( vol * .5 ) ) ) ); + player_character.deal_damage( nullptr, bodypart_id( "hand_l" ), damage_instance( DT_CUT, rng( 0, + static_cast( vol * .5 ) ) ) ); } - u.remove_weapon(); - u.check_dead_state(); + player_character.remove_weapon(); + player_character.check_dead_state(); } // It hurts if you smash things with your hands. const bool hard_target = ( ( bash_furn > 2 ) || ( bash_furn == -1 && bash_ter > 2 ) ); int glove_coverage = 0; - for( const item &i : u.worn ) { + for( const item &i : player_character.worn ) { if( ( i.covers( bodypart_id( "hand_l" ) ) || i.covers( bodypart_id( "hand_r" ) ) ) ) { - int temp_coverage = i.get_coverage(); - if( glove_coverage < temp_coverage ) { - glove_coverage = temp_coverage; - } + int l_coverage = i.get_coverage( bodypart_id( "hand_l" ) ); + int r_coverage = i.get_coverage( bodypart_id( "hand_r" ) ); + glove_coverage = std::max( l_coverage, r_coverage ); } } - if( !u.has_weapon() && hard_target ) { + if( !player_character.has_weapon() && hard_target ) { int dam = roll_remainder( 5.0 * ( 1 - glove_coverage / 100.0 ) ); - if( u.get_part_hp_cur( bodypart_id( "arm_r" ) ) > u.get_part_hp_cur( bodypart_id( "arm_l" ) ) ) { - u.deal_damage( nullptr, bodypart_id( "hand_r" ), damage_instance( DT_BASH, dam ) ); + if( player_character.get_part_hp_cur( bodypart_id( "arm_r" ) ) > player_character.get_part_hp_cur( + bodypart_id( "arm_l" ) ) ) { + player_character.deal_damage( nullptr, bodypart_id( "hand_r" ), damage_instance( DT_BASH, dam ) ); } else { - u.deal_damage( nullptr, bodypart_id( "hand_l" ), damage_instance( DT_BASH, dam ) ); + player_character.deal_damage( nullptr, bodypart_id( "hand_l" ), damage_instance( DT_BASH, dam ) ); } if( dam > 0 ) { add_msg( m_bad, _( "You hurt your hands trying to smash the %s." ), here.furnname( smashp ) ); } } } - u.moves -= move_cost; + player_character.moves -= move_cost; if( smashskill < here.bash_resistance( smashp ) && one_in( 10 ) ) { if( here.has_furn( smashp ) && here.furn( smashp ).obj().bash.str_min != -1 ) { @@ -821,7 +826,7 @@ static void smash() static int try_set_alarm() { uilist as_m; - const bool already_set = g->u.has_effect( effect_alarm_clock ); + const bool already_set = get_player_character().has_effect( effect_alarm_clock ); as_m.text = already_set ? _( "You already have an alarm set. What do you want to do?" ) : @@ -842,17 +847,18 @@ static void wait() { std::map durations; uilist as_m; - player &u = g->u; + Character &player_character = get_player_character(); bool setting_alarm = false; map &here = get_map(); - if( u.controlling_vehicle && ( here.veh_at( u.pos() )->vehicle().velocity || - here.veh_at( u.pos() )->vehicle().cruise_velocity ) ) { + if( player_character.controlling_vehicle && + ( here.veh_at( player_character.pos() )->vehicle().velocity || + here.veh_at( player_character.pos() )->vehicle().cruise_velocity ) ) { popup( _( "You can't pass time while controlling a moving vehicle." ) ); return; } - if( u.has_alarm_clock() ) { + if( player_character.has_alarm_clock() ) { int alarm_query = try_set_alarm(); if( alarm_query == UILIST_CANCEL ) { return; @@ -860,7 +866,7 @@ static void wait() setting_alarm = alarm_query == 1; } - const bool has_watch = u.has_watch() || setting_alarm; + const bool has_watch = player_character.has_watch() || setting_alarm; const auto add_menu_item = [ &as_m, &durations, has_watch ] ( int retval, int hotkey, const std::string &caption = "", @@ -885,7 +891,7 @@ static void wait() } } else { - if( g->u.get_stamina() < g->u.get_stamina_max() ) { + if( player_character.get_stamina() < player_character.get_stamina_max() ) { as_m.addentry( 12, true, 'w', _( "Wait until you catch your breath" ) ); durations.emplace( 12, 15_minutes ); // to hide it from showing } @@ -923,7 +929,7 @@ static void wait() setting_alarm ? _( "Set alarm for midnight" ) : _( "Wait till midnight" ), diurnal_time_before( last_midnight + 0_hours ) ); if( setting_alarm ) { - if( u.has_effect( effect_alarm_clock ) ) { + if( player_character.has_effect( effect_alarm_clock ) ) { add_menu_item( 11, 'x', _( "Cancel the currently set alarm." ), 0_turns ); } @@ -945,11 +951,11 @@ static void wait() if( setting_alarm ) { // Setting alarm - u.remove_effect( effect_alarm_clock ); + player_character.remove_effect( effect_alarm_clock ); if( as_m.ret == 11 ) { add_msg( _( "You cancel your alarm." ) ); } else { - u.add_effect( effect_alarm_clock, time_to_wait ); + player_character.add_effect( effect_alarm_clock, time_to_wait ); add_msg( _( "You set your alarm." ) ); } @@ -966,15 +972,15 @@ static void wait() player_activity new_act( actType, 100 * ( to_turns( time_to_wait ) - 1 ), 0 ); - u.assign_activity( new_act, false ); + player_character.assign_activity( new_act, false ); } } static void sleep() { - player &u = g->u; - if( u.is_mounted() ) { - u.add_msg_if_player( m_info, _( "You cannot sleep while mounted." ) ); + avatar &player_character = get_avatar(); + if( player_character.is_mounted() ) { + add_msg( m_info, _( "You cannot sleep while mounted." ) ); return; } uilist as_m; @@ -992,15 +998,16 @@ static void sleep() // List all active items, bionics or mutations so player can deactivate them std::vector active; - for( auto &it : u.inv_dump() ) { + for( auto &it : player_character.inv_dump() ) { if( it->has_flag( flag_LITCIG ) || - ( it->active && ( it->charges > 0 || it->units_remaining( u ) > 0 ) && it->is_tool() && + ( it->active && ( it->charges > 0 || it->units_remaining( player_character ) > 0 ) && + it->is_tool() && !it->has_flag( flag_SLEEP_IGNORE ) ) ) { active.push_back( it->tname() ); } } - for( int i = 0; i < g->u.num_bionics(); i++ ) { - const bionic &bio = u.bionic_at_index( i ); + for( int i = 0; i < player_character.num_bionics(); i++ ) { + const bionic &bio = player_character.bionic_at_index( i ); if( !bio.powered ) { continue; } @@ -1017,17 +1024,18 @@ static void sleep() active.push_back( info.name.translated() ); } } - for( auto &mut : u.get_mutations() ) { + for( auto &mut : player_character.get_mutations() ) { const auto &mdata = mut.obj(); - if( mdata.cost > 0 && u.has_active_mutation( mut ) ) { + if( mdata.cost > 0 && player_character.has_active_mutation( mut ) ) { active.push_back( mdata.name() ); } } // check for deactivating any currently played music instrument. - for( auto &item : u.inv_dump() ) { + for( auto &item : player_character.inv_dump() ) { if( item->active && item->get_use( "musical_instrument" ) != nullptr ) { - u.add_msg_if_player( _( "You stop playing your %s before trying to sleep." ), item->tname() ); + player_character.add_msg_if_player( _( "You stop playing your %s before trying to sleep." ), + item->tname() ); // deactivate instrument item->active = false; } @@ -1058,12 +1066,13 @@ static void sleep() time_duration try_sleep_dur = 24_hours; std::string deaf_text; - if( g->u.is_deaf() ) { + if( player_character.is_deaf() ) { deaf_text = _( " (DEAF!)" ); } - if( u.has_alarm_clock() ) { + if( player_character.has_alarm_clock() ) { /* Reuse menu to ask player whether they want to set an alarm. */ - bool can_hibernate = u.get_hunger() < -60 && u.has_active_mutation( trait_HIBERNATE ); + bool can_hibernate = player_character.get_hunger() < -60 && + player_character.has_active_mutation( trait_HIBERNATE ); as_m.reset(); as_m.text = can_hibernate ? @@ -1083,15 +1092,15 @@ static void sleep() as_m.query(); if( as_m.ret >= 3 && as_m.ret <= 9 ) { - u.add_effect( effect_alarm_clock, 1_hours * as_m.ret ); + player_character.add_effect( effect_alarm_clock, 1_hours * as_m.ret ); try_sleep_dur = 1_hours * as_m.ret + 1_turns; } else if( as_m.ret < 0 ) { return; } } - u.moves = 0; - u.try_to_sleep( try_sleep_dur ); + player_character.moves = 0; + player_character.try_to_sleep( try_sleep_dur ); } static void loot() @@ -1110,31 +1119,36 @@ static void loot() MultiMining = 8192 }; - player &u = g->u; + Character &player_character = get_player_character(); int flags = 0; auto &mgr = zone_manager::get_manager(); - const bool has_fertilizer = u.has_item_with_flag( "FERTILIZER" ); + const bool has_fertilizer = player_character.has_item_with_flag( "FERTILIZER" ); // Manually update vehicle cache. // In theory this would be handled by the related activity (activity_on_turn_move_loot()) // but with a stale cache we never get that far. mgr.cache_vzones(); - flags |= g->check_near_zone( zone_type_id( "LOOT_UNSORTED" ), u.pos() ) ? SortLoot : 0; - if( g->check_near_zone( zone_type_id( "FARM_PLOT" ), u.pos() ) ) { + flags |= g->check_near_zone( zone_type_id( "LOOT_UNSORTED" ), + player_character.pos() ) ? SortLoot : 0; + if( g->check_near_zone( zone_type_id( "FARM_PLOT" ), player_character.pos() ) ) { flags |= FertilizePlots; flags |= MultiFarmPlots; } flags |= g->check_near_zone( zone_type_id( "CONSTRUCTION_BLUEPRINT" ), - u.pos() ) ? ConstructPlots : 0; + player_character.pos() ) ? ConstructPlots : 0; - flags |= g->check_near_zone( zone_type_id( "CHOP_TREES" ), u.pos() ) ? Multichoptrees : 0; - flags |= g->check_near_zone( zone_type_id( "LOOT_WOOD" ), u.pos() ) ? Multichopplanks : 0; + flags |= g->check_near_zone( zone_type_id( "CHOP_TREES" ), + player_character.pos() ) ? Multichoptrees : 0; + flags |= g->check_near_zone( zone_type_id( "LOOT_WOOD" ), + player_character.pos() ) ? Multichopplanks : 0; flags |= g->check_near_zone( zone_type_id( "VEHICLE_DECONSTRUCT" ), - u.pos() ) ? Multideconvehicle : 0; - flags |= g->check_near_zone( zone_type_id( "VEHICLE_REPAIR" ), u.pos() ) ? Multirepairvehicle : 0; - flags |= g->check_near_zone( zone_type_id( "LOOT_CORPSE" ), u.pos() ) ? MultiButchery : 0; - flags |= g->check_near_zone( zone_type_id( "MINING" ), u.pos() ) ? MultiMining : 0; + player_character.pos() ) ? Multideconvehicle : 0; + flags |= g->check_near_zone( zone_type_id( "VEHICLE_REPAIR" ), + player_character.pos() ) ? Multirepairvehicle : 0; + flags |= g->check_near_zone( zone_type_id( "LOOT_CORPSE" ), + player_character.pos() ) ? MultiButchery : 0; + flags |= g->check_near_zone( zone_type_id( "MINING" ), player_character.pos() ) ? MultiMining : 0; if( flags == 0 ) { add_msg( m_info, _( "There is no compatible zone nearby." ) ); add_msg( m_info, _( "Compatible zones are %s and %s" ), @@ -1199,34 +1213,34 @@ static void loot() add_msg( _( "Never mind." ) ); break; case SortLoot: - u.assign_activity( ACT_MOVE_LOOT ); + player_character.assign_activity( ACT_MOVE_LOOT ); break; case FertilizePlots: - u.assign_activity( ACT_FERTILIZE_PLOT ); + player_character.assign_activity( ACT_FERTILIZE_PLOT ); break; case ConstructPlots: - u.assign_activity( ACT_MULTIPLE_CONSTRUCTION ); + player_character.assign_activity( ACT_MULTIPLE_CONSTRUCTION ); break; case MultiFarmPlots: - u.assign_activity( ACT_MULTIPLE_FARM ); + player_character.assign_activity( ACT_MULTIPLE_FARM ); break; case Multichoptrees: - u.assign_activity( ACT_MULTIPLE_CHOP_TREES ); + player_character.assign_activity( ACT_MULTIPLE_CHOP_TREES ); break; case Multichopplanks: - u.assign_activity( ACT_MULTIPLE_CHOP_PLANKS ); + player_character.assign_activity( ACT_MULTIPLE_CHOP_PLANKS ); break; case Multideconvehicle: - u.assign_activity( ACT_VEHICLE_DECONSTRUCTION ); + player_character.assign_activity( ACT_VEHICLE_DECONSTRUCTION ); break; case Multirepairvehicle: - u.assign_activity( ACT_VEHICLE_REPAIR ); + player_character.assign_activity( ACT_VEHICLE_REPAIR ); break; case MultiButchery: - u.assign_activity( ACT_MULTIPLE_BUTCHER ); + player_character.assign_activity( ACT_MULTIPLE_BUTCHER ); break; case MultiMining: - u.assign_activity( ACT_MULTIPLE_MINE ); + player_character.assign_activity( ACT_MULTIPLE_MINE ); break; default: debugmsg( "Unsupported flag" ); @@ -1236,11 +1250,11 @@ static void loot() static void wear() { - avatar &u = g->u; - item_location loc = game_menus::inv::wear( u ); + avatar &player_character = get_avatar(); + item_location loc = game_menus::inv::wear( player_character ); if( loc ) { - u.wear( *loc.obtain( u ) ); + player_character.wear( *loc.obtain( player_character ) ); } else { add_msg( _( "Never mind." ) ); } @@ -1248,11 +1262,11 @@ static void wear() static void takeoff() { - avatar &u = g->u; - item_location loc = game_menus::inv::take_off( u ); + avatar &player_character = get_avatar(); + item_location loc = game_menus::inv::take_off( player_character ); if( loc ) { - u.takeoff( *loc.obtain( u ) ); + player_character.takeoff( *loc.obtain( player_character ) ); } else { add_msg( _( "Never mind." ) ); } @@ -1260,16 +1274,17 @@ static void takeoff() static void read() { - avatar &u = g->u; + avatar &player_character = get_avatar(); // Can read items from inventory or within one tile (including in vehicles) - item_location loc = game_menus::inv::read( u ); + item_location loc = game_menus::inv::read( player_character ); if( loc ) { if( loc->type->can_use( "learn_spell" ) ) { item spell_book = *loc.get_item(); - spell_book.get_use( "learn_spell" )->call( u, spell_book, spell_book.active, u.pos() ); + spell_book.get_use( "learn_spell" )->call( player_character, spell_book, + spell_book.active, player_character.pos() ); } else { - u.read( *loc.obtain( u ) ); + player_character.read( *loc.obtain( player_character ) ); } } else { add_msg( _( "Never mind." ) ); @@ -1291,17 +1306,17 @@ static void reach_attack( avatar &you ) static void fire() { - avatar &u = g->u; + avatar &player_character = get_avatar(); map &here = get_map(); // Use vehicle turret or draw a pistol from a holster if unarmed - if( !u.is_armed() ) { + if( !player_character.is_armed() ) { - const optional_vpart_position vp = here.veh_at( u.pos() ); + const optional_vpart_position vp = here.veh_at( player_character.pos() ); turret_data turret; - if( vp && ( turret = vp->vehicle().turret_query( u.pos() ) ) ) { - avatar_action::fire_turret_manual( u, here, turret ); + if( vp && ( turret = vp->vehicle().turret_query( player_character.pos() ) ) ) { + avatar_action::fire_turret_manual( player_character, here, turret ); return; } @@ -1314,7 +1329,7 @@ static void fire() std::vector options; std::vector> actions; - for( auto &w : u.worn ) { + for( auto &w : player_character.worn ) { std::vector guns = w.items_with( []( const item & it ) { return it.is_gun(); @@ -1328,12 +1343,12 @@ static void fire() w.type_name(), guns.front()->ammo_remaining() ) ); - actions.emplace_back( [&] { u.invoke_item( &w, "holster" ); } ); + actions.emplace_back( [&] { player_character.invoke_item( &w, "holster" ); } ); } else if( w.is_gun() && w.gunmod_find( itype_shoulder_strap ) ) { // wield item currently worn using shoulder strap options.push_back( w.display_name() ); - actions.emplace_back( [&] { u.wield( w ); } ); + actions.emplace_back( [&] { player_character.wield( w ); } ); } } if( !options.empty() ) { @@ -1344,26 +1359,26 @@ static void fire() } } - if( u.weapon.is_gun() && !u.weapon.gun_current_mode().melee() ) { - avatar_action::fire_wielded_weapon( u ); - } else if( u.weapon.current_reach_range( u ) > 1 ) { - if( u.has_effect( effect_relax_gas ) ) { + if( player_character.weapon.is_gun() && !player_character.weapon.gun_current_mode().melee() ) { + avatar_action::fire_wielded_weapon( player_character ); + } else if( player_character.weapon.current_reach_range( player_character ) > 1 ) { + if( player_character.has_effect( effect_relax_gas ) ) { if( one_in( 8 ) ) { add_msg( m_good, _( "Your willpower asserts itself, and so do you!" ) ); - reach_attack( u ); + reach_attack( player_character ); } else { - u.moves -= rng( 2, 8 ) * 10; + player_character.moves -= rng( 2, 8 ) * 10; add_msg( m_bad, _( "You're too pacified to strike anything…" ) ); } } else { - reach_attack( u ); + reach_attack( player_character ); } } } static void open_movement_mode_menu() { - avatar &u = g->u; + avatar &player_character = get_avatar(); const std::vector &modes = move_modes_by_speed(); const int cycle = 1027; uilist as_m; @@ -1372,9 +1387,12 @@ static void open_movement_mode_menu() for( size_t i = 0; i < modes.size(); ++i ) { const move_mode_id &curr = modes[i]; - as_m.entries.emplace_back( i, u.can_switch_to( curr ), curr->letter(), curr->name() ); + as_m.entries.emplace_back( static_cast( i ), player_character.can_switch_to( curr ), + curr->letter(), + curr->name() ); } - as_m.entries.emplace_back( cycle, u.can_switch_to( u.current_movement_mode()->cycle() ), '"', + as_m.entries.emplace_back( cycle, + player_character.can_switch_to( player_character.current_movement_mode()->cycle() ), '"', _( "Cycle move mode" ) ); // This should select the middle move mode as_m.selected = std::floor( modes.size() / 2 ); @@ -1382,20 +1400,20 @@ static void open_movement_mode_menu() if( as_m.ret != UILIST_CANCEL ) { if( as_m.ret == cycle ) { - u.cycle_move_mode(); + player_character.cycle_move_mode(); } else { - u.set_movement_mode( modes[as_m.ret] ); + player_character.set_movement_mode( modes[as_m.ret] ); } } } -static bool assign_spellcasting( avatar &you, spell &sp, bool fake_spell ); +static bool assign_spellcasting( Character &you, spell &sp, bool fake_spell ); static void cast_spell() { - avatar &u = g->u; + Character &player_character = get_player_character(); - std::vector spells = u.magic.spells(); + std::vector spells = player_character.magic.spells(); if( spells.empty() ) { add_msg( game_message_params{ m_bad, gmf_bypass_cooldown }, @@ -1405,8 +1423,8 @@ static void cast_spell() bool can_cast_spells = false; for( const spell_id &sp : spells ) { - spell temp_spell = u.magic.get_spell( sp ); - if( temp_spell.can_cast( u ) ) { + spell temp_spell = player_character.magic.get_spell( sp ); + if( temp_spell.can_cast( player_character ) ) { can_cast_spells = true; } } @@ -1416,18 +1434,18 @@ static void cast_spell() _( "You can't cast any of the spells you know!" ) ); } - const int spell_index = u.magic.select_spell( u ); + const int spell_index = player_character.magic.select_spell( player_character ); if( spell_index < 0 ) { return; } - spell &sp = *u.magic.get_spells()[spell_index]; + spell &sp = *player_character.magic.get_spells()[spell_index]; - assign_spellcasting( u, sp, false ); + assign_spellcasting( player_character, sp, false ); } // returns if the spell was assigned -static bool assign_spellcasting( avatar &you, spell &sp, bool fake_spell ) +static bool assign_spellcasting( Character &you, spell &sp, bool fake_spell ) { if( you.is_armed() && !sp.has_flag( spell_flag::NO_HANDS ) && !you.weapon.has_flag( flag_MAGIC_FOCUS ) ) { @@ -1503,15 +1521,16 @@ void game::open_consume_item_menu() as_m.entries.emplace_back( 2, true, 'm', _( "Medication" ) ); as_m.query(); + avatar &player_character = get_avatar(); switch( as_m.ret ) { case 0: - avatar_action::eat( u, game_menus::inv::consume_food( u ) ); + avatar_action::eat( player_character, game_menus::inv::consume_food( player_character ) ); break; case 1: - avatar_action::eat( u, game_menus::inv::consume_drink( u ) ); + avatar_action::eat( player_character, game_menus::inv::consume_drink( player_character ) ); break; case 2: - avatar_action::eat( u, game_menus::inv::consume_meds( u ) ); + avatar_action::eat( player_character, game_menus::inv::consume_meds( player_character ) ); break; default: break; @@ -1524,26 +1543,27 @@ bool game::handle_action() input_context ctxt; action_id act = ACTION_NULL; user_turn current_turn; + avatar &player_character = get_avatar(); // Check if we have an auto-move destination - if( u.has_destination() ) { - act = u.get_next_auto_move_direction(); + if( player_character.has_destination() ) { + act = player_character.get_next_auto_move_direction(); if( act == ACTION_NULL ) { add_msg( m_info, _( "Auto-move canceled" ) ); - u.clear_destination(); + player_character.clear_destination(); return false; } - } else if( u.has_destination_activity() ) { + } else if( player_character.has_destination_activity() ) { // starts destination activity after the player successfully reached his destination - u.start_destination_activity(); + player_character.start_destination_activity(); return false; } else { // No auto-move, ask player for input ctxt = get_player_input( action ); } - const optional_vpart_position vp = m.veh_at( u.pos() ); - bool veh_ctrl = !u.is_dead_state() && - ( ( vp && vp->vehicle().player_in_control( u ) ) || remoteveh() != nullptr ); + const optional_vpart_position vp = m.veh_at( player_character.pos() ); + bool veh_ctrl = !player_character.is_dead_state() && + ( ( vp && vp->vehicle().player_in_control( player_character ) ) || remoteveh() != nullptr ); // If performing an action with right mouse button, co-ordinates // of location clicked. @@ -1567,7 +1587,7 @@ bool game::handle_action() return false; } // No auto-move actions have or can be set at this point. - u.clear_destination(); + player_character.clear_destination(); destination_preview.clear(); act = handle_main_menu(); if( act == ACTION_NULL ) { @@ -1580,7 +1600,7 @@ bool game::handle_action() return false; } // No auto-move actions have or can be set at this point. - u.clear_destination(); + player_character.clear_destination(); destination_preview.clear(); act = handle_action_menu(); if( act == ACTION_NULL ) { @@ -1594,7 +1614,7 @@ bool game::handle_action() } if( act == ACTION_KEYBINDINGS ) { - u.clear_destination(); + player_character.clear_destination(); destination_preview.clear(); act = ctxt.display_menu( true ); if( act == ACTION_NULL ) { @@ -1613,7 +1633,7 @@ bool game::handle_action() return false; } - if( u.is_dead_state() ) { + if( player_character.is_dead_state() ) { // do not allow mouse actions while dead return false; } @@ -1621,7 +1641,7 @@ bool game::handle_action() const cata::optional mouse_pos = ctxt.get_coordinates( w_terrain ); if( !mouse_pos ) { return false; - } else if( !u.sees( *mouse_pos ) ) { + } else if( !player_character.sees( *mouse_pos ) ) { // Not clicked in visible terrain return false; } @@ -1646,7 +1666,7 @@ bool game::handle_action() // auto-move destination if the action is only a timeout, as this // would require the user to double click quicker than the // timeout delay. - u.clear_destination(); + player_character.clear_destination(); destination_preview.clear(); } } @@ -1674,18 +1694,18 @@ bool game::handle_action() int soffset = get_option( "MOVE_VIEW_OFFSET" ); - int before_action_moves = u.moves; + int before_action_moves = player_character.moves; // These actions are allowed while deathcam is active. Registered in game::get_player_input - if( uquit == QUIT_WATCH || !u.is_dead_state() ) { + if( uquit == QUIT_WATCH || !player_character.is_dead_state() ) { switch( act ) { case ACTION_TOGGLE_MAP_MEMORY: - u.toggle_map_memory(); + player_character.toggle_map_memory(); break; case ACTION_CENTER: - u.view_offset.x = driving_view_offset.x; - u.view_offset.y = driving_view_offset.y; + player_character.view_offset.x = driving_view_offset.x; + player_character.view_offset.y = driving_view_offset.y; break; case ACTION_SHIFT_N: @@ -1706,8 +1726,8 @@ bool game::handle_action() { ACTION_SHIFT_W, { point_west, point_north_west } }, { ACTION_SHIFT_NW, { point_north_west, point_north } }, }; - u.view_offset += use_tiles && tile_iso ? - shift_delta.at( act ).second * soffset : shift_delta.at( act ).first * soffset; + player_character.view_offset += use_tiles && tile_iso ? + shift_delta.at( act ).second * soffset : shift_delta.at( act ).first * soffset; } break; @@ -1725,7 +1745,7 @@ bool game::handle_action() } // actions allowed only while alive - if( !u.is_dead_state() ) { + if( !player_character.is_dead_state() ) { switch( act ) { case ACTION_NULL: case NUM_ACTIONS: @@ -1737,30 +1757,30 @@ bool game::handle_action() case ACTION_TIMEOUT: if( check_safe_mode_allowed( false ) ) { - u.pause(); + player_character.pause(); } break; case ACTION_PAUSE: if( check_safe_mode_allowed() ) { - u.pause(); + player_character.pause(); } break; case ACTION_CYCLE_MOVE: - u.cycle_move_mode(); + player_character.cycle_move_mode(); break; case ACTION_RESET_MOVE: - u.reset_move_mode(); + player_character.reset_move_mode(); break; case ACTION_TOGGLE_RUN: - u.toggle_run_mode(); + player_character.toggle_run_mode(); break; case ACTION_TOGGLE_CROUCH: - u.toggle_crouch_mode(); + player_character.toggle_crouch_mode(); break; case ACTION_OPEN_MOVEMENT: @@ -1775,9 +1795,9 @@ bool game::handle_action() case ACTION_MOVE_BACK_LEFT: case ACTION_MOVE_LEFT: case ACTION_MOVE_FORTH_LEFT: - if( !u.get_value( "remote_controlling" ).empty() && - ( u.has_active_item( itype_radiocontrol ) || - u.has_active_bionic( bio_remote ) ) ) { + if( !player_character.get_value( "remote_controlling" ).empty() && + ( player_character.has_active_item( itype_radiocontrol ) || + player_character.has_active_bionic( bio_remote ) ) ) { rcdrive( get_delta_from_movement_action( act, iso_rotate::yes ) ); } else if( veh_ctrl ) { // vehicle control uses x for steering and y for ac/deceleration, @@ -1785,43 +1805,43 @@ bool game::handle_action() pldrive( get_delta_from_movement_action( act, iso_rotate::no ) ); } else { point dest_delta = get_delta_from_movement_action( act, iso_rotate::yes ); - if( auto_travel_mode && !u.is_auto_moving() ) { + if( auto_travel_mode && !player_character.is_auto_moving() ) { for( int i = 0; i < SEEX; i++ ) { - tripoint auto_travel_destination( u.posx() + dest_delta.x * ( SEEX - i ), - u.posy() + dest_delta.y * ( SEEX - i ), - u.posz() ); - destination_preview = m.route( u.pos(), + tripoint auto_travel_destination( player_character.posx() + dest_delta.x * ( SEEX - i ), + player_character.posy() + dest_delta.y * ( SEEX - i ), + player_character.posz() ); + destination_preview = m.route( player_character.pos(), auto_travel_destination, - u.get_pathfinding_settings(), - u.get_path_avoid() ); + player_character.get_pathfinding_settings(), + player_character.get_path_avoid() ); if( !destination_preview.empty() ) { destination_preview.erase( destination_preview.begin() + 1, destination_preview.end() ); - u.set_destination( destination_preview ); + player_character.set_destination( destination_preview ); break; } } - act = u.get_next_auto_move_direction(); + act = player_character.get_next_auto_move_direction(); const point dest_next = get_delta_from_movement_action( act, iso_rotate::yes ); if( dest_next == point_zero ) { - u.clear_destination(); + player_character.clear_destination(); } dest_delta = dest_next; } - if( !avatar_action::move( u, m, dest_delta ) ) { + if( !avatar_action::move( player_character, m, dest_delta ) ) { // auto-move should be canceled due to a failed move or obstacle - u.clear_destination(); + player_character.clear_destination(); } } break; case ACTION_MOVE_DOWN: - if( u.is_mounted() ) { - auto mon = u.mounted_creature.get(); + if( player_character.is_mounted() ) { + auto mon = player_character.mounted_creature.get(); if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { add_msg( m_info, _( "You can't go down stairs while you're riding." ) ); break; } } - if( !u.in_vehicle ) { + if( !player_character.in_vehicle ) { vertical_move( -1, false ); } else if( veh_ctrl && vp->vehicle().is_rotorcraft() ) { pldrive( tripoint_below ); @@ -1829,14 +1849,14 @@ bool game::handle_action() break; case ACTION_MOVE_UP: - if( u.is_mounted() ) { - auto mon = u.mounted_creature.get(); + if( player_character.is_mounted() ) { + auto mon = player_character.mounted_creature.get(); if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { add_msg( m_info, _( "You can't go down stairs while you're riding." ) ); break; } } - if( !u.in_vehicle ) { + if( !player_character.in_vehicle ) { vertical_move( 1, false ); } else if( veh_ctrl && vp->vehicle().is_rotorcraft() ) { pldrive( tripoint_above ); @@ -1844,9 +1864,9 @@ bool game::handle_action() break; case ACTION_OPEN: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't open things while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't open things while you're riding." ) ); } else { open(); @@ -1854,15 +1874,15 @@ bool game::handle_action() break; case ACTION_CLOSE: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't close things while you're in your shell." ) ); - } else if( u.is_mounted() ) { - auto mon = u.mounted_creature.get(); + } else if( player_character.is_mounted() ) { + auto mon = player_character.mounted_creature.get(); if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { add_msg( m_info, _( "You can't close things while you're riding." ) ); } } else if( mouse_target ) { - doors::close_door( m, u, *mouse_target ); + doors::close_door( m, player_character, *mouse_target ); } else { close(); } @@ -1871,7 +1891,7 @@ bool game::handle_action() case ACTION_SMASH: if( veh_ctrl ) { handbrake(); - } else if( u.has_active_mutation( trait_SHELL2 ) ) { + } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't smash things while you're in your shell." ) ); } else { smash(); @@ -1879,7 +1899,7 @@ bool game::handle_action() break; case ACTION_EXAMINE: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't examine your surroundings while you're in your shell." ) ); } else if( mouse_target ) { examine( *mouse_target ); @@ -1889,9 +1909,9 @@ bool game::handle_action() break; case ACTION_ADVANCEDINV: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't move mass quantities while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't move mass quantities while you're riding." ) ); } else { create_advanced_inv(); @@ -1899,9 +1919,9 @@ bool game::handle_action() break; case ACTION_PICKUP: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't pick anything up while you're riding." ) ); } else if( mouse_target ) { pickup( *mouse_target ); @@ -1911,7 +1931,7 @@ bool game::handle_action() break; case ACTION_PICKUP_FEET: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); } else { pickup_feet(); @@ -1919,9 +1939,9 @@ bool game::handle_action() break; case ACTION_GRAB: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't grab things while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't grab things while you're riding." ) ); } else { grab(); @@ -1929,9 +1949,9 @@ bool game::handle_action() break; case ACTION_HAUL: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't haul things while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't haul things while you're riding." ) ); } else { haul(); @@ -1939,9 +1959,9 @@ bool game::handle_action() break; case ACTION_BUTCHER: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't butcher while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't butcher while you're riding." ) ); } else { butcher(); @@ -1953,9 +1973,9 @@ bool game::handle_action() break; case ACTION_PEEK: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't peek around corners while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't peek around corners while you're riding." ) ); } else { peek(); @@ -1975,25 +1995,25 @@ bool game::handle_action() break; case ACTION_INVENTORY: - game_menus::inv::common( u ); + game_menus::inv::common( player_character ); break; case ACTION_COMPARE: - game_menus::inv::compare( u, cata::nullopt ); + game_menus::inv::compare( player_character, cata::nullopt ); break; case ACTION_ORGANIZE: - game_menus::inv::swap_letters( u ); + game_menus::inv::swap_letters( player_character ); break; case ACTION_USE: // Shell-users are presumed to be able to mess with their inventories, etc // while in the shell. Eating, gear-changing, and item use are OK. - avatar_action::use_item( u ); + avatar_action::use_item( player_character ); break; case ACTION_USE_WIELDED: - u.use_wielded(); + player_character.use_wielded(); break; case ACTION_WEAR: @@ -2005,13 +2025,13 @@ bool game::handle_action() break; case ACTION_EAT: - if( !avatar_action::eat_here( u ) ) { - avatar_action::eat( u ); + if( !avatar_action::eat_here( player_character ) ) { + avatar_action::eat( player_character ); } break; case ACTION_OPEN_CONSUME: - if( !avatar_action::eat_here( u ) ) { + if( !avatar_action::eat_here( player_character ) ) { open_consume_item_menu(); } break; @@ -2026,7 +2046,7 @@ bool game::handle_action() break; case ACTION_PICK_STYLE: - u.martial_arts_data.pick_style( u ); + player_character.martial_arts_data.pick_style( player_character ); break; case ACTION_RELOAD_ITEM: @@ -2042,16 +2062,16 @@ bool game::handle_action() break; case ACTION_UNLOAD: - avatar_action::unload( u ); + avatar_action::unload( player_character ); break; case ACTION_MEND: - avatar_action::mend( g->u, item_location() ); + avatar_action::mend( player_character, item_location() ); break; case ACTION_THROW: { item_location loc; - avatar_action::plthrow( g->u, loc ); + avatar_action::plthrow( player_character, loc ); break; } @@ -2064,26 +2084,28 @@ bool game::handle_action() break; case ACTION_FIRE_BURST: { - gun_mode_id original_mode = u.weapon.gun_get_mode_id(); - if( u.weapon.gun_set_mode( gun_mode_id( "AUTO" ) ) ) { - avatar_action::fire_wielded_weapon( u ); - u.weapon.gun_set_mode( original_mode ); + gun_mode_id original_mode = player_character.weapon.gun_get_mode_id(); + if( player_character.weapon.gun_set_mode( gun_mode_id( "AUTO" ) ) ) { + avatar_action::fire_wielded_weapon( player_character ); + player_character.weapon.gun_set_mode( original_mode ); } break; } case ACTION_SELECT_FIRE_MODE: - if( u.is_armed() ) { - if( u.weapon.is_gun() && !u.weapon.is_gunmod() && u.weapon.gun_all_modes().size() > 1 ) { - u.weapon.gun_cycle_mode(); - } else if( u.weapon.has_flag( flag_RELOAD_ONE ) || u.weapon.has_flag( flag_RELOAD_AND_SHOOT ) ) { - item::reload_option opt = u.select_ammo( u.weapon, false ); + if( player_character.is_armed() ) { + if( player_character.weapon.is_gun() && !player_character.weapon.is_gunmod() && + player_character.weapon.gun_all_modes().size() > 1 ) { + player_character.weapon.gun_cycle_mode(); + } else if( player_character.weapon.has_flag( flag_RELOAD_ONE ) || + player_character.weapon.has_flag( flag_RELOAD_AND_SHOOT ) ) { + item::reload_option opt = player_character.select_ammo( player_character.weapon, false ); if( !opt ) { break; - } else if( u.ammo_location && opt.ammo == u.ammo_location ) { - u.ammo_location = item_location(); + } else if( player_character.ammo_location && opt.ammo == player_character.ammo_location ) { + player_character.ammo_location = item_location(); } else { - u.ammo_location = opt.ammo; + player_character.ammo_location = opt.ammo; } } } @@ -2095,21 +2117,21 @@ bool game::handle_action() break; case ACTION_DIR_DROP: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't drop things to another tile while you're in your shell." ) ); } else { drop_in_direction(); } break; case ACTION_BIONICS: - u.power_bionics(); + player_character.power_bionics(); break; case ACTION_MUTATIONS: - u.power_mutations(); + player_character.power_mutations(); break; case ACTION_SORT_ARMOR: - u.sort_armor(); + player_character.sort_armor(); break; case ACTION_WAIT: @@ -2117,51 +2139,51 @@ bool game::handle_action() break; case ACTION_CRAFT: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't craft while you're riding." ) ); } else { - u.craft(); + player_character.craft(); } break; case ACTION_RECRAFT: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't craft while you're riding." ) ); } else { - u.recraft(); + player_character.recraft(); } break; case ACTION_LONGCRAFT: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't craft while you're riding." ) ); } else { - u.long_craft(); + player_character.long_craft(); } break; case ACTION_DISASSEMBLE: - if( u.controlling_vehicle ) { + if( player_character.controlling_vehicle ) { add_msg( m_info, _( "You can't disassemble items while driving." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't disassemble items while you're riding." ) ); } else { - u.disassemble(); + player_character.disassemble(); } break; case ACTION_CONSTRUCT: - if( u.in_vehicle ) { + if( player_character.in_vehicle ) { add_msg( m_info, _( "You can't construct while in a vehicle." ) ); - } else if( u.has_active_mutation( trait_SHELL2 ) ) { + } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't construct while you're in your shell." ) ); - } else if( u.is_mounted() ) { + } else if( player_character.is_mounted() ) { add_msg( m_info, _( "You can't construct while you're riding." ) ); } else { construction_menu( false ); @@ -2179,11 +2201,11 @@ bool game::handle_action() break; case ACTION_CONTROL_VEHICLE: - if( u.has_active_mutation( trait_SHELL2 ) ) { + if( player_character.has_active_mutation( trait_SHELL2 ) ) { add_msg( m_info, _( "You can't operate a vehicle while you're in your shell." ) ); - } else if( u.is_mounted() ) { - u.dismount(); - } else if( u.has_trait( trait_WAYFARER ) ) { + } else if( player_character.is_mounted() ) { + player_character.dismount(); + } else if( player_character.has_trait( trait_WAYFARER ) ) { add_msg( m_info, _( "You refuse to take control of this vehicle." ) ); } else { control_vehicle(); @@ -2206,8 +2228,8 @@ bool game::handle_action() add_msg( m_info, get_option( "AUTOSAFEMODE" ) ? _( "Safe mode OFF! (Auto safe mode still enabled!)" ) : _( "Safe mode OFF!" ) ); } - if( u.has_effect( effect_laserlocked ) ) { - u.remove_effect( effect_laserlocked ); + if( player_character.has_effect( effect_laserlocked ) ) { + player_character.remove_effect( effect_laserlocked ); safe_mode_warning_logged = false; } break; @@ -2223,18 +2245,18 @@ bool game::handle_action() case ACTION_IGNORE_ENEMY: if( safe_mode == SAFE_MODE_STOP ) { add_msg( m_info, _( "Ignoring enemy!" ) ); - for( auto &elem : u.get_mon_visible().new_seen_mon ) { + for( auto &elem : player_character.get_mon_visible().new_seen_mon ) { monster &critter = *elem; - critter.ignoring = rl_dist( u.pos(), critter.pos() ); + critter.ignoring = rl_dist( player_character.pos(), critter.pos() ); } set_safe_mode( SAFE_MODE_ON ); - } else if( u.has_effect( effect_laserlocked ) ) { - if( u.has_trait( trait_PROF_CHURL ) ) { + } else if( player_character.has_effect( effect_laserlocked ) ) { + if( player_character.has_trait( trait_PROF_CHURL ) ) { add_msg( m_warning, _( "You make the sign of the cross." ) ); } else { add_msg( m_info, _( "Ignoring laser targeting!" ) ); } - u.remove_effect( effect_laserlocked ); + player_character.remove_effect( effect_laserlocked ); safe_mode_warning_logged = false; } break; @@ -2251,11 +2273,18 @@ bool game::handle_action() } break; + case ACTION_WORKOUT: + if( query_yn( _( "Start workout?" ) ) ) { + player_character.assign_activity( player_activity( workout_activity_actor( + player_character.pos() ) ) ); + } + break; + case ACTION_SUICIDE: if( query_yn( _( "Commit suicide?" ) ) ) { if( query_yn( _( "REALLY commit suicide?" ) ) ) { - u.moves = 0; - u.place_corpse(); + player_character.moves = 0; + player_character.place_corpse(); uquit = QUIT_SUICIDE; } } @@ -2264,7 +2293,7 @@ bool game::handle_action() case ACTION_SAVE: if( query_yn( _( "Save and quit?" ) ) ) { if( save() ) { - u.moves = 0; + player_character.moves = 0; uquit = QUIT_SAVED; } } @@ -2279,7 +2308,7 @@ bool game::handle_action() return false; case ACTION_PL_INFO: - u.disp_info(); + player_character.disp_info(); break; case ACTION_MAP: @@ -2287,7 +2316,7 @@ bool game::handle_action() break; case ACTION_SKY: - if( m.is_outside( u.pos() ) ) { + if( m.is_outside( player_character.pos() ) ) { ui::omap::display_visible_weather(); } else { add_msg( m_info, _( "You can't see the sky from here." ) ); @@ -2307,7 +2336,7 @@ bool game::handle_action() break; case ACTION_MORALE: - u.disp_morale(); + player_character.disp_morale(); break; case ACTION_MESSAGES: @@ -2393,24 +2422,25 @@ bool game::handle_action() break; case ACTION_TOGGLE_THIEF_MODE: - if( g->u.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { - u.set_value( "THIEF_MODE", "THIEF_HONEST" ); - u.set_value( "THIEF_MODE_KEEP", "YES" ); + if( player_character.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { + player_character.set_value( "THIEF_MODE", "THIEF_HONEST" ); + player_character.set_value( "THIEF_MODE_KEEP", "YES" ); //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL add_msg( _( "You will not pick up other peoples belongings." ) ); - } else if( g->u.get_value( "THIEF_MODE" ) == "THIEF_HONEST" ) { - u.set_value( "THIEF_MODE", "THIEF_STEAL" ); - u.set_value( "THIEF_MODE_KEEP", "YES" ); + } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_HONEST" ) { + player_character.set_value( "THIEF_MODE", "THIEF_STEAL" ); + player_character.set_value( "THIEF_MODE_KEEP", "YES" ); //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL add_msg( _( "You will pick up also those things that belong to others!" ) ); - } else if( g->u.get_value( "THIEF_MODE" ) == "THIEF_STEAL" ) { - u.set_value( "THIEF_MODE", "THIEF_ASK" ); - u.set_value( "THIEF_MODE_KEEP", "NO" ); + } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_STEAL" ) { + player_character.set_value( "THIEF_MODE", "THIEF_ASK" ); + player_character.set_value( "THIEF_MODE_KEEP", "NO" ); //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL add_msg( _( "You will be reminded not to steal." ) ); } else { // ERROR - add_msg( _( "THIEF_MODE CONTAINED BAD VALUE [ %s ]!" ), g->u.get_value( "THIEF_MODE" ) ); + add_msg( _( "THIEF_MODE CONTAINED BAD VALUE [ %s ]!" ), + player_character.get_value( "THIEF_MODE" ) ); } break; @@ -2504,7 +2534,7 @@ bool game::handle_action() break; case ACTION_AUTOATTACK: - avatar_action::autoattack( u, m ); + avatar_action::autoattack( player_character, m ); break; default: @@ -2512,12 +2542,14 @@ bool game::handle_action() } } if( act != ACTION_TIMEOUT ) { - u.mod_moves( -current_turn.moves_elapsed() ); + player_character.mod_moves( -current_turn.moves_elapsed() ); } gamemode->post_action( act ); - u.movecounter = ( !u.is_dead_state() ? ( before_action_moves - u.moves ) : 0 ); + player_character.movecounter = ( !player_character.is_dead_state() ? ( before_action_moves - + player_character.moves ) : 0 ); dbg( D_INFO ) << string_format( "%s: [%d] %d - %d = %d", action_ident( act ), - to_turn( calendar::turn ), before_action_moves, u.movecounter, u.moves ); - return ( !u.is_dead_state() ); + to_turn( calendar::turn ), before_action_moves, player_character.movecounter, + player_character.moves ); + return ( !player_character.is_dead_state() ); } diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 7476f9e8eae9f..aef9fbe4187b3 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -63,6 +63,7 @@ #include "messages.h" #include "mission_companion.h" #include "monster.h" +#include "morale_types.h" #include "mtype.h" #include "npc.h" #include "options.h" @@ -81,6 +82,7 @@ #include "string_formatter.h" #include "string_id.h" #include "string_input_popup.h" +#include "talker.h" #include "timed_event.h" #include "translations.h" #include "trap.h" @@ -157,6 +159,7 @@ static const skill_id skill_cooking( "cooking" ); static const skill_id skill_fabrication( "fabrication" ); static const skill_id skill_mechanics( "mechanics" ); static const skill_id skill_survival( "survival" ); +static const skill_id skill_traps( "traps" ); static const trait_id trait_AMORPHOUS( "AMORPHOUS" ); static const trait_id trait_ARACHNID_ARMS_OK( "ARACHNID_ARMS_OK" ); @@ -371,13 +374,14 @@ void iexamine::gaspump( player &p, const tripoint &examp ) void iexamine::translocator( player &, const tripoint &examp ) { const tripoint omt_loc = ms_to_omt_copy( get_map().getabs( examp ) ); - const bool activated = g->u.translocators.knows_translocator( examp ); + avatar &player_character = get_avatar(); + const bool activated = player_character.translocators.knows_translocator( examp ); if( !activated ) { - g->u.translocators.activate_teleporter( omt_loc, examp ); + player_character.translocators.activate_teleporter( omt_loc, examp ); add_msg( m_info, _( "Translocator gate active." ) ); } else { if( query_yn( _( "Do you want to deactivate this active Translocator?" ) ) ) { - g->u.translocators.deactivate_teleporter( omt_loc, examp ); + player_character.translocators.deactivate_teleporter( omt_loc, examp ); } } } @@ -897,7 +901,7 @@ void iexamine::elevator( player &p, const tripoint &examp ) } else if( here.ter( critter.pos() ) == ter_id( "t_elevator" ) ) { tripoint critter_omt = ms_to_omt_copy( here.getabs( critter.pos() ) ); if( critter_omt == new_floor_omt ) { - for( const tripoint &candidate : closest_tripoints_first( critter.pos(), 10 ) ) { + for( const tripoint &candidate : closest_points_first( critter.pos(), 10 ) ) { if( here.ter( candidate ) != ter_id( "t_elevator" ) && here.passable( candidate ) && !g->critter_at( candidate ) ) { @@ -920,7 +924,7 @@ void iexamine::elevator( player &p, const tripoint &examp ) tripoint critter_omt = ms_to_omt_copy( here.getabs( critter.pos() ) ); if( critter_omt == original_floor_omt ) { - for( const tripoint &candidate : closest_tripoints_first( p.pos(), 10 ) ) { + for( const tripoint &candidate : closest_points_first( p.pos(), 10 ) ) { if( here.ter( candidate ) == ter_id( "t_elevator" ) && candidate != p.pos() && !g->critter_at( candidate ) ) { @@ -1055,7 +1059,8 @@ void iexamine::intercom( player &p, const tripoint &examp ) if( intercom_npcs.empty() ) { p.add_msg_if_player( m_info, _( "No one responds." ) ); } else { - intercom_npcs.front()->talk_to_u( false, false ); + // TODO: This needs to be converted a talker_console or something + g->u.talk_to( get_talker_for( *intercom_npcs.front() ), false, false ); } } @@ -1074,7 +1079,7 @@ void iexamine::rubble( player &p, const tripoint &examp ) return; } map &here = get_map(); - if( ( here.veh_at( examp ) || !here.tr_at( examp ).is_null() || + if( ( here.veh_at( examp ) || here.can_see_trap_at( examp, p ) || g->critter_at( examp ) != nullptr ) && !query_yn( _( "Clear up that %s?" ), here.furnname( examp ) ) ) { return; @@ -1124,7 +1129,9 @@ void iexamine::chainfence( player &p, const tripoint &examp ) return; } p.moves += climb * 10; - sfx::play_variant_sound( "plmove", "clear_obstacle", sfx::get_heard_volume( g->u.pos() ) ); + Character &player_character = get_player_character(); + sfx::play_variant_sound( "plmove", "clear_obstacle", + sfx::get_heard_volume( player_character.pos() ) ); } if( p.in_vehicle ) { here.unboard_vehicle( p.pos() ); @@ -1148,9 +1155,11 @@ void iexamine::bars( player &p, const tripoint &examp ) return; } map &here = get_map(); - if( ( ( p.encumb( bp_torso ) ) >= 10 ) && ( ( p.encumb( bp_head ) ) >= 10 ) && - ( p.encumb( bp_foot_l ) >= 10 || - p.encumb( bp_foot_r ) >= 10 ) ) { // Most likely places for rigid gear that would catch on the bars. + if( ( ( p.encumb( bodypart_id( "torso" ) ) ) >= 10 ) && + ( ( p.encumb( bodypart_id( "head" ) ) ) >= 10 ) && + ( p.encumb( bodypart_id( "foot_l" ) ) >= 10 || + p.encumb( bodypart_id( "foot_r" ) ) >= + 10 ) ) { // Most likely places for rigid gear that would catch on the bars. add_msg( m_info, _( "Your amorphous body could slip though the %s, but your cumbersome gear can't." ), here.tername( examp ) ); @@ -1998,7 +2007,7 @@ void iexamine::egg_sack_generic( player &p, const tripoint &examp, here.furn_set( examp, f_egg_sacke ); int monster_count = 0; if( one_in( 2 ) ) { - for( const tripoint &nearby_pos : closest_tripoints_first( examp, 1 ) ) { + for( const tripoint &nearby_pos : closest_points_first( examp, 1 ) ) { if( !one_in( 3 ) ) { continue; } else if( g->place_critter_at( montype, nearby_pos ) ) { @@ -2116,7 +2125,7 @@ void iexamine::plant_seed( player &p, const tripoint &examp, const itype_id &see void iexamine::dirtmound( player &p, const tripoint &examp ) { - if( !warm_enough_to_plant( g->u.pos() ) ) { + if( !warm_enough_to_plant( get_player_character().pos() ) ) { add_msg( m_info, _( "It is too cold to plant anything now." ) ); return; } @@ -3191,8 +3200,9 @@ void iexamine::keg( player &p, const tripoint &examp ) drink.set_relative_rot( drink_rot[ drink_index ] ); drink.charges = 0; bool keg_full = false; + Character &player_character = get_player_character(); for( int i = 0; i < charges_held && !keg_full; i++ ) { - g->u.use_charges( drink.typeId(), 1 ); + player_character.use_charges( drink.typeId(), 1 ); drink.charges++; keg_full = drink.volume() >= keg_cap; } @@ -3511,8 +3521,9 @@ void iexamine::tree_maple_tapped( player &p, const tripoint &examp ) } case REMOVE_CONTAINER: { - g->u.assign_activity( player_activity( pickup_activity_actor( - { item_location( map_cursor( examp ), container ) }, { 0 }, g->u.pos() ) ) ); + Character &player_character = get_player_character(); + player_character.assign_activity( player_activity( pickup_activity_actor( + { item_location( map_cursor( examp ), container ) }, { 0 }, player_character.pos() ) ) ); return; } @@ -3562,7 +3573,7 @@ void iexamine::shrub_wildveggies( player &p, const tripoint &examp ) // Ask if there's something possibly more interesting than this shrub here if( ( !here.i_at( examp ).empty() || here.veh_at( examp ) || - !here.tr_at( examp ).is_null() || + here.can_see_trap_at( examp, p ) || g->critter_at( examp ) != nullptr ) && !query_yn( _( "Forage through %s?" ), here.tername( examp ) ) ) { none( p, examp ); @@ -3689,57 +3700,101 @@ void iexamine::recycle_compactor( player &, const tripoint &examp ) } } -void iexamine::trap( player &p, const tripoint &examp ) +void trap::examine( const tripoint &examp ) const { + avatar &player_character = get_avatar(); map &here = get_map(); - const auto &tr = here.tr_at( examp ); - if( !p.is_player() || tr.is_null() ) { + + // If the player can't see the trap, they can't interact with it. + if( !can_see( examp, player_character ) ) { return; } - const int possible = tr.get_difficulty(); - bool seen = tr.can_see( examp, p ); - if( tr.loadid == tr_unfinished_construction || here.partial_con_at( examp ) ) { - partial_con *pc = here.partial_con_at( examp ); - if( pc ) { - if( g->u.fine_detail_vision_mod() > 4 && !g->u.has_trait( trait_DEBUG_HS ) ) { - add_msg( m_info, _( "It is too dark to construct right now." ) ); - return; - } - const construction &built = pc->id.obj(); - if( !query_yn( _( "Unfinished task: %s, %d%% complete here, continue construction?" ), - built.description, pc->counter / 100000 ) ) { - if( query_yn( _( "Cancel construction?" ) ) ) { - here.disarm_trap( examp ); - for( const item &it : pc->components ) { - here.add_item_or_charges( g->u.pos(), it ); - } - here.partial_con_remove( examp ); - return; - } else { - return; + + if( player_character.is_mounted() ) { + add_msg( m_warning, _( "You cannot do that while mounted." ) ); + return; + } + + if( partial_con *const pc = here.partial_con_at( examp ) ) { + if( player_character.fine_detail_vision_mod() > 4 && + !player_character.has_trait( trait_DEBUG_HS ) ) { + add_msg( m_info, _( "It is too dark to construct right now." ) ); + return; + } + const construction &built = pc->id.obj(); + if( !query_yn( _( "Unfinished task: %s, %d%% complete here, continue construction?" ), + built.description, pc->counter / 100000 ) ) { + if( query_yn( _( "Cancel construction?" ) ) ) { + on_disarmed( here, examp ); + for( const item &it : pc->components ) { + here.add_item_or_charges( player_character.pos(), it ); } - } else { - g->u.assign_activity( ACT_BUILD ); - g->u.activity.placement = here.getabs( examp ); - return; + here.partial_con_remove( examp ); } } else { - return; + player_character.assign_activity( ACT_BUILD ); + player_character.activity.placement = here.getabs( examp ); } + return; + } + if( can_not_be_disarmed() ) { + add_msg( m_info, _( "That %s looks too dangerous to mess with. Best leave it alone." ), name() ); + return; } - if( seen && possible >= 99 ) { - add_msg( m_info, _( "That %s looks too dangerous to mess with. Best leave it alone." ), - tr.name() ); + + // Some traps are not actual traps. Those should get a different query, no skill checks, and the option to grab it right away. + if( easy_take_down() ) { // Separated so saying no doesn't trigger the other query. + if( !query_yn( _( "There is a %s there. Take down?" ), name() ) ) { + return; + } + add_msg( _( "The %s is taken down." ), name() ); + on_disarmed( here, examp ); return; } - // Some traps are not actual traps. Those should get a different query. - if( seen && possible == 0 && - tr.get_avoidance() == 0 ) { // Separated so saying no doesn't trigger the other query. - if( query_yn( _( "There is a %s there. Take down?" ), tr.name() ) ) { - here.disarm_trap( examp ); + + if( query_yn( _( "There is a %s there. Disarm?" ), name() ) ) { + const int tSkillLevel = player_character.get_skill_level( skill_traps ); + int roll = rng( tSkillLevel, 4 * tSkillLevel ); + + ///\EFFECT_PER increases chance of disarming trap + + ///\EFFECT_DEX increases chance of disarming trap + + ///\EFFECT_TRAPS increases chance of disarming trap + while( ( rng( 5, 20 ) < player_character.per_cur || + rng( 1, 20 ) < player_character.dex_cur ) && roll < 50 ) { + roll++; } - } else if( seen && query_yn( _( "There is a %s there. Disarm?" ), tr.name() ) ) { - here.disarm_trap( examp ); + if( roll >= difficulty ) { + add_msg( _( "You disarm the trap!" ) ); + const int morale_buff = avoidance * 0.4 + difficulty + rng( 0, 4 ); + player_character.rem_morale( MORALE_FAILURE ); + player_character.add_morale( MORALE_ACCOMPLISHMENT, morale_buff, 40 ); + on_disarmed( here, examp ); + if( difficulty > 1.25 * tSkillLevel ) { // failure might have set off trap + player_character.practice( skill_traps, 1.5 * ( difficulty - tSkillLevel ) ); + } + } else if( roll >= difficulty * .8 ) { + add_msg( _( "You fail to disarm the trap." ) ); + const int morale_debuff = -rng( 6, 18 ); + player_character.rem_morale( MORALE_ACCOMPLISHMENT ); + player_character.add_morale( MORALE_FAILURE, morale_debuff, -40 ); + if( difficulty > 1.25 * tSkillLevel ) { + player_character.practice( skill_traps, 1.5 * ( difficulty - tSkillLevel ) ); + } + } else { + add_msg( m_bad, _( "You fail to disarm the trap, and you set it off!" ) ); + const int morale_debuff = -rng( 12, 24 ); + player_character.rem_morale( MORALE_ACCOMPLISHMENT ); + player_character.add_morale( MORALE_FAILURE, morale_debuff, -40 ); + trigger( examp, player_character ); + if( difficulty - roll <= 6 ) { + // Give xp for failing, but not if we failed terribly (in which + // case the trap may not be disarmable). + player_character.practice( skill_traps, 2 * difficulty ); + } + } + return; } } @@ -3801,11 +3856,12 @@ void iexamine::reload_furniture( player &p, const tripoint &examp ) if( amount_in_furn > 0 ) { if( p.query_yn( _( "The %1$s contains %2$d %3$s. Unload?" ), f.name(), amount_in_furn, ammo->nname( amount_in_furn ) ) ) { + Character &player_character = get_player_character(); map_stack items = here.i_at( examp ); for( auto &itm : items ) { if( itm.type == ammo ) { - g->u.assign_activity( player_activity( pickup_activity_actor( - { item_location( map_cursor( examp ), &itm ) }, { 0 }, g->u.pos() ) ) ); + player_character.assign_activity( player_activity( pickup_activity_actor( + { item_location( map_cursor( examp ), &itm ) }, { 0 }, player_character.pos() ) ) ); return; } } @@ -3987,14 +4043,14 @@ cata::optional iexamine::getNearFilledGasTank( const tripoint ¢er, map &here = get_map(); for( const tripoint &tmp : here.points_in_radius( center, SEEX * 2 ) ) { - auto checkingTerr = here.ter( tmp ); + auto check_for_fuel_tank = here.furn( tmp ); if( fuel_type == "gasoline" ) { - if( checkingTerr != ter_str_id( "t_gas_tank" ) ) { + if( check_for_fuel_tank != furn_str_id( "f_gas_tank" ) ) { continue; } } else if( fuel_type == "diesel" ) { - if( checkingTerr != ter_str_id( "t_diesel_tank" ) ) { + if( check_for_fuel_tank != furn_str_id( "f_diesel_tank" ) ) { continue; } } @@ -4055,7 +4111,7 @@ static int findBestGasDiscount( player &p ) static std::string str_to_illiterate_str( std::string s ) { - if( !g->u.has_trait( trait_ILLITERATE ) ) { + if( !get_player_character().has_trait( trait_ILLITERATE ) ) { return s; } else { for( auto &i : s ) { @@ -4553,12 +4609,13 @@ static player &best_installer( player &p, player &null_player, int difficulty ) return rhs.first < lhs.first; } ); int player_cos = bionic_success_chance( true, -1, difficulty, p ); + avatar &player_character = get_avatar(); for( size_t i = 0; i < g->allies().size() ; i ++ ) { if( ally_chances[ i ].first > player_cos ) { const npc *e = g->allies()[ ally_chances[ i ].second ]; player &ally = *g->critter_by_id( e->getID() ); if( e->has_effect( effect_sleep ) ) { - if( !g->u.query_yn( + if( !player_character.query_yn( //~ %1$s is the name of the ally _( "%1$s is asleep, but has a %2$d chance of success compared to your %3$d chance of success. Continue with a higher risk of failure?" ), ally.disp_name(), ally_chances[i].first, player_cos ) ) { @@ -4750,6 +4807,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) return; } + Character &player_character = get_player_character(); for( const bionic &bio : installed_bionics ) { if( bio.id != bio_power_storage || bio.id != bio_power_storage_mkII ) { @@ -4761,14 +4819,14 @@ void iexamine::autodoc( player &p, const tripoint &examp ) // TODO: refactor this whole bit. adding items to the inventory will // cause major issues when inv gets removed. this is a shim for now // in order to reduce lines of change for nested containers. - g->u.inv.push_back( bionic_to_uninstall ); + player_character.inv.push_back( bionic_to_uninstall ); } } } const item_location bionic = game_menus::inv::uninstall_bionic( p, patient ); if( !bionic ) { - g->u.remove_items_with( []( const item & it ) {// remove cbm items from inventory + player_character.remove_items_with( []( const item & it ) {// remove cbm items from inventory return it.has_flag( flag_IN_CBM ); } ); return; @@ -4777,7 +4835,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) const itype *itemtype = it->type; const bionic_id &bid = itemtype->bionic->id; - g->u.remove_items_with( []( const item & it ) {// remove cbm items from inventory + player_character.remove_items_with( []( const item & it ) {// remove cbm items from inventory return it.has_flag( flag_IN_CBM ); } ); @@ -4804,8 +4862,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) case BONESETTING: { int broken_limbs_count = 0; - for( int i = 0; i < num_hp_parts; i++ ) { - const bodypart_id &part = convert_bp( player::hp_to_bp( static_cast( i ) ) ).id(); + for( const bodypart_id &part : patient.get_all_body_parts( true ) ) { const bool broken = patient.is_limb_broken( part ); effect &existing_effect = patient.get_effect( effect_mending, part->token ); // Skip part if not broken or already healed 50% @@ -4822,9 +4879,9 @@ void iexamine::autodoc( player &p, const tripoint &examp ) // TODO: fail here if unable to perform the action, i.e. can't wear more, trait mismatch. if( !patient.worn_with_flag( flag_SPLINT, part ) ) { item splint; - if( i == hp_arm_l || i == hp_arm_r ) { + if( part == bodypart_id( "arm_l" ) || part == bodypart_id( "arm_r" ) ) { splint = item( "arm_splint", 0 ); - } else if( i == hp_leg_l || i == hp_leg_r ) { + } else if( part == bodypart_id( "leg_l" ) || part == bodypart_id( "leg_r" ) ) { splint = item( "leg_splint", 0 ); } item &equipped_splint = patient.i_add( splint ); @@ -4897,9 +4954,8 @@ void iexamine::autodoc( player &p, const tripoint &examp ) patient.add_effect( effect_disinfected, 1_turns, bp_healed->token ); effect &e = patient.get_effect( effect_disinfected, bp_healed->token ); e.set_duration( e.get_int_dur_factor() * disinfectant_intensity ); - hp_part target_part = player::bp_to_hp( bp_healed->token ); - patient.damage_disinfected[target_part] = patient.get_part_hp_max( bp_healed ) - - patient.get_part_hp_cur( bp_healed ); + patient.set_part_damage_disinfected( bp_healed, + patient.get_part_hp_max( bp_healed ) - patient.get_part_hp_cur( bp_healed ) ); } } patient.moves -= 500; @@ -5286,8 +5342,9 @@ static void smoker_load_food( player &p, const tripoint &examp, comps.clear(); comps.push_back( item_comp( what->typeId(), amount ) ); + Character &player_character = get_player_character(); // select from where to get the items from and place them - inv.form_from_map( g->u.pos(), PICKUP_RANGE, &g->u ); + inv.form_from_map( player_character.pos(), PICKUP_RANGE, &player_character ); inv.remove_items_with( []( const item & it ) { return it.rotten(); } ); @@ -5394,8 +5451,9 @@ static void mill_load_food( player &p, const tripoint &examp, comps.clear(); comps.push_back( item_comp( what->typeId(), amount ) ); + Character &player_character = get_player_character(); // select from where to get the items from and place them - inv.form_from_map( g->u.pos(), PICKUP_RANGE, &g->u ); + inv.form_from_map( player_character.pos(), PICKUP_RANGE, &player_character ); inv.remove_items_with( []( const item & it ) { return it.rotten(); } ); @@ -5417,7 +5475,7 @@ void iexamine::on_smoke_out( const tripoint &examp, const time_point &start_time map &here = get_map(); if( here.furn( examp ) == furn_str_id( "f_smoking_rack_active" ) || here.furn( examp ) == furn_str_id( "f_metal_smoking_rack_active" ) ) { - smoker_finalize( g->u, examp, start_time ); + smoker_finalize( get_avatar(), examp, start_time ); } } @@ -5953,6 +6011,15 @@ void iexamine::workbench_internal( player &p, const tripoint &examp, } } +void iexamine::workout( player &p, const tripoint &examp ) +{ + if( !query_yn( _( "Use the %s to exercise?" ), get_map().furnname( examp ) ) ) { + none( p, examp ); + return; + } + p.assign_activity( player_activity( workout_activity_actor( examp ) ) ); +} + /** * Given then name of one of the above functions, returns the matching function * pointer. If no match is found, defaults to iexamine::none but prints out a @@ -6017,7 +6084,6 @@ iexamine_function iexamine_function_from_string( const std::string &function_nam { "tree_maple_tapped", &iexamine::tree_maple_tapped }, { "shrub_wildveggies", &iexamine::shrub_wildveggies }, { "recycle_compactor", &iexamine::recycle_compactor }, - { "trap", &iexamine::trap }, { "water_source", &iexamine::water_source }, { "clean_water_source", &iexamine::clean_water_source }, { "reload_furniture", &iexamine::reload_furniture }, @@ -6039,7 +6105,8 @@ iexamine_function iexamine_function_from_string( const std::string &function_nam { "quern_examine", &iexamine::quern_examine }, { "smoker_options", &iexamine::smoker_options }, { "open_safe", &iexamine::open_safe }, - { "workbench", &iexamine::workbench } + { "workbench", &iexamine::workbench }, + { "workout", &iexamine::workout } } }; diff --git a/src/iexamine.h b/src/iexamine.h index 9e4b2e2ca4c33..2c59f1743d7f0 100644 --- a/src/iexamine.h +++ b/src/iexamine.h @@ -82,7 +82,6 @@ void shrub_marloss( player &p, const tripoint &examp ); void tree_marloss( player &p, const tripoint &examp ); void shrub_wildveggies( player &p, const tripoint &examp ); void recycle_compactor( player &p, const tripoint &examp ); -void trap( player &p, const tripoint &examp ); void water_source( player &p, const tripoint &examp ); void clean_water_source( player &, const tripoint &examp ); void kiln_empty( player &p, const tripoint &examp ); @@ -111,6 +110,7 @@ void open_safe( player &p, const tripoint &examp ); void workbench( player &p, const tripoint &examp ); void workbench_internal( player &p, const tripoint &examp, const cata::optional &part ); +void workout( player &p, const tripoint &examp ); bool pour_into_keg( const tripoint &pos, item &liquid ); cata::optional getGasPumpByNumber( const tripoint &p, int number ); diff --git a/src/init.cpp b/src/init.cpp index 20132236b1e48..22d0846f93365 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -69,6 +69,7 @@ #include "overmap_connection.h" #include "overmap_location.h" #include "profession.h" +#include "proficiency.h" #include "recipe_dictionary.h" #include "recipe_groups.h" #include "regional_settings.h" @@ -90,6 +91,8 @@ #include "veh_type.h" #include "vehicle_group.h" #include "vitamin.h" +#include "weather.h" +#include "weather_type.h" #include "worldfactory.h" DynamicDataLoader::DynamicDataLoader() @@ -201,7 +204,9 @@ void DynamicDataLoader::initialize() add( "EXTERNAL_OPTION", &load_external_option ); add( "json_flag", &json_flag::load ); add( "fault", &fault::load_fault ); + add( "relic_procgen_data", &relic_procgen_data::load_relic_procgen_data ); add( "field_type", &field_types::load ); + add( "weather_type", &weather_types::load ); add( "ammo_effect", &ammo_effects::load ); add( "emit", &emit::load_emit ); add( "activity_type", &activity_type::load ); @@ -211,6 +216,7 @@ void DynamicDataLoader::initialize() add( "bionic", &bionic_data::load_bionic ); add( "profession", &profession::load_profession ); add( "profession_item_substitutions", &profession::load_item_substitutions ); + add( "proficiency", &proficiency::load_proficiencies ); add( "skill", &Skill::load_skill ); add( "skill_display_type", &SkillDisplayType::load ); add( "dream", &dream::load ); @@ -520,6 +526,7 @@ void DynamicDataLoader::unload_data() overmap_specials::reset(); overmap_terrains::reset(); profession::reset(); + proficiency::reset(); quality::reset(); reset_monster_adjustment(); recipe_dictionary::reset(); @@ -553,6 +560,7 @@ void DynamicDataLoader::unload_data() vehicle_prototype::reset(); vitamin::reset(); vpart_info::reset(); + weather_types::reset(); } void DynamicDataLoader::finalize_loaded_data() @@ -571,6 +579,7 @@ void DynamicDataLoader::finalize_loaded_data( loading_ui &ui ) using named_entry = std::pair>; const std::vector entries = {{ { _( "Body parts" ), &body_part_type::finalize_all }, + { _( "Weather types" ), &weather_types::finalize_all }, { _( "Field types" ), &field_types::finalize_all }, { _( "Ammo effects" ), &ammo_effects::finalize_all }, { _( "Emissions" ), &emit::finalize }, @@ -653,6 +662,7 @@ void DynamicDataLoader::check_consistency( loading_ui &ui ) } }, { _( "Vitamins" ), &vitamin::check_consistency }, + { _( "Weather types" ), &weather_types::check_consistency }, { _( "Field types" ), &field_types::check_consistency }, { _( "Ammo effects" ), &ammo_effects::check_consistency }, { _( "Emissions" ), &emit::check_consistency }, diff --git a/src/inventory.cpp b/src/inventory.cpp index 8baac97a3e809..9723c37d4564a 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -261,6 +261,7 @@ void inventory::update_cache_with_item( item &newit ) char inventory::find_usable_cached_invlet( const itype_id &item_type ) { + Character &player_character = get_player_character(); // Some of our preferred letters might already be used. for( auto invlet : invlet_cache.invlets_for( item_type ) ) { // Don't overwrite user assignments. @@ -268,7 +269,7 @@ char inventory::find_usable_cached_invlet( const itype_id &item_type ) continue; } // Check if anything is using this invlet. - if( g->u.invlet_to_item( invlet ) != nullptr ) { + if( player_character.invlet_to_item( invlet ) != nullptr ) { continue; } return invlet; @@ -281,6 +282,7 @@ item &inventory::add_item( item newit, bool keep_invlet, bool assign_invlet, boo { binned = false; + Character &player_character = get_player_character(); if( should_stack ) { // See if we can't stack this item. for( auto &elem : items ) { @@ -302,7 +304,7 @@ item &inventory::add_item( item newit, bool keep_invlet, bool assign_invlet, boo return elem.back(); } else if( keep_invlet && assign_invlet && it_ref->invlet == newit.invlet ) { // If keep_invlet is true, we'll be forcing other items out of their current invlet. - assign_empty_invlet( *it_ref, g->u ); + assign_empty_invlet( *it_ref, player_character ); } } } @@ -333,7 +335,7 @@ void inventory::push_back( item newit ) extern void remove_stale_inventory_quick_shortcuts(); #endif -void inventory::restack( player &p ) +void inventory::restack( Character &p ) { // tasks that the old restack seemed to do: // 1. reassign inventory letters @@ -410,7 +412,7 @@ void inventory::form_from_map( const tripoint &origin, int range, const Characte bool assign_invlet, bool clear_path ) { - form_from_map( g->m, origin, range, pl, assign_invlet, clear_path ); + form_from_map( get_map(), origin, range, pl, assign_invlet, clear_path ); } void inventory::form_from_zone( map &m, std::unordered_set &zone_pts, const Character *pl, @@ -434,7 +436,7 @@ void inventory::form_from_map( map &m, const tripoint &origin, int range, const m.reachable_flood_steps( reachable_pts, origin, range, 1, 100 ); } else { // Fill reachable points with points_in_radius - tripoint_range in_radius = m.points_in_radius( origin, range ); + tripoint_range in_radius = m.points_in_radius( origin, range ); for( const tripoint &p : in_radius ) { reachable_pts.emplace_back( p ); } @@ -877,6 +879,8 @@ item *inventory::most_appropriate_painkiller( int pain ) void inventory::rust_iron_items() { + Character &player_character = get_player_character(); + map &here = get_map(); for( auto &elem : items ) { for( auto &elem_stack_iter : elem ) { if( elem_stack_iter.made_of( material_id( "iron" ) ) && @@ -894,7 +898,7 @@ void inventory::rust_iron_items() elem_stack_iter.base_volume().value() ) / 250 ) ) ) ) && // ^season length ^14/5*0.75/pi (from volume of sphere) //Freshwater without oxygen rusts slower than air - g->m.water_from( g->u.pos() ).typeId() == itype_salt_water ) { + here.water_from( player_character.pos() ).typeId() == itype_salt_water ) { elem_stack_iter.inc_damage( DT_ACID ); // rusting never completely destroys an item add_msg( m_bad, _( "Your %s is damaged by rust." ), elem_stack_iter.tname() ); } @@ -1040,8 +1044,7 @@ void inventory::assign_empty_invlet( item &it, const Character &p, const bool fo if( cur_inv.count() < inv_chars.size() ) { // XXX YUCK I don't know how else to get the keybindings // FIXME: Find a better way to get bound keys - avatar &u = g->u; - inventory_selector selector( u ); + inventory_selector selector( get_avatar() ); for( const auto &inv_char : inv_chars ) { if( assigned_invlet.count( inv_char ) ) { @@ -1101,11 +1104,12 @@ void inventory::update_invlet( item &newit, bool assign_invlet ) } } + Character &player_character = get_player_character(); // Remove letters that have been assigned to other items in the inventory if( newit.invlet ) { char tmp_invlet = newit.invlet; newit.invlet = '\0'; - if( g->u.invlet_to_item( tmp_invlet ) == nullptr ) { + if( player_character.invlet_to_item( tmp_invlet ) == nullptr ) { newit.invlet = tmp_invlet; } } @@ -1118,7 +1122,7 @@ void inventory::update_invlet( item &newit, bool assign_invlet ) // Give the item an invlet if it has none if( !newit.invlet ) { - assign_empty_invlet( newit, g->u ); + assign_empty_invlet( newit, player_character ); } } } diff --git a/src/inventory.h b/src/inventory.h index 0b935752c3ee3..aa005773ae257 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -124,7 +124,7 @@ class inventory : public visitable * game pointer is not necessary, but if supplied, will ensure no overlap with * the player's worn items / weapon */ - void restack( player &p ); + void restack( Character &p ); void form_from_zone( map &m, std::unordered_set &zone_pts, const Character *pl = nullptr, bool assign_invlet = true ); void form_from_map( const tripoint &origin, int range, const Character *pl = nullptr, diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index eb98670ff40df..38c4105806d3d 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -1,12 +1,10 @@ #include "inventory_ui.h" -#include "avatar.h" #include "cata_utility.h" #include "catacharset.h" #include "character.h" #include "colony.h" #include "debug.h" -#include "game.h" #include "ime.h" #include "inventory.h" #include "item.h" @@ -18,7 +16,6 @@ #include "optional.h" #include "options.h" #include "output.h" -#include "player.h" #include "point.h" #include "string_formatter.h" #include "string_id.h" @@ -114,10 +111,11 @@ class selection_column_preset : public inventory_selector_preset } nc_color get_color( const inventory_entry &entry ) const override { + Character &player_character = get_player_character(); if( entry.is_item() ) { - if( &*entry.any_item() == &g->u.weapon ) { + if( &*entry.any_item() == &player_character.weapon ) { return c_light_blue; - } else if( g->u.is_worn( *entry.any_item() ) ) { + } else if( player_character.is_worn( *entry.any_item() ) ) { return c_cyan; } } @@ -171,7 +169,7 @@ nc_color inventory_entry::get_invlet_color() const { if( !is_selectable() ) { return c_dark_gray; - } else if( g->u.inv.assigned_invlet.count( get_invlet() ) ) { + } else if( get_player_character().inv.assigned_invlet.count( get_invlet() ) ) { return c_yellow; } else { return c_white; @@ -232,9 +230,10 @@ inventory_selector_preset::inventory_selector_preset() bool inventory_selector_preset::sort_compare( const inventory_entry &lhs, const inventory_entry &rhs ) const { + Character &player_character = get_player_character(); // Place items with an assigned inventory letter first, since the player cared enough to assign them - const bool left_fav = g->u.inv.assigned_invlet.count( lhs.any_item()->invlet ); - const bool right_fav = g->u.inv.assigned_invlet.count( rhs.any_item()->invlet ); + const bool left_fav = player_character.inv.assigned_invlet.count( lhs.any_item()->invlet ); + const bool right_fav = player_character.inv.assigned_invlet.count( rhs.any_item()->invlet ); if( left_fav == right_fav ) { return lhs.cached_name.compare( rhs.cached_name ) < 0; // Simple alphabetic order } else if( left_fav ) { @@ -576,7 +575,7 @@ size_t inventory_column::page_of( const inventory_entry &entry ) const } bool inventory_column::has_available_choices() const { - if( !allows_selecting() ) { + if( !allows_selecting() || !activatable() ) { return false; } for( size_t i = 0; i < entries.size(); ++i ) { @@ -637,17 +636,21 @@ void inventory_column::set_stack_favorite( const item_location &location, bool f { const item *selected_item = location.get_item(); std::list to_favorite; + map &here = get_map(); + Character &player_character = get_player_character(); if( location.where() == item_location::type::character ) { - int position = g->u.get_item_position( selected_item ); + int position = player_character.get_item_position( selected_item ); if( position < 0 ) { - g->u.i_at( position ).set_favorite( !selected_item->is_favorite ); // worn/wielded + // worn/wielded + player_character.i_at( position ).set_favorite( !selected_item->is_favorite ); } else { - g->u.inv.set_stack_favorite( position, !selected_item->is_favorite ); // in inventory + // in inventory + player_character.inv.set_stack_favorite( position, !selected_item->is_favorite ); } } else if( location.where() == item_location::type::map ) { - map_stack items = g->m.i_at( location.position() ); + map_stack items = here.i_at( location.position() ); for( auto &item : items ) { if( item.stacks_with( *selected_item ) ) { @@ -658,7 +661,7 @@ void inventory_column::set_stack_favorite( const item_location &location, bool f item->set_favorite( favorite ); } } else if( location.where() == item_location::type::vehicle ) { - const cata::optional vp = g->m.veh_at( + const cata::optional vp = here.veh_at( location.position() ).part_with_feature( "CARGO", true ); assert( vp ); @@ -910,13 +913,13 @@ size_t inventory_column::get_entry_indent( const inventory_entry &entry ) const if( get_option( "ITEM_SYMBOLS" ) ) { res += 2; } - if( allows_selecting() && multiselect ) { + if( allows_selecting() && activatable() && multiselect ) { res += 2; } return res; } -int inventory_column::reassign_custom_invlets( const player &p, int min_invlet, int max_invlet ) +int inventory_column::reassign_custom_invlets( const Character &p, int min_invlet, int max_invlet ) { int cur_invlet = min_invlet; for( auto &elem : entries ) { @@ -1048,7 +1051,7 @@ void inventory_column::draw( const catacurses::window &win, const point &p ) mvwputch( win, point( xx, yy ), color, entry.any_item()->symbol() ); xx += 2; } - if( allows_selecting() && multiselect ) { + if( allows_selecting() && activatable() && multiselect ) { if( entry.chosen_count == 0 ) { mvwputch( win, point( xx, yy ), c_dark_gray, '-' ); } else if( entry.chosen_count >= entry.get_available_count() ) { @@ -1287,10 +1290,14 @@ void inventory_selector::add_contained_items( item_location &container ) void inventory_selector::add_contained_items( item_location &container, inventory_column &column ) { + if( container->has_flag( "NO_UNLOAD" ) ) { + return; + } + for( item *it : container->contents.all_items_top() ) { item_location child( container, it ); add_contained_items( child, column ); - add_item( column, std::move( child ) ); + add_entry( column, std::vector( 1, child ) ); } } @@ -1324,9 +1331,10 @@ void inventory_selector::add_character_items( Character &character ) void inventory_selector::add_map_items( const tripoint &target ) { - if( g->m.accessible_items( target ) ) { - map_stack items = g->m.i_at( target ); - const std::string name = to_upper_case( g->m.name( target ) ); + map &here = get_map(); + if( here.accessible_items( target ) ) { + map_stack items = here.i_at( target ); + const std::string name = to_upper_case( here.name( target ) ); const item_category map_cat( name, no_translation( name ), 100 ); add_items( map_column, [ &target ]( item * it ) { @@ -1342,7 +1350,8 @@ void inventory_selector::add_map_items( const tripoint &target ) void inventory_selector::add_vehicle_items( const tripoint &target ) { - const cata::optional vp = g->m.veh_at( target ).part_with_feature( "CARGO", true ); + const cata::optional vp = + get_map().veh_at( target ).part_with_feature( "CARGO", true ); if( !vp ) { return; } @@ -1367,9 +1376,10 @@ void inventory_selector::add_vehicle_items( const tripoint &target ) void inventory_selector::add_nearby_items( int radius ) { if( radius >= 0 ) { - for( const tripoint &pos : closest_tripoints_first( u.pos(), radius ) ) { + map &here = get_map(); + for( const tripoint &pos : closest_points_first( u.pos(), radius ) ) { // can not reach this -> can not access its contents - if( u.pos() != pos && !g->m.clear_path( u.pos(), pos, rl_dist( u.pos(), pos ), 1, 100 ) ) { + if( u.pos() != pos && !here.clear_path( u.pos(), pos, rl_dist( u.pos(), pos ), 1, 100 ) ) { continue; } add_map_items( pos ); @@ -1828,7 +1838,7 @@ void inventory_selector::draw_footer( const catacurses::window &w ) const } } -inventory_selector::inventory_selector( player &u, const inventory_selector_preset &preset ) +inventory_selector::inventory_selector( Character &u, const inventory_selector_preset &preset ) : u( u ) , preset( preset ) , ctxt( "INVENTORY" ) @@ -2125,7 +2135,7 @@ item_location inventory_pick_selector::execute() } } -inventory_multiselector::inventory_multiselector( player &p, +inventory_multiselector::inventory_multiselector( Character &p, const inventory_selector_preset &preset, const std::string &selection_column_title ) : inventory_selector( p, preset ), @@ -2147,7 +2157,7 @@ void inventory_multiselector::rearrange_columns( size_t client_width ) selection_col->set_visibility( !is_overflown( client_width ) ); } -inventory_compare_selector::inventory_compare_selector( player &p ) : +inventory_compare_selector::inventory_compare_selector( Character &p ) : inventory_multiselector( p, default_preset, _( "ITEMS TO COMPARE" ) ) {} std::pair inventory_compare_selector::execute() @@ -2218,7 +2228,7 @@ void inventory_compare_selector::toggle_entry( inventory_entry *entry ) } inventory_iuse_selector::inventory_iuse_selector( - player &p, + Character &p, const std::string &selector_title, const inventory_selector_preset &preset, const GetStats &get_st @@ -2282,12 +2292,10 @@ drop_locations inventory_iuse_selector::execute() count = 0; } } - drop_locations dropped_pos_and_qty; - for( const std::pair &use_pair : to_use ) { - item_location loc( u, const_cast( use_pair.first ) ); - dropped_pos_and_qty.push_back( std::make_pair( loc, use_pair.second ) ); + for( const std::pair &use_pair : to_use ) { + dropped_pos_and_qty.push_back( std::make_pair( *use_pair.first, use_pair.second ) ); } return dropped_pos_and_qty; @@ -2295,17 +2303,26 @@ drop_locations inventory_iuse_selector::execute() void inventory_iuse_selector::set_chosen_count( inventory_entry &entry, size_t count ) { - const item *it = &*entry.any_item(); + const item_location &it = entry.any_item(); if( count == 0 ) { entry.chosen_count = 0; - const auto iter = to_use.find( it ); - if( iter != to_use.end() ) { - to_use.erase( iter ); + for( const item_location &loc : entry.locations ) { + to_use.erase( &loc ); } } else { entry.chosen_count = std::min( std::min( count, max_chosen_count ), entry.get_available_count() ); - to_use[it] = entry.chosen_count; + if( it->count_by_charges() ) { + to_use[&it] = entry.chosen_count; + } else { + for( const item_location &loc : entry.locations ) { + if( count == 0 ) { + break; + } + to_use[&loc] = 1; + count--; + } + } } on_change( entry ); @@ -2319,7 +2336,7 @@ inventory_selector::stats inventory_iuse_selector::get_raw_stats() const return stats{{ stat{{ "", "", "", "" }}, stat{{ "", "", "", "" }} }}; } -inventory_drop_selector::inventory_drop_selector( player &p, +inventory_drop_selector::inventory_drop_selector( Character &p, const inventory_selector_preset &preset, const std::string &selection_column_title ) : inventory_multiselector( p, preset, selection_column_title ), max_chosen_count( std::numeric_limits::max() ) @@ -2371,7 +2388,7 @@ void inventory_drop_selector::deselect_contained_items() if( !selected->is_item() ) { continue; } - for( item_location selected_loc : selected->locations ) { + for( const item_location &selected_loc : selected->locations ) { if( selected_loc == loc_contained ) { set_chosen_count( *selected, 0 ); } @@ -2416,11 +2433,12 @@ drop_locations inventory_drop_selector::execute() const auto filter_to_nonfavorite_and_nonworn = []( const inventory_entry & entry ) { return entry.is_item() && !entry.any_item()->is_favorite && - !g->u.is_worn( *entry.any_item() ); + !get_player_character().is_worn( *entry.any_item() ); }; const auto selected( get_active_column().get_entries( filter_to_nonfavorite_and_nonworn ) ); process_selected( count, selected ); + deselect_contained_items(); } else if( input.action == "RIGHT" ) { const auto selected( get_active_column().get_all_selected() ); @@ -2525,5 +2543,5 @@ inventory_selector::stats inventory_drop_selector::get_raw_stats() const u.weight_carried_with_tweaks( dropping ), u.weight_capacity(), u.volume_carried_with_tweaks( dropping ), - u.volume_capacity() ); + u.volume_capacity_with_tweaks( dropping ) ); } diff --git a/src/inventory_ui.h b/src/inventory_ui.h index 70c2808689d1d..5fb8397915964 100644 --- a/src/inventory_ui.h +++ b/src/inventory_ui.h @@ -27,7 +27,6 @@ class Character; class item; -class player; class string_input_popup; struct tripoint; class ui_adaptor; @@ -257,6 +256,7 @@ class inventory_column /** * Can this column be activated? * @return Whether the column contains selectable entries. + * Note: independent from 'allows_selecting' */ virtual bool activatable() const; /** Is this column visible? */ @@ -266,9 +266,10 @@ class inventory_column /** * Does this column allow selecting? * "Cosmetic" columns (list of selected items) can explicitly prohibit selecting. + * Note: independent from 'activatable' */ virtual bool allows_selecting() const { - return activatable(); + return true; } size_t page_index() const { @@ -336,7 +337,7 @@ class inventory_column /** Resets width to original (unchanged). */ virtual void reset_width( const std::vector &all_columns ); /** Returns next custom inventory letter. */ - int reassign_custom_invlets( const player &p, int min_invlet, int max_invlet ); + int reassign_custom_invlets( const Character &p, int min_invlet, int max_invlet ); /** Reorder entries, repopulate titles, adjust to the new height. */ virtual void prepare_paging( const std::string &filter = "" ); /** @@ -479,7 +480,7 @@ class selection_column : public inventory_column class inventory_selector { public: - inventory_selector( player &u, const inventory_selector_preset &preset = default_preset ); + inventory_selector( Character &u, const inventory_selector_preset &preset = default_preset ); virtual ~inventory_selector(); /** These functions add items from map / vehicles. */ void add_contained_items( item_location &container ); @@ -519,7 +520,7 @@ class inventory_selector bool keep_open = false; protected: - player &u; + Character &u; const inventory_selector_preset &preset; /** @@ -698,7 +699,7 @@ inventory_selector::stat display_stat( const std::string &caption, int cur_value class inventory_pick_selector : public inventory_selector { public: - inventory_pick_selector( player &p, + inventory_pick_selector( Character &p, const inventory_selector_preset &preset = default_preset ) : inventory_selector( p, preset ) {} @@ -708,7 +709,7 @@ class inventory_pick_selector : public inventory_selector class inventory_multiselector : public inventory_selector { public: - inventory_multiselector( player &p, const inventory_selector_preset &preset = default_preset, + inventory_multiselector( Character &p, const inventory_selector_preset &preset = default_preset, const std::string &selection_column_title = "" ); protected: void rearrange_columns( size_t client_width ) override; @@ -720,7 +721,7 @@ class inventory_multiselector : public inventory_selector class inventory_compare_selector : public inventory_multiselector { public: - inventory_compare_selector( player &p ); + inventory_compare_selector( Character &p ); std::pair execute(); protected: @@ -734,8 +735,8 @@ class inventory_compare_selector : public inventory_multiselector class inventory_iuse_selector : public inventory_multiselector { public: - using GetStats = std::function & )>; - inventory_iuse_selector( player &p, + using GetStats = std::function & )>; + inventory_iuse_selector( Character &p, const std::string &selector_title, const inventory_selector_preset &preset = default_preset, const GetStats & = {} ); @@ -747,14 +748,14 @@ class inventory_iuse_selector : public inventory_multiselector private: GetStats get_stats; - std::map to_use; + std::map to_use; size_t max_chosen_count; }; class inventory_drop_selector : public inventory_multiselector { public: - inventory_drop_selector( player &p, + inventory_drop_selector( Character &p, const inventory_selector_preset &preset = default_preset, const std::string &selection_column_title = _( "ITEMS TO DROP" ) ); drop_locations execute(); @@ -769,4 +770,6 @@ class inventory_drop_selector : public inventory_multiselector std::vector> dropping; size_t max_chosen_count; }; + + #endif // CATA_SRC_INVENTORY_UI_H diff --git a/src/item.cpp b/src/item.cpp index ea1169e61133b..9b6de1d7f0362 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -102,11 +102,13 @@ static const ammotype ammo_plutonium( "plutonium" ); static const item_category_id item_category_drugs( "drugs" ); static const item_category_id item_category_food( "food" ); static const item_category_id item_category_maps( "maps" ); +static const item_category_id item_category_container( "container" ); static const efftype_id effect_cig( "cig" ); static const efftype_id effect_shakes( "shakes" ); static const efftype_id effect_sleep( "sleep" ); static const efftype_id effect_weed_high( "weed_high" ); +static const efftype_id effect_bleed( "bleed" ); static const fault_id fault_gun_blackpowder( "fault_gun_blackpowder" ); @@ -250,6 +252,7 @@ static const std::string flag_SKINTIGHT( "SKINTIGHT" ); static const std::string flag_SLOW_WIELD( "SLOW_WIELD" ); static const std::string flag_SPEEDLOADER( "SPEEDLOADER" ); static const std::string flag_SPLINT( "SPLINT" ); +static const std::string flag_TOURNIQUET( "TOURNIQUET" ); static const std::string flag_STR_DRAW( "STR_DRAW" ); static const std::string flag_TOBACCO( "TOBACCO" ); static const std::string flag_UNARMED_WEAPON( "UNARMED_WEAPON" ); @@ -562,7 +565,7 @@ item &item::activate() bool item::activate_thrown( const tripoint &pos ) { - return type->invoke( g->u, *this, pos ); + return type->invoke( get_avatar(), *this, pos ); } units::energy item::set_energy( const units::energy &qty ) @@ -586,12 +589,15 @@ units::energy item::set_energy( const units::energy &qty ) item &item::ammo_set( const itype_id &ammo, int qty ) { if( !ammo->ammo ) { - debugmsg( "can't set ammo %s in %s as it is not an ammo", ammo.c_str(), type_name() ); + if( !has_flag( flag_USES_BIONIC_POWER ) ) { + debugmsg( "can't set ammo %s in %s as it is not an ammo", ammo.c_str(), type_name() ); + } return *this; } const ammotype &ammo_type = ammo->ammo->type; if( qty < 0 ) { // completely fill an integral or existing magazine + //if( magazine_current() ) then we need capacity of the magazine instead of the item maybe? if( magazine_integral() || magazine_current() ) { qty = ammo_capacity( ammo_type ); @@ -628,7 +634,8 @@ item &item::ammo_set( const itype_id &ammo, int qty ) // check ammo is valid for the item const itype *atype = item_controller->find_template( ammo ); if( atype->ammo && ammo_types().count( atype->ammo->type ) == 0 && - !magazine_compatible().count( atype->get_id() ) ) { + !magazine_compatible().count( atype->get_id() ) && !( magazine_current() && + magazine_current()->ammo_types().count( atype->ammo->type ) ) ) { debugmsg( "Tried to set invalid ammo of %s for %s", atype->nname( qty ), tname() ); return *this; } @@ -779,8 +786,12 @@ body_part_set item::get_covered_body_parts( const side s ) const if( armor == nullptr ) { return res; } + for( const armor_portion_data &data : armor->data ) { + if( data.covers.has_value() ) { + res.unify_set( data.covers.value() ); + } + } - res.unify_set( armor->covers ); if( !armor->sided ) { return res; // Just ignore the side. @@ -877,6 +888,36 @@ item item::in_container( const itype_id &cont, int qty ) const return *this; } +void item::update_modified_pockets() +{ + cata::optional mag_or_mag_well; + std::vector container_pockets; + + for( const pocket_data &pocket : type->pockets ) { + if( pocket.type == item_pocket::pocket_type::CONTAINER ) { + container_pockets.push_back( &pocket ); + } else if( pocket.type == item_pocket::pocket_type::MAGAZINE || + pocket.type == item_pocket::pocket_type::MAGAZINE_WELL ) { + mag_or_mag_well = &pocket; + } + } + + for( const item *mod : mods() ) { + if( mod->type->mod ) { + for( const pocket_data &pocket : mod->type->mod->add_pockets ) { + if( pocket.type == item_pocket::pocket_type::CONTAINER ) { + container_pockets.push_back( &pocket ); + } else if( pocket.type == item_pocket::pocket_type::MAGAZINE || + pocket.type == item_pocket::pocket_type::MAGAZINE_WELL ) { + mag_or_mag_well = &pocket; + } + } + } + } + + contents.update_modified_pockets( mag_or_mag_well, container_pockets ); +} + int item::charges_per_volume( const units::volume &vol ) const { if( count_by_charges() ) { @@ -1026,10 +1067,14 @@ bool item::merge_charges( const item &rhs ) return true; } -void item::put_in( const item &payload, item_pocket::pocket_type pk_type ) +ret_val item::put_in( const item &payload, item_pocket::pocket_type pk_type ) { - contents.insert_item( payload, pk_type ); + ret_val result = contents.insert_item( payload, pk_type ); + if( pk_type == item_pocket::pocket_type::MOD ) { + update_modified_pockets(); + } on_contents_changed(); + return result; } void item::set_var( const std::string &name, const int value ) @@ -1165,9 +1210,10 @@ static std::string get_freshness_description( const item &food_item ) time_left = shelf_life; } + Character &player_character = get_player_character(); if( food_item.is_fresh() ) { // Fresh food is assumed to be obviously so regardless of skill. - if( g->u.can_estimate_rot() ) { + if( player_character.can_estimate_rot() ) { return string_format( _( "* This food looks as fresh as it can be. " "It still has %s until it spoils." ), to_string_approx( time_left ) ); @@ -1176,7 +1222,7 @@ static std::string get_freshness_description( const item &food_item ) } } else if( food_item.is_going_bad() ) { // Old food likewise is assumed to be fairly obvious. - if( g->u.can_estimate_rot() ) { + if( player_character.can_estimate_rot() ) { return string_format( _( "* This food looks old. " "It's just %s from becoming inedible." ), to_string_approx( time_left ) ); @@ -1186,7 +1232,7 @@ static std::string get_freshness_description( const item &food_item ) } } - if( !g->u.can_estimate_rot() ) { + if( !player_character.can_estimate_rot() ) { // Unskilled characters only get a hint that more information exists... return _( "* This food looks fine. If you were more skilled in " "cooking or survival, you might be able to make a better estimation." ); @@ -1216,9 +1262,21 @@ static std::string get_freshness_description( const item &food_item ) } } -item::sizing item::get_sizing( const Character &p, bool wearable ) const +item::sizing item::get_sizing( const Character &p ) const { - if( wearable ) { + const islot_armor *armor_data = find_armor_data(); + if( !armor_data ) { + return sizing::ignore; + } + bool to_ignore = true; + for( const armor_portion_data &piece : armor_data->data ) { + if( piece.encumber != 0 ) { + to_ignore = false; + } + } + if( to_ignore ) { + return sizing::ignore; + } else { const bool small = p.has_trait( trait_SMALL2 ) || p.has_trait( trait_SMALL_OK ); @@ -1258,8 +1316,6 @@ item::sizing item::get_sizing( const Character &p, bool wearable ) const } } } - return sizing::not_wearable; - } static int get_base_env_resist( const item &it ) @@ -1371,7 +1427,7 @@ double item::effective_dps( const player &guy, monster &mon ) const { const float mon_dodge = mon.get_dodge(); float base_hit = guy.get_dex() / 4.0f + guy.get_hit_weapon( *this ); - base_hit *= std::max( 0.25f, 1.0f - guy.encumb( bp_torso ) / 100.0f ); + base_hit *= std::max( 0.25f, 1.0f - guy.encumb( bodypart_id( "torso" ) ) / 100.0f ); float mon_defense = mon_dodge + mon.size_melee_penalty() / 5.0; constexpr double hit_trials = 10000.0; const int rng_mean = std::max( std::min( static_cast( base_hit - mon_defense ), 20 ), @@ -1487,7 +1543,7 @@ std::map item::dps( const bool for_display, const bool for_ std::map item::dps( const bool for_display, const bool for_calc ) const { - return dps( for_display, for_calc, g->u ); + return dps( for_display, for_calc, get_avatar() ); } double item::average_dps( const player &guy ) const @@ -1677,9 +1733,10 @@ void item::med_info( const item *med_item, std::vector &info, const it info.push_back( iteminfo( "MED", _( "Quench: " ), med_com->quench ) ); } + Character &player_character = get_player_character(); if( med_item->get_comestible_fun() != 0 && parts->test( iteminfo_parts::MED_JOY ) ) { info.push_back( iteminfo( "MED", _( "Enjoyability: " ), - g->u.fun_for( *med_item ).first ) ); + player_character.fun_for( *med_item ).first ) ); } if( med_com->stim != 0 && parts->test( iteminfo_parts::MED_STIMULATION ) ) { @@ -1695,7 +1752,7 @@ void item::med_info( const item *med_item, std::vector &info, const it if( parts->test( iteminfo_parts::MED_CONSUME_TIME ) ) { info.push_back( iteminfo( "MED", _( "Consume time: " ), - to_string( g->u.get_consume_time( *med_item ) ) ) ); + to_string( player_character.get_consume_time( *med_item ) ) ) ); } if( med_com->addict && parts->test( iteminfo_parts::DESCRIPTION_MED_ADDICTING ) ) { @@ -1709,12 +1766,13 @@ void item::food_info( const item *food_item, std::vector &info, nutrients min_nutr; nutrients max_nutr; + Character &player_character = get_player_character(); std::string recipe_exemplar = get_var( "recipe_exemplar", "" ); if( recipe_exemplar.empty() ) { - min_nutr = max_nutr = g->u.compute_effective_nutrients( *food_item ); + min_nutr = max_nutr = player_character.compute_effective_nutrients( *food_item ); } else { std::tie( min_nutr, max_nutr ) = - g->u.compute_nutrient_range( *food_item, recipe_id( recipe_exemplar ) ); + player_character.compute_nutrient_range( *food_item, recipe_id( recipe_exemplar ) ); } bool show_nutr = parts->test( iteminfo_parts::FOOD_NUTRITION ) || @@ -1745,7 +1803,7 @@ void item::food_info( const item *food_item, std::vector &info, } } - const std::pair fun_for_food_item = g->u.fun_for( *food_item ); + const std::pair fun_for_food_item = player_character.fun_for( *food_item ); if( fun_for_food_item.first != 0 && parts->test( iteminfo_parts::FOOD_JOY ) ) { info.push_back( iteminfo( "FOOD", _( "Enjoyability: " ), fun_for_food_item.first ) ); } @@ -1755,24 +1813,24 @@ void item::food_info( const item *food_item, std::vector &info, std::abs( static_cast( food_item->charges ) * batch ) ) ); } if( food_item->corpse != nullptr && parts->test( iteminfo_parts::FOOD_SMELL ) && - ( debug || ( g != nullptr && ( g->u.has_trait( trait_CARNIVORE ) || - g->u.has_artifact_with( AEP_SUPER_CLAIRVOYANCE ) ) ) ) ) { + ( debug || ( g != nullptr && ( player_character.has_trait( trait_CARNIVORE ) || + player_character.has_artifact_with( AEP_SUPER_CLAIRVOYANCE ) ) ) ) ) { info.push_back( iteminfo( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ) ); } if( parts->test( iteminfo_parts::FOOD_CONSUME_TIME ) ) { info.push_back( iteminfo( "FOOD", _( "Consume time: " ), - to_string( g->u.get_consume_time( *food_item ) ) ) ); + to_string( player_character.get_consume_time( *food_item ) ) ) ); } auto format_vitamin = [&]( const std::pair &v, bool display_vitamins ) { const bool is_vitamin = v.first->type() == vitamin_type::VITAMIN; // only display vitamins that we actually require - if( g->u.vitamin_rate( v.first ) == 0_turns || v.second == 0 || + if( player_character.vitamin_rate( v.first ) == 0_turns || v.second == 0 || display_vitamins != is_vitamin || v.first->has_flag( flag_NO_DISPLAY ) ) { return std::string(); } - const double multiplier = g->u.vitamin_rate( v.first ) / 1_days * 100; + const double multiplier = player_character.vitamin_rate( v.first ) / 1_days * 100; const int min_value = min_nutr.get_vitamin( v.first ); const int max_value = v.second; const int min_rda = std::lround( min_value * multiplier ); @@ -1806,14 +1864,14 @@ void item::food_info( const item *food_item, std::vector &info, insert_separation_line( info ); if( parts->test( iteminfo_parts::FOOD_ALLERGEN ) - && g->u.allergy_type( *food_item ) != morale_type( "morale_null" ) ) { + && player_character.allergy_type( *food_item ) != morale_type( "morale_null" ) ) { info.emplace_back( "DESCRIPTION", _( "* This food will cause an allergic reaction." ) ); } if( food_item->has_flag( flag_CANNIBALISM ) && parts->test( iteminfo_parts::FOOD_CANNIBALISM ) ) { - if( !g->u.has_trait_flag( trait_flag_CANNIBAL ) ) { + if( !player_character.has_trait_flag( trait_flag_CANNIBAL ) ) { info.emplace_back( "DESCRIPTION", _( "* This food contains human flesh." ) ); } else { @@ -1828,7 +1886,8 @@ void item::food_info( const item *food_item, std::vector &info, } ///\EFFECT_SURVIVAL >=3 allows detection of poisonous food - if( food_item->has_flag( flag_HIDDEN_POISON ) && g->u.get_skill_level( skill_survival ) >= 3 && + if( food_item->has_flag( flag_HIDDEN_POISON ) && + player_character.get_skill_level( skill_survival ) >= 3 && parts->test( iteminfo_parts::FOOD_POISON ) ) { info.emplace_back( "DESCRIPTION", _( "* On closer inspection, this appears to be " @@ -1836,7 +1895,8 @@ void item::food_info( const item *food_item, std::vector &info, } ///\EFFECT_SURVIVAL >=5 allows detection of hallucinogenic food - if( food_item->has_flag( flag_HIDDEN_HALLU ) && g->u.get_skill_level( skill_survival ) >= 5 && + if( food_item->has_flag( flag_HIDDEN_HALLU ) && + player_character.get_skill_level( skill_survival ) >= 5 && parts->test( iteminfo_parts::FOOD_HALLUCINOGENIC ) ) { info.emplace_back( "DESCRIPTION", _( "* On closer inspection, this appears to be " @@ -1865,18 +1925,19 @@ void item::food_info( const item *food_item, std::vector &info, _( "* It was frozen once and after thawing became mushy and " "tasteless. It will rot quickly if thawed again." ) ); } - if( food_item->has_flag( flag_NO_PARASITES ) && g->u.get_skill_level( skill_cooking ) >= 3 ) { + if( food_item->has_flag( flag_NO_PARASITES ) && + player_character.get_skill_level( skill_cooking ) >= 3 ) { info.emplace_back( "DESCRIPTION", _( "* It seems that deep freezing killed all " "parasites." ) ); } if( food_item->rotten() ) { - if( g->u.has_bionic( bio_digestion ) ) { + if( player_character.has_bionic( bio_digestion ) ) { info.push_back( iteminfo( "DESCRIPTION", _( "This food has started to rot, " "but your bionic digestion can tolerate " "it." ) ) ); - } else if( g->u.has_trait( trait_SAPROVORE ) ) { + } else if( player_character.has_trait( trait_SAPROVORE ) ) { info.push_back( iteminfo( "DESCRIPTION", _( "This food has started to rot, " "but you can tolerate it." ) ) ); @@ -2081,7 +2142,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } } - int max_gun_range = loaded_mod->gun_range( &g->u ); + avatar &player_character = get_avatar(); + int max_gun_range = loaded_mod->gun_range( &player_character ); if( max_gun_range > 0 && parts->test( iteminfo_parts::GUN_MAX_RANGE ) ) { info.emplace_back( "GUN", _( "Maximum range: " ), "", iteminfo::no_flags, max_gun_range ); @@ -2133,7 +2195,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf // if effective sight dispersion differs from actual sight dispersion display both int act_disp = mod->sight_dispersion(); - int eff_disp = g->u.effective_dispersion( act_disp ); + int eff_disp = player_character.effective_dispersion( act_disp ); int adj_disp = eff_disp - act_disp; if( parts->test( iteminfo_parts::GUN_DISPERSION_SIGHT ) ) { @@ -2153,16 +2215,16 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf bool bipod = mod->has_flag( flag_BIPOD ); - if( loaded_mod->gun_recoil( g->u ) ) { + if( loaded_mod->gun_recoil( player_character ) ) { if( parts->test( iteminfo_parts::GUN_RECOIL ) ) { info.emplace_back( "GUN", _( "Effective recoil: " ), "", iteminfo::no_newline | iteminfo::lower_is_better, - loaded_mod->gun_recoil( g->u ) ); + loaded_mod->gun_recoil( player_character ) ); } if( bipod && parts->test( iteminfo_parts::GUN_RECOIL_BIPOD ) ) { info.emplace_back( "GUN", "bipod_recoil", _( " (with bipod )" ), iteminfo::lower_is_better | iteminfo::no_name, - loaded_mod->gun_recoil( g->u, true ) ); + loaded_mod->gun_recoil( player_character, true ) ); } } info.back().bNewLine = true; @@ -2229,8 +2291,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( parts->test( iteminfo_parts::GUN_AIMING_STATS ) ) { insert_separation_line( info ); info.emplace_back( "GUN", _( "Base aim speed: " ), "", iteminfo::no_flags, - g->u.aim_per_move( *mod, MAX_RECOIL ) ); - for( const aim_type &type : g->u.get_aim_types( *mod ) ) { + player_character.aim_per_move( *mod, MAX_RECOIL ) ); + for( const aim_type &type : player_character.get_aim_types( *mod ) ) { // Nameless aim levels don't get an entry. if( type.name.empty() ) { continue; @@ -2239,11 +2301,11 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf // distinct tag per aim type. const std::string tag = "GUN_" + type.name; info.emplace_back( tag, string_format( "%s", type.name ) ); - int max_dispersion = g->u.get_weapon_dispersion( *loaded_mod ).max(); + int max_dispersion = player_character.get_weapon_dispersion( *loaded_mod ).max(); int range = range_with_even_chance_of_good_hit( max_dispersion + type.threshold ); info.emplace_back( tag, _( "Even chance of good hit at range: " ), _( "" ), iteminfo::no_flags, range ); - int aim_mv = g->u.gun_engagement_moves( *mod, type.threshold ); + int aim_mv = player_character.gun_engagement_moves( *mod, type.threshold ); info.emplace_back( tag, _( "Time to reach aim level: " ), _( " moves" ), iteminfo::lower_is_better, aim_mv ); } @@ -2494,8 +2556,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, return; } - int encumbrance = get_encumber( g->u ); - const sizing sizing_level = get_sizing( g->u, encumbrance != 0 ); + Character &player_character = get_player_character(); const std::string space = " "; body_part_set covered_parts = get_covered_body_parts(); bool covers_anything = covered_parts.any(); @@ -2568,25 +2629,25 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, if( has_flag( flag_PERSONAL ) ) { layering += _( "Personal aura. " ); } else if( has_flag( flag_SKINTIGHT ) ) { - layering += _( "Close to skin. " ); + layering += _( "Close to skin. " ); } else if( has_flag( flag_BELTED ) ) { - layering += _( "Strapped. " ); + layering += _( "Strapped. " ); } else if( has_flag( flag_OUTER ) ) { - layering += _( "Outer. " ); + layering += _( "Outer. " ); } else if( has_flag( flag_WAIST ) ) { - layering += _( "Waist. " ); + layering += _( "Waist. " ); } else if( has_flag( flag_AURA ) ) { - layering += _( "Outer aura. " ); + layering += _( "Outer aura. " ); } else { - layering += _( "Normal. " ); + layering += _( "Normal. " ); } info.push_back( iteminfo( "ARMOR", layering ) ); } if( parts->test( iteminfo_parts::ARMOR_COVERAGE ) && covers_anything ) { - info.push_back( iteminfo( "ARMOR", _( "Coverage: " ), "%", - iteminfo::no_newline, get_coverage() ) ); + info.push_back( iteminfo( "ARMOR", _( "Average Coverage: " ), "%", + iteminfo::no_newline, get_avg_coverage() ) ); } if( parts->test( iteminfo_parts::ARMOR_WARMTH ) && covers_anything ) { info.push_back( iteminfo( "ARMOR", space + _( "Warmth: " ), get_warmth() ) ); @@ -2596,35 +2657,99 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) && covers_anything ) { std::string format; + const bool sizing_matters = get_sizing( player_character ) != sizing::ignore; if( has_flag( flag_FIT ) ) { - format = _( " (fits)" ); - } else if( has_flag( flag_VARSIZE ) && encumbrance ) { - format = _( " (poor fit)" ); + format = _( " (fits)" ); + } else if( has_flag( flag_VARSIZE ) && sizing_matters ) { + format = _( " (poor fit)" ); } - - //If we have the wrong size, we do not fit so alert the player - if( sizing_level == sizing::human_sized_small_char ) { - format = _( " (too big)" ); - } else if( sizing_level == sizing::big_sized_small_char ) { - format = _( " (huge!)" ); - } else if( sizing_level == sizing::small_sized_human_char || - sizing_level == sizing::human_sized_big_char ) { - format = _( " (too small)" ); - } else if( sizing_level == sizing::small_sized_big_char ) { - format = _( " (tiny!)" ); + if( sizing_matters ) { + const sizing sizing_level = get_sizing( player_character ); + //If we have the wrong size, we do not fit so alert the player + if( sizing_level == sizing::human_sized_small_char ) { + format = _( " (too big)" ); + } else if( sizing_level == sizing::big_sized_small_char ) { + format = _( " (huge!)" ); + } else if( sizing_level == sizing::small_sized_human_char || + sizing_level == sizing::human_sized_big_char ) { + format = _( " (too small)" ); + } else if( sizing_level == sizing::small_sized_big_char ) { + format = _( " (tiny!)" ); + } } - info.push_back( iteminfo( "ARMOR", _( "Encumbrance: " ), format, - iteminfo::no_newline | iteminfo::lower_is_better, - encumbrance ) ); + info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); if( const islot_armor *t = find_armor_data() ) { - if( t->max_encumber != t->encumber ) { - const int encumbrance_when_full = - get_encumber( g->u, encumber_flags::assume_full ); - info.push_back( iteminfo( "ARMOR", space + _( "Encumbrance when full: " ), "", - iteminfo::no_newline | iteminfo::lower_is_better, - encumbrance_when_full ) ); + if( !t->data.empty() ) { + struct armor_portion_type { + int encumber; + int max_encumber; + int coverage; + + bool operator==( const armor_portion_type &other ) { + return encumber == other.encumber + && max_encumber == other.max_encumber + && coverage == other.coverage; + }; + }; + struct body_part_display_info { + translation to_display; + armor_portion_type portion; + bool active; + }; + + std::map to_display_data; + + for( const armor_portion_data &piece : t->data ) { + if( piece.covers.has_value() ) { + for( const bodypart_str_id &covering_id : piece.covers.value() ) { + if( covering_id != bodypart_str_id( "num_bp" ) ) { + to_display_data[covering_id] = { covering_id.obj().name_as_heading, { + get_encumber( player_character, covering_id ), + get_encumber( player_character, covering_id, encumber_flags::assume_full ), + piece.coverage + }, true + }; + } + } + } + } + // Handle things that use both sides to avoid showing L. Arm R. Arm etc when both are the same + if( !t->sided ) { + for( const body_part &legacy_part : all_body_parts ) { + bodypart_str_id bp( convert_bp( legacy_part ) ); + bodypart_str_id opposite = bp->opposite_part; + if( opposite != bp && covers( bp ) && covers( opposite ) + && to_display_data.at( bp ).portion == to_display_data.at( opposite ).portion + && to_display_data.at( opposite ).active ) { + to_display_data.at( opposite ).to_display = bp->name_as_heading_multiple; + to_display_data.at( bp ).active = false; + } + } + } + for( auto &piece : to_display_data ) { + if( t->sided ) { + const bodypart_str_id &covering_id = piece.first; + if( !covers( covering_id.id() ) ) { + continue; + } + } + if( piece.second.active ) { + info.push_back( iteminfo( "ARMOR", + string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.encumber ) ); + + info.push_back( iteminfo( "ARMOR", space + _( "When Full:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.max_encumber ) ); + + info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::lower_is_better, + piece.second.portion.coverage ) ); + } + } } } } @@ -2678,8 +2803,8 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa return; } - int encumbrance = get_encumber( g->u ); - const sizing sizing_level = get_sizing( g->u, encumbrance != 0 ); + Character &player_character = get_player_character(); + const sizing sizing_level = get_sizing( player_character ); if( has_flag( flag_HELMET_COMPAT ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { @@ -2843,11 +2968,12 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, if( !book.skill && !type->can_use( "MA_MANUAL" ) && parts->test( iteminfo_parts::BOOK_SUMMARY ) ) { info.push_back( iteminfo( "BOOK", _( "Just for fun." ) ) ); } + avatar &player_character = get_avatar(); if( type->can_use( "MA_MANUAL" ) && parts->test( iteminfo_parts::BOOK_SUMMARY ) ) { info.push_back( iteminfo( "BOOK", _( "Some sort of martial arts training " "manual." ) ) ); - if( g->u.has_identified( typeId() ) ) { + if( player_character.has_identified( typeId() ) ) { const matype_id style_to_learn = martial_art_learned_from( *type ); info.push_back( iteminfo( "BOOK", string_format( _( "You can learn %s style " @@ -2866,9 +2992,9 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "BOOK", _( "It can be understood by " "beginners." ) ) ); } - if( g->u.has_identified( typeId() ) ) { + if( player_character.has_identified( typeId() ) ) { if( book.skill ) { - const SkillLevel &skill = g->u.get_skill_level_object( book.skill ); + const SkillLevel &skill = player_character.get_skill_level_object( book.skill ); if( skill.can_train() && parts->test( iteminfo_parts::BOOK_SKILLRANGE_MAX ) ) { const std::string skill_name = book.skill->name(); std::string fmt = string_format( _( "Can bring your %s skill to " @@ -2893,11 +3019,11 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, _( "Requires intelligence of to easily " "read." ), iteminfo::lower_is_better, book.intel ) ); } - if( g->u.book_fun_for( *this, g->u ) != 0 && + if( player_character.book_fun_for( *this, player_character ) != 0 && parts->test( iteminfo_parts::BOOK_MORALECHANGE ) ) { info.push_back( iteminfo( "BOOK", "", _( "Reading this book affects your morale by " ), - iteminfo::show_plus, g->u.book_fun_for( *this, g->u ) ) ); + iteminfo::show_plus, player_character.book_fun_for( *this, player_character ) ) ); } if( parts->test( iteminfo_parts::BOOK_TIMEPERCHAPTER ) ) { std::string fmt = ngettext( @@ -2917,7 +3043,7 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, } if( book.chapters > 0 && parts->test( iteminfo_parts::BOOK_NUMUNREADCHAPTERS ) ) { - const int unread = get_remaining_chapters( g->u ); + const int unread = get_remaining_chapters( player_character ); std::string fmt = ngettext( "This book has unread chapter.", "This book has unread chapters.", unread ); @@ -2927,8 +3053,9 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::BOOK_INCLUDED_RECIPES ) ) { std::vector recipe_list; for( const islot_book::recipe_with_description_t &elem : book.recipes ) { - const bool knows_it = g->u.knows_recipe( elem.recipe ); - const bool can_learn = g->u.get_skill_level( elem.recipe->skill_used ) >= elem.skill_level; + const bool knows_it = player_character.knows_recipe( elem.recipe ); + const bool can_learn = player_character.get_skill_level( elem.recipe->skill_used ) >= + elem.skill_level; // If the player knows it, they recognize it even if it's not clearly stated. if( elem.is_hidden() && !knows_it ) { continue; @@ -3136,7 +3263,7 @@ void item::disassembly_info( std::vector &info, const iteminfo_query * const recipe &dis = recipe_dictionary::get_uncraft( typeId() ); const requirement_data &req = dis.disassembly_requirements(); if( !req.is_empty() ) { - const std::string approx_time = to_string_approx( time_duration::from_turns( dis.time / 100 ) ); + const std::string approx_time = to_string_approx( dis.time_to_craft( get_player_character() ) ); const requirement_data::alter_item_comp_vector &comps_list = req.get_components(); const std::string comps_str = enumerate_as_string( comps_list.begin(), comps_list.end(), @@ -3419,9 +3546,11 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } } + Character &player_character = get_player_character(); // display which martial arts styles character can use with this weapon if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { - const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); + const std::string valid_styles = player_character.martial_arts_data.enumerate_known_styles( + typeId() ); if( !valid_styles.empty() ) { insert_separation_line( info ); info.push_back( iteminfo( "DESCRIPTION", @@ -3445,13 +3574,13 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } ///\EFFECT_MELEE >2 allows seeing melee damage stats on weapons - if( ( g->u.get_skill_level( skill_melee ) > 2 && + if( ( player_character.get_skill_level( skill_melee ) > 2 && ( dmg_bash || dmg_cut || dmg_stab || type->m_to_hit > 0 ) ) || debug_mode ) { damage_instance non_crit; - g->u.roll_all_damage( false, non_crit, true, *this ); + player_character.roll_all_damage( false, non_crit, true, *this ); damage_instance crit; - g->u.roll_all_damage( true, crit, true, *this ); - int attack_cost = g->u.attack_speed( *this ); + player_character.roll_all_damage( true, crit, true, *this ); + int attack_cost = player_character.attack_speed( *this ); insert_separation_line( info ); if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG ) ) { info.push_back( iteminfo( "DESCRIPTION", _( "Average melee damage:" ) ) ); @@ -3460,9 +3589,9 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_CRIT ) ) { info.push_back( iteminfo( "DESCRIPTION", string_format( _( "Critical hit chance %d%% - %d%%" ), - static_cast( g->u.crit_chance( 0, 100, *this ) * + static_cast( player_character.crit_chance( 0, 100, *this ) * 100 ), - static_cast( g->u.crit_chance( 100, 0, *this ) * + static_cast( player_character.crit_chance( 100, 0, *this ) * 100 ) ) ) ); } // Bash damage @@ -3561,7 +3690,11 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { if( const islot_armor *t = find_armor_data() ) { - if( t->max_encumber != t->encumber ) { + bool any_encumb_increase = std::any_of( t->data.begin(), t->data.end(), + []( armor_portion_data data ) { + return data.encumber != data.max_encumber; + } ); + if( any_encumb_increase ) { info.emplace_back( "BASE", _( "* This item is not rigid. Its" " volume and encumbrance increase with contents." ) ); @@ -3586,8 +3719,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } + avatar &player_character = get_avatar(); if( parts->test( iteminfo_parts::DESCRIPTION_ALLERGEN ) ) { - if( is_armor() && g->u.has_trait( trait_WOOLALLERGY ) && + if( is_armor() && player_character.has_trait( trait_WOOLALLERGY ) && ( made_of( material_id( "wool" ) ) || item_tags.count( "wooled" ) ) ) { info.push_back( iteminfo( "DESCRIPTION", _( "* This clothing will give you an allergic " @@ -3794,8 +3928,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES ) ) { // with the inventory display allowing you to select items, showing the things you could make with contained items could be confusing. itype_id tid = typeId(); - const inventory &crafting_inv = g->u.crafting_inventory(); - const recipe_subset available_recipe_subset = g->u.get_available_recipes( crafting_inv ); + const inventory &crafting_inv = player_character.crafting_inventory(); + const recipe_subset available_recipe_subset = player_character.get_available_recipes( + crafting_inv ); const std::set &item_recipes = available_recipe_subset.of_component( tid ); if( item_recipes.empty() ) { @@ -3970,7 +4105,7 @@ const std::string &item::symbol() const nc_color item::color_in_inventory() const { // TODO: make a const reference - avatar &u = g->u; + avatar &player_character = get_avatar(); // Only item not otherwise colored gets colored as favorite nc_color ret = is_favorite ? c_white : c_light_gray; @@ -3980,10 +4115,12 @@ nc_color item::color_in_inventory() const static_cast( iuse->get_actor_ptr() ); for( const std::string &spell_id_str : actor_ptr->spells ) { const spell_id sp_id( spell_id_str ); - if( u.magic.knows_spell( sp_id ) && !u.magic.get_spell( sp_id ).is_max_level() ) { + if( player_character.magic.knows_spell( sp_id ) && + !player_character.magic.get_spell( sp_id ).is_max_level() ) { ret = c_yellow; } - if( !u.magic.knows_spell( sp_id ) && u.magic.can_learn_spell( u, sp_id ) ) { + if( !player_character.magic.knows_spell( sp_id ) && + player_character.magic.can_learn_spell( player_character, sp_id ) ) { return c_light_blue; } } @@ -3991,14 +4128,14 @@ nc_color item::color_in_inventory() const ret = c_cyan; } else if( has_flag( flag_LITCIG ) ) { ret = c_red; - } else if( is_armor() && u.has_trait( trait_WOOLALLERGY ) && + } else if( is_armor() && player_character.has_trait( trait_WOOLALLERGY ) && ( made_of( material_id( "wool" ) ) || item_tags.count( "wooled" ) ) ) { ret = c_red; } else if( is_filthy() || item_tags.count( "DIRTY" ) ) { ret = c_brown; } else if( is_bionic() ) { - if( !u.has_bionic( type->bionic->id ) ) { - ret = u.bionic_installation_issues( type->bionic->id ).empty() ? c_green : c_red; + if( !player_character.has_bionic( type->bionic->id ) ) { + ret = player_character.bionic_installation_issues( type->bionic->id ).empty() ? c_green : c_red; } else if( !has_flag( flag_NO_STERILE ) ) { ret = c_dark_gray; } @@ -4014,7 +4151,7 @@ nc_color item::color_in_inventory() const // Give color priority to allergy (allergy > inedible by freeze or other conditions) // TODO: refactor u.will_eat to let this section handle coloring priority without duplicating code. - if( u.allergy_type( *food ) != morale_type( "morale_null" ) ) { + if( player_character.allergy_type( *food ) != morale_type( "morale_null" ) ) { return c_red; } @@ -4024,7 +4161,7 @@ nc_color item::color_in_inventory() const // Red: morale penalty // Yellow: will rot soon // Cyan: will rot eventually - const ret_val rating = u.will_eat( *food ); + const ret_val rating = player_character.will_eat( *food ); // TODO: More colors switch( rating.value() ) { case EDIBLE: @@ -4056,8 +4193,9 @@ nc_color item::color_in_inventory() const // Gun with integrated mag counts as both for( const ammotype &at : ammo_types() ) { // get_ammo finds uncontained ammo, find_ammo finds ammo in magazines - bool has_ammo = !u.get_ammo( at ).empty() || !u.find_ammo( *this, false, -1 ).empty(); - bool has_mag = magazine_integral() || !u.find_ammo( *this, true, -1 ).empty(); + bool has_ammo = !player_character.get_ammo( at ).empty() || + !player_character.find_ammo( *this, false, -1 ).empty(); + bool has_mag = magazine_integral() || !player_character.find_ammo( *this, true, -1 ).empty(); if( has_ammo && has_mag ) { ret = c_green; break; @@ -4070,10 +4208,10 @@ nc_color item::color_in_inventory() const // Likewise, ammo is green if you have guns that use it // ltred if you have the gun but no mags // Gun with integrated mag counts as both - bool has_gun = u.has_item_with( [this]( const item & i ) { + bool has_gun = player_character.has_item_with( [this]( const item & i ) { return i.is_gun() && i.ammo_types().count( ammo_type() ); } ); - bool has_mag = u.has_item_with( [this]( const item & i ) { + bool has_mag = player_character.has_item_with( [this]( const item & i ) { return ( i.is_gun() && i.magazine_integral() && i.ammo_types().count( ammo_type() ) ) || ( i.is_magazine() && i.ammo_types().count( ammo_type() ) ); } ); @@ -4085,31 +4223,31 @@ nc_color item::color_in_inventory() const } else if( is_magazine() ) { // Magazines are green if you have guns and ammo for them // ltred if you have one but not the other - bool has_gun = u.has_item_with( [this]( const item & it ) { + bool has_gun = player_character.has_item_with( [this]( const item & it ) { return it.is_gun() && it.magazine_compatible().count( typeId() ) > 0; } ); - bool has_ammo = !u.find_ammo( *this, false, -1 ).empty(); + bool has_ammo = !player_character.find_ammo( *this, false, -1 ).empty(); if( has_gun && has_ammo ) { ret = c_green; } else if( has_gun || has_ammo ) { ret = c_light_red; } } else if( is_book() ) { - if( u.has_identified( typeId() ) ) { + if( player_character.has_identified( typeId() ) ) { const islot_book &tmp = *type->book; if( tmp.skill && // Book can improve skill: blue - u.get_skill_level_object( tmp.skill ).can_train() && - u.get_skill_level( tmp.skill ) >= tmp.req && - u.get_skill_level( tmp.skill ) < tmp.level ) { + player_character.get_skill_level_object( tmp.skill ).can_train() && + player_character.get_skill_level( tmp.skill ) >= tmp.req && + player_character.get_skill_level( tmp.skill ) < tmp.level ) { ret = c_light_blue; } else if( type->can_use( "MA_MANUAL" ) && - !u.martial_arts_data.has_martialart( martial_art_learned_from( *type ) ) ) { + !player_character.martial_arts_data.has_martialart( martial_art_learned_from( *type ) ) ) { ret = c_light_blue; } else if( tmp.skill && // Book can't improve skill right now, but maybe later: pink - u.get_skill_level_object( tmp.skill ).can_train() && - u.get_skill_level( tmp.skill ) < tmp.level ) { + player_character.get_skill_level_object( tmp.skill ).can_train() && + player_character.get_skill_level( tmp.skill ) < tmp.level ) { ret = c_pink; - } else if( !u.studied_all_recipes( + } else if( !player_character.studied_all_recipes( *type ) ) { // Book can't improve skill anymore, but has more recipes: yellow ret = c_yellow; } @@ -4131,20 +4269,26 @@ void item::on_wear( Character &p ) !p.worn_with_flag( flag_SPLINT, bodypart_id( "arm_r" ) ) ) ) { set_side( side::RIGHT ); } + } else if( has_flag( flag_TOURNIQUET ) ) { + set_side( side::LEFT ); + if( ( covers( bodypart_id( "leg_l" ) ) && p.has_effect( effect_bleed, bp_leg_r ) && + !p.worn_with_flag( flag_TOURNIQUET, bodypart_id( "leg_r" ) ) ) || + ( covers( bodypart_id( "arm_l" ) ) && p.has_effect( effect_bleed, bp_arm_r ) && + !p.worn_with_flag( flag_TOURNIQUET, bodypart_id( "arm_r" ) ) ) ) { + set_side( side::RIGHT ); + } } else { // for sided items wear the item on the side which results in least encumbrance int lhs = 0; int rhs = 0; set_side( side::LEFT ); - const auto left_enc = p.get_encumbrance( *this ); - for( const body_part bp : all_body_parts ) { - lhs += left_enc[bp].encumbrance; + for( const bodypart_id &bp : p.get_all_body_parts() ) { + lhs += p.get_part_encumbrance_data( bp ).encumbrance; } set_side( side::RIGHT ); - const auto right_enc = p.get_encumbrance( *this ); - for( const body_part bp : all_body_parts ) { - rhs += right_enc[bp].encumbrance; + for( const bodypart_id &bp : p.get_all_body_parts() ) { + rhs += p.get_part_encumbrance_data( bp ).encumbrance; } set_side( lhs <= rhs ? side::LEFT : side::RIGHT ); @@ -4152,11 +4296,11 @@ void item::on_wear( Character &p ) } // TODO: artifacts currently only work with the player character - if( &p == &g->u && type->artifact ) { + if( p.is_avatar() && type->artifact ) { g->add_artifact_messages( type->artifact->effects_worn ); } // if game is loaded - don't want ownership assigned during char creation - if( g->u.getID().is_valid() ) { + if( get_player_character().getID().is_valid() ) { handle_pickup_ownership( p ); } p.on_item_wear( *this ); @@ -4174,7 +4318,7 @@ void item::on_takeoff( Character &p ) void item::on_wield( player &p, int mv ) { // TODO: artifacts currently only work with the player character - if( &p == &g->u && type->artifact ) { + if( p.is_avatar() && type->artifact ) { g->add_artifact_messages( type->artifact->effects_wielded ); } @@ -4219,7 +4363,7 @@ void item::on_wield( player &p, int mv ) msg = _( "You wield your %s." ); } // if game is loaded - don't want ownership assigned during char creation - if( g->u.getID().is_valid() ) { + if( get_player_character().getID().is_valid() ) { handle_pickup_ownership( p ); } p.add_msg_if_player( m_neutral, msg, tname() ); @@ -4237,15 +4381,16 @@ void item::handle_pickup_ownership( Character &c ) if( is_owned_by( c ) ) { return; } + Character &player_character = get_player_character(); // Add ownership to item if unowned if( owner.is_null() ) { set_owner( c ); } else { - if( !is_owned_by( c ) && &c == &g->u ) { + if( !is_owned_by( c ) && c.is_avatar() ) { std::vector witnesses; for( npc &elem : g->all_npcs() ) { - if( rl_dist( elem.pos(), g->u.pos() ) < MAX_VIEW_DISTANCE && elem.get_faction() && - is_owned_by( elem ) && elem.sees( g->u.pos() ) ) { + if( rl_dist( elem.pos(), player_character.pos() ) < MAX_VIEW_DISTANCE && + elem.get_faction() && is_owned_by( elem ) && elem.sees( player_character.pos() ) ) { elem.say( "", 7 ); npc *npc_to_add = &elem; witnesses.push_back( npc_to_add ); @@ -4277,11 +4422,11 @@ void item::on_pickup( Character &p ) return; } // TODO: artifacts currently only work with the player character - if( &p == &g->u && type->artifact ) { + if( p.is_avatar() && type->artifact ) { g->add_artifact_messages( type->artifact->effects_carried ); } // if game is loaded - don't want ownership assigned during char creation - if( g->u.getID().is_valid() ) { + if( get_player_character().getID().is_valid() ) { handle_pickup_ownership( p ); } contents.on_pickup( p ); @@ -4422,11 +4567,13 @@ std::string item::tname( unsigned int quantity, bool with_prefix, unsigned int t maintext = label( quantity ); } + Character &player_character = get_player_character(); std::string tagtext; if( is_food() ) { - if( has_flag( flag_HIDDEN_POISON ) && g->u.get_skill_level( skill_survival ) >= 3 ) { + if( has_flag( flag_HIDDEN_POISON ) && player_character.get_skill_level( skill_survival ) >= 3 ) { tagtext += _( " (poisonous)" ); - } else if( has_flag( flag_HIDDEN_HALLU ) && g->u.get_skill_level( skill_survival ) >= 5 ) { + } else if( has_flag( flag_HIDDEN_HALLU ) && + player_character.get_skill_level( skill_survival ) >= 5 ) { tagtext += _( " (hallucinogenic)" ); } } @@ -4459,7 +4606,7 @@ std::string item::tname( unsigned int quantity, bool with_prefix, unsigned int t } } - const sizing sizing_level = get_sizing( g->u, get_encumber( g->u ) != 0 ); + const sizing sizing_level = get_sizing( player_character ); if( sizing_level == sizing::human_sized_small_char ) { tagtext += _( " (too big)" ); @@ -4510,7 +4657,7 @@ std::string item::tname( unsigned int quantity, bool with_prefix, unsigned int t if( has_flag( flag_WET ) ) { tagtext += _( " (wet)" ); } - if( already_used_by_player( g->u ) ) { + if( already_used_by_player( player_character ) ) { tagtext += _( " (used)" ); } if( active && ( has_flag( flag_WATER_EXTINGUISH ) || has_flag( flag_LITCIG ) ) ) { @@ -4590,13 +4737,14 @@ std::string item::display_name( unsigned int quantity ) const sidetxt = string_format( " (%s)", _( "right" ) ); break; } + avatar &player_character = get_avatar(); int amount = 0; int max_amount = 0; bool show_amt = false; // We should handle infinite charges properly in all cases. if( is_book() && get_chapters() > 0 ) { // a book which has remaining unread chapters - amount = get_remaining_chapters( g->u ); + amount = get_remaining_chapters( player_character ); } else if( magazine_current() ) { show_amt = true; const item *mag = magazine_current(); @@ -4675,7 +4823,7 @@ std::string item::display_name( unsigned int quantity ) const // HACK: This is a hack to prevent possible crashing when displaying maps as items during character creation if( is_map() && calendar::turn != calendar::turn_zero ) { const city *c = overmap_buffer.closest_city( omt_to_sm_copy( get_var( "reveal_map_center_omt", - g->u.global_omt_location() ) ) ).city; + player_character.global_omt_location() ) ) ).city; if( c != nullptr ) { name = string_format( "%s %s", c->name, name ); } @@ -4807,7 +4955,7 @@ units::mass item::weight( bool, bool integral ) const // reduce weight for sawn-off weapons capped to the apportioned weight of the barrel if( gunmod_find( itype_barrel_small ) ) { - const units::volume b = type->gun->barrel_length; + const units::volume b = type->gun->barrel_volume; const units::mass max_barrel_weight = units::from_gram( to_milliliter( b ) ); const units::mass barrel_weight = units::from_gram( b.value() * type->weight.value() / type->volume.value() ); @@ -4939,7 +5087,7 @@ units::volume item::volume( bool integral ) const if( has_flag( flag_COLLAPSIBLE_STOCK ) ) { // consider only the base size of the gun (without mods) int tmpvol = get_var( "volume", - ( type->volume - type->gun->barrel_length ) / units::legacy_volume_factor ); + ( type->volume - type->gun->barrel_volume ) / units::legacy_volume_factor ); if( tmpvol <= 3 ) { // intentional NOP } else if( tmpvol <= 5 ) { @@ -4958,7 +5106,7 @@ units::volume item::volume( bool integral ) const } if( gunmod_find( itype_barrel_small ) ) { - ret -= type->gun->barrel_length; + ret -= type->gun->barrel_volume; } } @@ -5522,14 +5670,46 @@ bool item::is_power_armor() const return t->power_armor; } -int item::get_encumber( const Character &p, encumber_flags flags ) const +int item::get_avg_encumber( const Character &p, encumber_flags flags ) const { const islot_armor *t = find_armor_data(); - if( t == nullptr ) { + if( !t ) { + // handle wearable guns (e.g. shoulder strap) as special case + return is_gun() ? volume() / 750_ml : 0; + } + + int avg_encumber = 0; + int avg_ctr = 0; + + for( const armor_portion_data &entry : t->data ) { + if( entry.covers.has_value() ) { + for( const bodypart_str_id &limb : entry.covers.value() ) { + int encumber = get_encumber( p, bodypart_id( limb ), flags ); + if( encumber ) { + avg_encumber += encumber; + ++avg_ctr; + } + } + } + } + if( avg_encumber == 0 ) { + return 0; + } else { + avg_encumber /= avg_ctr; + return avg_encumber; + } +} + +int item::get_encumber( const Character &p, const bodypart_id &bodypart, + encumber_flags flags ) const +{ + const islot_armor *t = find_armor_data(); + if( !t ) { // handle wearable guns (e.g. shoulder strap) as special case return is_gun() ? volume() / 750_ml : 0; } - int encumber = t->encumber; + + int encumber = 0; // Additional encumbrance from non-rigid pockets float relative_encumbrance = 1; @@ -5537,7 +5717,11 @@ int item::get_encumber( const Character &p, encumber_flags flags ) const relative_encumbrance = contents.relative_encumbrance(); } - encumber += std::ceil( relative_encumbrance * ( t->max_encumber - t->encumber ) ); + if( cata::optional portion_data = portion_for_bodypart( bodypart ) ) { + encumber = portion_data->encumber; + encumber += std::ceil( relative_encumbrance * ( portion_data->max_encumber - + portion_data->encumber ) ); + } // Fit checked before changes, fitting shouldn't reduce penalties from patching. if( has_flag( flag_FIT ) && has_flag( flag_VARSIZE ) ) { @@ -5545,7 +5729,7 @@ int item::get_encumber( const Character &p, encumber_flags flags ) const } // TODO: Should probably have sizing affect coverage - const sizing sizing_level = get_sizing( p, encumber != 0 ); + const sizing sizing_level = get_sizing( p ); switch( sizing_level ) { case sizing::small_sized_human_char: case sizing::small_sized_big_char: @@ -5591,13 +5775,53 @@ layer_level item::get_layer() const } } -int item::get_coverage() const +int item::get_avg_coverage() const { const islot_armor *t = find_armor_data(); - if( t == nullptr ) { + if( !t ) { + return 0; + } + int avg_coverage = 0; + int avg_ctr = 0; + for( const armor_portion_data &entry : t->data ) { + if( entry.covers.has_value() ) { + for( const bodypart_str_id &limb : entry.covers.value() ) { + int coverage = get_coverage( limb ); + if( coverage ) { + avg_coverage += coverage; + ++avg_ctr; + } + } + } + } + if( avg_coverage == 0 ) { return 0; + } else { + avg_coverage /= avg_ctr; + return avg_coverage; + } +} + +int item::get_coverage( const bodypart_id &bodypart ) const +{ + if( cata::optional portion_data = portion_for_bodypart( bodypart ) ) { + return portion_data->coverage; + } + return 0; +} + +cata::optional item::portion_for_bodypart( const bodypart_id &bodypart ) const +{ + const islot_armor *t = find_armor_data(); + if( !t ) { + return cata::optional(); } - return t->coverage; + for( const armor_portion_data &entry : t->data ) { + if( entry.covers.has_value() && entry.covers->test( bodypart.id() ) ) { + return entry; + } + } + return cata::optional(); } int item::get_thickness() const @@ -5662,7 +5886,7 @@ bool item::ready_to_revive( const tripoint &pos ) const if( !can_revive() ) { return false; } - if( g->m.veh_at( pos ) ) { + if( get_map().veh_at( pos ) ) { return false; } if( !calendar::once_every( 1_seconds ) ) { @@ -5678,7 +5902,7 @@ bool item::ready_to_revive( const tripoint &pos ) const // If we're a special revival zombie, wait to get up until the player is nearby. const bool isReviveSpecial = has_flag( flag_REVIVE_SPECIAL ); if( isReviveSpecial ) { - const int distance = rl_dist( pos, g->u.pos() ); + const int distance = rl_dist( pos, get_player_character().pos() ); if( distance > 3 ) { return false; } @@ -6587,6 +6811,13 @@ bool item::is_reloadable_helper( const itype_id &ammo, bool now ) const return false; } } + //Now single shoted gun also has magazine_well slot for speedloader + //If ammo is not an ammo it may be dangerous to use parameters like ammo->ammo->type + //It is complicated: normal magazine in addition to speedloader? Magazines of mods? + if( now && !ammo->ammo ) { + return magazine_compatible().count( ammo ); + } + return now ? ammo_remaining() < ammo_capacity( ammo->ammo->type ) : true; } return magazine_compatible().count( ammo ); @@ -6789,7 +7020,7 @@ void item::mark_chapter_as_read( const player &u ) set_var( var, remain ); } -std::vector> item::get_available_recipes( const player &u ) const +std::vector> item::get_available_recipes( const Character &u ) const { std::vector> recipe_entries; if( is_book() ) { @@ -7075,16 +7306,12 @@ int item::ammo_remaining() const } if( is_tool() ) { - // dirty hack for UPS, hopefully temporary - if( typeId() == itype_UPS_off || typeId() == itype_adv_UPS_off ) { - return charges; - } if( ammo_types().empty() || !contents.has_pocket_type( item_pocket::pocket_type::MAGAZINE ) ) { // includes auxiliary gunmods if( has_flag( flag_USES_BIONIC_POWER ) ) { - int power = units::to_kilojoule( g->u.get_power_level() ); + int power = units::to_kilojoule( get_player_character().get_power_level() ); return power; } return charges; @@ -7138,6 +7365,8 @@ int item::ammo_capacity( const ammotype &ammo ) const const item *mag = magazine_current(); if( mag ) { return mag->ammo_capacity( ammo ); + } else if( has_flag( flag_USES_BIONIC_POWER ) ) { + return units::to_kilojoule( get_player_character().get_max_power_level() ); } return contents.ammo_capacity( ammo ); @@ -7185,9 +7414,10 @@ int item::ammo_consume( int qty, const tripoint &pos ) if( !contents.has_pocket_type( item_pocket::pocket_type::MAGAZINE ) || ( is_tool() && type->tool->ammo_id.empty() ) ) { qty = std::min( qty, charges ); + Character &player_character = get_player_character(); if( has_flag( flag_USES_BIONIC_POWER ) ) { - charges = units::to_kilojoule( g->u.get_power_level() ); - g->u.mod_power_level( units::from_kilojoule( -qty ) ); + charges = units::to_kilojoule( player_character.get_power_level() ); + player_character.mod_power_level( units::from_kilojoule( -qty ) ); } charges -= qty; if( charges == 0 ) { @@ -7345,23 +7575,8 @@ itype_id item::magazine_default( bool conversion ) const return itype_id::NULL_ID(); } -std::set item::magazine_compatible( bool conversion ) const +std::set item::magazine_compatible( bool /* conversion */ ) const { - std::set mags = {}; - // mods that define magazine_adaptor may override the items usual magazines - const std::vector &mods = is_gun() ? gunmods() : toolmods(); - for( const item *m : mods ) { - if( !m->type->mod->magazine_adaptor.empty() ) { - for( const ammotype &atype : ammo_types( conversion ) ) { - if( m->type->mod->magazine_adaptor.count( atype ) ) { - std::set magazines_for_atype = m->type->mod->magazine_adaptor.find( atype )->second; - mags.insert( magazines_for_atype.begin(), magazines_for_atype.end() ); - } - } - return mags; - } - } - return contents.magazine_compatible(); } @@ -7385,6 +7600,11 @@ std::vector item::gunmods() const return contents.gunmods(); } +std::vector item::mods() const +{ + return contents.mods(); +} + item *item::gunmod_find( const itype_id &mod ) { std::vector mods = gunmods(); @@ -8411,6 +8631,15 @@ const item_category &item::get_category() const return type->category_force.is_valid() ? type->category_force.obj() : null_category; } +const item_category &item::get_category_of_contents() const +{ + if( type->category_force == item_category_container && contents.num_item_stacks() == 1 ) { + return contents.only_item().get_category(); + } else { + return this->get_category(); + } +} + iteminfo::iteminfo( const std::string &Type, const std::string &Name, const std::string &Fmt, flags Flags, double Value ) { @@ -8547,7 +8776,7 @@ bool item_compare_by_charges( const item &left, const item &right ) } static const std::string USED_BY_IDS( "USED_BY_IDS" ); -bool item::already_used_by_player( const player &p ) const +bool item::already_used_by_player( const Character &p ) const { const auto it = item_vars.find( USED_BY_IDS ); if( it == item_vars.end() ) { @@ -8724,7 +8953,7 @@ bool item::process_temperature_rot( float insulation, const tripoint &pos, const weather_generator &wgen = g->weather.get_cur_weather_gen(); const unsigned int seed = g->get_seed(); - int local_mod = g->new_game ? 0 : g->m.get_temperature( pos ); + int local_mod = g->new_game ? 0 : get_map().get_temperature( pos ); int enviroment_mod; // Toilets and vending machines will try to get the heat radiation and convection during mapgen and segfault. @@ -9042,11 +9271,16 @@ void item::process_artifact( player *carrier, const tripoint & /*pos*/ ) // don't consider npcs. Also they are not processed when laying on the ground. // TODO: change game::process_artifact to work with npcs, // TODO: consider moving game::process_artifact here. - if( carrier == &g->u ) { + if( carrier && carrier->is_avatar() ) { g->process_artifact( *this, *carrier ); } } +void item::overwrite_relic( const relic &nrelic ) +{ + this->relic_data = cata::make_value( nrelic ); +} + void item::process_relic( Character *carrier ) { if( !is_relic() ) { @@ -9089,7 +9323,7 @@ bool item::process_corpse( player *carrier, const tripoint &pos ) } if( rng( 0, volume() / units::legacy_volume_factor ) > burnt && g->revive_corpse( pos, *this ) ) { if( carrier == nullptr ) { - if( g->u.sees( pos ) ) { + if( get_player_character().sees( pos ) ) { if( corpse->in_species( species_ROBOT ) ) { add_msg( m_warning, _( "A nearby robot has repaired itself and stands up!" ) ); } else { @@ -9114,13 +9348,15 @@ bool item::process_corpse( player *carrier, const tripoint &pos ) bool item::process_fake_mill( player * /*carrier*/, const tripoint &pos ) { - if( g->m.furn( pos ) != furn_str_id( "f_wind_mill_active" ) && - g->m.furn( pos ) != furn_str_id( "f_water_mill_active" ) ) { + map &here = get_map(); + if( here.furn( pos ) != furn_str_id( "f_wind_mill_active" ) && + here.furn( pos ) != furn_str_id( "f_water_mill_active" ) ) { item_counter = 0; return true; //destroy fake mill } if( age() >= 6_hours || item_counter == 0 ) { - iexamine::mill_finalize( g->u, pos, birthday() ); //activate effects when timers goes to zero + iexamine::mill_finalize( get_avatar(), pos, + birthday() ); //activate effects when timers goes to zero return true; //destroy fake mill item } @@ -9129,8 +9365,9 @@ bool item::process_fake_mill( player * /*carrier*/, const tripoint &pos ) bool item::process_fake_smoke( player * /*carrier*/, const tripoint &pos ) { - if( g->m.furn( pos ) != furn_str_id( "f_smoking_rack_active" ) && - g->m.furn( pos ) != furn_str_id( "f_metal_smoking_rack_active" ) ) { + map &here = get_map(); + if( here.furn( pos ) != furn_str_id( "f_smoking_rack_active" ) && + here.furn( pos ) != furn_str_id( "f_metal_smoking_rack_active" ) ) { item_counter = 0; return true; //destroy fake smoke } @@ -9153,6 +9390,7 @@ bool item::process_litcig( player *carrier, const tripoint &pos ) if( !active ) { return false; } + map &here = get_map(); // if carried by someone: if( carrier != nullptr ) { time_duration duration = 15_seconds; @@ -9173,24 +9411,24 @@ bool item::process_litcig( player *carrier, const tripoint &pos ) ( carrier->has_trait( trait_JITTERY ) && one_in( 200 ) ) ) { carrier->add_msg_if_player( m_bad, _( "Your shaking hand causes you to drop your %s." ), tname() ); - g->m.add_item_or_charges( pos + point( rng( -1, 1 ), rng( -1, 1 ) ), *this ); + here.add_item_or_charges( pos + point( rng( -1, 1 ), rng( -1, 1 ) ), *this ); return true; // removes the item that has just been added to the map } if( carrier->has_effect( effect_sleep ) ) { carrier->add_msg_if_player( m_bad, _( "You fall asleep and drop your %s." ), tname() ); - g->m.add_item_or_charges( pos + point( rng( -1, 1 ), rng( -1, 1 ) ), *this ); + here.add_item_or_charges( pos + point( rng( -1, 1 ), rng( -1, 1 ) ), *this ); return true; // removes the item that has just been added to the map } } else { // If not carried by someone, but laying on the ground: if( item_counter % 5 == 0 ) { // lit cigarette can start fires - if( g->m.flammable_items_at( pos ) || - g->m.has_flag( flag_FLAMMABLE, pos ) || - g->m.has_flag( flag_FLAMMABLE_ASH, pos ) ) { - g->m.add_field( pos, fd_fire, 1 ); + if( here.flammable_items_at( pos ) || + here.has_flag( flag_FLAMMABLE, pos ) || + here.has_flag( flag_FLAMMABLE_ASH, pos ) ) { + here.add_field( pos, fd_fire, 1 ); } } } @@ -9208,7 +9446,7 @@ bool item::process_litcig( player *carrier, const tripoint &pos ) convert( itype_joint_roach ); if( carrier != nullptr ) { carrier->add_effect( effect_weed_high, 1_minutes ); // one last puff - g->m.add_field( pos + point( rng( -1, 1 ), rng( -1, 1 ) ), fd_weedsmoke, 2 ); + here.add_field( pos + point( rng( -1, 1 ), rng( -1, 1 ) ), fd_weedsmoke, 2 ); weed_msg( *carrier ); } } @@ -9226,33 +9464,27 @@ bool item::process_extinguish( player *carrier, const tripoint &pos ) bool submerged = false; bool precipitation = false; bool windtoostrong = false; - w_point weatherPoint = *g->weather.weather_precise; - int windpower = g->weather.windspeed; - switch( g->weather.weather ) { - case WEATHER_LIGHT_DRIZZLE: + w_point weatherPoint = *get_weather().weather_precise; + int windpower = get_weather().windspeed; + switch( get_weather().weather_id->precip ) { + case precip_class::very_light: precipitation = one_in( 100 ); break; - case WEATHER_DRIZZLE: - case WEATHER_FLURRIES: + case precip_class::light: precipitation = one_in( 50 ); break; - case WEATHER_RAINY: - case WEATHER_SNOW: - precipitation = one_in( 25 ); - break; - case WEATHER_THUNDER: - case WEATHER_LIGHTNING: - case WEATHER_SNOWSTORM: + case precip_class::heavy: precipitation = one_in( 10 ); break; default: break; } - if( in_inv && g->m.has_flag( flag_DEEP_WATER, pos ) ) { + map &here = get_map(); + if( in_inv && here.has_flag( flag_DEEP_WATER, pos ) ) { extinguish = true; submerged = true; } - if( ( !in_inv && g->m.has_flag( flag_LIQUID, pos ) ) || + if( ( !in_inv && here.has_flag( flag_LIQUID, pos ) ) || ( precipitation && !g->is_sheltered( pos ) ) ) { extinguish = true; } @@ -9290,7 +9522,7 @@ bool item::process_extinguish( player *carrier, const tripoint &pos ) if( type->tool->revert_to ) { convert( *type->tool->revert_to ); } else { - type->invoke( carrier != nullptr ? *carrier : g->u, *this, pos, "transform" ); + type->invoke( carrier != nullptr ? *carrier : get_avatar(), *this, pos, "transform" ); } } @@ -9305,7 +9537,8 @@ cata::optional item::get_cable_target( Character *p, const tripoint &p if( state != "pay_out_cable" && state != "cable_charger_link" ) { return cata::nullopt; } - const optional_vpart_position vp_pos = g->m.veh_at( pos ); + map &here = get_map(); + const optional_vpart_position vp_pos = here.veh_at( pos ); if( vp_pos ) { const cata::optional seat = vp_pos.part_with_feature( "BOARDABLE", true ); if( seat && p == seat->vehicle().get_passenger( seat->part_index() ) ) { @@ -9316,7 +9549,7 @@ cata::optional item::get_cable_target( Character *p, const tripoint &p tripoint source2( get_var( "source_x", 0 ), get_var( "source_y", 0 ), get_var( "source_z", 0 ) ); tripoint source( source2 ); - return g->m.getlocal( source ); + return here.getlocal( source ); } bool item::process_cable( player *carrier, const tripoint &pos ) @@ -9353,7 +9586,8 @@ bool item::process_cable( player *carrier, const tripoint &pos ) return false; } - if( !g->m.veh_at( *source ) || ( source->z != g->get_levz() && !g->m.has_zlevels() ) ) { + map &here = get_map(); + if( !here.veh_at( *source ) || ( source->z != g->get_levz() && !here.has_zlevels() ) ) { if( carrier->has_item( *this ) ) { carrier->add_msg_if_player( m_bad, _( "You notice the cable has come loose!" ) ); } @@ -9445,6 +9679,7 @@ bool item::process_tool( player *carrier, const tripoint &pos ) } } + avatar &player_character = get_avatar(); // if insufficient available charges shutdown the tool if( energy > 0 ) { if( carrier && has_flag( flag_USE_UPS ) ) { @@ -9453,7 +9688,7 @@ bool item::process_tool( player *carrier, const tripoint &pos ) // invoking the object can convert the item to another type const bool had_revert_to = type->tool->revert_to.has_value(); - type->invoke( carrier != nullptr ? *carrier : g->u, *this, pos ); + type->invoke( carrier != nullptr ? *carrier : player_character, *this, pos ); if( had_revert_to ) { deactivate( carrier ); return false; @@ -9462,7 +9697,7 @@ bool item::process_tool( player *carrier, const tripoint &pos ) } } - type->tick( carrier != nullptr ? *carrier : g->u, *this, pos ); + type->tick( carrier != nullptr ? *carrier : player_character, *this, pos ); return false; } @@ -9527,14 +9762,15 @@ bool item::process_internal( player *carrier, const tripoint &pos, } if( item_counter == 0 && type->countdown_action ) { - type->countdown_action.call( carrier ? *carrier : g->u, *this, false, pos ); + type->countdown_action.call( carrier ? *carrier : get_avatar(), *this, false, pos ); if( type->countdown_destroy ) { return true; } } + map &here = get_map(); for( const emit_id &e : type->emits ) { - g->m.emit_field( pos, e ); + here.emit_field( pos, e ); } if( has_flag( flag_FAKE_SMOKE ) && process_fake_smoke( carrier, pos ) ) { @@ -9572,7 +9808,7 @@ bool item::process_internal( player *carrier, const tripoint &pos, if( has_temperature() && process_temperature_rot( insulation, pos, carrier, flag, spoil_modifier ) ) { if( is_comestible() ) { - g->m.rotten_item_spawn( *this, pos ); + here.rotten_item_spawn( *this, pos ); } return true; } @@ -9850,7 +10086,7 @@ bool item::is_filthy() const bool item::on_drop( const tripoint &pos ) { - return on_drop( pos, g->m ); + return on_drop( pos, get_map() ); } bool item::on_drop( const tripoint &pos, map &m ) @@ -9862,8 +10098,9 @@ bool item::on_drop( const tripoint &pos, map &m ) item_tags.insert( "DIRTY" ); } - g->u.flag_encumbrance(); - return type->drop_action && type->drop_action.call( g->u, *this, false, pos ); + avatar &player_character = get_avatar(); + player_character.flag_encumbrance(); + return type->drop_action && type->drop_action.call( player_character, *this, false, pos ); } time_duration item::age() const @@ -10028,7 +10265,7 @@ units::volume item::check_for_free_space( const item *it ) const if( containedPockets.success() ) { volume += check_for_free_space( container ); - for( auto pocket : containedPockets.value() ) { + for( const auto &pocket : containedPockets.value() ) { if( pocket.rigid() ) { volume += pocket.remaining_volume(); } diff --git a/src/item.h b/src/item.h index 4d25475c675c9..c5aed88575924 100644 --- a/src/item.h +++ b/src/item.h @@ -47,6 +47,7 @@ class nc_color; class player; class recipe; class relic; +struct armor_portion_data; struct islot_comestible; struct itype; struct mtype; @@ -463,6 +464,9 @@ class item : public visitable // Returns the category of this item. const item_category &get_category() const; + // Returns the category of item inside this item. I.e. "can of meat" would be food, instead of container. + // If there are multiple items/stacks or none then it defaults to category of this item. + const item_category &get_category_of_contents() const; class reload_option { @@ -692,6 +696,13 @@ class item : public visitable /** Whether this is container. Note that container does not necessarily means it's * suitable for liquids. */ bool is_container() const; + + /** + * Updates the pockets of this item to be correct based on the mods that are installed. + * Pockets which are modified that contain an item will be spilled + * NOTE: This assumes that there is always one and only one pocket where ammo goes (mag or mag well) + */ + void update_modified_pockets(); // for pocket update stuff, which pocket is @contained in? // returns a nullptr if the item is not contaiend, and prints a debug message item_pocket *contained_where( const item &contained ); @@ -738,9 +749,9 @@ class item : public visitable return contents.has_pocket_type( item_pocket::pocket_type::CONTAINER ); } /** - * Puts the given item into this one, no checks are performed. + * Puts the given item into this one. */ - void put_in( const item &payload, item_pocket::pocket_type pk_type ); + ret_val put_in( const item &payload, item_pocket::pocket_type pk_type ); /** * Returns this item into its default container. If it does not have a default container, @@ -1094,7 +1105,7 @@ class item : public visitable * Check whether the item has been marked (by calling mark_as_used_by_player) * as used by this specific player. */ - bool already_used_by_player( const player &p ) const; + bool already_used_by_player( const Character &p ) const; /** * Marks the item as being used by this specific player, it remains unmarked * for other players. The player is identified by its id. @@ -1149,6 +1160,8 @@ class item : public visitable void process_artifact( player *carrier, const tripoint &pos ); void process_relic( Character *carrier ); + void overwrite_relic( const relic &nrelic ); + bool destroyed_at_zero_charges() const; // Most of the is_whatever() functions call the same function in our itype bool is_null() const; // True if type is NULL, or points to the null item (id == 0) @@ -1569,24 +1582,39 @@ class item : public visitable * Returns clothing layer for item. */ layer_level get_layer() const; + + /* + * Returns the average coverage of each piece of data this item + */ + int get_avg_coverage() const; /** - * Returns the relative coverage that this item has when worn. - * Values range from 0 (not covering anything, or no armor at all) to - * 100 (covering the whole body part). Items that cover more are more likely to absorb - * damage from attacks. + * Returns the highest coverage that any piece of data that this item has that covers the bodypart. + * Values range from 0 (not covering anything) to 100 (covering the whole body part). + * Items that cover more are more likely to absorb damage from attacks. */ - int get_coverage() const; + int get_coverage( const bodypart_id &bodypart ) const; enum class encumber_flags : int { none = 0, assume_full = 1, }; + + cata::optional portion_for_bodypart( const bodypart_id &bodypart ) const; + + /** + * Returns the average encumbrance value that this item across all portions + * Returns 0 if this is can not be worn at all. + */ + int get_avg_encumber( const Character &, encumber_flags = encumber_flags::none ) const; + /** * Returns the encumbrance value that this item has when worn by given * player. * Returns 0 if this is can not be worn at all. */ - int get_encumber( const Character &, encumber_flags = encumber_flags::none ) const; + int get_encumber( const Character &, const bodypart_id &bodypart, + encumber_flags = encumber_flags::none ) const; + /** * Returns the weight capacity modifier (@ref islot_armor::weight_capacity_modifier) that this item provides when worn. * For non-armor it returns 1. The modifier is multiplied with the weight capacity of the character that wears the item. @@ -1668,7 +1696,7 @@ class item : public visitable /** * Enumerates recipes available from this book and the skill level required to use them. */ - std::vector> get_available_recipes( const player &u ) const; + std::vector> get_available_recipes( const Character &u ) const; /*@}*/ /** @@ -1757,19 +1785,17 @@ class item : public visitable const itype *ammo_data() const; /** Specific ammo type, returns "null" if item is neither ammo nor loaded with any */ itype_id ammo_current() const; - /** Set of ammo types (@ref ammunition_type) used by item - * @param conversion whether to include the effect of any flags or mods which convert the type - * @return empty set if item does not use a specific ammo type (and is consequently not reloadable) */ - std::set ammo_types( bool conversion = true ) const; - /** Ammo type of an ammo item * @return ammotype of ammo item or a null id if the item is not ammo */ ammotype ammo_type() const; - /** Get default ammo used by item or a null id if item does not have a default ammo type + /** Ammo types (@ref ammunition_type) the item magazine pocket can contain. * @param conversion whether to include the effect of any flags or mods which convert the type - * @return itype_id::NULL_ID() if item does not use a specific ammo type - * (and is consequently not reloadable) */ + * @return empty set if item does not have a magazine for a specific ammo type */ + std::set ammo_types( bool conversion = true ) const; + /** Default ammo for the the item magazine pocket, if item has ammo_types(). + * @param conversion whether to include the effect of any flags or mods which convert the type + * @return itype_id::NULL_ID() if item does have a magazine for a specific ammo type */ itype_id ammo_default( bool conversion = true ) const; /** Get default ammo for the first ammotype common to an item and its current magazine or "NULL" if none exists @@ -1815,6 +1841,8 @@ class item : public visitable std::vector gunmods(); std::vector gunmods() const; + std::vector mods() const; + /** Get first attached gunmod matching type or nullptr if no such mod or item is not a gun */ item *gunmod_find( const itype_id &mod ); const item *gunmod_find( const itype_id &mod ) const; @@ -2068,7 +2096,7 @@ class item : public visitable * Causes a debugmsg if called on non-craft. * @param crafter the crafting player */ - void set_next_failure_point( const player &crafter ); + void set_next_failure_point( const Character &crafter ); /** * Handle failure during crafting. @@ -2076,7 +2104,7 @@ class item : public visitable * @param crafter the crafting player. * @return whether the craft being worked on should be entirely destroyed */ - bool handle_craft_failure( player &crafter ); + bool handle_craft_failure( Character &crafter ); /** * Returns requirement data representing what is needed to resume work on an in progress craft. @@ -2150,10 +2178,10 @@ class item : public visitable small_sized_small_char, human_sized_small_char, big_sized_small_char, - not_wearable + ignore }; - sizing get_sizing( const Character &, bool ) const; + sizing get_sizing( const Character & ) const; protected: // Sub-functions of @ref process, they handle the processing for different diff --git a/src/item_contents.cpp b/src/item_contents.cpp index cea650f10942b..8b14c7a56126b 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "avatar.h" #include "character.h" @@ -259,6 +260,17 @@ size_t item_contents::size() const return contents.size(); } +void item_contents::read_mods( const item_contents &read_input ) +{ + for( const item_pocket &pocket : read_input.contents ) { + if( pocket.saved_type() == item_pocket::pocket_type::MOD ) { + for( const item *it : pocket.all_items_top() ) { + insert_item( *it, item_pocket::pocket_type::MOD ); + } + } + } +} + void item_contents::combine( const item_contents &read_input ) { std::vector uninserted_items; @@ -266,21 +278,27 @@ void item_contents::combine( const item_contents &read_input ) for( const item_pocket &pocket : read_input.contents ) { if( pocket_index < contents.size() ) { + if( pocket.saved_type() == item_pocket::pocket_type::MOD ) { + // this is already handled in item_contents::read_mods + ++pocket_index; + continue; + } else if( pocket.saved_type() == item_pocket::pocket_type::MIGRATION || + pocket.saved_type() == item_pocket::pocket_type::CORPSE ) { + for( const item *it : pocket.all_items_top() ) { + insert_item( *it, pocket.saved_type() ); + } + ++pocket_index; + continue; + } auto current_pocket_iter = contents.begin(); std::advance( current_pocket_iter, pocket_index ); for( const item *it : pocket.all_items_top() ) { - if( it->is_gunmod() || it->is_toolmod() ) { - if( !insert_item( *it, item_pocket::pocket_type::MOD ).success() ) { - uninserted_items.push_back( *it ); - } - } else { - const ret_val inserted = current_pocket_iter->insert_item( *it ); - if( !inserted.success() ) { - uninserted_items.push_back( *it ); - debugmsg( "error: tried to put an item into a pocket that can't fit into it while loading. err: %s", - inserted.str() ); - } + const ret_val inserted = current_pocket_iter->insert_item( *it ); + if( !inserted.success() ) { + uninserted_items.push_back( *it ); + debugmsg( "error: tried to put an item into a pocket that can't fit into it while loading. err: %s", + inserted.str() ); } } @@ -303,46 +321,70 @@ void item_contents::combine( const item_contents &read_input ) } } -ret_val item_contents::find_pocket_for( const item &it, - item_pocket::pocket_type pk_type ) -{ - static item_pocket *null_pocket = nullptr; - ret_val ret = ret_val::make_failure( null_pocket, - _( "is not a container" ) ); - for( item_pocket &pocket : contents ) { - if( !pocket.is_type( pk_type ) ) { - continue; - } - if( pk_type != item_pocket::pocket_type::CONTAINER && - pk_type != item_pocket::pocket_type::MAGAZINE && - pk_type != item_pocket::pocket_type::MAGAZINE_WELL && - pocket.is_type( pk_type ) ) { - return ret_val::make_success( &pocket, "special pocket type override" ); +struct item_contents::item_contents_helper { + // Static helper function to implement the const and non-const versions of + // find_pocket_for with less code duplication + template + using pocket_type = std::conditional_t < + std::is_const::value, + const item_pocket, + item_pocket + >; + + template + static ret_val*> find_pocket_for( + ItemContents &contents, const item &it, item_pocket::pocket_type pk_type ) { + using my_pocket_type = pocket_type; + static constexpr item_pocket *null_pocket = nullptr; + + std::vector failure_messages; + int num_pockets_of_type = 0; + + for( my_pocket_type &pocket : contents.contents ) { + if( !pocket.is_type( pk_type ) ) { + continue; + } + if( pk_type != item_pocket::pocket_type::CONTAINER && + pk_type != item_pocket::pocket_type::MAGAZINE && + pk_type != item_pocket::pocket_type::MAGAZINE_WELL && + pocket.is_type( pk_type ) ) { + return ret_val::make_success( + &pocket, "special pocket type override" ); + } + ++num_pockets_of_type; + ret_val ret_contain = pocket.can_contain( it ); + if( ret_contain.success() ) { + return ret_val::make_success( &pocket, ret_contain.str() ); + } else { + failure_messages.push_back( ret_contain.str() ); + } } - ret_val ret_contain = pocket.can_contain( it ); - if( ret_contain.success() ) { - return ret_val::make_success( &pocket, ret_contain.str() ); + + if( failure_messages.empty() ) { + return ret_val::make_failure( null_pocket, _( "is not a container" ) ); } + std::sort( failure_messages.begin(), failure_messages.end(), localized_compare ); + failure_messages.erase( + std::unique( failure_messages.begin(), failure_messages.end() ), + failure_messages.end() ); + return ret_val::make_failure( + null_pocket, + ngettext( "pocket unacceptable because %s", "pockets unacceptable because %s", + num_pockets_of_type ), + enumerate_as_string( failure_messages, enumeration_conjunction::or_ ) ); } - return ret; +}; + +ret_val item_contents::find_pocket_for( const item &it, + item_pocket::pocket_type pk_type ) +{ + return item_contents_helper::find_pocket_for( *this, it, pk_type ); } ret_val item_contents::find_pocket_for( const item &it, item_pocket::pocket_type pk_type ) const { - static item_pocket *null_pocket = nullptr; - ret_val ret = ret_val::make_failure( null_pocket, - _( "is not a container" ) ); - for( const item_pocket &pocket : contents ) { - if( !pocket.is_type( pk_type ) ) { - continue; - } - ret_val ret_contain = pocket.can_contain( it ); - if( ret_contain.success() ) { - return ret_val::make_success( &pocket, ret_contain.str() ); - } - } - return ret; + return item_contents_helper::find_pocket_for( *this, it, pk_type ); } int item_contents::obtain_cost( const item &it ) const @@ -372,17 +414,17 @@ ret_val item_contents::insert_item( const item &it, item_pocket::pocket_ty // LAST is invalid, so we assume it will be a regular container pk_type = item_pocket::pocket_type::CONTAINER; } - ret_val pocket = find_pocket_for( it, pk_type ); + ret_val pocket = find_pocket_for( it, pk_type ); if( pocket.value() == nullptr ) { - return ret_val::make_failure( "No success" ); + return ret_val::make_failure( "Found no suitable pocket for item" ); } ret_val pocket_contain_code = pocket.value()->insert_item( it ); if( pocket_contain_code.success() ) { return ret_val::make_success(); } - return ret_val::make_failure( "No success" ); + return ret_val::make_failure( "Failed to insert into pocket" ); } void item_contents::force_insert_item( const item &it, item_pocket::pocket_type pk_type ) @@ -827,12 +869,14 @@ const item &item_contents::only_item() const return null_item_reference(); } for( const item_pocket &pocket : contents ) { - if( pocket.empty() || !pocket.is_type( item_pocket::pocket_type::CONTAINER ) ) { + if( pocket.empty() || !( pocket.is_type( item_pocket::pocket_type::CONTAINER ) || + pocket.is_type( item_pocket::pocket_type::SOFTWARE ) ) ) { continue; } // the first item we come to is the only one. return pocket.front(); } + return null_item_reference(); } @@ -915,37 +959,62 @@ std::list item_contents::all_items_top() const std::list item_contents::all_items_ptr( item_pocket::pocket_type pk_type ) { - std::list all_items_internal; - for( item_pocket &pocket : contents ) { - if( pocket.is_type( pk_type ) ) { - std::list contained_items = pocket.all_items_ptr( pk_type ); - all_items_internal.insert( all_items_internal.end(), contained_items.begin(), - contained_items.end() ); - } + return all_items_top_recursive( pk_type ); +} + +std::list item_contents::all_items_ptr( item_pocket::pocket_type pk_type ) const +{ + return all_items_top_recursive( pk_type ); +} + +std::list item_contents::all_items_ptr() const +{ + std::list all_items_internal; + for( int i = item_pocket::pocket_type::CONTAINER; i < item_pocket::pocket_type::LAST; i++ ) { + std::list inserted{ all_items_top_recursive( static_cast( i ) ) }; + all_items_internal.insert( all_items_internal.end(), inserted.begin(), inserted.end() ); } return all_items_internal; } -std::list item_contents::all_items_ptr( item_pocket::pocket_type pk_type ) const +std::list item_contents::all_items_top_recursive( item_pocket::pocket_type pk_type ) +const { std::list all_items_internal; for( const item_pocket &pocket : contents ) { if( pocket.is_type( pk_type ) ) { - std::list contained_items = pocket.all_items_ptr( pk_type ); + std::list contained_items = pocket.all_items_top(); all_items_internal.insert( all_items_internal.end(), contained_items.begin(), contained_items.end() ); + std::list recursion_items; + for( const item *it : contained_items ) { + recursion_items = it->contents.all_items_top_recursive( pk_type ); + all_items_internal.insert( all_items_internal.end(), recursion_items.begin(), + recursion_items.end() ); + } } } + return all_items_internal; } -std::list item_contents::all_items_ptr() const +std::list item_contents::all_items_top_recursive( item_pocket::pocket_type pk_type ) { - std::list all_items_internal; - for( int i = item_pocket::pocket_type::CONTAINER; i < item_pocket::pocket_type::LAST; i++ ) { - std::list inserted{ all_items_ptr( static_cast( i ) ) }; - all_items_internal.insert( all_items_internal.end(), inserted.begin(), inserted.end() ); + std::list< item *> all_items_internal; + for( item_pocket &pocket : contents ) { + if( pocket.is_type( pk_type ) ) { + std::list< item *> contained_items = pocket.all_items_top(); + all_items_internal.insert( all_items_internal.end(), contained_items.begin(), + contained_items.end() ); + std::list< item *> recursion_items; + for( item *it : contained_items ) { + recursion_items = it->contents.all_items_top_recursive( pk_type ); + all_items_internal.insert( all_items_internal.end(), recursion_items.begin(), + recursion_items.end() ); + } + } } + return all_items_internal; } @@ -991,6 +1060,83 @@ std::vector item_contents::gunmods() const return mods; } +std::vector item_contents::mods() const +{ + std::vector mods; + for( const item_pocket &pocket : contents ) { + if( pocket.is_type( item_pocket::pocket_type::MOD ) ) { + for( const item *it : pocket.all_items_top() ) { + mods.insert( mods.end(), it ); + } + } + } + return mods; +} + +void item_contents::update_modified_pockets( + const cata::optional &mag_or_mag_well, + std::vector container_pockets ) +{ + for( auto pocket_iter = contents.begin(); pocket_iter != contents.end(); ) { + item_pocket &pocket = *pocket_iter; + if( pocket.is_type( item_pocket::pocket_type::CONTAINER ) ) { + + const pocket_data *current = pocket.get_pocket_data(); + bool found = false; + // this loop is to make sure the pockets on the current item are already here from @container_pockets, + // so we don't need to clear them (saving the favorite data) + for( auto container_pocket = container_pockets.begin(); container_pocket != container_pockets.end(); + ) { + // comparing pointers because each pocket is uniquely defined in json as its own. + if( *container_pocket == current ) { + container_pocket = container_pockets.erase( container_pocket ); + found = true; + // there will not be more than one pocket with the same pocket_data pointer, so exit early + break; + } else { + ++container_pocket; + } + } + + if( !found ) { + if( !pocket.empty() ) { + // in case the debugmsg wasn't clear, this should never happen + debugmsg( "Oops! deleted some items when updating pockets that were added via toolmods" ); + } + pocket_iter = contents.erase( pocket_iter ); + } else { + ++pocket_iter; + } + + } else if( pocket.is_type( item_pocket::pocket_type::MAGAZINE ) || + pocket.is_type( item_pocket::pocket_type::MAGAZINE_WELL ) ) { + if( mag_or_mag_well ) { + if( pocket.get_pocket_data() != *mag_or_mag_well ) { + if( !pocket.empty() ) { + // in case the debugmsg wasn't clear, this should never happen + debugmsg( "Oops! deleted some items when updating pockets that were added via toolmods" ); + } + contents.push_back( item_pocket( *mag_or_mag_well ) ); + pocket_iter = contents.erase( pocket_iter ); + } else { + ++pocket_iter; + } + } else { + // no mag or mag well, so it needs to be erased + pocket_iter = contents.erase( pocket_iter ); + } + } else { + ++pocket_iter; + } + } + + // we've deleted all of the superfluous copies already, so time to add the new pockets + for( const pocket_data *container_pocket : container_pockets ) { + contents.push_back( item_pocket( container_pocket ) ); + } + +} + std::set item_contents::magazine_compatible() const { std::set ret; diff --git a/src/item_contents.h b/src/item_contents.h index cc5f3024fe67b..9c8570bd79d84 100644 --- a/src/item_contents.h +++ b/src/item_contents.h @@ -83,6 +83,11 @@ class item_contents std::vector gunmods(); /** gets all gunmods in the item */ std::vector gunmods() const; + + std::vector mods() const; + + void update_modified_pockets( const cata::optional &mag_or_mag_well, + std::vector container_pockets ); // all magazines compatible with any pockets. // this only checks MAGAZINE_WELL std::set magazine_compatible() const; @@ -228,6 +233,8 @@ class item_contents void info( std::vector &info, const iteminfo_query *parts ) const; + // reads the items in the MOD pocket first + void read_mods( const item_contents &read_input ); void combine( const item_contents &read_input ); void serialize( JsonOut &json ) const; @@ -242,7 +249,15 @@ class item_contents ret_val find_pocket_for( const item &it, item_pocket::pocket_type pk_type = item_pocket::pocket_type::CONTAINER ) const; + //called by all_items_ptr to recursively get all items without duplicating items in nested pockets + std::list all_items_top_recursive( item_pocket::pocket_type pk_type ) const; + //called by all_items_ptr to recursively get all items without duplicating items in nested pockets + std::list all_items_top_recursive( item_pocket::pocket_type pk_type ); + std::list contents; + + struct item_contents_helper; + friend struct item_contents_helper; }; #endif // CATA_SRC_ITEM_CONTENTS_H diff --git a/src/item_factory.cpp b/src/item_factory.cpp index db6bd5e985921..efd7653583191 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -70,6 +70,13 @@ const itype &string_id::obj() const return result ? *result : dummy; } +/** @relates string_id */ +template<> +bool string_id::is_valid() const +{ + return item_controller->has_template( *this ); +} + static item_category_id calc_category( const itype &obj ); static void set_allergy_flags( itype &item_template ); static void hflesh_to_flesh( itype &item_template ); @@ -110,8 +117,14 @@ static bool assign_coverage_from_json( const JsonObject &jo, const std::string & parts.set( bodypart_str_id( "foot_l" ) ); parts.set( bodypart_str_id( "foot_r" ) ); } else { - parts.set( convert_bp( get_body_part_token( val ) ) ); + // Convert from legacy enum to new and apply coverage + if( !is_legacy_bodypart_id( val ) ) { + parts.set( bodypart_str_id( val ) ); + } else { + parts.set( convert_bp( get_body_part_token( val ) ) ); + } } + sided |= val == "ARM_EITHER" || val == "HAND_EITHER" || val == "LEG_EITHER" || val == "FOOT_EITHER"; }; @@ -510,14 +523,16 @@ void Item_factory::finalize_post( itype &obj ) if( obj.armor ) { // Setting max_encumber must be in finalize_post because it relies on // stack_size being set for all ammo, which happens in finalize_pre. - if( obj.armor->max_encumber < 0 ) { - units::volume total_nonrigid_volume = 0_ml; - for( const pocket_data &pocket : obj.pockets ) { - if( !pocket.rigid ) { - total_nonrigid_volume += pocket.max_contains_volume(); + for( armor_portion_data &data : obj.armor->data ) { + if( data.max_encumber == -1 ) { + units::volume total_nonrigid_volume = 0_ml; + for( const pocket_data &pocket : obj.pockets ) { + if( !pocket.rigid ) { + total_nonrigid_volume += pocket.max_contains_volume(); + } } + data.max_encumber = data.encumber + total_nonrigid_volume / 250_ml; } - obj.armor->max_encumber = obj.armor->encumber + total_nonrigid_volume / 250_ml; } } @@ -1071,9 +1086,13 @@ void Item_factory::check_definitions() const if( item_contents( type->pockets ).bigger_on_the_inside( volume ) ) { msg += "is bigger on the inside. consider using TARDIS flag.\n"; } - for( const pocket_data &data : type->pockets ) { - msg += data.check_definition(); - } + } + } + + for( const pocket_data &data : type->pockets ) { + std::string pocket_error = data.check_definition(); + if( !pocket_error.empty() ) { + msg += "problem with pocket: " + pocket_error; } } @@ -1081,6 +1100,22 @@ void Item_factory::check_definitions() const msg += "undefined category " + type->category_force.str() + "\n"; } + if( type->armor ) { + cata::flat_set observed_bps; + for( const armor_portion_data &portion : type->armor->data ) { + if( portion.covers.has_value() ) { + for( const body_part &bp : all_body_parts ) { + if( portion.covers->test( convert_bp( bp ) ) ) { + if( observed_bps.count( convert_bp( bp ) ) ) { + msg += "multiple portions with same body_part defined\n"; + } + observed_bps.insert( convert_bp( bp ) ); + } + } + } + } + } + if( type->weight < 0_gram ) { msg += "negative weight\n"; } @@ -1245,8 +1280,8 @@ void Item_factory::check_definitions() const } } } - if( type->gun->barrel_length < 0_ml ) { - msg += "gun barrel length cannot be negative\n"; + if( type->gun->barrel_volume < 0_ml ) { + msg += "gun barrel volume cannot be negative\n"; } if( !type->gun->skill_used ) { @@ -1713,7 +1748,7 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "reload", slot.reload_time, strict, 0 ); assign( jo, "reload_noise", slot.reload_noise, strict ); assign( jo, "reload_noise_volume", slot.reload_noise_volume, strict, 0 ); - assign( jo, "barrel_length", slot.barrel_length, strict, 0_ml ); + assign( jo, "barrel_volume", slot.barrel_volume, strict, 0_ml ); assign( jo, "built_in_mods", slot.built_in_mods, strict ); assign( jo, "default_mods", slot.default_mods, strict ); assign( jo, "ups_charges", slot.ups_charges, strict, 0 ); @@ -1779,13 +1814,147 @@ void Item_factory::load_pet_armor( const JsonObject &jo, const std::string &src } } +namespace io +{ +template<> +std::string enum_to_string( layer_level data ) +{ + switch( data ) { + case layer_level::PERSONAL: + return "Personal"; + case layer_level::UNDERWEAR: + return "Underwear"; + case layer_level::REGULAR: + return "Regular"; + case layer_level::WAIST: + return "Waist"; + case layer_level::OUTER: + return "Outer"; + case layer_level::BELTED: + return "Belted"; + case layer_level::AURA: + return "Aura"; + case layer_level::NUM_LAYER_LEVELS: + break; + } + debugmsg( "Invalid layer_level" ); + abort(); +} +} // namespace io + void islot_armor::load( const JsonObject &jo ) { - optional( jo, was_loaded, "encumbrance", encumber, 0 ); - // Default max_encumbrance will be set to a reasonable value in - // finalize_post - optional( jo, was_loaded, "max_encumbrance", max_encumber, -1 ); - optional( jo, was_loaded, "coverage", coverage, 0 ); + if( jo.has_array( "armor_portion_data" ) ) { + bool dont_add_first = false; + if( !data.empty() ) { // Uses copy-from + dont_add_first = true; + const JsonObject &obj = *jo.get_array( "armor_portion_data" ).begin(); + armor_portion_data tempData; + + if( obj.has_array( "encumbrance" ) ) { + tempData.encumber = obj.get_array( "encumbrance" ).get_int( 0 ); + tempData.max_encumber = obj.get_array( "encumbrance" ).get_int( 1 ); + } else if( obj.has_int( "encumbrance" ) ) { + tempData.encumber = obj.get_int( "encumbrance" ); + tempData.max_encumber = -1; + } + if( obj.has_int( "coverage" ) ) { + tempData.coverage = obj.get_int( "coverage" ); + } + if( tempData.encumber != data[0].encumber ) { + data[0].encumber = tempData.encumber; + } + if( tempData.max_encumber != data[0].max_encumber ) { + data[0].max_encumber = tempData.max_encumber; + } + if( tempData.coverage != data[0].coverage ) { + data[0].coverage = tempData.coverage; + } + body_part_set temp_cover_data; + assign_coverage_from_json( obj, "covers", temp_cover_data, sided ); + if( temp_cover_data.any() ) { + data[0].covers = temp_cover_data; + } + } + + for( const JsonObject &obj : jo.get_array( "armor_portion_data" ) ) { + // If this item used copy-from, data[0] is already set, so skip adding first data + if( dont_add_first ) { + obj.allow_omitted_members(); + dont_add_first = false; + continue; + } + armor_portion_data tempData; + body_part_set temp_cover_data; + assign_coverage_from_json( obj, "covers", temp_cover_data, sided ); + tempData.covers = temp_cover_data; + + if( obj.has_array( "encumbrance" ) ) { + tempData.encumber = obj.get_array( "encumbrance" ).get_int( 0 ); + tempData.max_encumber = obj.get_array( "encumbrance" ).get_int( 1 ); + } else if( obj.has_int( "encumbrance" ) ) { + tempData.encumber = obj.get_int( "encumbrance" ); + tempData.max_encumber = -1; + } + if( obj.has_int( "coverage" ) ) { + tempData.coverage = obj.get_int( "coverage" ); + } + data.push_back( tempData ); + + // TODO: Not currently supported, we still use flags for this + //if( obj.has_string( "layer" ) ) { + // for( auto &piece : data ) { + // layer_level layer; + // obj.read( "layer", layer ); + // } + //} else { + // for( armor_portion_data &piece : data ) { + // piece.layer = layer_level::REGULAR; + // } + //} + } + } else { + if( data.empty() ) { // Loading item does not have copy-from + data.emplace_back(); + optional( jo, was_loaded, "encumbrance", data[0].encumber, 0 ); + // Default max_encumbrance will be set to a reasonable value in finalize_post + optional( jo, was_loaded, "max_encumbrance", data[0].max_encumber, -1 ); + optional( jo, was_loaded, "coverage", data[0].coverage, 0 ); + body_part_set temp_cover_data; + assign_coverage_from_json( jo, "covers", temp_cover_data, sided ); + data[0].covers = temp_cover_data; + } else { // This item has copy-from and already has taken data from parent + armor_portion_data child_data; + if( jo.has_int( "encumbrance" ) ) { + child_data.encumber = jo.get_int( "encumbrance" ); + child_data.max_encumber = -1; + } + if( jo.has_int( "max_encumbrance" ) ) { + child_data.max_encumber = jo.get_int( "max_encumbrance" ); + } else { + child_data.max_encumber = -1; + } + if( jo.has_int( "coverage" ) ) { + child_data.coverage = jo.get_int( "coverage" ); + } + // If child item contains data, use that data, otherwise use parents data + if( child_data.encumber != data[0].encumber && child_data.encumber != 0 ) { + data[0].encumber = child_data.encumber; + } + if( child_data.max_encumber != data[0].max_encumber && child_data.max_encumber != -1 ) { + data[0].max_encumber = child_data.max_encumber; + } + if( child_data.coverage != data[0].coverage && child_data.coverage != 0 ) { + data[0].coverage = child_data.coverage; + } + body_part_set temp_cover_data; + assign_coverage_from_json( jo, "covers", temp_cover_data, sided ); + if( temp_cover_data.any() ) { + data[0].covers = temp_cover_data; + } + } + } + optional( jo, was_loaded, "material_thickness", thickness, 0 ); optional( jo, was_loaded, "environmental_protection", env_resist, 0 ); optional( jo, was_loaded, "environmental_protection_with_filter", env_resist_w_filter, 0 ); @@ -1795,7 +1964,6 @@ void islot_armor::load( const JsonObject &jo ) optional( jo, was_loaded, "weight_capacity_bonus", weight_capacity_bonus, mass_reader{}, 0_gram ); optional( jo, was_loaded, "power_armor", power_armor, false ); optional( jo, was_loaded, "valid_mods", valid_mods ); - assign_coverage_from_json( jo, "covers", covers, sided ); } void islot_armor::deserialize( JsonIn &jsin ) @@ -1897,6 +2065,8 @@ void Item_factory::load( islot_mod &slot, const JsonObject &jo, const std::strin slot.magazine_adaptor[ ammo ].insert( itype_id( line ) ); } } + + optional( jo, false, "pocket_mods", slot.add_pockets ); } void Item_factory::load_toolmod( const JsonObject &jo, const std::string &src ) diff --git a/src/item_group.cpp b/src/item_group.cpp index ddfaa377a1ae1..10bb167b12919 100644 --- a/src/item_group.cpp +++ b/src/item_group.cpp @@ -378,6 +378,7 @@ void Item_modifier::modify( item &new_item ) const if( !cont.is_null() ) { cont.put_in( new_item, item_pocket::pocket_type::CONTAINER ); + cont.seal(); new_item = cont; } @@ -386,6 +387,7 @@ void Item_modifier::modify( item &new_item ) const for( const item &it : contentitems ) { new_item.put_in( it, item_pocket::pocket_type::CONTAINER ); } + new_item.seal(); } for( auto &flag : custom_flags ) { diff --git a/src/item_location.cpp b/src/item_location.cpp index 51a614767f147..0474e4034b4ff 100644 --- a/src/item_location.cpp +++ b/src/item_location.cpp @@ -3,7 +3,6 @@ #include #include -#include "avatar.h" #include "character.h" #include "character_id.h" #include "color.h" @@ -19,7 +18,6 @@ #include "map.h" #include "map_selector.h" #include "optional.h" -#include "player.h" #include "point.h" #include "safe_reference.h" #include "translations.h" @@ -217,7 +215,7 @@ class item_location::impl::item_on_map : public item_location::impl obj = *target(); } - int mv = dynamic_cast( &ch )->item_handling_cost( obj, true, MAP_HANDLING_PENALTY ); + int mv = ch.item_handling_cost( obj, true, MAP_HANDLING_PENALTY ); mv += 100 * rl_dist( ch.pos(), cur ); // TODO: handle unpacking costs @@ -444,8 +442,7 @@ class item_location::impl::item_on_vehicle : public item_location::impl obj = *target(); } - int mv = dynamic_cast( &ch )->item_handling_cost( obj, true, - VEHICLE_HANDLING_PENALTY ); + int mv = ch.item_handling_cost( obj, true, VEHICLE_HANDLING_PENALTY ); mv += 100 * rl_dist( ch.pos(), cur.veh.global_part_pos3( cur.part ) ); // TODO: handle unpacking costs @@ -658,7 +655,7 @@ void item_location::deserialize( JsonIn &js ) } else { // This is for migrating saves before npc item locations were supported and all // character item locations were assumed to be on g->u - who_id = g->u.getID(); + who_id = get_player_character().getID(); } ptr.reset( new impl::item_on_person( who_id, idx ) ); diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index af3f0d59c0f7a..40ff5bbc0ea62 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -46,11 +46,18 @@ std::string pocket_data::check_definition() const type == item_pocket::pocket_type::MIGRATION ) { return ""; } + if( max_contains_volume() == 0_ml ) { + return "has zero max volume\n"; + } if( magazine_well > 0_ml && rigid ) { return "rigid overrides magazine_well\n"; } if( magazine_well >= max_contains_volume() ) { - return "magazine well larger than pocket volume. consider using rigid instead.\n"; + return string_format( + "magazine well (%s) larger than pocket volume (%s); " + "consider using rigid instead.\n", + quantity_to_string( magazine_well ), + quantity_to_string( max_contains_volume() ) ); } if( max_item_volume && *max_item_volume < min_item_volume ) { return "max_item_volume is greater than min_item_volume. no item can fit.\n"; @@ -58,6 +65,30 @@ std::string pocket_data::check_definition() const if( ( watertight || airtight ) && min_item_volume > 0_ml ) { return "watertight or gastight is incompatible with min_item_volume\n"; } + for( const itype_id &it : item_id_restriction ) { + if( !it.is_valid() ) { + return string_format( "item_id %s used in restriction invalid\n", it.str() ); + } + if( it->phase == phase_id::LIQUID && !watertight ) { + return string_format( "restricted to liquid item %s but not watertight\n", + it->get_id().str() ); + } + if( it->phase == phase_id::GAS && !airtight ) { + return string_format( "restricted to gas item %s but not airtight\n", + it->get_id().str() ); + } + } + for( const std::pair &ammo_res : ammo_restriction ) { + const itype_id &it = ammo_res.first->default_ammotype(); + if( it->phase == phase_id::LIQUID && !watertight ) { + return string_format( "restricted to liquid item %s but not watertight\n", + it->get_id().str() ); + } + if( it->phase == phase_id::GAS && !airtight ) { + return string_format( "restricted to gas item %s but not airtight\n", + it->get_id().str() ); + } + } return ""; } @@ -1129,7 +1160,7 @@ void item_pocket::on_pickup( Character &guy ) void item_pocket::on_contents_changed() { - _sealed = false; + unseal(); restack(); } @@ -1244,6 +1275,11 @@ bool item_pocket::airtight() const return data->airtight; } +const pocket_data *item_pocket::get_pocket_data() const +{ + return data; +} + void item_pocket::add( const item &it, item **ret ) { contents.push_back( it ); @@ -1374,16 +1410,13 @@ units::volume pocket_data::max_contains_volume() const return t.ammo && ammo_restriction.count( t.ammo->type ); } ); // Figure out which has the greatest volume and calculate on that basis - std::map max_ammo_volume_by_type{}; + units::volume max_total_volume = 0_ml; for( const auto *ammo_type : ammo_types ) { - units::volume &max_ammo_volume = max_ammo_volume_by_type[ammo_type->ammo->type]; int stack_size = ammo_type->stack_size ? ammo_type->stack_size : 1; - max_ammo_volume = std::max( max_ammo_volume, ammo_type->volume / stack_size ); - } - units::volume max_total_volume = 0_ml; - for( const std::pair &p : max_ammo_volume_by_type ) { - max_total_volume = std::max( max_total_volume, - p.second * ammo_restriction.at( p.first ) ); + int max_count = ammo_restriction.at( ammo_type->ammo->type ); + units::volume this_volume = + 1_ml * divide_round_up( ammo_type->volume / 1_ml * max_count, stack_size ); + max_total_volume = std::max( max_total_volume, this_volume ); } return max_total_volume; } diff --git a/src/item_pocket.h b/src/item_pocket.h index 7a11a02dd68c4..376f33f2fafe5 100644 --- a/src/item_pocket.h +++ b/src/item_pocket.h @@ -121,6 +121,8 @@ class item_pocket // exceptions are MOD, CORPSE, SOFTWARE, MIGRATION, etc. bool is_standard_type() const; + const pocket_data *get_pocket_data() const; + std::list all_items_top(); std::list all_items_top() const; std::list all_items_ptr( pocket_type pk_type ); diff --git a/src/itype.h b/src/itype.h index aa4e7d3b2240c..2437ac581e3cc 100644 --- a/src/itype.h +++ b/src/itype.h @@ -17,6 +17,7 @@ #include "explosion.h" #include "game_constants.h" #include "item_contents.h" +#include "item_pocket.h" #include "iuse.h" // use_function #include "optional.h" #include "pldata.h" // add_type @@ -207,29 +208,31 @@ struct islot_brewable { void deserialize( JsonIn &jsin ); }; -struct islot_armor { - /** - * Bitfield of enum body_part - * TODO: document me. - */ - body_part_set covers; - /** - * Whether this item can be worn on either side of the body - */ - bool sided = false; - /** - * How much this item encumbers the player. - */ +struct armor_portion_data { + + // How much this piece encumbers the player. int encumber = 0; - /** - * When storage is full, how much it encumbers the player. - */ + + // When storage is full, how much it encumbers the player. int max_encumber = 0; - /** - * Percentage of the body part area that this item covers. - * This determines how likely it is to hit the item instead of the player. - */ + + // Percentage of the body part that this item covers. + // This determines how likely it is to hit the item instead of the player. int coverage = 0; + + // Where does this cover if any + cata::optional covers; + + // What layer does it cover if any + // TODO: Not currently supported, we still use flags for this + //cata::optional layer; +}; + +struct islot_armor { + /** + * Whether this item can be worn on either side of the body + */ + bool sided = false; /** * TODO: document me. */ @@ -264,6 +267,9 @@ struct islot_armor { */ std::vector valid_mods; + // Layer, encumbrance and coverage information. + std::vector data; + bool was_loaded = false; void load( const JsonObject &jo ); @@ -386,6 +392,13 @@ struct islot_mod { /** If non-empty replaces the compatible magazines for the parent item */ std::map< ammotype, std::set > magazine_adaptor; + /** + * Pockets the mod will add to the item. + * Any MAGAZINE_WELL or MAGAZINE type pockets will be overwritten, + * and CONTAINER pockets will be added. + */ + std::vector add_pockets; + /** Proportional adjustment of parent item ammo capacity */ float capacity_multiplier = 1.0; }; @@ -509,7 +522,7 @@ struct islot_gun : common_ranged_data { /** * Length of gun barrel, if positive allows sawing down of the barrel */ - units::volume barrel_length = 0_ml; + units::volume barrel_volume = 0_ml; /** * Effects that are applied to the ammo when fired. */ diff --git a/src/iuse.cpp b/src/iuse.cpp index 4fae904d301d5..bc999f348e205 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -430,7 +430,7 @@ static const std::vector camera_ter_whitelist_types = { ter_str_id( "t_pit_spiked_covered" ), ter_str_id( "t_pit_glass" ), ter_str_id( "t_pit_glass" ), ter_str_id( "t_utility_light" ) }; -void remove_radio_mod( item &it, player &p ) +void remove_radio_mod( item &it, Character &p ) { if( !it.has_flag( "RADIO_MOD" ) ) { return; @@ -480,7 +480,7 @@ int iuse::sewage( player *p, item *it, bool, const tripoint & ) int iuse::honeycomb( player *p, item *it, bool, const tripoint & ) { - g->m.spawn_item( p->pos(), itype_wax, 2 ); + get_map().spawn_item( p->pos(), itype_wax, 2 ); return it->type->charges_to_use(); } @@ -705,17 +705,18 @@ int iuse::fungicide( player *p, item *it, bool, const tripoint & ) } p->remove_effect( effect_spores ); int spore_count = rng( 1, 6 ); - for( const tripoint &dest : g->m.points_in_radius( p->pos(), 1 ) ) { + map &here = get_map(); + for( const tripoint &dest : here.points_in_radius( p->pos(), 1 ) ) { if( spore_count == 0 ) { break; } if( dest == p->pos() ) { continue; } - if( g->m.passable( dest ) && x_in_y( spore_count, 8 ) ) { + if( here.passable( dest ) && x_in_y( spore_count, 8 ) ) { if( monster *const mon_ptr = g->critter_at( dest ) ) { monster &critter = *mon_ptr; - if( g->u.sees( dest ) && + if( get_player_character().sees( dest ) && !critter.type->in_species( species_FUNGUS ) ) { add_msg( m_warning, _( "The %s is covered in tiny spores!" ), critter.name() ); @@ -873,9 +874,10 @@ int iuse::meth( player *p, item *it, bool, const tripoint & ) } else { duration *= ( p->has_trait( trait_LIGHTWEIGHT ) ? 1.8 : 1.5 ); } + map &here = get_map(); // breathe out some smoke for( int i = 0; i < 3; i++ ) { - g->m.add_field( {p->posx() + static_cast( rng( -2, 2 ) ), p->posy() + static_cast( rng( -2, 2 ) ), p->posz()}, + here.add_field( {p->posx() + static_cast( rng( -2, 2 ) ), p->posy() + static_cast( rng( -2, 2 ) ), p->posz()}, fd_methsmoke, 2 ); } } else { @@ -1302,9 +1304,10 @@ int iuse::purify_smart( player *p, item *it, bool, const tripoint & ) static void spawn_spores( const player &p ) { int spores_spawned = 0; - fungal_effects fe( *g, g->m ); - for( const tripoint &dest : closest_tripoints_first( p.pos(), 4 ) ) { - if( g->m.impassable( dest ) ) { + map &here = get_map(); + fungal_effects fe( *g, here ); + for( const tripoint &dest : closest_points_first( p.pos(), 4 ) ) { + if( here.impassable( dest ) ) { continue; } float dist = rl_dist( dest, p.pos() ); @@ -1426,7 +1429,7 @@ static void marloss_common( player &p, item &it, const trait_id ¤t_color ) } p.set_mutation( trait_THRESH_MARLOSS ); - g->m.ter_set( p.pos(), t_marloss ); + get_map().ter_set( p.pos(), t_marloss ); g->events().send( p.getID() ); p.add_msg_if_player( m_good, _( "You wake up in a marloss bush. Almost *cradled* in it, actually, as though it grew there for you." ) ); @@ -1566,8 +1569,9 @@ int iuse::mycus( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( m_good, _( "Even now, our fruits adapt to better serve local physiology." ) ); p->add_msg_if_player( m_good, _( "As, in time, shall we adapt to better welcome those who have not received us." ) );*/ - fungal_effects fe( *g, g->m ); - for( const tripoint &nearby_pos : g->m.points_in_radius( p->pos(), 3 ) ) { + map &here = get_map(); + fungal_effects fe( *g, here ); + for( const tripoint &nearby_pos : here.points_in_radius( p->pos(), 3 ) ) { fe.marlossify( nearby_pos ); } p->rem_addiction( add_type::MARLOSS_R ); @@ -1805,7 +1809,7 @@ int iuse::remove_all_mods( player *p, item *, bool, const tripoint & ) return 0; } - if( !loc->ammo_remaining() || g->unload( loc ) ) { + if( !loc->ammo_remaining() || p->unload( loc ) ) { item *mod = loc->contents.get_item_with( []( const item & e ) { return e.is_toolmod() && !e.is_irremovable(); @@ -1819,16 +1823,17 @@ int iuse::remove_all_mods( player *p, item *, bool, const tripoint & ) return 0; } -static bool good_fishing_spot( tripoint pos ) +static bool good_fishing_spot( tripoint pos, player *p ) { std::unordered_set fishable_locations = g->get_fishable_locations( 60, pos ); std::vector fishables = g->get_fishable_monsters( fishable_locations ); + map &here = get_map(); // isolated little body of water with no definite fish population - const oter_id &cur_omt = overmap_buffer.ter( ms_to_omt_copy( g->m.getabs( pos ) ) ); + const oter_id &cur_omt = overmap_buffer.ter( ms_to_omt_copy( here.getabs( pos ) ) ); std::string om_id = cur_omt.id().c_str(); - if( fishables.empty() && !g->m.has_flag( "CURRENT", pos ) && + if( fishables.empty() && !here.has_flag( "CURRENT", pos ) && om_id.find( "river_" ) == std::string::npos && !cur_omt->is_lake() && !cur_omt->is_lake_shore() ) { - g->u.add_msg_if_player( m_info, _( "You doubt you will have much luck catching fish here" ) ); + p->add_msg_if_player( m_info, _( "You doubt you will have much luck catching fish here" ) ); return false; } return true; @@ -1844,9 +1849,10 @@ int iuse::fishing_rod( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); return 0; } + map &here = get_map(); cata::optional found; - for( const tripoint &pnt : g->m.points_in_radius( p->pos(), 1 ) ) { - if( g->m.has_flag( flag_FISHABLE, pnt ) && good_fishing_spot( pnt ) ) { + for( const tripoint &pnt : here.points_in_radius( p->pos(), 1 ) ) { + if( here.has_flag( flag_FISHABLE, pnt ) && good_fishing_spot( pnt, p ) ) { found = pnt; break; } @@ -1864,6 +1870,7 @@ int iuse::fishing_rod( player *p, item *it, bool, const tripoint & ) int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) { + map &here = get_map(); if( !t ) { // Handle deploying fish trap. if( it->active ) { @@ -1895,16 +1902,16 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) } const tripoint pnt = *pnt_; - if( !g->m.has_flag( "FISHABLE", pnt ) ) { + if( !here.has_flag( "FISHABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't fish there!" ) ); return 0; } - if( !good_fishing_spot( pnt ) ) { + if( !good_fishing_spot( pnt, p ) ) { return 0; } it->active = true; it->set_age( 0_turns ); - g->m.add_item_or_charges( pnt, *it ); + here.add_item_or_charges( pnt, *it ); p->i_rem( it ); p->add_msg_if_player( m_info, _( "You place the fish trap, in three hours or so you may catch some fish." ) ); @@ -1920,7 +1927,7 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) if( it->age() > 3_hours ) { it->active = false; - if( !g->m.has_flag( "FISHABLE", pos ) ) { + if( !here.has_flag( "FISHABLE", pos ) ) { return 0; } @@ -1968,7 +1975,7 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) if( chosen_fish->fish_population <= 0 ) { g->catch_a_monster( chosen_fish, pos, p, 300_hours ); //catch the fish! } else { - g->m.add_item_or_charges( pos, item::make_corpse( chosen_fish->type->id, + here.add_item_or_charges( pos, item::make_corpse( chosen_fish->type->id, calendar::turn + rng( 0_turns, 3_hours ) ) ); } @@ -1985,7 +1992,7 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) //but it's not as comfortable as if you just put fishes in the same tile with the trap. //Also: corpses and comestibles do not rot in containers like this, but on the ground they will rot. //we don't know when it was caught so use a random turn - g->m.add_item_or_charges( pos, item::make_corpse( fish_mon, it->birthday() + rng( 0_turns, + here.add_item_or_charges( pos, item::make_corpse( fish_mon, it->birthday() + rng( 0_turns, 3_hours ) ) ); break; //this can happen only once } @@ -2011,8 +2018,9 @@ int iuse::extinguisher( player *p, item *it, bool, const tripoint & ) p->moves -= to_moves( 2_seconds ); + map &here = get_map(); // Reduce the strength of fire (if any) in the target tile. - g->m.add_field( dest, fd_extinguisher, 3, 10_turns ); + here.add_field( dest, fd_extinguisher, 3, 10_turns ); // Also spray monsters in that tile. if( monster *const mon_ptr = g->critter_at( dest, true ) ) { @@ -2023,14 +2031,15 @@ int iuse::extinguisher( player *p, item *it, bool, const tripoint & ) blind = true; critter.add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); } - if( g->u.sees( critter ) ) { + Character &player_character = get_player_character(); + if( player_character.sees( critter ) ) { p->add_msg_if_player( _( "The %s is sprayed!" ), critter.name() ); if( blind ) { p->add_msg_if_player( _( "The %s looks blinded." ), critter.name() ); } } if( critter.made_of( phase_id::LIQUID ) ) { - if( g->u.sees( critter ) ) { + if( player_character.sees( critter ) ) { p->add_msg_if_player( _( "The %s is frozen!" ), critter.name() ); } critter.apply_damage( p, bodypart_id( "torso" ), rng( 20, 60 ) ); @@ -2039,11 +2048,11 @@ int iuse::extinguisher( player *p, item *it, bool, const tripoint & ) } // Slightly reduce the strength of fire immediately behind the target tile. - if( g->m.passable( dest ) ) { + if( here.passable( dest ) ) { dest.x += ( dest.x - p->posx() ); dest.y += ( dest.y - p->posy() ); - g->m.mod_field_intensity( dest, fd_fire, std::min( 0 - rng( 0, 1 ) + rng( 0, 1 ), 0 ) ); + here.mod_field_intensity( dest, fd_fire, std::min( 0 - rng( 0, 1 ) + rng( 0, 1 ), 0 ) ); } return it->type->charges_to_use(); @@ -2066,7 +2075,7 @@ int iuse::rm13armor_off( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "Electro-reactive armor system: ONLINE." ) ); p->add_msg_if_player( _( "All systems nominal." ) ); it->convert( itype_id( oname ) ).active = true; - p->reset_encumbrance(); + p->calc_encumbrance(); return it->type->charges_to_use(); } } @@ -2086,7 +2095,7 @@ int iuse::rm13armor_on( player *p, item *it, bool t, const tripoint & ) p->add_msg_if_player( _( "Shutting down." ) ); p->add_msg_if_player( _( "Your RM13 combat armor turns off." ) ); it->convert( itype_id( oname ) ).active = false; - p->reset_encumbrance(); + p->calc_encumbrance(); } return it->type->charges_to_use(); } @@ -2401,11 +2410,13 @@ int iuse::hammer( player *p, item *it, bool, const tripoint & ) t_rdoor_boarded_damaged }; - const std::function f = [&allowed_ter_id]( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = + [&allowed_ter_id, &here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - const ter_id ter = g->m.ter( pnt ); + const ter_id ter = here.ter( pnt ); const bool is_allowed = allowed_ter_id.find( ter ) != allowed_ter_id.end(); return is_allowed; @@ -2417,7 +2428,7 @@ int iuse::hammer( player *p, item *it, bool, const tripoint & ) return 0; } const tripoint &pnt = *pnt_; - const ter_id type = g->m.ter( pnt ); + const ter_id type = here.ter( pnt ); if( !f( pnt ) ) { if( pnt == p->pos() ) { p->add_msg_if_player( _( "You try to hit yourself with the hammer." ) ); @@ -2465,13 +2476,14 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) f_coffin_c }; - const std::function f = [&allowed_ter_id, - &allowed_furn_id]( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = + [&allowed_ter_id, &allowed_furn_id, &here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - const ter_id ter = g->m.ter( pnt ); - const auto furn = g->m.furn( pnt ); + const ter_id ter = here.ter( pnt ); + const auto furn = here.furn( pnt ); const bool is_allowed = allowed_ter_id.find( ter ) != allowed_ter_id.end() || allowed_furn_id.find( furn ) != allowed_furn_id.end(); @@ -2484,8 +2496,8 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) return 0; } const tripoint &pnt = *pnt_; - const ter_id type = g->m.ter( pnt ); - const furn_id furn = g->m.furn( pnt ); + const ter_id type = here.ter( pnt ); + const furn_id furn = here.furn( pnt ); if( !f( pnt ) ) { if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "You attempt to pry open your wallet " @@ -2518,12 +2530,12 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) difficulty = 6; } else if( type == t_door_c ) { p->add_msg_if_player( m_info, _( "You notice the door is unlocked, so you simply open it." ) ); - g->m.ter_set( pnt, t_door_o ); + here.ter_set( pnt, t_door_o ); p->mod_moves( -100 ); return 0; } else if( type == t_door_c_peep ) { p->add_msg_if_player( m_info, _( "You notice the door is unlocked, so you simply open it." ) ); - g->m.ter_set( pnt, t_door_o_peep ); + here.ter_set( pnt, t_door_o_peep ); p->mod_moves( -100 ); return 0; } else if( type == t_manhole_cover ) { @@ -2580,19 +2592,19 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) if( dice( 4, difficulty ) < dice( 4, p->str_cur ) ) { p->add_msg_if_player( m_good, succ_action ); - if( g->m.furn( pnt ) == f_crate_c ) { - g->m.furn_set( pnt, f_crate_o ); - } else if( g->m.furn( pnt ) == f_coffin_c ) { - g->m.furn_set( pnt, f_coffin_o ); + if( here.furn( pnt ) == f_crate_c ) { + here.furn_set( pnt, f_crate_o ); + } else if( here.furn( pnt ) == f_coffin_c ) { + here.furn_set( pnt, f_coffin_o ); } else { - g->m.ter_set( pnt, new_type ); + here.ter_set( pnt, new_type ); } if( noisy ) { sounds::sound( pnt, 12, sounds::sound_t::combat, _( "crunch!" ), true, "tool", "crowbar" ); } if( type == t_manhole_cover ) { - g->m.spawn_item( pnt, itype_manhole_cover ); + here.spawn_item( pnt, itype_manhole_cover ); } if( type == t_door_locked_alarm ) { g->events().send( p->getID() ); @@ -2613,10 +2625,10 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) p->str_cur ) ) { p->add_msg_if_player( m_mixed, _( "You break the glass." ) ); sounds::sound( pnt, 24, sounds::sound_t::combat, _( "glass breaking!" ), true, "smash", "glass" ); - g->m.ter_set( pnt, t_window_frame ); - g->m.spawn_item( pnt, itype_sheet, 2 ); - g->m.spawn_item( pnt, itype_stick ); - g->m.spawn_item( pnt, itype_string_36 ); + here.ter_set( pnt, t_window_frame ); + here.spawn_item( pnt, itype_sheet, 2 ); + here.spawn_item( pnt, itype_stick ); + here.spawn_item( pnt, itype_string_36 ); return it->type->charges_to_use(); } } @@ -2646,10 +2658,11 @@ int iuse::makemound( player *p, item *it, bool t, const tripoint & ) return 0; } - if( g->m.has_flag( flag_PLOWABLE, pnt ) && !g->m.has_flag( flag_PLANT, pnt ) ) { + map &here = get_map(); + if( here.has_flag( flag_PLOWABLE, pnt ) && !here.has_flag( flag_PLANT, pnt ) ) { p->add_msg_if_player( _( "You start churning up the earth here." ) ); p->assign_activity( ACT_CHURN, 18000, -1, p->get_item_position( it ) ); - p->activity.placement = g->m.getabs( pnt ); + p->activity.placement = here.getabs( pnt ); return it->type->charges_to_use(); } else { p->add_msg_if_player( _( "You can't churn up this ground." ) ); @@ -2775,7 +2788,7 @@ static digging_moves_and_byproducts dig_pit_moves_and_byproducts( player *p, ite // Modify the number of moves based on the help. // TODO: this block of code is all over the place and could probably be consolidated. - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const int helpersize = p->get_num_crafting_helpers( 3 ); moves = moves * ( 1 - ( helpersize / 10 ) ); ter_id result_terrain; @@ -2799,19 +2812,20 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) } const tripoint dig_point = p->pos(); - const bool can_dig_here = g->m.has_flag( "DIGGABLE", dig_point ) && - !g->m.has_furn( dig_point ) && - g->m.tr_at( dig_point ).is_null() && - ( g->m.ter( dig_point ) == t_grave_new || g->m.i_at( dig_point ).empty() ) && - !g->m.veh_at( dig_point ); + map &here = get_map(); + const bool can_dig_here = here.has_flag( "DIGGABLE", dig_point ) && + !here.has_furn( dig_point ) && + !here.can_see_trap_at( dig_point, *p ) && + ( here.ter( dig_point ) == t_grave_new || here.i_at( dig_point ).empty() ) && + !here.veh_at( dig_point ); if( !can_dig_here ) { p->add_msg_if_player( _( "You can't dig a pit in this location. Ensure it is clear diggable ground with no items or obstacles." ) ); return 0; } - const bool can_deepen = g->m.has_flag( "DIGGABLE_CAN_DEEPEN", dig_point ); - const bool grave = g->m.ter( dig_point ) == t_grave; + const bool can_deepen = here.has_flag( "DIGGABLE_CAN_DEEPEN", dig_point ); + const bool grave = here.ter( dig_point ) == t_grave; if( !p->crafting_inventory().has_quality( qual_DIG, 2 ) ) { if( can_deepen ) { @@ -2823,8 +2837,8 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) } } - const std::function f = []( const tripoint & pnt ) { - return g->m.passable( pnt ); + const std::function f = [&here]( const tripoint & pnt ) { + return here.passable( pnt ); }; const cata::optional pnt_ = choose_adjacent_highlight( @@ -2842,28 +2856,28 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) } if( grave ) { - if( g->u.has_trait( trait_SPIRITUAL ) && !g->u.has_trait( trait_PSYCHOPATH ) && - g->u.query_yn( _( "Would you really touch the sacred resting place of the dead?" ) ) ) { + if( p->has_trait( trait_SPIRITUAL ) && !p->has_trait( trait_PSYCHOPATH ) && + p->query_yn( _( "Would you really touch the sacred resting place of the dead?" ) ) ) { add_msg( m_info, _( "Exhuming a grave is really against your beliefs." ) ); - g->u.add_morale( MORALE_GRAVEDIGGER, -50, -100, 48_hours, 12_hours ); + p->add_morale( MORALE_GRAVEDIGGER, -50, -100, 48_hours, 12_hours ); if( one_in( 3 ) ) { - g->u.vomit(); + p->vomit(); } - } else if( g->u.has_trait( trait_PSYCHOPATH ) ) { + } else if( p->has_trait( trait_PSYCHOPATH ) ) { p->add_msg_if_player( m_good, _( "Exhuming a grave is fun now, where there is no one to object." ) ); - g->u.add_morale( MORALE_GRAVEDIGGER, 25, 50, 2_hours, 1_hours ); - } else if( !g->u.has_trait( trait_EATDEAD ) && - !g->u.has_trait( trait_SAPROVORE ) ) { + p->add_morale( MORALE_GRAVEDIGGER, 25, 50, 2_hours, 1_hours ); + } else if( !p->has_trait( trait_EATDEAD ) && + !p->has_trait( trait_SAPROVORE ) ) { p->add_msg_if_player( m_bad, _( "Exhuming this grave is utterly disgusting!" ) ); - g->u.add_morale( MORALE_GRAVEDIGGER, -25, -50, 2_hours, 1_hours ); + p->add_morale( MORALE_GRAVEDIGGER, -25, -50, 2_hours, 1_hours ); if( one_in( 5 ) ) { p->vomit(); } } } - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = p->get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); break; @@ -2900,11 +2914,13 @@ int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) tripoint west = dig_point + point_west; tripoint east = dig_point + point_east; - const bool can_dig_here = g->m.has_flag( flag_DIGGABLE, dig_point ) && - !g->m.has_furn( dig_point ) && - g->m.tr_at( dig_point ).is_null() && g->m.i_at( dig_point ).empty() && !g->m.veh_at( dig_point ) && - ( g->m.has_flag( flag_CURRENT, north ) || g->m.has_flag( flag_CURRENT, south ) || - g->m.has_flag( flag_CURRENT, east ) || g->m.has_flag( flag_CURRENT, west ) ); + map &here = get_map(); + const bool can_dig_here = here.has_flag( flag_DIGGABLE, dig_point ) && + !here.has_furn( dig_point ) && + !here.can_see_trap_at( dig_point, *p ) && here.i_at( dig_point ).empty() && + !here.veh_at( dig_point ) && + ( here.has_flag( flag_CURRENT, north ) || here.has_flag( flag_CURRENT, south ) || + here.has_flag( flag_CURRENT, east ) || here.has_flag( flag_CURRENT, west ) ); if( !can_dig_here ) { p->add_msg_if_player( @@ -2912,8 +2928,8 @@ int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) return 0; } - const std::function f = []( const tripoint & pnt ) { - return g->m.passable( pnt ); + const std::function f = [&here]( const tripoint & pnt ) { + return here.passable( pnt ); }; const cata::optional pnt_ = choose_adjacent_highlight( @@ -2930,7 +2946,7 @@ int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) return 0; } - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = p->get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); break; @@ -2968,11 +2984,13 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) t_dirtmound }; - const std::function f = [&allowed_ter_id]( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = + [&allowed_ter_id, &here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - const ter_id type = g->m.ter( pnt ); + const ter_id type = here.ter( pnt ); return ( allowed_ter_id.find( type ) != allowed_ter_id.end() ); }; @@ -2982,7 +3000,7 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) return 0; } const tripoint &pnt = *pnt_; - const ter_id ter = g->m.ter( pnt ); + const ter_id ter = here.ter( pnt ); if( !f( pnt ) ) { if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "You decide not to bury yourself that early." ) ); @@ -3003,8 +3021,8 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) } else { return 0; } - const std::vector helpers = g->u.get_crafting_helpers(); - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const std::vector helpers = p->get_crafting_helpers(); + const int helpersize = p->get_num_crafting_helpers( 3 ); moves = moves * ( 1 - ( helpersize / 10 ) ); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); @@ -3030,7 +3048,7 @@ int iuse::clear_rubble( player *p, item *it, bool, const tripoint & ) return 0; } const std::function f = []( const tripoint & pnt ) { - return g->m.has_flag( "RUBBLE", pnt ); + return get_map().has_flag( "RUBBLE", pnt ); }; const cata::optional pnt_ = choose_adjacent_highlight( @@ -3045,12 +3063,12 @@ int iuse::clear_rubble( player *p, item *it, bool, const tripoint & ) } int bonus = std::max( it->get_quality( quality_id( "DIG" ) ) - 1, 1 ); - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = p->get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); break; } - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const int helpersize = p->get_num_crafting_helpers( 3 ); const int moves = to_moves( 30_seconds ) * ( 1 - ( helpersize / 10 ) ); player_activity act( ACT_CLEAR_RUBBLE, moves / bonus, bonus ); p->assign_activity( act ); @@ -3066,15 +3084,16 @@ int iuse::siphon( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); return 0; } - const std::function f = []( const tripoint & pnt ) { - const optional_vpart_position vp = g->m.veh_at( pnt ); + map &here = get_map(); + const std::function f = [&here]( const tripoint & pnt ) { + const optional_vpart_position vp = here.veh_at( pnt ); return !!vp; }; vehicle *v = nullptr; bool found_more_than_one = false; - for( const tripoint &pos : g->m.points_in_radius( g->u.pos(), 1 ) ) { - const optional_vpart_position vp = g->m.veh_at( pos ); + for( const tripoint &pos : here.points_in_radius( p->pos(), 1 ) ) { + const optional_vpart_position vp = here.veh_at( pos ); if( !vp ) { continue; } @@ -3096,7 +3115,7 @@ int iuse::siphon( player *p, item *it, bool, const tripoint & ) if( !pnt_ ) { return 0; } - const optional_vpart_position vp = g->m.veh_at( *pnt_ ); + const optional_vpart_position vp = here.veh_at( *pnt_ ); if( vp ) { v = &vp->vehicle(); } @@ -3337,23 +3356,24 @@ int iuse::jackhammer( player *p, item *it, bool, const tripoint &pos ) pnt = *pnt_; } - if( !g->m.has_flag( "MINEABLE", pnt ) ) { + map &here = get_map(); + if( !here.has_flag( "MINEABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't drill there." ) ); return 0; } - if( g->m.veh_at( pnt ) ) { + if( here.veh_at( pnt ) ) { p->add_msg_if_player( _( "There's a vehicle in the way!" ) ); return 0; } int moves = to_moves( 30_minutes ); - if( g->m.move_cost( pnt ) == 2 ) { + if( here.move_cost( pnt ) == 2 ) { // We're breaking up some flat surface like pavement, which is much easier moves /= 2; } - const std::vector helpers = g->u.get_crafting_helpers(); - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const std::vector helpers = p->get_crafting_helpers(); + const int helpersize = p->get_num_crafting_helpers( 3 ); moves *= ( 1 - ( helpersize / 10 ) ); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); @@ -3361,9 +3381,9 @@ int iuse::jackhammer( player *p, item *it, bool, const tripoint &pos ) } p->assign_activity( ACT_JACKHAMMER, moves, -1, p->get_item_position( it ) ); - p->activity.placement = g->m.getabs( pnt ); + p->activity.placement = here.getabs( pnt ); p->add_msg_if_player( _( "You start drilling into the %1$s with your %2$s." ), - g->m.tername( pnt ), it->tname() ); + here.tername( pnt ), it->tname() ); return it->type->charges_to_use(); } @@ -3405,7 +3425,7 @@ int iuse::pick_lock( player *p, item *it, bool, const tripoint &pos ) } you.assign_activity( lockpick_activity_actor( duration, item_location( you, it ), cata::nullopt, - g->m.getabs( *target ) ) ); + get_map().getabs( *target ) ) ); return it->type->charges_to_use(); } @@ -3433,24 +3453,25 @@ int iuse::pickaxe( player *p, item *it, bool, const tripoint &pos ) pnt = *pnt_; } - if( !g->m.has_flag( "MINEABLE", pnt ) ) { + map &here = get_map(); + if( !here.has_flag( "MINEABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't mine there." ) ); return 0; } - if( g->m.veh_at( pnt ) ) { + if( here.veh_at( pnt ) ) { p->add_msg_if_player( _( "There's a vehicle in the way!" ) ); return 0; } int moves = to_moves( 20_minutes ); moves += ( ( MAX_STAT + 4 ) - std::min( p->str_cur, MAX_STAT ) ) * to_moves( 5_minutes ); - if( g->m.move_cost( pnt ) == 2 ) { + if( here.move_cost( pnt ) == 2 ) { // We're breaking up some flat surface like pavement, which is much easier moves /= 2; } - const std::vector helpers = g->u.get_crafting_helpers(); - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const std::vector helpers = p->get_crafting_helpers(); + const int helpersize = p->get_num_crafting_helpers( 3 ); moves *= ( 1 - ( helpersize / 10 ) ); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); @@ -3459,9 +3480,9 @@ int iuse::pickaxe( player *p, item *it, bool, const tripoint &pos ) p->assign_activity( ACT_PICKAXE, moves, -1 ); p->activity.targets.push_back( item_location( *p, it ) ); - p->activity.placement = g->m.getabs( pnt ); + p->activity.placement = here.getabs( pnt ); p->add_msg_if_player( _( "You strike the %1$s with your %2$s." ), - g->m.tername( pnt ), it->tname() ); + here.tername( pnt ), it->tname() ); return 0; // handled when the activity finishes } @@ -3489,32 +3510,34 @@ int iuse::burrow( player *p, item *it, bool, const tripoint &pos ) pnt = *pnt_; } - if( !g->m.has_flag( "MINEABLE", pnt ) ) { + map &here = get_map(); + if( !here.has_flag( "MINEABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't burrow there." ) ); return 0; } - if( g->m.veh_at( pnt ) ) { + if( here.veh_at( pnt ) ) { p->add_msg_if_player( _( "There's a vehicle in the way!" ) ); return 0; } int moves = to_moves( 5_minutes ); moves += ( ( MAX_STAT + 3 ) - std::min( p->str_cur, MAX_STAT ) ) * to_moves( 2_minutes ); - if( g->m.move_cost( pnt ) == 2 ) { + if( here.move_cost( pnt ) == 2 ) { // We're breaking up some flat surface like pavement, which is much easier moves /= 2; } p->assign_activity( ACT_BURROW, moves, -1, 0 ); p->activity.placement = pnt; p->add_msg_if_player( _( "You start tearing into the %1$s with your %2$s." ), - g->m.tername( pnt ), it->tname() ); + here.tername( pnt ), it->tname() ); return 0; // handled when the activity finishes } int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) { + map &here = get_map(); if( t ) { // Every-turn use when it's on - const int rads = g->m.get_radiation( pos ); + const int rads = here.get_radiation( pos ); if( rads == 0 ) { return it->type->charges_to_use(); } @@ -3567,7 +3590,7 @@ int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) return 0; } const tripoint &pnt = *pnt_; - if( pnt == g->u.pos() ) { + if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "Your radiation level: %d mSv (%d mSv from items)" ), p->get_rad(), p->leak_level( "RADIOACTIVE" ) ); break; @@ -3582,7 +3605,7 @@ int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) } case 1: p->add_msg_if_player( m_info, _( "The ground's radiation level: %d mSv/h" ), - g->m.get_radiation( p->pos() ) ); + here.get_radiation( p->pos() ) ); break; case 2: p->add_msg_if_player( _( "The geiger counter's scan LED turns on." ) ); @@ -3620,17 +3643,19 @@ int iuse::can_goo( player *p, item *it, bool, const tripoint & ) int tries = 0; tripoint goop; goop.z = p->posz(); + map &here = get_map(); do { goop.x = p->posx() + rng( -2, 2 ); goop.y = p->posy() + rng( -2, 2 ); tries++; - } while( g->m.impassable( goop ) && tries < 10 ); + } while( here.impassable( goop ) && tries < 10 ); if( tries == 10 ) { return 0; } + Character &player_character = get_player_character(); if( monster *const mon_ptr = g->critter_at( goop ) ) { monster &critter = *mon_ptr; - if( g->u.sees( goop ) ) { + if( player_character.sees( goop ) ) { add_msg( _( "Black goo emerges from the canister and envelopes a %s!" ), critter.name() ); } @@ -3639,7 +3664,7 @@ int iuse::can_goo( player *p, item *it, bool, const tripoint & ) critter.set_speed_base( critter.get_speed_base() - rng( 5, 25 ) ); critter.set_hp( critter.get_speed() ); } else { - if( g->u.sees( goop ) ) { + if( player_character.sees( goop ) ) { add_msg( _( "Living black goo emerges from the canister!" ) ); } if( monster *const goo = g->place_critter_at( mon_blob, goop ) ) { @@ -3653,13 +3678,13 @@ int iuse::can_goo( player *p, item *it, bool, const tripoint & ) goop.x = p->posx() + rng( -2, 2 ); goop.y = p->posy() + rng( -2, 2 ); tries++; - found = g->m.passable( goop ) && g->m.tr_at( goop ).is_null(); + found = here.passable( goop ) && here.tr_at( goop ).is_null(); } while( !found && tries < 10 ); if( found ) { - if( g->u.sees( goop ) ) { + if( player_character.sees( goop ) ) { add_msg( m_warning, _( "A nearby splatter of goo forms into a goo pit." ) ); } - g->m.trap_set( goop, tr_goo ); + here.trap_set( goop, tr_goo ); } else { return 0; } @@ -3681,6 +3706,7 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) if( pos.x == -999 || pos.y == -999 ) { return 0; } + map &here = get_map(); if( t ) { // Simple timer effects // Vol 0 = only heard if you hold it sounds::sound( pos, 0, sounds::sound_t::electronic_speech, _( "Merged!" ), @@ -3696,12 +3722,13 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) auto modified_stat = current_stat + modify_by; current_stat = std::max( current_stat, std::min( 15, modified_stat ) ); }; + avatar &player_character = get_avatar(); switch( effect_roll ) { case 1: sounds::sound( pos, 100, sounds::sound_t::electronic_speech, _( "BUGFIXES!" ), true, "speech", it->typeId().str() ); explosion_handler::draw_explosion( pos, explosion_radius, c_light_cyan ); - for( const tripoint &dest : g->m.points_in_radius( pos, explosion_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, explosion_radius ) ) { monster *const mon = g->critter_at( dest, true ); if( mon && ( mon->type->in_species( species_INSECT ) || mon->is_hallucination() ) ) { mon->die_in_explosion( nullptr ); @@ -3713,7 +3740,7 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) sounds::sound( pos, 100, sounds::sound_t::electronic_speech, _( "BUFFS!" ), true, "speech", it->typeId().str() ); explosion_handler::draw_explosion( pos, explosion_radius, c_green ); - for( const tripoint &dest : g->m.points_in_radius( pos, explosion_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, explosion_radius ) ) { if( monster *const mon_ptr = g->critter_at( dest ) ) { monster &critter = *mon_ptr; critter.set_speed_base( @@ -3728,21 +3755,22 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) buff_stat( person->int_max, rng( 0, person->int_max / 2 ) ); /** @EFFECT_PER_MAX increases possible granade per buff for NPCs */ buff_stat( person->per_max, rng( 0, person->per_max / 2 ) ); - } else if( g->u.pos() == dest ) { + } else if( player_character.pos() == dest ) { /** @EFFECT_STR_MAX increases possible granade str buff */ - buff_stat( g->u.str_max, rng( 0, g->u.str_max / 2 ) ); + buff_stat( player_character.str_max, rng( 0, player_character.str_max / 2 ) ); /** @EFFECT_DEX_MAX increases possible granade dex buff */ - buff_stat( g->u.dex_max, rng( 0, g->u.dex_max / 2 ) ); + buff_stat( player_character.dex_max, rng( 0, player_character.dex_max / 2 ) ); /** @EFFECT_INT_MAX increases possible granade int buff */ - buff_stat( g->u.int_max, rng( 0, g->u.int_max / 2 ) ); + buff_stat( player_character.int_max, rng( 0, player_character.int_max / 2 ) ); /** @EFFECT_PER_MAX increases possible granade per buff */ - buff_stat( g->u.per_max, rng( 0, g->u.per_max / 2 ) ); - g->u.recalc_hp(); - for( const bodypart_id &bp : g->u.get_all_body_parts() ) { - g->u.set_part_hp_cur( bp, g->u.get_part_hp_cur( bp ) * rng_float( 1, 1.2 ) ); - const int hp_max = g->u.get_part_hp_max( bp ); - if( g->u.get_part_hp_cur( bp ) > hp_max ) { - g->u.set_part_hp_cur( bp, hp_max ); + buff_stat( player_character.per_max, rng( 0, player_character.per_max / 2 ) ); + player_character.recalc_hp(); + for( const bodypart_id &bp : player_character.get_all_body_parts() ) { + player_character.set_part_hp_cur( bp, player_character.get_part_hp_cur( bp ) * rng_float( 1, + 1.2 ) ); + const int hp_max = player_character.get_part_hp_max( bp ); + if( player_character.get_part_hp_cur( bp ) > hp_max ) { + player_character.set_part_hp_cur( bp, hp_max ); } } } @@ -3753,7 +3781,7 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) sounds::sound( pos, 100, sounds::sound_t::electronic_speech, _( "NERFS!" ), true, "speech", it->typeId().str() ); explosion_handler::draw_explosion( pos, explosion_radius, c_red ); - for( const tripoint &dest : g->m.points_in_radius( pos, explosion_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, explosion_radius ) ) { if( monster *const mon_ptr = g->critter_at( dest ) ) { monster &critter = *mon_ptr; critter.set_speed_base( @@ -3768,20 +3796,20 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) person->int_max -= rng( 0, person->int_max / 2 ); /** @EFFECT_PER_MAX increases possible granade per debuff for NPCs (NEGATIVE) */ person->per_max -= rng( 0, person->per_max / 2 ); - } else if( g->u.pos() == dest ) { + } else if( player_character.pos() == dest ) { /** @EFFECT_STR_MAX increases possible granade str debuff (NEGATIVE) */ - g->u.str_max -= rng( 0, g->u.str_max / 2 ); + player_character.str_max -= rng( 0, player_character.str_max / 2 ); /** @EFFECT_DEX_MAX increases possible granade dex debuff (NEGATIVE) */ - g->u.dex_max -= rng( 0, g->u.dex_max / 2 ); + player_character.dex_max -= rng( 0, player_character.dex_max / 2 ); /** @EFFECT_INT_MAX increases possible granade int debuff (NEGATIVE) */ - g->u.int_max -= rng( 0, g->u.int_max / 2 ); + player_character.int_max -= rng( 0, player_character.int_max / 2 ); /** @EFFECT_PER_MAX increases possible granade per debuff (NEGATIVE) */ - g->u.per_max -= rng( 0, g->u.per_max / 2 ); - g->u.recalc_hp(); - for( const bodypart_id &bp : g->u.get_all_body_parts() ) { - const int hp_cur = g->u.get_part_hp_cur( bp ); + player_character.per_max -= rng( 0, player_character.per_max / 2 ); + player_character.recalc_hp(); + for( const bodypart_id &bp : player_character.get_all_body_parts() ) { + const int hp_cur = player_character.get_part_hp_cur( bp ); if( hp_cur > 0 ) { - g->u.set_part_hp_cur( bp, rng( 1, hp_cur ) ); + player_character.set_part_hp_cur( bp, rng( 1, hp_cur ) ); } } } @@ -3792,7 +3820,7 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) sounds::sound( pos, 100, sounds::sound_t::electronic_speech, _( "REVERTS!" ), true, "speech", it->typeId().str() ); explosion_handler::draw_explosion( pos, explosion_radius, c_pink ); - for( const tripoint &dest : g->m.points_in_radius( pos, explosion_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, explosion_radius ) ) { if( monster *const mon_ptr = g->critter_at( dest ) ) { monster &critter = *mon_ptr; critter.set_speed_base( critter.type->speed ); @@ -3800,9 +3828,9 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) critter.clear_effects(); } else if( npc *const person = g->critter_at( dest ) ) { person->environmental_revert_effect(); - } else if( g->u.pos() == dest ) { - g->u.environmental_revert_effect(); - do_purify( g->u ); + } else if( player_character.pos() == dest ) { + player_character.environmental_revert_effect(); + do_purify( player_character ); } } break; @@ -3810,9 +3838,9 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) sounds::sound( pos, 100, sounds::sound_t::electronic_speech, _( "BEES!" ), true, "speech", it->typeId().str() ); explosion_handler::draw_explosion( pos, explosion_radius, c_yellow ); - for( const tripoint &dest : g->m.points_in_radius( pos, explosion_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, explosion_radius ) ) { if( one_in( 5 ) && !g->critter_at( dest ) ) { - g->m.add_field( dest, fd_bees, rng( 1, 3 ) ); + here.add_field( dest, fd_bees, rng( 1, 3 ) ); } } break; @@ -3840,8 +3868,9 @@ int iuse::acidbomb_act( player *p, item *it, bool, const tripoint &pos ) { if( !p->has_item( *it ) ) { it->charges = -1; - for( const tripoint &tmp : g->m.points_in_radius( pos.x == -999 ? p->pos() : pos, 1 ) ) { - g->m.add_field( tmp, fd_acid, 3 ); + map &here = get_map(); + for( const tripoint &tmp : here.points_in_radius( pos.x == -999 ? p->pos() : pos, 1 ) ) { + here.add_field( tmp, fd_acid, 3 ); } return 1; } @@ -3861,17 +3890,18 @@ int iuse::grenade_inc_act( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( m_info, _( "You've already released the handle, try throwing it instead." ) ); return 0; } else { // blow up + map &here = get_map(); int num_flames = rng( 3, 5 ); for( int current_flame = 0; current_flame < num_flames; current_flame++ ) { tripoint dest( pos + point( rng( -5, 5 ), rng( -5, 5 ) ) ); std::vector flames = line_to( pos, dest, 0, 0 ); for( auto &flame : flames ) { - g->m.add_field( flame, fd_fire, rng( 0, 2 ) ); + here.add_field( flame, fd_fire, rng( 0, 2 ) ); } } explosion_handler::explosion( pos, 8, 0.8, true ); - for( const tripoint &dest : g->m.points_in_radius( pos, 2 ) ) { - g->m.add_field( dest, fd_incendiary, 3 ); + for( const tripoint &dest : here.points_in_radius( pos, 2 ) ) { + here.add_field( dest, fd_incendiary, 3 ); } } @@ -3904,6 +3934,13 @@ int iuse::molotov_lit( player *p, item *it, bool t, const tripoint &pos ) { if( pos.x == -999 || pos.y == -999 ) { return 0; + } else if( !t ) { + map &here = get_map(); + for( const tripoint &pt : here.points_in_radius( pos, 1, 0 ) ) { + const int intensity = 1 + one_in( 3 ) + one_in( 5 ); + here.add_field( pt, fd_fire, intensity ); + } + return 1; } else if( it->charges > 0 ) { p->add_msg_if_player( m_info, _( "You've already lit the %s, try throwing it instead." ), it->tname() ); @@ -3914,13 +3951,7 @@ int iuse::molotov_lit( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( _( "Your lit Molotov goes out." ) ); it->convert( itype_molotov ).active = false; } - } else { - if( !t ) { - for( auto &pt : g->m.points_in_radius( pos, 1, 0 ) ) { - const int intensity = 1 + one_in( 3 ) + one_in( 5 ); - g->m.add_field( pt, fd_fire, intensity ); - } - } + return 0; } return 0; } @@ -4037,7 +4068,7 @@ int iuse::pheromone( player *p, item *it, bool, const tripoint &pos ) p->moves -= 15; int converts = 0; - for( const tripoint &dest : g->m.points_in_radius( pos, 4 ) ) { + for( const tripoint &dest : get_map().points_in_radius( pos, 4 ) ) { monster *const mon_ptr = g->critter_at( dest, true ); if( !mon_ptr ) { continue; @@ -4050,7 +4081,7 @@ int iuse::pheromone( player *p, item *it, bool, const tripoint &pos ) } } - if( g->u.sees( *p ) ) { + if( get_player_character().sees( *p ) ) { if( converts == 0 ) { add_msg( _( "…but nothing happens." ) ); } else if( converts == 1 ) { @@ -4072,7 +4103,7 @@ int iuse::portal( player *p, item *it, bool, const tripoint & ) return 0; } tripoint t( p->posx() + rng( -2, 2 ), p->posy() + rng( -2, 2 ), p->posz() ); - g->m.trap_set( t, tr_portal ); + get_map().trap_set( t, tr_portal ); return it->type->charges_to_use(); } @@ -4266,7 +4297,8 @@ static std::string get_music_description() return _( "a sweet guitar solo!" ); } -void iuse::play_music( player &p, const tripoint &source, const int volume, const int max_morale ) +void iuse::play_music( Character &p, const tripoint &source, const int volume, + const int max_morale ) { // TODO: what about other "player", e.g. when a NPC is listening or when the PC is listening, // the other characters around should be able to profit as well. @@ -4442,7 +4474,7 @@ int iuse::gasmask( player *p, item *it, bool t, const tripoint &pos ) if( t ) { // Normal use if( p->is_worn( *it ) ) { // calculate amount of absorbed gas per filter charge - const field &gasfield = g->m.field_at( pos ); + const field &gasfield = get_map().field_at( pos ); for( auto &dfield : gasfield ) { const field_entry &entry = dfield.second; if( entry.get_gas_absorption_factor() > 0 ) { @@ -4725,7 +4757,7 @@ int iuse::dog_whistle( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You blow your dog whistle." ) ); for( monster &critter : g->all_monsters() ) { if( critter.friendly != 0 && critter.has_flag( MF_DOGFOOD ) ) { - bool u_see = g->u.sees( critter ); + bool u_see = get_player_character().sees( critter ); if( critter.has_effect( effect_docile ) ) { if( u_see ) { p->add_msg_if_player( _( "Your %s looks ready to attack." ), critter.name() ); @@ -4744,9 +4776,10 @@ int iuse::dog_whistle( player *p, item *it, bool, const tripoint & ) int iuse::call_of_tindalos( player *p, item *it, bool, const tripoint & ) { - for( const tripoint &dest : g->m.points_in_radius( p->pos(), 12 ) ) { - if( g->m.is_cornerfloor( dest ) ) { - g->m.add_field( dest, fd_tindalos_rift, 3 ); + map &here = get_map(); + for( const tripoint &dest : here.points_in_radius( p->pos(), 12 ) ) { + if( here.is_cornerfloor( dest ) ) { + here.add_field( dest, fd_tindalos_rift, 3 ); add_msg( m_info, _( "You hear a low-pitched echoing howl." ) ); } } @@ -4770,7 +4803,7 @@ int iuse::blood_draw( player *p, item *it, bool, const tripoint & ) item blood( "blood", calendar::turn ); bool drew_blood = false; bool acid_blood = false; - for( item &map_it : g->m.i_at( point( p->posx(), p->posy() ) ) ) { + for( item &map_it : get_map().i_at( point( p->posx(), p->posy() ) ) ) { if( map_it.is_corpse() && query_yn( _( "Draw blood from %s?" ), colorize( map_it.tname(), map_it.color_in_inventory() ) ) ) { @@ -4826,7 +4859,7 @@ int iuse::mind_splicer( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); return 0; } - for( item &map_it : g->m.i_at( point( p->posx(), p->posy() ) ) ) { + for( item &map_it : get_map().i_at( point( p->posx(), p->posy() ) ) ) { if( map_it.typeId() == itype_rmi2_corpse && query_yn( _( "Use the mind splicer kit on the %s?" ), colorize( map_it.tname(), map_it.color_in_inventory() ) ) ) { @@ -4859,7 +4892,7 @@ int iuse::mind_splicer( player *p, item *it, bool, const tripoint & ) return 0; } -void iuse::cut_log_into_planks( player &p ) +void iuse::cut_log_into_planks( Character &p ) { if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); @@ -4869,7 +4902,7 @@ void iuse::cut_log_into_planks( player &p ) p.add_msg_if_player( _( "You cut the log into planks." ) ); p.assign_activity( ACT_CHOP_PLANKS, moves, -1 ); - p.activity.placement = g->m.getabs( p.pos() ); + p.activity.placement = get_map().getabs( p.pos() ); } int iuse::lumber( player *p, item *it, bool t, const tripoint & ) @@ -4881,10 +4914,11 @@ int iuse::lumber( player *p, item *it, bool t, const tripoint & ) p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); return 0; } + map &here = get_map(); // Check if player is standing on any lumber - for( item &i : g->m.i_at( p->pos() ) ) { + for( item &i : here.i_at( p->pos() ) ) { if( i.typeId() == itype_log ) { - g->m.i_rem( p->pos(), &i ); + here.i_rem( p->pos(), &i ); cut_log_into_planks( *p ); return it->type->charges_to_use(); } @@ -4918,7 +4952,7 @@ static int chop_moves( player *p, item *it ) const int attr = it->has_flag( "POWERED" ) ? p->dex_cur : p->str_cur; int moves = to_moves( time_duration::from_minutes( 60 - attr ) / std::pow( 2, quality - 1 ) ); - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const int helpersize = p->get_num_crafting_helpers( 3 ); moves = moves * ( 1 - ( helpersize / 10 ) ); return moves; } @@ -4932,11 +4966,12 @@ int iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); return 0; } - const std::function f = []( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = [&here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - return g->m.has_flag( "TREE", pnt ); + return here.has_flag( "TREE", pnt ); }; const cata::optional pnt_ = choose_adjacent_highlight( @@ -4954,13 +4989,13 @@ int iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) return 0; } int moves = chop_moves( p, it ); - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = p->get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); break; } p->assign_activity( ACT_CHOP_TREE, moves, -1, p->get_item_position( it ) ); - p->activity.placement = g->m.getabs( pnt ); + p->activity.placement = here.getabs( pnt ); return it->type->charges_to_use(); } @@ -4979,8 +5014,9 @@ int iuse::chop_logs( player *p, item *it, bool t, const tripoint & ) t_trunk, t_stump }; - const std::function f = [&allowed_ter_id]( const tripoint & pnt ) { - const ter_id type = g->m.ter( pnt ); + map &here = get_map(); + const std::function f = [&allowed_ter_id, &here]( const tripoint & pnt ) { + const ter_id type = here.ter( pnt ); const bool is_allowed_terrain = allowed_ter_id.find( type ) != allowed_ter_id.end(); return is_allowed_terrain; }; @@ -4997,13 +5033,13 @@ int iuse::chop_logs( player *p, item *it, bool t, const tripoint & ) } int moves = chop_moves( p, it ); - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = p->get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); break; } p->assign_activity( ACT_CHOP_LOGS, moves, -1, p->get_item_position( it ) ); - p->activity.placement = g->m.getabs( pnt ); + p->activity.placement = here.getabs( pnt ); return it->type->charges_to_use(); } @@ -5045,13 +5081,14 @@ int iuse::oxytorch( player *p, item *it, bool, const tripoint & ) f_rack }; - const std::function f = [&allowed_ter_id, - &allowed_furn_id]( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = + [&allowed_ter_id, &allowed_furn_id, &here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - const ter_id ter = g->m.ter( pnt ); - const auto furn = g->m.furn( pnt ); + const ter_id ter = here.ter( pnt ); + const auto furn = here.furn( pnt ); const bool is_allowed = ( allowed_ter_id.find( ter ) != allowed_ter_id.end() ) || ( allowed_furn_id.find( furn ) != allowed_furn_id.end() ); @@ -5064,8 +5101,8 @@ int iuse::oxytorch( player *p, item *it, bool, const tripoint & ) return 0; } const tripoint &pnt = *pnt_; - const ter_id ter = g->m.ter( pnt ); - const furn_id furn = g->m.furn( pnt ); + const ter_id ter = here.ter( pnt ); + const furn_id furn = here.furn( pnt ); if( !f( pnt ) ) { if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "Yuck. Acetylene gas smells weird." ) ); @@ -5135,13 +5172,14 @@ int iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) const std::set allowed_furn_id { f_rack }; - const std::function f = [&allowed_ter_id, - &allowed_furn_id]( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = + [&allowed_ter_id, &allowed_furn_id, &here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - const ter_id ter = g->m.ter( pnt ); - const auto furn = g->m.furn( pnt ); + const ter_id ter = here.ter( pnt ); + const auto furn = here.furn( pnt ); const bool is_allowed = ( allowed_ter_id.find( ter ) != allowed_ter_id.end() ) || ( allowed_furn_id.find( furn ) != allowed_furn_id.end() ); @@ -5154,7 +5192,7 @@ int iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) return 0; } const tripoint &pnt = *pnt_; - const ter_id ter = g->m.ter( pnt ); + const ter_id ter = here.ter( pnt ); if( !f( pnt ) ) { if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "Why would you do that?" ) ); @@ -5166,7 +5204,7 @@ int iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) } int moves; - if( ter == t_chainfence_posts || g->m.furn( pnt ) == f_rack ) { + if( ter == t_chainfence_posts || here.furn( pnt ) == f_rack ) { moves = to_moves( 2_minutes ); } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { moves = to_moves( 5_minutes ); @@ -5196,11 +5234,13 @@ int iuse::boltcutters( player *p, item *it, bool, const tripoint & ) t_chaingate_l, t_chainfence }; - const std::function f = [&allowed_ter_id]( const tripoint & pnt ) { - if( pnt == g->u.pos() ) { + map &here = get_map(); + const std::function f = + [&allowed_ter_id, &here, p]( const tripoint & pnt ) { + if( pnt == p->pos() ) { return false; } - const ter_id ter = g->m.ter( pnt ); + const ter_id ter = here.ter( pnt ); const bool is_allowed = allowed_ter_id.find( ter ) != allowed_ter_id.end(); return is_allowed; }; @@ -5211,7 +5251,7 @@ int iuse::boltcutters( player *p, item *it, bool, const tripoint & ) return 0; } const tripoint &pnt = *pnt_; - const ter_id type = g->m.ter( pnt ); + const ter_id type = here.ter( pnt ); if( !f( pnt ) ) { if( pnt == p->pos() ) { p->add_msg_if_player( m_info, @@ -5224,15 +5264,15 @@ int iuse::boltcutters( player *p, item *it, bool, const tripoint & ) if( type == t_chaingate_l ) { p->moves -= to_moves( 1_seconds ); - g->m.ter_set( pnt, t_chaingate_c ); + here.ter_set( pnt, t_chaingate_c ); sounds::sound( pnt, 5, sounds::sound_t::combat, _( "Gachunk!" ), true, "tool", "boltcutters" ); - g->m.spawn_item( point( p->posx(), p->posy() ), "scrap", 3 ); + here.spawn_item( point( p->posx(), p->posy() ), "scrap", 3 ); } else if( type == t_chainfence ) { p->moves -= to_moves( 5_seconds ); - g->m.ter_set( pnt, t_chainfence_posts ); + here.ter_set( pnt, t_chainfence_posts ); sounds::sound( pnt, 5, sounds::sound_t::combat, _( "Snick, snick, gachunk!" ), true, "tool", "boltcutters" ); - g->m.spawn_item( pnt, "wire", 20 ); + here.spawn_item( pnt, "wire", 20 ); } else { return 0; } @@ -5259,9 +5299,10 @@ int iuse::mop( player *p, item *it, bool, const tripoint & ) fd_slime, fd_sludge }; - const std::function f = [&to_check]( const tripoint & pnt ) { - if( !g->m.has_flag( "LIQUIDCONT", pnt ) ) { - map_stack items = g->m.i_at( pnt ); + map &here = get_map(); + const std::function f = [&to_check, &here]( const tripoint & pnt ) { + if( !here.has_flag( "LIQUIDCONT", pnt ) ) { + map_stack items = here.i_at( pnt ); auto found = std::find_if( items.begin(), items.end(), []( const item & it ) { return it.made_of( phase_id::LIQUID ); } ); @@ -5269,13 +5310,13 @@ int iuse::mop( player *p, item *it, bool, const tripoint & ) return true; } } - field &fld = g->m.field_at( pnt ); + field &fld = here.field_at( pnt ); for( field_type_id fid : to_check ) { if( fld.find_field_c( fid ) ) { return true; } } - if( const optional_vpart_position vp = g->m.veh_at( pnt ) ) { + if( const optional_vpart_position vp = here.veh_at( pnt ) ) { vehicle *const veh = &vp->vehicle(); std::vector parts_here = veh->parts_at_relative( vp->mount(), true ); for( int elem : parts_here ) { @@ -5313,9 +5354,9 @@ int iuse::mop( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You move the mop around, unsure whether it's doing any good." ) ); p->moves -= 15; if( one_in( 3 ) ) { - g->m.mop_spills( pnt ); + here.mop_spills( pnt ); } - } else if( g->m.mop_spills( pnt ) ) { + } else if( here.mop_spills( pnt ) ) { p->add_msg_if_player( m_info, _( "You mop up the spill." ) ); p->moves -= 15; } else { @@ -5348,6 +5389,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) num_used += rng( 1, art->effects_activated.size() - num_used ); } + map &here = get_map(); std::vector effects = art->effects_activated; for( size_t i = 0; i < num_used && !effects.empty(); i++ ) { const art_effect_active used = random_entry_removed( effects ); @@ -5368,7 +5410,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) for( int n = 0; n < dist; n++ ) { bolt.x += dir.x; bolt.y += dir.y; - g->m.add_field( {bolt, p->posz()}, fd_electricity, rng( 2, 3 ) ); + here.add_field( {bolt, p->posz()}, fd_electricity, rng( 2, 3 ) ); if( one_in( 4 ) ) { if( dir.x == 0 ) { dir.x = rng( 0, 1 ) * 2 - 1; @@ -5413,9 +5455,9 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) case AEA_BLOOD: { bool blood = false; - for( const tripoint &tmp : g->m.points_in_radius( p->pos(), 4 ) ) { - if( !one_in( 4 ) && g->m.add_field( tmp, fd_blood, 3 ) && - ( blood || g->u.sees( tmp ) ) ) { + for( const tripoint &tmp : here.points_in_radius( p->pos(), 4 ) ) { + if( !one_in( 4 ) && here.add_field( tmp, fd_blood, 3 ) && + ( blood || get_player_character().sees( tmp ) ) ) { blood = true; } } @@ -5428,14 +5470,14 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) case AEA_FATIGUE: { p->add_msg_if_player( m_warning, _( "The fabric of space seems to decay." ) ); point p2( rng( p->posx() - 3, p->posx() + 3 ), rng( p->posy() - 3, p->posy() + 3 ) ); - g->m.add_field( {p2, p->posz()}, fd_fatigue, rng( 1, 2 ) ); + here.add_field( {p2, p->posz()}, fd_fatigue, rng( 1, 2 ) ); } break; case AEA_ACIDBALL: { if( const cata::optional acidball = g->look_around() ) { - for( const tripoint &tmp : g->m.points_in_radius( *acidball, 1 ) ) { - g->m.add_field( tmp, fd_acid, rng( 2, 3 ) ); + for( const tripoint &tmp : here.points_in_radius( *acidball, 1 ) ) { + here.add_field( tmp, fd_acid, rng( 2, 3 ) ); } } } @@ -5444,12 +5486,12 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) case AEA_PULSE: sounds::sound( p->pos(), 30, sounds::sound_t::combat, _( "The earth shakes!" ), true, "misc", "earthquake" ); - for( const tripoint &pt : g->m.points_in_radius( p->pos(), 2 ) ) { - g->m.bash( pt, 40 ); - g->m.bash( pt, 40 ); // Multibash effect, so that doors &c will fall - g->m.bash( pt, 40 ); - if( g->m.is_bashable( pt ) && rng( 1, 10 ) >= 3 ) { - g->m.bash( pt, 999, false, true ); + for( const tripoint &pt : here.points_in_radius( p->pos(), 2 ) ) { + here.bash( pt, 40 ); + here.bash( pt, 40 ); // Multibash effect, so that doors &c will fall + here.bash( pt, 40 ); + if( here.is_bashable( pt ) && rng( 1, 10 ) >= 3 ) { + here.bash( pt, 999, false, true ); } } break; @@ -5460,7 +5502,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) break; case AEA_CONFUSED: - for( const tripoint &dest : g->m.points_in_radius( p->pos(), 8 ) ) { + for( const tripoint &dest : here.points_in_radius( p->pos(), 8 ) ) { if( monster *const mon = g->critter_at( dest, true ) ) { mon->add_effect( effect_stunned, rng( 5_turns, 15_turns ) ); } @@ -5468,7 +5510,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) break; case AEA_ENTRANCE: - for( const tripoint &dest : g->m.points_in_radius( p->pos(), 8 ) ) { + for( const tripoint &dest : here.points_in_radius( p->pos(), 8 ) ) { monster *const mon = g->critter_at( dest, true ); if( mon && mon->friendly == 0 && rng( 0, 600 ) > mon->get_hp() ) { mon->make_friendly(); @@ -5529,8 +5571,8 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) case AEA_RADIATION: add_msg( m_warning, _( "Horrible gases are emitted!" ) ); - for( const tripoint &dest : g->m.points_in_radius( p->pos(), 1 ) ) { - g->m.add_field( dest, fd_nuke_gas, rng( 2, 3 ) ); + for( const tripoint &dest : here.points_in_radius( p->pos(), 1 ) ) { + here.add_field( dest, fd_nuke_gas, rng( 2, 3 ) ); } break; @@ -5555,10 +5597,10 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) case AEA_FIRESTORM: { p->add_msg_if_player( m_bad, _( "Fire rains down around you!" ) ); - std::vector ps = closest_tripoints_first( p->pos(), 3 ); + std::vector ps = closest_points_first( p->pos(), 3 ); for( auto p_it : ps ) { if( !one_in( 3 ) ) { - g->m.add_field( p_it, fd_fire, 1 + rng( 0, 1 ) * rng( 0, 1 ), 3_minutes ); + here.add_field( p_it, fd_fire, 1 + rng( 0, 1 ) * rng( 0, 1 ), 3_minutes ); } } break; @@ -5617,7 +5659,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) monp.x = ( one_in( 2 ) ? p->posx() - 5 : p->posx() + 5 ); monp.y = rng( p->posy() - 5, p->posy() + 5 ); } - if( !g->m.sees( monp, p->pos(), 10 ) ) { + if( !here.sees( monp, p->pos(), 10 ) ) { continue; } if( monster *const spawned = g->place_critter_at( mon_shadow, monp ) ) { @@ -5669,25 +5711,26 @@ int iuse::spray_can( player *p, item *it, bool, const tripoint & ) return handle_ground_graffiti( *p, it, _( "Spray what?" ), dest_.value() ); } -int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix, +int iuse::handle_ground_graffiti( Character &p, item *it, const std::string &prefix, const tripoint &where ) { + map &here = get_map(); string_input_popup popup; std::string message = popup .title( prefix + " " + _( "(To delete, clear the text and confirm)" ) ) - .text( g->m.has_graffiti_at( where ) ? g->m.graffiti_at( where ) : std::string() ) + .text( here.has_graffiti_at( where ) ? here.graffiti_at( where ) : std::string() ) .identifier( "graffiti" ) .query_string(); if( popup.canceled() ) { return 0; } - bool grave = g->m.ter( where ) == t_grave_new; + bool grave = here.ter( where ) == t_grave_new; int move_cost; if( message.empty() ) { - if( g->m.has_graffiti_at( where ) ) { - move_cost = 3 * g->m.graffiti_at( where ).length(); - g->m.delete_graffiti( where ); + if( here.has_graffiti_at( where ) ) { + move_cost = 3 * here.graffiti_at( where ).length(); + here.delete_graffiti( where ); if( grave ) { p.add_msg_if_player( m_info, _( "You blur the inscription on the grave." ) ); } else { @@ -5697,7 +5740,7 @@ int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix return 0; } } else { - g->m.set_graffiti( where, message ); + here.set_graffiti( where, message ); if( grave ) { p.add_msg_if_player( m_info, _( "You carve an inscription on the grave." ) ); } else { @@ -5753,7 +5796,7 @@ int iuse::heatpack( player *p, item *it, bool, const tripoint & ) int iuse::heat_food( player *p, item *it, bool, const tripoint & ) { - if( g->m.has_nearby_fire( p->pos() ) ) { + if( get_map().has_nearby_fire( p->pos() ) ) { heat_item( *p ); } else if( p->has_active_bionic( bio_tools ) && p->get_power_level() > 10_kJ && query_yn( _( "There is no fire around, use your integrated toolset instead?" ) ) ) { @@ -5803,7 +5846,7 @@ int iuse::towel( player *p, item *it, bool t, const tripoint & ) return towel_common( p, it, t ); } -int iuse::towel_common( player *p, item *it, bool t ) +int iuse::towel_common( Character *p, item *it, bool t ) { if( t ) { // Continuous usage, do nothing as not initiated by the player, this is for @@ -5881,21 +5924,22 @@ int iuse::unfold_generic( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); return 0; } - vehicle *veh = g->m.add_vehicle( vproto_id( "none" ), p->pos(), 0, 0, 0, false ); + map &here = get_map(); + vehicle *veh = here.add_vehicle( vproto_id( "none" ), p->pos(), 0, 0, 0, false ); if( veh == nullptr ) { p->add_msg_if_player( m_info, _( "There's no room to unfold the %s." ), it->tname() ); return 0; } veh->name = it->get_var( "vehicle_name" ); if( !veh->restore( it->get_var( "folding_bicycle_parts" ) ) ) { - g->m.destroy_vehicle( veh ); + here.destroy_vehicle( veh ); return 0; } const bool can_float = size( veh->get_avail_parts( "FLOATS" ) ) > 2; - const auto invalid_pos = []( const tripoint & pp, bool can_float ) { - return ( g->m.has_flag_ter( TFLAG_DEEP_WATER, pp ) && !can_float ) || - g->m.veh_at( pp ) || g->m.impassable( pp ); + const auto invalid_pos = [&here]( const tripoint & pp, bool can_float ) { + return ( here.has_flag_ter( TFLAG_DEEP_WATER, pp ) && !can_float ) || + here.veh_at( pp ) || here.impassable( pp ); }; for( const vpart_reference &vp : veh->get_all_parts() ) { if( vp.info().location != "structure" ) { @@ -5904,12 +5948,12 @@ int iuse::unfold_generic( player *p, item *it, bool, const tripoint & ) const tripoint pp = vp.pos(); if( invalid_pos( pp, can_float ) ) { p->add_msg_if_player( m_info, _( "There's no room to unfold the %s." ), it->tname() ); - g->m.destroy_vehicle( veh ); + here.destroy_vehicle( veh ); return 0; } } - g->m.add_vehicle_to_cache( veh ); + here.add_vehicle_to_cache( veh ); std::string unfold_msg = it->get_var( "unfold_msg" ); if( unfold_msg.empty() ) { @@ -6088,7 +6132,8 @@ int iuse::gun_repair( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You need a mechanics skill of 2 to use this repair kit." ) ); return 0; } - item_location loc = game_menus::inv::titled_menu( g->u, ( "Select the firearm to repair" ) ); + item_location loc = game_menus::inv::titled_menu( get_avatar(), + ( "Select the firearm to repair" ) ); if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); return 0; @@ -6186,11 +6231,15 @@ int iuse::toolmod_attach( player *p, item *it, bool, const tripoint & ) return false; } + // cannot mod non-tool, or a tool with existing mods, or a battery currently installed + if( !e.is_tool() || !e.toolmods().empty() || e.magazine_current() ) { + return false; + } + // can only attach to unmodified tools that use compatible ammo - return e.is_tool() && e.toolmods().empty() && !e.magazine_current() && - std::any_of( it->type->mod->acceptable_ammo.begin(), + return std::any_of( it->type->mod->acceptable_ammo.begin(), it->type->mod->acceptable_ammo.end(), [&]( const ammotype & at ) { - return e.ammo_types( false ).count( at ); + return e.type->tool->ammo_id.count( at ); } ); }; @@ -6203,7 +6252,7 @@ int iuse::toolmod_attach( player *p, item *it, bool, const tripoint & ) } if( loc->ammo_remaining() ) { - if( !g->unload( loc ) ) { + if( !p->unload( loc ) ) { p->add_msg_if_player( m_info, _( "You cancel unloading the tool." ) ); return 0; } @@ -6958,9 +7007,9 @@ struct extended_photo_def : public JsonDeserializer, public JsonSerializer { static std::string colorized_trap_name_at( const tripoint &point ) { - const trap &trap = g->m.tr_at( point ); + const trap &trap = get_map().tr_at( point ); std::string name; - if( !trap.is_null() && trap.get_visibility() <= 1 ) { + if( trap.can_see( point, get_player_character() ) ) { name = colorize( trap.name(), trap.color ) + _( " on " ); } return name; @@ -6969,7 +7018,7 @@ static std::string colorized_trap_name_at( const tripoint &point ) static std::string colorized_field_description_at( const tripoint &point ) { std::string field_text; - const field &field = g->m.field_at( point ); + const field &field = get_map().field_at( point ); const field_entry *entry = field.find_field( field.displayed_field_type() ); if( entry ) { field_text = string_format( _( description_affixes.at( field.displayed_description_affix() ) ), @@ -7000,7 +7049,7 @@ static std::string colorized_item_description( const item &item ) static item get_top_item_at_point( const tripoint &point, const units::volume &min_visible_volume ) { - map_stack items = g->m.i_at( point ); + map_stack items = get_map().i_at( point ); // iterate from topmost item down to ground for( const item &it : items ) { if( it.volume() > min_visible_volume ) { @@ -7014,9 +7063,10 @@ static item get_top_item_at_point( const tripoint &point, static std::string colorized_ter_name_flags_at( const tripoint &point, const std::vector &flags, const std::vector &ter_whitelist ) { - const ter_id ter = g->m.ter( point ); + map &here = get_map(); + const ter_id ter = here.ter( point ); std::string name = colorize( ter->name(), ter->color() ); - const std::string &graffiti_message = g->m.graffiti_at( point ); + const std::string &graffiti_message = here.graffiti_at( point ); if( !graffiti_message.empty() ) { name += string_format( _( " with graffiti \"%s\"" ), graffiti_message ); @@ -7049,10 +7099,11 @@ static std::string colorized_feature_description_at( const tripoint ¢er_poin const units::volume &min_visible_volume ) { item_found = false; - const furn_id furn = g->m.furn( center_point ); + map &here = get_map(); + const furn_id furn = here.furn( center_point ); if( furn != f_null && furn.is_valid() ) { std::string furn_str = colorize( furn->name(), c_yellow ); - std::string sign_message = g->m.get_signage( center_point ); + std::string sign_message = here.get_signage( center_point ); if( !sign_message.empty() ) { furn_str += string_format( _( " with message \"%s\"" ), sign_message ); } @@ -7191,8 +7242,10 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p std::unordered_set &ignored_points, std::unordered_set &vehicles_recorded ) { - const tripoint_range bounds = g->m.points_in_radius( bounds_center_point, bounds_radius ); - const tripoint_range points_in_radius = g->m.points_in_radius( point, radius ); + map &here = get_map(); + const tripoint_range bounds = + here.points_in_radius( bounds_center_point, bounds_radius ); + const tripoint_range points_in_radius = here.points_in_radius( point, radius ); int dist = rl_dist( camera_pos, point ); bool item_found = false; @@ -7206,7 +7259,7 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p // store objects in radius for( const tripoint &point_around_figure : points_in_radius ) { if( !bounds.is_point_inside( point_around_figure ) || - !g->m.sees( camera_pos, point_around_figure, dist + radius ) || + !here.sees( camera_pos, point_around_figure, dist + radius ) || ( ignored_points.find( point_around_figure ) != ignored_points.end() && !( point_around_figure == point && create_figure_desc ) ) ) { continue; // disallow photos with not visible objects @@ -7219,7 +7272,7 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p const item item = get_top_item_at_point( point_around_figure, volume_to_search ); - const optional_vpart_position veh_part_pos = g->m.veh_at( point_around_figure ); + const optional_vpart_position veh_part_pos = here.veh_at( point_around_figure ); std::string unusual_ter_desc = colorized_ter_name_flags_at( point_around_figure, camera_ter_whitelist_flags, camera_ter_whitelist_types ); @@ -7343,7 +7396,8 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, std::string timestamp = to_string( time_point( calendar::turn ) ); int dist = rl_dist( camera_pos, aim_point ); - const tripoint_range bounds = g->m.points_in_radius( aim_point, 2 ); + map &here = get_map(); + const tripoint_range bounds = here.points_in_radius( aim_point, 2 ); extended_photo_def photo; bool need_store_weather = false; int outside_tiles_num = 0; @@ -7361,14 +7415,14 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, // first scan for critters and mark nearby furniture, vehicles and items for( const tripoint ¤t : bounds ) { - if( !g->m.sees( camera_pos, current, dist + 3 ) ) { + if( !here.sees( camera_pos, current, dist + 3 ) ) { continue; // disallow photos with non-visible objects } monster *const mon = g->critter_at( current, false ); avatar *guy = g->critter_at( current ); total_tiles_num++; - if( g->m.is_outside( current ) ) { + if( here.is_outside( current ) ) { need_store_weather = true; outside_tiles_num++; } @@ -7378,7 +7432,7 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, Creature *creature; if( mon && mon->has_effect( effect_ridden ) ) { // only player can ride, see monexamine::mount_pet - guy = &g->u; + guy = &get_avatar(); description_figures_appearance[ mon->name() ] = "\"" + mon->type->get_description() + "\""; } @@ -7447,15 +7501,15 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, std::string ter_name = colorized_ter_name_flags_at( aim_point, {}, {} ); const std::string field_desc = colorized_field_description_at( aim_point ); - bool found_vehicle_aim_point = g->m.veh_at( aim_point ).has_value(), + bool found_vehicle_aim_point = here.veh_at( aim_point ).has_value(), found_furniture_aim_point = !furn_desc.empty(); // colorized_feature_description_at do not update flag if no furniture found, so need to check again if( !found_furniture_aim_point ) { found_item_aim_point = !item.is_null(); } - const ter_id ter_aim = g->m.ter( aim_point ); - const furn_id furn_aim = g->m.furn( aim_point ); + const ter_id ter_aim = here.ter( aim_point ); + const furn_id furn_aim = here.furn( aim_point ); if( !description_figures_status.empty() ) { std::string names = enumerate_as_string( description_figures_status.begin(), @@ -7472,7 +7526,7 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, + " " + figure_status.second; } } else if( found_vehicle_aim_point ) { - const optional_vpart_position veh_part_pos = g->m.veh_at( aim_point ); + const optional_vpart_position veh_part_pos = here.veh_at( aim_point ); const std::string veh_name = colorize( veh_part_pos->vehicle().disp_name(), c_light_blue ); photo.name = veh_name; photo_text += veh_name + "."; @@ -7547,7 +7601,7 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, obj_list ); } - const oter_id &cur_ter = overmap_buffer.ter( ms_to_omt_copy( g->m.getabs( aim_point ) ) ); + const oter_id &cur_ter = overmap_buffer.ter( ms_to_omt_copy( here.getabs( aim_point ) ) ); std::string overmap_desc = string_format( _( "In the background you can see a %s" ), colorize( cur_ter->get_name(), cur_ter->get_color() ) ); if( outside_tiles_num == total_tiles_num ) { @@ -7576,9 +7630,8 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, } else { photo_text += _( "It is day. " ); } - - const weather_datum w_data = weather_data( g->weather.weather ); - photo_text += string_format( _( "The weather is %s." ), colorize( w_data.name, w_data.color ) ); + photo_text += string_format( _( "The weather is %s." ), colorize( get_weather().weather_id->name, + get_weather().weather_id->color ) ); } for( const auto &figure : description_figures_appearance ) { @@ -7752,6 +7805,7 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) return 0; } + map &here = get_map(); if( c_shot == choice ) { const cata::optional aim_point_ = g->look_around(); @@ -7761,7 +7815,7 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) } tripoint aim_point = *aim_point_; bool incorrect_focus = false; - tripoint_range aim_bounds = g->m.points_in_radius( aim_point, 2 ); + tripoint_range aim_bounds = here.points_in_radius( aim_point, 2 ); std::vector trajectory = line_to( p->pos(), aim_point, 0, 0 ); trajectory.push_back( aim_point ); @@ -7776,12 +7830,12 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) const tripoint trajectory_point = *point_it; if( point_it != trajectory.end() ) { const tripoint next_point = *( point_it + 1 ); // Trajectory ends on last visible tile - if( !g->m.sees( p->pos(), next_point, rl_dist( p->pos(), next_point ) + 3 ) ) { + if( !here.sees( p->pos(), next_point, rl_dist( p->pos(), next_point ) + 3 ) ) { p->add_msg_if_player( _( "You have the wrong camera focus." ) ); incorrect_focus = true; // recalculate target point aim_point = trajectory_point; - aim_bounds = g->m.points_in_radius( trajectory_point, 2 ); + aim_bounds = here.points_in_radius( trajectory_point, 2 ); } } @@ -8014,7 +8068,7 @@ int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) if( t ) { - if( g->m.has_flag( "SWIMMABLE", pos.xy() ) ) { + if( get_map().has_flag( "SWIMMABLE", pos.xy() ) ) { it->item_tags.erase( "NO_UNWIELD" ); it->ammo_unset(); it->active = false; @@ -8234,8 +8288,9 @@ int iuse::radiocaron( player *p, item *it, bool t, const tripoint &pos ) static void sendRadioSignal( player &p, const std::string &signal ) { - for( const tripoint &loc : g->m.points_in_radius( p.pos(), 30 ) ) { - for( item &it : g->m.i_at( loc ) ) { + map &here = get_map(); + for( const tripoint &loc : here.points_in_radius( p.pos(), 30 ) ) { + for( item &it : here.i_at( loc ) ) { if( it.has_flag( "RADIO_ACTIVATION" ) && it.has_flag( signal ) ) { sounds::sound( p.pos(), 6, sounds::sound_t::alarm, _( "beep" ), true, "misc", "beep" ); if( it.has_flag( "RADIO_INVOKE_PROC" ) ) { @@ -8292,6 +8347,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) _( "Press red button" ), _( "Press blue button" ), _( "Press green button" ) } ); + map &here = get_map(); if( choice < 0 ) { return 0; } else if( choice == 0 ) { @@ -8299,7 +8355,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) it->active = false; p->remove_value( "remote_controlling" ); } else { - std::list> rc_pairs = g->m.get_rc_items(); + std::list> rc_pairs = here.get_rc_items(); tripoint rc_item_location = {999, 999, 999}; // TODO: grab the closest car or similar? for( auto &rc_pairs_rc_pair : rc_pairs ) { @@ -8426,7 +8482,7 @@ static vehicle *pickveh( const tripoint ¢er, bool advanced ) pmenu.title = _( "Select vehicle to access" ); std::vector< vehicle * > vehs; - for( auto &veh : g->m.get_vehicles() ) { + for( auto &veh : get_map().get_vehicles() ) { auto &v = veh.v; if( rl_dist( center, v->global_pos3() ) < 40 && v->fuel_left( itype_battery, true ) > 0 && @@ -8498,7 +8554,8 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) return 0; } - point p2( g->u.view_offset.xy() ); + avatar &player_character = get_avatar(); + point p2( player_character.view_offset.xy() ); vehicle *veh = pickveh( pos, choice == 0 ); @@ -8511,7 +8568,7 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) } if( choice == 0 ) { - if( g->u.has_trait( trait_WAYFARER ) ) { + if( p->has_trait( trait_WAYFARER ) ) { add_msg( m_info, _( "Despite using a controller, you still refuse to take control of this vehicle." ) ); } else { @@ -8532,8 +8589,8 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) } } - g->u.view_offset.x = p2.x; - g->u.view_offset.y = p2.y; + player_character.view_offset.x = p2.x; + player_character.view_offset.y = p2.y; return it->type->charges_to_use(); } @@ -8575,7 +8632,7 @@ static bool multicooker_hallu( player &p ) } else { p.add_msg_if_player( m_info, _( "You're surrounded by aggressive multi-cookers!" ) ); - for( const tripoint &pn : g->m.points_in_radius( p.pos(), 1 ) ) { + for( const tripoint &pn : get_map().points_in_radius( p.pos(), 1 ) ) { if( monster *const m = g->place_critter_at( mon_hallu_multicooker, pn ) ) { m->hallucination = true; } @@ -8628,7 +8685,7 @@ int iuse::autoclave( player *p, item *it, bool t, const tripoint &pos ) if( clean_cbm ) { empty = false; if( query_yn( _( "Autoclave already contains a CBM. Do you want to remove it?" ) ) ) { - g->m.add_item( pos, *clean_cbm ); + get_map().add_item( pos, *clean_cbm ); it->remove_item( *clean_cbm ); if( !query_yn( _( "Do you want to use the autoclave?" ) ) ) { return 0; @@ -8853,7 +8910,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) std::vector dishes; - inventory crafting_inv = g->u.crafting_inventory(); + inventory crafting_inv = p->crafting_inventory(); //add some tools and qualities. we can't add this qualities to json, because multicook must be used only by activating, not as component other crafts. crafting_inv.push_back( item( "hotplate", 0 ) ); //hotplate inside crafting_inv.push_back( item( "tongs", 0 ) ); //some recipes requires tongs @@ -8862,7 +8919,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) int counter = 0; - for( const auto &r : g->u.get_learned_recipes().in_category( "CC_FOOD" ) ) { + for( const auto &r : get_avatar().get_learned_recipes().in_category( "CC_FOOD" ) ) { if( multicooked_subcats.count( r->subcategory ) > 0 ) { dishes.push_back( r ); const bool can_make = r->deduped_requirements().can_make_with_inventory( @@ -8882,9 +8939,9 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) const recipe *meal = dishes[choice]; int mealtime; if( it->get_var( "MULTI_COOK_UPGRADE" ) == "UPGRADE" ) { - mealtime = meal->time; + mealtime = meal->time_to_craft_moves( *p ); } else { - mealtime = meal->time * 2; + mealtime = meal->time_to_craft_moves( *p ) * 2; } const int all_charges = charges_to_start + mealtime / ( it->type->tool->power_draw / 10000 ); @@ -8934,7 +8991,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) bool has_tools = true; - const inventory &cinv = g->u.crafting_inventory(); + const inventory &cinv = p->crafting_inventory(); if( !cinv.has_amount( itype_soldering_iron, 1 ) ) { p->add_msg_if_player( m_warning, _( "You need a %s." ), @@ -9010,6 +9067,7 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) it->process( p, p->pos(), false ); p->moves -= 15; }; + map &here = get_map(); if( initial_state == "attach_first" ) { const cata::optional posp_ = choose_adjacent( _( "Attach cable to the vehicle that will do the towing." ) ); @@ -9017,7 +9075,7 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) return 0; } const tripoint posp = *posp_; - const optional_vpart_position vp = g->m.veh_at( posp ); + const optional_vpart_position vp = here.veh_at( posp ); if( !vp ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); return 0; @@ -9034,19 +9092,19 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) return 0; } } - const tripoint &abspos = g->m.getabs( posp ); + const tripoint &abspos = here.getabs( posp ); it->set_var( "source_x", abspos.x ); it->set_var( "source_y", abspos.y ); it->set_var( "source_z", g->get_levz() ); set_cable_active( p, it, "pay_out_cable" ); } } else { - const auto confirm_source_vehicle = []( player * p, item * it, const bool detach_if_missing ) { + const auto confirm_source_vehicle = [&here]( player * p, item * it, const bool detach_if_missing ) { tripoint source_global( it->get_var( "source_x", 0 ), it->get_var( "source_y", 0 ), it->get_var( "source_z", 0 ) ); - tripoint source_local = g->m.getlocal( source_global ); - const optional_vpart_position source_vp = g->m.veh_at( source_local ); + tripoint source_local = here.getlocal( source_global ); + const optional_vpart_position source_vp = here.veh_at( source_local ); vehicle *const source_veh = veh_pointer_or_null( source_vp ); if( detach_if_missing && source_veh == nullptr ) { if( p->has_item( *it ) ) { @@ -9084,7 +9142,7 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) } const tripoint vpos = *vpos_; - const optional_vpart_position target_vp = g->m.veh_at( vpos ); + const optional_vpart_position target_vp = here.veh_at( vpos ); if( !target_vp ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); return 0; @@ -9156,6 +9214,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) p->find_remote_fuel(); } }; + map &here = get_map(); if( initial_state == "attach_first" ) { if( has_bio_cable ) { uilist kmenu; @@ -9203,25 +9262,25 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) return 0; } const tripoint posp = *posp_; - const optional_vpart_position vp = g->m.veh_at( posp ); - auto ter = g->m.ter( posp ); + const optional_vpart_position vp = here.veh_at( posp ); + auto ter = here.ter( posp ); if( !vp && ter != t_chainfence ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); return 0; } else { - const auto abspos = g->m.getabs( posp ); + const auto abspos = here.getabs( posp ); it->set_var( "source_x", abspos.x ); it->set_var( "source_y", abspos.y ); it->set_var( "source_z", g->get_levz() ); set_cable_active( p, it, "pay_out_cable" ); } } else { - const auto confirm_source_vehicle = []( player * p, item * it, const bool detach_if_missing ) { + const auto confirm_source_vehicle = [&here]( player * p, item * it, const bool detach_if_missing ) { tripoint source_global( it->get_var( "source_x", 0 ), it->get_var( "source_y", 0 ), it->get_var( "source_z", 0 ) ); - tripoint source_local = g->m.getlocal( source_global ); - const optional_vpart_position source_vp = g->m.veh_at( source_local ); + tripoint source_local = here.getlocal( source_global ); + const optional_vpart_position source_vp = here.veh_at( source_local ); vehicle *const source_veh = veh_pointer_or_null( source_vp ); if( detach_if_missing && source_veh == nullptr ) { if( p != nullptr && p->has_item( *it ) ) { @@ -9314,12 +9373,12 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) } const tripoint vpos = *vpos_; - const optional_vpart_position target_vp = g->m.veh_at( vpos ); + const optional_vpart_position target_vp = here.veh_at( vpos ); if( !target_vp ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); return 0; } else if( cable_cbm ) { - const auto abspos = g->m.getabs( vpos ); + const auto abspos = here.getabs( vpos ); it->set_var( "source_x", abspos.x ); it->set_var( "source_y", abspos.y ); it->set_var( "source_z", g->get_levz() ); @@ -9336,7 +9395,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) return 0; } - tripoint target_global = g->m.getabs( vpos ); + tripoint target_global = here.getabs( vpos ); // TODO: make sure there is always a matching vpart id here. Maybe transform this into // a iuse_actor class, or add a check in item_factory. const vpart_id vpid( it->typeId().str() ); @@ -9344,7 +9403,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) point vcoords = source_vp->mount(); vehicle_part source_part( vpid, vcoords, item( *it ) ); source_part.target.first = target_global; - source_part.target.second = g->m.getabs( target_veh->global_pos3() ); + source_part.target.second = here.getabs( target_veh->global_pos3() ); source_veh->install_part( vcoords, source_part ); vcoords = target_vp->mount(); @@ -9353,7 +9412,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) it->get_var( "source_y", 0 ), it->get_var( "source_z", 0 ) ); target_part.target.first = source_global; - target_part.target.second = g->m.getabs( source_veh->global_pos3() ); + target_part.target.second = here.getabs( source_veh->global_pos3() ); target_veh->install_part( vcoords, target_part ); if( p != nullptr && p->has_item( *it ) ) { @@ -9399,7 +9458,7 @@ int iuse::weather_tool( player *p, item *it, bool, const tripoint & ) const w_point weatherPoint = *g->weather.weather_precise; /* Possibly used twice. Worth spending the time to precalculate. */ - const auto player_local_temp = g->weather.get_temperature( g->u.pos() ); + const auto player_local_temp = g->weather.get_temperature( p->pos() ); if( it->typeId() == itype_weather_reader ) { p->add_msg_if_player( m_neutral, _( "The %s's monitor slowly outputs the data…" ), @@ -9418,13 +9477,13 @@ int iuse::weather_tool( player *p, item *it, bool, const tripoint & ) if( it->typeId() == itype_hygrometer ) { p->add_msg_if_player( m_neutral, _( "The %1$s reads %2$s." ), it->tname(), - print_humidity( get_local_humidity( weatherPoint.humidity, g->weather.weather, - g->is_sheltered( g->u.pos() ) ) ) ); + print_humidity( get_local_humidity( weatherPoint.humidity, get_weather().weather_id, + g->is_sheltered( p->pos() ) ) ) ); } else { p->add_msg_if_player( m_neutral, _( "Relative Humidity: %s." ), - print_humidity( get_local_humidity( weatherPoint.humidity, g->weather.weather, - g->is_sheltered( g->u.pos() ) ) ) ); + print_humidity( get_local_humidity( weatherPoint.humidity, get_weather().weather_id, + g->is_sheltered( p->pos() ) ) ) ); } } if( it->has_flag( "BAROMETER" ) ) { @@ -9440,7 +9499,7 @@ int iuse::weather_tool( player *p, item *it, bool, const tripoint & ) if( it->typeId() == itype_weather_reader ) { int vehwindspeed = 0; - if( optional_vpart_position vp = g->m.veh_at( p->pos() ) ) { + if( optional_vpart_position vp = get_map().veh_at( p->pos() ) ) { vehwindspeed = std::abs( vp->vehicle().velocity / 100 ); // For mph } const oter_id &cur_om_ter = overmap_buffer.ter( p->global_omt_location() ); @@ -9638,7 +9697,8 @@ int iuse::capture_monster_act( player *p, item *it, bool, const tripoint &pos ) int iuse::ladder( player *p, item *, bool, const tripoint & ) { - if( !g->m.has_zlevels() ) { + map &here = get_map(); + if( !here.has_zlevels() ) { debugmsg( "Ladder can't be used in non-z-level mode" ); return 0; } @@ -9652,14 +9712,14 @@ int iuse::ladder( player *p, item *, bool, const tripoint & ) } const tripoint pnt = *pnt_; - if( !g->is_empty( pnt ) || g->m.has_furn( pnt ) ) { + if( !g->is_empty( pnt ) || here.has_furn( pnt ) ) { p->add_msg_if_player( m_bad, _( "Can't place it there." ) ); return 0; } p->add_msg_if_player( _( "You set down the ladder." ) ); p->moves -= to_moves( 5_seconds ); - g->m.furn_set( pnt, furn_str_id( "f_ladder" ) ); + here.furn_set( pnt, furn_str_id( "f_ladder" ) ); return 1; } @@ -9755,12 +9815,12 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) ( hard_items && !location->is_soft() ) ); } ); auto make_raw_stats = [available_water, available_cleanser]( - const std::map &items + const std::map &locs ) { units::volume total_volume = 0_ml; - for( const auto &p : items ) { - total_volume += p.first->volume() * p.second / - ( p.first->count_by_charges() ? p.first->charges : 1 ); + for( const auto &p : locs ) { + total_volume += ( *p.first )->base_volume() * p.second / + ( ( *p.first )->count_by_charges() ? ( *p.first )->charges : 1 ); } washing_requirements required = washing_requirements_for_volume( total_volume ); auto to_string = []( int val ) -> std::string { @@ -9789,7 +9849,6 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) if( to_clean.empty() ) { return 0; } - // Determine if we have enough water and cleanser for all the items. units::volume total_volume = 0_ml; for( drop_location pair : to_clean ) { @@ -9798,7 +9857,7 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) return 0; } item &i = *pair.first; - total_volume += i.volume() * pair.second / ( i.count_by_charges() ? i.charges : 1 ); + total_volume += i.base_volume() * pair.second / ( i.count_by_charges() ? i.charges : 1 ); } washing_requirements required = washing_requirements_for_volume( total_volume ); @@ -9814,8 +9873,8 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) required.cleanser ); return 0; } - const std::vector helpers = g->u.get_crafting_helpers(); - const int helpersize = g->u.get_num_crafting_helpers( 3 ); + const std::vector helpers = p->get_crafting_helpers(); + const int helpersize = p->get_num_crafting_helpers( 3 ); required.time = required.time * ( 1 - ( helpersize / 10 ) ); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); @@ -9823,7 +9882,6 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) } // Assign the activity values. p->assign_activity( ACT_WASH, required.time ); - for( const drop_location &pair : to_clean ) { p->activity.targets.push_back( pair.first ); p->activity.values.push_back( pair.second ); @@ -9849,18 +9907,19 @@ int iuse::break_stick( player *p, item *it, bool, const tripoint & ) comps.push_back( item_comp( it->typeId(), 1 ) ); p->consume_items( comps, 1, is_crafting_component ); int chance = rng( 0, 100 ); + map &here = get_map(); if( chance <= 20 ) { p->add_msg_if_player( _( "You try to break the stick in two, but it shatters into splinters." ) ); - g->m.spawn_item( p->pos(), "splinter", 2 ); + here.spawn_item( p->pos(), "splinter", 2 ); return 1; } else if( chance <= 40 ) { p->add_msg_if_player( _( "The stick breaks clean into two parts." ) ); - g->m.spawn_item( p->pos(), "stick", 2 ); + here.spawn_item( p->pos(), "stick", 2 ); return 1; } else if( chance <= 100 ) { p->add_msg_if_player( _( "You break the stick, but one half shatters into splinters." ) ); - g->m.spawn_item( p->pos(), "stick", 1 ); - g->m.spawn_item( p->pos(), "splinter", 1 ); + here.spawn_item( p->pos(), "stick", 1 ); + here.spawn_item( p->pos(), "splinter", 1 ); return 1; } return 0; diff --git a/src/iuse.h b/src/iuse.h index 6de160f2a237e..ddc3779b59180 100644 --- a/src/iuse.h +++ b/src/iuse.h @@ -228,20 +228,20 @@ int disassemble( player *, item *, bool, const tripoint & ); int artifact( player *, item *, bool, const tripoint & ); // Helper functions for other iuse functions -void cut_log_into_planks( player & ); -void play_music( player &p, const tripoint &source, int volume, int max_morale ); -int towel_common( player *, item *, bool ); +void cut_log_into_planks( Character & ); +void play_music( Character &p, const tripoint &source, int volume, int max_morale ); +int towel_common( Character *, item *, bool ); // Helper for validating a potential taget of robot control bool robotcontrol_can_target( player *, const monster & ); // Helper for handling pesky wannabe-artists -int handle_ground_graffiti( player &p, item *it, const std::string &prefix, +int handle_ground_graffiti( Character &p, item *it, const std::string &prefix, const tripoint &where ); } // namespace iuse -void remove_radio_mod( item &it, player &p ); +void remove_radio_mod( item &it, Character &p ); // Helper for clothes washing struct washing_requirements { diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 73069a4020575..082cb274947e4 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -273,7 +273,7 @@ int iuse_transform::use( player &p, item &it, bool t, const tripoint &pos ) cons it.put_in( *obj, item_pocket::pocket_type::CONTAINER ); } if( p.is_worn( *obj ) ) { - p.reset_encumbrance(); + p.calc_encumbrance(); p.update_bodytemp(); p.on_worn_item_transform( obj_copy, *obj ); } @@ -370,6 +370,7 @@ int unpack_actor::use( player &p, item &it, bool, const tripoint & ) const p.add_msg_if_player( _( "You unpack the %s." ), it.tname() ); + map &here = get_map(); for( item &content : items ) { if( content.is_armor() ) { if( items_fit ) { @@ -389,7 +390,7 @@ int unpack_actor::use( player &p, item &it, bool, const tripoint & ) const content.set_flag( "FILTHY" ); } - g->m.add_item_or_charges( p.pos(), content ); + here.add_item_or_charges( p.pos(), content ); } p.i_rem( &it ); @@ -475,13 +476,14 @@ std::unique_ptr explosion_iuse::clone() const // They must also be passable. static std::vector points_for_gas_cloud( const tripoint ¢er, int radius ) { + map &here = get_map(); std::vector result; - for( const auto &p : closest_tripoints_first( center, radius ) ) { - if( g->m.impassable( p ) ) { + for( const auto &p : closest_points_first( center, radius ) ) { + if( here.impassable( p ) ) { continue; } if( p != center ) { - if( !g->m.clear_path( center, p, radius, 1, 100 ) ) { + if( !here.clear_path( center, p, radius, 1, 100 ) ) { // Can not splatter gas from center to that point, something is in the way continue; } @@ -551,20 +553,21 @@ int explosion_iuse::use( player &p, item &it, bool t, const tripoint &pos ) cons if( do_flashbang ) { explosion_handler::flashbang( pos, flashbang_player_immune ); } + map &here = get_map(); if( fields_radius >= 0 && fields_type.id() ) { std::vector gas_sources = points_for_gas_cloud( pos, fields_radius ); for( auto &gas_source : gas_sources ) { const int field_intensity = rng( fields_min_intensity, fields_max_intensity ); - g->m.add_field( gas_source, fields_type, field_intensity, 1_turns ); + here.add_field( gas_source, fields_type, field_intensity, 1_turns ); } } if( scrambler_blast_radius >= 0 ) { - for( const tripoint &dest : g->m.points_in_radius( pos, scrambler_blast_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, scrambler_blast_radius ) ) { explosion_handler::scrambler_blast( dest ); } } if( emp_blast_radius >= 0 ) { - for( const tripoint &dest : g->m.points_in_radius( pos, emp_blast_radius ) ) { + for( const tripoint &dest : here.points_in_radius( pos, emp_blast_radius ) ) { explosion_handler::emp_blast( dest ); } } @@ -619,7 +622,7 @@ int unfold_vehicle_iuse::use( player &p, item &it, bool, const tripoint & ) cons } } - vehicle *veh = g->m.add_vehicle( vehicle_id, p.pos(), 0, 0, 0, false ); + vehicle *veh = get_map().add_vehicle( vehicle_id, p.pos(), 0, 0, 0, false ); if( veh == nullptr ) { p.add_msg_if_player( m_info, _( "There's no room to unfold the %s." ), it.tname() ); return 0; @@ -721,7 +724,7 @@ void consume_drug_iuse::info( const item &, std::vector &dump ) const { const std::string vits = enumerate_as_string( vitamins.begin(), vitamins.end(), []( const decltype( vitamins )::value_type & v ) { - const time_duration rate = g->u.vitamin_rate( v.first ); + const time_duration rate = get_player_character().vitamin_rate( v.first ); if( rate <= 0_turns ) { return std::string(); } @@ -786,10 +789,11 @@ int consume_drug_iuse::use( player &p, item &it, bool, const tripoint & ) const for( const auto &stat_adjustment : stat_adjustments ) { p.mod_stat( stat_adjustment.first, stat_adjustment.second ); } + map &here = get_map(); for( const auto &field : fields_produced ) { const field_type_id fid = field_type_id( field.first ); for( int i = 0; i < 3; i++ ) { - g->m.add_field( {p.posx() + static_cast( rng( -2, 2 ) ), p.posy() + static_cast( rng( -2, 2 ) ), p.posz()}, + here.add_field( {p.posx() + static_cast( rng( -2, 2 ) ), p.posy() + static_cast( rng( -2, 2 ) ), p.posz()}, fid, field.second ); } @@ -964,11 +968,12 @@ void place_npc_iuse::load( const JsonObject &obj ) int place_npc_iuse::use( player &p, item &, bool, const tripoint & ) const { + map &here = get_map(); cata::optional target_pos; if( place_randomly ) { - const tripoint_range target_range = points_in_radius( p.pos(), 1 ); - target_pos = random_point( target_range, []( const tripoint & t ) { - return !g->m.passable( t ); + const tripoint_range target_range = points_in_radius( p.pos(), 1 ); + target_pos = random_point( target_range, [&here]( const tripoint & t ) { + return !here.passable( t ); } ); } else { const std::string query = _( "Place npc where?" ); @@ -977,12 +982,12 @@ int place_npc_iuse::use( player &p, item &, bool, const tripoint & ) const if( !target_pos ) { return 0; } - if( !g->m.passable( target_pos.value() ) ) { + if( !here.passable( target_pos.value() ) ) { p.add_msg_if_player( m_info, _( "There is no square to spawn npc in!" ) ); return 0; } - g->m.place_npc( target_pos.value().xy(), npc_class_id ); + here.place_npc( target_pos.value().xy(), npc_class_id ); p.mod_moves( -moves ); p.add_msg_if_player( m_info, "%s", _( summon_msg ) ); return 1; @@ -1024,7 +1029,7 @@ int ups_based_armor_actor::use( player &p, item &it, bool t, const tripoint & ) return 0; } it.active = !it.active; - p.reset_encumbrance(); + p.calc_encumbrance(); if( it.active ) { if( activate_msg.empty() ) { p.add_msg_if_player( m_info, _( "You activate your %s." ), it.tname() ); @@ -1115,7 +1120,8 @@ int deploy_furn_actor::use( player &p, item &it, bool, const tripoint &pos ) con return 0; } - optional_vpart_position veh_there = g->m.veh_at( pnt ); + map &here = get_map(); + optional_vpart_position veh_there = here.veh_at( pnt ); if( veh_there.has_value() ) { // TODO: check for protrusion+short furniture, wheels+tiny furniture, NOCOLLIDE flag, etc. // and/or integrate furniture deployment with construction (which already seems to perform these checks sometimes?) @@ -1125,17 +1131,17 @@ int deploy_furn_actor::use( player &p, item &it, bool, const tripoint &pos ) con } // For example: dirt = 2, long grass = 3 - if( g->m.move_cost( pnt ) != 2 && g->m.move_cost( pnt ) != 3 ) { + if( here.move_cost( pnt ) != 2 && here.move_cost( pnt ) != 3 ) { p.add_msg_if_player( m_info, _( "You can't deploy a %s there." ), it.tname() ); return 0; } - if( g->m.has_furn( pnt ) ) { + if( here.has_furn( pnt ) ) { p.add_msg_if_player( m_info, _( "There is already furniture at that location." ) ); return 0; } - g->m.furn_set( pnt, furn_type ); + here.furn_set( pnt, furn_type ); p.mod_moves( to_turns( 2_seconds ) ); return 1; } @@ -1230,14 +1236,15 @@ bool firestarter_actor::prep_firestarter_use( const player &p, tripoint &pos ) p.add_msg_if_player( _( "But you're already smokin' hot." ) ); return false; } - if( g->m.get_field( pos, fd_fire ) ) { + map &here = get_map(); + if( here.get_field( pos, fd_fire ) ) { // check if there's already a fire p.add_msg_if_player( m_info, _( "There is already a fire." ) ); return false; } // Check for a brazier. bool has_unactivated_brazier = false; - for( const item &i : g->m.i_at( pos ) ) { + for( const item &i : here.i_at( pos ) ) { if( i.typeId() == itype_brazier ) { has_unactivated_brazier = true; } @@ -1249,7 +1256,7 @@ bool firestarter_actor::prep_firestarter_use( const player &p, tripoint &pos ) void firestarter_actor::resolve_firestarter_use( player &p, const tripoint &pos ) { - if( g->m.add_field( pos, fd_fire, 1, 10_minutes ) ) { + if( get_map().add_field( pos, fd_fire, 1, 10_minutes ) ) { if( !p.has_trait( trait_PYROMANIA ) ) { p.add_msg_if_player( _( "You successfully light a fire." ) ); } else { @@ -1290,8 +1297,8 @@ float firestarter_actor::light_mod( const tripoint &pos ) const } const float light_level = g->natural_light_level( pos.z ); - if( ( g->weather.weather == WEATHER_CLEAR || g->weather.weather == WEATHER_SUNNY ) && - light_level >= 60.0f && !g->m.has_flag( TFLAG_INDOORS, pos ) ) { + if( get_weather().weather_id->sun_intensity >= sun_intensity_type::normal && + light_level >= 60.0f && !get_map().has_flag( TFLAG_INDOORS, pos ) ) { return std::pow( light_level / 80.0f, 8 ); } @@ -1300,11 +1307,12 @@ float firestarter_actor::light_mod( const tripoint &pos ) const int firestarter_actor::moves_cost_by_fuel( const tripoint &pos ) const { - if( g->m.flammable_items_at( pos, 100 ) ) { + map &here = get_map(); + if( here.flammable_items_at( pos, 100 ) ) { return moves_cost_fast; } - if( g->m.flammable_items_at( pos, 10 ) ) { + if( here.flammable_items_at( pos, 10 ) ) { return ( moves_cost_slow + moves_cost_fast ) / 2; } @@ -1337,7 +1345,7 @@ int firestarter_actor::use( player &p, item &it, bool t, const tripoint &spos ) _( "If the current weather holds, it will take around %d minutes to light a fire." ) : _( "At your skill level, it will take around %d minutes to light a fire." ), moves / to_moves( 1_minutes ) ); - } else if( moves < to_moves( 2_turns ) && g->m.is_flammable( pos ) ) { + } else if( moves < to_moves( 2_turns ) && get_map().is_flammable( pos ) ) { // If less than 2 turns, don't start a long action resolve_firestarter_use( p, pos ); p.mod_moves( -moves ); @@ -1541,8 +1549,9 @@ int salvage_actor::cut_up( player &p, item &it, item_location &cut ) const // Original item has been consumed. cut.remove_item(); // Force an encumbrance update in case they were wearing that item. - p.reset_encumbrance(); + p.calc_encumbrance(); + map &here = get_map(); for( const auto &salvaged : materials_salvaged ) { itype_id mat_name = salvaged.first; int amount = salvaged.second; @@ -1561,7 +1570,7 @@ int salvage_actor::cut_up( player &p, item &it, item_location &cut ) const p.i_add_or_drop( result, amount ); } else { for( int i = 0; i < amount; i++ ) { - g->m.add_item_or_charges( pos, result ); + here.add_item_or_charges( pos, result ); } } } else { @@ -1701,7 +1710,7 @@ int inscribe_actor::use( player &p, item &it, bool t, const tripoint & ) const dest_.value() ); } - item_location loc = game_menus::inv::titled_menu( g->u, _( "Inscribe which item?" ) ); + item_location loc = game_menus::inv::titled_menu( get_avatar(), _( "Inscribe which item?" ) ); if( !loc ) { p.add_msg_if_player( m_info, _( "Never mind." ) ); return 0; @@ -1737,7 +1746,7 @@ static heal_actor prepare_dummy() dummy.limb_power = -2; dummy.head_power = -2; dummy.torso_power = -2; - dummy.bleed = 1.0f; + dummy.bleed = 25; dummy.bite = 0.5f; dummy.move_cost = 100; return dummy; @@ -1747,8 +1756,8 @@ bool cauterize_actor::cauterize_effect( player &p, item &it, bool force ) { // TODO: Make this less hacky static const heal_actor dummy = prepare_dummy(); - hp_part hpart = dummy.use_healing_item( p, p, it, force ); - if( hpart != num_hp_parts ) { + bodypart_id hpart = dummy.use_healing_item( p, p, it, force ); + if( hpart != bodypart_id( "num_bp" ) ) { p.add_msg_if_player( m_neutral, _( "You cauterize yourself." ) ); if( !( p.has_trait( trait_NOPAIN ) ) ) { p.mod_pain( 15 ); @@ -1756,9 +1765,11 @@ bool cauterize_actor::cauterize_effect( player &p, item &it, bool force ) } else { p.add_msg_if_player( m_neutral, _( "It itches a little." ) ); } - const body_part bp = player::hp_to_bp( hpart ); - if( p.has_effect( effect_bite, bp ) ) { - p.add_effect( effect_bite, 260_minutes, bp, true ); + if( p.has_effect( effect_bleed, hpart->token ) ) { + p.add_msg_if_player( m_bad, _( "Bleeding has not stopped completely!" ) ); + } + if( p.has_effect( effect_bite, hpart->token ) ) { + p.add_effect( effect_bite, 260_minutes, hpart->token, true ); } p.moves = 0; @@ -2524,7 +2535,7 @@ static item_location get_item_location( player &p, item &it, const tripoint &pos } // Item in a vehicle - if( const optional_vpart_position &vp = g->m.veh_at( pos ) ) { + if( const optional_vpart_position &vp = get_map().veh_at( pos ) ) { vehicle_cursor vc( vp->vehicle(), vp->part_index() ); bool found_in_vehicle = false; vc.visit_items( [&]( const item * e ) { @@ -2754,7 +2765,7 @@ bool repair_item_actor::can_repair_target( player &pl, const item &fix, return true; } - const bool resizing_matters = fix.get_encumber( pl ) != 0; + const bool resizing_matters = fix.get_sizing( pl ) != item::sizing::ignore; const bool small = pl.has_trait( trait_SMALL2 ) || pl.has_trait( trait_SMALL_OK ); const bool can_resize = small != fix.has_flag( "UNDERSIZE" ); if( can_be_refitted && resizing_matters && can_resize ) { @@ -2844,12 +2855,13 @@ repair_item_actor::repair_type repair_item_actor::default_action( const item &fi return RT_REFIT; } - const bool smol = g->u.has_trait( trait_SMALL2 ) || - g->u.has_trait( trait_SMALL_OK ); + Character &player_character = get_player_character(); + const bool smol = player_character.has_trait( trait_SMALL2 ) || + player_character.has_trait( trait_SMALL_OK ); const bool is_undersized = fix.has_flag( flag_UNDERSIZE ); const bool is_oversized = fix.has_flag( flag_OVERSIZE ); - const bool resizing_matters = fix.get_encumber( g->u ) != 0; + const bool resizing_matters = fix.get_sizing( player_character ) != item::sizing::ignore; const bool too_big_while_smol = smol && !is_undersized && !is_oversized; if( too_big_while_smol && can_be_refitted && resizing_matters ) { @@ -2882,7 +2894,7 @@ static bool damage_item( player &pl, item_location &fix ) if( destroyed ) { pl.add_msg_if_player( m_bad, _( "You destroy it!" ) ); if( fix.where() == item_location::type::character ) { - pl.i_rem_keep_contents( pl.get_item_position( fix.get_item() ) ); + pl.i_rem_keep_contents( fix.get_item() ); } else { for( const item *it : fix->contents.all_items_top() ) { put_into_vehicle_or_drop( pl, item_drop_reason::deliberate, { *it }, fix.position() ); @@ -3069,7 +3081,7 @@ void heal_actor::load( const JsonObject &obj ) head_scaling = obj.get_float( "head_scaling", scaling_ratio * head_power ); torso_scaling = obj.get_float( "torso_scaling", scaling_ratio * torso_power ); - bleed = obj.get_float( "bleed", 0.0f ); + bleed = obj.get_int( "bleed", 0 ); bite = obj.get_float( "bite", 0.0f ); infect = obj.get_float( "infect", 0.0f ); @@ -3124,8 +3136,8 @@ int heal_actor::use( player &p, item &it, bool, const tripoint &pos ) const } player &patient = get_patient( p, pos ); - const hp_part hpp = use_healing_item( p, patient, it, false ); - if( hpp == num_hp_parts ) { + const bodypart_str_id hpp = use_healing_item( p, patient, it, false ).id(); + if( hpp == bodypart_str_id( "num_bp" ) ) { return 0; } @@ -3142,7 +3154,7 @@ int heal_actor::use( player &p, item &it, bool, const tripoint &pos ) const /** @EFFECT_FIRSTAID speeds up firstaid activity */ p.assign_activity( ACT_FIRSTAID, cost, 0, 0, it.tname() ); p.activity.targets.push_back( item_location( p, &it ) ); - p.activity.values.push_back( hpp ); + p.activity.str_values.push_back( hpp.c_str() ); p.moves = 0; return 0; } @@ -3157,14 +3169,14 @@ std::unique_ptr heal_actor::clone() const return std::make_unique( *this ); } -int heal_actor::get_heal_value( const player &healer, hp_part healed ) const +int heal_actor::get_heal_value( const Character &healer, bodypart_id healed ) const { int heal_base; float bonus_mult; - if( healed == hp_head ) { + if( healed == bodypart_id( "head" ) ) { heal_base = head_power; bonus_mult = head_scaling; - } else if( healed == hp_torso ) { + } else if( healed == bodypart_id( "torso" ) ) { heal_base = torso_power; bonus_mult = torso_scaling; } else { @@ -3180,7 +3192,7 @@ int heal_actor::get_heal_value( const player &healer, hp_part healed ) const return heal_base; } -int heal_actor::get_bandaged_level( const player &healer ) const +int heal_actor::get_bandaged_level( const Character &healer ) const { if( bandages_power > 0 ) { /** @EFFECT_FIRSTAID increases healing item effects */ @@ -3190,7 +3202,7 @@ int heal_actor::get_bandaged_level( const player &healer ) const return bandages_power; } -int heal_actor::get_disinfected_level( const player &healer ) const +int heal_actor::get_disinfected_level( const Character &healer ) const { if( disinfectant_power > 0 ) { /** @EFFECT_FIRSTAID increases healing item effects */ @@ -3200,24 +3212,31 @@ int heal_actor::get_disinfected_level( const player &healer ) const return disinfectant_power; } -int heal_actor::finish_using( player &healer, player &patient, item &it, hp_part healed ) const +int heal_actor::get_stopbleed_level( const Character &healer ) const +{ + if( bleed > 0 ) { + /** @EFFECT_FIRSTAID increases healing item effects */ + return bleed + healer.get_skill_level( skill_firstaid ) / 2; + } + + return bleed; +} + +int heal_actor::finish_using( player &healer, player &patient, item &it, bodypart_id healed ) const { float practice_amount = limb_power * 3.0f; const int dam = get_heal_value( healer, healed ); - - const bodypart_id bp = convert_bp( Character::hp_to_bp( healed ) ).id(); - const int cur_hp = patient.get_part_hp_cur( bp ); + const int cur_hp = patient.get_part_hp_cur( healed ); if( ( cur_hp >= 1 ) && ( dam > 0 ) ) { // Prevent first-aid from mending limbs - patient.heal( bp, dam ); + patient.heal( healed, dam ); } else if( ( cur_hp >= 1 ) && ( dam < 0 ) ) { - patient.apply_damage( nullptr, bp, -dam ); //hurt takes + damage + patient.apply_damage( nullptr, healed, -dam ); //hurt takes + damage } - const body_part bp_healed = player::hp_to_bp( healed ); - + Character &player_character = get_player_character(); const bool u_see = healer.is_player() || patient.is_player() || - g->u.sees( healer ) || g->u.sees( patient ); + player_character.sees( healer ) || player_character.sees( patient ); const bool player_healing_player = healer.is_player() && patient.is_player(); // Need a helper here - messages are from healer's point of view // but it would be cool if NPCs could use this function too @@ -3234,19 +3253,33 @@ int heal_actor::finish_using( player &healer, player &patient, item &it, hp_part } }; - if( patient.has_effect( effect_bleed, bp_healed ) ) { - if( x_in_y( bleed, 1.0f ) ) { - patient.remove_effect( effect_bleed, bp_healed ); - heal_msg( m_good, _( "You stop the bleeding." ), _( "The bleeding is stopped." ) ); + if( patient.has_effect( effect_bleed, healed->token ) ) { + // small band-aids won't stop big arterial bleeding, but with tourniquet they just might + int pwr = 3 * get_stopbleed_level( healer ); + if( patient.worn_with_flag( "TOURNIQUET", convert_bp( healed->token ) ) ) { + pwr *= 2; + } + if( pwr > patient.get_effect_int( effect_bleed, healed->token ) ) { + effect &wound = patient.get_effect( effect_bleed, healed->token ); + time_duration dur = wound.get_duration() - ( get_stopbleed_level( healer ) * + wound.get_int_dur_factor() ); + wound.set_duration( std::max( 0_turns, dur ) ); + if( wound.get_duration() == 0_turns ) { + heal_msg( m_good, _( "You stop the bleeding." ), _( "The bleeding is stopped." ) ); + } else { + heal_msg( m_good, _( "You reduce the bleeding, but it's not stopped yet." ), + _( "The bleeding is reduced, but not stopped." ) ); + } } else { - heal_msg( m_warning, _( "You fail to stop the bleeding." ), _( "The wound still bleeds." ) ); + heal_msg( m_warning, + _( "Your dressing is too ineffective for a bleeding of this extent, and you fail to stop it." ), + _( "The wound still bleeds." ) ); } - - practice_amount += bleed * 3.0f; + practice_amount += bleed / 3.0f; } - if( patient.has_effect( effect_bite, bp_healed ) ) { + if( patient.has_effect( effect_bite, healed->token ) ) { if( x_in_y( bite, 1.0f ) ) { - patient.remove_effect( effect_bite, bp_healed ); + patient.remove_effect( effect_bite, healed->token ); heal_msg( m_good, _( "You clean the wound." ), _( "The wound is cleaned." ) ); } else { heal_msg( m_warning, _( "Your wound still aches." ), _( "The wound still looks bad." ) ); @@ -3254,10 +3287,10 @@ int heal_actor::finish_using( player &healer, player &patient, item &it, hp_part practice_amount += bite * 3.0f; } - if( patient.has_effect( effect_infected, bp_healed ) ) { + if( patient.has_effect( effect_infected, healed->token ) ) { if( x_in_y( infect, 1.0f ) ) { - const time_duration infected_dur = patient.get_effect_dur( effect_infected, bp_healed ); - patient.remove_effect( effect_infected, bp_healed ); + const time_duration infected_dur = patient.get_effect_dur( effect_infected, healed->token ); + patient.remove_effect( effect_infected, healed->token ); patient.add_effect( effect_recover, infected_dur ); heal_msg( m_good, _( "You disinfect the wound." ), _( "The wound is disinfected." ) ); } else { @@ -3296,18 +3329,20 @@ int heal_actor::finish_using( player &healer, player &patient, item &it, hp_part // apply healing over time effects if( bandages_power > 0 ) { int bandages_intensity = get_bandaged_level( healer ); - patient.add_effect( effect_bandaged, 1_turns, bp_healed ); - effect &e = patient.get_effect( effect_bandaged, bp_healed ); + patient.add_effect( effect_bandaged, 1_turns, healed->token ); + effect &e = patient.get_effect( effect_bandaged, healed->token ); e.set_duration( e.get_int_dur_factor() * bandages_intensity ); - patient.damage_bandaged[healed] = patient.get_part_hp_max( bp ) - patient.get_part_hp_cur( bp ); + patient.set_part_damage_bandaged( healed, + patient.get_part_hp_max( healed ) - patient.get_part_hp_cur( healed ) ); practice_amount += 2 * bandages_intensity; } if( disinfectant_power > 0 ) { int disinfectant_intensity = get_disinfected_level( healer ); - patient.add_effect( effect_disinfected, 1_turns, bp_healed ); - effect &e = patient.get_effect( effect_disinfected, bp_healed ); + patient.add_effect( effect_disinfected, 1_turns, healed->token ); + effect &e = patient.get_effect( effect_disinfected, healed->token ); e.set_duration( e.get_int_dur_factor() * disinfectant_intensity ); - patient.damage_disinfected[healed] = patient.get_part_hp_max( bp ) - patient.get_part_hp_cur( bp ); + patient.set_part_damage_disinfected( healed, + patient.get_part_hp_max( healed ) - patient.get_part_hp_cur( healed ) ); practice_amount += 2 * disinfectant_intensity; } practice_amount = std::max( 9.0f, practice_amount ); @@ -3316,14 +3351,14 @@ int heal_actor::finish_using( player &healer, player &patient, item &it, hp_part return it.type->charges_to_use(); } -static hp_part pick_part_to_heal( +static bodypart_id pick_part_to_heal( const player &healer, const player &patient, const std::string &menu_header, int limb_power, int head_bonus, int torso_bonus, - float bleed_chance, float bite_chance, float infect_chance, + int bleed_stop, float bite_chance, float infect_chance, bool force, float bandage_power, float disinfectant_power ) { - const bool bleed = bleed_chance > 0.0f; + const bool bleed = bleed_stop > 0; const bool bite = bite_chance > 0.0f; const bool infect = infect_chance > 0.0f; const bool precise = &healer == &patient ? @@ -3333,24 +3368,23 @@ static hp_part pick_part_to_heal( /** @EFFECT_FIRSTAID increases precision when using first aid on someone else */ ( healer.get_skill_level( skill_firstaid ) * 4 + healer.per_cur >= 20 ); while( true ) { - hp_part healed_part = patient.body_window( menu_header, force, precise, - limb_power, head_bonus, torso_bonus, - bleed_chance, bite_chance, infect_chance, bandage_power, disinfectant_power ); - if( healed_part == num_hp_parts ) { - return num_hp_parts; + bodypart_id healed_part = patient.body_window( menu_header, force, precise, + limb_power, head_bonus, torso_bonus, + bleed_stop, bite_chance, infect_chance, bandage_power, disinfectant_power ); + if( healed_part == bodypart_id( "num_bp" ) ) { + return bodypart_id( "num_bp" ); } - const bodypart_id &bp = convert_bp( player::hp_to_bp( healed_part ) ).id(); - if( ( infect && patient.has_effect( effect_infected, bp->token ) ) || - ( bite && patient.has_effect( effect_bite, bp->token ) ) || - ( bleed && patient.has_effect( effect_bleed, bp->token ) ) ) { + if( ( infect && patient.has_effect( effect_infected, healed_part->token ) ) || + ( bite && patient.has_effect( effect_bite, healed_part->token ) ) || + ( bleed && patient.has_effect( effect_bleed, healed_part->token ) ) ) { return healed_part; } - if( patient.is_limb_broken( bp ) ) { - if( healed_part == hp_arm_l || healed_part == hp_arm_r ) { + if( patient.is_limb_broken( healed_part ) ) { + if( healed_part == bodypart_id( "arm_l" ) || healed_part == bodypart_id( "arm_r" ) ) { add_msg( m_info, _( "That arm is broken. It needs surgical attention or a splint." ) ); - } else if( healed_part == hp_leg_l || healed_part == hp_leg_r ) { + } else if( healed_part == bodypart_id( "leg_l" ) || healed_part == bodypart_id( "leg_r" ) ) { add_msg( m_info, _( "That leg is broken. It needs surgical attention or a splint." ) ); } else { add_msg( m_info, "That body part is bugged. It needs developer's attention." ); @@ -3359,29 +3393,30 @@ static hp_part pick_part_to_heal( continue; } - if( force || patient.get_part_hp_cur( bp ) < patient.get_part_hp_max( bp ) ) { + if( force || patient.get_part_hp_cur( healed_part ) < patient.get_part_hp_max( healed_part ) ) { return healed_part; } } } -hp_part heal_actor::use_healing_item( player &healer, player &patient, item &it, bool force ) const +bodypart_id heal_actor::use_healing_item( player &healer, player &patient, item &it, + bool force ) const { bodypart_id healed = bodypart_id( "num_bp" ); - const int head_bonus = get_heal_value( healer, hp_head ); - const int limb_power = get_heal_value( healer, hp_arm_l ); - const int torso_bonus = get_heal_value( healer, hp_torso ); + const int head_bonus = get_heal_value( healer, bodypart_id( "head" ) ); + const int limb_power = get_heal_value( healer, bodypart_id( "arm_l" ) ); + const int torso_bonus = get_heal_value( healer, bodypart_id( "torso" ) ); if( !patient.can_use_heal_item( it ) ) { patient.add_msg_player_or_npc( m_bad, _( "Your biology is not compatible with that item." ), _( "'s biology is not compatible with that item." ) ); - return num_hp_parts; // canceled + return bodypart_id( "num_bp" ); // canceled } if( healer.is_npc() ) { - // NPCs heal whatever has sustained the most damaged that they can heal but never - // rebandage parts + // NPCs heal whatever has sustained the most damage that they can heal but don't + // rebandage parts unless they are bleeding significantly int highest_damage = 0; for( const std::pair &elem : patient.get_body() ) { const bodypart &part = elem.second; @@ -3389,10 +3424,12 @@ hp_part heal_actor::use_healing_item( player &healer, player &patient, item &it, if( ( !patient.has_effect( effect_bandaged, elem.first->token ) && bandages_power > 0 ) || ( !patient.has_effect( effect_disinfected, elem.first->token ) && disinfectant_power > 0 ) ) { damage += part.get_hp_max() - part.get_hp_cur(); - damage += bleed * patient.get_effect_dur( effect_bleed, elem.first->token ) / 5_minutes; damage += bite * patient.get_effect_dur( effect_bite, elem.first->token ) / 10_minutes; damage += infect * patient.get_effect_dur( effect_infected, elem.first->token ) / 10_minutes; } + if( patient.get_effect_int( effect_bleed, elem.first->token ) > 5 && bleed > 0 ) { + damage += bleed * patient.get_effect_dur( effect_bleed, elem.first->token ) / 5_minutes; + } if( damage > highest_damage ) { highest_damage = damage; healed = elem.first.id(); @@ -3402,24 +3439,21 @@ hp_part heal_actor::use_healing_item( player &healer, player &patient, item &it, // Player healing self - let player select if( healer.activity.id() != ACT_FIRSTAID ) { const std::string menu_header = _( "Select a body part for: " ) + it.tname(); - healed = convert_bp( Character::hp_to_bp( pick_part_to_heal( healer, patient, menu_header, - limb_power, head_bonus, torso_bonus, - bleed, bite, infect, force, - get_bandaged_level( healer ), - get_disinfected_level( healer ) ) ) ).id(); + healed = pick_part_to_heal( healer, patient, menu_header, limb_power, head_bonus, torso_bonus, + get_stopbleed_level( healer ), bite, infect, force, get_bandaged_level( healer ), + get_disinfected_level( healer ) ); if( healed == bodypart_id( "num_bp" ) ) { add_msg( m_info, _( "Never mind." ) ); - return num_hp_parts; // canceled + return bodypart_id( "num_bp" ); // canceled } } // Brick healing if using a first aid kit for the first time. if( long_action && healer.activity.id() != ACT_FIRSTAID ) { // Cancel and wait for activity completion. - return Character::bp_to_hp( healed->token ); + return healed; } else if( healer.activity.id() == ACT_FIRSTAID ) { // Completed activity, extract body part from it. - healed = convert_bp( Character::hp_to_bp( static_cast - ( healer.activity.values[0] ) ) ).id(); + healed = bodypart_id( healer.activity.str_values[0] ); } } else { // Player healing NPC @@ -3428,27 +3462,26 @@ hp_part heal_actor::use_healing_item( player &healer, player &patient, item &it, //~ %1$s: patient name, %2$s: healing item name "Select a body part of %1$s for %2$s:" ), patient.disp_name(), it.tname() ); - healed = convert_bp( Character::hp_to_bp( pick_part_to_heal( healer, patient, menu_header, - limb_power, head_bonus, torso_bonus, - bleed, bite, infect, force, - get_bandaged_level( healer ), - get_disinfected_level( healer ) ) ) ).id(); + healed = pick_part_to_heal( healer, patient, menu_header, limb_power, head_bonus, torso_bonus, + get_stopbleed_level( healer ), bite, infect, force, get_bandaged_level( healer ), + get_disinfected_level( healer ) ); } if( healed != bodypart_id( "num_bp" ) ) { - finish_using( healer, patient, it, Character::bp_to_hp( healed->token ) ); + finish_using( healer, patient, it, healed ); } - return Character::bp_to_hp( healed->token ); + return healed; } void heal_actor::info( const item &, std::vector &dump ) const { if( head_power > 0 || torso_power > 0 || limb_power > 0 || bandages_power > 0 || - disinfectant_power > 0 || bleed > 0.0f || bite > 0.0f || infect > 0.0f ) { + disinfectant_power > 0 || bleed > 0 || bite > 0.0f || infect > 0.0f ) { dump.emplace_back( "HEAL", _( "Healing effects " ) ); } + Character &player_character = get_player_character(); if( head_power > 0 || torso_power > 0 || limb_power > 0 ) { dump.emplace_back( "HEAL", _( "Base healing: " ) ); dump.emplace_back( "HEAL_BASE", _( "Head: " ), "", iteminfo::no_newline, head_power ); @@ -3457,10 +3490,11 @@ void heal_actor::info( const item &, std::vector &dump ) const if( g != nullptr ) { dump.emplace_back( "HEAL", _( "Actual healing: " ) ); dump.emplace_back( "HEAL_ACT", _( "Head: " ), "", iteminfo::no_newline, - get_heal_value( g->u, hp_head ) ); + get_heal_value( player_character, bodypart_id( "head" ) ) ); dump.emplace_back( "HEAL_ACT", _( " Torso: " ), "", iteminfo::no_newline, - get_heal_value( g->u, hp_torso ) ); - dump.emplace_back( "HEAL_ACT", _( " Limbs: " ), get_heal_value( g->u, hp_arm_l ) ); + get_heal_value( player_character, bodypart_id( "torso" ) ) ); + dump.emplace_back( "HEAL_ACT", _( " Limbs: " ), get_heal_value( player_character, + bodypart_id( "arm_l" ) ) ); } } @@ -3469,7 +3503,7 @@ void heal_actor::info( const item &, std::vector &dump ) const texitify_base_healing_power( static_cast( bandages_power ) ) ); if( g != nullptr ) { dump.emplace_back( "HEAL", _( "Actual bandaging quality: " ), - texitify_healing_power( get_bandaged_level( g->u ) ) ); + texitify_healing_power( get_bandaged_level( player_character ) ) ); } } @@ -3478,16 +3512,18 @@ void heal_actor::info( const item &, std::vector &dump ) const texitify_base_healing_power( static_cast( disinfectant_power ) ) ); if( g != nullptr ) { dump.emplace_back( "HEAL", _( "Actual disinfecting quality: " ), - texitify_healing_power( get_disinfected_level( g->u ) ) ); + texitify_healing_power( get_disinfected_level( player_character ) ) ); } } - - if( bleed > 0.0f || bite > 0.0f || infect > 0.0f ) { - dump.emplace_back( "HEAL", _( "Chance to heal (percent): " ) ); - if( bleed > 0.0f ) { - dump.emplace_back( "HEAL", _( "* Bleeding: " ), - static_cast( bleed * 100 ) ); + if( bleed > 0 ) { + dump.emplace_back( "HEAL", _( "Effect on bleeding: " ), texitify_bandage_power( bleed ) ); + if( g != nullptr ) { + dump.emplace_back( "HEAL", _( "Actual effect on bleeding: " ), + texitify_healing_power( get_stopbleed_level( g->u ) ) ); } + } + if( bite > 0.0f || infect > 0.0f ) { + dump.emplace_back( "HEAL", _( "Chance to heal (percent): " ) ); if( bite > 0.0f ) { dump.emplace_back( "HEAL", _( "* Bite: " ), static_cast( bite * 100 ) ); @@ -3497,7 +3533,6 @@ void heal_actor::info( const item &, std::vector &dump ) const static_cast( infect * 100 ) ); } } - dump.emplace_back( "HEAL", _( "Moves to use: " ), move_cost ); } @@ -3537,15 +3572,17 @@ std::unique_ptr place_trap_actor::clone() const static bool is_solid_neighbor( const tripoint &pos, const point &offset ) { + map &here = get_map(); const tripoint a = pos + tripoint( offset, 0 ); const tripoint b = pos - tripoint( offset, 0 ); - return g->m.move_cost( a ) != 2 && g->m.move_cost( b ) != 2; + return here.move_cost( a ) != 2 && here.move_cost( b ) != 2; } static bool has_neighbor( const tripoint &pos, const ter_id &terrain_id ) { - for( const tripoint &t : g->m.points_in_radius( pos, 1, 0 ) ) { - if( g->m.ter( t ) == terrain_id ) { + map &here = get_map(); + for( const tripoint &t : here.points_in_radius( pos, 1, 0 ) ) { + if( here.ter( t ) == terrain_id ) { return true; } } @@ -3559,7 +3596,8 @@ bool place_trap_actor::is_allowed( player &p, const tripoint &pos, const std::st name ); return false; } - if( g->m.move_cost( pos ) != 2 ) { + map &here = get_map(); + if( here.move_cost( pos ) != 2 ) { p.add_msg_if_player( m_info, _( "You can't place a %s there." ), name ); return false; } @@ -3575,14 +3613,14 @@ bool place_trap_actor::is_allowed( player &p, const tripoint &pos, const std::st needs_neighbor_terrain.obj().name() ); return false; } - const trap &existing_trap = g->m.tr_at( pos ); + const trap &existing_trap = here.tr_at( pos ); if( !existing_trap.is_null() ) { if( existing_trap.can_see( pos, p ) ) { p.add_msg_if_player( m_info, _( "You can't place a %s there. It contains a trap already." ), name ); } else { p.add_msg_if_player( m_bad, _( "You trigger a %s!" ), existing_trap.name() ); - existing_trap.trigger( pos, &p ); + existing_trap.trigger( pos, p ); } return false; } @@ -3591,8 +3629,9 @@ bool place_trap_actor::is_allowed( player &p, const tripoint &pos, const std::st static void place_and_add_as_known( player &p, const tripoint &pos, const trap_str_id &id ) { - g->m.trap_set( pos, id ); - const trap &tr = g->m.tr_at( pos ); + map &here = get_map(); + here.trap_set( pos, id ); + const trap &tr = here.tr_at( pos ); if( !tr.can_see( pos, p ) ) { p.add_known_trap( pos, tr ); } @@ -3620,13 +3659,14 @@ int place_trap_actor::use( player &p, item &it, bool, const tripoint & ) const return 0; } + map &here = get_map(); int distance_to_trap_center = unburied_data.trap.obj().get_trap_radius() + outer_layer_trap.obj().get_trap_radius() + 1; if( unburied_data.trap.obj().get_trap_radius() > 0 ) { // Math correction for multi-tile traps pos.x = ( pos.x - p.posx() ) * distance_to_trap_center + p.posx(); pos.y = ( pos.y - p.posy() ) * distance_to_trap_center + p.posy(); - for( const tripoint &t : g->m.points_in_radius( pos, outer_layer_trap.obj().get_trap_radius(), + for( const tripoint &t : here.points_in_radius( pos, outer_layer_trap.obj().get_trap_radius(), 0 ) ) { if( !is_allowed( p, t, it.tname() ) ) { p.add_msg_if_player( m_info, @@ -3638,7 +3678,7 @@ int place_trap_actor::use( player &p, item &it, bool, const tripoint & ) const } const bool has_shovel = p.has_quality( quality_id( "DIG" ), 3 ); - const bool is_diggable = g->m.has_flag( "DIGGABLE", pos ); + const bool is_diggable = here.has_flag( "DIGGABLE", pos ); bool bury = false; if( could_bury && has_shovel && is_diggable ) { bury = query_yn( _( bury_question ) ); @@ -3650,7 +3690,7 @@ int place_trap_actor::use( player &p, item &it, bool, const tripoint & ) const p.mod_moves( -data.moves ); place_and_add_as_known( p, pos, data.trap ); - for( const tripoint &t : g->m.points_in_radius( pos, data.trap.obj().get_trap_radius(), 0 ) ) { + for( const tripoint &t : here.points_in_radius( pos, data.trap.obj().get_trap_radius(), 0 ) ) { if( t != pos ) { place_and_add_as_known( p, t, outer_layer_trap ); } @@ -3666,9 +3706,10 @@ void emit_actor::load( const JsonObject &obj ) int emit_actor::use( player &, item &it, bool, const tripoint &pos ) const { + map &here = get_map(); const float scaling = scale_qty ? it.charges : 1; for( const auto &e : emits ) { - g->m.emit_field( pos, e, scaling ); + here.emit_field( pos, e, scaling ); } return 1; @@ -3728,8 +3769,8 @@ ret_val saw_barrel_actor::can_use_on( const player &, const item &, const return ret_val::make_failure( _( "It's not a gun." ) ); } - if( target.type->gun->barrel_length <= 0_ml ) { - return ret_val::make_failure( _( "The barrel is too short." ) ); + if( target.type->gun->barrel_volume <= 0_ml ) { + return ret_val::make_failure( _( "The barrel is too small." ) ); } if( target.gunmod_find( itype_barrel_small ) ) { @@ -3757,8 +3798,10 @@ std::unique_ptr saw_barrel_actor::clone() const int install_bionic_actor::use( player &p, item &it, bool, const tripoint & ) const { if( p.can_install_bionics( *it.type, p, false ) ) { - p.consume_installation_requirment( it.type->bionic->id ); - p.consume_anesth_requirment( *it.type, p ); + if( !p.has_trait( trait_DEBUG_BIONICS ) ) { + p.consume_installation_requirment( it.type->bionic->id ); + p.consume_anesth_requirment( *it.type, p ); + } return p.install_bionics( *it.type, p, false ) ? it.type->charges_to_use() : 0; } else { return 0; @@ -4042,13 +4085,14 @@ int deploy_tent_actor::use( player &p, item &it, bool, const tripoint & ) const } const tripoint direction = *dir; + map &here = get_map(); // We place the center of the structure (radius + 1) // spaces away from the player. // First check there's enough room. const tripoint center = p.pos() + tripoint( ( radius + 1 ) * direction.x, ( radius + 1 ) * direction.y, 0 ); - for( const tripoint &dest : g->m.points_in_radius( center, radius ) ) { - if( const auto vp = g->m.veh_at( dest ) ) { + for( const tripoint &dest : here.points_in_radius( center, radius ) ) { + if( const auto vp = here.veh_at( dest ) ) { add_msg( m_info, _( "The %s is in the way." ), vp->vehicle().name ); return 0; } @@ -4056,28 +4100,28 @@ int deploy_tent_actor::use( player &p, item &it, bool, const tripoint & ) const add_msg( m_info, _( "The %s is in the way." ), c->disp_name() ); return 0; } - if( g->m.impassable( dest ) || !g->m.has_flag( "FLAT", dest ) ) { + if( here.impassable( dest ) || !here.has_flag( "FLAT", dest ) ) { add_msg( m_info, _( "The %s in that direction isn't suitable for placing the %s." ), - g->m.name( dest ), it.tname() ); + here.name( dest ), it.tname() ); return 0; } - if( g->m.has_furn( dest ) ) { - add_msg( m_info, _( "There is already furniture (%s) there." ), g->m.furnname( dest ) ); + if( here.has_furn( dest ) ) { + add_msg( m_info, _( "There is already furniture (%s) there." ), here.furnname( dest ) ); return 0; } } // Make a square of floor surrounded by wall. - for( const tripoint &dest : g->m.points_in_radius( center, radius ) ) { - g->m.furn_set( dest, wall ); + for( const tripoint &dest : here.points_in_radius( center, radius ) ) { + here.furn_set( dest, wall ); } - for( const tripoint &dest : g->m.points_in_radius( center, radius - 1 ) ) { - g->m.furn_set( dest, floor ); + for( const tripoint &dest : here.points_in_radius( center, radius - 1 ) ) { + here.furn_set( dest, floor ); } // Place the center floor and the door. if( floor_center ) { - g->m.furn_set( center, *floor_center ); + here.furn_set( center, *floor_center ); } - g->m.furn_set( p.pos() + direction, door_closed ); + here.furn_set( p.pos() + direction, door_closed ); add_msg( m_info, _( "You set up the %s on the ground." ), it.tname() ); add_msg( m_info, _( "Examine the center square to pack it up again." ) ); return 1; @@ -4085,8 +4129,9 @@ int deploy_tent_actor::use( player &p, item &it, bool, const tripoint & ) const bool deploy_tent_actor::check_intact( const tripoint ¢er ) const { - for( const tripoint &dest : g->m.points_in_radius( center, radius ) ) { - const furn_id fid = g->m.furn( dest ); + map &here = get_map(); + for( const tripoint &dest : here.points_in_radius( center, radius ) ) { + const furn_id fid = here.furn( dest ); if( dest == center && floor_center ) { if( fid != *floor_center ) { return false; @@ -4291,8 +4336,8 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const desc += format_desc_string( _( "Acid" ), mod.acid_resist(), temp_item.acid_resist(), true ); desc += format_desc_string( _( "Fire" ), mod.fire_resist(), temp_item.fire_resist(), true ); desc += format_desc_string( _( "Warmth" ), mod.get_warmth(), temp_item.get_warmth(), true ); - desc += format_desc_string( _( "Encumbrance" ), mod.get_encumber( p ), temp_item.get_encumber( p ), - false ); + desc += format_desc_string( _( "Encumbrance" ), mod.get_avg_encumber( p ), + temp_item.get_avg_encumber( p ), false ); tmenu.addentry_desc( index++, enab, MENU_AUTOASSIGN, prompt, desc ); } @@ -4341,7 +4386,7 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const mod.tname( 1, false ), startdurability, resultdurability ); if( destroyed ) { p.add_msg_if_player( m_bad, _( "You destroy it!" ) ); - p.i_rem_keep_contents( p.get_item_position( &mod ) ); + p.i_rem_keep_contents( &mod ); } return thread_needed / 2; } else if( rn <= 10 ) { diff --git a/src/iuse_actor.h b/src/iuse_actor.h index e2a14bfc7b43e..dccd8013f536d 100644 --- a/src/iuse_actor.h +++ b/src/iuse_actor.h @@ -30,7 +30,6 @@ class player; struct iteminfo; struct tripoint; -enum hp_part : int; enum body_part : int; class JsonObject; class item_location; @@ -895,8 +894,8 @@ class heal_actor : public iuse_actor float disinfectant_power = 0; /** Extra intensity levels gained per skill level when healing limbs. */ float disinfectant_scaling = 0; - /** Chance to remove bleed effect. */ - float bleed = 0; + /** How many levels of bleeding effect intensity can it remove (dressing efficiency). */ + int bleed = 0; /** Chance to remove bite effect. */ float bite = 0; /** Chance to remove infected effect. */ @@ -924,15 +923,17 @@ class heal_actor : public iuse_actor std::set used_up_item_flags; /** How much hp would `healer` heal using this actor on `healed` body part. */ - int get_heal_value( const player &healer, hp_part healed ) const; + int get_heal_value( const Character &healer, bodypart_id healed ) const; /** How many intensity levels will be applied using this actor by `healer`. */ - int get_bandaged_level( const player &healer ) const; + int get_bandaged_level( const Character &healer ) const; /** How many intensity levels will be applied using this actor by `healer`. */ - int get_disinfected_level( const player &healer ) const; + int get_disinfected_level( const Character &healer ) const; + /** How many intensity levels of bleeding will be reduced using this actor by `healer`. */ + int get_stopbleed_level( const Character &healer ) const; /** Does the actual healing. Used by both long and short actions. Returns charges used. */ - int finish_using( player &healer, player &patient, item &it, hp_part healed ) const; + int finish_using( player &healer, player &patient, item &it, bodypart_id healed ) const; - hp_part use_healing_item( player &healer, player &patient, item &it, bool force ) const; + bodypart_id use_healing_item( player &healer, player &patient, item &it, bool force ) const; heal_actor( const std::string &type = "heal" ) : iuse_actor( type ) {} diff --git a/src/kill_tracker.cpp b/src/kill_tracker.cpp index 5cee5f4cccd37..63748db738ee8 100644 --- a/src/kill_tracker.cpp +++ b/src/kill_tracker.cpp @@ -121,7 +121,7 @@ void kill_tracker::notify( const cata::event &e ) switch( e.type() ) { case event_type::character_kills_monster: { character_id killer = e.get( "killer" ); - if( killer != get_avatar().getID() ) { + if( killer != get_player_character().getID() ) { // TODO: add a kill counter for npcs? break; } @@ -131,7 +131,7 @@ void kill_tracker::notify( const cata::event &e ) } case event_type::character_kills_character: { character_id killer = e.get( "killer" ); - if( killer != get_avatar().getID() ) { + if( killer != get_player_character().getID() ) { break; } std::string victim_name = e.get( "victim_name" ); diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 32f81d7d94a8e..29096b3252caa 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -90,7 +90,7 @@ bool map::build_transparency_cache( const int zlev ) &transparency_cache[0][0], MAPSIZE_X * MAPSIZE_Y, static_cast( LIGHT_TRANSPARENCY_OPEN_AIR ) ); - const float sight_penalty = weather::sight_penalty( g->weather.weather ); + const float sight_penalty = get_weather().weather_id->sight_penalty; // Traverse the submaps in order for( int smx = 0; smx < my_MAPSIZE; ++smx ) { @@ -245,7 +245,7 @@ void map::build_sunlight_cache( int zlev ) const auto &prev_transparency_cache = prev_map_cache.transparency_cache; const auto &prev_floor_cache = prev_map_cache.floor_cache; const auto &outside_cache = map_cache.outside_cache; - const float sight_penalty = weather::sight_penalty( g->weather.weather ); + const float sight_penalty = get_weather().weather_id->sight_penalty; for( int x = 0, prev_x = offset.x; x < MAPSIZE_X; x++, prev_x++ ) { bool x_inbounds = prev_x >= 0 && prev_x < MAPSIZE_X; for( int y = 0, prev_y = offset.y; y < MAPSIZE_Y; y++, prev_y++ ) { diff --git a/src/magic.cpp b/src/magic.cpp index 3147ea802946d..016e4e64984e9 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -9,7 +9,6 @@ #include #include -#include "avatar.h" #include "calendar.h" #include "cata_utility.h" #include "catacharset.h" @@ -676,7 +675,8 @@ int spell::energy_cost( const Character &guy ) const } if( !has_flag( spell_flag::NO_HANDS ) ) { // the first 10 points of combined encumbrance is ignored, but quickly adds up - const int hands_encumb = std::max( 0, guy.encumb( bp_hand_l ) + guy.encumb( bp_hand_r ) - 10 ); + const int hands_encumb = std::max( 0, + guy.encumb( bodypart_id( "hand_l" ) ) + guy.encumb( bodypart_id( "hand_r" ) ) - 10 ); switch( type->energy_source ) { default: cost += 10 * hands_encumb; @@ -732,7 +732,7 @@ int spell::get_difficulty() const return type->difficulty; } -int spell::casting_time( const Character &guy ) const +int spell::casting_time( const Character &guy, bool ignore_encumb ) const { // casting time in moves int casting_time = 0; @@ -747,15 +747,19 @@ int spell::casting_time( const Character &guy ) const } else { casting_time = type->base_casting_time; } - if( !has_flag( spell_flag::NO_LEGS ) ) { - // the first 20 points of encumbrance combined is ignored - const int legs_encumb = std::max( 0, guy.encumb( bp_leg_l ) + guy.encumb( bp_leg_r ) - 20 ); - casting_time += legs_encumb * 3; - } - if( has_flag( spell_flag::SOMATIC ) ) { - // the first 20 points of encumbrance combined is ignored - const int arms_encumb = std::max( 0, guy.encumb( bp_arm_l ) + guy.encumb( bp_arm_r ) - 20 ); - casting_time += arms_encumb * 2; + if( !ignore_encumb ) { + if( !has_flag( spell_flag::NO_LEGS ) ) { + // the first 20 points of encumbrance combined is ignored + const int legs_encumb = std::max( 0, + guy.encumb( bodypart_id( "leg_l" ) ) + guy.encumb( bodypart_id( "leg_r" ) ) - 20 ); + casting_time += legs_encumb * 3; + } + if( has_flag( spell_flag::SOMATIC ) ) { + // the first 20 points of encumbrance combined is ignored + const int arms_encumb = std::max( 0, + guy.encumb( bodypart_id( "arm_l" ) ) + guy.encumb( bodypart_id( "arm_r" ) ) - 20 ); + casting_time += arms_encumb * 2; + } } return casting_time; } @@ -794,13 +798,14 @@ float spell::spell_fail( const Character &guy ) const float fail_chance = std::pow( ( effective_skill - 30.0f ) / 30.0f, 2 ); if( has_flag( spell_flag::SOMATIC ) && !guy.has_trait_flag( "SUBTLE_SPELL" ) ) { // the first 20 points of encumbrance combined is ignored - const int arms_encumb = std::max( 0, guy.encumb( bp_arm_l ) + guy.encumb( bp_arm_r ) - 20 ); + const int arms_encumb = std::max( 0, + guy.encumb( bodypart_id( "arm_l" ) ) + guy.encumb( bodypart_id( "arm_r" ) ) - 20 ); // each encumbrance point beyond the "gray" color counts as half an additional fail % fail_chance += arms_encumb / 200.0f; } if( has_flag( spell_flag::VERBAL ) && !guy.has_trait_flag( "SILENT_SPELL" ) ) { // a little bit of mouth encumbrance is allowed, but not much - const int mouth_encumb = std::max( 0, guy.encumb( bp_mouth ) - 5 ); + const int mouth_encumb = std::max( 0, guy.encumb( bodypart_id( "mouth" ) ) - 5 ); fail_chance += mouth_encumb / 100.0f; } // concentration spells work better than you'd expect with a higher focus pool @@ -878,7 +883,7 @@ std::string spell::energy_cost_string( const Character &guy ) const return colorize( to_string( energy_cost( guy ) ), c_light_blue ); } if( energy_source() == magic_energy_type::hp ) { - auto pair = get_hp_bar( energy_cost( guy ), guy.get_hp_max() / num_hp_parts ); + auto pair = get_hp_bar( energy_cost( guy ), guy.get_hp_max() / 6 ); return colorize( pair.first, pair.second ); } if( energy_source() == magic_energy_type::stamina ) { @@ -1297,7 +1302,7 @@ void known_magic::serialize( JsonOut &json ) const json.member( "spellbook" ); json.start_array(); - for( auto pair : spellbook ) { + for( const auto &pair : spellbook ) { json.start_object(); json.member( "id", pair.second.id() ); json.member( "xp", pair.second.xp() ); @@ -1419,7 +1424,7 @@ void known_magic::forget_spell( const spell_id &sp ) } add_msg( m_bad, _( "All knowledge of %s leaves you." ), sp->name ); // TODO: add parameter for owner of known_magic for this function - g->events().send( get_avatar().getID(), sp->id ); + g->events().send( get_player_character().getID(), sp->id ); spellbook.erase( sp ); } @@ -1563,8 +1568,8 @@ class spellcasting_callback : public uilist_callback int invlet = 0; invlet = popup_getkey( _( "Choose a new hotkey for this spell." ) ); if( inv_chars.valid( invlet ) ) { - const bool invlet_set = g->u.magic.set_invlet( known_spells[entnum]->id(), invlet, - reserved_invlets ); + const bool invlet_set = + get_player_character().magic.set_invlet( known_spells[entnum]->id(), invlet, reserved_invlets ); if( !invlet_set ) { popup( _( "Hotkey already used." ) ); } else { @@ -1573,7 +1578,7 @@ class spellcasting_callback : public uilist_callback } } else { popup( _( "Hotkey removed." ) ); - g->u.magic.rem_invlet( known_spells[entnum]->id() ); + get_player_character().magic.rem_invlet( known_spells[entnum]->id() ); } return true; } @@ -1606,11 +1611,13 @@ static bool casting_time_encumbered( const spell &sp, const Character &guy ) int encumb = 0; if( !sp.has_flag( spell_flag::NO_LEGS ) ) { // the first 20 points of encumbrance combined is ignored - encumb += std::max( 0, guy.encumb( bp_leg_l ) + guy.encumb( bp_leg_r ) - 20 ); + encumb += std::max( 0, guy.encumb( bodypart_id( "leg_l" ) ) + guy.encumb( + bodypart_id( "leg_r" ) ) - 20 ); } if( sp.has_flag( spell_flag::SOMATIC ) ) { // the first 20 points of encumbrance combined is ignored - encumb += std::max( 0, guy.encumb( bp_arm_l ) + guy.encumb( bp_arm_r ) - 20 ); + encumb += std::max( 0, guy.encumb( bodypart_id( "arm_l" ) ) + guy.encumb( + bodypart_id( "arm_r" ) ) - 20 ); } return encumb > 0; } @@ -1618,7 +1625,9 @@ static bool casting_time_encumbered( const spell &sp, const Character &guy ) static bool energy_cost_encumbered( const spell &sp, const Character &guy ) { if( !sp.has_flag( spell_flag::NO_HANDS ) ) { - return std::max( 0, guy.encumb( bp_hand_l ) + guy.encumb( bp_hand_r ) - 10 ) > 0; + return std::max( 0, guy.encumb( bodypart_id( "hand_l" ) ) + guy.encumb( + bodypart_id( "hand_r" ) ) - 10 ) > + 0; } return false; } @@ -1687,7 +1696,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu string_format( "%s: %d", _( "Max Level" ), sp.get_max_level() ) ); print_colored_text( w_menu, point( h_col1, line ), gray, gray, - sp.colorized_fail_percent( g->u ) ); + sp.colorized_fail_percent( get_player_character() ) ); print_colored_text( w_menu, point( h_col2, line++ ), gray, gray, string_format( "%s: %d", _( "Difficulty" ), sp.get_difficulty() ) ); @@ -1701,21 +1710,21 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu line++; } - const bool cost_encumb = energy_cost_encumbered( sp, g->u ); + const bool cost_encumb = energy_cost_encumbered( sp, get_player_character() ); std::string cost_string = cost_encumb ? _( "Casting Cost (impeded)" ) : _( "Casting Cost" ); std::string energy_cur = sp.energy_source() == magic_energy_type::hp ? "" : - string_format( _( " (%s current)" ), sp.energy_cur_string( g->u ) ); - if( !sp.can_cast( g->u ) ) { + string_format( _( " (%s current)" ), sp.energy_cur_string( get_player_character() ) ); + if( !sp.can_cast( get_player_character() ) ) { cost_string = colorize( _( "Not Enough Energy" ), c_red ); energy_cur = ""; } print_colored_text( w_menu, point( h_col1, line++ ), gray, gray, string_format( "%s: %s %s%s", cost_string, - sp.energy_cost_string( g->u ), sp.energy_string(), energy_cur ) ); - const bool c_t_encumb = casting_time_encumbered( sp, g->u ); + sp.energy_cost_string( get_player_character() ), sp.energy_string(), energy_cur ) ); + const bool c_t_encumb = casting_time_encumbered( sp, get_player_character() ); print_colored_text( w_menu, point( h_col1, line++ ), gray, gray, colorize( string_format( "%s: %s", c_t_encumb ? _( "Casting Time (impeded)" ) : _( "Casting Time" ), - moves_to_string( sp.casting_time( g->u ) ) ), + moves_to_string( sp.casting_time( get_player_character() ) ) ), c_t_encumb ? c_red : c_light_gray ) ); if( line <= win_height * 3 / 4 ) { @@ -2159,7 +2168,7 @@ void spell_events::notify( const cata::event &e ) int learn_at_level = it->second; if( learn_at_level == slvl ) { std::string learn_spell_id = it->first; - g->u.magic.learn_spell( learn_spell_id, g->u ); + get_player_character().magic.learn_spell( learn_spell_id, get_player_character() ); spell_type spell_learned = spell_factory.obj( spell_id( learn_spell_id ) ); add_msg( _( "Your experience and knowledge in creating and manipulating magical energies to cast %s have opened your eyes to new possibilities, you can now cast %s." ), diff --git a/src/magic.h b/src/magic.h index a46ad99c80cce..cded00ea86f74 100644 --- a/src/magic.h +++ b/src/magic.h @@ -358,7 +358,7 @@ class spell float spell_fail( const Character &guy ) const; std::string colorized_fail_percent( const Character &guy ) const; // how long does it take to cast the spell - int casting_time( const Character &guy ) const; + int casting_time( const Character &guy, bool ignore_encumb = false ) const; // can the Character cast this spell? bool can_cast( const Character &guy ) const; diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 64f82b989ff22..b4fb44ef4e478 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -17,23 +17,6 @@ #include "string_id.h" #include "units.h" -template struct enum_traits; - -template<> -struct enum_traits { - static constexpr enchantment::has last = enchantment::has::NUM_HAS; -}; - -template<> -struct enum_traits { - static constexpr enchantment::condition last = enchantment::condition::NUM_CONDITION; -}; - -template<> -struct enum_traits { - static constexpr enchant_vals::mod last = enchant_vals::mod::NUM_MOD; -}; - namespace io { // *INDENT-OFF* @@ -90,12 +73,10 @@ namespace io case enchant_vals::mod::BONUS_BLOCK: return "BONUS_BLOCK"; case enchant_vals::mod::BONUS_DODGE: return "BONUS_DODGE"; case enchant_vals::mod::ATTACK_NOISE: return "ATTACK_NOISE"; - case enchant_vals::mod::SPELL_NOISE: return "SPELL_NOISE"; case enchant_vals::mod::SHOUT_NOISE: return "SHOUT_NOISE"; case enchant_vals::mod::FOOTSTEP_NOISE: return "FOOTSTEP_NOISE"; case enchant_vals::mod::SIGHT_RANGE: return "SIGHT_RANGE"; case enchant_vals::mod::CARRY_WEIGHT: return "CARRY_WEIGHT"; - case enchant_vals::mod::CARRY_VOLUME: return "CARRY_VOLUME"; case enchant_vals::mod::SOCIAL_LIE: return "SOCIAL_LIE"; case enchant_vals::mod::SOCIAL_PERSUADE: return "SOCIAL_PERSUADE"; case enchant_vals::mod::SOCIAL_INTIMIDATE: return "SOCIAL_INTIMIDATE"; @@ -366,6 +347,31 @@ void enchantment::force_add( const enchantment &rhs ) } } +void enchantment::set_has( enchantment::has value ) +{ + active_conditions.first = value; +} + +void enchantment::add_value_add( enchant_vals::mod value, int add_value ) +{ + values_add[value] = add_value; +} + +void enchantment::add_value_mult( enchant_vals::mod value, float mult_value ) +{ + values_multiply[value] = mult_value; +} + +void enchantment::add_hit_me( const fake_spell &sp ) +{ + hit_me_effect.push_back( sp ); +} + +void enchantment::add_hit_you( const fake_spell &sp ) +{ + hit_you_effect.push_back( sp ); +} + int enchantment::get_value_add( const enchant_vals::mod value ) const { const auto found = values_add.find( value ); @@ -384,6 +390,29 @@ double enchantment::get_value_multiply( const enchant_vals::mod value ) const return found->second; } +double enchantment::modify_value( const enchant_vals::mod mod_val, double value ) const +{ + value += get_value_add( mod_val ); + value *= 1.0 + get_value_multiply( mod_val ); + return value; +} + +units::energy enchantment::modify_value( const enchant_vals::mod mod_val, + units::energy value ) const +{ + value += units::from_millijoule( get_value_add( mod_val ) ); + value *= 1.0 + get_value_multiply( mod_val ); + return value; +} + +units::mass enchantment::modify_value( const enchant_vals::mod mod_val, + units::mass value ) const +{ + value += units::from_gram( get_value_add( mod_val ) ); + value *= 1.0 + get_value_multiply( mod_val ); + return value; +} + int enchantment::mult_bonus( enchant_vals::mod value_type, int base_value ) const { return get_value_multiply( value_type ) * base_value; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 053bd333deced..a05b0aa27a7b7 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -9,10 +9,12 @@ #include #include "calendar.h" +#include "enum_traits.h" #include "json.h" #include "magic.h" #include "optional.h" #include "type_id.h" +#include "units.h" class Character; class Creature; @@ -20,6 +22,8 @@ class item; namespace enchant_vals { +// the different types of values that can be modified by enchantments +// either the item directly or the Character, whichever is more appropriate enum class mod : int { // effects for the Character STRENGTH, @@ -38,19 +42,17 @@ enum class mod : int { REGEN_STAMINA, MAX_HP, // for all limbs! use with caution REGEN_HP, - THIRST, // cost or regen over time - FATIGUE, // cost or regen over time + THIRST, // thirst rate + FATIGUE, // fatigue rate PAIN, // cost or regen over time BONUS_DODGE, BONUS_BLOCK, BONUS_DAMAGE, ATTACK_NOISE, - SPELL_NOISE, SHOUT_NOISE, FOOTSTEP_NOISE, SIGHT_RANGE, CARRY_WEIGHT, - CARRY_VOLUME, SOCIAL_LIE, SOCIAL_PERSUADE, SOCIAL_INTIMIDATE, @@ -112,79 +114,6 @@ class enchantment UNDERWATER, NUM_CONDITION }; - // the different types of values that can be modified by enchantments - // either the item directly or the Character, whichever is more appropriate - enum mod { - // effects for the Character - STRENGTH, - DEXTERITY, - PERCEPTION, - INTELLIGENCE, - SPEED, - ATTACK_COST, - ATTACK_SPEED, // affects attack speed of item even if it's not the one you're wielding - MOVE_COST, - METABOLISM, - MAX_MANA, - REGEN_MANA, - BIONIC_POWER, - MAX_STAMINA, - REGEN_STAMINA, - MAX_HP, // for all limbs! use with caution - REGEN_HP, - THIRST, // cost or regen over time - FATIGUE, // cost or regen over time - PAIN, // cost or regen over time - BONUS_DODGE, - BONUS_BLOCK, - BONUS_DAMAGE, - ATTACK_NOISE, - SPELL_NOISE, - SHOUT_NOISE, - FOOTSTEP_NOISE, - SIGHT_RANGE, - CARRY_WEIGHT, - CARRY_VOLUME, - SOCIAL_LIE, - SOCIAL_PERSUADE, - SOCIAL_INTIMIDATE, - ARMOR_BASH, - ARMOR_CUT, - ARMOR_STAB, - ARMOR_BULLET, - ARMOR_HEAT, - ARMOR_COLD, - ARMOR_ELEC, - ARMOR_ACID, - ARMOR_BIO, - // effects for the item that has the enchantment - ITEM_DAMAGE_BASH, - ITEM_DAMAGE_CUT, - ITEM_DAMAGE_STAB, - ITEM_DAMAGE_BULLET, - ITEM_DAMAGE_HEAT, - ITEM_DAMAGE_COLD, - ITEM_DAMAGE_ELEC, - ITEM_DAMAGE_ACID, - ITEM_DAMAGE_BIO, - ITEM_DAMAGE_AP, // armor piercing - ITEM_ARMOR_BASH, - ITEM_ARMOR_CUT, - ITEM_ARMOR_STAB, - ITEM_ARMOR_BULLET, - ITEM_ARMOR_HEAT, - ITEM_ARMOR_COLD, - ITEM_ARMOR_ELEC, - ITEM_ARMOR_ACID, - ITEM_ARMOR_BIO, - ITEM_WEIGHT, - ITEM_ENCUMBRANCE, - ITEM_VOLUME, - ITEM_COVERAGE, - ITEM_ATTACK_SPEED, - ITEM_WET_PROTECTION, - NUM_MOD - }; static void load_enchantment( const JsonObject &jo, const std::string &src ); void load( const JsonObject &jo, const std::string &src = "" ); @@ -196,8 +125,20 @@ class enchantment // adds two enchantments together and ignores their conditions void force_add( const enchantment &rhs ); + void set_has( has value ); + + void add_value_add( enchant_vals::mod value, int add_value ); + void add_value_mult( enchant_vals::mod value, float mult_value ); + + void add_hit_me( const fake_spell &sp ); + void add_hit_you( const fake_spell &sp ); + int get_value_add( enchant_vals::mod value ) const; double get_value_multiply( enchant_vals::mod value ) const; + // the standard way of modifying a value, adds then multiplies. + double modify_value( enchant_vals::mod mod_val, double value ) const; + units::energy modify_value( enchant_vals::mod mod_val, units::energy value ) const; + units::mass modify_value( enchant_vals::mod mod_val, units::mass value ) const; // this enchantment has a valid condition and is in the right location bool is_active( const Character &guy, const item &parent ) const; @@ -250,4 +191,21 @@ class enchantment const fake_spell &sp ) const; }; +template struct enum_traits; + +template<> +struct enum_traits { + static constexpr enchantment::has last = enchantment::has::NUM_HAS; +}; + +template<> +struct enum_traits { + static constexpr enchantment::condition last = enchantment::condition::NUM_CONDITION; +}; + +template<> +struct enum_traits { + static constexpr enchant_vals::mod last = enchant_vals::mod::NUM_MOD; +}; + #endif // CATA_SRC_MAGIC_ENCHANTMENT_H diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index f3aed9077037f..6116154f6ff24 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -128,7 +128,7 @@ static void swap_pos( Creature &caster, const tripoint &target ) critter->setpos( caster.pos() ); caster.setpos( target ); //update map in case a monster swapped positions with the player - g->update_map( g->u ); + g->update_map( get_player_character() ); } void spell_effect::pain_split( const spell &sp, Creature &caster, const tripoint & ) @@ -162,9 +162,10 @@ static bool in_spell_aoe( const tripoint &start, const tripoint &end, const int if( ignore_walls ) { return true; } + map &here = get_map(); const std::vector trajectory = line_to( start, end ); for( const tripoint &pt : trajectory ) { - if( g->m.impassable( pt ) ) { + if( here.impassable( pt ) ) { return false; } } @@ -176,7 +177,7 @@ std::set spell_effect::spell_effect_blast( const spell &, const tripoi { std::set targets; // TODO: Make this breadth-first - for( const tripoint &potential_target : g->m.points_in_radius( target, aoe_radius ) ) { + for( const tripoint &potential_target : get_map().points_in_radius( target, aoe_radius ) ) { if( in_spell_aoe( target, potential_target, aoe_radius, ignore_walls ) ) { targets.emplace( potential_target ); } @@ -201,7 +202,7 @@ std::set spell_effect::spell_effect_cone( const spell &sp, const tripo for( const tripoint &ep : end_points ) { std::vector trajectory = line_to( source, ep ); for( const tripoint &tp : trajectory ) { - if( ignore_walls || g->m.passable( tp ) ) { + if( ignore_walls || get_map().passable( tp ) ) { targets.emplace( tp ); } else { break; @@ -219,7 +220,7 @@ static bool test_always_true( const tripoint & ) } static bool test_passable( const tripoint &p ) { - return g->m.passable( p ); + return get_map().passable( p ); } std::set spell_effect::spell_effect_line( const spell &, const tripoint &source, @@ -389,7 +390,7 @@ static std::set spell_effect_area( const spell &sp, const tripoint &ta explosion_colors[pt] = sp.damage_type_color(); } - explosion_handler::draw_custom_explosion( g->u.pos(), explosion_colors ); + explosion_handler::draw_custom_explosion( get_player_character().pos(), explosion_colors ); return targets; } @@ -419,14 +420,15 @@ static void add_effect_to_target( const tripoint &target, const spell &sp ) static void damage_targets( const spell &sp, Creature &caster, const std::set &targets ) { + map &here = get_map(); for( const tripoint &target : targets ) { if( !sp.is_valid_target( caster, target ) ) { continue; } sp.make_sound( target ); sp.create_field( target ); - if( sp.has_flag( spell_flag::IGNITE_FLAMMABLE ) && g->m.is_flammable( target ) ) { - g->m.add_field( target, fd_fire, 1, 10_minutes ); + if( sp.has_flag( spell_flag::IGNITE_FLAMMABLE ) && here.is_flammable( target ) ) { + here.add_field( target, fd_fire, 1, 10_minutes ); } Creature *const cr = g->critter_at( target ); if( !cr ) { @@ -462,7 +464,7 @@ void spell_effect::projectile_attack( const spell &sp, Creature &caster, { std::vector trajectory = line_to( caster.pos(), target ); for( std::vector::iterator iter = trajectory.begin(); iter != trajectory.end(); iter++ ) { - if( g->m.impassable( *iter ) ) { + if( get_map().impassable( *iter ) ) { if( iter != trajectory.begin() ) { target_attack( sp, caster, *( iter - 1 ) ); } else { @@ -522,7 +524,7 @@ static void magical_polymorph( monster &victim, Creature &caster, const spell &s return; } - if( g->u.sees( victim ) ) { + if( get_player_character().sees( victim ) ) { add_msg( _( "The %s transforms into a %s." ), victim.type->nname(), new_id->nname() ); } @@ -605,6 +607,7 @@ int area_expander::run( const tripoint ¢er ) // Number of nodes expanded. int expanded = 0; + map &here = get_map(); while( !frontier.empty() ) { int best_index = frontier.top(); frontier.pop(); @@ -613,7 +616,7 @@ int area_expander::run( const tripoint ¢er ) for( size_t i = 0; i < 8; i++ ) { tripoint pt = best.position + point( x_offset[ i ], y_offset[ i ] ); - if( g->m.impassable( pt ) ) { + if( here.impassable( pt ) ) { continue; } @@ -672,7 +675,7 @@ static void spell_move( const spell &sp, const Creature &caster, if( can_target_creature ) { if( Creature *victim = g->critter_at( from ) ) { - Creature::Attitude cr_att = victim->attitude_to( g->u ); + Creature::Attitude cr_att = victim->attitude_to( get_player_character() ); bool valid = cr_att != Creature::Attitude::FRIENDLY && sp.is_valid_effect_target( spell_target::hostile ); valid |= cr_att == Creature::Attitude::FRIENDLY && sp.is_valid_effect_target( spell_target::ally ); @@ -683,10 +686,11 @@ static void spell_move( const spell &sp, const Creature &caster, } } + map &here = get_map(); // Moving items if( sp.is_valid_effect_target( spell_target::item ) ) { - map_stack src_items = g->m.i_at( from ); - map_stack dst_items = g->m.i_at( to ); + map_stack src_items = here.i_at( from ); + map_stack dst_items = here.i_at( to ); for( const item &item : src_items ) { dst_items.insert( item ); } @@ -694,15 +698,15 @@ static void spell_move( const spell &sp, const Creature &caster, } // Helper function to move particular field type if corresponding target flag is enabled. - auto move_field = [&sp, from, to]( spell_target target, field_type_id fid ) { + auto move_field = [&sp, from, to, &here]( spell_target target, field_type_id fid ) { if( !sp.is_valid_effect_target( target ) ) { return; } - auto &src_field = g->m.field_at( from ); + auto &src_field = here.field_at( from ); if( field_entry *entry = src_field.find_field( fid ) ) { int intensity = entry->get_field_intensity(); - g->m.remove_field( from, fid ); - g->m.set_field_intensity( to, fid, intensity ); + here.remove_field( from, fid ); + here.set_field_intensity( to, fid, intensity ); } }; // Moving fields. @@ -760,17 +764,18 @@ void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const if( sp.has_flag( spell_flag::WITH_CONTAINER ) ) { granted = granted.in_its_container(); } - if( g->u.can_wear( granted ).success() ) { + avatar &player_character = get_avatar(); + if( player_character.can_wear( granted ).success() ) { granted.set_flag( "FIT" ); - g->u.wear_item( granted, false ); - } else if( !g->u.is_armed() && g->u.wield( granted, 0 ) ) { + player_character.wear_item( granted, false ); + } else if( !player_character.is_armed() && player_character.wield( granted, 0 ) ) { // nothing to do } else { - g->u.i_add( granted ); + player_character.i_add( granted ); } if( !granted.count_by_charges() ) { for( int i = 1; i < sp.damage(); i++ ) { - g->u.i_add( granted ); + player_character.i_add( granted ); } } sp.make_sound( caster.pos() ); @@ -908,11 +913,12 @@ void spell_effect::spawn_summoned_monster( const spell &sp, Creature &caster, void spell_effect::spawn_summoned_vehicle( const spell &sp, Creature &caster, const tripoint &target ) { - if( g->m.veh_at( target ) ) { + ::map &here = get_map(); + if( here.veh_at( target ) ) { caster.add_msg_if_player( m_bad, _( "There is already a vehicle there." ) ); return; } - if( vehicle *veh = g->m.add_vehicle( sp.summon_vehicle_id(), target, -90, 100, 0 ) ) { + if( vehicle *veh = here.add_vehicle( sp.summon_vehicle_id(), target, -90, 100, 0 ) ) { veh->magic = true; if( !sp.has_flag( spell_flag::PERMANENT ) ) { veh->summon_time_limit = sp.duration_turns(); @@ -1084,12 +1090,13 @@ void spell_effect::mutate( const spell &sp, Creature &caster, const tripoint &ta void spell_effect::bash( const spell &sp, Creature &caster, const tripoint &target ) { + ::map &here = get_map(); const std::set area = spell_effect_blast( sp, caster.pos(), target, sp.aoe(), false ); for( const tripoint &potential_target : area ) { if( !sp.is_valid_target( caster, potential_target ) ) { continue; } // the bash already makes noise, so no need for spell::make_sound() - g->m.bash( potential_target, sp.damage(), sp.has_flag( spell_flag::SILENT ) ); + here.bash( potential_target, sp.damage(), sp.has_flag( spell_flag::SILENT ) ); } } diff --git a/src/magic_teleporter_list.cpp b/src/magic_teleporter_list.cpp index c50bb36e846a2..3de08f1fa71db 100644 --- a/src/magic_teleporter_list.cpp +++ b/src/magic_teleporter_list.cpp @@ -9,6 +9,7 @@ #include "bodypart.h" #include "calendar.h" #include "catacharset.h" +#include "character.h" #include "color.h" #include "coordinate_conversions.h" #include "enums.h" @@ -70,7 +71,7 @@ static cata::optional find_valid_teleporters_omt( const tripoint &omt_ return cata::nullopt; } -bool teleporter_list::place_avatar_overmap( avatar &you, const tripoint &omt_pt ) const +bool teleporter_list::place_avatar_overmap( Character &you, const tripoint &omt_pt ) const { tinymap omt_dest( 2, true ); tripoint sm_dest = omt_to_sm_copy( omt_pt ); @@ -101,9 +102,9 @@ void teleporter_list::translocate( const std::set &targets ) bool valid_targets = false; for( const tripoint &pt : targets ) { - avatar *you = g->critter_at( pt ); + Character *you = g->critter_at( pt ); - if( you ) { + if( you && you->is_avatar() ) { valid_targets = true; if( !place_avatar_overmap( *you, *omt_dest ) ) { add_msg( _( "Failed to teleport. Teleporter obstructed or destroyed." ) ); @@ -169,11 +170,13 @@ class teleporter_callback : public uilist_callback mvwputch( menu->window, point( start_x, i ), c_magenta, LINE_XOXO ); } if( entnum >= 0 && static_cast( entnum ) < index_pairs.size() ) { - overmap_ui::draw_overmap_chunk( menu->window, g->u, index_pairs[entnum], point( start_x + 1, 1 ), + avatar &player_character = get_avatar(); + overmap_ui::draw_overmap_chunk( menu->window, player_character, index_pairs[entnum], + point( start_x + 1, 1 ), 29, 21 ); mvwprintz( menu->window, point( start_x + 2, 1 ), c_white, string_format( _( "Distance: %d (%d, %d)" ), - rl_dist( ms_to_omt_copy( g->m.getabs( g->u.pos() ) ), index_pairs[entnum] ), + rl_dist( ms_to_omt_copy( get_map().getabs( player_character.pos() ) ), index_pairs[entnum] ), index_pairs[entnum].x, index_pairs[entnum].y ) ); } wnoutrefresh( menu->window ); diff --git a/src/magic_teleporter_list.h b/src/magic_teleporter_list.h index 4e925c0d37477..f06d7c8a7bd2c 100644 --- a/src/magic_teleporter_list.h +++ b/src/magic_teleporter_list.h @@ -9,7 +9,7 @@ #include "optional.h" #include "point.h" -class avatar; +class Character; class JsonIn; class JsonOut; @@ -23,7 +23,7 @@ class teleporter_list cata::optional choose_teleport_location(); // returns true if a teleport is successful // does not do any loading or unloading - bool place_avatar_overmap( avatar &you, const tripoint &omt_pt ) const; + bool place_avatar_overmap( Character &you, const tripoint &omt_pt ) const; public: bool knows_translocator( const tripoint &omt_pos ) const; // adds teleporter to known_teleporters and does any other activation necessary diff --git a/src/main.cpp b/src/main.cpp index a2073d9126148..bcb7869dbe5d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,11 +101,26 @@ int start_logger( const char *app_name ) #endif //__ANDROID__ -void exit_handler( int s ); - namespace { +void exit_handler( int s ) +{ + const int old_timeout = inp_mngr.get_timeout(); + inp_mngr.reset_timeout(); + if( s != 2 || query_yn( _( "Really Quit? All unsaved changes will be lost." ) ) ) { + deinitDebug(); + + int exit_status = 0; + g.reset(); + + catacurses::endwin(); + + exit( exit_status ); + } + inp_mngr.set_timeout( old_timeout ); +} + struct arg_handler { //! Handler function to be invoked when this argument is encountered. The handler will be //! called with the number of parameters after the flag was encountered, along with the array @@ -117,11 +132,366 @@ struct arg_handler { const char *param_documentation; //!< Human readable description of this arguments parameter. const char *documentation; //!< Human readable documentation for this argument. const char *help_group; //!< Section of the help message in which to include this argument. + int num_args; //!< How many further arguments are expected for this parameter (usually 0 or 1). handler_method handler; //!< The callback to be invoked when this argument is encountered. }; -void printHelpMessage( const arg_handler *first_pass_arguments, size_t num_first_pass_arguments, - const arg_handler *second_pass_arguments, size_t num_second_pass_arguments ); +template +void printHelpMessage( const FirstPassArgs &first_pass_arguments, + const SecondPassArgs &second_pass_arguments ) +{ + // Group all arguments by help_group. + std::multimap help_map; + for( const arg_handler &handler : first_pass_arguments ) { + std::string help_group; + if( handler.help_group ) { + help_group = handler.help_group; + } + help_map.emplace( help_group, &handler ); + } + for( const arg_handler &handler : second_pass_arguments ) { + std::string help_group; + if( handler.help_group ) { + help_group = handler.help_group; + } + help_map.emplace( help_group, &handler ); + } + + printf( "Command line parameters:\n" ); + std::string current_help_group; + for( std::pair &help_entry : help_map ) { + if( help_entry.first != current_help_group ) { + current_help_group = help_entry.first; + printf( "\n%s\n", current_help_group.c_str() ); + } + + const arg_handler *handler = help_entry.second; + printf( "%s", handler->flag ); + if( handler->param_documentation ) { + printf( " %s", handler->param_documentation ); + } + printf( "\n" ); + if( handler->documentation ) { + printf( " %s\n", handler->documentation ); + } + } +} + +template +void process_args( const char **argv, int argc, const ArgHandlerContainer &arg_handlers ) +{ + while( argc ) { + bool arg_handled = false; + for( const arg_handler &handler : arg_handlers ) { + if( !strcmp( argv[0], handler.flag ) ) { + argc--; + argv++; + if( argc < handler.num_args ) { + printf( "Missing expected argument to command line parameter %s\n", + handler.flag ); + std::exit( 1 ); + } + int args_consumed = handler.handler( argc, argv ); + if( args_consumed < 0 ) { + printf( "Failed parsing parameter '%s'\n", *( argv - 1 ) ); + std::exit( 1 ); + } + argc -= args_consumed; + argv += args_consumed; + arg_handled = true; + break; + } + } + // Skip other options. + if( !arg_handled ) { + --argc; + ++argv; + } + } +} + +struct cli_opts { + int seed = time( nullptr ); + bool verifyexit = false; + bool check_mods = false; + std::string dump; + dump_mode dmode = dump_mode::TSV; + std::vector opts; + std::string world; /** if set try to load first save in this world on startup */ +}; + +cli_opts parse_commandline( int argc, const char **argv ) +{ + cli_opts result; + + const char *section_default = nullptr; + const char *section_map_sharing = "Map sharing"; + const char *section_user_directory = "User directories"; + const std::array first_pass_arguments = {{ + { + "--seed", "", + "Sets the random number generator's seed value", + section_default, + 1, + [&result]( int, const char **params ) -> int { + const unsigned char *hash_input = reinterpret_cast( params[0] ); + result.seed = djb2_hash( hash_input ); + return 1; + } + }, + { + "--jsonverify", nullptr, + "Checks the CDDA json files", + section_default, + 0, + [&result]( int, const char ** ) -> int { + result.verifyexit = true; + return 0; + } + }, + { + "--check-mods", "[mod…]", + "Checks the json files belonging to given CDDA mod", + section_default, + 1, + [&result]( int n, const char **params ) -> int { + result.check_mods = true; + test_mode = true; + for( int i = 0; i < n; ++i ) + { + result.opts.emplace_back( params[ i ] ); + } + return 0; + } + }, + { + "--dump-stats", " [mode = TSV] [opts…]", + "Dumps item stats", + section_default, + 1, + [&result]( int n, const char **params ) -> int { + test_mode = true; + result.dump = params[ 0 ]; + for( int i = 2; i < n; ++i ) + { + result.opts.emplace_back( params[ i ] ); + } + if( n >= 2 ) + { + if( !strcmp( params[ 1 ], "TSV" ) ) { + result.dmode = dump_mode::TSV; + return 0; + } else if( !strcmp( params[ 1 ], "HTML" ) ) { + result.dmode = dump_mode::HTML; + return 0; + } else { + return -1; + } + } + return 0; + } + }, + { + "--world", "", + "Load world", + section_default, + 1, + [&result]( int, const char **params ) -> int { + result.world = params[0]; + return 1; + } + }, + { + "--basepath", "", + "Base path for all game data subdirectories", + section_default, + 1, + []( int, const char **params ) + { + PATH_INFO::init_base_path( params[0] ); + PATH_INFO::set_standard_filenames(); + return 1; + } + }, + { + "--shared", nullptr, + "Activates the map-sharing mode", + section_map_sharing, + 0, + []( int, const char ** ) -> int { + MAP_SHARING::setSharing( true ); + MAP_SHARING::setCompetitive( true ); + MAP_SHARING::setWorldmenu( false ); + return 0; + } + }, + { + "--username", "", + "Instructs map-sharing code to use this name for your character.", + section_map_sharing, + 1, + []( int, const char **params ) -> int { + MAP_SHARING::setUsername( params[0] ); + return 1; + } + }, + { + "--addadmin", "", + "Instructs map-sharing code to use this name for your character and give you " + "access to the cheat functions.", + section_map_sharing, + 1, + []( int, const char **params ) -> int { + MAP_SHARING::addAdmin( params[0] ); + return 1; + } + }, + { + "--adddebugger", "", + "Informs map-sharing code that you're running inside a debugger", + section_map_sharing, + 1, + []( int, const char **params ) -> int { + MAP_SHARING::addDebugger( params[0] ); + return 1; + } + }, + { + "--competitive", nullptr, + "Instructs map-sharing code to disable access to the in-game cheat functions", + section_map_sharing, + 0, + []( int, const char ** ) -> int { + MAP_SHARING::setCompetitive( true ); + return 0; + } + }, + { + "--userdir", "", + // NOLINTNEXTLINE(cata-text-style): the dot is not a period + "Base path for user-overrides to files from the ./data directory and named below", + section_user_directory, + 1, + []( int, const char **params ) -> int { + PATH_INFO::init_user_dir( params[0] ); + PATH_INFO::set_standard_filenames(); + return 1; + } + } + } + }; + + // The following arguments are dependent on one or more of the previous flags and are run + // in a second pass. + const std::array second_pass_arguments = {{ + { + "--worldmenu", nullptr, + "Enables the world menu in the map-sharing code", + section_map_sharing, + 0, + []( int, const char ** ) -> int { + MAP_SHARING::setWorldmenu( true ); + return true; + } + }, + { + "--datadir", "", + "Sub directory from which game data is loaded", + nullptr, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_datadir( params[0] ); + return 1; + } + }, + { + "--savedir", "", + "Subdirectory for game saves", + section_user_directory, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_savedir( params[0] ); + return 1; + } + }, + { + "--configdir", "", + "Subdirectory for game configuration", + section_user_directory, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_config_dir( params[0] ); + return 1; + } + }, + { + "--memorialdir", "", + "Subdirectory for memorials", + section_user_directory, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_memorialdir( params[0] ); + return 1; + } + }, + { + "--optionfile", "", + "Name of the options file within the configdir", + section_user_directory, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_options( params[0] ); + return 1; + } + }, + { + "--keymapfile", "", + "Name of the keymap file within the configdir", + section_user_directory, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_keymap( params[0] ); + return 1; + } + }, + { + "--autopickupfile", "", + "Name of the autopickup options file within the configdir", + nullptr, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_autopickup( params[0] ); + return 1; + } + }, + { + "--motdfile", "", + "Name of the message of the day file within the motd directory", + nullptr, + 1, + []( int, const char **params ) -> int { + PATH_INFO::set_motd( params[0] ); + return 1; + } + }, + } + }; + + if( std::count( argv, argv + argc, std::string( "--help" ) ) ) { + printHelpMessage( first_pass_arguments, second_pass_arguments ); + std::exit( 0 ); + } + + // skip program name + --argc; + ++argv; + + process_args( argv, argc, first_pass_arguments ); + process_args( argv, argc, second_pass_arguments ); + + return result; +} + } // namespace #if defined(USE_WINMAIN) @@ -133,17 +503,10 @@ int APIENTRY WinMain( HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, #elif defined(__ANDROID__) extern "C" int SDL_main( int argc, char **argv ) { #else -int main( int argc, char *argv[] ) +int main( int argc, const char *argv[] ) { #endif init_crash_handlers(); - int seed = time( nullptr ); - bool verifyexit = false; - bool check_mods = false; - std::string dump; - dump_mode dmode = dump_mode::TSV; - std::vector opts; - std::string world; /** if set try to load first save in this world on startup */ #if defined(__ANDROID__) // Start the standard output logging redirector @@ -180,364 +543,8 @@ int main( int argc, char *argv[] ) PATH_INFO::set_standard_filenames(); MAP_SHARING::setDefaults(); - { - const char *section_default = nullptr; - const char *section_map_sharing = "Map sharing"; - const char *section_user_directory = "User directories"; - const std::array first_pass_arguments = {{ - { - "--seed", "", - "Sets the random number generator's seed value", - section_default, - [&seed]( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - const unsigned char *hash_input = reinterpret_cast( params[0] ); - seed = djb2_hash( hash_input ); - return 1; - } - }, - { - "--jsonverify", nullptr, - "Checks the CDDA json files", - section_default, - [&verifyexit]( int, const char ** ) -> int { - verifyexit = true; - return 0; - } - }, - { - "--check-mods", "[mods…]", - "Checks the json files belonging to CDDA mods", - section_default, - [&check_mods, &opts]( int n, const char *params[] ) -> int { - check_mods = true; - test_mode = true; - for( int i = 0; i < n; ++i ) - { - opts.emplace_back( params[ i ] ); - } - return 0; - } - }, - { - "--dump-stats", " [mode = TSV] [opts…]", - "Dumps item stats", - section_default, - [&dump, &dmode, &opts]( int n, const char *params[] ) -> int { - if( n < 1 ) - { - return -1; - } - test_mode = true; - dump = params[ 0 ]; - for( int i = 2; i < n; ++i ) - { - opts.emplace_back( params[ i ] ); - } - if( n >= 2 ) - { - if( !strcmp( params[ 1 ], "TSV" ) ) { - dmode = dump_mode::TSV; - return 0; - } else if( !strcmp( params[ 1 ], "HTML" ) ) { - dmode = dump_mode::HTML; - return 0; - } else { - return -1; - } - } - return 0; - } - }, - { - "--world", "", - "Load world", - section_default, - [&world]( int n, const char *params[] ) -> int { - if( n < 1 ) - { - return -1; - } - world = params[0]; - return 1; - } - }, - { - "--basepath", "", - "Base path for all game data subdirectories", - section_default, - []( int num_args, const char **params ) - { - if( num_args < 1 ) { - return -1; - } - PATH_INFO::init_base_path( params[0] ); - PATH_INFO::set_standard_filenames(); - return 1; - } - }, - { - "--shared", nullptr, - "Activates the map-sharing mode", - section_map_sharing, - []( int, const char ** ) -> int { - MAP_SHARING::setSharing( true ); - MAP_SHARING::setCompetitive( true ); - MAP_SHARING::setWorldmenu( false ); - return 0; - } - }, - { - "--username", "", - "Instructs map-sharing code to use this name for your character.", - section_map_sharing, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - MAP_SHARING::setUsername( params[0] ); - return 1; - } - }, - { - "--addadmin", "", - "Instructs map-sharing code to use this name for your character and give you " - "access to the cheat functions.", - section_map_sharing, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - MAP_SHARING::addAdmin( params[0] ); - return 1; - } - }, - { - "--adddebugger", "", - "Informs map-sharing code that you're running inside a debugger", - section_map_sharing, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - MAP_SHARING::addDebugger( params[0] ); - return 1; - } - }, - { - "--competitive", nullptr, - "Instructs map-sharing code to disable access to the in-game cheat functions", - section_map_sharing, - []( int, const char ** ) -> int { - MAP_SHARING::setCompetitive( true ); - return 0; - } - }, - { - "--userdir", "", - // NOLINTNEXTLINE(cata-text-style): the dot is not a period - "Base path for user-overrides to files from the ./data directory and named below", - section_user_directory, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::init_user_dir( params[0] ); - PATH_INFO::set_standard_filenames(); - return 1; - } - } - } - }; - // The following arguments are dependent on one or more of the previous flags and are run - // in a second pass. - const std::array second_pass_arguments = {{ - { - "--worldmenu", nullptr, - "Enables the world menu in the map-sharing code", - section_map_sharing, - []( int, const char ** ) -> int { - MAP_SHARING::setWorldmenu( true ); - return true; - } - }, - { - "--datadir", "", - "Sub directory from which game data is loaded", - nullptr, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_datadir( params[0] ); - return 1; - } - }, - { - "--savedir", "", - "Subdirectory for game saves", - section_user_directory, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_savedir( params[0] ); - return 1; - } - }, - { - "--configdir", "", - "Subdirectory for game configuration", - section_user_directory, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_config_dir( params[0] ); - return 1; - } - }, - { - "--memorialdir", "", - "Subdirectory for memorials", - section_user_directory, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_memorialdir( params[0] ); - return 1; - } - }, - { - "--optionfile", "", - "Name of the options file within the configdir", - section_user_directory, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_options( params[0] ); - return 1; - } - }, - { - "--keymapfile", "", - "Name of the keymap file within the configdir", - section_user_directory, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_keymap( params[0] ); - return 1; - } - }, - { - "--autopickupfile", "", - "Name of the autopickup options file within the configdir", - nullptr, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_autopickup( params[0] ); - return 1; - } - }, - { - "--motdfile", "", - "Name of the message of the day file within the motd directory", - nullptr, - []( int num_args, const char **params ) -> int { - if( num_args < 1 ) - { - return -1; - } - PATH_INFO::set_motd( params[0] ); - return 1; - } - }, - } - }; - - // Process CLI arguments. - const size_t num_first_pass_arguments = - sizeof( first_pass_arguments ) / sizeof( first_pass_arguments[0] ); - const size_t num_second_pass_arguments = - sizeof( second_pass_arguments ) / sizeof( second_pass_arguments[0] ); - int saved_argc = --argc; // skip program name - const char **saved_argv = const_cast( ++argv ); - while( argc ) { - if( !strcmp( argv[0], "--help" ) ) { - printHelpMessage( first_pass_arguments.data(), num_first_pass_arguments, - second_pass_arguments.data(), num_second_pass_arguments ); - return 0; - } else { - bool arg_handled = false; - for( size_t i = 0; i < num_first_pass_arguments; ++i ) { - auto &arg_handler = first_pass_arguments[i]; - if( !strcmp( argv[0], arg_handler.flag ) ) { - argc--; - argv++; - int args_consumed = arg_handler.handler( argc, const_cast( argv ) ); - if( args_consumed < 0 ) { - printf( "Failed parsing parameter '%s'\n", *( argv - 1 ) ); - exit( 1 ); - } - argc -= args_consumed; - argv += args_consumed; - arg_handled = true; - break; - } - } - // Skip other options. - if( !arg_handled ) { - --argc; - ++argv; - } - } - } - while( saved_argc ) { - bool arg_handled = false; - for( size_t i = 0; i < num_second_pass_arguments; ++i ) { - auto &arg_handler = second_pass_arguments[i]; - if( !strcmp( saved_argv[0], arg_handler.flag ) ) { - --saved_argc; - ++saved_argv; - int args_consumed = arg_handler.handler( saved_argc, saved_argv ); - if( args_consumed < 0 ) { - printf( "Failed parsing parameter '%s'\n", *( argv - 1 ) ); - exit( 1 ); - } - saved_argc -= args_consumed; - saved_argv += args_consumed; - arg_handled = true; - break; - } - } - // Ignore unknown options. - if( !arg_handled ) { - --saved_argc; - ++saved_argv; - } - } - } + cli_opts cli = parse_commandline( argc, argv ); if( !dir_exist( PATH_INFO::datadir() ) ) { printf( "Fatal: Can't find data directory \"%s\"\nPlease ensure the current working directory is correct or specify data directory with --datadir. Perhaps you meant to start \"cataclysm-launcher\"?\n", @@ -619,24 +626,24 @@ int main( int argc, char *argv[] ) set_language(); - rng_set_engine_seed( seed ); + rng_set_engine_seed( cli.seed ); g = std::make_unique(); // First load and initialize everything that does not // depend on the mods. try { g->load_static_data(); - if( verifyexit ) { + if( cli.verifyexit ) { exit_handler( 0 ); } - if( !dump.empty() ) { + if( !cli.dump.empty() ) { init_colors(); - exit( g->dump_stats( dump, dmode, opts ) ? 0 : 1 ); + exit( g->dump_stats( cli.dump, cli.dmode, cli.opts ) ? 0 : 1 ); } - if( check_mods ) { + if( cli.check_mods ) { init_colors(); loading_ui ui( false ); - const std::vector mods( opts.begin(), opts.end() ); + const std::vector mods( cli.opts.begin(), cli.opts.end() ); exit( g->check_mod_data( mods, ui ) && !debug_has_error_been_observed() ? 0 : 1 ); } } catch( const std::exception &err ) { @@ -680,11 +687,11 @@ int main( int argc, char *argv[] ) #endif while( true ) { - if( !world.empty() ) { - if( !g->load( world ) ) { + if( !cli.world.empty() ) { + if( !g->load( cli.world ) ) { break; } - world.clear(); // ensure quit returns to opening screen + cli.world.clear(); // ensure quit returns to opening screen } else { main_menu menu; @@ -700,68 +707,3 @@ int main( int argc, char *argv[] ) exit_handler( -999 ); return 0; } - -namespace -{ -void printHelpMessage( const arg_handler *first_pass_arguments, - size_t num_first_pass_arguments, - const arg_handler *second_pass_arguments, - size_t num_second_pass_arguments ) -{ - - // Group all arguments by help_group. - std::multimap help_map; - for( size_t i = 0; i < num_first_pass_arguments; ++i ) { - std::string help_group; - if( first_pass_arguments[i].help_group ) { - help_group = first_pass_arguments[i].help_group; - } - help_map.insert( std::make_pair( help_group, &first_pass_arguments[i] ) ); - } - for( size_t i = 0; i < num_second_pass_arguments; ++i ) { - std::string help_group; - if( second_pass_arguments[i].help_group ) { - help_group = second_pass_arguments[i].help_group; - } - help_map.insert( std::make_pair( help_group, &second_pass_arguments[i] ) ); - } - - printf( "Command line parameters:\n" ); - std::string current_help_group; - auto it = help_map.begin(); - auto it_end = help_map.end(); - for( ; it != it_end; ++it ) { - if( it->first != current_help_group ) { - current_help_group = it->first; - printf( "\n%s\n", current_help_group.c_str() ); - } - - const arg_handler *handler = it->second; - printf( "%s", handler->flag ); - if( handler->param_documentation ) { - printf( " %s", handler->param_documentation ); - } - printf( "\n" ); - if( handler->documentation ) { - printf( " %s\n", handler->documentation ); - } - } -} -} // namespace - -void exit_handler( int s ) -{ - const int old_timeout = inp_mngr.get_timeout(); - inp_mngr.reset_timeout(); - if( s != 2 || query_yn( _( "Really Quit? All unsaved changes will be lost." ) ) ) { - deinitDebug(); - - int exit_status = 0; - g.reset(); - - catacurses::endwin(); - - exit( exit_status ); - } - inp_mngr.set_timeout( old_timeout ); -} diff --git a/src/main_menu.cpp b/src/main_menu.cpp index df548a9c31a00..413e050f29b46 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -28,6 +28,7 @@ #include "loading_ui.h" #include "mapbuffer.h" #include "mapsharing.h" +#include "messages.h" #include "optional.h" #include "options.h" #include "output.h" @@ -974,7 +975,7 @@ bool main_menu::new_character_tab() } // end while if( start ) { - g->u.add_msg_if_player( g->scen->description( g->u.male ) ); + add_msg( g->scen->description( g->u.male ) ); world_generator->last_world_name = world_generator->active_world->world_name; world_generator->last_character_name = g->u.name; diff --git a/src/map.cpp b/src/map.cpp index 53e08c0711b5a..04e980bfc5813 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,6 +1,7 @@ #include "map.h" #include +#include #include #include #include @@ -113,8 +114,6 @@ static const itype_id itype_welder( "welder" ); static const mtype_id mon_zombie( "mon_zombie" ); -static const skill_id skill_traps( "traps" ); - static const efftype_id effect_boomered( "boomered" ); static const efftype_id effect_crushed( "crushed" ); @@ -243,53 +242,42 @@ void map::add_vehicle_to_cache( vehicle *veh ) return; } - auto &ch = get_cache( veh->sm_pos.z ); - ch.veh_in_active_range = true; // Get parts for( const vpart_reference &vpr : veh->get_all_parts() ) { if( vpr.part().removed ) { continue; } const tripoint p = veh->global_part_pos3( vpr.part() ); - ch.veh_cached_parts.insert( std::make_pair( p, - std::make_pair( veh, static_cast( vpr.part_index() ) ) ) ); + level_cache &ch = get_cache( p.z ); + ch.veh_in_active_range = true; + ch.veh_cached_parts[p] = std::make_pair( veh, static_cast( vpr.part_index() ) ); if( inbounds( p ) ) { ch.veh_exists_at[p.x][p.y] = true; } } } -void map::update_vehicle_cache( vehicle *veh, const int old_zlevel ) +void map::clear_vehicle_point_from_cache( vehicle *veh, const tripoint &pt ) { if( veh == nullptr ) { debugmsg( "Tried to add null vehicle to cache" ); return; } - // Existing must be cleared - auto &ch = get_cache( old_zlevel ); - auto it = ch.veh_cached_parts.begin(); - const auto end = ch.veh_cached_parts.end(); - while( it != end ) { - if( it->second.first == veh ) { - const tripoint p = it->first; - if( inbounds( p ) ) { - ch.veh_exists_at[p.x][p.y] = false; - } - ch.veh_cached_parts.erase( it++ ); - // If something was resting on vehicle, drop it - support_dirty( tripoint( p.xy(), old_zlevel + 1 ) ); - } else { - ++it; - } + level_cache &ch = get_cache( pt.z ); + if( inbounds( pt ) ) { + ch.veh_exists_at[pt.x][pt.y] = false; + } + auto it = ch.veh_cached_parts.find( pt ); + if( it != ch.veh_cached_parts.end() && it->second.first == veh ) { + ch.veh_cached_parts.erase( it ); } - add_vehicle_to_cache( veh ); } void map::clear_vehicle_cache( const int zlev ) { - auto &ch = get_cache( zlev ); + level_cache &ch = get_cache( zlev ); while( !ch.veh_cached_parts.empty() ) { const auto part = ch.veh_cached_parts.begin(); const auto &p = part->first; @@ -298,6 +286,7 @@ void map::clear_vehicle_cache( const int zlev ) } ch.veh_cached_parts.erase( part ); } + ch.veh_in_active_range = false; } void map::clear_vehicle_list( const int zlev ) @@ -310,7 +299,7 @@ void map::clear_vehicle_list( const int zlev ) void map::update_vehicle_list( const submap *const to, const int zlev ) { // Update vehicle data - auto &ch = get_cache( zlev ); + level_cache &ch = get_cache( zlev ); for( const auto &elem : to->vehicles ) { ch.vehicle_list.insert( elem.get() ); if( !elem->loot_zones.empty() ) { @@ -343,7 +332,7 @@ std::unique_ptr map::detach_vehicle( vehicle *veh ) } veh->invalidate_towing( true ); submap *const current_submap = get_submap_at_grid( veh->sm_pos ); - auto &ch = get_cache( z ); + level_cache &ch = get_cache( z ); for( size_t i = 0; i < current_submap->vehicles.size(); i++ ) { if( current_submap->vehicles[i].get() == veh ) { ch.vehicle_list.erase( veh ); @@ -454,6 +443,23 @@ bool map::vehproceed( VehicleList &vehicle_list ) if( cur_veh->v == nullptr ) { vehicle_list = get_vehicles(); } + + // confirm that veh_in_active_range is still correct for each z-level + int minz = zlevels ? -OVERMAP_DEPTH : abs_sub.z; + int maxz = zlevels ? OVERMAP_HEIGHT : abs_sub.z; + for( int zlev = minz; zlev <= maxz; ++zlev ) { + level_cache &cache = get_cache( zlev ); + + // Check if any vehicles exist in the active range for this z-level + cache.veh_in_active_range = cache.veh_in_active_range && + std::any_of( std::begin( cache.veh_exists_at ), + std::end( cache.veh_exists_at ), []( const auto & row ) { + return std::any_of( std::begin( row ), std::end( row ), []( bool veh_exists ) { + return veh_exists; + } ); + } ); + } + return true; } @@ -610,7 +616,8 @@ vehicle *map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &fac } } - const bool seen = sees_veh( g->u, veh, false ); + Character &player_character = get_player_character(); + const bool seen = sees_veh( player_character, veh, false ); vehicle *new_vehicle = &veh; if( can_move ) { @@ -629,12 +636,15 @@ vehicle *map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &fac veh.on_move(); // Actually change position displace_vehicle( *new_vehicle, dp1 ); + level_vehicle( *new_vehicle ); } else if( !vertical ) { veh.stop(); } + veh.check_falling_or_floating(); // If the PC is in the currently moved vehicle, adjust the // view offset. - if( g->u.controlling_vehicle && veh_pointer_or_null( veh_at( g->u.pos() ) ) == &veh ) { + if( player_character.controlling_vehicle && + veh_pointer_or_null( veh_at( player_character.pos() ) ) == &veh ) { g->calc_driving_offset( &veh ); if( veh.skidding && can_move ) { // TODO: Make skid recovery in air hard @@ -683,7 +693,7 @@ vehicle *map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &fac } // Redraw scene // But only if the vehicle was seen before or after the move - if( seen || sees_veh( g->u, veh, true ) ) { + if( seen || sees_veh( player_character, veh, true ) ) { g->invalidate_main_ui_adaptor(); ui_manager::redraw_invalidated(); refresh_display(); @@ -940,7 +950,7 @@ VehicleList map::get_vehicles( const tripoint &start, const tripoint &end ) optional_vpart_position map::veh_at( const tripoint &p ) const { - if( !const_cast( this )->get_cache( p.z ).veh_in_active_range || !inbounds( p ) ) { + if( !inbounds( p ) || !const_cast( this )->get_cache( p.z ).veh_in_active_range ) { return optional_vpart_position( cata::nullopt ); } @@ -956,7 +966,7 @@ optional_vpart_position map::veh_at( const tripoint &p ) const const vehicle *map::veh_at_internal( const tripoint &p, int &part_num ) const { // This function is called A LOT. Move as much out of here as possible. - const auto &ch = get_cache_ref( p.z ); + const level_cache &ch = get_cache( p.z ); if( !ch.veh_in_active_range || !ch.veh_exists_at[p.x][p.y] ) { part_num = -1; return nullptr; // Clear cache indicates no vehicle. This should optimize a great deal. @@ -978,7 +988,7 @@ vehicle *map::veh_at_internal( const tripoint &p, int &part_num ) return const_cast( const_cast( this )->veh_at_internal( p, part_num ) ); } -void map::board_vehicle( const tripoint &pos, player *p ) +void map::board_vehicle( const tripoint &pos, Character *p ) { if( p == nullptr ) { debugmsg( "map::board_vehicle: null player" ); @@ -988,7 +998,9 @@ void map::board_vehicle( const tripoint &pos, player *p ) const cata::optional vp = veh_at( pos ).part_with_feature( VPFLAG_BOARDABLE, true ); if( !vp ) { - if( p->grab_point.x == 0 && p->grab_point.y == 0 ) { + avatar *player_character = p->as_avatar(); + if( player_character != nullptr && + player_character->grab_point.x == 0 && player_character->grab_point.y == 0 ) { debugmsg( "map::board_vehicle: vehicle not found" ); } return; @@ -1005,12 +1017,12 @@ void map::board_vehicle( const tripoint &pos, player *p ) p->setpos( pos ); p->in_vehicle = true; - if( p == &g->u ) { - g->update_map( g->u ); + if( p->is_avatar() ) { + g->update_map( *p->as_avatar() ); } } -void map::unboard_vehicle( const vpart_reference &vp, player *passenger, bool dead_passenger ) +void map::unboard_vehicle( const vpart_reference &vp, Character *passenger, bool dead_passenger ) { // Mark the part as un-occupied regardless of whether there's a live passenger here. vp.part().remove_flag( vehicle_part::passenger_flag ); @@ -1048,12 +1060,22 @@ void map::unboard_vehicle( const tripoint &p, bool dead_passenger ) unboard_vehicle( *vp, passenger, dead_passenger ); } -bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) +bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_pos, + const std::set &parts_to_move ) { - const tripoint p = veh.global_pos3(); - const tripoint p2 = p + dp; - const tripoint src = p; - const tripoint dst = p2; + const tripoint src = veh.global_pos3(); + // handle vehicle ramps + int ramp_offset = 0; + if( adjust_pos ) { + if( has_flag( TFLAG_RAMP_UP, src + dp ) ) { + ramp_offset += 1; + } else if( has_flag( TFLAG_RAMP_DOWN, src + dp ) ) { + ramp_offset -= 1; + } + } + + const tripoint dst = src + ( adjust_pos ? + ( dp + tripoint( 0, 0, ramp_offset ) ) : tripoint_zero ); if( !inbounds( src ) ) { add_msg( m_debug, "map::displace_vehicle: coordinates out of bounds %d,%d,%d->%d,%d,%d", @@ -1065,6 +1087,7 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) point dst_offset; submap *src_submap = get_submap_at( src, src_offset ); submap *const dst_submap = get_submap_at( dst, dst_offset ); + std::set smzs; // first, let's find our position in current vehicles vector size_t our_i = 0; @@ -1090,7 +1113,7 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) // move the vehicle // don't let it go off grid - if( !inbounds( p2 ) ) { + if( !inbounds( dst ) ) { veh.stop(); // Silent debug dbg( D_ERROR ) << "map:displace_vehicle: Stopping vehicle, displaced dp=(" @@ -1098,8 +1121,9 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) return true; } + Character &player_character = get_player_character(); // Need old coordinates to check for remote control - const bool remote = veh.remote_controlled( g->u ); + const bool remote = veh.remote_controlled( player_character ); // record every passenger and pet inside std::vector riders = veh.get_riders(); @@ -1116,12 +1140,16 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) continue; } const int prt = r.prt; + if( !parts_to_move.empty() && parts_to_move.find( prt ) == parts_to_move.end() ) { + r.moved = true; + continue; + } Creature *psg = r.psg; const tripoint part_pos = veh.global_part_pos3( prt ); if( psg == nullptr ) { debugmsg( "Empty passenger for part #%d at %d,%d,%d player at %d,%d,%d?", prt, part_pos.x, part_pos.y, part_pos.z, - g->u.posx(), g->u.posy(), g->u.posz() ); + player_character.posx(), player_character.posy(), player_character.posz() ); veh.part( prt ).remove_flag( vehicle_part::passenger_flag ); r.moved = true; continue; @@ -1132,52 +1160,69 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) "passenger at %d,%d,%d", prt, part_pos.x, part_pos.y, part_pos.z, psg->posx(), psg->posy(), psg->posz() ); } + const vehicle_part &veh_part = veh.part( prt ); + + // ramps make everything super tricky + int psg_offset_z = -ramp_offset; + tripoint next_pos; // defaults to 0,0,0 + if( parts_to_move.empty() ) { + next_pos = veh_part.precalc[1]; + } + if( has_flag( TFLAG_RAMP_UP, src + dp + next_pos ) ) { + psg_offset_z += 1; + } else if( has_flag( TFLAG_RAMP_DOWN, src + dp + next_pos ) ) { + psg_offset_z -= 1; + } // Place passenger on the new part location - const vehicle_part &veh_part = veh.part( prt ); - tripoint psgp( dp + part_pos.xy() - veh_part.precalc[0] + veh_part.precalc[1] + tripoint( 0, 0, - psg->posz() ) ); + tripoint psgp( dst + next_pos + tripoint( 0, 0, psg_offset_z ) ); // someone is in the way so try again if( g->critter_at( psgp ) ) { complete = false; continue; } - if( psg == &g->u ) { + if( psg->is_avatar() ) { // If passenger is you, we need to update the map need_update = true; - z_change = dp.z; + z_change = psgp.z - part_pos.z; } + psg->setpos( psgp ); r.moved = true; } } veh.shed_loose_parts(); - veh.advance_precalc_mounts( dst_offset, p2.z ); - + smzs = veh.advance_precalc_mounts( dst_offset, src, dp, ramp_offset, adjust_pos, parts_to_move ); if( src_submap != dst_submap ) { - veh.set_submap_moved( point( p2.x / SEEX, p2.y / SEEY ) ); + veh.set_submap_moved( tripoint( dst.x / SEEX, dst.y / SEEY, dst.z ) ); auto src_submap_veh_it = src_submap->vehicles.begin() + our_i; dst_submap->vehicles.push_back( std::move( *src_submap_veh_it ) ); src_submap->vehicles.erase( src_submap_veh_it ); dst_submap->is_uniform = false; } - update_vehicle_cache( &veh, src.z ); if( need_update ) { - g->update_map( g->u ); + g->update_map( player_character ); } + add_vehicle_to_cache( &veh ); - if( z_change != 0 ) { - g->vertical_move( z_change, true ); - // I don't know why all this is needed, but the cache does not update properly without. + if( z_change || src.z != dst.z ) { + if( z_change ) { + g->vertical_move( z_change, true ); + // vertical moves can flush the caches, so make sure we're still in the cache + add_vehicle_to_cache( &veh ); + } update_vehicle_list( dst_submap, dst.z ); - update_vehicle_cache( &veh, src.z ); - level_cache &ch2 = get_cache( src.z ); - for( const vehicle *elem : ch2.vehicle_list ) { - if( elem == &veh ) { - ch2.vehicle_list.erase( &veh ); - ch2.zone_vehicles.erase( &veh ); - break; + // delete the vehicle from the source z-level vehicle cache set if it is no longer on + // that z-level + if( src.z != dst.z ) { + level_cache &ch2 = get_cache( src.z ); + for( const vehicle *elem : ch2.vehicle_list ) { + if( elem == &veh ) { + ch2.vehicle_list.erase( &veh ); + ch2.zone_vehicles.erase( &veh ); + break; + } } } veh.check_is_heli_landed(); @@ -1188,15 +1233,24 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp ) g->setremoteveh( &veh ); } - veh.check_falling_or_floating(); - + // //global positions of vehicle loot zones have changed. veh.zones_dirty = true; - on_vehicle_moved( veh.sm_pos.z ); + for( int vsmz : smzs ) { + on_vehicle_moved( vsmz ); + } return true; } +void map::level_vehicle( vehicle &veh ) +{ + int cnt = 0; + while( !veh.level_vehicle() && cnt < ( 2 * OVERMAP_DEPTH ) ) { + cnt++; + } +} + bool map::displace_water( const tripoint &p ) { // Check for shallow water @@ -1296,11 +1350,12 @@ void map::furn_set( const tripoint &p, const furn_id &new_furniture ) const furn_t &old_t = old_id.obj(); const furn_t &new_t = new_furniture.obj(); + avatar &player_character = get_avatar(); // If player has grabbed this furniture and it's no longer grabbable, release the grab. - if( g->u.get_grab_type() == object_type::FURNITURE && g->u.grab_point == p && - !new_t.is_movable() ) { + if( player_character.get_grab_type() == object_type::FURNITURE && + player_character.grab_point == p && !new_t.is_movable() ) { add_msg( _( "The %s you were grabbing is destroyed!" ), old_t.name() ); - g->u.grab( object_type::NONE ); + player_character.grab( object_type::NONE ); } // If a creature was crushed under a rubble -> free it if( old_id == f_rubble && new_furniture == f_null ) { @@ -1406,17 +1461,18 @@ uint8_t map::get_known_connections( const tripoint &p, int connect_group, auto &ch = access_cache( p.z ); uint8_t val = 0; std::function is_memorized; + avatar &player_character = get_avatar(); #ifdef TILES if( use_tiles ) { is_memorized = [&]( const tripoint & q ) { - return !g->u.get_memorized_tile( getabs( q ) ).tile.empty(); + return !player_character.get_memorized_tile( getabs( q ) ).tile.empty(); }; } else { #endif is_memorized = [&]( const tripoint & q ) { - return g->u.get_memorized_symbol( getabs( q ) ); + return player_character.get_memorized_symbol( getabs( q ) ); }; #ifdef TILES } @@ -1713,7 +1769,7 @@ bool map::passable_ter_furn( const tripoint &p ) const int map::combined_movecost( const tripoint &from, const tripoint &to, const vehicle *ignored_vehicle, - const int modifier, const bool flying ) const + const int modifier, const bool flying, const bool via_ramp ) const { const int mults[4] = { 0, 50, 71, 100 }; const int cost1 = move_cost( from, ignored_vehicle ); @@ -1726,7 +1782,7 @@ int map::combined_movecost( const tripoint &from, const tripoint &to, } // Inter-z-level movement by foot (not flying) - if( !valid_move( from, to, false ) ) { + if( !valid_move( from, to, false, via_ramp ) ) { return 0; } @@ -1735,7 +1791,7 @@ int map::combined_movecost( const tripoint &from, const tripoint &to, } bool map::valid_move( const tripoint &from, const tripoint &to, - const bool bash, const bool flying ) const + const bool bash, const bool flying, const bool via_ramp ) const { // Used to account for the fact that older versions of GCC can trip on the if statement here. assert( to.z > std::numeric_limits::min() ); @@ -1767,7 +1823,7 @@ bool map::valid_move( const tripoint &from, const tripoint &to, // actually make a valid ledge drop location with zlevels on, this forces // at least one zlevel drop and if down_ter is impassible it's probably // inside a wall, we could workaround that further but it's unnecessary. - const bool up_is_ledge = tr_at( up_p ).loadid == tr_ledge; + const bool up_is_ledge = tr_at( up_p ) == tr_ledge; if( up_ter.movecost == 0 ) { // Unpassable tile @@ -1785,19 +1841,20 @@ bool map::valid_move( const tripoint &from, const tripoint &to, return false; } - if( !up_ter.has_flag( TFLAG_NO_FLOOR ) && !up_ter.has_flag( TFLAG_GOES_DOWN ) && !up_is_ledge ) { + if( !up_ter.has_flag( TFLAG_NO_FLOOR ) && !up_ter.has_flag( TFLAG_GOES_DOWN ) && !up_is_ledge && + !via_ramp ) { // Can't move from up to down if( std::abs( from.x - to.x ) == 1 || std::abs( from.y - to.y ) == 1 ) { // Break the move into two - vertical then horizontal tripoint midpoint( down_p.xy(), up_p.z ); - return valid_move( down_p, midpoint, bash, flying ) && - valid_move( midpoint, up_p, bash, flying ); + return valid_move( down_p, midpoint, bash, flying, via_ramp ) && + valid_move( midpoint, up_p, bash, flying, via_ramp ); } return false; } if( !flying && !down_ter.has_flag( TFLAG_GOES_UP ) && !down_ter.has_flag( TFLAG_RAMP ) && - !up_is_ledge ) { + !up_is_ledge && !via_ramp ) { // Can't safely reach the lower tile return false; } @@ -1853,7 +1910,8 @@ int map::climb_difficulty( const tripoint &p ) const if( has_flag( "LADDER", p ) ) { // Really easy, but you have to stand on the tile return 1; - } else if( has_flag( TFLAG_RAMP, p ) ) { + } else if( has_flag( TFLAG_RAMP, p ) || has_flag( TFLAG_RAMP_UP, p ) || + has_flag( TFLAG_RAMP_DOWN, p ) ) { // We're on something stair-like, so halfway there already best_difficulty = 7; } @@ -2661,6 +2719,16 @@ bool map::has_nearby_chair( const tripoint &p, int radius ) return false; } +bool map::has_nearby_ter( const tripoint &p, const ter_id &type, int radius ) +{ + for( const tripoint &pt : points_in_radius( p, radius ) ) { + if( ter( pt ) == type ) { + return true; + } + } + return false; +} + bool map::mop_spills( const tripoint &p ) { bool retval = false; @@ -2911,15 +2979,16 @@ void map::smash_items( const tripoint &p, const int power, const std::string &ca } } + Character &player_character = get_player_character(); // Let the player know that the item was damaged if they can see it. - if( items_destroyed > 1 && g->u.sees( p ) ) { + if( items_destroyed > 1 && player_character.sees( p ) ) { add_msg( m_bad, _( "The %s destroys several items!" ), cause_message ); - } else if( items_destroyed == 1 && items_damaged == 1 && g->u.sees( p ) ) { + } else if( items_destroyed == 1 && items_damaged == 1 && player_character.sees( p ) ) { //~ %1$s: the cause of destruction, %2$s: destroyed item name add_msg( m_bad, _( "The %1$s destroys the %2$s!" ), cause_message, damaged_item_name ); - } else if( items_damaged > 1 && g->u.sees( p ) ) { + } else if( items_damaged > 1 && player_character.sees( p ) ) { add_msg( m_bad, _( "The %s damages several items." ), cause_message ); - } else if( items_damaged == 1 && g->u.sees( p ) ) { + } else if( items_damaged == 1 && player_character.sees( p ) ) { //~ %1$s: the cause of damage, %2$s: damaged item name add_msg( m_bad, _( "The %1$s damages the %2$s." ), cause_message, damaged_item_name ); } @@ -3034,9 +3103,10 @@ void map::bash_ter_furn( const tripoint &p, bash_params ¶ms ) if( has_flag( "ALARMED", p ) && !g->timed_events.queued( timed_event_type::WANTED ) ) { sounds::sound( p, 40, sounds::sound_t::alarm, _( "an alarm go off!" ), false, "environment", "alarm" ); + Character &player_character = get_player_character(); // Blame nearby player - if( rl_dist( g->u.pos(), p ) <= 3 ) { - g->events().send( g->u.getID() ); + if( rl_dist( player_character.pos(), p ) <= 3 ) { + g->events().send( player_character.getID() ); const point abs = ms_to_sm_copy( getabs( p.xy() ) ); g->timed_events.add( timed_event_type::WANTED, calendar::turn + 30_minutes, 0, tripoint( abs, p.z ) ); @@ -3347,7 +3417,7 @@ void map::bash_vehicle( const tripoint &p, bash_params ¶ms ) void map::bash_field( const tripoint &p, bash_params ¶ms ) { - for( const std::pair &fd : field_at( p ) ) { + for( const std::pair &fd : field_at( p ) ) { if( fd.first->bash_info.str_min > -1 ) { params.did_bash = true; params.bashed_solid = true; // To prevent bashing furniture/vehicles @@ -3578,7 +3648,7 @@ void map::shoot( const tripoint &p, projectile &proj, const bool hit_items ) } else { //Greatly weakens power of bullets dam -= 40; - if( dam <= 0 && g->u.sees( p ) ) { + if( dam <= 0 && get_player_character().sees( p ) ) { if( terrain == t_reinforced_door_glass_c ) { add_msg( _( "The shot is stopped by the reinforced glass door!" ) ); } else { @@ -3652,7 +3722,7 @@ void map::shoot( const tripoint &p, projectile &proj, const bool hit_items ) dam = std::max( 0.0f, dam ); // Check fields? - for( const std::pair &fd : field_at( p ) ) { + for( const std::pair &fd : field_at( p ) ) { if( fd.first->bash_info.str_min > 0 ) { if( inc ) { add_field( p, fd_fire, fd.second.get_field_intensity() - 1 ); @@ -3748,6 +3818,7 @@ bool map::open_door( const tripoint &p, const bool inside, const bool check_only { const auto &ter = this->ter( p ).obj(); const auto &furn = this->furn( p ).obj(); + avatar &player_character = get_avatar(); if( ter.open ) { if( has_flag( "OPENCLOSE_INSIDE", p ) && !inside ) { return false; @@ -3758,9 +3829,10 @@ bool map::open_door( const tripoint &p, const bool inside, const bool check_only "open_door", ter.id.str() ); ter_set( p, ter.open ); - if( ( g->u.has_trait( trait_id( "SCHIZOPHRENIC" ) ) || g->u.has_artifact_with( AEP_SCHIZO ) ) - && one_in( 50 ) && !ter.has_flag( "TRANSPARENT" ) ) { - tripoint mp = p + -2 * g->u.pos().xy() + tripoint( 2 * p.x, 2 * p.y, p.z ); + if( ( player_character.has_trait( trait_id( "SCHIZOPHRENIC" ) ) || + player_character.has_artifact_with( AEP_SCHIZO ) ) && + one_in( 50 ) && !ter.has_flag( "TRANSPARENT" ) ) { + tripoint mp = p + -2 * player_character.pos().xy() + tripoint( 2 * p.x, 2 * p.y, p.z ); g->spawn_hallucination( mp ); } } @@ -3782,7 +3854,7 @@ bool map::open_door( const tripoint &p, const bool inside, const bool check_only int openable = vp->vehicle().next_part_to_open( vp->part_index(), true ); if( openable >= 0 ) { if( !check_only ) { - if( !vp->vehicle().handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( !vp->vehicle().handle_potential_theft( player_character ) ) { return false; } vp->vehicle().open_all_at( openable ); @@ -4030,14 +4102,14 @@ std::vector map::spawn_items( const tripoint &p, const std::vector return ret; } -void map::spawn_artifact( const tripoint &p ) +void map::spawn_artifact( const tripoint &p, const relic_procgen_id &id ) { - add_item_or_charges( p, item( new_artifact(), 0 ) ); -} + relic_procgen_data::generation_rules rules; + rules.max_attributes = 5; + rules.power_level = 1000; + rules.max_negative_power = -2000; -void map::spawn_natural_artifact( const tripoint &p, artifact_natural_property prop ) -{ - add_item_or_charges( p, item( new_natural_artifact( prop ), 0 ) ); + add_item_or_charges( p, id->create_item( rules ) ); } void map::spawn_item( const tripoint &p, const itype_id &type_id, @@ -4165,7 +4237,7 @@ item &map::add_item_or_charges( const tripoint &pos, item obj, bool overflow ) } else if( overflow ) { // ...otherwise try to overflow to adjacent tiles (if permitted) const int max_dist = 2; - std::vector tiles = closest_tripoints_first( pos, max_dist ); + std::vector tiles = closest_points_first( pos, max_dist ); tiles.erase( tiles.begin() ); // we already tried this position const int max_path_length = 4 * max_dist; const pathfinding_settings setting( 0, max_dist, max_path_length, 0, false, true, false, false, @@ -4729,7 +4801,8 @@ std::list use_charges_from_stack( Stack stack, const itype_id &type, int & } static void use_charges_from_furn( const furn_t &f, const itype_id &type, int &quantity, - map *m, const tripoint &p, std::list &ret, const std::function &filter ) + map *m, const tripoint &p, std::list &ret, + const std::function &filter ) { if( m->has_flag( "LIQUIDCONT", p ) ) { map_stack item_list = m->i_at( p ); @@ -5005,6 +5078,11 @@ std::list > map::get_rc_items( const tripoint &p ) return rc_pairs; } +bool map::can_see_trap_at( const tripoint &p, const Character &c ) const +{ + return tr_at( p ).can_see( p, c ); +} + const trap &map::tr_at( const tripoint &p ) const { if( !inbounds( p ) ) { @@ -5083,64 +5161,6 @@ void map::trap_set( const tripoint &p, const trap_id &type ) } } -void map::disarm_trap( const tripoint &p ) -{ - const trap &tr = tr_at( p ); - if( tr.is_null() ) { - debugmsg( "Tried to disarm a trap where there was none (%d %d %d)", p.x, p.y, p.z ); - return; - } - - const int tSkillLevel = g->u.get_skill_level( skill_traps ); - const int diff = tr.get_difficulty(); - int roll = rng( tSkillLevel, 4 * tSkillLevel ); - - // Some traps are not actual traps. Skip the rolls, different message and give the option to grab it right away. - if( tr.get_avoidance() == 0 && tr.get_difficulty() == 0 ) { - add_msg( _( "The %s is taken down." ), tr.name() ); - tr.on_disarmed( *this, p ); - return; - } - - ///\EFFECT_PER increases chance of disarming trap - - ///\EFFECT_DEX increases chance of disarming trap - - ///\EFFECT_TRAPS increases chance of disarming trap - while( ( rng( 5, 20 ) < g->u.per_cur || rng( 1, 20 ) < g->u.dex_cur ) && roll < 50 ) { - roll++; - } - if( roll >= diff ) { - add_msg( _( "You disarm the trap!" ) ); - const int morale_buff = tr.get_avoidance() * 0.4 + tr.get_difficulty() + rng( 0, 4 ); - g->u.rem_morale( MORALE_FAILURE ); - g->u.add_morale( MORALE_ACCOMPLISHMENT, morale_buff, 40 ); - tr.on_disarmed( *this, p ); - if( diff > 1.25 * tSkillLevel ) { // failure might have set off trap - g->u.practice( skill_traps, 1.5 * ( diff - tSkillLevel ) ); - } - } else if( roll >= diff * .8 ) { - add_msg( _( "You fail to disarm the trap." ) ); - const int morale_debuff = -rng( 6, 18 ); - g->u.rem_morale( MORALE_ACCOMPLISHMENT ); - g->u.add_morale( MORALE_FAILURE, morale_debuff, -40 ); - if( diff > 1.25 * tSkillLevel ) { - g->u.practice( skill_traps, 1.5 * ( diff - tSkillLevel ) ); - } - } else { - add_msg( m_bad, _( "You fail to disarm the trap, and you set it off!" ) ); - const int morale_debuff = -rng( 12, 24 ); - g->u.rem_morale( MORALE_ACCOMPLISHMENT ); - g->u.add_morale( MORALE_FAILURE, morale_debuff, -40 ); - tr.trigger( p, &g->u ); - if( diff - roll <= 6 ) { - // Give xp for failing, but not if we failed terribly (in which - // case the trap may not be disarmable). - g->u.practice( skill_traps, 2 * diff ); - } - } -} - void map::remove_trap( const tripoint &p ) { if( !inbounds( p ) ) { @@ -5152,8 +5172,8 @@ void map::remove_trap( const tripoint &p ) trap_id tid = current_submap->get_trap( l ); if( tid != tr_null ) { - if( g != nullptr && this == &g->m ) { - g->u.add_known_trap( p, tr_null.obj() ); + if( g != nullptr && this == &get_map() ) { + get_player_character().add_known_trap( p, tr_null.obj() ); } current_submap->set_trap( l, tr_null ); @@ -5220,7 +5240,8 @@ time_duration map::set_field_age( const tripoint &p, const field_type_id &type, * set intensity of field type at point, creating if not present, removing if intensity is 0 * returns resulting intensity, or 0 for not present */ -int map::set_field_intensity( const tripoint &p, const field_type_id &type, const int new_intensity, +int map::set_field_intensity( const tripoint &p, const field_type_id &type, + const int new_intensity, bool isoffset ) { field_entry *field_ptr = get_field( p, type ); @@ -5306,8 +5327,10 @@ bool map::add_field( const tripoint &p, const field_type_id &type, int intensity } } - if( g != nullptr && this == &g->m && p == g->u.pos() ) { - creature_in_field( g->u ); //Hit the player with the field if it spawned on top of them. + Character &player_character = get_player_character(); + if( g != nullptr && this == &get_map() && p == player_character.pos() ) { + //Hit the player with the field if it spawned on top of them. + creature_in_field( player_character ); } // Dirty the transparency cache now that field processing doesn't always do it @@ -5342,7 +5365,7 @@ void map::remove_field( const tripoint &p, const field_type_id &field_to_remove p.y / SEEX ) * MAPSIZE ) ) ); } const auto &fdata = field_to_remove.obj(); - if( fdata.is_transparent() ) { + if( !fdata.is_transparent() ) { set_transparency_cache_dirty( p.z ); } if( fdata.is_dangerous() ) { @@ -5370,7 +5393,8 @@ void map::add_splatter( const field_type_id &type, const tripoint &where, int in mod_field_intensity( where, type, intensity ); } -void map::add_splatter_trail( const field_type_id &type, const tripoint &from, const tripoint &to ) +void map::add_splatter_trail( const field_type_id &type, const tripoint &from, + const tripoint &to ) { if( !type.id() ) { return; @@ -5387,7 +5411,8 @@ void map::add_splatter_trail( const field_type_id &type, const tripoint &from, c } } -void map::add_splash( const field_type_id &type, const tripoint ¢er, int radius, int intensity ) +void map::add_splash( const field_type_id &type, const tripoint ¢er, int radius, + int intensity ) { if( !type.id() ) { return; @@ -5440,7 +5465,7 @@ void map::add_camp( const tripoint &omt_pos, const std::string &name ) { basecamp temp_camp = basecamp( name, omt_pos ); overmap_buffer.add_camp( temp_camp ); - g->u.camps.insert( omt_pos ); + get_player_character().camps.insert( omt_pos ); g->validate_camps(); } @@ -5455,14 +5480,16 @@ void map::update_submap_active_item_status( const tripoint &p ) void map::update_visibility_cache( const int zlev ) { + Character &player_character = get_player_character(); visibility_variables_cache.variables_set = true; // Not used yet visibility_variables_cache.g_light_level = static_cast( g->light_level( zlev ) ); - visibility_variables_cache.vision_threshold = g->u.get_vision_threshold( - get_cache_ref( g->u.posz() ).lm[g->u.posx()][g->u.posy()].max() ); + visibility_variables_cache.vision_threshold = player_character.get_vision_threshold( + get_cache_ref( + player_character.posz() ).lm[player_character.posx()][player_character.posy()].max() ); - visibility_variables_cache.u_clairvoyance = g->u.clairvoyance(); - visibility_variables_cache.u_sight_impaired = g->u.sight_impaired(); - visibility_variables_cache.u_is_boomered = g->u.has_effect( effect_boomered ); + visibility_variables_cache.u_clairvoyance = player_character.clairvoyance(); + visibility_variables_cache.u_sight_impaired = player_character.sight_impaired(); + visibility_variables_cache.u_is_boomered = player_character.has_effect( effect_boomered ); int sm_squares_seen[MAPSIZE][MAPSIZE]; std::memset( sm_squares_seen, 0, sizeof( sm_squares_seen ) ); @@ -5498,7 +5525,8 @@ const visibility_variables &map::get_visibility_variables_cache() const return visibility_variables_cache; } -visibility_type map::get_visibility( const lit_level ll, const visibility_variables &cache ) const +visibility_type map::get_visibility( const lit_level ll, + const visibility_variables &cache ) const { switch( ll ) { case lit_level::DARK: @@ -5564,9 +5592,9 @@ bool map::apply_vision_effects( const catacurses::window &w, const visibility_ty bool map::draw_maptile_from_memory( const catacurses::window &w, const tripoint &p, const tripoint &view_center, bool move_cursor ) const { - int sym = g->u.get_memorized_symbol( getabs( p ) ); + int sym = get_avatar().get_memorized_symbol( getabs( p ) ); if( sym == 0 ) { - return false; + return true; } if( move_cursor ) { const int k = p.x + getmaxx( w ) / 2 - view_center.x; @@ -5576,7 +5604,7 @@ bool map::draw_maptile_from_memory( const catacurses::window &w, const tripoint } else { wputch( w, c_brown, sym ); } - return true; + return false; } void map::draw( const catacurses::window &w, const tripoint ¢er ) @@ -5599,7 +5627,8 @@ void map::draw( const catacurses::window &w, const tripoint ¢er ) p.z = center.z; int &x = p.x; int &y = p.y; - const bool do_map_memory = g->u.should_show_map_memory(); + avatar &player_character = get_avatar(); + const bool do_map_memory = player_character.should_show_map_memory(); for( y = center.y - getmaxy( w ) / 2; y <= center.y + getmaxy( w ) / 2; y++ ) { if( y - center.y + getmaxy( w ) / 2 >= getmaxy( w ) ) { continue; @@ -5611,7 +5640,7 @@ void map::draw( const catacurses::window &w, const tripoint ¢er ) x = center.x - getmaxx( w ) / 2; if( y < 0 || y >= MAPSIZE_Y ) { for( ; x < maxxrender; x++ ) { - if( !do_map_memory || !draw_maptile_from_memory( w, p, center, false ) ) { + if( !do_map_memory || draw_maptile_from_memory( w, p, center, false ) ) { wputch( w, c_black, ' ' ); } } @@ -5619,7 +5648,7 @@ void map::draw( const catacurses::window &w, const tripoint ¢er ) } while( x < 0 ) { - if( !do_map_memory || !draw_maptile_from_memory( w, p, center, false ) ) { + if( !do_map_memory || draw_maptile_from_memory( w, p, center, false ) ) { wputch( w, c_black, ' ' ); } x++; @@ -5636,15 +5665,17 @@ void map::draw( const catacurses::window &w, const tripoint ¢er ) const visibility_type vis = get_visibility( lighting, cache ); if( !apply_vision_effects( w, vis ) ) { const maptile curr_maptile = maptile( cur_submap, l ); - const bool just_this_zlevel = - draw_maptile( w, g->u, p, curr_maptile, + const bool draw_lower_zlevel = + draw_maptile( w, player_character, p, curr_maptile, false, true, center, - lighting == lit_level::LOW, lighting == lit_level::BRIGHT, true ); - if( !just_this_zlevel ) { + lighting == lit_level::LOW, + lighting == lit_level::BRIGHT, true ); + if( draw_lower_zlevel ) { p.z--; const maptile tile_below = maptile( sm_below, l ); - draw_from_above( w, g->u, p, tile_below, false, center, - lighting == lit_level::LOW, lighting == lit_level::BRIGHT, false ); + draw_from_above( w, player_character, p, tile_below, false, center, + lighting == lit_level::LOW, + lighting == lit_level::BRIGHT, false ); p.z++; } } else if( do_map_memory && ( vis == visibility_type::HIDDEN || vis == visibility_type::DARK ) ) { @@ -5657,7 +5688,7 @@ void map::draw( const catacurses::window &w, const tripoint ¢er ) } while( x < maxxrender ) { - if( !do_map_memory || !draw_maptile_from_memory( w, p, center, false ) ) { + if( !do_map_memory || draw_maptile_from_memory( w, p, center, false ) ) { wputch( w, c_black, ' ' ); } x++; @@ -5671,7 +5702,8 @@ void map::drawsq( const catacurses::window &w, player &u, const tripoint &p, drawsq( w, u, p, invert, show_items, u.pos() + u.view_offset, false, false, false ); } -void map::drawsq( const catacurses::window &w, player &u, const tripoint &p, const bool invert_arg, +void map::drawsq( const catacurses::window &w, player &u, const tripoint &p, + const bool invert_arg, const bool show_items_arg, const tripoint &view_center, const bool low_light, const bool bright_light, const bool inorder ) const { @@ -5688,9 +5720,9 @@ void map::drawsq( const catacurses::window &w, player &u, const tripoint &p, con } const maptile tile = maptile_at( p ); - const bool done = draw_maptile( w, u, p, tile, invert_arg, show_items_arg, + const bool more = draw_maptile( w, u, p, tile, invert_arg, show_items_arg, view_center, low_light, bright_light, inorder ); - if( !done ) { + if( more ) { tripoint below( p.xy(), p.z - 1 ); const maptile tile_below = maptile_at( below ); draw_from_above( w, u, below, tile_below, @@ -5700,11 +5732,13 @@ void map::drawsq( const catacurses::window &w, player &u, const tripoint &p, con } // a check to see if the lower floor needs to be rendered in tiles -bool map::need_draw_lower_floor( const tripoint &p ) +bool map::dont_draw_lower_floor( const tripoint &p ) { - return !( !zlevels || p.z <= -OVERMAP_DEPTH || !ter( p ).obj().has_flag( TFLAG_NO_FLOOR ) ); + return !zlevels || p.z <= -OVERMAP_DEPTH || + !( has_flag( TFLAG_NO_FLOOR, p ) || has_flag( TFLAG_Z_TRANSPARENT, p ) ); } +// returns true if lower z-level needs to be drawn, false otherwise bool map::draw_maptile( const catacurses::window &w, const player &u, const tripoint &p, const maptile &curr_maptile, bool invert, bool show_items, @@ -5739,8 +5773,9 @@ bool map::draw_maptile( const catacurses::window &w, const player &u, const trip !u.is_underwater() ) { show_items = false; // Can only see underwater items if WE are underwater } + avatar &player_character = get_avatar(); // If there's a trap here, and we have sufficient perception, draw that instead - if( curr_trap.can_see( p, g->u ) ) { + if( curr_trap.can_see( p, player_character ) ) { tercol = curr_trap.color; if( curr_trap.sym == '%' ) { switch( rng( 1, 5 ) ) { @@ -5819,7 +5854,8 @@ bool map::draw_maptile( const catacurses::window &w, const player &u, const trip std::string item_sym; // If there are items here, draw those instead - if( show_items && curr_maptile.get_item_count() > 0 && sees_some_items( p, g->u ) ) { + if( show_items && curr_maptile.get_item_count() > 0 && + sees_some_items( p, player_character ) ) { // if there's furniture/terrain/trap/fields (sym!='.') // and we should not override it, then only highlight the square if( sym != '.' && sym != '%' && !draw_item_sym ) { @@ -5844,13 +5880,13 @@ bool map::draw_maptile( const catacurses::window &w, const player &u, const trip tercol = veh->part_color( veh_part ); item_sym.clear(); // clear the item symbol so `sym` is used instead. - if( !veh->forward_velocity() && !veh->player_in_control( g->u ) ) { + if( !veh->forward_velocity() && !veh->player_in_control( player_character ) ) { memory_sym = sym; } } if( check_and_set_seen_cache( p ) ) { - g->u.memorize_symbol( getabs( p ), memory_sym ); + player_character.memorize_symbol( getabs( p ), memory_sym ); } // If there's graffiti here, change background color @@ -5895,8 +5931,9 @@ bool map::draw_maptile( const catacurses::window &w, const player &u, const trip } } - return !zlevels || sym != ' ' || !item_sym.empty() || p.z <= -OVERMAP_DEPTH || - !curr_ter.has_flag( TFLAG_NO_FLOOR ); + return zlevels && item_sym.empty() && p.z > -OVERMAP_DEPTH && + ( curr_ter.has_flag( TFLAG_Z_TRANSPARENT ) || + ( sym == ' ' && curr_ter.has_flag( TFLAG_NO_FLOOR ) ) ); } void map::draw_from_above( const catacurses::window &w, const player &u, const tripoint &p, @@ -5989,7 +6026,8 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range ) const /** * This one is internal-only, we don't want to expose the slope tweaking ickiness outside the map class. **/ -bool map::sees( const tripoint &F, const tripoint &T, const int range, int &bresenham_slope ) const +bool map::sees( const tripoint &F, const tripoint &T, const int range, + int &bresenham_slope ) const { if( ( range >= 0 && range < rl_dist( F, T ) ) || !inbounds( T ) ) { @@ -6330,10 +6368,10 @@ std::vector map::get_dir_circle( const tripoint &f, const tripoint &t // The line below can be crazy expensive - we only take the FIRST point of it const std::vector line = line_to( f, t, 0, 0 ); - const std::vector spiral = closest_tripoints_first( f, 1 ); + const std::vector spiral = closest_points_first( f, 1 ); const std::vector pos_index {1, 2, 4, 6, 8, 7, 5, 3}; - // All possible constellations (closest_tripoints_first goes clockwise) + // All possible constellations (closest_points_first goes clockwise) // 753 531 312 124 246 468 687 875 // 8 1 7 2 5 4 3 6 1 8 2 7 4 5 6 3 // 642 864 786 578 357 135 213 421 @@ -6461,10 +6499,11 @@ void map::shift( const point &sp ) set_abs_sub( abs + sp ); + Character &player_character = get_player_character(); // if player is in vehicle, (s)he must be shifted with vehicle too - if( g->u.in_vehicle ) { - g->u.setx( g->u.posx() - sp.x * SEEX ); - g->u.sety( g->u.posy() - sp.y * SEEY ); + if( player_character.in_vehicle ) { + player_character.setx( player_character.posx() - sp.x * SEEX ); + player_character.sety( player_character.posy() - sp.y * SEEY ); } g->shift_destination_preview( point( -sp.x * SEEX, -sp.y * SEEY ) ); @@ -6486,6 +6525,8 @@ void map::shift( const point &sp ) // absx and absy are our position in the world, for saving/loading purposes. for( int gridz = zmin; gridz <= zmax; gridz++ ) { // Clear vehicle list and rebuild after shift + // mlangsdorf 2020 - this is kind of insane, building the cache is not free, why are + // we doing this? clear_vehicle_cache( gridz ); clear_vehicle_list( gridz ); shift_bitset_cache( get_cache( gridz ).map_memory_seen_cache, sp ); @@ -6755,7 +6796,7 @@ void map::rotten_item_spawn( const item &item, const tripoint &pnt ) if( rng( 0, 100 ) < chance ) { MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( mgroup ); add_spawn( spawn_details, pnt ); - if( g->u.sees( pnt ) ) { + if( get_player_character().sees( pnt ) ) { if( item.is_seed() ) { add_msg( m_warning, _( "Something has crawled out of the %s plants!" ), item.get_plant_name() ); } else { @@ -7022,7 +7063,8 @@ void map::rad_scorch( const tripoint &p, const time_duration &time_since_last_ac } } -void map::decay_cosmetic_fields( const tripoint &p, const time_duration &time_since_last_actualize ) +void map::decay_cosmetic_fields( const tripoint &p, + const time_duration &time_since_last_actualize ) { for( auto &pr : field_at( p ) ) { auto &fd = pr.second; @@ -7150,8 +7192,9 @@ void map::copy_grid( const tripoint &to, const tripoint &from ) void map::spawn_monsters_submap_group( const tripoint &gp, mongroup &group, bool ignore_sight ) { + Character &player_character = get_player_character(); const int s_range = std::min( HALF_MAPSIZE_X, - g->u.sight_range( g->light_level( g->u.posz() ) ) ); + player_character.sight_range( g->light_level( player_character.posz() ) ) ); int pop = group.population; std::vector locations; if( !ignore_sight ) { @@ -7162,7 +7205,7 @@ void map::spawn_monsters_submap_group( const tripoint &gp, mongroup &group, bool } } - if( gp.z != g->u.posz() ) { + if( gp.z != player_character.posz() ) { // Note: this is only OK because 3D vision isn't a thing yet ignore_sight = true; } @@ -7206,7 +7249,7 @@ void map::spawn_monsters_submap_group( const tripoint &gp, mongroup &group, bool continue; // solid area, impassable } - if( !ignore_sight && sees( g->u.pos(), fp, s_range ) ) { + if( !ignore_sight && sees( player_character.pos(), fp, s_range ) ) { continue; // monster must spawn outside the viewing range of the player } @@ -7299,7 +7342,7 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight ) for( auto &i : current_submap->spawns ) { const tripoint center = gp_ms + i.pos; - const tripoint_range points = points_in_radius( center, 3 ); + const tripoint_range points = points_in_radius( center, 3 ); for( int j = 0; j < i.count; j++ ) { monster tmp( i.type ); @@ -7321,7 +7364,7 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight ) const auto valid_location = [&]( const tripoint & p ) { // Checking for creatures via g is only meaningful if this is the main game map. // If it's some local map instance, the coordinates will most likely not even match. - return ( !g || &g->m != this || !g->critter_at( p ) ) && tmp.can_move_to( p ); + return ( !g || &get_map() != this || !g->critter_at( p ) ) && tmp.can_move_to( p ); }; const auto place_it = [&]( const tripoint & p ) { @@ -7698,40 +7741,44 @@ void map::build_floor_caches() } } -void map::do_vehicle_caching( int z ) +static void vehicle_caching_internal( level_cache &zch, const vpart_reference &vp, vehicle *v ) { - auto &ch = get_cache( z ); - auto &outside_cache = ch.outside_cache; - auto &transparency_cache = ch.transparency_cache; - auto &floor_cache = ch.floor_cache; - for( vehicle *v : ch.vehicle_list ) { - for( const vpart_reference &vp : v->get_all_parts() ) { - const size_t part = vp.part_index(); - point p2( v->global_pos3().xy() + vp.part().precalc[0] ); - const point p( p2 ); - if( !inbounds( p ) ) { - continue; - } + auto &outside_cache = zch.outside_cache; + auto &transparency_cache = zch.transparency_cache; + auto &floor_cache = zch.floor_cache; - bool vehicle_is_opaque = - vp.has_feature( VPFLAG_OPAQUE ) && !vp.part().is_broken(); + const size_t part = vp.part_index(); + const tripoint &part_pos = v->global_part_pos3( vp.part() ); - if( vehicle_is_opaque ) { - int dpart = v->part_with_feature( part, VPFLAG_OPENABLE, true ); - if( dpart < 0 || !v->part( dpart ).open ) { - transparency_cache[p2.x][p2.y] = LIGHT_TRANSPARENCY_SOLID; - } else { - vehicle_is_opaque = false; - } - } + bool vehicle_is_opaque = vp.has_feature( VPFLAG_OPAQUE ) && !vp.part().is_broken(); - if( vehicle_is_opaque || vp.is_inside() ) { - outside_cache[p2.x][p2.y] = false; - } + if( vehicle_is_opaque ) { + int dpart = v->part_with_feature( part, VPFLAG_OPENABLE, true ); + if( dpart < 0 || !v->part( dpart ).open ) { + transparency_cache[part_pos.x][part_pos.y] = LIGHT_TRANSPARENCY_SOLID; + } else { + vehicle_is_opaque = false; + } + } - if( vp.has_feature( VPFLAG_BOARDABLE ) && !vp.part().is_broken() ) { - floor_cache[p2.x][p2.y] = true; + if( vehicle_is_opaque || vp.is_inside() ) { + outside_cache[part_pos.x][part_pos.y] = false; + } + + if( vp.has_feature( VPFLAG_BOARDABLE ) && !vp.part().is_broken() ) { + floor_cache[part_pos.x][part_pos.y] = true; + } +} +void map::do_vehicle_caching( int z ) +{ + level_cache &ch = get_cache( z ); + for( vehicle *v : ch.vehicle_list ) { + for( const vpart_reference &vp : v->get_all_parts() ) { + const tripoint &part_pos = v->global_part_pos3( vp.part() ); + if( !inbounds( part_pos.xy() ) ) { + continue; } + vehicle_caching_internal( get_cache( part_pos.z ), vp, v ); } } } @@ -7753,7 +7800,7 @@ void map::build_map_cache( const int zlev, bool skip_lightmap ) skew_vision_cache.clear(); } // Initial value is illegal player position. - const tripoint &p = g->u.pos(); + const tripoint &p = get_player_character().pos(); static tripoint player_prev_pos; if( seen_cache_dirty || player_prev_pos != p ) { build_seen_cache( p, zlev ); @@ -7912,7 +7959,8 @@ void map::draw_square_ter( ter_id( *f )(), const point &p1, const point &p2 ) }, p1, p2 ); } -void map::draw_square_ter( const weighted_int_list &f, const point &p1, const point &p2 ) +void map::draw_square_ter( const weighted_int_list &f, const point &p1, + const point &p2 ) { draw_square( [this, f]( const point & p ) { const ter_id *tid = f.pick(); @@ -7983,20 +8031,36 @@ field &map::get_field( const tripoint &p ) void map::creature_on_trap( Creature &c, const bool may_avoid ) { - const auto &tr = tr_at( c.pos() ); - if( tr.is_null() ) { - return; - } // boarded in a vehicle means the player is above the trap, like a flying monster and can // never trigger the trap. const player *const p = dynamic_cast( &c ); if( p != nullptr && p->in_vehicle ) { return; } - if( may_avoid && c.avoid_trap( c.pos(), tr ) ) { + maybe_trigger_trap( c.pos(), c, may_avoid ); +} + +void map::maybe_trigger_trap( const tripoint &pos, Creature &c, const bool may_avoid ) +{ + const auto &tr = tr_at( pos ); + if( tr.is_null() ) { + return; + } + + if( may_avoid && c.avoid_trap( pos, tr ) ) { + player *const pl = c.as_player(); + if( !tr.is_always_invisible() && pl && !pl->knows_trap( pos ) ) { + pl->add_msg_if_player( _( "You've spotted a %1$ss!" ), tr.name() ); + pl->add_known_trap( pos, tr ); + } return; } - tr.trigger( c.pos(), &c ); + + if( !tr.is_always_invisible() ) { + c.add_msg_player_or_npc( m_bad, _( "You trigger a %s!" ), _( " triggers a %s!" ), + tr.name() ); + } + tr.trigger( c.pos(), c ); } template @@ -8108,42 +8172,44 @@ void map::scent_blockers( std::array, MAPSIZE_Y> &bl } } -tripoint_range map::points_in_rectangle( const tripoint &from, const tripoint &to ) const +tripoint_range map::points_in_rectangle( const tripoint &from, const tripoint &to ) const { const tripoint min( std::max( 0, std::min( from.x, to.x ) ), std::max( 0, std::min( from.y, to.y ) ), std::max( -OVERMAP_DEPTH, std::min( from.z, to.z ) ) ); const tripoint max( std::min( SEEX * my_MAPSIZE - 1, std::max( from.x, to.x ) ), std::min( SEEX * my_MAPSIZE - 1, std::max( from.y, to.y ) ), std::min( OVERMAP_HEIGHT, std::max( from.z, to.z ) ) ); - return tripoint_range( min, max ); + return tripoint_range( min, max ); } -tripoint_range map::points_in_radius( const tripoint ¢er, size_t radius, size_t radiusz ) const +tripoint_range map::points_in_radius( const tripoint ¢er, size_t radius, + size_t radiusz ) const { const tripoint min( std::max( 0, center.x - radius ), std::max( 0, center.y - radius ), clamp( center.z - radiusz, -OVERMAP_DEPTH, OVERMAP_HEIGHT ) ); const tripoint max( std::min( SEEX * my_MAPSIZE - 1, center.x + radius ), std::min( SEEX * my_MAPSIZE - 1, center.y + radius ), clamp( center.z + radiusz, -OVERMAP_DEPTH, OVERMAP_HEIGHT ) ); - return tripoint_range( min, max ); + return tripoint_range( min, max ); } -tripoint_range map::points_on_zlevel( const int z ) const +tripoint_range map::points_on_zlevel( const int z ) const { if( z < -OVERMAP_DEPTH || z > OVERMAP_HEIGHT ) { // TODO: need a default constructor that creates an empty range. - return tripoint_range( tripoint_zero, tripoint_zero - tripoint_above ); + return tripoint_range( tripoint_zero, tripoint_zero - tripoint_above ); } - return tripoint_range( tripoint( 0, 0, z ), tripoint( SEEX * my_MAPSIZE - 1, SEEY * my_MAPSIZE - 1, - z ) ); + return tripoint_range( + tripoint( 0, 0, z ), tripoint( SEEX * my_MAPSIZE - 1, SEEY * my_MAPSIZE - 1, z ) ); } -tripoint_range map::points_on_zlevel() const +tripoint_range map::points_on_zlevel() const { return points_on_zlevel( abs_sub.z ); } -std::list map::get_active_items_in_radius( const tripoint ¢er, int radius ) const +std::list map::get_active_items_in_radius( const tripoint ¢er, + int radius ) const { return get_active_items_in_radius( center, radius, special_item_type::none ); } @@ -8188,7 +8254,8 @@ std::list map::get_active_items_in_radius( const tripoint ¢er return result; } -std::list map::find_furnitures_with_flag_in_radius( const tripoint ¢er, size_t radius, +std::list map::find_furnitures_with_flag_in_radius( const tripoint ¢er, + size_t radius, const std::string &flag, size_t radiusz ) { @@ -8351,7 +8418,8 @@ void map::update_pathfinding_cache( int zlev ) const } if( terrain.has_flag( TFLAG_GOES_DOWN ) || terrain.has_flag( TFLAG_GOES_UP ) || - terrain.has_flag( TFLAG_RAMP ) ) { + terrain.has_flag( TFLAG_RAMP ) || terrain.has_flag( TFLAG_RAMP_UP ) || + terrain.has_flag( TFLAG_RAMP_DOWN ) ) { cur_value |= PF_UPDOWN; } diff --git a/src/map.h b/src/map.h index 2a209ceaea716..f2e033219f702 100644 --- a/src/map.h +++ b/src/map.h @@ -56,7 +56,9 @@ class mapgendata; class monster; class optional_vpart_position; class player; +class relic_procgen_data; class submap; +template class tripoint_range; class vehicle; class zone_data; @@ -93,6 +95,8 @@ struct pathfinding_settings; template struct weighted_int_list; +using relic_procgen_id = string_id; + class map_stack : public item_stack { private: @@ -212,7 +216,7 @@ class map public: // Constructors & Initialization - map( int mapsize = MAPSIZE, bool zlev = false ); + map( int mapsize = MAPSIZE, bool zlev = true ); map( bool zlev ) : map( MAPSIZE, zlev ) { } virtual ~map(); @@ -439,7 +443,7 @@ class map */ int combined_movecost( const tripoint &from, const tripoint &to, const vehicle *ignored_vehicle = nullptr, - int modifier = 0, bool flying = false ) const; + int modifier = 0, bool flying = false, bool via_ramp = false ) const; /** * Returns true if a creature could walk from `from` to `to` in one step. @@ -447,7 +451,7 @@ class map * by stairs or (in case of flying monsters) open air with no floors. */ bool valid_move( const tripoint &from, const tripoint &to, - bool bash = false, bool flying = false ) const; + bool bash = false, bool flying = false, bool via_ramp = false ) const; /** * Size of map objects at `p` for purposes of ranged combat. @@ -543,6 +547,7 @@ class map // Vehicles: Common to 2D and 3D VehicleList get_vehicles(); void add_vehicle_to_cache( vehicle * ); + void clear_vehicle_point_from_cache( vehicle *veh, const tripoint &pt ); void update_vehicle_cache( vehicle *, int old_zlevel ); void reset_vehicle_cache( int zlev ); void clear_vehicle_cache( int zlev ); @@ -573,16 +578,21 @@ class map vehicle *veh_at_internal( const tripoint &p, int &part_num ); const vehicle *veh_at_internal( const tripoint &p, int &part_num ) const; // Put player on vehicle at x,y - void board_vehicle( const tripoint &p, player *pl ); + void board_vehicle( const tripoint &p, Character *pl ); // Remove given passenger from given vehicle part. // If dead_passenger, then null passenger is acceptable. - void unboard_vehicle( const vpart_reference &, player *passenger, + void unboard_vehicle( const vpart_reference &, Character *passenger, bool dead_passenger = false ); // Remove passenger from vehicle at p. void unboard_vehicle( const tripoint &p, bool dead_passenger = false ); // Change vehicle coordinates and move vehicle's driver along. // WARNING: not checking collisions! - bool displace_vehicle( vehicle &veh, const tripoint &dp ); + // optionally: include a list of parts to displace instead of the entire vehicle + bool displace_vehicle( vehicle &veh, const tripoint &dp, bool adjust_pos = true, + const std::set &parts_to_move = {} ); + // make sure a vehicle that is split across z-levels is properly supported + // calls displace_vehicle() and shouldn't be called from displace_vehicle + void level_vehicle( vehicle &veh ); // move water under wheels. true if moved bool displace_water( const tripoint &dp ); @@ -686,6 +696,10 @@ class map * Check whether a chair or vehicle seat is nearby. */ bool has_nearby_chair( const tripoint &p, int radius = 1 ); + /** + * Checks whether a specific terrain is nearby. + */ + bool has_nearby_ter( const tripoint &p, const ter_id &type, int radius = 1 ); /** * Check if creature can see some items at p. Includes: * - check for items at this location (has_items(p)) @@ -1008,8 +1022,7 @@ class map void i_rem( const point &p, item *it ) { i_rem( tripoint( p, abs_sub.z ), it ); } - void spawn_artifact( const tripoint &p ); - void spawn_natural_artifact( const tripoint &p, artifact_natural_property prop ); + void spawn_artifact( const tripoint &p, const relic_procgen_id &id ); void spawn_item( const tripoint &p, const itype_id &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0 ); @@ -1150,17 +1163,28 @@ class map void trap_set( const tripoint &p, const trap_id &type ); const trap &tr_at( const tripoint &p ) const; + /// See @ref trap::can_see, which is called for the trap here. + bool can_see_trap_at( const tripoint &p, const Character &c ) const; - void disarm_trap( const tripoint &p ); void remove_trap( const tripoint &p ); const std::vector &get_furn_field_locations() const; const std::vector &trap_locations( const trap_id &type ) const; + /** + * Handles activating a trap. It includes checks for avoiding the trap + * (which also makes it visible). + * This functions assumes the character is either on top of the trap, + * or adjacent to it. + */ + void maybe_trigger_trap( const tripoint &pos, Creature &c, bool may_avoid ); + // Spawns byproducts from items destroyed in fire. void create_burnproducts( const tripoint &p, const item &fuel, const units::mass &burned_mass ); // See fields.cpp bool process_fields(); bool process_fields_in_submap( submap *current_submap, const tripoint &submap_pos ); + bool process_fire_field_in_submap( maptile &map_tile, const tripoint &p, + field_entry &cur, bool &dirty_transparency_cache ); /** * Apply field effects to the creature when it's on a square with fields. */ @@ -1343,8 +1367,7 @@ class map void place_toilet( const point &p, int charges = 6 * 4 ); void place_vending( const point &p, const std::string &type, bool reinforced = false ); // places an NPC, if static NPCs are enabled or if force is true - character_id place_npc( const point &p, const string_id &type, - bool force = false ); + character_id place_npc( const point &p, const string_id &type ); void apply_faction_ownership( const point &p1, const point &p2, const faction_id &id ); void add_spawn( const mtype_id &type, int count, const tripoint &p, bool friendly = false, int faction_id = -1, int mission_id = -1, @@ -1648,7 +1671,7 @@ class map /** * Internal version of the drawsq. Keeps a cached maptile for less re-getting. - * Returns true if it has drawn all it should, false if `draw_from_above` should be called after. + * Returns false if it has drawn all it should, true if `draw_from_above` should be called after. */ bool draw_maptile( const catacurses::window &w, const player &u, const tripoint &p, const maptile &tile, @@ -1783,16 +1806,18 @@ class map return submaps_with_active_items; } // Clips the area to map bounds - tripoint_range points_in_rectangle( const tripoint &from, const tripoint &to ) const; - tripoint_range points_in_radius( const tripoint ¢er, size_t radius, size_t radiusz = 0 ) const; + tripoint_range points_in_rectangle( + const tripoint &from, const tripoint &to ) const; + tripoint_range points_in_radius( + const tripoint ¢er, size_t radius, size_t radiusz = 0 ) const; /** * Yields a range of all points that are contained in the map and have the z-level of * this map (@ref abs_sub). */ - tripoint_range points_on_zlevel() const; + tripoint_range points_on_zlevel() const; /// Same as above, but uses the specific z-level. If the given z-level is invalid, it /// returns an empty range. - tripoint_range points_on_zlevel( int z ) const; + tripoint_range points_on_zlevel( int z ) const; std::list get_active_items_in_radius( const tripoint ¢er, int radius ) const; std::list get_active_items_in_radius( const tripoint ¢er, int radius, @@ -1808,7 +1833,7 @@ class map level_cache &access_cache( int zlev ); const level_cache &access_cache( int zlev ) const; - bool need_draw_lower_floor( const tripoint &p ); + bool dont_draw_lower_floor( const tripoint &p ); }; map &get_map(); diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 55ffc8b999d9c..8295fb44505e0 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -797,7 +797,7 @@ static bool mx_marloss_pilgrimage( map &m, const tripoint &abs_sub ) const tripoint leader_pos( rng( 4, 19 ), rng( 4, 19 ), abs_sub.z ); const int max_followers = rng( 3, 12 ); const int rad = 3; - const tripoint_range spawnzone = m.points_in_radius( leader_pos, rad ); + const tripoint_range spawnzone = m.points_in_radius( leader_pos, rad ); m.place_npc( leader_pos.xy(), string_id( "marloss_voice" ) ); for( int spawned = 0 ; spawned <= max_followers ; spawned++ ) { @@ -1051,7 +1051,8 @@ static bool mx_portal( map &m, const tripoint &abs_sub ) { // All points except the borders are valid--we need the 1 square buffer so that we can do a 1 unit radius // around our chosen portal point without clipping against the edge of the map. - const tripoint_range points = m.points_in_rectangle( { 1, 1, abs_sub.z }, { SEEX * 2 - 2, SEEY * 2 - 2, abs_sub.z } ); + const tripoint_range points = + m.points_in_rectangle( { 1, 1, abs_sub.z }, { SEEX * 2 - 2, SEEY * 2 - 2, abs_sub.z } ); // Get a random point in our collection that does not have a trap and does not have the NO_FLOOR flag. const cata::optional portal_pos = random_point( points, [&]( const tripoint & p ) { @@ -1098,7 +1099,7 @@ static bool mx_portal( map &m, const tripoint &abs_sub ) return true; } -static bool mx_minefield( map &m, const tripoint &abs_sub ) +static bool mx_minefield( map &, const tripoint &abs_sub ) { const tripoint abs_omt = sm_to_omt_copy( abs_sub ); const oter_id ¢er = overmap_buffer.ter( abs_omt ); @@ -1107,7 +1108,7 @@ static bool mx_minefield( map &m, const tripoint &abs_sub ) const oter_id &west = overmap_buffer.ter( abs_omt + point_west ); const oter_id &east = overmap_buffer.ter( abs_omt + point_east ); - const bool bridge_at_center = is_ot_match( "bridge", center, ot_match_type::type ); + const bool bridgehead_at_center = is_ot_match( "bridgehead_ground", center, ot_match_type::type ); const bool bridge_at_north = is_ot_match( "bridge", north, ot_match_type::type ); const bool bridge_at_south = is_ot_match( "bridge", south, ot_match_type::type ); const bool bridge_at_west = is_ot_match( "bridge", west, ot_match_type::type ); @@ -1124,7 +1125,14 @@ static bool mx_minefield( map &m, const tripoint &abs_sub ) bool did_something = false; - if( bridge_at_north && bridge_at_center && road_at_south ) { + if( !bridgehead_at_center ) { + return false; + } + + tinymap m; + if( bridge_at_north && bridgehead_at_center && road_at_south ) { + m.load( omt_to_sm_copy( abs_omt + point_south ), false ); + //Sandbag block at the left edge line_furn( &m, f_sandbag_half, point( 3, 4 ), point( 3, 7 ) ); line_furn( &m, f_sandbag_half, point( 3, 7 ), point( 9, 7 ) ); @@ -1222,7 +1230,8 @@ static bool mx_minefield( map &m, const tripoint &abs_sub ) did_something = true; } - if( bridge_at_south && bridge_at_center && road_at_north ) { + if( bridge_at_south && bridgehead_at_center && road_at_north ) { + m.load( omt_to_sm_copy( abs_omt + point_north ), false ); //Two horizontal lines of sandbags line_furn( &m, f_sandbag_half, point( 5, 15 ), point( 10, 15 ) ); line_furn( &m, f_sandbag_half, point( 13, 15 ), point( 18, 15 ) ); @@ -1323,7 +1332,8 @@ static bool mx_minefield( map &m, const tripoint &abs_sub ) did_something = true; } - if( bridge_at_west && bridge_at_center && road_at_east ) { + if( bridge_at_west && bridgehead_at_center && road_at_east ) { + m.load( omt_to_sm_copy( abs_omt + point_east ), false ); //Draw walls of first tent square_furn( &m, f_canvas_wall, point( 0, 3 ), point( 4, 13 ) ); @@ -1469,7 +1479,8 @@ static bool mx_minefield( map &m, const tripoint &abs_sub ) did_something = true; } - if( bridge_at_east && bridge_at_center && road_at_west ) { + if( bridge_at_east && bridgehead_at_center && road_at_west ) { + m.load( omt_to_sm_copy( abs_omt + point_west ), false ); //Spawn military cargo truck blocking the entry m.add_vehicle( vproto_id( "military_cargo_truck" ), point( 15, 11 ), 270, 70, 1 ); @@ -1771,7 +1782,8 @@ static bool mx_portal_in( map &m, const tripoint &abs_sub ) artifact_natural_property prop = static_cast( rng( ARTPROP_NULL + 1, ARTPROP_MAX - 1 ) ); m.create_anomaly( portal_location, prop ); - m.spawn_natural_artifact( p + tripoint( rng( -1, 1 ), rng( -1, 1 ), abs_sub.z ), prop ); + m.spawn_artifact( p + tripoint( rng( -1, 1 ), rng( -1, 1 ), abs_sub.z ), + relic_procgen_id( "alien_reality" ) ); break; } } @@ -3019,7 +3031,7 @@ static bool mx_city_trap( map &/*m*/, const tripoint &abs_sub ) for( const tripoint &p : points_in_radius( trap_center, 1 ) ) { compmap.trap_set( p, tr_blade ); } - compmap.trap_set( trap_center, tr_engine ); + compmap.trap_set( trap_center, trap_str_id( "tr_engine" ) ); //... and a loudspeaker to attract zombies compmap.add_spawn( mon_turret_speaker, 1, trap_center ); } diff --git a/src/map_field.cpp b/src/map_field.cpp index 229ed9f24c59e..ca8733c4f4b00 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -124,7 +124,7 @@ int map::burn_body_part( player &u, field_entry &cur, body_part bp, const int sc { int total_damage = 0; const int intensity = cur.get_field_intensity(); - const int damage = rng( 1, scale + intensity ); + const int damage = rng( 1, ( scale + intensity ) / 2 ); // A bit ugly, but better than being annoyed by acid when in hazmat if( u.get_armor_type( DT_ACID, convert_bp( bp ) ) < damage ) { const dealt_damage_instance ddi = u.deal_damage( nullptr, convert_bp( bp ).id(), @@ -454,7 +454,6 @@ bool map::process_fields_in_submap( submap *const current_submap, cur.set_field_intensity( cur.get_field_intensity() + 1 ); } - int part; const ter_t &ter = map_tile.get_ter_t(); // Dissipate faster in water if( ter.has_flag( TFLAG_SWIMMABLE ) ) { @@ -501,484 +500,8 @@ bool map::process_fields_in_submap( submap *const current_submap, sblk.apply_slime( p, cur.get_field_intensity() * curtype.obj().apply_slime_factor ); } if( curtype == fd_fire ) { - cur.set_field_age( std::max( -24_hours, cur.get_field_age() ) ); - // Entire objects for ter/frn for flags - const oter_id &cur_om_ter = overmap_buffer.ter( ms_to_omt_copy( here.getabs( p ) ) ); - bool sheltered = g->is_sheltered( p ); - int winddirection = g->weather.winddirection; - int windpower = get_local_windpower( g->weather.windspeed, cur_om_ter, p, winddirection, - sheltered ); - const ter_t &ter = map_tile.get_ter_t(); - const furn_t &frn = map_tile.get_furn_t(); - - // We've got ter/furn cached, so let's use that - const bool is_sealed = ter_furn_has_flag( ter, frn, TFLAG_SEALED ) && - !ter_furn_has_flag( ter, frn, TFLAG_ALLOW_FIELD_EFFECT ); - // Smoke generation probability, consumed items count - int smoke = 0; - int consumed = 0; - // How much time to add to the fire's life due to burned items/terrain/furniture - time_duration time_added = 0_turns; - // Checks if the fire can spread - const bool can_spread = !ter_furn_has_flag( ter, frn, TFLAG_FIRE_CONTAINER ); - // If the flames are in furniture with fire_container flag like brazier or oven, - // they're fully contained, so skip consuming terrain - const bool can_burn = ( ter.is_flammable() || frn.is_flammable() ) && - !ter_furn_has_flag( ter, frn, TFLAG_FIRE_CONTAINER ); - // The huge indent below should probably be somehow moved away from here - // without forcing the function to use i_at( p ) for fires without items - if( !is_sealed && map_tile.get_item_count() > 0 ) { - map_stack items_here = i_at( p ); - std::vector new_content; - for( auto it = items_here.begin(); it != items_here.end(); ) { - if( it->will_explode_in_fire() ) { - // We need to make a copy because the iterator validity is not predictable - item copy = *it; - it = items_here.erase( it ); - if( copy.detonate( p, new_content ) ) { - // Need to restart, iterators may not be valid - it = items_here.begin(); - } - } else { - ++it; - } - } - - fire_data frd( cur.get_field_intensity(), !can_spread ); - // The highest # of items this fire can remove in one turn - int max_consume = cur.get_field_intensity() * 2; - - for( auto fuel = items_here.begin(); fuel != items_here.end() && consumed < max_consume; ) { - // `item::burn` modifies the charges in order to simulate some of them getting - // destroyed by the fire, this changes the item weight, but may not actually - // destroy it. We need to spawn products anyway. - const units::mass old_weight = fuel->weight( false ); - bool destroyed = fuel->burn( frd ); - // If the item is considered destroyed, it may have negative charge count, - // see `item::burn?. This in turn means `item::weight` returns a negative value, - // which we can not use, so only call `weight` when it's still an existing item. - const units::mass new_weight = destroyed ? 0_gram : fuel->weight( false ); - if( old_weight != new_weight ) { - create_burnproducts( p, *fuel, old_weight - new_weight ); - } - - if( destroyed ) { - // If we decided the item was destroyed by fire, remove it. - // But remember its contents, except for irremovable mods, if any - const std::list content_list = fuel->contents.all_items_top(); - for( item *it : content_list ) { - if( !it->is_irremovable() ) { - new_content.push_back( item( *it ) ); - } - } - fuel = items_here.erase( fuel ); - consumed++; - } else { - ++fuel; - } - } - - spawn_items( p, new_content ); - smoke = roll_remainder( frd.smoke_produced ); - time_added = 1_turns * roll_remainder( frd.fuel_produced ); - } - - // Get the part of the vehicle in the fire (_internal skips the boundary check) - vehicle *veh = veh_at_internal( p, part ); - if( veh != nullptr ) { - veh->damage( part, cur.get_field_intensity() * 10, DT_HEAT, true ); - // Damage the vehicle in the fire. - } - if( can_burn ) { - if( ter.has_flag( TFLAG_SWIMMABLE ) ) { - // Flames die quickly on water - cur.set_field_age( cur.get_field_age() + 4_minutes ); - } - - // Consume the terrain we're on - if( ter_furn_has_flag( ter, frn, TFLAG_FLAMMABLE ) ) { - // The fire feeds on the ground itself until max intensity. - time_added += 1_turns * ( 5 - cur.get_field_intensity() ); - smoke += 2; - smoke += static_cast( windpower / 5 ); - if( cur.get_field_intensity() > 1 && - one_in( 200 - cur.get_field_intensity() * 50 ) ) { - destroy( p, false ); - } - - } else if( ter_furn_has_flag( ter, frn, TFLAG_FLAMMABLE_HARD ) && - one_in( 3 ) ) { - // The fire feeds on the ground itself until max intensity. - time_added += 1_turns * ( 4 - cur.get_field_intensity() ); - smoke += 2; - smoke += static_cast( windpower / 5 ); - if( cur.get_field_intensity() > 1 && - one_in( 200 - cur.get_field_intensity() * 50 ) ) { - destroy( p, false ); - } - - } else if( ter.has_flag( TFLAG_FLAMMABLE_ASH ) ) { - // The fire feeds on the ground itself until max intensity. - time_added += 1_turns * ( 5 - cur.get_field_intensity() ); - smoke += 2; - smoke += static_cast( windpower / 5 ); - if( cur.get_field_intensity() > 1 && - one_in( 200 - cur.get_field_intensity() * 50 ) ) { - if( p.z > 0 ) { - // We're in the air - ter_set( p, t_open_air ); - } else { - ter_set( p, t_dirt ); - } - } - - } else if( frn.has_flag( TFLAG_FLAMMABLE_ASH ) ) { - // The fire feeds on the ground itself until max intensity. - time_added += 1_turns * ( 5 - cur.get_field_intensity() ); - smoke += 2; - smoke += static_cast( windpower / 5 ); - if( cur.get_field_intensity() > 1 && - one_in( 200 - cur.get_field_intensity() * 50 ) ) { - furn_set( p, f_ash ); - add_item_or_charges( p, item( "ash" ) ); - } - - } else if( ter.has_flag( TFLAG_NO_FLOOR ) && zlevels && p.z > -OVERMAP_DEPTH ) { - // We're hanging in the air - let's fall down - tripoint dst{ p.xy(), p.z - 1 }; - if( valid_move( p, dst, true, true ) ) { - maptile dst_tile = maptile_at_internal( dst ); - field_entry *fire_there = dst_tile.find_field( fd_fire ); - if( fire_there == nullptr ) { - dst_tile.add_field( fd_fire, 1, 0_turns ); - cur.set_field_intensity( cur.get_field_intensity() - 1 ); - } else { - // Don't fuel raging fires or they'll burn forever - // as they can produce small fires above themselves - int new_intensity = std::max( cur.get_field_intensity(), - fire_there->get_field_intensity() ); - // Allow smaller fires to combine - if( new_intensity < 3 && - cur.get_field_intensity() == fire_there->get_field_intensity() ) { - new_intensity++; - } - // A raging fire below us can support us for a while - // Otherwise decay and decay fast - if( fire_there->get_field_intensity() < 3 || one_in( 10 ) ) { - cur.set_field_intensity( cur.get_field_intensity() - 1 ); - } - fire_there->set_field_intensity( new_intensity ); - } - break; - } - } - } - // Lower age is a longer lasting fire - if( time_added != 0_turns ) { - cur.set_field_age( cur.get_field_age() - time_added ); - } else if( can_burn ) { - // Nothing to burn = fire should be dying out faster - // Drain more power from big fires, so that they stop raging over nothing - // Except for fires on stoves and fireplaces, those are made to keep the fire alive - cur.mod_field_age( 10_seconds * cur.get_field_intensity() ); - } - - // Below we will access our nearest 8 neighbors, so let's cache them now - // This should probably be done more globally, because large fires will re-do it a lot - auto neighs = get_neighbors( p ); - // Get the neighbours that are allowed due to wind direction - auto maptiles = get_wind_blockers( winddirection, p ); - maptile remove_tile = std::get<0>( maptiles ); - maptile remove_tile2 = std::get<1>( maptiles ); - maptile remove_tile3 = std::get<2>( maptiles ); - std::vector neighbour_vec; - size_t end_it = static_cast( rng( 0, neighs.size() - 1 ) ); - // Start at end_it + 1, then wrap around until all elements have been processed - for( size_t i = ( end_it + 1 ) % neighs.size(), count = 0; - count != neighs.size(); - i = ( i + 1 ) % neighs.size(), count++ ) { - const auto &neigh = neighs[i]; - if( ( neigh.pos_.x != remove_tile.pos_.x && neigh.pos_.y != remove_tile.pos_.y ) || - ( neigh.pos_.x != remove_tile2.pos_.x && neigh.pos_.y != remove_tile2.pos_.y ) || - ( neigh.pos_.x != remove_tile3.pos_.x && neigh.pos_.y != remove_tile3.pos_.y ) ) { - neighbour_vec.push_back( neigh ); - } else if( x_in_y( 1, std::max( 2, windpower ) ) ) { - neighbour_vec.push_back( neigh ); - } - } - // If the flames are in a pit, it can't spread to non-pit - const bool in_pit = ter.id.id() == t_pit; - - // Count adjacent fires, to optimize out needless smoke and hot air - int adjacent_fires = 0; - - // If the flames are big, they contribute to adjacent flames - if( can_spread ) { - if( cur.get_field_intensity() > 1 && one_in( 3 ) ) { - // Basically: Scan around for a spot, - // if there is more fire there, make it bigger and give it some fuel. - // This is how big fires spend their excess age: - // making other fires bigger. Flashpoint. - if( sheltered || windpower < 5 ) { - end_it = static_cast( rng( 0, neighs.size() - 1 ) ); - for( size_t i = ( end_it + 1 ) % neighs.size(), count = 0; - count != neighs.size() && cur.get_field_age() < 0_turns; - i = ( i + 1 ) % neighs.size(), count++ ) { - maptile &dst = neighs[i]; - auto dstfld = dst.find_field( fd_fire ); - // If the fire exists and is weaker than ours, boost it - if( dstfld != nullptr && - ( dstfld->get_field_intensity() <= cur.get_field_intensity() || - dstfld->get_field_age() > cur.get_field_age() ) && - ( in_pit == ( dst.get_ter() == t_pit ) ) ) { - if( dstfld->get_field_intensity() < 2 ) { - dstfld->set_field_intensity( dstfld->get_field_intensity() + 1 ); - } - - dstfld->set_field_age( dstfld->get_field_age() - 5_minutes ); - cur.set_field_age( cur.get_field_age() + 5_minutes ); - } - if( dstfld != nullptr ) { - adjacent_fires++; - } - } - } else { - end_it = static_cast( rng( 0, neighbour_vec.size() - 1 ) ); - for( size_t i = ( end_it + 1 ) % neighbour_vec.size(), count = 0; - count != neighbour_vec.size() && cur.get_field_age() < 0_turns; - i = ( i + 1 ) % neighbour_vec.size(), count++ ) { - maptile &dst = neighbour_vec[i]; - field_entry *dstfld = dst.find_field( fd_fire ); - // If the fire exists and is weaker than ours, boost it - if( dstfld != nullptr && - ( dstfld->get_field_intensity() <= cur.get_field_intensity() || - dstfld->get_field_age() > cur.get_field_age() ) && - ( in_pit == ( dst.get_ter() == t_pit ) ) ) { - if( dstfld->get_field_intensity() < 2 ) { - dstfld->set_field_intensity( dstfld->get_field_intensity() + 1 ); - } - - dstfld->set_field_age( dstfld->get_field_age() - 5_minutes ); - cur.set_field_age( cur.get_field_age() + 5_minutes ); - } - - if( dstfld != nullptr ) { - adjacent_fires++; - } - } - } - } else if( cur.get_field_age() < 0_turns && cur.get_field_intensity() < 3 ) { - // See if we can grow into a stage 2/3 fire, for this - // burning neighbors are necessary in addition to - // field age < 0, or alternatively, a LOT of fuel. - - // The maximum fire intensity is 1 for a lone fire, 2 for at least 1 neighbor, - // 3 for at least 2 neighbors. - int maximum_intensity = 1; - - // The following logic looks a bit complex due to optimization concerns, so here are the semantics: - // 1. Calculate maximum field intensity based on fuel, -50 minutes is 2(medium), -500 minutes is 3(raging) - // 2. Calculate maximum field intensity based on neighbors, 3 neighbors is 2(medium), 7 or more neighbors is 3(raging) - // 3. Pick the higher maximum between 1. and 2. - if( cur.get_field_age() < -500_minutes ) { - maximum_intensity = 3; - } else { - for( auto &neigh : neighs ) { - if( neigh.get_field().find_field( fd_fire ) != nullptr ) { - adjacent_fires++; - } - } - maximum_intensity = 1 + ( adjacent_fires >= 3 ) + ( adjacent_fires >= 7 ); - - if( maximum_intensity < 2 && cur.get_field_age() < -50_minutes ) { - maximum_intensity = 2; - } - } - - // If we consumed a lot, the flames grow higher - if( cur.get_field_intensity() < maximum_intensity && cur.get_field_age() < 0_turns ) { - // Fires under 0 age grow in size. Level 3 fires under 0 spread later on. - // Weaken the newly-grown fire - cur.set_field_intensity( cur.get_field_intensity() + 1 ); - cur.set_field_age( cur.get_field_age() + 10_minutes * cur.get_field_intensity() ); - } - } - } - // Consume adjacent fuel / terrain / webs to spread. - // Allow raging fires (and only raging fires) to spread up - // Spreading down is achieved by wrecking the walls/floor and then falling - if( zlevels && cur.get_field_intensity() == 3 && p.z < OVERMAP_HEIGHT ) { - // Let it burn through the floor - maptile dst = maptile_at_internal( {p.xy(), p.z + 1} ); - const auto &dst_ter = dst.get_ter_t(); - if( dst_ter.has_flag( TFLAG_NO_FLOOR ) || - dst_ter.has_flag( TFLAG_FLAMMABLE ) || - dst_ter.has_flag( TFLAG_FLAMMABLE_ASH ) || - dst_ter.has_flag( TFLAG_FLAMMABLE_HARD ) ) { - field_entry *nearfire = dst.find_field( fd_fire ); - if( nearfire != nullptr ) { - nearfire->mod_field_age( -2_turns ); - } else { - dst.add_field( fd_fire, 1, 0_turns ); - } - // Fueling fires above doesn't cost fuel - } - } - // Our iterator will start at end_i + 1 and increment from there and then wrap around. - // This guarantees it will check all neighbors, starting from a random one - if( sheltered || windpower < 5 ) { - const size_t end_i = static_cast( rng( 0, neighs.size() - 1 ) ); - for( size_t i = ( end_i + 1 ) % neighs.size(), count = 0; - count != neighs.size(); - i = ( i + 1 ) % neighs.size(), count++ ) { - if( one_in( cur.get_field_intensity() * 2 ) ) { - // Skip some processing to save on CPU - continue; - } - - maptile &dst = neighs[i]; - // No bounds checking here: we'll treat the invalid neighbors as valid. - // We're using the map tile wrapper, so we can treat invalid tiles as sentinels. - // This will create small oddities on map edges, but nothing more noticeable than - // "cut-off" that happens with bounds checks. - - field_entry *nearfire = dst.find_field( fd_fire ); - if( nearfire != nullptr ) { - // We handled supporting fires in the section above, no need to do it here - continue; - } - - field_entry *nearwebfld = dst.find_field( fd_web ); - int spread_chance = 25 * ( cur.get_field_intensity() - 1 ); - if( nearwebfld != nullptr ) { - spread_chance = 50 + spread_chance / 2; - } - - const ter_t &dster = dst.get_ter_t(); - const furn_t &dsfrn = dst.get_furn_t(); - // Allow weaker fires to spread occasionally - const int power = cur.get_field_intensity() + one_in( 5 ); - if( can_spread && rng( 1, 100 ) < spread_chance && - ( dster.is_flammable() || dsfrn.is_flammable() ) && - ( in_pit == ( dster.id.id() == t_pit ) ) && - ( - ( power >= 3 && cur.get_field_age() < 0_turns && one_in( 20 ) ) || - ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE ) && one_in( 2 ) ) ) || - ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_ASH ) && one_in( 2 ) ) ) || - ( power >= 3 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_HARD ) && one_in( 5 ) ) ) || - nearwebfld || ( dst.get_item_count() > 0 && - flammable_items_at( p + eight_horizontal_neighbors[i] ) && - one_in( 5 ) ) - ) ) { - // Nearby open flammable ground? Set it on fire. - dst.add_field( fd_fire, 1, 0_turns ); - tmpfld = dst.find_field( fd_fire ); - if( tmpfld != nullptr ) { - // Make the new fire quite weak, so that it doesn't start jumping around instantly - tmpfld->set_field_age( 2_minutes ); - // Consume a bit of our fuel - cur.set_field_age( cur.get_field_age() + 1_minutes ); - } - if( nearwebfld ) { - nearwebfld->set_field_intensity( 0 ); - } - } - } - } else { - const size_t end_i = static_cast( rng( 0, neighbour_vec.size() - 1 ) ); - for( size_t i = ( end_i + 1 ) % neighbour_vec.size(), count = 0; - count != neighbour_vec.size(); - i = ( i + 1 ) % neighbour_vec.size(), count++ ) { - if( one_in( cur.get_field_intensity() * 2 ) ) { - // Skip some processing to save on CPU - continue; - } - - if( neighbour_vec.empty() ) { - continue; - } - - maptile &dst = neighbour_vec[i]; - // No bounds checking here: we'll treat the invalid neighbors as valid. - // We're using the map tile wrapper, so we can treat invalid tiles as sentinels. - // This will create small oddities on map edges, but nothing more noticeable than - // "cut-off" that happens with bounds checks. - - field_entry *nearfire = dst.find_field( fd_fire ); - if( nearfire != nullptr ) { - // We handled supporting fires in the section above, no need to do it here - continue; - } - - field_entry *nearwebfld = dst.find_field( fd_web ); - int spread_chance = 25 * ( cur.get_field_intensity() - 1 ); - if( nearwebfld != nullptr ) { - spread_chance = 50 + spread_chance / 2; - } - - const ter_t &dster = dst.get_ter_t(); - const furn_t &dsfrn = dst.get_furn_t(); - // Allow weaker fires to spread occasionally - const int power = cur.get_field_intensity() + one_in( 5 ); - if( can_spread && rng( 1, 100 - windpower ) < spread_chance && - ( dster.is_flammable() || dsfrn.is_flammable() ) && - ( in_pit == ( dster.id.id() == t_pit ) ) && - ( - ( power >= 3 && cur.get_field_age() < 0_turns && one_in( 20 ) ) || - ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE ) && one_in( 2 ) ) ) || - ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_ASH ) && one_in( 2 ) ) ) || - ( power >= 3 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_HARD ) && one_in( 5 ) ) ) || - nearwebfld || ( dst.get_item_count() > 0 && - flammable_items_at( p + eight_horizontal_neighbors[i] ) && - one_in( 5 ) ) - ) ) { - // Nearby open flammable ground? Set it on fire. - dst.add_field( fd_fire, 1, 0_turns ); - tmpfld = dst.find_field( fd_fire ); - if( tmpfld != nullptr ) { - // Make the new fire quite weak, so that it doesn't start jumping around instantly - tmpfld->set_field_age( 2_minutes ); - // Consume a bit of our fuel - cur.set_field_age( cur.get_field_age() + 1_minutes ); - } - if( nearwebfld ) { - nearwebfld->set_field_intensity( 0 ); - } - } - } - } - // Create smoke once - above us if possible, at us otherwise - if( !ter_furn_has_flag( ter, frn, TFLAG_SUPPRESS_SMOKE ) && - rng( 0, 100 - windpower ) <= smoke && - rng( 3, 35 ) < cur.get_field_intensity() * 10 ) { - bool smoke_up = zlevels && p.z < OVERMAP_HEIGHT; - if( smoke_up ) { - tripoint up{p.xy(), p.z + 1}; - maptile dst = maptile_at_internal( up ); - const ter_t &dst_ter = dst.get_ter_t(); - if( dst_ter.has_flag( TFLAG_NO_FLOOR ) ) { - dst.add_field( fd_smoke, rng( 1, cur.get_field_intensity() ), 0_turns ); - } else { - // Can't create smoke above - smoke_up = false; - } - } - - if( !smoke_up ) { - maptile dst = maptile_at_internal( p ); - // Create thicker smoke - dst.add_field( fd_smoke, cur.get_field_intensity(), 0_turns ); - } - - // Smoke affects transparency - dirty_transparency_cache = true; - } - - // Hot air is a load on the CPU - // Don't produce too much of it if we have a lot fires nearby, they produce - // radiant heat which does what hot air would do anyway - if( adjacent_fires < 5 && rng( 0, 4 - adjacent_fires ) ) { - create_hot_air( p, cur.get_field_intensity() ); + if( process_fire_field_in_submap( map_tile, p, cur, dirty_transparency_cache ) ) { + break; } } @@ -1349,6 +872,497 @@ bool map::process_fields_in_submap( submap *const current_submap, return dirty_transparency_cache; } +bool map::process_fire_field_in_submap( maptile &map_tile, const tripoint &p, + field_entry &cur, bool &dirty_transparency_cache ) +{ + bool breaks_loop = false; + map &here = get_map(); + field_entry *tmpfld = nullptr; + cur.set_field_age( std::max( -24_hours, cur.get_field_age() ) ); + // Entire objects for ter/frn for flags + const oter_id &cur_om_ter = overmap_buffer.ter( ms_to_omt_copy( here.getabs( p ) ) ); + bool sheltered = g->is_sheltered( p ); + int winddirection = g->weather.winddirection; + int windpower = get_local_windpower( g->weather.windspeed, cur_om_ter, p, winddirection, + sheltered ); + const ter_t &ter = map_tile.get_ter_t(); + const furn_t &frn = map_tile.get_furn_t(); + + // We've got ter/furn cached, so let's use that + const bool is_sealed = ter_furn_has_flag( ter, frn, TFLAG_SEALED ) && + !ter_furn_has_flag( ter, frn, TFLAG_ALLOW_FIELD_EFFECT ); + // Smoke generation probability, consumed items count + int smoke = 0; + int consumed = 0; + // How much time to add to the fire's life due to burned items/terrain/furniture + time_duration time_added = 0_turns; + // Checks if the fire can spread + const bool can_spread = !ter_furn_has_flag( ter, frn, TFLAG_FIRE_CONTAINER ); + // If the flames are in furniture with fire_container flag like brazier or oven, + // they're fully contained, so skip consuming terrain + const bool can_burn = ( ter.is_flammable() || frn.is_flammable() ) && + !ter_furn_has_flag( ter, frn, TFLAG_FIRE_CONTAINER ); + // The huge indent below should probably be somehow moved away from here + // without forcing the function to use i_at( p ) for fires without items + if( !is_sealed && map_tile.get_item_count() > 0 ) { + map_stack items_here = i_at( p ); + std::vector new_content; + for( auto it = items_here.begin(); it != items_here.end(); ) { + if( it->will_explode_in_fire() ) { + // We need to make a copy because the iterator validity is not predictable + item copy = *it; + it = items_here.erase( it ); + if( copy.detonate( p, new_content ) ) { + // Need to restart, iterators may not be valid + it = items_here.begin(); + } + } else { + ++it; + } + } + + fire_data frd( cur.get_field_intensity(), !can_spread ); + // The highest # of items this fire can remove in one turn + int max_consume = cur.get_field_intensity() * 2; + + for( auto fuel = items_here.begin(); fuel != items_here.end() && consumed < max_consume; ) { + // `item::burn` modifies the charges in order to simulate some of them getting + // destroyed by the fire, this changes the item weight, but may not actually + // destroy it. We need to spawn products anyway. + const units::mass old_weight = fuel->weight( false ); + bool destroyed = fuel->burn( frd ); + // If the item is considered destroyed, it may have negative charge count, + // see `item::burn?. This in turn means `item::weight` returns a negative value, + // which we can not use, so only call `weight` when it's still an existing item. + const units::mass new_weight = destroyed ? 0_gram : fuel->weight( false ); + if( old_weight != new_weight ) { + create_burnproducts( p, *fuel, old_weight - new_weight ); + } + + if( destroyed ) { + // If we decided the item was destroyed by fire, remove it. + // But remember its contents, except for irremovable mods, if any + const std::list content_list = fuel->contents.all_items_top(); + for( item *it : content_list ) { + if( !it->is_irremovable() ) { + new_content.push_back( item( *it ) ); + } + } + fuel = items_here.erase( fuel ); + consumed++; + } else { + ++fuel; + } + } + + spawn_items( p, new_content ); + smoke = roll_remainder( frd.smoke_produced ); + time_added = 1_turns * roll_remainder( frd.fuel_produced ); + } + + int part; + // Get the part of the vehicle in the fire (_internal skips the boundary check) + vehicle *veh = veh_at_internal( p, part ); + if( veh != nullptr ) { + veh->damage( part, cur.get_field_intensity() * 10, DT_HEAT, true ); + // Damage the vehicle in the fire. + } + if( can_burn ) { + if( ter.has_flag( TFLAG_SWIMMABLE ) ) { + // Flames die quickly on water + cur.set_field_age( cur.get_field_age() + 4_minutes ); + } + + // Consume the terrain we're on + if( ter_furn_has_flag( ter, frn, TFLAG_FLAMMABLE ) ) { + // The fire feeds on the ground itself until max intensity. + time_added += 1_turns * ( 5 - cur.get_field_intensity() ); + smoke += 2; + smoke += static_cast( windpower / 5 ); + if( cur.get_field_intensity() > 1 && + one_in( 200 - cur.get_field_intensity() * 50 ) ) { + destroy( p, false ); + } + + } else if( ter_furn_has_flag( ter, frn, TFLAG_FLAMMABLE_HARD ) && + one_in( 3 ) ) { + // The fire feeds on the ground itself until max intensity. + time_added += 1_turns * ( 4 - cur.get_field_intensity() ); + smoke += 2; + smoke += static_cast( windpower / 5 ); + if( cur.get_field_intensity() > 1 && + one_in( 200 - cur.get_field_intensity() * 50 ) ) { + destroy( p, false ); + } + + } else if( ter.has_flag( TFLAG_FLAMMABLE_ASH ) ) { + // The fire feeds on the ground itself until max intensity. + time_added += 1_turns * ( 5 - cur.get_field_intensity() ); + smoke += 2; + smoke += static_cast( windpower / 5 ); + if( cur.get_field_intensity() > 1 && + one_in( 200 - cur.get_field_intensity() * 50 ) ) { + if( p.z > 0 ) { + // We're in the air + ter_set( p, t_open_air ); + } else { + ter_set( p, t_dirt ); + } + } + + } else if( frn.has_flag( TFLAG_FLAMMABLE_ASH ) ) { + // The fire feeds on the ground itself until max intensity. + time_added += 1_turns * ( 5 - cur.get_field_intensity() ); + smoke += 2; + smoke += static_cast( windpower / 5 ); + if( cur.get_field_intensity() > 1 && + one_in( 200 - cur.get_field_intensity() * 50 ) ) { + furn_set( p, f_ash ); + add_item_or_charges( p, item( "ash" ) ); + } + + } else if( ter.has_flag( TFLAG_NO_FLOOR ) && zlevels && p.z > -OVERMAP_DEPTH ) { + // We're hanging in the air - let's fall down + tripoint dst{ p.xy(), p.z - 1 }; + if( valid_move( p, dst, true, true ) ) { + maptile dst_tile = maptile_at_internal( dst ); + field_entry *fire_there = dst_tile.find_field( fd_fire ); + if( fire_there == nullptr ) { + dst_tile.add_field( fd_fire, 1, 0_turns ); + cur.set_field_intensity( cur.get_field_intensity() - 1 ); + } else { + // Don't fuel raging fires or they'll burn forever + // as they can produce small fires above themselves + int new_intensity = std::max( cur.get_field_intensity(), + fire_there->get_field_intensity() ); + // Allow smaller fires to combine + if( new_intensity < 3 && + cur.get_field_intensity() == fire_there->get_field_intensity() ) { + new_intensity++; + } + // A raging fire below us can support us for a while + // Otherwise decay and decay fast + if( fire_there->get_field_intensity() < 3 || one_in( 10 ) ) { + cur.set_field_intensity( cur.get_field_intensity() - 1 ); + } + fire_there->set_field_intensity( new_intensity ); + } + dirty_transparency_cache = true; + return breaks_loop; + } + } + } + // Lower age is a longer lasting fire + if( time_added != 0_turns ) { + cur.set_field_age( cur.get_field_age() - time_added ); + } else if( can_burn ) { + // Nothing to burn = fire should be dying out faster + // Drain more power from big fires, so that they stop raging over nothing + // Except for fires on stoves and fireplaces, those are made to keep the fire alive + cur.mod_field_age( 10_seconds * cur.get_field_intensity() ); + } + + // Below we will access our nearest 8 neighbors, so let's cache them now + // This should probably be done more globally, because large fires will re-do it a lot + auto neighs = get_neighbors( p ); + // Get the neighbours that are allowed due to wind direction + auto maptiles = get_wind_blockers( winddirection, p ); + maptile remove_tile = std::get<0>( maptiles ); + maptile remove_tile2 = std::get<1>( maptiles ); + maptile remove_tile3 = std::get<2>( maptiles ); + std::vector neighbour_vec; + size_t end_it = static_cast( rng( 0, neighs.size() - 1 ) ); + // Start at end_it + 1, then wrap around until all elements have been processed + for( size_t i = ( end_it + 1 ) % neighs.size(), count = 0; + count != neighs.size(); + i = ( i + 1 ) % neighs.size(), count++ ) { + const auto &neigh = neighs[i]; + if( ( neigh.pos_.x != remove_tile.pos_.x && neigh.pos_.y != remove_tile.pos_.y ) || + ( neigh.pos_.x != remove_tile2.pos_.x && neigh.pos_.y != remove_tile2.pos_.y ) || + ( neigh.pos_.x != remove_tile3.pos_.x && neigh.pos_.y != remove_tile3.pos_.y ) ) { + neighbour_vec.push_back( neigh ); + } else if( x_in_y( 1, std::max( 2, windpower ) ) ) { + neighbour_vec.push_back( neigh ); + } + } + // If the flames are in a pit, it can't spread to non-pit + const bool in_pit = ter.id.id() == t_pit; + + // Count adjacent fires, to optimize out needless smoke and hot air + int adjacent_fires = 0; + + // If the flames are big, they contribute to adjacent flames + if( can_spread ) { + if( cur.get_field_intensity() > 1 && one_in( 3 ) ) { + // Basically: Scan around for a spot, + // if there is more fire there, make it bigger and give it some fuel. + // This is how big fires spend their excess age: + // making other fires bigger. Flashpoint. + if( sheltered || windpower < 5 ) { + end_it = static_cast( rng( 0, neighs.size() - 1 ) ); + for( size_t i = ( end_it + 1 ) % neighs.size(), count = 0; + count != neighs.size() && cur.get_field_age() < 0_turns; + i = ( i + 1 ) % neighs.size(), count++ ) { + maptile &dst = neighs[i]; + auto dstfld = dst.find_field( fd_fire ); + // If the fire exists and is weaker than ours, boost it + if( dstfld != nullptr && + ( dstfld->get_field_intensity() <= cur.get_field_intensity() || + dstfld->get_field_age() > cur.get_field_age() ) && + ( in_pit == ( dst.get_ter() == t_pit ) ) ) { + if( dstfld->get_field_intensity() < 2 ) { + dstfld->set_field_intensity( dstfld->get_field_intensity() + 1 ); + } + + dstfld->set_field_age( dstfld->get_field_age() - 5_minutes ); + cur.set_field_age( cur.get_field_age() + 5_minutes ); + } + if( dstfld != nullptr ) { + adjacent_fires++; + } + } + } else { + end_it = static_cast( rng( 0, neighbour_vec.size() - 1 ) ); + for( size_t i = ( end_it + 1 ) % neighbour_vec.size(), count = 0; + count != neighbour_vec.size() && cur.get_field_age() < 0_turns; + i = ( i + 1 ) % neighbour_vec.size(), count++ ) { + maptile &dst = neighbour_vec[i]; + field_entry *dstfld = dst.find_field( fd_fire ); + // If the fire exists and is weaker than ours, boost it + if( dstfld != nullptr && + ( dstfld->get_field_intensity() <= cur.get_field_intensity() || + dstfld->get_field_age() > cur.get_field_age() ) && + ( in_pit == ( dst.get_ter() == t_pit ) ) ) { + if( dstfld->get_field_intensity() < 2 ) { + dstfld->set_field_intensity( dstfld->get_field_intensity() + 1 ); + } + + dstfld->set_field_age( dstfld->get_field_age() - 5_minutes ); + cur.set_field_age( cur.get_field_age() + 5_minutes ); + } + + if( dstfld != nullptr ) { + adjacent_fires++; + } + } + } + } else if( cur.get_field_age() < 0_turns && cur.get_field_intensity() < 3 ) { + // See if we can grow into a stage 2/3 fire, for this + // burning neighbors are necessary in addition to + // field age < 0, or alternatively, a LOT of fuel. + + // The maximum fire intensity is 1 for a lone fire, 2 for at least 1 neighbor, + // 3 for at least 2 neighbors. + int maximum_intensity = 1; + + // The following logic looks a bit complex due to optimization concerns, so here are the semantics: + // 1. Calculate maximum field intensity based on fuel, -50 minutes is 2(medium), -500 minutes is 3(raging) + // 2. Calculate maximum field intensity based on neighbors, 3 neighbors is 2(medium), 7 or more neighbors is 3(raging) + // 3. Pick the higher maximum between 1. and 2. + if( cur.get_field_age() < -500_minutes ) { + maximum_intensity = 3; + } else { + for( auto &neigh : neighs ) { + if( neigh.get_field().find_field( fd_fire ) != nullptr ) { + adjacent_fires++; + } + } + maximum_intensity = 1 + ( adjacent_fires >= 3 ) + ( adjacent_fires >= 7 ); + + if( maximum_intensity < 2 && cur.get_field_age() < -50_minutes ) { + maximum_intensity = 2; + } + } + + // If we consumed a lot, the flames grow higher + if( cur.get_field_intensity() < maximum_intensity && cur.get_field_age() < 0_turns ) { + // Fires under 0 age grow in size. Level 3 fires under 0 spread later on. + // Weaken the newly-grown fire + cur.set_field_intensity( cur.get_field_intensity() + 1 ); + cur.set_field_age( cur.get_field_age() + 10_minutes * cur.get_field_intensity() ); + } + } + } + // Consume adjacent fuel / terrain / webs to spread. + // Allow raging fires (and only raging fires) to spread up + // Spreading down is achieved by wrecking the walls/floor and then falling + if( zlevels && cur.get_field_intensity() == 3 && p.z < OVERMAP_HEIGHT ) { + // Let it burn through the floor + maptile dst = maptile_at_internal( {p.xy(), p.z + 1} ); + const auto &dst_ter = dst.get_ter_t(); + if( dst_ter.has_flag( TFLAG_NO_FLOOR ) || + dst_ter.has_flag( TFLAG_FLAMMABLE ) || + dst_ter.has_flag( TFLAG_FLAMMABLE_ASH ) || + dst_ter.has_flag( TFLAG_FLAMMABLE_HARD ) ) { + field_entry *nearfire = dst.find_field( fd_fire ); + if( nearfire != nullptr ) { + nearfire->mod_field_age( -2_turns ); + } else { + dst.add_field( fd_fire, 1, 0_turns ); + } + // Fueling fires above doesn't cost fuel + } + } + // Our iterator will start at end_i + 1 and increment from there and then wrap around. + // This guarantees it will check all neighbors, starting from a random one + if( sheltered || windpower < 5 ) { + const size_t end_i = static_cast( rng( 0, neighs.size() - 1 ) ); + for( size_t i = ( end_i + 1 ) % neighs.size(), count = 0; + count != neighs.size(); + i = ( i + 1 ) % neighs.size(), count++ ) { + if( one_in( cur.get_field_intensity() * 2 ) ) { + // Skip some processing to save on CPU + continue; + } + + maptile &dst = neighs[i]; + // No bounds checking here: we'll treat the invalid neighbors as valid. + // We're using the map tile wrapper, so we can treat invalid tiles as sentinels. + // This will create small oddities on map edges, but nothing more noticeable than + // "cut-off" that happens with bounds checks. + + field_entry *nearfire = dst.find_field( fd_fire ); + if( nearfire != nullptr ) { + // We handled supporting fires in the section above, no need to do it here + continue; + } + + field_entry *nearwebfld = dst.find_field( fd_web ); + int spread_chance = 25 * ( cur.get_field_intensity() - 1 ); + if( nearwebfld != nullptr ) { + spread_chance = 50 + spread_chance / 2; + } + + const ter_t &dster = dst.get_ter_t(); + const furn_t &dsfrn = dst.get_furn_t(); + // Allow weaker fires to spread occasionally + const int power = cur.get_field_intensity() + one_in( 5 ); + if( can_spread && rng( 1, 100 ) < spread_chance && + ( dster.is_flammable() || dsfrn.is_flammable() ) && + ( in_pit == ( dster.id.id() == t_pit ) ) && + ( + ( power >= 3 && cur.get_field_age() < 0_turns && one_in( 20 ) ) || + ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE ) && one_in( 2 ) ) ) || + ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_ASH ) && one_in( 2 ) ) ) || + ( power >= 3 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_HARD ) && one_in( 5 ) ) ) || + nearwebfld || ( dst.get_item_count() > 0 && + flammable_items_at( p + eight_horizontal_neighbors[i] ) && + one_in( 5 ) ) + ) ) { + // Nearby open flammable ground? Set it on fire. + dst.add_field( fd_fire, 1, 0_turns ); + tmpfld = dst.find_field( fd_fire ); + if( tmpfld != nullptr ) { + // Make the new fire quite weak, so that it doesn't start jumping around instantly + tmpfld->set_field_age( 2_minutes ); + // Consume a bit of our fuel + cur.set_field_age( cur.get_field_age() + 1_minutes ); + } + if( nearwebfld ) { + nearwebfld->set_field_intensity( 0 ); + } + } + } + } else { + const size_t end_i = static_cast( rng( 0, neighbour_vec.size() - 1 ) ); + for( size_t i = ( end_i + 1 ) % neighbour_vec.size(), count = 0; + count != neighbour_vec.size(); + i = ( i + 1 ) % neighbour_vec.size(), count++ ) { + if( one_in( cur.get_field_intensity() * 2 ) ) { + // Skip some processing to save on CPU + continue; + } + + if( neighbour_vec.empty() ) { + continue; + } + + maptile &dst = neighbour_vec[i]; + // No bounds checking here: we'll treat the invalid neighbors as valid. + // We're using the map tile wrapper, so we can treat invalid tiles as sentinels. + // This will create small oddities on map edges, but nothing more noticeable than + // "cut-off" that happens with bounds checks. + + field_entry *nearfire = dst.find_field( fd_fire ); + if( nearfire != nullptr ) { + // We handled supporting fires in the section above, no need to do it here + continue; + } + + field_entry *nearwebfld = dst.find_field( fd_web ); + int spread_chance = 25 * ( cur.get_field_intensity() - 1 ); + if( nearwebfld != nullptr ) { + spread_chance = 50 + spread_chance / 2; + } + + const ter_t &dster = dst.get_ter_t(); + const furn_t &dsfrn = dst.get_furn_t(); + // Allow weaker fires to spread occasionally + const int power = cur.get_field_intensity() + one_in( 5 ); + if( can_spread && rng( 1, 100 - windpower ) < spread_chance && + ( dster.is_flammable() || dsfrn.is_flammable() ) && + ( in_pit == ( dster.id.id() == t_pit ) ) && + ( + ( power >= 3 && cur.get_field_age() < 0_turns && one_in( 20 ) ) || + ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE ) && one_in( 2 ) ) ) || + ( power >= 2 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_ASH ) && one_in( 2 ) ) ) || + ( power >= 3 && ( ter_furn_has_flag( dster, dsfrn, TFLAG_FLAMMABLE_HARD ) && one_in( 5 ) ) ) || + nearwebfld || ( dst.get_item_count() > 0 && + flammable_items_at( p + eight_horizontal_neighbors[i] ) && + one_in( 5 ) ) + ) ) { + // Nearby open flammable ground? Set it on fire. + dst.add_field( fd_fire, 1, 0_turns ); + tmpfld = dst.find_field( fd_fire ); + if( tmpfld != nullptr ) { + // Make the new fire quite weak, so that it doesn't start jumping around instantly + tmpfld->set_field_age( 2_minutes ); + // Consume a bit of our fuel + cur.set_field_age( cur.get_field_age() + 1_minutes ); + } + if( nearwebfld ) { + nearwebfld->set_field_intensity( 0 ); + } + } + } + } + // Create smoke once - above us if possible, at us otherwise + if( !ter_furn_has_flag( ter, frn, TFLAG_SUPPRESS_SMOKE ) && + rng( 0, 100 - windpower ) <= smoke && + rng( 3, 35 ) < cur.get_field_intensity() * 10 ) { + bool smoke_up = zlevels && p.z < OVERMAP_HEIGHT; + if( smoke_up ) { + tripoint up{p.xy(), p.z + 1}; + maptile dst = maptile_at_internal( up ); + const ter_t &dst_ter = dst.get_ter_t(); + if( dst_ter.has_flag( TFLAG_NO_FLOOR ) ) { + dst.add_field( fd_smoke, rng( 1, cur.get_field_intensity() ), 0_turns ); + } else { + // Can't create smoke above + smoke_up = false; + } + } + + if( !smoke_up ) { + maptile dst = maptile_at_internal( p ); + // Create thicker smoke + dst.add_field( fd_smoke, cur.get_field_intensity(), 0_turns ); + } + + // Smoke affects transparency + dirty_transparency_cache = true; + } + + // Hot air is a load on the CPU + // Don't produce too much of it if we have a lot fires nearby, they produce + // radiant heat which does what hot air would do anyway + if( adjacent_fires < 5 && rng( 0, 4 - adjacent_fires ) ) { + create_hot_air( p, cur.get_field_intensity() ); + } + + return breaks_loop; +} + // This entire function makes very little sense. Why are the rules the way they are? Why does walking into some things destroy them but not others? /* @@ -1387,16 +1401,13 @@ void map::player_in_field( player &u ) // you're certainly not standing in it. if( !u.in_vehicle && !u.has_trait( trait_ACIDPROOF ) ) { int total_damage = 0; - const int intensity = cur.get_field_intensity(); - // 1-3 at intensity, 1-4 at 2, 1-5 at 3 total_damage += burn_body_part( u, cur, bp_foot_l, 2 ); total_damage += burn_body_part( u, cur, bp_foot_r, 2 ); - // 1 dmg at 1 intensity, 1-3 at 2, 1-5 at 3 - total_damage += burn_body_part( u, cur, bp_leg_l, intensity - 1 ); - total_damage += burn_body_part( u, cur, bp_leg_r, intensity - 1 ); const bool on_ground = u.is_on_ground(); if( on_ground ) { - // Before, it would just break the legs and leave the survivor alone + // Apply the effect to the remaining body parts + total_damage += burn_body_part( u, cur, bp_leg_l, 2 ); + total_damage += burn_body_part( u, cur, bp_leg_r, 2 ); total_damage += burn_body_part( u, cur, bp_hand_l, 2 ); total_damage += burn_body_part( u, cur, bp_hand_r, 2 ); total_damage += burn_body_part( u, cur, bp_torso, 2 ); @@ -1578,8 +1589,7 @@ void map::player_in_field( player &u ) // Small universal damage based on intensity, only if not electroproofed. if( !u.is_elec_immune() ) { int total_damage = 0; - for( size_t i = 0; i < num_hp_parts; i++ ) { - const bodypart_id bp = convert_bp( player::hp_to_bp( static_cast( i ) ) ).id(); + for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { const int dmg = rng( 1, cur.get_field_intensity() ); total_damage += u.deal_damage( nullptr, bp, damage_instance( DT_ELECTRIC, dmg ) ).total_damage(); } @@ -1621,7 +1631,7 @@ void map::player_in_field( player &u ) int sum_cover = 0; for( const item &i : u.worn ) { if( i.covers( bp ) ) { - sum_cover += i.get_coverage(); + sum_cover += i.get_coverage( bp ); } } // Get stung if [clothing on a body part isn't thick enough (like t-shirt) OR clothing covers less than 100% of body part] diff --git a/src/map_iterator.h b/src/map_iterator.h index aa3048b9aae7a..72044516f0e73 100644 --- a/src/map_iterator.h +++ b/src/map_iterator.h @@ -6,10 +6,14 @@ #include "enums.h" #include "point.h" +#include "point_traits.h" +template class tripoint_range { + static_assert( Tripoint::dimension == 3, "Requires tripoint type" ); private: + using traits = point_traits; /** * Generates points in a rectangle. */ @@ -17,47 +21,50 @@ class tripoint_range { friend class tripoint_range; private: - tripoint p; + Tripoint p; const tripoint_range ⦥ + public: - using value_type = tripoint; + using value_type = Tripoint; using difference_type = std::ptrdiff_t; - using pointer = tripoint *; - using reference = tripoint &; + using pointer = value_type *; + using reference = value_type &; using iterator_category = std::forward_iterator_tag; - point_generator( const tripoint &_p, const tripoint_range &_range ) + point_generator( const Tripoint &_p, const tripoint_range &_range ) : p( _p ), range( _range ) { } // Increment x, then if it goes outside range, "wrap around" and increment y // Same for y and z inline point_generator &operator++() { - p.x++; - if( p.x <= range.maxp.x ) { + traits::x( p )++; + if( traits::x( p ) <= traits::x( range.maxp ) ) { return *this; } - p.y++; - p.x = range.minp.x; - if( p.y <= range.maxp.y ) { + traits::y( p )++; + traits::x( p ) = traits::x( range.minp ); + if( traits::y( p ) <= traits::y( range.maxp ) ) { return *this; } - p.z++; - p.y = range.minp.y; + traits::z( p )++; + traits::y( p ) = traits::y( range.minp ); return *this; } - inline const tripoint &operator*() const { + inline const Tripoint &operator*() const { return p; } inline bool operator!=( const point_generator &other ) const { // Reverse coordinates order, because it will usually only be compared with endpoint // which will always differ in Z, except for the very last comparison - const tripoint &pt = other.p; - return p.z != pt.z || p.y != pt.y || p.x != pt.x; + // TODO: In C++17 this range should use a sentinel to + // optimise the comparison. + const Tripoint &pt = other.p; + return traits::z( p ) != traits::z( pt ) || p.xy() != pt.xy(); } inline bool operator==( const point_generator &other ) const { @@ -65,20 +72,16 @@ class tripoint_range } }; - tripoint minp; - tripoint maxp; + Tripoint minp; + Tripoint maxp; public: - using value_type = point_generator::value_type; - using difference_type = point_generator::difference_type; - using pointer = point_generator::pointer; - using reference = point_generator::reference; - using iterator_category = point_generator::iterator_category; - - tripoint_range( const tripoint &_minp, const tripoint &_maxp ) : - minp( _minp ), maxp( _maxp ) { - } + using value_type = typename point_generator::value_type; + using difference_type = typename point_generator::difference_type; + using pointer = typename point_generator::pointer; + using reference = typename point_generator::reference; + using iterator_category = typename point_generator::iterator_category; - tripoint_range( tripoint &&_minp, tripoint &&_maxp ) : + tripoint_range( const Tripoint &_minp, const Tripoint &_maxp ) : minp( _minp ), maxp( _maxp ) { } @@ -89,20 +92,20 @@ class tripoint_range point_generator end() const { // Return the point AFTER the last one // That is, point under (in z-levels) the first one, but one z-level below the last one - return point_generator( tripoint( minp.xy(), maxp.z + 1 ), *this ); + return point_generator( Tripoint( minp.xy(), traits::z( maxp ) + 1 ), *this ); } size_t size() const { - tripoint range( maxp - minp ); - return std::max( ++range.x * ++range.y * ++range.z, 0 ); + Tripoint range( maxp - minp ); + return std::max( ++traits::x( range ) * ++traits::y( range ) * ++traits::z( range ), 0 ); } bool empty() const { return size() == 0; } - bool is_point_inside( const tripoint &point ) const { - for( const tripoint ¤t : *this ) { + bool is_point_inside( const Tripoint &point ) const { + for( const Tripoint ¤t : *this ) { if( current == point ) { return true; } @@ -110,19 +113,21 @@ class tripoint_range return false; } - const tripoint &min() const { + const Tripoint &min() const { return minp; } - const tripoint &max() const { + const Tripoint &max() const { return maxp; } }; -inline tripoint_range points_in_radius( const tripoint ¢er, const int radius, - const int radiusz = 0 ) +template +inline tripoint_range points_in_radius( const Tripoint ¢er, const int radius, + const int radiusz = 0 ) { + static_assert( Tripoint::dimension == 3, "Requires tripoint type" ); const tripoint offset( radius, radius, radiusz ); - return tripoint_range( center - offset, center + offset ); + return tripoint_range( center - offset, center + offset ); } #endif // CATA_SRC_MAP_ITERATOR_H diff --git a/src/map_selector.cpp b/src/map_selector.cpp index 8c14a7c3a9c7f..c3de3b7fdd7a4 100644 --- a/src/map_selector.cpp +++ b/src/map_selector.cpp @@ -14,19 +14,20 @@ map_selector::map_selector( const tripoint &pos, int radius, bool accessible ) { - for( const tripoint &e : closest_tripoints_first( pos, radius ) ) { + for( const tripoint &e : closest_points_first( pos, radius ) ) { if( !accessible || get_map().clear_path( pos, e, radius, 1, 100 ) ) { data.emplace_back( e ); } } } -tripoint_range points_in_range( const map &m ) +tripoint_range points_in_range( const map &m ) { const int z = m.get_abs_sub().z; const bool hasz = m.has_zlevels(); - return tripoint_range( tripoint( 0, 0, hasz ? -OVERMAP_DEPTH : z ), - tripoint( SEEX * m.getmapsize() - 1, SEEY * m.getmapsize() - 1, hasz ? OVERMAP_HEIGHT : z ) ); + return tripoint_range( + tripoint( 0, 0, hasz ? -OVERMAP_DEPTH : z ), + tripoint( SEEX * m.getmapsize() - 1, SEEY * m.getmapsize() - 1, hasz ? OVERMAP_HEIGHT : z ) ); } cata::optional random_point( const map &m, @@ -35,7 +36,7 @@ cata::optional random_point( const map &m, return random_point( points_in_range( m ), predicate ); } -cata::optional random_point( const tripoint_range &range, +cata::optional random_point( const tripoint_range &range, const std::function &predicate ) { // Optimist approach: just assume there are plenty of suitable places and a randomly diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 7fedd71ff51c4..ed44da5fdb1c8 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -175,8 +175,11 @@ static const std::unordered_map ter_bitflags_map = { { "BLOCK_WIND", TFLAG_BLOCK_WIND }, // This tile will partially block the wind. { "FLAT", TFLAG_FLAT }, // This tile is flat. { "RAMP", TFLAG_RAMP }, // Can be used to move up a z-level + { "RAMP_DOWN", TFLAG_RAMP_DOWN }, // Anything entering this tile moves down a z-level + { "RAMP_UP", TFLAG_RAMP_UP }, // Anything entering this tile moves up a z-level { "RAIL", TFLAG_RAIL }, // Rail tile (used heavily) { "THIN_OBSTACLE", TFLAG_THIN_OBSTACLE }, // Passable by players and monsters. Vehicles destroy it. + { "Z_TRANSPARENT", TFLAG_Z_TRANSPARENT }, // Doesn't block vision passing through the z-level { "SMALL_PASSAGE", TFLAG_SMALL_PASSAGE } // A small passage, that large or huge things cannot pass through } }; diff --git a/src/mapdata.h b/src/mapdata.h index 15bfdee87a0d6..3efd0fa2090e2 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -195,6 +195,8 @@ enum ter_bitflags : int { TFLAG_GOES_UP, TFLAG_NO_FLOOR, TFLAG_SEEN_FROM_ABOVE, + TFLAG_RAMP_DOWN, + TFLAG_RAMP_UP, TFLAG_RAMP, TFLAG_HIDE_PLACE, TFLAG_BLOCK_WIND, @@ -202,6 +204,7 @@ enum ter_bitflags : int { TFLAG_RAIL, TFLAG_THIN_OBSTACLE, TFLAG_SMALL_PASSAGE, + TFLAG_Z_TRANSPARENT, NUM_TERFLAGS }; diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 234b022c7ddf5..1ce7a6db69db8 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1559,8 +1559,7 @@ class jmapgen_computer : public jmapgen_piece } void apply( mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y ) const override { const point r( x.get(), y.get() ); - dat.m.ter_set( r, t_console ); - dat.m.furn_set( r, f_null ); + dat.m.furn_set( r, furn_str_id( "f_console" ) ); computer *cpu = dat.m.add_computer( tripoint( r, dat.m.get_abs_sub().z ), name.translated(), security ); for( const auto &opt : options ) { @@ -4373,7 +4372,7 @@ void map::draw_lab( mapgendata &dat ) line( this, t_reinforced_glass, point( SEEX - 2, SEEY - 1 ), point( SEEX - 2, SEEY ) ); line( this, t_reinforced_glass, point( SEEX + 1, SEEY - 1 ), point( SEEX + 1, SEEY ) ); spawn_item( point( SEEX - 4, SEEY - 3 ), "id_science" ); - ter_set( point( SEEX - 3, SEEY - 3 ), t_console ); + furn_set( point( SEEX - 3, SEEY - 3 ), furn_str_id( "f_console" ) ); tmpcomp = add_computer( tripoint( SEEX - 3, SEEY - 3, abs_sub.z ), _( "Bionic access" ), 3 ); tmpcomp->add_option( _( "Manifest" ), COMPACT_LIST_BIONICS, 0 ); @@ -4682,8 +4681,10 @@ void map::draw_temple( mapgendata &dat ) square( this, t_rock_floor, point( SEEX - 1, 1 ), point( SEEX + 2, 4 ) ); square( this, t_rock_floor, point( SEEX, 5 ), point( SEEX + 1, SOUTH_EDGE ) ); line( this, t_stairs_up, point( SEEX, SOUTH_EDGE ), point( SEEX + 1, SOUTH_EDGE ) ); - spawn_artifact( tripoint( rng( SEEX, SEEX + 1 ), rng( 2, 3 ), abs_sub.z ) ); - spawn_artifact( tripoint( rng( SEEX, SEEX + 1 ), rng( 2, 3 ), abs_sub.z ) ); + spawn_artifact( tripoint( rng( SEEX, SEEX + 1 ), rng( 2, 3 ), abs_sub.z ), + relic_procgen_id( "cult" ) ); + spawn_artifact( tripoint( rng( SEEX, SEEX + 1 ), rng( 2, 3 ), abs_sub.z ), + relic_procgen_id( "cult" ) ); return; } @@ -5088,7 +5089,8 @@ void map::draw_mine( mapgendata &dat ) calendar::start_of_cataclysm ); } place_spawns( GROUP_DOG_THING, 1, point( SEEX, SEEX ), point( SEEX + 1, SEEX + 1 ), 1, true, true ); - spawn_artifact( tripoint( rng( SEEX, SEEX + 1 ), rng( SEEY, SEEY + 1 ), abs_sub.z ) ); + spawn_artifact( tripoint( rng( SEEX, SEEX + 1 ), rng( SEEY, SEEY + 1 ), abs_sub.z ), + relic_procgen_id( "netherum_tunnels" ) ); } break; @@ -5133,7 +5135,7 @@ void map::draw_mine( mapgendata &dat ) break; } - ter_set( point( SEEX, SEEY ), t_console ); + furn_set( point( SEEX, SEEY ), furn_str_id( "f_console" ) ); tmpcomp = add_computer( tripoint( SEEX, SEEY, abs_sub.z ), _( "NEPowerOS" ), 0 ); tmpcomp->add_option( _( "Read Logs" ), COMPACT_AMIGARA_LOG, 0 ); tmpcomp->add_option( _( "Initiate Tremors" ), COMPACT_AMIGARA_START, 4 ); @@ -5673,11 +5675,8 @@ void map::place_vending( const point &p, const std::string &type, bool reinforce } } -character_id map::place_npc( const point &p, const string_id &type, bool force ) +character_id map::place_npc( const point &p, const string_id &type ) { - if( !force && !get_option( "STATIC_NPC" ) ) { - return character_id(); //Do not generate an npc. - } shared_ptr_fast temp = make_shared_fast(); temp->normalize(); temp->load_npc_template( type ); @@ -5988,7 +5987,7 @@ std::unique_ptr map::add_vehicle_to_map( computer *map::add_computer( const tripoint &p, const std::string &name, int security ) { // TODO: Turn this off? - ter_set( p, t_console ); + furn_set( p, furn_str_id( "f_console" ) ); point l; submap *const place_on_submap = get_submap_at( p, l ); place_on_submap->set_computer( l, computer( name, security ) ); @@ -6047,7 +6046,7 @@ void map::rotate( int turns, const bool setpos_safe ) // to be between 0-11,0-11 and teleports NPCs when used inside of update_mapgen // calls const tripoint new_global_sq = sq - local_sq + new_pos; - np.setpos( g->m.getlocal( new_global_sq ) ); + np.setpos( get_map().getlocal( new_global_sq ) ); } else { // OK, this is ugly: we remove the NPC from the whole map // Then we place it back from scratch @@ -6372,7 +6371,7 @@ void science_room( map *m, const point &p1, const point &p2, int z, int rotate ) m->place_items( "bionics_common", 70, point( biox, bioy ), point( biox, bioy ), false, calendar::start_of_cataclysm ); - m->ter_set( point( biox, bioy + 2 ), t_console ); + m->furn_set( point( biox, bioy + 2 ), furn_str_id( "f_console" ) ); computer *tmpcomp = m->add_computer( tripoint( biox, bioy + 2, z ), _( "Bionic access" ), 2 ); tmpcomp->add_option( _( "Manifest" ), COMPACT_LIST_BIONICS, 0 ); tmpcomp->add_option( _( "Open Chambers" ), COMPACT_RELEASE_BIONICS, 3 ); @@ -6391,7 +6390,7 @@ void science_room( map *m, const point &p1, const point &p2, int z, int rotate ) m->place_items( "bionics_common", 70, point( biox, bioy ), point( biox, bioy ), false, calendar::start_of_cataclysm ); - m->ter_set( point( biox, bioy - 2 ), t_console ); + m->furn_set( point( biox, bioy - 2 ), furn_str_id( "f_console" ) ); computer *tmpcomp2 = m->add_computer( tripoint( biox, bioy - 2, z ), _( "Bionic access" ), 2 ); tmpcomp2->add_option( _( "Manifest" ), COMPACT_LIST_BIONICS, 0 ); tmpcomp2->add_option( _( "Open Chambers" ), COMPACT_RELEASE_BIONICS, 3 ); @@ -6411,7 +6410,7 @@ void science_room( map *m, const point &p1, const point &p2, int z, int rotate ) m->place_items( "bionics_common", 70, point( biox, bioy ), point( biox, bioy ), false, calendar::start_of_cataclysm ); - m->ter_set( point( biox + 2, bioy ), t_console ); + m->furn_set( point( biox + 2, bioy ), furn_str_id( "f_console" ) ); computer *tmpcomp = m->add_computer( tripoint( biox + 2, bioy, z ), _( "Bionic access" ), 2 ); tmpcomp->add_option( _( "Manifest" ), COMPACT_LIST_BIONICS, 0 ); tmpcomp->add_option( _( "Open Chambers" ), COMPACT_RELEASE_BIONICS, 3 ); @@ -6429,7 +6428,7 @@ void science_room( map *m, const point &p1, const point &p2, int z, int rotate ) mapf::furn_bind( "c", f_counter ) ); m->place_items( "bionics_common", 70, point( biox, bioy ), point( biox, bioy ), false, 0 ); - m->ter_set( point( biox - 2, bioy ), t_console ); + m->furn_set( point( biox - 2, bioy ), furn_str_id( "f_console" ) ); computer *tmpcomp2 = m->add_computer( tripoint( biox - 2, bioy, z ), _( "Bionic access" ), 2 ); tmpcomp2->add_option( _( "Manifest" ), COMPACT_LIST_BIONICS, 0 ); tmpcomp2->add_option( _( "Open Chambers" ), COMPACT_RELEASE_BIONICS, 3 ); @@ -6577,7 +6576,7 @@ void build_mine_room( room_type type, const point &p1, const point &p2, mapgenda // Main build switch! switch( type ) { case room_mine_shaft: { - m->ter_set( p1 + point_south_east, t_console ); + m->furn_set( p1 + point_south_east, furn_str_id( "f_console" ) ); line( m, t_wall, point( p2.x - 2, p1.y + 2 ), point( p2.x - 1, p1.y + 2 ) ); m->ter_set( point( p2.x - 2, p1.y + 1 ), t_elevator ); m->ter_set( point( p2.x - 1, p1.y + 1 ), t_elevator_control_off ); diff --git a/src/mapgen_functions.cpp b/src/mapgen_functions.cpp index 9077f9ba3a7b3..db75db95b46b7 100644 --- a/src/mapgen_functions.cpp +++ b/src/mapgen_functions.cpp @@ -103,7 +103,6 @@ building_gen_pointer get_mapgen_cfunction( const std::string &ident ) { "road_tee", &mapgen_road }, { "road_four_way", &mapgen_road }, { "field", &mapgen_field }, - { "bridge", &mapgen_bridge }, { "highway", &mapgen_highway }, { "railroad_straight", &mapgen_railroad }, { "railroad_curved", &mapgen_railroad }, @@ -1356,45 +1355,6 @@ void mapgen_sewer_four_way( mapgendata &dat ) m->place_items( "sewer", 28, point_zero, point( SEEX * 2 - 1, SEEY * 2 - 1 ), true, dat.when() ); } -/////////////////// -void mapgen_bridge( mapgendata &dat ) -{ - map *const m = &dat.m; - const auto is_river = [&]( const om_direction::type dir ) { - return dat.t_nesw[static_cast( om_direction::add( dir, - dat.terrain_type()->get_dir() ) )]->is_river(); - }; - - const bool river_west = is_river( om_direction::type::west ); - const bool river_east = is_river( om_direction::type::east ); - - for( int i = 0; i < SEEX * 2; i++ ) { - for( int j = 0; j < SEEY * 2; j++ ) { - if( i < 2 ) { - m->ter_set( point( i, j ), river_west ? t_water_moving_dp : grass_or_dirt() ); - } else if( i >= SEEX * 2 - 2 ) { - m->ter_set( point( i, j ), river_east ? t_water_moving_dp : grass_or_dirt() ); - } else if( i == 2 || i == SEEX * 2 - 3 ) { - m->ter_set( point( i, j ), t_guardrail_bg_dp ); - } else if( i == 3 || i == SEEX * 2 - 4 ) { - m->ter_set( point( i, j ), t_sidewalk_bg_dp ); - } else { - if( ( i == SEEX - 1 || i == SEEX ) && j % 4 != 0 ) { - m->ter_set( point( i, j ), t_pavement_y_bg_dp ); - } else { - m->ter_set( point( i, j ), t_pavement_bg_dp ); - } - } - } - } - - // spawn regular road out of fuel vehicles - VehicleSpawn::apply( vspawn_id( "default_bridge" ), *m, "bridge" ); - - m->rotate( static_cast( dat.terrain_type()->get_dir() ) ); - m->place_items( "road", 5, point_zero, point( SEEX * 2 - 1, SEEX * 2 - 1 ), false, dat.when() ); -} - void mapgen_highway( mapgendata &dat ) { map *const m = &dat.m; diff --git a/src/mapgen_functions.h b/src/mapgen_functions.h index 004d7919bdb4a..cc719b05c4f1f 100644 --- a/src/mapgen_functions.h +++ b/src/mapgen_functions.h @@ -44,7 +44,7 @@ void mapgen_hive( mapgendata &dat ); void mapgen_spider_pit( mapgendata &dat ); void mapgen_river_center( mapgendata &dat ); void mapgen_road( mapgendata &dat ); -void mapgen_bridge( mapgendata &dat ); +//void mapgen_bridge( mapgendata &dat ); void mapgen_railroad( mapgendata &dat ); void mapgen_railroad_bridge( mapgendata &dat ); void mapgen_highway( mapgendata &dat ); diff --git a/src/mapsharing.cpp b/src/mapsharing.cpp index da5d18872e296..f8715c8bfa96e 100644 --- a/src/mapsharing.cpp +++ b/src/mapsharing.cpp @@ -134,13 +134,15 @@ void ofstream_wrapper::close() return; } - if( file_stream.fail() ) { + file_stream.flush(); + bool failed = file_stream.fail(); + file_stream.close(); + if( failed ) { // Remove the incomplete or otherwise faulty file (if possible). // Failures from it are ignored as we can't really do anything about them. remove_file( temp_path ); throw std::runtime_error( "writing to file failed" ); } - file_stream.close(); if( !rename_file( temp_path, path ) ) { // Leave the temp path, so the user can move it if possible. throw std::runtime_error( "moving temporary file \"" + temp_path + "\" failed" ); diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index c9c677ae2b864..bb6cf66b59c6c 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -167,7 +167,7 @@ void mon_spellcasting_actor::load_internal( const JsonObject &obj, const std::st spell_data = intermediate.get_spell(); spell_data.set_message( monster_message ); avatar fake_player; - move_cost = spell_data.casting_time( fake_player ); + move_cost = spell_data.casting_time( fake_player, true ); } bool mon_spellcasting_actor::call( monster &mon ) const @@ -287,7 +287,7 @@ bool melee_actor::call( monster &z ) const int hitspread = target->deal_melee_attack( &z, dice( acc, 10 ) ); if( hitspread < 0 ) { - auto msg_type = target == &g->u ? m_warning : m_info; + auto msg_type = target->is_avatar() ? m_warning : m_info; sfx::play_variant_sound( "mon_bite", "bite_miss", sfx::get_heard_volume( z.pos() ), sfx::get_heard_angle( z.pos() ) ); target->add_msg_player_or_npc( msg_type, miss_msg_u, miss_msg_npc, z.name() ); diff --git a/src/melee.cpp b/src/melee.cpp index 63ac92469fb80..feb848e922141 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -265,7 +265,7 @@ bool Character::handle_melee_wear( item &shield, float wear_multiplier ) if( comp.typeId() == big_comp && !is_armed() ) { wield( comp ); } else { - g->m.add_item_or_charges( pos(), comp ); + get_map().add_item_or_charges( pos(), comp ); } } } else { @@ -316,7 +316,7 @@ float Character::hit_roll() const hit *= 0.75f; } - hit *= std::max( 0.25f, 1.0f - encumb( bp_torso ) / 100.0f ); + hit *= std::max( 0.25f, 1.0f - encumb( bodypart_id( "torso" ) ) / 100.0f ); return melee::melee_hit_range( hit ); } @@ -339,7 +339,7 @@ std::string Character::get_miss_reason() // in one turn add_miss_reason( _( "Your torso encumbrance throws you off-balance." ), - roll_remainder( encumb( bp_torso ) / 10.0 ) ); + roll_remainder( encumb( bodypart_id( "torso" ) ) / 10.0 ) ); const int farsightedness = 2 * ( has_trait( trait_HYPEROPIC ) && !worn_with_flag( "FIX_FARSIGHT" ) && !has_effect( effect_contacts ) ); @@ -454,6 +454,7 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id &f int move_cost = attack_speed( *cur_weapon ); + Character &player_character = get_player_character(); if( hit_spread < 0 ) { int stumble_pen = stumble( *this, *cur_weapon ); sfx::generate_melee_sound( pos(), t.pos(), false, false ); @@ -476,7 +477,7 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id &f } else { add_msg( _( "You miss." ) ); } - } else if( g->u.sees( *this ) ) { + } else if( player_character.sees( *this ) ) { if( stumble_pen >= 60 ) { add_msg( _( "%s misses and stumbles with the momentum." ), name ); } else if( stumble_pen >= 10 ) { @@ -502,7 +503,7 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id &f } else { melee::melee_stats.hit_count += 1; // Remember if we see the monster at start - it may change - const bool seen = g->u.sees( t ); + const bool seen = player_character.sees( t ); // Start of attacks. const bool critical_hit = scored_crit( t.dodge_roll(), *cur_weapon ); if( critical_hit ) { @@ -542,6 +543,16 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id &f perform_technique( technique, t, d, move_cost ); } + //player has a very small chance, based on their intelligence, to learn a style whilst using the CQB bionic + if( has_active_bionic( bio_cqb ) && !martial_arts_data.knows_selected_style() ) { + /** @EFFECT_INT slightly increases chance to learn techniques when using CQB bionic */ + // Enhanced Memory Banks bionic doubles chance to learn martial art + const int bionic_boost = has_active_bionic( bionic_id( bio_memory ) ) ? 2 : 1; + if( one_in( ( 1400 - ( get_int() * 50 ) ) / bionic_boost ) ) { + martial_arts_data.learn_current_style_CQB( is_player() ); + } + } + // Proceed with melee attack. if( !t.is_dead_state() ) { // Handles speed penalties to monster & us, etc @@ -594,7 +605,7 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id &f } // Treat monster as seen if we see it before or after the attack - if( seen || g->u.sees( t ) ) { + if( seen || player_character.sees( t ) ) { std::string message = melee_message( technique, *this, dealt_dam ); player_hit_message( this, message, t, dam, critical_hit ); } else { @@ -664,6 +675,7 @@ void player::reach_attack( const tripoint &p ) int move_cost = attack_speed( weapon ); int skill = std::min( 10, get_skill_level( skill_stabbing ) ); int t = 0; + map &here = get_map(); std::vector path = line_to( pos(), p, t, 0 ); path.pop_back(); // Last point is our critter for( const tripoint &path_point : path ) { @@ -677,13 +689,13 @@ void player::reach_attack( const tripoint &p ) critter = inter; break; /** @EFFECT_STABBING increases ability to reach attack through fences */ - } else if( g->m.impassable( path_point ) && + } else if( here.impassable( path_point ) && // Fences etc. Spears can stab through those !( weapon.has_flag( "SPEAR" ) && - g->m.has_flag( "THIN_OBSTACLE", path_point ) && + here.has_flag( "THIN_OBSTACLE", path_point ) && x_in_y( skill, 10 ) ) ) { /** @EFFECT_STR increases bash effects when reach attacking past something */ - g->m.bash( path_point, str_cur + weapon.damage_melee( DT_BASH ) ); + here.bash( path_point, str_cur + weapon.damage_melee( DT_BASH ) ); handle_melee_wear( weapon ); mod_moves( -move_cost ); return; @@ -830,7 +842,7 @@ float player::get_dodge() const if( has_effect( effect_grabbed ) ) { int zed_number = 0; - for( auto &dest : g->m.points_in_radius( pos(), 1, 0 ) ) { + for( auto &dest : get_map().points_in_radius( pos(), 1, 0 ) ) { const monster *const mon = g->critter_at( dest ); if( mon && mon->has_effect( effect_grabbing ) ) { zed_number++; @@ -1170,7 +1182,7 @@ matec_id Character::pick_technique( Creature &t, const item &weap, bool downed = t.has_effect( effect_downed ); bool stunned = t.has_effect( effect_stunned ); - bool wall_adjacent = g->m.is_wall_adjacent( pos() ); + bool wall_adjacent = get_map().is_wall_adjacent( pos() ); // first add non-aoe tecs for( const matec_id &tec_id : all ) { @@ -1353,7 +1365,7 @@ bool Character::valid_aoe_technique( Creature &t, const ma_technique &technique, } if( targets.empty() && technique.aoe == "spin" ) { - for( const tripoint &tmp : g->m.points_in_radius( pos(), 1 ) ) { + for( const tripoint &tmp : get_map().points_in_radius( pos(), 1 ) ) { if( tmp == t.pos() ) { continue; } @@ -1476,6 +1488,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d t.add_effect( effect_stunned, rng( 1_turns, time_duration::from_turns( technique.stun_dur ) ) ); } + map &here = get_map(); if( technique.knockback_dist ) { const tripoint prev_pos = t.pos(); // track target startpoint for knockback_follow const int kb_offset_x = rng( -technique.knockback_spread, technique.knockback_spread ); @@ -1486,10 +1499,10 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d } // This technique makes the player follow into the tile the target was knocked from if( technique.knockback_follow ) { - const optional_vpart_position vp0 = g->m.veh_at( pos() ); + const optional_vpart_position vp0 = here.veh_at( pos() ); vehicle *const veh0 = veh_pointer_or_null( vp0 ); - bool to_swimmable = g->m.has_flag( "SWIMMABLE", prev_pos ); - bool to_deepwater = g->m.has_flag( TFLAG_DEEP_WATER, prev_pos ); + bool to_swimmable = here.has_flag( "SWIMMABLE", prev_pos ); + bool to_deepwater = here.has_flag( TFLAG_DEEP_WATER, prev_pos ); // Check if it's possible to move to the new tile bool move_issue = @@ -1497,7 +1510,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d ( to_swimmable && to_deepwater ) || // Dive into deep water is_mounted() || ( veh0 != nullptr && std::abs( veh0->velocity ) > 100 ) || // Diving from moving vehicle - ( veh0 != nullptr && veh0->player_in_control( g->u ) ) || // Player is driving + ( veh0 != nullptr && veh0->player_in_control( get_avatar() ) ) || // Player is driving has_effect( effect_amigara ); if( !move_issue ) { @@ -1524,7 +1537,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d } if( technique.disarms && p != nullptr && p->is_armed() ) { - g->m.add_item_or_charges( p->pos(), p->remove_weapon() ); + here.add_item_or_charges( p->pos(), p->remove_weapon() ); if( p->is_player() ) { add_msg_if_npc( _( " disarms you!" ) ); } else { @@ -1564,16 +1577,6 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d moves = temp_moves; set_stamina( temp_stamina ); } - - //player has a very small chance, based on their intelligence, to learn a style whilst using the CQB bionic - if( has_active_bionic( bio_cqb ) && !martial_arts_data.knows_selected_style() ) { - /** @EFFECT_INT slightly increases chance to learn techniques when using CQB bionic */ - // Enhanced Memory Banks bionic doubles chance to learn martial art - const int bionic_boost = has_active_bionic( bionic_id( bio_memory ) ) ? 2 : 1; - if( one_in( ( 1400 - ( get_int() * 50 ) ) / bionic_boost ) ) { - martial_arts_data.learn_current_style_CQB( is_player() ); - } - } } static int blocking_ability( const item &shield ) @@ -2193,6 +2196,7 @@ void player_hit_message( Character *attacker, const std::string &message, std::string sSCTmod; game_message_type gmtSCTcolor = m_good; + Character &player_character = get_player_character(); if( dam <= 0 ) { if( attacker->is_npc() ) { //~ NPC hits something but does no damage @@ -2202,9 +2206,9 @@ void player_hit_message( Character *attacker, const std::string &message, msg = string_format( _( "%s but do no damage." ), message ); } msgtype = m_neutral; - } else if( - crit ) { //Player won't see exact numbers of damage dealt by NPC unless player has DEBUG_NIGHTVISION trait - if( attacker->is_npc() && !g->u.has_trait( trait_DEBUG_NIGHTVISION ) ) { + } else if( crit ) { + //Player won't see exact numbers of damage dealt by NPC unless player has DEBUG_NIGHTVISION trait + if( attacker->is_npc() && !player_character.has_trait( trait_DEBUG_NIGHTVISION ) ) { //~ NPC hits something (critical) msg = string_format( _( "%s. Critical!" ), message ); } else { @@ -2214,7 +2218,7 @@ void player_hit_message( Character *attacker, const std::string &message, sSCTmod = _( "Critical!" ); gmtSCTcolor = m_critical; } else { - if( attacker->is_npc() && !g->u.has_trait( trait_DEBUG_NIGHTVISION ) ) { + if( attacker->is_npc() && !player_character.has_trait( trait_DEBUG_NIGHTVISION ) ) { //~ NPC hits something msg = string_format( _( "%s." ), message ); } else { @@ -2256,8 +2260,8 @@ int Character::attack_speed( const item &weap ) const const int skill_cost = static_cast( ( base_move_cost * ( 15 - melee_skill ) / 15 ) ); /** @EFFECT_DEX increases attack speed */ const int dexbonus = dex_cur / 2; - const int encumbrance_penalty = encumb( bp_torso ) + - ( encumb( bp_hand_l ) + encumb( bp_hand_r ) ) / 2; + const int encumbrance_penalty = encumb( bodypart_id( "torso" ) ) + + ( encumb( bodypart_id( "hand_l" ) ) + encumb( bodypart_id( "hand_r" ) ) ) / 2; const int ma_move_cost = mabuff_attack_cost_penalty(); const float stamina_ratio = static_cast( get_stamina() ) / static_cast ( get_stamina_max() ); @@ -2372,6 +2376,7 @@ void player::disarm( npc &target ) return; } + map &here = get_map(); // hitspread >= 0, which means we are going to disarm by grabbing target by their weapon if( !is_armed() ) { /** @EFFECT_UNARMED increases chance to disarm, bonus when nothing wielded */ @@ -2389,7 +2394,7 @@ void player::disarm( npc &target ) add_msg( _( "You grab at %s and pull with all your force, but it drops nearby!" ), it.tname() ); const tripoint tp = target.pos() + tripoint( rng( -1, 1 ), rng( -1, 1 ), 0 ); - g->m.add_item_or_charges( tp, target.i_rem( &it ) ); + here.add_item_or_charges( tp, target.i_rem( &it ) ); mod_moves( -100 ); } else { add_msg( _( "You grab at %s and pull with all your force, but in vain!" ), it.tname() ); @@ -2406,7 +2411,7 @@ void player::disarm( npc &target ) add_msg( _( "You smash %s with all your might forcing their %s to drop down nearby!" ), target.name, it.tname() ); const tripoint tp = target.pos() + tripoint( rng( -1, 1 ), rng( -1, 1 ), 0 ); - g->m.add_item_or_charges( tp, target.i_rem( &it ) ); + here.add_item_or_charges( tp, target.i_rem( &it ) ); } else { add_msg( _( "You smash %s with all your might but %s remains in their hands!" ), target.name, it.tname() ); diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index 0c87b416bcb7b..6442b7ca7e568 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -87,6 +87,50 @@ static const trait_id trait_CANNIBAL( "CANNIBAL" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); +memorial_log_entry::memorial_log_entry( const std::string &preformatted_msg ) : + preformatted_( preformatted_msg ) +{} + +memorial_log_entry::memorial_log_entry( time_point time, const oter_type_str_id &oter_id, + const std::string &oter_name, const std::string &msg ) : + time_( time ), oter_id_( oter_id ), oter_name_( oter_name ), message_( msg ) +{} + +std::string memorial_log_entry::to_string() const +{ + if( preformatted_ ) { + return *preformatted_; + } else { + return "| " + ::to_string( time_ ) + " | " + oter_name_ + " | " + message_; + } +} + +void memorial_log_entry::deserialize( JsonIn &jsin ) +{ + JsonObject jo = jsin.get_object(); + if( jo.read( "preformatted", preformatted_ ) ) { + return; + } + jo.read( "time", time_, true ); + jo.read( "oter_id", oter_id_, true ); + jo.read( "oter_name", oter_name_, true ); + jo.read( "message", message_, true ); +} + +void memorial_log_entry::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + if( preformatted_ ) { + jsout.member( "preformatted", preformatted_ ); + } else { + jsout.member( "time", time_ ); + jsout.member( "oter_id", oter_id_ ); + jsout.member( "oter_name", oter_name_ ); + jsout.member( "message", message_ ); + } + jsout.end_object(); +} + void memorial_logger::clear() { log.clear(); @@ -100,39 +144,55 @@ void memorial_logger::clear() void memorial_logger::add( const std::string &male_msg, const std::string &female_msg ) { - const std::string &msg = g->u.male ? male_msg : female_msg; + Character &player_character = get_player_character(); + const std::string &msg = player_character.male ? male_msg : female_msg; if( msg.empty() ) { return; } - const oter_id &cur_ter = overmap_buffer.ter( g->u.global_omt_location() ); - const std::string &location = cur_ter->get_name(); + const oter_id &cur_ter = overmap_buffer.ter( player_character.global_omt_location() ); + const oter_type_str_id cur_oter_type = cur_ter->get_type_id(); + const std::string &oter_name = cur_ter->get_name(); - std::string log_message = "| " + to_string( calendar::turn ) + " | " + location + " | " + msg; - - log.push_back( log_message ); + log.push_back( { calendar::turn, cur_oter_type, oter_name, msg } ); } /** - * Loads the data in a memorial file from the given ifstream. All the memorial - * entry lines begin with a pipe (|). - * @param fin The ifstream to read the memorial entries from. + * Loads the data in a memorial file from the given ifstream. + * In legacy format all the memorial entry lines begin with a pipe (|). + * (This legacy format stopped being used before 0.F release.) + * In new format the entries are stored as json. + * @param fin The stream to read the memorial entries from. */ void memorial_logger::load( std::istream &fin ) { - std::string entry; log.clear(); - while( fin.peek() == '|' ) { - getline( fin, entry ); - // strip all \r from end of string - while( *entry.rbegin() == '\r' ) { - entry.pop_back(); + if( fin.peek() == '|' ) { + // Legacy plain text format + while( fin.peek() == '|' ) { + std::string entry; + getline( fin, entry ); + // strip all \r from end of string + while( *entry.rbegin() == '\r' ) { + entry.pop_back(); + } + log.emplace_back( entry ); + } + } else { + JsonIn jsin( fin ); + if( !jsin.read( log ) ) { + debugmsg( "Error reading JSON memorial log" ); } - log.push_back( entry ); } } +void memorial_logger::save( std::ostream &os ) const +{ + JsonOut jsout( os ); + jsout.write( log ); +} + /** * Concatenates all of the memorial log entries, delimiting them with newlines, * and returns the resulting string. Used for saving and for writing out to the @@ -144,16 +204,17 @@ std::string memorial_logger::dump() const std::string output; for( auto &elem : log ) { - output += elem; + output += elem.to_string(); output += eol; } return output; } -void memorial_logger::write( std::ostream &file, const std::string &epitaph ) const +void memorial_logger::write_text_memorial( std::ostream &file, + const std::string &epitaph ) const { - avatar &u = g->u; + avatar &u = get_avatar(); static const char *eol = cata_files::eol(); //Size of indents in the memorial file @@ -362,12 +423,33 @@ void memorial_logger::write( std::ostream &file, const std::string &epitaph ) co file << dump(); } +void memorial_logger::write_json_memorial( std::ostream &memorial_file ) const +{ + JsonOut jsout( memorial_file, true, 2 ); + jsout.start_object(); + jsout.member( "memorial_version", 0 ); + jsout.member( "log", log ); + jsout.member( "achievements", g->achievements() ); + jsout.member( "stats", g->stats() ); + + std::map, cata_variant> scores; + for( const score *scr : g->stats().valid_scores() ) { + scores.emplace( scr->id, scr->value( g->stats() ) ); + } + jsout.member( "scores", scores ); + + jsout.end_object(); +} + void memorial_logger::notify( const cata::event &e ) { + Character &player_character = get_player_character(); + character_id avatar_id = player_character.getID(); + std::string &avatar_name = player_character.name; switch( e.type() ) { case event_type::activates_artifact: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string item_name = e.get( "item_name" ); //~ %s is artifact name add( pgettext( "memorial_male", "Activated the %s." ), @@ -378,7 +460,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::activates_mininuke: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Activated a mininuke." ), pgettext( "memorial_female", "Activated a mininuke." ) ); } @@ -386,7 +468,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::administers_mutagen: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { mutagen_technique technique = e.get( "technique" ); switch( technique ) { case mutagen_technique::consumed_mutagen: @@ -427,7 +509,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::becomes_wanted: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Became wanted by the police!" ), pgettext( "memorial_female", "Became wanted by the police!" ) ); } @@ -435,7 +517,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::broken_bone: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { body_part part = e.get( "part" ); //~ %s is bodypart add( pgettext( "memorial_male", "Broke his %s." ), @@ -446,7 +528,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::broken_bone_mends: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { body_part part = e.get( "part" ); //~ %s is bodypart add( pgettext( "memorial_male", "Broken %s began to mend." ), @@ -457,7 +539,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::buries_corpse: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { const mtype &corpse_type = e.get( "corpse_type" ).obj(); std::string corpse_name = e.get( "corpse_name" ); if( corpse_name.empty() ) { @@ -482,7 +564,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_gains_effect: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { const effect_type &type = e.get( "effect" ).obj(); const std::string message = type.get_apply_memorial_log(); if( !message.empty() ) { @@ -494,11 +576,11 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_kills_character: { character_id ch = e.get( "killer" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string name = e.get( "victim_name" ); - bool cannibal = g->u.has_trait( trait_CANNIBAL ); - bool psycho = g->u.has_trait( trait_PSYCHOPATH ); - if( g->u.has_trait( trait_SAPIOVORE ) ) { + bool cannibal = player_character.has_trait( trait_CANNIBAL ); + bool psycho = player_character.has_trait( trait_PSYCHOPATH ); + if( player_character.has_trait( trait_SAPIOVORE ) ) { add( pgettext( "memorial_male", "Caught and killed an ape. Prey doesn't have a name." ), pgettext( "memorial_female", @@ -533,7 +615,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_kills_monster: { character_id ch = e.get( "killer" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { mtype_id victim_type = e.get( "victim_type" ); if( victim_type->difficulty >= 30 ) { add( pgettext( "memorial_male", "Killed a %s." ), @@ -545,7 +627,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_loses_effect: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { const effect_type &type = e.get( "effect" ).obj(); const std::string message = type.get_remove_memorial_log(); if( !message.empty() ) { @@ -557,7 +639,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_triggers_trap: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { trap_str_id trap = e.get( "trap" ); if( trap == tr_bubblewrap ) { add( pgettext( "memorial_male", "Stepped on bubble wrap." ), @@ -646,7 +728,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::consumes_marloss_item: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { const itype *it = item_controller->find_template( e.get( "itype" ) ); std::string itname = it->nname( 1 ); @@ -657,7 +739,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::crosses_marloss_threshold: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Opened the Marloss Gateway." ), pgettext( "memorial_female", "Opened the Marloss Gateway." ) ); } @@ -665,7 +747,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::crosses_mutation_threshold: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string category_id = e.get( "category" ); const mutation_category_trait &category = @@ -677,7 +759,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::crosses_mycus_threshold: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Became one with the Mycus." ), pgettext( "memorial_female", "Became one with the Mycus." ) ); } @@ -685,7 +767,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::dermatik_eggs_hatch: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Dermatik eggs hatched." ), pgettext( "memorial_female", "Dermatik eggs hatched." ) ); } @@ -693,7 +775,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::dermatik_eggs_injected: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Injected with dermatik eggs." ), pgettext( "memorial_female", "Injected with dermatik eggs." ) ); } @@ -706,7 +788,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::dies_from_asthma_attack: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Succumbed to an asthma attack." ), pgettext( "memorial_female", "Succumbed to an asthma attack." ) ); } @@ -714,7 +796,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::dies_from_drug_overdose: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { efftype_id effect = e.get( "effect" ); if( effect == effect_datura ) { add( pgettext( "memorial_male", "Died of datura overdose." ), @@ -735,9 +817,33 @@ void memorial_logger::notify( const cata::event &e ) } break; } + case event_type::dies_from_bleeding: { + character_id ch = e.get( "character" ); + if( ch == avatar_id ) { + add( pgettext( "memorial_male", "Bled to death." ), + pgettext( "memorial_female", "Bled to death." ) ); + } + break; + } + case event_type::dies_from_hypovolemia: { + character_id ch = e.get( "character" ); + if( ch == avatar_id ) { + add( pgettext( "memorial_male", "Died of hypovolemic shock." ), + pgettext( "memorial_female", "Died of hypovolemic shock." ) ); + } + break; + } + case event_type::dies_from_redcells_loss: { + character_id ch = e.get( "character" ); + if( ch == avatar_id ) { + add( pgettext( "memorial_male", "Died from loss of red blood cells." ), + pgettext( "memorial_female", "Died from loss of red blood cells." ) ); + } + break; + } case event_type::dies_of_infection: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Succumbed to the infection." ), pgettext( "memorial_female", "Succumbed to the infection." ) ); } @@ -745,7 +851,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::dies_of_starvation: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Died of starvation." ), pgettext( "memorial_female", "Died of starvation." ) ); } @@ -753,7 +859,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::dies_of_thirst: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Died of thirst." ), pgettext( "memorial_female", "Died of thirst." ) ); } @@ -776,7 +882,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::evolves_mutation: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { trait_id from = e.get( "from_trait" ); trait_id to = e.get( "to_trait" ); add( pgettext( "memorial_male", "'%s' mutation turned into '%s'" ), @@ -787,7 +893,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::exhumes_grave: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Exhumed a grave." ), pgettext( "memorial_female", "Exhumed a grave." ) ); } @@ -795,7 +901,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::fails_to_install_cbm: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string cbm_name = e.get( "bionic" )->name.translated(); add( pgettext( "memorial_male", "Failed install of bionic: %s." ), pgettext( "memorial_female", "Failed install of bionic: %s." ), @@ -805,7 +911,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::fails_to_remove_cbm: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string cbm_name = e.get( "bionic" )->name.translated(); add( pgettext( "memorial_male", "Failed to remove bionic: %s." ), pgettext( "memorial_female", "Failed to remove bionic: %s." ), @@ -815,7 +921,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::falls_asleep_from_exhaustion: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Succumbed to lack of sleep." ), pgettext( "memorial_female", "Succumbed to lack of sleep." ) ); } @@ -830,7 +936,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::gains_addiction: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add_type type = e.get( "add_type" ); const std::string &type_name = addiction_type_name( type ); //~ %s is addiction name @@ -842,7 +948,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::gains_mutation: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { trait_id trait = e.get( "trait" ); add( pgettext( "memorial_male", "Gained the mutation '%s'." ), pgettext( "memorial_female", "Gained the mutation '%s'." ), @@ -852,7 +958,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::gains_skill_level: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { int new_level = e.get( "new_level" ); if( new_level % 4 == 0 ) { skill_id skill = e.get( "skill" ); @@ -873,11 +979,11 @@ void memorial_logger::notify( const cata::event &e ) if( suicide ) { add( pgettext( "memorial_male", "%s committed suicide." ), pgettext( "memorial_female", "%s committed suicide." ), - g->u.name ); + avatar_name ); } else { add( pgettext( "memorial_male", "%s was killed." ), pgettext( "memorial_female", "%s was killed." ), - g->u.name ); + avatar_name ); } if( !last_words.empty() ) { add( pgettext( "memorial_male", "Last words: %s" ), @@ -890,12 +996,12 @@ void memorial_logger::notify( const cata::event &e ) add( //~ %s is player name pgettext( "memorial_male", "%s began their journey into the Cataclysm." ), pgettext( "memorial_female", "%s began their journey into the Cataclysm." ), - g->u.name ); + avatar_name ); break; } case event_type::installs_cbm: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string cbm_name = e.get( "bionic" )->name.translated(); add( pgettext( "memorial_male", "Installed bionic: %s." ), pgettext( "memorial_female", "Installed bionic: %s." ), @@ -905,7 +1011,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::installs_faulty_cbm: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string cbm_name = e.get( "bionic" )->name.translated(); add( pgettext( "memorial_male", "Installed bad bionic: %s." ), pgettext( "memorial_female", "Installed bad bionic: %s." ), @@ -915,7 +1021,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::learns_martial_art: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { matype_id mastyle = e.get( "martial_art" ); //~ %s is martial art add( pgettext( "memorial_male", "Learned %s." ), @@ -926,7 +1032,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::loses_addiction: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add_type type = e.get( "add_type" ); const std::string &type_name = addiction_type_name( type ); //~ %s is addiction name @@ -969,7 +1075,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_forgets_spell: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string spell_name = e.get( "spell" )->name.translated(); add( pgettext( "memorial_male", "Forgot the spell %s." ), pgettext( "memorial_female", "Forgot the spell %s." ), @@ -979,7 +1085,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::character_learns_spell: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string spell_name = e.get( "spell" )->name.translated(); add( pgettext( "memorial_male", "Learned the spell %s." ), pgettext( "memorial_female", "Learned the spell %s." ), @@ -989,7 +1095,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::player_levels_spell: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string spell_name = e.get( "spell" )->name.translated(); add( pgettext( "memorial_male", "Gained a spell level on %s." ), pgettext( "memorial_female", "Gained a spell level on %s." ), @@ -1004,7 +1110,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::removes_cbm: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string cbm_name = e.get( "bionic" )->name.translated(); add( pgettext( "memorial_male", "Removed bionic: %s." ), pgettext( "memorial_female", "Removed bionic: %s." ), @@ -1019,7 +1125,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::telefrags_creature: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string victim_name = e.get( "victim_name" ); add( pgettext( "memorial_male", "Telefragged a %s." ), pgettext( "memorial_female", "Telefragged a %s." ), @@ -1029,7 +1135,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::teleglow_teleports: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Spontaneous teleport." ), pgettext( "memorial_female", "Spontaneous teleport." ) ); } @@ -1037,7 +1143,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::teleports_into_wall: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { std::string obstacle_name = e.get( "obstacle_name" ); add( pgettext( "memorial_male", "Teleported into a %s." ), pgettext( "memorial_female", "Teleported into a %s." ), @@ -1052,7 +1158,7 @@ void memorial_logger::notify( const cata::event &e ) } case event_type::throws_up: { character_id ch = e.get( "character" ); - if( ch == g->u.getID() ) { + if( ch == avatar_id ) { add( pgettext( "memorial_male", "Threw up." ), pgettext( "memorial_female", "Threw up." ) ); } diff --git a/src/memorial_logger.h b/src/memorial_logger.h index 52fc2ee637114..c0657124f1c6e 100644 --- a/src/memorial_logger.h +++ b/src/memorial_logger.h @@ -14,6 +14,30 @@ namespace cata class event; } // namespace cata +class memorial_log_entry +{ + public: + memorial_log_entry() = default; + memorial_log_entry( const std::string &preformatted_msg ); + memorial_log_entry( time_point, const oter_type_str_id &, const std::string &oter_name, + const std::string &msg ); + + std::string to_string() const; + + void deserialize( JsonIn & ); + void serialize( JsonOut & ) const; + private: + time_point time_; + oter_type_str_id oter_id_; + std::string oter_name_; + std::string message_; + + // For legacy lines loaded from the text memorial file. For any given + // memorial_log_entry either the following value will be populated or + // the above four values (but not both). + cata::optional preformatted_; +}; + class memorial_logger : public event_subscriber { public: @@ -34,18 +58,21 @@ class memorial_logger : public event_subscriber } // Loads the memorial log from a file - void load( std::istream &fin ); + void load( std::istream & ); + void save( std::ostream & ) const; // Dumps all memorial events into a single newline-delimited string // (this is the content of the temporary file used to preserve the log // over saves, not the final memorial file). std::string dump() const; // Prints out the final memorial file - void write( std::ostream &memorial_file, const std::string &epitaph ) const; + void write_text_memorial( std::ostream &memorial_file, + const std::string &epitaph ) const; + void write_json_memorial( std::ostream &memorial_file ) const; void notify( const cata::event & ) override; private: - std::vector log; + std::vector log; }; #endif // CATA_SRC_MEMORIAL_LOGGER_H diff --git a/src/mission.cpp b/src/mission.cpp index 0fd633679f6d4..094def531af1c 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -448,8 +448,8 @@ bool mission::is_complete( const character_id &_npc_id ) const } mission_goal_condition_context cc; - cc.alpha = &u; - cc.beta = n; + cc.alpha = get_talker_for( g->u ); + cc.beta = get_talker_for( *n ); for( auto &mission : n->chatbin.missions_assigned ) { if( mission->get_assigned_player_id() == g->u.getID() ) { diff --git a/src/mission.h b/src/mission.h index d22069632527d..555ecf2d2b490 100644 --- a/src/mission.h +++ b/src/mission.h @@ -20,6 +20,7 @@ #include "overmap.h" #include "point.h" #include "string_id.h" +#include "talker.h" #include "translations.h" #include "type_id.h" @@ -31,7 +32,6 @@ class JsonOut; class avatar; class item; class mission; -class npc; class overmapbuffer; class player; template struct enum_traits; @@ -187,11 +187,14 @@ bool load_funcs( const JsonObject &jo, std::vector alpha; + std::unique_ptr beta; std::vector missions_assigned; mutable std::string reason; bool by_radio = false; + talker *actor( const bool is_beta ) const { + return ( is_beta ? beta : alpha ).get(); + } }; struct mission_type { diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index 0074e24485605..636d60e214aa9 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -695,14 +695,15 @@ npc_ptr talk_function::individual_mission( const tripoint &omt_pos, if( comp->has_effect( effect_riding ) ) { comp->npc_dismount(); } + Character &player_character = get_player_character(); //Ensure we have someone to give equipment to before we lose it for( auto i : equipment ) { comp->companion_mission_inv.add_item( *i ); //comp->i_add(*i); if( item::count_by_charges( i->typeId() ) ) { - g->u.use_charges( i->typeId(), i->charges ); + player_character.use_charges( i->typeId(), i->charges ); } else { - g->u.use_amount( i->typeId(), 1 ); + player_character.use_amount( i->typeId(), 1 ); } } if( comp->in_vehicle ) { @@ -740,8 +741,10 @@ void talk_function::caravan_depart( npc &p, const std::string &dest, const std:: //Could be expanded to actually path to the site, just returns the distance int talk_function::caravan_dist( const std::string &dest ) { - const tripoint site = overmap_buffer.find_closest( g->u.global_omt_location(), dest, 0, false ); - int distance = rl_dist( g->u.pos(), site ); + Character &player_character = get_player_character(); + const tripoint site = overmap_buffer.find_closest( player_character.global_omt_location(), dest, 0, + false ); + int distance = rl_dist( player_character.pos(), site ); return distance; } @@ -811,7 +814,7 @@ void talk_function::caravan_return( npc &p, const std::string &dest, const std:: } if( money != 0 ) { - g->u.cash += ( 100 * money ); + get_player_character().cash += ( 100 * money ); popup( _( "The caravan party has returned. Your share of the profits are $%d!" ), money ); } else { popup( _( "The caravan was a disaster and your companions never made it home…" ) ); @@ -912,14 +915,15 @@ npc_ptr talk_function::temp_npc( const string_id &type ) //The field is designed as more of a convenience than a profit opportunity. void talk_function::field_build_1( npc &p ) { - if( g->u.cash < 100000 ) { + Character &player_character = get_player_character(); + if( player_character.cash < 100000 ) { popup( _( "I'm sorry, you don't have enough money." ) ); return; } p.set_mutation( trait_NPC_CONSTRUCTION_LEV_1 ); - g->u.cash += -100000; - const tripoint site = overmap_buffer.find_closest( g->u.global_omt_location(), "ranch_camp_63", 20, - false ); + player_character.cash += -100000; + const tripoint site = overmap_buffer.find_closest( player_character.global_omt_location(), + "ranch_camp_63", 20, false ); tinymap bay; bay.load( tripoint( site.x * 2, site.y * 2, site.z ), false ); bay.draw_square_ter( t_dirt, point( 5, 4 ), point( 15, 14 ) ); @@ -936,13 +940,15 @@ void talk_function::field_build_1( npc &p ) //Really expensive, but that is so you can't tear down the fence and sell the wood for a profit! void talk_function::field_build_2( npc &p ) { - if( g->u.cash < 550000 ) { + Character &player_character = get_player_character(); + if( player_character.cash < 550000 ) { popup( _( "I'm sorry, you don't have enough money." ) ); return; } p.set_mutation( trait_NPC_CONSTRUCTION_LEV_2 ); - g->u.cash += -550000; - const tripoint site = overmap_buffer.find_closest( g->u.global_omt_location(), "ranch_camp_63", + player_character.cash += -550000; + const tripoint site = overmap_buffer.find_closest( player_character.global_omt_location(), + "ranch_camp_63", 20, false ); tinymap bay; bay.load( tripoint( site.x * 2, site.y * 2, site.z ), false ); @@ -960,11 +966,12 @@ void talk_function::field_build_2( npc &p ) void talk_function::field_plant( npc &p, const std::string &place ) { - if( !warm_enough_to_plant( g->u.pos() ) ) { + Character &player_character = get_player_character(); + if( !warm_enough_to_plant( player_character.pos() ) ) { popup( _( "It is too cold to plant anything now." ) ); return; } - std::vector seed_inv = g->u.items_with( []( const item & itm ) { + std::vector seed_inv = player_character.items_with( []( const item & itm ) { return itm.is_seed() && itm.typeId() != itype_marloss_seed && itm.typeId() != itype_fungal_seeds; } ); @@ -994,14 +1001,14 @@ void talk_function::field_plant( npc &p, const std::string &place ) const auto &seed_id = seed_types[seed_index]; if( item::count_by_charges( seed_id ) ) { - free_seeds = g->u.charges_of( seed_id ); + free_seeds = player_character.charges_of( seed_id ); } else { - free_seeds = g->u.amount_of( seed_id ); + free_seeds = player_character.amount_of( seed_id ); } //Now we need to find how many free plots we have to plant in... - const tripoint site = overmap_buffer.find_closest( g->u.global_omt_location(), place, 20, - false ); + const tripoint site = overmap_buffer.find_closest( player_character.global_omt_location(), place, + 20, false ); tinymap bay; bay.load( tripoint( site.x * 2, site.y * 2, site.z ), false ); for( const tripoint &plot : bay.points_on_zlevel() ) { @@ -1021,7 +1028,7 @@ void talk_function::field_plant( npc &p, const std::string &place ) } signed int a = limiting_number * 300; - if( a > g->u.cash ) { + if( a > player_character.cash ) { popup( _( "I'm sorry, you don't have enough money to plant those seeds…" ) ); return; } @@ -1035,9 +1042,9 @@ void talk_function::field_plant( npc &p, const std::string &place ) if( bay.ter( plot ) == t_dirtmound && limiting_number > 0 ) { std::list used_seed; if( item::count_by_charges( seed_id ) ) { - used_seed = g->u.use_charges( seed_id, 1 ); + used_seed = player_character.use_charges( seed_id, 1 ); } else { - used_seed = g->u.use_amount( seed_id, 1 ); + used_seed = player_character.use_amount( seed_id, 1 ); } used_seed.front().set_age( 0_turns ); bay.add_item_or_charges( plot, used_seed.front() ); @@ -1053,9 +1060,10 @@ void talk_function::field_plant( npc &p, const std::string &place ) void talk_function::field_harvest( npc &p, const std::string &place ) { + Character &player_character = get_player_character(); //First we need a list of plants that can be harvested... - const tripoint site = overmap_buffer.find_closest( g->u.global_omt_location(), place, 20, - false ); + const tripoint site = overmap_buffer.find_closest( player_character.global_omt_location(), place, + 20, false ); tinymap bay; item tmp; std::vector seed_types; @@ -1142,7 +1150,7 @@ void talk_function::field_harvest( npc &p, const std::string &place ) bool liquidate = false; signed int a = number_plots * 2; - if( a > g->u.cash ) { + if( a > player_character.cash ) { liquidate = true; popup( _( "You don't have enough to pay the workers to harvest the crop so you are forced " "to sell…" ) ); @@ -1154,14 +1162,14 @@ void talk_function::field_harvest( npc &p, const std::string &place ) //Add fruit if( liquidate ) { add_msg( _( "The %s are sold for $%d…" ), plant_names[plant_index], money ); - g->u.cash += ( number_plants * tmp.price( true ) - number_plots * 2 ) / 100; + player_character.cash += ( number_plants * tmp.price( true ) - number_plots * 2 ) / 100; } else { if( tmp.count_by_charges() ) { tmp.charges = 1; } for( int i = 0; i < number_plants; ++i ) { //Should be dropped at your feet once greedy companions can be controlled - g->u.i_add( tmp ); + player_character.i_add( tmp ); } add_msg( _( "You receive %d %s…" ), number_plants, plant_names[plant_index] ); } @@ -1172,7 +1180,7 @@ void talk_function::field_harvest( npc &p, const std::string &place ) tmp.charges = 1; } for( int i = 0; i < number_seeds; ++i ) { - g->u.i_add( tmp ); + player_character.i_add( tmp ); } add_msg( _( "You receive %d %s…" ), number_seeds, tmp.type_name( 3 ) ); } @@ -1225,8 +1233,9 @@ bool talk_function::scavenging_patrol_return( npc &p ) } } + Character &player_character = get_player_character(); int money = rng( 25, 450 ); - g->u.cash += money * 100; + player_character.cash += money * 100; companion_skill_trainer( *comp, "combat", experience * 10_minutes, 10 ); popup( _( "%s returns from patrol having earned $%d and a fair bit of experience…" ), @@ -1234,7 +1243,7 @@ bool talk_function::scavenging_patrol_return( npc &p ) if( one_in( 10 ) ) { popup( _( "%s was impressed with %s's performance and gave you a small bonus ( $100 )" ), p.name, comp->name ); - g->u.cash += 10000; + player_character.cash += 10000; } if( one_in( 10 ) && !p.has_trait( trait_NPC_MISSION_LEV_1 ) ) { p.set_mutation( trait_NPC_MISSION_LEV_1 ); @@ -1273,8 +1282,9 @@ bool talk_function::scavenging_raid_return( npc &p ) } } } + Character &player_character = get_player_character(); //The loot value needs to be added to the faction - what the player is payed - tripoint loot_location = g->u.global_omt_location(); + tripoint loot_location = player_character.global_omt_location(); // Only check at the ground floor. loot_location.z = 0; for( int i = 0; i < rng( 2, 3 ); i++ ) { @@ -1285,7 +1295,7 @@ bool talk_function::scavenging_raid_return( npc &p ) } int money = rng( 200, 900 ); - g->u.cash += money * 100; + player_character.cash += money * 100; companion_skill_trainer( *comp, "combat", experience * 10_minutes, 10 ); popup( _( "%s returns from the raid having earned $%d and a fair bit of experience…" ), @@ -1293,7 +1303,7 @@ bool talk_function::scavenging_raid_return( npc &p ) if( one_in( 20 ) ) { popup( _( "%s was impressed with %s's performance and gave you a small bonus ( $100 )" ), p.name, comp->name ); - g->u.cash += 10000; + player_character.cash += 10000; } if( one_in( 2 ) ) { std::string itemlist = "npc_misc"; @@ -1303,7 +1313,7 @@ bool talk_function::scavenging_raid_return( npc &p ) auto result = item_group::item_from( itemlist ); if( !result.is_null() ) { popup( _( "%s returned with a %s for you!" ), comp->name, result.tname() ); - g->u.i_add( result ); + player_character.i_add( result ); } } companion_return( *comp ); @@ -1317,9 +1327,10 @@ bool talk_function::labor_return( npc &p ) return false; } + Character &player_character = get_player_character(); float hours = to_hours( calendar::turn - comp->companion_mission_time ); int money = 8 * hours; - g->u.cash += money * 100; + player_character.cash += money * 100; companion_skill_trainer( *comp, "menial", calendar::turn - comp->companion_mission_time, 1 ); @@ -1376,7 +1387,7 @@ bool talk_function::carpenter_return( npc &p ) float hours = to_hours( calendar::turn - comp->companion_mission_time ); int money = 12 * hours; - g->u.cash += money * 100; + get_player_character().cash += money * 100; companion_skill_trainer( *comp, "construction", calendar::turn - comp->companion_mission_time, 2 ); @@ -1436,9 +1447,10 @@ bool talk_function::forage_return( npc &p ) } } + Character &player_character = get_player_character(); float hours = to_hours( calendar::turn - comp->companion_mission_time ); int money = 10 * hours; - g->u.cash += money * 100; + player_character.cash += money * 100; companion_skill_trainer( *comp, "gathering", calendar::turn - comp->companion_mission_time, 2 ); @@ -1472,7 +1484,7 @@ bool talk_function::forage_return( npc &p ) auto result = item_group::item_from( itemlist ); if( !result.is_null() ) { popup( _( "%s returned with a %s for you!" ), comp->name, result.tname() ); - g->u.i_add( result ); + player_character.i_add( result ); } if( one_in( 6 ) && !p.has_trait( trait_NPC_MISSION_LEV_1 ) ) { p.set_mutation( trait_NPC_MISSION_LEV_1 ); @@ -1567,7 +1579,8 @@ bool talk_function::force_on_force( const std::vector &defender, } else if( advantage > 0 ) { adv = ", defender advantage"; } - faction *yours = g->u.get_faction(); + Character &player_character = get_player_character(); + faction *yours = player_character.get_faction(); //Find out why your followers don't have your faction... popup( _( "Engagement between %d members of %s %s and %d %s%s!" ), defender.size(), yours->name, def_desc, monsters_fighting.size(), att_desc, adv ); @@ -1730,11 +1743,12 @@ void talk_function::companion_return( npc &comp ) comp.reset_companion_mission(); comp.companion_mission_time = calendar::before_time_starts; comp.companion_mission_time_ret = calendar::before_time_starts; + Character &player_character = get_player_character(); map &here = get_map(); for( size_t i = 0; i < comp.companion_mission_inv.size(); i++ ) { for( const auto &it : comp.companion_mission_inv.const_stack( i ) ) { if( !it.count_by_charges() || it.charges > 0 ) { - here.add_item_or_charges( g->u.pos(), it ); + here.add_item_or_charges( player_character.pos(), it ); } } } @@ -1866,8 +1880,10 @@ std::vector talk_function::companion_rank( const std::vector npc_ptr talk_function::companion_choose( const std::map &required_skills ) { + Character &player_character = get_player_character(); std::vector available; - cata::optional bcp = overmap_buffer.find_camp( g->u.global_omt_location().xy() ); + cata::optional bcp = overmap_buffer.find_camp( + player_character.global_omt_location().xy() ); for( auto &elem : g->get_follower_list() ) { npc_ptr guy = overmap_buffer.find_npc( elem ); @@ -1876,9 +1892,10 @@ npc_ptr talk_function::companion_choose( const std::map &required } npc_companion_mission c_mission = guy->get_companion_mission(); // get non-assigned visible followers - if( g->u.posz() == guy->posz() && !guy->has_companion_mission() && + if( player_character.posz() == guy->posz() && !guy->has_companion_mission() && !guy->is_travelling() && - ( rl_dist( g->u.pos(), guy->pos() ) <= SEEX * 2 ) && g->u.sees( guy->pos() ) ) { + ( rl_dist( player_character.pos(), guy->pos() ) <= SEEX * 2 ) && + player_character.sees( guy->pos() ) ) { available.push_back( guy ); } else if( bcp ) { basecamp *player_camp = *bcp; @@ -1984,13 +2001,14 @@ npc_ptr talk_function::companion_choose_return( const tripoint &omt_pos, const bool by_mission ) { std::vector available; + Character &player_character = get_player_character(); for( npc_ptr &guy : overmap_buffer.get_companion_mission_npcs() ) { npc_companion_mission c_mission = guy->get_companion_mission(); if( c_mission.position != omt_pos || ( by_mission && c_mission.mission_id != mission_id ) || c_mission.role_id != role_id ) { continue; } - if( g->u.has_trait( trait_DEBUG_HS ) ) { + if( player_character.has_trait( trait_DEBUG_HS ) ) { available.push_back( guy ); } else if( deadline == calendar::before_time_starts ) { if( guy->companion_mission_time_ret <= calendar::turn ) { diff --git a/src/mission_end.cpp b/src/mission_end.cpp index 86641904bae5e..e0956e85a5efd 100644 --- a/src/mission_end.cpp +++ b/src/mission_end.cpp @@ -2,7 +2,7 @@ #include -#include "avatar.h" +#include "character.h" #include "debug.h" #include "game.h" #include "messages.h" @@ -26,6 +26,6 @@ void mission_end::deposit_box( mission *miss ) } else if( one_in( 3 ) ) { itemName = "m4a1"; } - g->u.i_add( item( itemName, 0 ) ); + get_player_character().i_add( item( itemName, 0 ) ); add_msg( m_good, _( "%s gave you an item from the deposit box." ), p->name ); } diff --git a/src/mission_util.cpp b/src/mission_util.cpp index 1ab66e3dcde99..2e0fd87880f58 100644 --- a/src/mission_util.cpp +++ b/src/mission_util.cpp @@ -26,6 +26,7 @@ #include "overmapbuffer.h" #include "point.h" #include "rng.h" +#include "talker.h" #include "translations.h" #include "type_id.h" @@ -520,12 +521,13 @@ bool mission_type::parse_funcs( const JsonObject &jo, std::functionfind_npc( miss->get_npc_id() ); + npc *beta = g->find_npc( miss->get_npc_id() ); standard_npc default_npc( "Default" ); - if( d.beta == nullptr ) { - d.beta = &default_npc; + if( beta == nullptr ) { + beta = &default_npc; } - d.alpha = &g->u; + d.alpha = get_talker_for( g->u ); + d.beta = get_talker_for( beta ); for( const talk_effect_fun_t &effect : talk_effects.effects ) { effect( d ); } diff --git a/src/monattack.cpp b/src/monattack.cpp index 648b4cdaa2790..a6a63997b010e 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -15,7 +15,6 @@ #include #include -#include "avatar.h" #include "ballistics.h" #include "bodypart.h" #include "calendar.h" @@ -209,7 +208,9 @@ static const bionic_id bio_uncanny_dodge( "bio_uncanny_dodge" ); // shared utility functions static bool within_visual_range( monster *z, int max_range ) { - return !( rl_dist( z->pos(), g->u.pos() ) > max_range || !z->sees( g->u ) ); + Character &player_character = get_player_character(); + return !( rl_dist( z->pos(), player_character.pos() ) > max_range || + !z->sees( player_character ) ); } static bool within_target_range( const monster *const z, const Creature *const target, int range ) @@ -229,7 +230,7 @@ static Creature *sting_get_target( monster *z, float range = 5.0f ) // Can't see/reach target, no attack if( !z->sees( *target ) || - !g->m.clear_path( z->pos(), target->pos(), range, 1, 100 ) ) { + !get_map().clear_path( z->pos(), target->pos(), range, 1, 100 ) ) { return nullptr; } @@ -296,7 +297,8 @@ static bool is_adjacent( const monster *z, const Creature *target, const bool al const bool target_above = target->posz() > z->posz(); const tripoint &up = target_above ? target->pos() : z->pos(); const tripoint &down = target_above ? z->pos() : target->pos(); - return g->m.ter( up ) == t_open_air && g->m.is_outside( down ); + map &here = get_map(); + return here.ter( up ) == t_open_air && here.is_outside( down ); } static npc make_fake_npc( monster *z, int str, int dex, int inte, int per ) @@ -327,15 +329,16 @@ bool mattack::eat_crop( monster *z ) { cata::optional target; int num_targets = 1; - for( const auto &p : g->m.points_in_radius( z->pos(), 1 ) ) { - if( g->m.has_flag( "PLANT", p ) && one_in( num_targets ) ) { + map &here = get_map(); + for( const auto &p : here.points_in_radius( z->pos(), 1 ) ) { + if( here.has_flag( "PLANT", p ) && one_in( num_targets ) ) { num_targets++; target = p; } } if( target ) { - g->m.furn_set( *target, furn_str_id( g->m.furn( *target )->plant->base ) ); - g->m.i_clear( *target ); + here.furn_set( *target, furn_str_id( here.furn( *target )->plant->base ) ); + here.i_clear( *target ); return true; } return true; @@ -343,12 +346,13 @@ bool mattack::eat_crop( monster *z ) bool mattack::eat_food( monster *z ) { - for( const auto &p : g->m.points_in_radius( z->pos(), 1 ) ) { + map &here = get_map(); + for( const auto &p : here.points_in_radius( z->pos(), 1 ) ) { //Protect crop seeds from carnivores, give omnivores eat_crop special also - if( g->m.has_flag( "PLANT", p ) ) { + if( here.has_flag( "PLANT", p ) ) { continue; } - map_stack items = g->m.i_at( p ); + map_stack items = here.i_at( p ); for( auto &item : items ) { //Fun limit prevents scavengers from eating feces if( !item.is_food() || item.get_comestible_fun() < -20 ) { @@ -358,9 +362,9 @@ bool mattack::eat_food( monster *z ) if( z->type->baby_egg != item.type->get_id() ) { int consumed = 1; if( item.count_by_charges() ) { - g->m.use_charges( p, 0, item.type->get_id(), consumed ); + here.use_charges( p, 0, item.type->get_id(), consumed ); } else { - g->m.use_amount( p, 0, item.type->get_id(), consumed ); + here.use_amount( p, 0, item.type->get_id(), consumed ); } return true; } @@ -373,9 +377,10 @@ bool mattack::antqueen( monster *z ) { std::vector egg_points; std::vector ants; + map &here = get_map(); // Count up all adjacent tiles the contain at least one egg. - for( const auto &dest : g->m.points_in_radius( z->pos(), 2 ) ) { - if( g->m.impassable( dest ) ) { + for( const auto &dest : here.points_in_radius( z->pos(), 2 ) ) { + if( here.impassable( dest ) ) { continue; } @@ -387,8 +392,8 @@ bool mattack::antqueen( monster *z ) continue; } - if( g->is_empty( dest ) && g->m.has_items( dest ) ) { - for( item &i : g->m.i_at( dest ) ) { + if( g->is_empty( dest ) && here.has_items( dest ) ) { + for( item &i : here.i_at( dest ) ) { if( i.typeId() == itype_ant_egg ) { egg_points.push_back( dest ); // Done looking at this tile @@ -398,30 +403,31 @@ bool mattack::antqueen( monster *z ) } } + Character &player_character = get_player_character(); if( !ants.empty() ) { // It takes a while z->moves -= 100; monster *ant = random_entry( ants ); - if( g->u.sees( *z ) && g->u.sees( *ant ) ) { + if( player_character.sees( *z ) && player_character.sees( *ant ) ) { add_msg( m_warning, _( "The %1$s feeds an %2$s and it grows!" ), z->name(), ant->name() ); } ant->poly( ant->type->upgrade_into ); } else if( egg_points.empty() ) { // There's no eggs nearby--lay one. - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( _( "The %s lays an egg!" ), z->name() ); } - g->m.spawn_item( z->pos(), "ant_egg", 1, 0, calendar::turn ); + here.spawn_item( z->pos(), "ant_egg", 1, 0, calendar::turn ); } else { // There are eggs nearby. Let's hatch some. // It takes a while z->moves -= 20 * egg_points.size(); - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %s tends nearby eggs, and they hatch!" ), z->name() ); } for( const tripoint &egg_pos : egg_points ) { - map_stack items = g->m.i_at( egg_pos ); + map_stack items = here.i_at( egg_pos ); for( map_stack::iterator it = items.begin(); it != items.end(); ) { if( it->typeId() != itype_ant_egg ) { ++it; @@ -470,7 +476,7 @@ bool mattack::shriek_alert( monster *z ) return false; } - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( _( "The %s begins shrieking!" ), z->name() ); } @@ -503,7 +509,8 @@ bool mattack::shriek_stun( monster *z ) int target_angle = coord_to_angle( z->pos(), target->pos() ); int cone_angle = 20; - for( const tripoint &cone : g->m.points_in_radius( z->pos(), 4 ) ) { + map &here = get_map(); + for( const tripoint &cone : here.points_in_radius( z->pos(), 4 ) ) { int tile_angle = coord_to_angle( z->pos(), cone ); int diff = std::abs( target_angle - tile_angle ); // Skip the target, because it's outside cone or it's the source @@ -512,7 +519,7 @@ bool mattack::shriek_stun( monster *z ) } // Affect the target // Small bash to every square, silent to not flood message box - g->m.bash( cone, 4, true ); + here.bash( cone, 4, true ); // If a monster is there, chance for stun Creature *target = g->critter_at( cone ); @@ -565,7 +572,7 @@ bool mattack::rattle( monster *z ) { // TODO: Let it rattle at non-player friendlies const int min_dist = z->friendly != 0 ? 1 : 4; - Creature *target = &g->u; + Creature *target = &get_player_character(); // Can't use attack_target - the snake has no target if( rl_dist( z->pos(), target->pos() ) > min_dist || !z->sees( *target ) ) { @@ -591,9 +598,10 @@ bool mattack::acid( monster *z ) return false; } + map &here = get_map(); // Can't see/reach target, no attack if( !z->sees( *target ) || - !g->m.clear_path( z->pos(), target->pos(), 10, 1, 100 ) ) { + !here.clear_path( z->pos(), target->pos(), 10, 1, 100 ) ) { return false; } // It takes a while @@ -610,10 +618,10 @@ bool mattack::acid( monster *z ) auto dealt = projectile_attack( proj, z->pos(), target->pos(), dispersion_sources{ 5400 }, z ); const tripoint &hitp = dealt.end_point; const Creature *hit_critter = dealt.hit_critter; - if( hit_critter == nullptr && g->m.hit_with_acid( hitp ) && g->u.sees( hitp ) ) { + if( hit_critter == nullptr && here.hit_with_acid( hitp ) && get_player_character().sees( hitp ) ) { add_msg( _( "A glob of acid hits the %s!" ), - g->m.tername( hitp ) ); - if( g->m.impassable( hitp ) ) { + here.tername( hitp ) ); + if( here.impassable( hitp ) ) { // TODO: Allow it to spill on the side it hit from return true; } @@ -622,10 +630,10 @@ bool mattack::acid( monster *z ) for( int i = -3; i <= 3; i++ ) { for( int j = -3; j <= 3; j++ ) { tripoint dest = hitp + tripoint( i, j, 0 ); - if( g->m.passable( dest ) && - g->m.clear_path( dest, hitp, 6, 1, 100 ) && + if( here.passable( dest ) && + here.clear_path( dest, hitp, 6, 1, 100 ) && ( ( one_in( std::abs( j ) ) && one_in( std::abs( i ) ) ) || ( i == 0 && j == 0 ) ) ) { - g->m.add_field( dest, fd_acid, 2 ); + here.add_field( dest, fd_acid, 2 ); } } } @@ -647,11 +655,11 @@ bool mattack::acid_barf( monster *z ) z->moves -= 80; // Make sure it happens before uncanny dodge - g->m.add_field( target->pos(), fd_acid, 1 ); + get_map().add_field( target->pos(), fd_acid, 1 ); bool uncanny = target->uncanny_dodge(); // Can we dodge the attack? Uses player dodge function % chance (melee.cpp) if( uncanny || dodge_check( z, target ) ) { - auto msg_type = target == &g->u ? m_warning : m_info; + auto msg_type = target->is_avatar() ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s barfs acid at you, but you dodge!" ), _( "The %s barfs acid at , but they dodge!" ), @@ -671,7 +679,7 @@ bool mattack::acid_barf( monster *z ) hit->token ); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_info; + auto msg_type = target->is_avatar() ? m_bad : m_info; target->add_msg_player_or_npc( msg_type, //~ 1$s is monster name, 2$s bodypart in accusative _( "The %1$s barfs acid on your %2$s for %3$d damage!" ), @@ -738,10 +746,12 @@ bool mattack::shockstorm( monster *z ) return false; } - bool seen = g->u.sees( *z ); + Character &player_character = get_player_character(); + bool seen = player_character.sees( *z ); + map &here = get_map(); // Can't see/reach target, no attack if( !z->sees( *target ) || - !g->m.clear_path( z->pos(), target->pos(), 12, 1, 100 ) ) { + !here.clear_path( z->pos(), target->pos(), 12, 1, 100 ) ) { return false; } @@ -749,10 +759,10 @@ bool mattack::shockstorm( monster *z ) z->moves -= 50; if( seen ) { - auto msg_type = target == &g->u ? m_bad : m_neutral; + auto msg_type = target->is_avatar() ? m_bad : m_neutral; add_msg( msg_type, _( "A bolt of electricity arcs towards %s!" ), target->disp_name() ); } - if( !g->u.is_deaf() ) { + if( !player_character.is_deaf() ) { sfx::play_variant_sound( "fire_gun", "bio_lightning", sfx::get_heard_volume( z->pos() ) ); } tripoint tarp( target->posx() + rng( -1, 1 ) + rng( -1, 1 ), @@ -762,13 +772,13 @@ bool mattack::shockstorm( monster *z ) // Fill the LOS with electricity for( auto &i : bolt ) { if( !one_in( 4 ) ) { - g->m.add_field( i, fd_electricity, rng( 1, 3 ) ); + here.add_field( i, fd_electricity, rng( 1, 3 ) ); } } // 5x5 cloud of electricity at the square hit - for( const auto &dest : g->m.points_in_radius( tarp, 2 ) ) { + for( const auto &dest : here.points_in_radius( tarp, 2 ) ) { if( !one_in( 4 ) ) { - g->m.add_field( dest, fd_electricity, rng( 1, 3 ) ); + here.add_field( dest, fd_electricity, rng( 1, 3 ) ); } } @@ -806,11 +816,11 @@ bool mattack::pull_metal_weapon( monster *z ) } // Can't see/reach target, no attack - if( !z->sees( *target ) || !g->m.clear_path( z->pos(), target->pos(), + if( !z->sees( *target ) || !get_map().clear_path( z->pos(), target->pos(), max_distance, 1, 100 ) ) { return false; } - player *foe = dynamic_cast< player * >( target ); + Character *foe = dynamic_cast< Character * >( target ); if( foe != nullptr ) { // Wielded steel or iron items except for built-in things like bionic claws or monomolecular blade if( !foe->weapon.has_flag( "NO_UNWIELD" ) && @@ -827,7 +837,7 @@ bool mattack::pull_metal_weapon( monster *z ) ///\EFFECT_MELEE increases resistance to pull_metal_weapon special attack success = std::max( 100 - ( 6 * ( foe->str_cur - 6 ) ) - ( 6 * wp_skill ), 0 ); } - auto m_type = foe == &g->u ? m_bad : m_neutral; + auto m_type = foe->is_avatar() ? m_bad : m_neutral; if( rng( 1, 100 ) <= success ) { target->add_msg_player_or_npc( m_type, _( "%s is pulled away from your hands!" ), _( "%s is pulled away from 's hands!" ), foe->weapon.tname() ); @@ -857,21 +867,23 @@ bool mattack::boomer( monster *z ) return false; } - std::vector line = g->m.find_clear_path( z->pos(), target->pos() ); + map &here = get_map(); + std::vector line = here.find_clear_path( z->pos(), target->pos() ); // It takes a while z->moves -= 250; - bool u_see = g->u.sees( *z ); + Character &player_character = get_player_character(); + bool u_see = player_character.sees( *z ); if( u_see ) { add_msg( m_warning, _( "The %s spews bile!" ), z->name() ); } for( auto &i : line ) { - g->m.add_field( i, fd_bile, 1 ); + here.add_field( i, fd_bile, 1 ); // If bile hit a solid tile, return. - if( g->m.impassable( i ) ) { - g->m.add_field( i, fd_bile, 3 ); - if( g->u.sees( i ) ) { + if( here.impassable( i ) ) { + here.add_field( i, fd_bile, 3 ); + if( player_character.sees( i ) ) { add_msg( _( "Bile splatters on the %s!" ), - g->m.tername( i ) ); + here.tername( i ) ); } return true; } @@ -901,19 +913,21 @@ bool mattack::boomer_glow( monster *z ) return false; } - std::vector line = g->m.find_clear_path( z->pos(), target->pos() ); + map &here = get_map(); + std::vector line = here.find_clear_path( z->pos(), target->pos() ); // It takes a while z->moves -= 250; - bool u_see = g->u.sees( *z ); + Character &player_character = get_player_character(); + bool u_see = player_character.sees( *z ); if( u_see ) { add_msg( m_warning, _( "The %s spews bile!" ), z->name() ); } for( auto &i : line ) { - g->m.add_field( i, fd_bile, 1 ); - if( g->m.impassable( i ) ) { - g->m.add_field( i, fd_bile, 3 ); - if( g->u.sees( i ) ) { - add_msg( _( "Bile splatters on the %s!" ), g->m.tername( i ) ); + here.add_field( i, fd_bile, 1 ); + if( here.impassable( i ) ) { + here.add_field( i, fd_bile, 3 ); + if( player_character.sees( i ) ) { + add_msg( _( "Bile splatters on the %s!" ), here.tername( i ) ); } return true; } @@ -958,19 +972,21 @@ bool mattack::resurrect( monster *z ) raising_level = z->get_effect_int( effect_raising ) * 40; } - bool sees_necromancer = g->u.sees( *z ); + Character &player_character = get_player_character(); + bool sees_necromancer = player_character.sees( *z ); std::vector> corpses; // Find all corpses that we can see within 10 tiles. int range = 10; bool found_eligible_corpse = false; int lowest_raise_score = INT_MAX; - for( const tripoint &p : g->m.points_in_radius( z->pos(), range ) ) { - if( !g->is_empty( p ) || g->m.get_field_intensity( p, fd_fire ) > 1 || - !g->m.sees( z->pos(), p, -1 ) ) { + map &here = get_map(); + for( const tripoint &p : here.points_in_radius( z->pos(), range ) ) { + if( !g->is_empty( p ) || here.get_field_intensity( p, fd_fire ) > 1 || + !here.sees( z->pos(), p, -1 ) ) { continue; } - for( item &i : g->m.i_at( p ) ) { + for( item &i : here.i_at( p ) ) { const mtype *mt = i.get_mtype(); if( !( i.is_corpse() && i.can_revive() && i.active && mt->has_flag( MF_REVIVES ) && mt->in_species( species_ZOMBIE ) && !mt->has_flag( MF_NO_NECRO ) ) ) { @@ -1046,7 +1062,7 @@ bool mattack::resurrect( monster *z ) float corpse_damage = raised.second->damage_level( 4 ); // Did we successfully raise something? if( g->revive_corpse( raised.first, *raised.second ) ) { - g->m.i_rem( raised.first, raised.second ); + here.i_rem( raised.first, raised.second ); if( sees_necromancer ) { add_msg( m_info, _( "The %s gestures at a nearby corpse." ), z->name() ); } @@ -1063,7 +1079,7 @@ bool mattack::resurrect( monster *z ) } zed->make_ally( *z ); - if( g->u.sees( *zed ) ) { + if( player_character.sees( *zed ) ) { add_msg( m_warning, _( "A nearby %s rises from the dead!" ), zed->name() ); } else if( sees_necromancer ) { // We saw the necromancer but not the revival @@ -1147,7 +1163,7 @@ find_empty_neighbors( const tripoint &origin ) std::pair < std::array < tripoint, ( 2 * N + 1 )*( 2 * N + 1 ) >, size_t > result; - for( const tripoint &tmp : g->m.points_in_radius( origin, r ) ) { + for( const tripoint &tmp : get_map().points_in_radius( origin, r ) ) { if( g->is_empty( tmp ) ) { result.first[result.second++] = tmp; } @@ -1258,10 +1274,8 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! valid_attacks[valid_attack_count++] = att_shock; } - // TODO: mutate() doesn't like non-players right now - // It will mutate NPCs, but it will say it mutated the player - player *const foe = dynamic_cast( target ); - if( ( foe == &g->u ) && dist <= 2 ) { + Character *const foe = dynamic_cast( target ); + if( foe && foe->is_avatar() && dist <= 2 ) { valid_attacks[valid_attack_count++] = att_radiation; } @@ -1279,6 +1293,7 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! // flavor is always okay valid_attacks[valid_attack_count++] = att_flavor; + Character &player_character = get_player_character(); //////////////////////////////////////////////////////////////////////////////////////////////// // choose and do a valid attack const int attack_index = get_random_index( valid_attack_count ); @@ -1297,8 +1312,7 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! z->moves -= att_cost_rad; // if the player can see it - if( g->u.sees( *z ) ) { - // TODO: mutate() doesn't like non-players right now + if( player_character.sees( *z ) ) { add_msg( m_bad, _( "The %1$s fires a shimmering beam towards %2$s!" ), z->name(), target->disp_name() ); } @@ -1336,7 +1350,7 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! z->ammo[itype_bot_manhack]--; // if the player can see it - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "A manhack flies out of one of the holes on the %s!" ), z->name() ); } @@ -1347,23 +1361,24 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! } } break; - case att_acid_pool : + case att_acid_pool : { z->moves -= att_cost_acid; // if the player can see it - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %s shudders, and some sort of caustic fluid leaks from a its damaged shell!" ), z->name() ); } + map &here = get_map(); // fill empty tiles with acid for( size_t i = 0; i < empty_neighbor_count; ++i ) { const tripoint &p = empty_neighbors.first[i]; - g->m.add_field( p, fd_acid, att_acid_intensity ); + here.add_field( p, fd_acid, att_acid_intensity ); } - - break; + } + break; case att_flavor : { // flavor messages static const std::array m_flavor = {{ @@ -1383,7 +1398,7 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! } // if the player can see it, else forget about it - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( m_flavor[i] ), z->name() ); } } @@ -1415,20 +1430,21 @@ static body_part body_part_hit_by_plant() bool mattack::growplants( monster *z ) { - for( const auto &p : g->m.points_in_radius( z->pos(), 3 ) ) { + map &here = get_map(); + for( const auto &p : here.points_in_radius( z->pos(), 3 ) ) { // Only affect natural, dirtlike terrain or trees. - if( !( g->m.has_flag_ter( "DIGGABLE", p ) || - g->m.has_flag_ter( "TREE", p ) || - g->m.ter( p ) == t_tree_young ) ) { + if( !( here.has_flag_ter( "DIGGABLE", p ) || + here.has_flag_ter( "TREE", p ) || + here.ter( p ) == t_tree_young ) ) { continue; } - if( g->m.is_bashable( p ) && one_in( 3 ) ) { + if( here.is_bashable( p ) && one_in( 3 ) ) { // Destroy everything - g->m.destroy( p ); + here.destroy( p ); // And then make the ground fertile - g->m.ter_set( p, t_dirtmound ); + here.ter_set( p, t_dirtmound ); continue; } @@ -1436,7 +1452,7 @@ bool mattack::growplants( monster *z ) if( !one_in( 4 ) ) { if( one_in( 3 ) ) { // If no tree, perhaps underbrush - g->m.ter_set( p, t_underbrush ); + here.ter_set( p, t_underbrush ); } continue; @@ -1450,7 +1466,7 @@ bool mattack::growplants( monster *z ) continue; } - g->m.ter_set( p, t_tree_young ); + here.ter_set( p, t_tree_young ); if( critter == nullptr || critter->uncanny_dodge() ) { continue; } @@ -1469,8 +1485,8 @@ bool mattack::growplants( monster *z ) if( !one_in( 5 ) ) { return true; } - for( const tripoint &p : g->m.points_in_radius( z->pos(), 5 ) ) { - const auto ter = g->m.ter( p ); + for( const tripoint &p : here.points_in_radius( z->pos(), 5 ) ) { + const auto ter = here.ter( p ); if( ter != t_tree_young && ter != t_underbrush ) { // Skip as soon as possible to avoid all the checks continue; @@ -1485,10 +1501,10 @@ bool mattack::growplants( monster *z ) if( ter == t_tree_young ) { // Young tree => tree // TODO: Make this deal damage too - young tree can be walked on, tree can't - g->m.ter_set( p, t_tree ); + here.ter_set( p, t_tree ); } else if( ter == t_underbrush ) { // Underbrush => young tree - g->m.ter_set( p, t_tree_young ); + here.ter_set( p, t_tree_young ); if( critter != nullptr && !critter->uncanny_dodge() ) { const body_part hit = body_part_hit_by_plant(); critter->add_msg_player_or_npc( m_bad, @@ -1509,7 +1525,7 @@ bool mattack::growplants( monster *z ) bool mattack::grow_vine( monster *z ) { if( z->friendly ) { - if( rl_dist( g->u.pos(), z->pos() ) <= 3 ) { + if( rl_dist( get_player_character().pos(), z->pos() ) <= 3 ) { // Friendly vines keep the area around you free, so you can move. return false; } @@ -1530,14 +1546,15 @@ bool mattack::grow_vine( monster *z ) bool mattack::vine( monster *z ) { int vine_neighbors = 0; - bool parent_out_of_range = !g->m.inbounds( z->move_target() ); + map &here = get_map(); + bool parent_out_of_range = !here.inbounds( z->move_target() ); monster *parent = g->critter_at( z->move_target() ); if( !parent_out_of_range && ( parent == nullptr || parent->type->id != mon_creeper_hub ) ) { // TODO: Should probably die instead. return true; } z->moves -= 100; - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 1 ) ) { + for( const tripoint &dest : here.points_in_radius( z->pos(), 1 ) ) { Creature *critter = g->critter_at( dest ); if( critter != nullptr && z->attitude_to( *critter ) == Creature::Attitude::HOSTILE ) { if( critter->uncanny_dodge() ) { @@ -1616,31 +1633,34 @@ bool mattack::triffid_heartbeat( monster *z ) return true; // TODO: when friendly: open a way to the stairs, don't spawn monsters } - if( g->u.posz() != z->posz() ) { + Character &player_character = get_player_character(); + if( player_character.posz() != z->posz() ) { // Maybe remove this and allow spawning monsters above? return true; } + map &here = get_map(); static pathfinding_settings root_pathfind( 10, 20, 50, 0, false, false, false, false, false ); - if( rl_dist( z->pos(), g->u.pos() ) > 5 && - !g->m.route( g->u.pos(), z->pos(), root_pathfind ).empty() ) { + if( rl_dist( z->pos(), player_character.pos() ) > 5 && + !here.route( player_character.pos(), z->pos(), root_pathfind ).empty() ) { add_msg( m_warning, _( "The root walls creak around you." ) ); - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 3 ) ) { + for( const tripoint &dest : here.points_in_radius( z->pos(), 3 ) ) { if( g->is_empty( dest ) && one_in( 4 ) ) { - g->m.ter_set( dest, t_root_wall ); - } else if( g->m.ter( dest ) == t_root_wall && one_in( 10 ) ) { - g->m.ter_set( dest, t_dirt ); + here.ter_set( dest, t_root_wall ); + } else if( here.ter( dest ) == t_root_wall && one_in( 10 ) ) { + here.ter_set( dest, t_dirt ); } } // Open blank tiles as long as there's no possible route int tries = 0; - while( g->m.route( g->u.pos(), z->pos(), root_pathfind ).empty() && + while( here.route( player_character.pos(), z->pos(), root_pathfind ).empty() && tries < 20 ) { - point p( rng( g->u.posx(), z->posx() - 3 ), rng( g->u.posy(), z->posy() - 3 ) ); + point p( rng( player_character.posx(), z->posx() - 3 ), + rng( player_character.posy(), z->posy() - 3 ) ); tripoint dest( p, z->posz() ); tries++; - g->m.ter_set( dest, t_dirt ); - if( rl_dist( dest, g->u.pos() ) > 3 && g->num_creatures() < 30 && + here.ter_set( dest, t_dirt ); + if( rl_dist( dest, player_character.pos() ) > 3 && g->num_creatures() < 30 && !g->critter_at( dest ) && one_in( 20 ) ) { // Spawn an extra monster mtype_id montype = mon_triffid; if( one_in( 4 ) ) { @@ -1672,12 +1692,13 @@ bool mattack::fungus( monster *z ) // TODO: Infect NPCs? // It takes a while z->moves -= 200; - if( g->u.has_trait( trait_THRESH_MYCUS ) ) { + Character &player_character = get_player_character(); + if( player_character.has_trait( trait_THRESH_MYCUS ) ) { z->friendly = 100; } //~ the sound of a fungus releasing spores sounds::sound( z->pos(), 10, sounds::sound_t::combat, _( "Pouf!" ), false, "misc", "puff" ); - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "Spores are released from the %s!" ), z->name() ); } @@ -1705,15 +1726,16 @@ bool mattack::fungus( monster *z ) } } - fungal_effects fe( *g, g->m ); - for( const tripoint &sporep : g->m.points_in_radius( z->pos(), radius ) ) { + map &here = get_map(); + fungal_effects fe( *g, here ); + for( const tripoint &sporep : here.points_in_radius( z->pos(), radius ) ) { if( sporep == z->pos() ) { continue; } const int dist = rl_dist( z->pos(), sporep ); if( !one_in( dist ) || - g->m.impassable( sporep ) || - ( dist > 1 && !g->m.clear_path( z->pos(), sporep, 2, 1, 10 ) ) ) { + here.impassable( sporep ) || + ( dist > 1 && !here.clear_path( z->pos(), sporep, 2, 1, 10 ) ) ) { continue; } @@ -1727,9 +1749,9 @@ bool mattack::fungus_corporate( monster *z ) { if( x_in_y( 1, 20 ) ) { sounds::sound( z->pos(), 10, sounds::sound_t::speech, _( "\"Buy SpOreos(tm) now!\"" ) ); - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "Delicious snacks are released from the %s!" ), z->name() ); - g->m.add_item( z->pos(), item( "sporeos" ) ); + get_map().add_item( z->pos(), item( "sporeos" ) ); } // only spawns SpOreos if the player is near; can't have the COMMONERS stealing our product from good customers return true; } else { @@ -1741,12 +1763,13 @@ bool mattack::fungus_haze( monster *z ) { //~ That spore sound again sounds::sound( z->pos(), 10, sounds::sound_t::combat, _( "Pouf!" ), true, "misc", "puff" ); - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_info, _( "The %s pulses, and fresh fungal material bursts forth." ), z->name() ); } z->moves -= 150; - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 3 ) ) { - g->m.add_field( dest, fd_fungal_haze, rng( 1, 2 ) ); + map &here = get_map(); + for( const tripoint &dest : here.points_in_radius( z->pos(), 3 ) ) { + here.add_field( dest, fd_fungal_haze, rng( 1, 2 ) ); } return true; @@ -1755,16 +1778,17 @@ bool mattack::fungus_haze( monster *z ) bool mattack::fungus_big_blossom( monster *z ) { bool firealarm = false; - const auto u_see = g->u.sees( *z ); + const auto u_see = get_player_character().sees( *z ); + map &here = get_map(); // Fungal fire-suppressor! >:D - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 6 ) ) { - if( g->m.get_field_intensity( dest, fd_fire ) != 0 ) { + for( const tripoint &dest : here.points_in_radius( z->pos(), 6 ) ) { + if( here.get_field_intensity( dest, fd_fire ) != 0 ) { firealarm = true; } if( firealarm ) { - g->m.remove_field( dest, fd_fire ); - g->m.remove_field( dest, fd_smoke ); - g->m.add_field( dest, fd_fungal_haze, 3 ); + here.remove_field( dest, fd_fire ); + here.remove_field( dest, fd_smoke ); + here.add_field( dest, fd_fungal_haze, 3 ); } } // Special effects handled outside the loop @@ -1790,8 +1814,8 @@ bool mattack::fungus_big_blossom( monster *z ) add_msg( m_info, _( "The %s pulses, and fresh fungal material bursts forth!" ), z->name() ); } z->moves -= 150; - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 12 ) ) { - g->m.add_field( dest, fd_fungal_haze, rng( 1, 2 ) ); + for( const tripoint &dest : here.points_in_radius( z->pos(), 12 ) ) { + here.add_field( dest, fd_fungal_haze, rng( 1, 2 ) ); } } @@ -1801,30 +1825,33 @@ bool mattack::fungus_big_blossom( monster *z ) bool mattack::fungus_inject( monster *z ) { // For faster copy+paste - Creature *target = &g->u; - if( rl_dist( z->pos(), g->u.pos() ) > 1 ) { + Creature *target = &get_player_character(); + Character &player_character = get_player_character(); + if( rl_dist( z->pos(), player_character.pos() ) > 1 ) { return false; } - if( g->u.has_trait( trait_THRESH_MARLOSS ) || g->u.has_trait( trait_THRESH_MYCUS ) ) { + if( player_character.has_trait( trait_THRESH_MARLOSS ) || + player_character.has_trait( trait_THRESH_MYCUS ) ) { z->friendly = 1; return true; } - if( ( g->u.has_trait( trait_MARLOSS ) ) && ( g->u.has_trait( trait_MARLOSS_BLUE ) ) && - !g->u.crossed_threshold() ) { + if( ( player_character.has_trait( trait_MARLOSS ) ) && + ( player_character.has_trait( trait_MARLOSS_BLUE ) ) && + !player_character.crossed_threshold() ) { add_msg( m_info, _( "The %s seems to wave you toward the tower…" ), z->name() ); z->anger = 0; return true; } if( z->friendly ) { - // TODO: attack other creatures, not just g->u, for now just skip the code below as it - // only attacks g->u but the monster is friendly. + // TODO: attack other creatures, not just player_character, for now just skip the code below as it + // only attacks player_character but the monster is friendly. return true; } add_msg( m_warning, _( "The %s jabs at you with a needlelike point!" ), z->name() ); z->moves -= 150; - if( g->u.uncanny_dodge() ) { + if( player_character.uncanny_dodge() ) { return true; } @@ -1838,7 +1865,7 @@ bool mattack::fungus_inject( monster *z ) const bodypart_id hit = target->get_random_body_part(); int dam = rng( 5, 11 ); - dam = g->u.deal_damage( z, hit, damage_instance( DT_CUT, dam ) ).total_damage(); + dam = player_character.deal_damage( z, hit, damage_instance( DT_CUT, dam ) ).total_damage(); if( dam > 0 ) { //~ 1$s is monster name, 2$s bodypart in accusative @@ -1846,7 +1873,7 @@ bool mattack::fungus_inject( monster *z ) body_part_name_accusative( hit ) ); if( one_in( 10 - dam ) ) { - g->u.add_effect( effect_fungus, 10_minutes, num_bp, true ); + player_character.add_effect( effect_fungus, 10_minutes, num_bp, true ); add_msg( m_warning, _( "You feel thousands of live spores pumping into you…" ) ); } } else { @@ -1856,14 +1883,16 @@ bool mattack::fungus_inject( monster *z ) } target->on_hit( z, hit, z->type->melee_skill ); - g->u.check_dead_state(); + player_character.check_dead_state(); return true; } bool mattack::fungus_bristle( monster *z ) { - if( g->u.has_trait( trait_THRESH_MARLOSS ) || g->u.has_trait( trait_THRESH_MYCUS ) ) { + Character &player_character = get_player_character(); + if( player_character.has_trait( trait_THRESH_MARLOSS ) || + player_character.has_trait( trait_THRESH_MYCUS ) ) { z->friendly = 1; } Creature *target = z->attack_target(); @@ -1873,7 +1902,7 @@ bool mattack::fungus_bristle( monster *z ) return false; } - auto msg_type = target == &g->u ? m_warning : m_neutral; + auto msg_type = target->is_avatar() ? m_warning : m_neutral; add_msg( msg_type, _( "The %1$s swipes at %2$s with a barbed tendril!" ), z->name(), target->disp_name() ); @@ -1921,7 +1950,7 @@ bool mattack::fungus_bristle( monster *z ) bool mattack::fungus_growth( monster *z ) { // Young fungaloid growing into an adult - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "The %s grows into an adult!" ), z->name() ); } @@ -1935,8 +1964,9 @@ bool mattack::fungus_sprout( monster *z ) { // To avoid map shift weirdness bool push_player = false; - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 1 ) ) { - if( g->u.pos() == dest ) { + Character &player_character = get_player_character(); + for( const tripoint &dest : get_map().points_in_radius( z->pos(), 1 ) ) { + if( player_character.pos() == dest ) { push_player = true; } if( monster *const wall = g->place_critter_at( mon_fungal_wall, dest ) ) { @@ -1945,9 +1975,9 @@ bool mattack::fungus_sprout( monster *z ) } if( push_player ) { - const int angle = coord_to_angle( z->pos(), g->u.pos() ); + const int angle = coord_to_angle( z->pos(), player_character.pos() ); add_msg( m_bad, _( "You're shoved away as a fungal wall grows!" ) ); - g->fling_creature( &g->u, angle, rng( 10, 50 ) ); + g->fling_creature( &player_character, angle, rng( 10, 50 ) ); } return true; @@ -1959,39 +1989,43 @@ bool mattack::fungus_fortify( monster *z ) // TODO: handle friendly monsters return false; } - Creature *target = &g->u; + Creature *target = &get_player_character(); + Character &player_character = get_player_character(); bool mycus = false; bool peaceful = true; //No nifty support effects. Yet. This lets it rebuild hedges. - if( g->u.has_trait( trait_THRESH_MARLOSS ) || g->u.has_trait( trait_THRESH_MYCUS ) ) { + if( player_character.has_trait( trait_THRESH_MARLOSS ) || + player_character.has_trait( trait_THRESH_MYCUS ) ) { mycus = true; } - if( ( g->u.has_trait( trait_MARLOSS ) ) && ( g->u.has_trait( trait_MARLOSS_BLUE ) ) && - !g->u.crossed_threshold() && !mycus ) { + map &here = get_map(); + if( ( player_character.has_trait( trait_MARLOSS ) ) && + ( player_character.has_trait( trait_MARLOSS_BLUE ) ) && + !player_character.crossed_threshold() && !mycus ) { // You have the other two. Is it really necessary for us to fight? add_msg( m_info, _( "The %s spreads its tendrils. It seems as though it's expecting you…" ), z->name() ); - if( rl_dist( z->pos(), g->u.pos() ) < 3 ) { + if( rl_dist( z->pos(), player_character.pos() ) < 3 ) { if( query_yn( _( "The tower extends and aims several tendrils from its depths. Hold still?" ) ) ) { add_msg( m_warning, _( "The %s works several tendrils into your arms, legs, torso, and even neck…" ), z->name() ); - g->u.hurtall( 1, z ); + player_character.hurtall( 1, z ); add_msg( m_warning, _( "You see a clear golden liquid pump through the tendrils--and then lose consciousness." ) ); - g->u.unset_mutation( trait_MARLOSS ); - g->u.unset_mutation( trait_MARLOSS_BLUE ); - g->u.set_mutation( trait_THRESH_MARLOSS ); - g->m.ter_set( g->u.pos(), + player_character.unset_mutation( trait_MARLOSS ); + player_character.unset_mutation( trait_MARLOSS_BLUE ); + player_character.set_mutation( trait_THRESH_MARLOSS ); + here.ter_set( player_character.pos(), t_marloss ); // We only show you the door. You walk through it on your own. g->memorial().add( pgettext( "memorial_male", "Was shown to the Marloss Gateway." ), pgettext( "memorial_female", "Was shown to the Marloss Gateway." ) ); - g->u.add_msg_if_player( m_good, - _( "You wake up in a marloss bush. Almost *cradled* in it, actually, as though it grew there for you." ) ); - g->u.add_msg_if_player( m_good, - //~ Beginning to hear the Mycus while conscious: this is it speaking - _( "assistance, on an arduous quest. unity. together we have reached the door. now to pass through…" ) ); + add_msg( m_good, + _( "You wake up in a marloss bush. Almost *cradled* in it, actually, as though it grew there for you." ) ); + add_msg( m_good, + //~ Beginning to hear the Mycus while conscious: this is it speaking + _( "assistance, on an arduous quest. unity. together we have reached the door. now to pass through…" ) ); return true; } else { peaceful = false; // You declined the offer. Fight! @@ -2003,8 +2037,8 @@ bool mattack::fungus_fortify( monster *z ) bool fortified = false; bool push_player = false; // To avoid map shift weirdness - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 1 ) ) { - if( g->u.pos() == dest ) { + for( const tripoint &dest : here.points_in_radius( z->pos(), 1 ) ) { + if( player_character.pos() == dest ) { push_player = true; } if( monster *const wall = g->place_critter_at( mon_fungal_hedgerow, dest ) ) { @@ -2014,14 +2048,15 @@ bool mattack::fungus_fortify( monster *z ) } if( push_player ) { add_msg( m_bad, _( "You're shoved away as a fungal hedgerow grows!" ) ); - g->fling_creature( &g->u, coord_to_angle( z->pos(), g->u.pos() ), rng( 10, 50 ) ); + g->fling_creature( &player_character, coord_to_angle( z->pos(), player_character.pos() ), rng( 10, + 50 ) ); } if( fortified || mycus || peaceful ) { return true; } // TODO: De-playerize the whole block - const int dist = rl_dist( z->pos(), g->u.pos() ); + const int dist = rl_dist( z->pos(), player_character.pos() ); if( dist >= 12 ) { return false; } @@ -2036,8 +2071,8 @@ bool mattack::fungus_fortify( monster *z ) //~ %s is bodypart name in accusative. add_msg( m_bad, _( "A fungal tendril bursts forth from the earth and pierces your %s!" ), body_part_name_accusative( convert_bp( hit ).id() ) ); - g->u.deal_damage( z, convert_bp( hit ).id(), damage_instance( DT_CUT, rng( 5, 11 ) ) ); - g->u.check_dead_state(); + player_character.deal_damage( z, convert_bp( hit ).id(), damage_instance( DT_CUT, rng( 5, 11 ) ) ); + player_character.check_dead_state(); // Probably doesn't have spores available *just* yet. Let's be nice. } else if( monster *const tendril = g->place_critter_at( mon_fungal_tendril, hit_pos ) ) { add_msg( m_bad, _( "A fungal tendril bursts forth from the earth!" ) ); @@ -2050,7 +2085,7 @@ bool mattack::fungus_fortify( monster *z ) z->name() ); z->moves -= 150; - if( g->u.uncanny_dodge() ) { + if( player_character.uncanny_dodge() ) { return true; } // Can we dodge the attack? Uses player dodge function % chance (melee.cpp) @@ -2064,13 +2099,13 @@ bool mattack::fungus_fortify( monster *z ) // TODO: 21 damage with no chance to critical isn't scary const bodypart_id hit = target->get_random_body_part(); int dam = rng( 15, 21 ); - dam = g->u.deal_damage( z, hit, damage_instance( DT_STAB, dam ) ).total_damage(); + dam = player_character.deal_damage( z, hit, damage_instance( DT_STAB, dam ) ).total_damage(); if( dam > 0 ) { //~ 1$s is monster name, 2$s bodypart in accusative add_msg( m_bad, _( "The %1$s sinks its point into your %2$s!" ), z->name(), body_part_name_accusative( hit ) ); - g->u.add_effect( effect_fungus, 40_minutes, num_bp, true ); + player_character.add_effect( effect_fungus, 40_minutes, num_bp, true ); add_msg( m_warning, _( "You feel millions of live spores pumping into you…" ) ); } else { //~ 1$s is monster name, 2$s bodypart in accusative @@ -2079,7 +2114,7 @@ bool mattack::fungus_fortify( monster *z ) } target->on_hit( z, hit, z->type->melee_skill ); - g->u.check_dead_state(); + player_character.check_dead_state(); return true; } @@ -2096,7 +2131,7 @@ bool mattack::impale( monster *z ) z->moves -= 80; bool uncanny = target->uncanny_dodge(); if( uncanny || dodge_check( z, target ) ) { - auto msg_type = target == &g->u ? m_warning : m_info; + auto msg_type = target->is_avatar() ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s lunges at you, but you dodge!" ), _( "The %s lunges at , but they dodge!" ), z->name() ); @@ -2111,7 +2146,7 @@ bool mattack::impale( monster *z ) rng( 5, 15 ), .5 ) ).total_damage(); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_info; + auto msg_type = target->is_avatar() ? m_bad : m_info; target->add_msg_player_or_npc( msg_type, //~ 1$s is monster name, 2$s bodypart in accusative _( "The %1$s impales your torso!" ), @@ -2120,15 +2155,6 @@ bool mattack::impale( monster *z ) z->name() ); target->on_hit( z, bodypart_id( "torso" ), z->type->melee_skill ); - if( one_in( 60 / ( dam + 20 ) ) ) { - if( target->is_player() || target->is_npc() ) { - target->as_character()->make_bleed( bodypart_id( "torso" ), rng( 75_turns, 125_turns ), true ); - } else { - target->add_effect( effect_bleed, rng( 75_turns, 125_turns ), bp_torso, true ); - } - - } - if( rng( 0, 200 + dam ) > 100 ) { target->add_effect( effect_downed, 3_turns ); } @@ -2167,7 +2193,7 @@ bool mattack::dermatik( monster *z ) } // Can we dodge the attack? Uses player dodge function % chance (melee.cpp) if( dodge_check( z, target ) ) { - if( target == &g->u ) { + if( target->is_avatar() ) { add_msg( _( "The %s tries to land on you, but you dodge." ), z->name() ); } z->stumble(); @@ -2190,10 +2216,11 @@ bool mattack::dermatik( monster *z ) ///\EFFECT_UNARMED increases chance of deflecting dermatik attack with TAIL_CATTLE player_swat += ( ( foe->dex_cur + foe->get_skill_level( skill_unarmed ) ) / 2 ); } + Character &player_character = get_player_character(); if( player_swat > dodge_roll ) { target->add_msg_if_player( _( "The %s lands on you, but you swat it off." ), z->name() ); if( z->get_hp() >= z->get_hp_max() / 2 ) { - z->apply_damage( &g->u, bodypart_id( "torso" ), 1 ); + z->apply_damage( &player_character, bodypart_id( "torso" ), 1 ); z->check_dead_state(); } if( player_swat > dodge_roll * 1.5 ) { @@ -2204,7 +2231,7 @@ bool mattack::dermatik( monster *z ) // Can the bug penetrate our armor? const bodypart_id targeted = target->get_random_body_part(); - if( 4 < g->u.get_armor_cut( targeted ) / 3 ) { + if( 4 < player_character.get_armor_cut( targeted ) / 3 ) { //~ 1$s monster name(dermatik), 2$s bodypart name in accusative. target->add_msg_if_player( _( "The %1$s lands on your %2$s, but can't penetrate your armor." ), z->name(), body_part_name_accusative( targeted ) ); @@ -2229,7 +2256,7 @@ bool mattack::dermatik( monster *z ) bool mattack::dermatik_growth( monster *z ) { // Dermatik larva growing into an adult - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "The %s dermatik larva grows into an adult!" ), z->name() ); } @@ -2240,20 +2267,22 @@ bool mattack::dermatik_growth( monster *z ) bool mattack::fungal_trail( monster *z ) { - fungal_effects fe( *g, g->m ); + fungal_effects fe( *g, get_map() ); fe.spread_fungus( z->pos() ); return false; } bool mattack::plant( monster *z ) { - fungal_effects fe( *g, g->m ); + map &here = get_map(); + fungal_effects fe( *g, here ); const tripoint monster_position = z->pos(); - const bool is_fungi = g->m.has_flag_ter( "FUNGUS", monster_position ); + const bool is_fungi = here.has_flag_ter( "FUNGUS", monster_position ); // Spores taking seed and growing into a fungaloid fe.spread_fungus( monster_position ); + Character &player_character = get_player_character(); if( is_fungi && one_in( 10 + g->num_creatures() / 5 ) ) { - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %s takes seed and becomes a young fungaloid!" ), z->name() ); } @@ -2262,7 +2291,7 @@ bool mattack::plant( monster *z ) z->moves -= 1000; // It takes a while return false; } else { - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( _( "The %s falls to the ground and bursts!" ), z->name() ); } @@ -2291,7 +2320,7 @@ static void poly_keep_speed( monster &mon, const mtype_id &id ) static bool blobify( monster &blob, monster &target ) { - if( g->u.sees( target ) ) { + if( get_player_character().sees( target ) ) { add_msg( m_warning, _( "%s is engulfed by %s!" ), target.disp_name(), blob.disp_name() ); } @@ -2333,7 +2362,7 @@ bool mattack::formblob( monster *z ) } bool didit = false; - std::vector pts = closest_tripoints_first( z->pos(), 1 ); + std::vector pts = closest_points_first( z->pos(), 1 ); // Don't check own tile pts.erase( pts.begin() ); for( const tripoint &dest : pts ) { @@ -2417,9 +2446,9 @@ bool mattack::callblobs( monster *z ) // if we want to deal with NPCS and friendly monsters as well. // The strategy is to send about 1/3 of the available blobs after the player, // and keep the rest near the brain blob for protection. - tripoint enemy = g->u.pos(); + tripoint enemy = get_player_character().pos(); std::list allies; - std::vector nearby_points = closest_tripoints_first( z->pos(), 3 ); + std::vector nearby_points = closest_points_first( z->pos(), 3 ); for( monster &candidate : g->all_monsters() ) { if( candidate.type->in_species( species_BLOB ) && candidate.type->id != mon_blob_brain ) { // Just give the allies consistent assignments. @@ -2452,7 +2481,7 @@ bool mattack::jackson( monster *z ) { // Jackson draws nearby zombies into the dance. std::list allies; - std::vector nearby_points = closest_tripoints_first( z->pos(), 3 ); + std::vector nearby_points = closest_points_first( z->pos(), 3 ); for( monster &candidate : g->all_monsters() ) { if( candidate.type->in_species( species_ZOMBIE ) && candidate.type->id != mon_zombie_jackson ) { // Just give the allies consistent assignments. @@ -2481,7 +2510,7 @@ bool mattack::jackson( monster *z ) } // Did we convert anybody? if( converted ) { - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "The %s lets out a high-pitched cry!" ), z->name() ); } } @@ -2491,7 +2520,7 @@ bool mattack::jackson( monster *z ) bool mattack::dance( monster *z ) { - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { switch( rng( 1, 10 ) ) { case 1: add_msg( m_neutral, _( "The %s swings its arms from side to side!" ), z->name() ); @@ -2536,14 +2565,14 @@ bool mattack::dogthing( monster *z ) return false; } - if( !one_in( 3 ) || !g->u.sees( *z ) ) { + if( !one_in( 3 ) || !get_player_character().sees( *z ) ) { return false; } add_msg( _( "The %s's head explodes in a mass of roiling tentacles!" ), z->name() ); - g->m.add_splash( z->bloodType(), z->pos(), 2, 3 ); + get_map().add_splash( z->bloodType(), z->pos(), 2, 3 ); z->friendly = 0; z->poly( mon_headless_dog_thing ); @@ -2561,7 +2590,7 @@ bool mattack::tentacle( monster *z ) if( target == nullptr || rl_dist( z->pos(), target->pos() ) > 3 || !z->sees( *target ) ) { return false; } - game_message_type msg_type = target == &g->u ? m_bad : m_info; + game_message_type msg_type = target->is_avatar() ? m_bad : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s lashes its tentacle at you!" ), _( "The %s lashes its tentacle at !" ), @@ -2615,8 +2644,9 @@ bool mattack::ranged_pull( monster *z ) } player *foe = dynamic_cast< player * >( target ); - std::vector line = g->m.find_clear_path( z->pos(), target->pos() ); - bool seen = g->u.sees( *z ); + map &here = get_map(); + std::vector line = here.find_clear_path( z->pos(), target->pos() ); + bool seen = get_player_character().sees( *z ); for( auto &i : line ) { // Player can't be pulled though bars, furniture, cars or creatures @@ -2631,7 +2661,7 @@ bool mattack::ranged_pull( monster *z ) const bool uncanny = target->uncanny_dodge(); if( uncanny || dodge_check( z, target ) ) { z->moves -= 200; - auto msg_type = foe == &g->u ? m_warning : m_info; + auto msg_type = foe && foe->is_avatar() ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s's arms fly out at you, but you dodge!" ), _( "The %s's arms fly out at , but they dodge!" ), z->name() ); @@ -2662,7 +2692,7 @@ bool mattack::ranged_pull( monster *z ) if( foe != nullptr ) { if( foe->in_vehicle ) { - g->m.unboard_vehicle( foe->pos() ); + here.unboard_vehicle( foe->pos() ); } if( target->is_player() && ( pt.x < HALF_MAPSIZE_X || pt.y < HALF_MAPSIZE_Y || @@ -2681,7 +2711,7 @@ bool mattack::ranged_pull( monster *z ) } // The monster might drag a target that's not on it's z level // So if they leave them on open air, make them fall - g->m.creature_on_trap( *target ); + here.creature_on_trap( *target ); if( seen ) { if( z->type->bodytype == "human" || z->type->bodytype == "angel" ) { add_msg( _( "The %1$s's arms fly out and pull and grab %2$s!" ), z->name(), @@ -2711,7 +2741,7 @@ bool mattack::grab( monster *z ) z->moves -= 80; const bool uncanny = target->uncanny_dodge(); - const auto msg_type = target == &g->u ? m_warning : m_info; + const auto msg_type = target->is_avatar() ? m_warning : m_info; if( uncanny || dodge_check( z, target ) ) { target->add_msg_player_or_npc( msg_type, _( "The %s gropes at you, but you dodge!" ), _( "The %s gropes at , but they dodge!" ), @@ -2805,7 +2835,7 @@ bool mattack::grab_drag( monster *z ) } if( foe != nullptr ) { if( foe->in_vehicle ) { - g->m.unboard_vehicle( foe->pos() ); + get_map().unboard_vehicle( foe->pos() ); } foe->setpos( zpt ); } else { @@ -2870,7 +2900,7 @@ bool mattack::para_sting( monster *z ) bool mattack::triffid_growth( monster *z ) { // Young triffid growing into an adult - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "The %s young triffid grows into an adult!" ), z->name() ); } @@ -2886,33 +2916,34 @@ bool mattack::stare( monster *z ) return false; } z->moves -= 200; - if( z->sees( g->u ) ) { + Character &player_character = get_player_character(); + if( z->sees( player_character ) ) { //dimensional effects don't take against dimensionally anchored foes. - if( g->u.worn_with_flag( "DIMENSIONAL_ANCHOR" ) || - g->u.has_effect_with_flag( "DIMENSIONAL_ANCHOR" ) ) { + if( player_character.worn_with_flag( "DIMENSIONAL_ANCHOR" ) || + player_character.has_effect_with_flag( "DIMENSIONAL_ANCHOR" ) ) { add_msg( m_warning, _( "You feel a strange reverberation across your body." ) ); return true; } - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_bad, _( "The %s stares at you, and you shudder." ), z->name() ); } else { add_msg( m_bad, _( "You feel like you're being watched, it makes you sick." ) ); } - g->u.add_effect( effect_taint, rng( 2_minutes, 5_minutes ) ); + player_character.add_effect( effect_taint, rng( 2_minutes, 5_minutes ) ); //Check severity before adding more debuffs - if( g->u.get_effect_int( effect_taint ) > 2 ) { - g->u.add_effect( effect_hallu, 30_minutes ); + if( player_character.get_effect_int( effect_taint ) > 2 ) { + player_character.add_effect( effect_hallu, 30_minutes ); //Check if target is a player before spawning hallucinations - if( g->u.is_player() && one_in( 2 ) ) { - g->spawn_hallucination( g->u.pos() + tripoint( rng( -10, 10 ), rng( -10, 10 ), 0 ) ); + if( player_character.is_player() && one_in( 2 ) ) { + g->spawn_hallucination( player_character.pos() + tripoint( rng( -10, 10 ), rng( -10, 10 ), 0 ) ); } if( one_in( 12 ) ) { - g->u.add_effect( effect_blind, 5_minutes ); + player_character.add_effect( effect_blind, 5_minutes ); add_msg( m_bad, _( "Your sight darkens as the visions overtake you!" ) ); } } - if( g->u.get_effect_int( effect_taint ) >= 3 && one_in( 12 ) ) { - g->u.add_effect( effect_tindrift, 1_turns ); + if( player_character.get_effect_int( effect_taint ) >= 3 && one_in( 12 ) ) { + player_character.add_effect( effect_tindrift, 1_turns ); } } return true; @@ -2924,15 +2955,17 @@ bool mattack::fear_paralyze( monster *z ) // TODO: handle friendly monsters return false; } - if( g->u.sees( *z ) && !g->u.has_effect( effect_fearparalyze ) ) { - if( g->u.has_artifact_with( AEP_PSYSHIELD ) || ( g->u.worn_with_flag( "PSYSHIELD_PARTIAL" ) && - one_in( 4 ) ) ) { + Character &player_character = get_player_character(); + if( player_character.sees( *z ) && !player_character.has_effect( effect_fearparalyze ) ) { + if( player_character.has_artifact_with( AEP_PSYSHIELD ) || + ( player_character.worn_with_flag( "PSYSHIELD_PARTIAL" ) && + one_in( 4 ) ) ) { add_msg( _( "The %s probes your mind, but is rebuffed!" ), z->name() ); ///\EFFECT_INT decreases chance of being paralyzed by fear attack - } else if( rng( 0, 20 ) > g->u.get_int() ) { + } else if( rng( 0, 20 ) > player_character.get_int() ) { add_msg( m_bad, _( "The terrifying visage of the %s paralyzes you." ), z->name() ); - g->u.add_effect( effect_fearparalyze, 5_turns ); - g->u.moves -= 4 * g->u.get_speed(); + player_character.add_effect( effect_fearparalyze, 5_turns ); + player_character.moves -= 4 * player_character.get_speed(); } else { add_msg( _( "You manage to avoid staring at the horrendous %s." ), z->name() ); } @@ -2945,10 +2978,11 @@ bool mattack::nurse_check_up( monster *z ) bool found_target = false; player *target = nullptr; tripoint tmp_pos( z->pos() + point( 12, 12 ) ); - for( auto critter : g->m.get_creatures_in_radius( z->pos(), 6 ) ) { + map &here = get_map(); + for( auto critter : here.get_creatures_in_radius( z->pos(), 6 ) ) { player *tmp_player = dynamic_cast( critter ); if( tmp_player != nullptr && z->sees( *tmp_player ) && - g->m.clear_path( z->pos(), tmp_player->pos(), 10, 0, + here.clear_path( z->pos(), tmp_player->pos(), 10, 0, 100 ) ) { // no need to scan players we can't reach if( rl_dist( z->pos(), tmp_player->pos() ) < rl_dist( z->pos(), tmp_pos ) ) { tmp_pos = tmp_player->pos(); @@ -2974,7 +3008,7 @@ bool mattack::nurse_check_up( monster *z ) sounds::sound( z->pos(), 8, sounds::sound_t::electronic_speech, string_format( _( "a soft robotic voice say, \"Here we go. Just hold still.\"" ) ) ); - if( target == &g->u ) { + if( target->is_avatar() ) { add_msg( m_good, _( "You get a medical check-up." ) ); } target->add_effect( effect_got_checked, 10_turns ); @@ -2987,7 +3021,7 @@ bool mattack::nurse_check_up( monster *z ) bool mattack::nurse_assist( monster *z ) { - const bool u_see = g->u.sees( *z ); + const bool u_see = get_player_character().sees( *z ); if( u_see && one_in( 100 ) ) { add_msg( m_info, _( "The %s is scanning its surroundings." ), z->name() ); @@ -2995,12 +3029,13 @@ bool mattack::nurse_assist( monster *z ) bool found_target = false; player *target = nullptr; + map &here = get_map(); tripoint tmp_pos( z->pos() + point( 12, 12 ) ); - for( auto critter : g->m.get_creatures_in_radius( z->pos(), 6 ) ) { + for( auto critter : here.get_creatures_in_radius( z->pos(), 6 ) ) { player *tmp_player = dynamic_cast( critter ); // No need to scan players we can't reach if( tmp_player != nullptr && z->sees( *tmp_player ) && - g->m.clear_path( z->pos(), tmp_player->pos(), 10, 0, 100 ) ) { + here.clear_path( z->pos(), tmp_player->pos(), 10, 0, 100 ) ) { if( rl_dist( z->pos(), tmp_player->pos() ) < rl_dist( z->pos(), tmp_pos ) ) { tmp_pos = tmp_player->pos(); target = tmp_player; @@ -3029,14 +3064,15 @@ bool mattack::nurse_operate( monster *z ) if( z->has_effect( effect_dragging ) || z->has_effect( effect_operating ) ) { return false; } - const bool u_see = g->u.sees( *z ); + Character &player_character = get_player_character(); + const bool u_see = player_character.sees( *z ); if( u_see && one_in( 100 ) ) { add_msg( m_info, _( "The %s is scanning its surroundings." ), z->name() ); } - if( ( ( g->u.is_wearing( itype_badge_doctor ) || - z->attitude_to( g->u ) == Creature::Attitude::FRIENDLY ) && u_see ) && one_in( 100 ) ) { + if( ( ( player_character.is_wearing( itype_badge_doctor ) || + z->attitude_to( player_character ) == Creature::Attitude::FRIENDLY ) && u_see ) && one_in( 100 ) ) { add_msg( m_info, _( "The %s doesn't seem to register you as a doctor." ), z->name() ); } @@ -3050,12 +3086,13 @@ bool mattack::nurse_operate( monster *z ) bool found_target = false; player *target = nullptr; + map &here = get_map(); tripoint tmp_pos( z->pos() + point( 12, 12 ) ); - for( auto critter : g->m.get_creatures_in_radius( z->pos(), 6 ) ) { + for( auto critter : here.get_creatures_in_radius( z->pos(), 6 ) ) { player *tmp_player = dynamic_cast< player *>( critter ); // No need to scan players we can't reach if( tmp_player != nullptr && z->sees( *tmp_player ) && - g->m.clear_path( z->pos(), tmp_player->pos(), 10, 0, 100 ) ) { + here.clear_path( z->pos(), tmp_player->pos(), 10, 0, 100 ) ) { if( tmp_player->has_any_bionic() ) { if( rl_dist( z->pos(), tmp_player->pos() ) < rl_dist( z->pos(), tmp_pos ) ) { tmp_pos = tmp_player->pos(); @@ -3065,7 +3102,7 @@ bool mattack::nurse_operate( monster *z ) } } } - if( found_target && z->attitude_to( g->u ) == Creature::Attitude::FRIENDLY ) { + if( found_target && z->attitude_to( player_character ) == Creature::Attitude::FRIENDLY ) { // 50% chance to not turn hostile again if( one_in( 2 ) ) { return false; @@ -3080,7 +3117,7 @@ bool mattack::nurse_operate( monster *z ) z->friendly = 0; z->anger = 100; - std::list couch_pos = g->m.find_furnitures_with_flag_in_radius( z->pos(), 10, + std::list couch_pos = here.find_furnitures_with_flag_in_radius( z->pos(), 10, flag_AUTODOC_COUCH ); if( couch_pos.empty() ) { @@ -3093,7 +3130,7 @@ bool mattack::nurse_operate( monster *z ) // Check if target is already grabbed by something else if( target->has_effect( effect_grabbed ) ) { - for( auto critter : g->m.get_creatures_in_radius( target->pos(), 1 ) ) { + for( auto critter : here.get_creatures_in_radius( target->pos(), 1 ) ) { monster *mon = dynamic_cast( critter ); if( mon != nullptr && mon != z ) { if( mon->type->id != mon_nursebot_defective ) { @@ -3135,7 +3172,7 @@ bool mattack::check_money_left( monster *z ) if( !z->inv.empty() ) { for( const item &it : z->inv ) { - g->m.add_item_or_charges( z->pos(), it ); + get_map().add_item_or_charges( z->pos(), it ); } z->inv.clear(); z->remove_effect( effect_has_bag ); @@ -3175,12 +3212,13 @@ bool mattack::photograph( monster *z ) return false; } + Character &player_character = get_player_character(); // Badges should NOT be swappable between roles. // Hence separate checking. // If you are in fact listed as a police officer - if( g->u.has_trait( trait_PROF_POLICE ) ) { + if( player_character.has_trait( trait_PROF_POLICE ) ) { // And you're wearing your badge - if( g->u.is_wearing( itype_badge_deputy ) ) { + if( player_character.is_wearing( itype_badge_deputy ) ) { if( one_in( 3 ) ) { add_msg( m_info, _( "The %s flashes a LED and departs. Human officer on scene." ), z->name() ); @@ -3198,9 +3236,9 @@ bool mattack::photograph( monster *z ) } } - if( g->u.has_trait( trait_PROF_PD_DET ) ) { + if( player_character.has_trait( trait_PROF_PD_DET ) ) { // And you have your shield on - if( g->u.is_wearing( itype_badge_detective ) ) { + if( player_character.is_wearing( itype_badge_detective ) ) { if( one_in( 4 ) ) { add_msg( m_info, _( "The %s flashes a LED and departs. Human officer on scene." ), z->name() ); @@ -3216,9 +3254,9 @@ bool mattack::photograph( monster *z ) return true; } } - } else if( g->u.has_trait( trait_PROF_SWAT ) ) { + } else if( player_character.has_trait( trait_PROF_SWAT ) ) { // And you're wearing your badge - if( g->u.is_wearing( itype_badge_swat ) ) { + if( player_character.is_wearing( itype_badge_swat ) ) { if( one_in( 3 ) ) { add_msg( m_info, _( "The %s flashes a LED and departs. SWAT's working the area." ), z->name() ); @@ -3233,9 +3271,9 @@ bool mattack::photograph( monster *z ) return true; } } - } else if( g->u.has_trait( trait_PROF_CYBERCO ) ) { + } else if( player_character.has_trait( trait_PROF_CYBERCO ) ) { // And you're wearing your badge - if( g->u.is_wearing( itype_badge_cybercop ) ) { + if( player_character.is_wearing( itype_badge_cybercop ) ) { if( one_in( 3 ) ) { add_msg( m_info, _( "The %s winks a LED and departs. One machine to another?" ), z->name() ); @@ -3253,9 +3291,9 @@ bool mattack::photograph( monster *z ) } } - if( g->u.has_trait( trait_PROF_FED ) ) { + if( player_character.has_trait( trait_PROF_FED ) ) { // And you're wearing your badge - if( g->u.is_wearing( itype_badge_marshal ) ) { + if( player_character.is_wearing( itype_badge_marshal ) ) { add_msg( m_info, _( "The %s flashes a LED and departs. The Feds got this." ), z->name() ); z->no_corpse_quiet = true; z->no_extra_death_drops = true; @@ -3264,7 +3302,7 @@ bool mattack::photograph( monster *z ) } } - if( z->friendly || g->u.weapon.typeId() == itype_e_handcuffs ) { + if( z->friendly || player_character.weapon.typeId() == itype_e_handcuffs ) { // Friendly (hacked?) bot ignore the player. Arrested suspect ignored too. // TODO: might need to be revisited when it can target npcs. return false; @@ -3274,23 +3312,23 @@ bool mattack::photograph( monster *z ) // TODO: Make the player known to the faction std::string cname = _( "…database connection lost!" ); if( one_in( 6 ) ) { - cname = Name::generate( g->u.male ); + cname = Name::generate( player_character.male ); } else if( one_in( 3 ) ) { - cname = g->u.name; + cname = player_character.name; } sounds::sound( z->pos(), 15, sounds::sound_t::alert, string_format( _( "a robotic voice boom, \"Citizen %s!\"" ), cname ), false, "speech", z->type->id.str() ); - if( g->u.weapon.is_gun() ) { + if( player_character.weapon.is_gun() ) { sounds::sound( z->pos(), 15, sounds::sound_t::alert, _( "\"Drop your gun! Now!\"" ) ); - } else if( g->u.is_armed() ) { + } else if( player_character.is_armed() ) { sounds::sound( z->pos(), 15, sounds::sound_t::alert, _( "\"Drop your weapon! Now!\"" ) ); } const SpeechBubble &speech = get_speech( z->type->id.str() ); sounds::sound( z->pos(), speech.volume, sounds::sound_t::alert, speech.text.translated() ); g->timed_events.add( timed_event_type::ROBOT_ATTACK, calendar::turn + rng( 15_turns, 30_turns ), 0, - g->u.global_sm_location() ); + player_character.global_sm_location() ); return true; } @@ -3323,7 +3361,8 @@ void mattack::taze( monster *z, Creature *target ) return; } - auto m_type = target->attitude_to( g->u ) == Creature::Attitude::FRIENDLY ? m_bad : m_neutral; + auto m_type = target->attitude_to( get_player_character() ) == Creature::Attitude::FRIENDLY ? + m_bad : m_neutral; target->add_msg_player_or_npc( m_type, _( "The %s shocks you!" ), _( "The %s shocks !" ), @@ -3347,7 +3386,7 @@ void mattack::rifle( monster *z, Creature *target ) // No need to aim tmp.recoil = 0; - if( target == &g->u ) { + if( target && target->is_avatar() ) { if( !z->has_effect( effect_targeted ) ) { sounds::sound( z->pos(), 8, sounds::sound_t::alarm, _( "beep-beep." ), false, "misc", "beep" ); z->add_effect( effect_targeted, 8_turns ); @@ -3366,7 +3405,7 @@ void mattack::rifle( monster *z, Creature *target ) } return; } - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "The %s opens up with its rifle!" ), z->name() ); } @@ -3375,7 +3414,7 @@ void mattack::rifle( monster *z, Creature *target ) z->ammo[ ammo_type ] -= tmp.fire_gun( target->pos(), burst ) * tmp.weapon.ammo_required(); - if( target == &g->u ) { + if( target && target->is_avatar() ) { z->add_effect( effect_targeted, 3_turns ); } } @@ -3390,9 +3429,10 @@ void mattack::frag( monster *z, Creature *target ) // This is for the bots, not z->ammo[ammo_type] = 200; } - if( target == &g->u ) { + Character &player_character = get_player_character(); + if( target && target->is_avatar() ) { if( !z->has_effect( effect_targeted ) ) { - if( g->u.has_trait( trait_PROF_CHURL ) ) { + if( player_character.has_trait( trait_PROF_CHURL ) ) { //~ Potential grenading detected. add_msg( m_warning, _( "Thee eye o dat divil be upon me!" ) ); } else { @@ -3400,7 +3440,7 @@ void mattack::frag( monster *z, Creature *target ) // This is for the bots, not add_msg( m_warning, _( "Those laser dots don't seem very friendly…" ) ); } // Effect removed in game.cpp, duration doesn't much matter - g->u.add_effect( effect_laserlocked, 3_turns ); + player_character.add_effect( effect_laserlocked, 3_turns ); sounds::sound( z->pos(), 10, sounds::sound_t::electronic_speech, _( "Targeting." ), false, "speech", z->type->id.str() ); z->add_effect( effect_targeted, 5_turns ); @@ -3426,7 +3466,7 @@ void mattack::frag( monster *z, Creature *target ) // This is for the bots, not } return; } - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %s's grenade launcher fires!" ), z->name() ); } @@ -3435,7 +3475,7 @@ void mattack::frag( monster *z, Creature *target ) // This is for the bots, not z->ammo[ ammo_type ] -= tmp.fire_gun( target->pos(), burst ) * tmp.weapon.ammo_required(); - if( target == &g->u ) { + if( target && target->is_avatar() ) { z->add_effect( effect_targeted, 3_turns ); } } @@ -3486,7 +3526,7 @@ void mattack::tankgun( monster *z, Creature *target ) } return; } - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "The %s's 120mm cannon fires!" ), z->name() ); } tmp.weapon = item( "TANK" ).ammo_set( ammo_type, z->ammo[ ammo_type ] ); @@ -3509,6 +3549,7 @@ bool mattack::searchlight( monster *z ) const int zposx = z->posx(); const int zposy = z->posy(); + map &here = get_map(); //this searchlight is not initialized if( z->inv.empty() ) { @@ -3521,7 +3562,7 @@ bool mattack::searchlight( monster *z ) settings.set_var( "SL_PREFER_RIGHT", "TRUE" ); settings.set_var( "SL_PREFER_LEFT", "TRUE" ); - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 24 ) ) { + for( const tripoint &dest : here.points_in_radius( z->pos(), 24 ) ) { const monster *const mon = g->critter_at( dest ); if( mon && mon->type->id == mon_turret_searchlight ) { if( dest.x < zposx ) { @@ -3554,7 +3595,7 @@ bool mattack::searchlight( monster *z ) for( int x = zposx - 24; x < zposx + 24; x++ ) { for( int y = zposy - 24; y < zposy + 24; y++ ) { tripoint dest( x, y, z->posz() ); - if( g->m.ter( dest ) == ter_str_id( "t_plut_generator" ) ) { + if( here.ter( dest ) == ter_str_id( "t_plut_generator" ) ) { generator_ok = true; } } @@ -3569,6 +3610,7 @@ bool mattack::searchlight( monster *z ) } } + Character &player_character = get_player_character(); for( int i = 0; i < max_lamp_count; i++ ) { item &settings = z->inv[i]; @@ -3603,7 +3645,7 @@ bool mattack::searchlight( monster *z ) for( int i = 0; i < rng( 1, 2 ); i++ ) { - if( !z->sees( g->u ) ) { + if( !z->sees( player_character ) ) { shift = settings.get_var( "SL_DIR", shift ); switch( shift ) { @@ -3641,16 +3683,16 @@ bool mattack::searchlight( monster *z ) } } else { - if( x < g->u.posx() ) { + if( x < player_character.posx() ) { x++; } - if( x > g->u.posx() ) { + if( x > player_character.posx() ) { x--; } - if( y < g->u.posy() ) { + if( y < player_character.posy() ) { y++; } - if( y > g->u.posy() ) { + if( y > player_character.posy() ) { y--; } } @@ -3674,7 +3716,7 @@ bool mattack::searchlight( monster *z ) settings.set_var( "SL_SPOT_X", x - zposx ); settings.set_var( "SL_SPOT_Y", y - zposy ); - g->m.add_field( tripoint( x, y, z->posz() ), fd_spotlight, 1 ); + here.add_field( tripoint( x, y, z->posz() ), fd_spotlight, 1 ); } @@ -3687,6 +3729,7 @@ bool mattack::flamethrower( monster *z ) // TODO: handle friendly monsters return false; } + Character &player_character = get_player_character(); // TODO: that is always false! if( z->friendly != 0 ) { // Attacking monsters, not the player! @@ -3695,7 +3738,7 @@ bool mattack::flamethrower( monster *z ) // Couldn't find any targets! if( target == nullptr ) { // Because that stupid oaf was in the way! - if( boo_hoo > 0 && g->u.sees( *z ) ) { + if( boo_hoo > 0 && player_character.sees( *z ) ) { add_msg( m_warning, ngettext( "Pointed in your direction, the %s emits an IFF warning beep.", "Pointed in your direction, the %s emits %d annoyed sounding beeps.", boo_hoo ), @@ -3712,7 +3755,7 @@ bool mattack::flamethrower( monster *z ) return false; } - flame( z, &g->u ); + flame( z, &player_character ); return true; } @@ -3720,27 +3763,29 @@ bool mattack::flamethrower( monster *z ) void mattack::flame( monster *z, Creature *target ) { int dist = rl_dist( z->pos(), target->pos() ); - if( target != &g->u ) { + Character &player_character = get_player_character(); + map &here = get_map(); + if( target != &player_character ) { // friendly // It takes a while z->moves -= 500; - if( !g->m.sees( z->pos(), target->pos(), dist ) ) { + if( !here.sees( z->pos(), target->pos(), dist ) ) { // shouldn't happen debugmsg( "mattack::flame invoked on invisible target" ); } - std::vector traj = g->m.find_clear_path( z->pos(), target->pos() ); + std::vector traj = here.find_clear_path( z->pos(), target->pos() ); for( auto &i : traj ) { // break out of attack if flame hits a wall // TODO: Z - if( g->m.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { - if( g->u.sees( i ) ) { + if( here.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { + if( player_character.sees( i ) ) { add_msg( _( "The tongue of flame hits the %s!" ), - g->m.tername( i.xy() ) ); + here.tername( i.xy() ) ); } return; } - g->m.add_field( i, fd_fire, 1 ); + here.add_field( i, fd_fire, 1 ); } target->add_effect( effect_onfire, 8_turns, bp_torso ); @@ -3749,22 +3794,22 @@ void mattack::flame( monster *z, Creature *target ) // It takes a while z->moves -= 500; - if( !g->m.sees( z->pos(), target->pos(), dist + 1 ) ) { + if( !here.sees( z->pos(), target->pos(), dist + 1 ) ) { // shouldn't happen debugmsg( "mattack::flame invoked on invisible target" ); } - std::vector traj = g->m.find_clear_path( z->pos(), target->pos() ); + std::vector traj = here.find_clear_path( z->pos(), target->pos() ); for( auto &i : traj ) { // break out of attack if flame hits a wall - if( g->m.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { - if( g->u.sees( i ) ) { + if( here.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { + if( player_character.sees( i ) ) { add_msg( _( "The tongue of flame hits the %s!" ), - g->m.tername( i.xy() ) ); + here.tername( i.xy() ) ); } return; } - g->m.add_field( i, fd_fire, 1 ); + here.add_field( i, fd_fire, 1 ); } if( !target->uncanny_dodge() ) { target->add_effect( effect_onfire, 8_turns, bp_torso ); @@ -3825,6 +3870,7 @@ bool mattack::chickenbot( monster *z ) int mode = 0; int boo_hoo = 0; Creature *target; + Character &player_character = get_player_character(); if( z->friendly == 0 ) { target = z->attack_target(); if( target == nullptr ) { @@ -3833,7 +3879,7 @@ bool mattack::chickenbot( monster *z ) } else { target = z->auto_find_hostile_target( 38, boo_hoo ); if( target == nullptr ) { - if( boo_hoo > 0 && g->u.sees( *z ) ) { // because that stupid oaf was in the way! + if( boo_hoo > 0 && player_character.sees( *z ) ) { // because that stupid oaf was in the way! add_msg( m_warning, ngettext( "Pointed in your direction, the %s emits an IFF warning beep.", "Pointed in your direction, the %s emits %d annoyed sounding beeps.", boo_hoo ), @@ -3854,13 +3900,13 @@ bool mattack::chickenbot( monster *z ) } int dist = rl_dist( z->pos(), target->pos() ); - int player_dist = rl_dist( target->pos(), g->u.pos() ); + int player_dist = rl_dist( target->pos(), player_character.pos() ); if( dist == 1 && one_in( 2 ) ) { // Use tazer at point-blank range, and even then, not continuously. mode = 1; } else if( ( z->friendly == 0 || player_dist >= 6 ) && // Avoid shooting near player if we're friendly. - ( dist >= 12 || ( g->u.in_vehicle && dist >= 6 ) ) ) { + ( dist >= 12 || ( player_character.in_vehicle && dist >= 6 ) ) ) { // Only use at long range, unless player is in a vehicle, then tolerate closer targeting. mode = 3; } else if( dist >= 4 ) { @@ -3907,6 +3953,7 @@ bool mattack::multi_robot( monster *z ) int mode = 0; int boo_hoo = 0; Creature *target; + Character &player_character = get_player_character(); if( z->friendly == 0 ) { target = z->attack_target(); if( target == nullptr ) { @@ -3915,7 +3962,7 @@ bool mattack::multi_robot( monster *z ) } else { target = z->auto_find_hostile_target( 48, boo_hoo ); if( target == nullptr ) { - if( boo_hoo > 0 && g->u.sees( *z ) ) { // because that stupid oaf was in the way! + if( boo_hoo > 0 && player_character.sees( *z ) ) { // because that stupid oaf was in the way! add_msg( m_warning, ngettext( "Pointed in your direction, the %s emits an IFF warning beep.", "Pointed in your direction, the %s emits %d annoyed sounding beeps.", boo_hoo ), @@ -3940,9 +3987,8 @@ bool mattack::multi_robot( monster *z ) mode = 1; } else if( dist <= 30 ) { mode = 2; - } else if( ( target == &g->u && g->u.in_vehicle ) || - z->friendly != 0 || - cap > 4 ) { + } else if( ( target && target->is_avatar() && player_character.in_vehicle ) || + z->friendly != 0 || cap > 4 ) { // Primary only kicks in if you're in a vehicle or are big enough to be mistaken for one. // Or if you've hacked it so the turret's on your side. ;-) if( dist < 50 ) { @@ -3985,8 +4031,10 @@ bool mattack::ratking( monster *z ) // TODO: handle friendly monsters return false; } + Character &player_character = get_player_character(); // Disable z-level ratting or it can get silly - if( rl_dist( z->pos(), g->u.pos() ) > 50 || z->posz() != g->u.posz() ) { + if( rl_dist( z->pos(), player_character.pos() ) > 50 || + z->posz() != player_character.posz() ) { return false; } @@ -4007,8 +4055,8 @@ bool mattack::ratking( monster *z ) add_msg( m_warning, _( "\"FOUL INTERLOPER…\"" ) ); break; } - if( rl_dist( z->pos(), g->u.pos() ) <= 10 ) { - g->u.add_effect( effect_rat, 3_minutes ); + if( rl_dist( z->pos(), player_character.pos() ) <= 10 ) { + player_character.add_effect( effect_rat, 3_minutes ); } return true; @@ -4052,11 +4100,12 @@ bool mattack::upgrade( monster *z ) monster *target = random_entry( targets ); std::string old_name = target->name(); - const auto could_see = g->u.sees( *target ); + Character &player_character = get_player_character(); + const bool could_see = player_character.sees( *target ); target->hasten_upgrade(); target->try_upgrade( false ); - const auto can_see = g->u.sees( *target ); - if( g->u.sees( *z ) ) { + const bool can_see = player_character.sees( *target ); + if( player_character.sees( *z ) ) { if( could_see ) { //~ %1$s is the name of the zombie upgrading the other, %2$s is the zombie being upgraded. add_msg( m_warning, _( "A black mist floats from the %1$s around the %2$s." ), @@ -4087,7 +4136,7 @@ bool mattack::breathe( monster *z ) bool able = ( z->type->id == mon_breather_hub ); if( !able ) { - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 3 ) ) { + for( const tripoint &dest : get_map().points_in_radius( z->pos(), 3 ) ) { monster *const mon = g->critter_at( dest ); if( mon && mon->type->id == mon_breather_hub ) { able = true; @@ -4122,12 +4171,13 @@ bool mattack::stretch_bite( monster *z ) z->moves -= 150; - for( auto &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { - if( g->m.impassable( pnt ) ) { + map &here = get_map(); + for( auto &pnt : here.find_clear_path( z->pos(), target->pos() ) ) { + if( here.impassable( pnt ) ) { z->add_effect( effect_stunned, 6_turns ); target->add_msg_player_or_npc( _( "The %1$s stretches its head at you, but bounces off the %2$s" ), _( "The %1$s stretches its head at , but bounces off the %2$s" ), - z->name(), g->m.obstacle_name( pnt ) ); + z->name(), here.obstacle_name( pnt ) ); return true; } } @@ -4136,7 +4186,7 @@ bool mattack::stretch_bite( monster *z ) if( uncanny || dodge_check( z, target ) ) { z->moves -= 150; z->add_effect( effect_stunned, 3_turns ); - auto msg_type = target == &g->u ? m_warning : m_info; + auto msg_type = target->is_avatar() ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s's head extends to bite you, but you dodge and the head sails past!" ), _( "The %s's head extends to bite , but they dodge and the head sails past!" ), @@ -4154,7 +4204,7 @@ bool mattack::stretch_bite( monster *z ) dam = target->deal_damage( z, hit, damage_instance( DT_STAB, dam ) ).total_damage(); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_info; + auto msg_type = target->is_avatar() ? m_bad : m_info; target->add_msg_player_or_npc( msg_type, //~ 1$s is monster name, 2$s bodypart in accusative _( "The %1$s's teeth sink into your %2$s!" ), @@ -4191,7 +4241,7 @@ bool mattack::brandish( monster *z ) return false; } // Only brandish if we can see you! - if( !z->sees( g->u ) ) { + if( !z->sees( get_player_character() ) ) { return false; } add_msg( m_warning, _( "He's brandishing a knife!" ) ); @@ -4231,7 +4281,7 @@ bool mattack::flesh_golem( monster *z ) // No attacking through floor, even if we can see the target somehow return false; } - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( _( "The %1$s swings a massive claw at %2$s!" ), z->name(), target->disp_name() ); } @@ -4273,9 +4323,11 @@ bool mattack::absorb_meat( monster *z ) const int max_meat_absorbed = monster_volume / 10.0 * average_meat_chunk_volume; //For every milliliter of meat absorbed, heal this many HP const float meat_absorption_factor = 0.01; + Character &player_character = get_player_character(); + map &here = get_map(); //Search surrounding tiles for meat - for( const auto &p : g->m.points_in_radius( z->pos(), 1 ) ) { - map_stack items = g->m.i_at( p ); + for( const auto &p : here.points_in_radius( z->pos(), 1 ) ) { + map_stack items = here.i_at( p ); for( auto ¤t_item : items ) { const material_id current_item_material = current_item.get_base_material().ident(); if( current_item_material == material_id( "flesh" ) || @@ -4295,15 +4347,15 @@ bool mattack::absorb_meat( monster *z ) int meat_absorbed = std::min( max_meat_absorbed, rng( 1, total_charges ) ); const int hp_to_heal = meat_absorbed * ml_per_charge * meat_absorption_factor; z->heal( hp_to_heal, true ); - g->m.use_charges( p, 0, current_item.type->get_id(), meat_absorbed ); + here.use_charges( p, 0, current_item.type->get_id(), meat_absorbed ); } else { //Only absorb one meaty item int meat_absorbed = 1; const int hp_to_heal = meat_absorbed * ml_per_charge * meat_absorption_factor; z->heal( hp_to_heal, true ); - g->m.use_amount( p, 0, current_item.type->get_id(), meat_absorbed ); + here.use_amount( p, 0, current_item.type->get_id(), meat_absorbed ); } - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %1$s absorbs the %2$s, growing larger." ), z->name(), current_item.tname() ); add_msg( m_debug, "The %1$s now has %2$s out of %3$s hp", z->name(), z->get_hp(), @@ -4333,7 +4385,7 @@ bool mattack::lunge( monster *z ) return false; } - bool seen = g->u.sees( *z ); + bool seen = get_player_character().sees( *z ); if( dist > 1 ) { if( one_in( 5 ) ) { // Out of range @@ -4372,7 +4424,7 @@ bool mattack::lunge( monster *z ) int dam = rng( 3, 7 ); dam = target->deal_damage( z, hit, damage_instance( DT_BASH, dam ) ).total_damage(); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_warning; + auto msg_type = target->is_avatar() ? m_bad : m_warning; target->add_msg_player_or_npc( msg_type, _( "The %1$s lunges at your %2$s, battering it for %3$d damage!" ), _( "The %1$s lunges at 's %2$s, battering it for %3$d damage!" ), @@ -4405,16 +4457,17 @@ bool mattack::longswipe( monster *z ) if( rl_dist( z->pos(), target->pos() ) > 3 || !z->sees( *target ) ) { return false; } + map &here = get_map(); //Is there something impassable blocking the claw? - for( const auto &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { - if( g->m.impassable( pnt ) ) { + for( const auto &pnt : here.find_clear_path( z->pos(), target->pos() ) ) { + if( here.impassable( pnt ) ) { //If we're here, it's an nonadjacent attack, which is only attempted 1/5 of the time. if( !one_in( 5 ) ) { return false; } target->add_msg_player_or_npc( _( "The %1$s thrusts a claw at you, but it bounces off the %2$s!" ), _( "The %1$s thrusts a claw at , but it bounces off the %2$s!" ), - z->name(), g->m.obstacle_name( pnt ) ); + z->name(), here.obstacle_name( pnt ) ); z->mod_moves( -150 ); return true; } @@ -4440,7 +4493,7 @@ bool mattack::longswipe( monster *z ) int dam = rng( 3, 7 ); dam = target->deal_damage( z, hit, damage_instance( DT_CUT, dam ) ).total_damage(); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_warning; + auto msg_type = target->is_avatar() ? m_bad : m_warning; target->add_msg_player_or_npc( msg_type, //~ 1$s is bodypart name, 2$d is damage value. _( "The %1$s thrusts a claw at your %2$s, slashing it for %3$d damage!" ), @@ -4477,15 +4530,15 @@ bool mattack::longswipe( monster *z ) dam = target->deal_damage( z, bodypart_id( "head" ), damage_instance( DT_CUT, dam ) ).total_damage(); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_warning; + auto msg_type = target->is_avatar() ? m_bad : m_warning; target->add_msg_player_or_npc( msg_type, _( "The %1$s slashes at your neck, cutting your throat for %2$d damage!" ), _( "The %1$s slashes at 's neck, cutting their throat for %2$d damage!" ), z->name(), dam ); if( target->is_player() || target->is_npc() ) { - target->as_character()->make_bleed( bodypart_id( "head" ), 10_minutes ); + target->as_character()->make_bleed( bodypart_id( "head" ), 15_minutes ); } else { - target->add_effect( effect_bleed, 10_minutes, bp_head ); + target->add_effect( effect_bleed, 15_minutes, bp_head ); } } else { @@ -4545,19 +4598,20 @@ bool mattack::darkman( monster *z ) // TODO: handle friendly monsters return false; } - if( rl_dist( z->pos(), g->u.pos() ) > 40 ) { + Character &player_character = get_player_character(); + if( rl_dist( z->pos(), player_character.pos() ) > 40 ) { return false; } if( monster *const shadow = g->place_critter_around( mon_shadow, z->pos(), 1 ) ) { z->moves -= 10; shadow->make_ally( *z ); - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "A shadow splits from the %s!" ), z->name() ); } } // Wont do the combat stuff unless it can see you - if( !z->sees( g->u ) ) { + if( !z->sees( player_character ) ) { return true; } // What do we say? @@ -4584,56 +4638,59 @@ bool mattack::darkman( monster *z ) add_msg( _( "\"Please dont\"" ) ); break; } - g->u.add_effect( effect_darkness, 1_turns, num_bp, true ); + player_character.add_effect( effect_darkness, 1_turns, num_bp, true ); return true; } bool mattack::slimespring( monster *z ) { - if( rl_dist( z->pos(), g->u.pos() ) > 30 ) { + Character &player_character = get_player_character(); + if( rl_dist( z->pos(), player_character.pos() ) > 30 ) { return false; } // This morale buff effect could get spammy - if( g->u.get_morale_level() <= 1 ) { + if( player_character.get_morale_level() <= 1 ) { switch( rng( 1, 3 ) ) { case 1: //~ Your slimes try to cheer you up! //~ Lowercase is intended: they're small voices. add_msg( m_good, _( "\"hey, it's gonna be all right!\"" ) ); - g->u.add_morale( MORALE_SUPPORT, 10, 50 ); + player_character.add_morale( MORALE_SUPPORT, 10, 50 ); break; case 2: //~ Your slimes try to cheer you up! //~ Lowercase is intended: they're small voices. add_msg( m_good, _( "\"we'll get through this!\"" ) ); - g->u.add_morale( MORALE_SUPPORT, 10, 50 ); + player_character.add_morale( MORALE_SUPPORT, 10, 50 ); break; case 3: //~ Your slimes try to cheer you up! //~ Lowercase is intended: they're small voices. add_msg( m_good, _( "\"i'm here for you!\"" ) ); - g->u.add_morale( MORALE_SUPPORT, 10, 50 ); + player_character.add_morale( MORALE_SUPPORT, 10, 50 ); break; } } - if( rl_dist( z->pos(), g->u.pos() ) <= 3 && z->sees( g->u ) ) { - if( ( g->u.has_effect( effect_bleed ) ) || ( g->u.has_effect( effect_bite ) ) ) { + if( rl_dist( z->pos(), player_character.pos() ) <= 3 && z->sees( player_character ) ) { + if( ( player_character.has_effect( effect_bleed ) ) || + ( player_character.has_effect( effect_bite ) ) ) { //~ Lowercase is intended: they're small voices. add_msg( _( "\"let me help!\"" ) ); // Yes, your slimespring(s) handle/don't all Bad Damage at the same time. - if( g->u.has_effect( effect_bite ) ) { + if( player_character.has_effect( effect_bite ) ) { if( one_in( 3 ) ) { - g->u.remove_effect( effect_bite ); + player_character.remove_effect( effect_bite ); add_msg( m_good, _( "The slime cleans you out!" ) ); } else { add_msg( _( "The slime flows over you, but your gouges still ache." ) ); } } - if( g->u.has_effect( effect_bleed ) ) { + if( player_character.has_effect( effect_bleed ) ) { if( one_in( 2 ) ) { - g->u.remove_effect( effect_bleed ); + effect &e = player_character.get_effect( effect_bleed ); + e.mod_duration( -e.get_int_dur_factor() * rng( 1, 5 ) ); add_msg( m_good, _( "The slime seals up your leaks!" ) ); } else { add_msg( _( "The slime flows over you, but your fluids are still leaking." ) ); @@ -4707,11 +4764,12 @@ bool mattack::riotbot( monster *z ) player *foe = dynamic_cast( target ); + map &here = get_map(); if( calendar::once_every( 1_minutes ) ) { - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 4 ) ) { - if( g->m.passable( dest ) && - g->m.clear_path( z->pos(), dest, 3, 1, 100 ) ) { - g->m.add_field( dest, fd_relax_gas, rng( 1, 3 ) ); + for( const tripoint &dest : here.points_in_radius( z->pos(), 4 ) ) { + if( here.passable( dest ) && + here.clear_path( z->pos(), dest, 3, 1, 100 ) ) { + here.add_field( dest, fd_relax_gas, rng( 1, 3 ) ); } } } @@ -4739,7 +4797,7 @@ bool mattack::riotbot( monster *z ) const int dist = rl_dist( z->pos(), target->pos() ); //we need empty hands to arrest - if( foe == &g->u && !foe->is_armed() ) { + if( foe && foe->is_avatar() && !foe->is_armed() ) { sounds::sound( z->pos(), 15, sounds::sound_t::electronic_speech, _( "Please stay in place, citizen, do not make any movements!" ), false, "speech", @@ -4845,10 +4903,10 @@ bool mattack::riotbot( monster *z ) add_msg( m_bad, _( "The robot sprays tear gas!" ) ); z->moves -= 200; - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 2 ) ) { - if( g->m.passable( dest ) && - g->m.clear_path( z->pos(), dest, 3, 1, 100 ) ) { - g->m.add_field( dest, fd_tear_gas, rng( 1, 3 ) ); + for( const tripoint &dest : here.points_in_radius( z->pos(), 2 ) ) { + if( here.passable( dest ) && + here.clear_path( z->pos(), dest, 3, 1, 100 ) ) { + here.add_field( dest, fd_tear_gas, rng( 1, 3 ) ); } } @@ -4883,10 +4941,10 @@ bool mattack::riotbot( monster *z ) std::vector traj = line_to( z->pos(), dest, 0, 0 ); for( auto &elem : traj ) { - if( !g->m.is_transparent( elem ) ) { + if( !here.is_transparent( elem ) ) { break; } - g->m.add_field( elem, fd_dazzling, 1 ); + here.add_field( elem, fd_dazzling, 1 ); } return true; @@ -4910,7 +4968,7 @@ bool mattack::evolve_kill_strike( monster *z ) z->moves -= 100; const bool uncanny = target->uncanny_dodge(); if( uncanny || dodge_check( z, target ) ) { - auto msg_type = target == &g->u ? m_warning : m_info; + auto msg_type = target->is_avatar() ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s lunges at you, but you dodge!" ), _( "The %s lunges at , but they dodge!" ), z->name() ); @@ -4930,7 +4988,7 @@ bool mattack::evolve_kill_strike( monster *z ) 15 ), 1.0, 0.5 ) ); int damage_dealt = target->deal_damage( z, bodypart_id( "torso" ), damage ).total_damage(); if( damage_dealt > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_warning; + auto msg_type = target->is_avatar() ? m_bad : m_warning; target->add_msg_player_or_npc( msg_type, _( "The %1$s impales yor chest for %2$d damage!" ), _( "The %1$s impales 's chest for %2$d damage!" ), @@ -4942,15 +5000,16 @@ bool mattack::evolve_kill_strike( monster *z ) z->name() ); return true; } + Character &player_character = get_player_character(); if( target->is_dead_state() && g->is_empty( target_pos ) && target->made_of_any( Creature::cmat_flesh ) ) { const std::string old_name = z->name(); - const bool could_see_z = g->u.sees( *z ); + const bool could_see_z = player_character.sees( *z ); z->allow_upgrade(); z->try_upgrade( false ); z->setpos( target_pos ); const std::string upgrade_name = z->name(); - const bool can_see_z_upgrade = g->u.sees( *z ); + const bool can_see_z_upgrade = player_character.sees( *z ); if( could_see_z && can_see_z_upgrade ) { add_msg( m_warning, _( "The %1$s burrows within %2$s corpse and a %3$s emerges from the remains!" ), old_name, @@ -4966,7 +5025,7 @@ bool mattack::evolve_kill_strike( monster *z ) bool mattack::leech_spawner( monster *z ) { - const bool u_see = g->u.sees( *z ); + const bool u_see = get_player_character().sees( *z ); std::list allies; for( monster &candidate : g->all_monsters() ) { if( candidate.in_species( species_LEECH_PLANT ) && !candidate.has_flag( MF_IMMOBILE ) ) { @@ -4998,7 +5057,7 @@ bool mattack::leech_spawner( monster *z ) bool mattack::mon_leech_evolution( monster *z ) { - const bool u_see = g->u.sees( *z ); + const bool u_see = get_player_character().sees( *z ); const bool is_queen = z->has_flag( MF_QUEEN ); std::list queens; for( monster &candidate : g->all_monsters() ) { @@ -5026,29 +5085,31 @@ bool mattack::tindalos_teleport( monster *z ) if( target == nullptr ) { return false; } + Character &player_character = get_player_character(); if( one_in( 7 ) ) { if( monster *const afterimage = g->place_critter_around( mon_hound_tindalos_afterimage, z->pos(), 1 ) ) { z->moves -= 140; afterimage->make_ally( *z ); - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The hound's movements chaotically rewind as a living afterimage splits from it!" ) ); } } } const int distance_to_target = rl_dist( z->pos(), target->pos() ); + map &here = get_map(); if( distance_to_target > 5 ) { const tripoint oldpos = z->pos(); - for( const tripoint &dest : g->m.points_in_radius( target->pos(), 4 ) ) { - if( g->m.is_cornerfloor( dest ) ) { + for( const tripoint &dest : here.points_in_radius( target->pos(), 4 ) ) { + if( here.is_cornerfloor( dest ) ) { if( g->is_empty( dest ) ) { z->setpos( dest ); // Not teleporting if it means losing sight of our current target if( z->sees( *target ) ) { - g->m.add_field( oldpos, fd_tindalos_rift, 2 ); - g->m.add_field( dest, fd_tindalos_rift, 2 ); - if( g->u.sees( *z ) ) { + here.add_field( oldpos, fd_tindalos_rift, 2 ); + here.add_field( dest, fd_tindalos_rift, 2 ); + if( player_character.sees( *z ) ) { add_msg( m_bad, _( "The %s dissipates and reforms close by." ), z->name() ); } return true; @@ -5088,8 +5149,8 @@ bool mattack::flesh_tendril( monster *z ) if( monster *const summoned = g->place_critter_around( spawned, z->pos(), 1 ) ) { z->moves -= 100; summoned->make_ally( *z ); - g->m.propagate_field( z->pos(), fd_gibs_flesh, 75, 1 ); - if( g->u.sees( *z ) ) { + get_map().propagate_field( z->pos(), fd_gibs_flesh, 75, 1 ); + if( get_player_character().sees( *z ) ) { add_msg( m_warning, _( "A %s struggles to pull itself free from the %s!" ), summoned->name(), z->name() ); } @@ -5177,7 +5238,7 @@ bool mattack::bio_op_takedown( monster *z ) return false; } - bool seen = g->u.sees( *z ); + bool seen = get_player_character().sees( *z ); player *foe = dynamic_cast< player * >( target ); if( seen ) { add_msg( _( "The %1$s mechanically grabs at %2$s!" ), z->name(), @@ -5271,7 +5332,7 @@ bool mattack::bio_op_impale( monster *z ) return false; } - const bool seen = g->u.sees( *z ); + const bool seen = get_player_character().sees( *z ); player *foe = dynamic_cast< player * >( target ); if( seen ) { add_msg( _( "The %1$s mechanically lunges at %2$s!" ), z->name(), @@ -5305,7 +5366,7 @@ bool mattack::bio_op_impale( monster *z ) // Handle mons earlier - less to check for target->deal_damage( z, bodypart_id( "torso" ), damage_instance( DT_STAB, dam ) ); if( do_bleed ) { - target->add_effect( effect_bleed, rng( 75_turns, 125_turns ), bp_torso, true ); + target->add_effect( effect_bleed, rng( 3_minutes, 10_minutes ), bp_torso, true ); } if( seen ) { add_msg( _( "The %1$s impales %2$s!" ), z->name(), target->disp_name() ); @@ -5352,7 +5413,7 @@ bool mattack::bio_op_disarm( monster *z ) return false; } - const bool seen = g->u.sees( *z ); + const bool seen = get_player_character().sees( *z ); player *foe = dynamic_cast< player * >( target ); // disarm doesn't work on creatures or unarmed targets @@ -5397,7 +5458,7 @@ bool mattack::bio_op_disarm( monster *z ) if( my_roll >= their_roll && !it.has_flag( "NO_UNWIELD" ) ) { target->add_msg_if_player( m_bad, _( "and throws it to the ground!" ) ); const tripoint tp = foe->pos() + tripoint( rng( -1, 1 ), rng( -1, 1 ), 0 ); - g->m.add_item_or_charges( tp, foe->i_rem( &it ) ); + get_map().add_item_or_charges( tp, foe->i_rem( &it ) ); } else { target->add_msg_if_player( m_good, _( "but you break its grip!" ) ); } @@ -5546,7 +5607,7 @@ bool mattack::kamikaze( monster *z ) */ // END HORRIBLE HACK - if( g->u.sees( z->pos() ) ) { + if( get_player_character().sees( z->pos() ) ) { add_msg( m_bad, _( "The %s lights up menacingly." ), z->name() ); } @@ -5601,7 +5662,7 @@ static int grenade_helper( monster *const z, Creature *const target, const int d z->ammo[att]--; // if the player can see it - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { if( data[att].message.empty() ) { add_msg( m_debug, "Invalid ammo message in grenadier special." ); } else { @@ -5652,7 +5713,7 @@ bool mattack::grenadier( monster *const z ) // Only can actively target the player right now. Once we have the ability to grab targets that we aren't // actively attacking change this to use that instead. - Creature *const target = static_cast( &g->u ); + Creature *const target = static_cast( &get_player_character() ); if( z->attitude_to( *target ) == Creature::Attitude::FRIENDLY ) { return false; } @@ -5685,7 +5746,7 @@ bool mattack::grenadier_elite( monster *const z ) // Only can actively target the player right now. Once we have the ability to grab targets that we aren't // actively attacking change this to use that instead. - Creature *const target = static_cast( &g->u ); + Creature *const target = static_cast( &get_player_character() ); if( z->attitude_to( *target ) == Creature::Attitude::FRIENDLY ) { return false; } @@ -5716,21 +5777,22 @@ bool mattack::stretch_attack( monster *z ) int dam = rng( 5, 10 ); z->moves -= 100; - for( auto &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { - if( g->m.impassable( pnt ) ) { + map &here = get_map(); + for( auto &pnt : here.find_clear_path( z->pos(), target->pos() ) ) { + if( here.impassable( pnt ) ) { target->add_msg_player_or_npc( _( "The %1$s thrusts its arm at you, but bounces off the %2$s." ), _( "The %1$s thrusts its arm at , but bounces off the %2$s." ), - z->name(), g->m.obstacle_name( pnt ) ); + z->name(), here.obstacle_name( pnt ) ); return true; } } - auto msg_type = target == &g->u ? m_warning : m_info; + auto msg_type = target->is_avatar() ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s thrusts its arm at you, stretching to reach you from afar." ), _( "The %s thrusts its arm at ." ), z->name() ); - if( dodge_check( z, target ) || g->u.uncanny_dodge() ) { + if( dodge_check( z, target ) || get_player_character().uncanny_dodge() ) { target->add_msg_player_or_npc( msg_type, _( "You evade the stretched arm and it sails past you!" ), _( " evades the stretched arm!" ) ); target->on_dodge( z, z->type->melee_skill * 2 ); @@ -5743,7 +5805,7 @@ bool mattack::stretch_attack( monster *z ) dam = target->deal_damage( z, hit, damage_instance( DT_STAB, dam ) ).total_damage(); if( dam > 0 ) { - auto msg_type = target == &g->u ? m_bad : m_info; + auto msg_type = target->is_avatar() ? m_bad : m_info; target->add_msg_player_or_npc( msg_type, //~ 1$s is monster name, 2$s bodypart in accusative _( "The %1$s's arm pierces your %2$s!" ), @@ -5768,7 +5830,7 @@ bool mattack::stretch_attack( monster *z ) bool mattack::zombie_fuse( monster *z ) { monster *critter = nullptr; - for( const tripoint &p : g->m.points_in_radius( z->pos(), 1 ) ) { + for( const tripoint &p : get_map().points_in_radius( z->pos(), 1 ) ) { critter = g->critter_at( p ); if( critter != nullptr && critter->faction == z->faction && critter != z && critter->get_size() <= z->get_size() ) { @@ -5781,7 +5843,7 @@ bool mattack::zombie_fuse( monster *z ) effect_grown_of_fuse ).get_max_intensity() ) ) ) { return false; } - if( g->u.sees( *z ) ) { + if( get_player_character().sees( *z ) ) { add_msg( _( "The %1$s fuses with the %2$s." ), critter->name(), z->name() ); @@ -5798,17 +5860,18 @@ bool mattack::zombie_fuse( monster *z ) bool mattack::doot( monster *z ) { z->moves -= 300; - if( g->u.sees( *z ) ) { + Character &player_character = get_player_character(); + if( player_character.sees( *z ) ) { add_msg( _( "The %s doots its trumpet!" ), z->name() ); } int spooks = 0; - for( const tripoint &spookyscary : g->m.points_in_radius( z->pos(), 2 ) ) { + for( const tripoint &spookyscary : get_map().points_in_radius( z->pos(), 2 ) ) { if( !g->is_empty( spookyscary ) ) { continue; } const int dist = rl_dist( z->pos(), spookyscary ); if( ( one_in( dist + 3 ) || spooks == 0 ) && spooks < 5 ) { - if( g->u.sees( *z ) ) { + if( player_character.sees( *z ) ) { add_msg( _( "A spooky skeleton rises from the ground!" ) ); } g->place_critter_at( mon_zombie_skeltal_minion, spookyscary ); diff --git a/src/mondeath.cpp b/src/mondeath.cpp index fb77eaee2811d..a5b1e24074df3 100644 --- a/src/mondeath.cpp +++ b/src/mondeath.cpp @@ -12,9 +12,9 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" +#include "character.h" #include "colony.h" #include "creature.h" #include "enums.h" @@ -38,7 +38,6 @@ #include "monster.h" #include "morale_types.h" #include "mtype.h" -#include "player.h" #include "pldata.h" #include "point.h" #include "rng.h" @@ -94,7 +93,7 @@ void mdeath::normal( monster &z ) sfx::play_variant_sound( "mon_death", "zombie_death", sfx::get_heard_volume( z.pos() ) ); } - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { //Currently it is possible to get multiple messages that a monster died. add_msg( m_good, _( "The %s dies!" ), z.name() ); } @@ -130,6 +129,7 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & pile_size = std::min( chunk_amt, pile_size ); distance = std::abs( distance ); const item chunk( chunk_name, calendar::turn, pile_size ); + map &here = get_map(); for( int i = 0; i < chunk_amt; i += pile_size ) { bool drop_chunks = true; tripoint tarp( z.pos() + point( rng( -distance, distance ), rng( -distance, distance ) ) ); @@ -138,13 +138,13 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & for( size_t j = 0; j < traj.size(); j++ ) { tarp = traj[j]; if( one_in( 2 ) && z.bloodType().id() ) { - g->m.add_splatter( z.bloodType(), tarp ); + here.add_splatter( z.bloodType(), tarp ); } else { - g->m.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); + here.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); } - if( g->m.impassable( tarp ) ) { - g->m.bash( tarp, distance ); - if( g->m.impassable( tarp ) ) { + if( here.impassable( tarp ) ) { + here.bash( tarp, distance ); + if( here.impassable( tarp ) ) { // Target is obstacle, not destroyed by bashing, // stop trajectory in front of it, if this is the first // point (e.g. wall adjacent to monster), don't drop anything on it @@ -158,7 +158,7 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & } } if( drop_chunks ) { - g->m.add_item_or_charges( tarp, chunk ); + here.add_item_or_charges( tarp, chunk ); } } } @@ -181,8 +181,9 @@ void mdeath::splatter( monster &z ) const field_type_id type_blood = z.bloodType(); const field_type_id type_gib = z.gibType(); + map &here = get_map(); if( gibbable ) { - const auto area = g->m.points_in_radius( z.pos(), 1 ); + const auto area = here.points_in_radius( z.pos(), 1 ); int number_of_gibs = std::min( std::floor( corpse_damage ) - 1, 1 + max_hp / 5.0f ); if( pulverized && z.type->size >= creature_size::medium ) { @@ -191,8 +192,8 @@ void mdeath::splatter( monster &z ) } for( int i = 0; i < number_of_gibs; ++i ) { - g->m.add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) ); - g->m.add_splatter( type_blood, random_entry( area ) ); + here.add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) ); + here.add_splatter( type_blood, random_entry( area ) ); } } // 1% of the weight of the monster is the base, with overflow damage as a multiplier @@ -231,13 +232,13 @@ void mdeath::splatter( monster &z ) if( z.has_effect( effect_no_ammo ) ) { corpse.set_var( "no_ammo", "no_ammo" ); } - g->m.add_item_or_charges( z.pos(), corpse ); + here.add_item_or_charges( z.pos(), corpse ); } } void mdeath::acid( monster &z ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { if( z.type->dies.size() == 1 ) { //If this death function is the only function. The corpse gets dissolved. add_msg( m_mixed, _( "The %s's body dissolves into acid." ), z.name() ); @@ -245,35 +246,38 @@ void mdeath::acid( monster &z ) add_msg( m_warning, _( "The %s's body leaks acid." ), z.name() ); } } - g->m.add_field( z.pos(), fd_acid, 3 ); + get_map().add_field( z.pos(), fd_acid, 3 ); } void mdeath::boomer( monster &z ) { + map &here = get_map(); std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); - for( const tripoint &dest : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* - g->m.bash( dest, 10 ); + for( const tripoint &dest : here.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* + here.bash( dest, 10 ); if( monster *const target = g->critter_at( dest ) ) { target->stumble(); target->moves -= 250; } } - if( rl_dist( z.pos(), g->u.pos() ) == 1 ) { - g->u.add_env_effect( effect_boomered, bp_eyes, 2, 24_turns ); + Character &player_character = get_player_character(); + if( rl_dist( z.pos(), player_character.pos() ) == 1 ) { + player_character.add_env_effect( effect_boomered, bp_eyes, 2, 24_turns ); } - g->m.propagate_field( z.pos(), fd_bile, 15, 1 ); + here.propagate_field( z.pos(), fd_bile, 15, 1 ); } void mdeath::boomer_glow( monster &z ) { std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); + map &here = get_map(); - for( const tripoint &dest : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* - g->m.bash( dest, 10 ); + for( const tripoint &dest : here.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* + here.bash( dest, 10 ); if( monster *const target = g->critter_at( dest ) ) { target->stumble(); target->moves -= 250; @@ -290,7 +294,7 @@ void mdeath::boomer_glow( monster &z ) } } - g->m.propagate_field( z.pos(), fd_bile, 30, 2 ); + here.propagate_field( z.pos(), fd_bile, 30, 2 ); } void mdeath::kill_vines( monster &z ) @@ -320,8 +324,9 @@ void mdeath::kill_vines( monster &z ) void mdeath::vine_cut( monster &z ) { + map &here = get_map(); std::vector vines; - for( const tripoint &tmp : g->m.points_in_radius( z.pos(), 1 ) ) { + for( const tripoint &tmp : here.points_in_radius( z.pos(), 1 ) ) { if( tmp == z.pos() ) { continue; // Skip ourselves } @@ -334,7 +339,7 @@ void mdeath::vine_cut( monster &z ) for( auto &vine : vines ) { bool found_neighbor = false; - for( const tripoint &dest : g->m.points_in_radius( vine->pos(), 1 ) ) { + for( const tripoint &dest : here.points_in_radius( vine->pos(), 1 ) ) { if( dest != z.pos() ) { // Not the dying vine if( monster *const v = g->critter_at( dest ) ) { @@ -353,7 +358,7 @@ void mdeath::vine_cut( monster &z ) void mdeath::triffid_heart( monster &z ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { add_msg( m_warning, _( "The surrounding roots begin to crack and crumble." ) ); } g->timed_events.add( timed_event_type::ROOTS_DIE, calendar::turn + 10_minutes ); @@ -364,9 +369,10 @@ void mdeath::fungus( monster &z ) //~ the sound of a fungus dying sounds::sound( z.pos(), 10, sounds::sound_t::combat, _( "Pouf!" ), false, "misc", "puff" ); - fungal_effects fe( *g, g->m ); - for( const tripoint &sporep : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* - if( g->m.impassable( sporep ) ) { + map &here = get_map(); + fungal_effects fe( *g, here ); + for( const tripoint &sporep : here.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* + if( here.impassable( sporep ) ) { continue; } // z is dead, don't credit it with the kill @@ -377,14 +383,14 @@ void mdeath::fungus( monster &z ) void mdeath::disintegrate( monster &z ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { add_msg( m_good, _( "The %s disintegrates!" ), z.name() ); } } void mdeath::worm( monster &z ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { if( z.type->dies.size() == 1 ) { add_msg( m_good, _( "The %s splits in two!" ), z.name() ); } else { @@ -400,7 +406,7 @@ void mdeath::worm( monster &z ) void mdeath::disappear( monster &z ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { add_msg( m_good, _( "The %s disappears." ), z.name() ); } } @@ -419,11 +425,12 @@ void mdeath::guilt( monster &z ) guilt_tresholds[50] = _( "You regret killing %s." ); guilt_tresholds[25] = _( "You feel remorse for killing %s." ); - if( g->u.has_trait( trait_PSYCHOPATH ) || g->u.has_trait_flag( "PRED3" ) || - g->u.has_trait_flag( "PRED4" ) || g->u.has_trait( trait_KILLER ) ) { + Character &player_character = get_player_character(); + if( player_character.has_trait( trait_PSYCHOPATH ) || player_character.has_trait_flag( "PRED3" ) || + player_character.has_trait_flag( "PRED4" ) || player_character.has_trait( trait_KILLER ) ) { return; } - if( rl_dist( z.pos(), g->u.pos() ) > MAX_GUILT_DISTANCE ) { + if( rl_dist( z.pos(), player_character.pos() ) > MAX_GUILT_DISTANCE ) { // Too far away, we can deal with it. return; } @@ -439,7 +446,8 @@ void mdeath::guilt( monster &z ) "about their deaths anymore." ), z.name( maxKills ) ); } return; - } else if( ( g->u.has_trait_flag( "PRED1" ) ) || ( g->u.has_trait_flag( "PRED2" ) ) ) { + } else if( ( player_character.has_trait_flag( "PRED1" ) ) || + ( player_character.has_trait_flag( "PRED2" ) ) ) { msg = ( _( "Culling the weak is distasteful, but necessary." ) ); msgtype = m_neutral; } else { @@ -459,30 +467,31 @@ void mdeath::guilt( monster &z ) time_duration decayDelay = 3_minutes * ( 1.0 - ( static_cast( kill_count ) / maxKills ) ); if( z.type->in_species( species_ZOMBIE ) ) { moraleMalus /= 10; - if( g->u.has_trait( trait_PACIFIST ) ) { + if( player_character.has_trait( trait_PACIFIST ) ) { moraleMalus *= 5; - } else if( g->u.has_trait_flag( "PRED1" ) ) { + } else if( player_character.has_trait_flag( "PRED1" ) ) { moraleMalus /= 4; - } else if( g->u.has_trait_flag( "PRED2" ) ) { + } else if( player_character.has_trait_flag( "PRED2" ) ) { moraleMalus /= 5; } } - g->u.add_morale( MORALE_KILLED_MONSTER, moraleMalus, maxMalus, duration, decayDelay ); + player_character.add_morale( MORALE_KILLED_MONSTER, moraleMalus, maxMalus, duration, decayDelay ); } void mdeath::blobsplit( monster &z ) { int speed = z.get_speed() - rng( 30, 50 ); - g->m.spawn_item( z.pos(), "slime_scrap", 1, 0, calendar::turn ); + get_map().spawn_item( z.pos(), "slime_scrap", 1, 0, calendar::turn ); + Character &player_character = get_player_character(); if( z.get_speed() <= 0 ) { - if( g->u.sees( z ) ) { + if( player_character.sees( z ) ) { // TODO: Add vermin-tagged tiny versions of the splattered blob :) add_msg( m_good, _( "The %s splatters apart." ), z.name() ); } return; } - if( g->u.sees( z ) ) { + if( player_character.sees( z ) ) { if( z.type->dies.size() == 1 ) { add_msg( m_good, _( "The %s splits in two!" ), z.name() ); } else { @@ -512,20 +521,22 @@ void mdeath::brainblob( monster &z ) void mdeath::jackson( monster &z ) { + bool music_stopped = false; for( monster &critter : g->all_monsters() ) { if( critter.type->id == mon_zombie_dancer ) { critter.poly( mon_zombie_hulk ); critter.remove_effect( effect_controlled ); } - if( g->u.sees( z ) ) { - add_msg( m_warning, _( "The music stops!" ) ); - } + music_stopped = true; + } + if( music_stopped && get_player_character().sees( z ) ) { + add_msg( m_warning, _( "The music stops!" ) ); } } void mdeath::melt( monster &z ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { add_msg( m_good, _( "The %s melts away." ), z.name() ); } } @@ -543,12 +554,13 @@ void mdeath::amigara( monster &z ) } // We were the last! - if( g->u.has_effect( effect_amigara ) ) { - g->u.remove_effect( effect_amigara ); + Character &player_character = get_player_character(); + if( player_character.has_effect( effect_amigara ) ) { + player_character.remove_effect( effect_amigara ); add_msg( _( "Your obsession with the fault fades away…" ) ); } - g->m.spawn_artifact( z.pos() ); + get_map().spawn_artifact( z.pos(), relic_procgen_id( "netherum_tunnels" ) ); } void mdeath::thing( monster &z ) @@ -581,7 +593,8 @@ void mdeath::explode( monster &z ) void mdeath::focused_beam( monster &z ) { - map_stack items = g->m.i_at( z.pos() ); + map &here = get_map(); + map_stack items = here.i_at( z.pos() ); for( map_stack::iterator it = items.begin(); it != items.end(); ) { if( it->typeId() == itype_processor ) { it = items.erase( it ); @@ -592,7 +605,7 @@ void mdeath::focused_beam( monster &z ) if( !z.inv.empty() ) { - if( g->u.sees( z ) ) { + if( get_player_character().sees( z ) ) { add_msg( m_warning, _( "As the final light is destroyed, it erupts in a blinding flare!" ) ); } @@ -604,10 +617,10 @@ void mdeath::focused_beam( monster &z ) std::vector traj = line_to( z.pos(), p, 0, 0 ); for( auto &elem : traj ) { - if( !g->m.is_transparent( elem ) ) { + if( !here.is_transparent( elem ) ) { break; } - g->m.add_field( elem, fd_dazzling, 2 ); + here.add_field( elem, fd_dazzling, 2 ); } } @@ -634,7 +647,8 @@ void mdeath::broken( monster &z ) const float corpse_damage = 2.5 * overflow_damage / max_hp; broken_mon.set_damage( static_cast( std::floor( corpse_damage * itype::damage_scale ) ) ); - g->m.add_item_or_charges( z.pos(), broken_mon ); + map &here = get_map(); + here.add_item_or_charges( z.pos(), broken_mon ); if( z.type->has_flag( MF_DROPS_AMMO ) ) { for( const std::pair &ammo_entry : z.ammo ) { @@ -661,14 +675,14 @@ void mdeath::broken( monster &z ) mags.insert( mags.end(), mag ); ammo_count -= mag.type->magazine->capacity; } - g->m.spawn_items( z.pos(), mags ); + here.spawn_items( z.pos(), mags ); spawned = true; break; } } } if( !spawned ) { - g->m.spawn_item( z.pos(), ammo_entry.first, ammo_entry.second, 1, + here.spawn_item( z.pos(), ammo_entry.first, ammo_entry.second, 1, calendar::turn ); } } @@ -676,17 +690,19 @@ void mdeath::broken( monster &z ) } // TODO: make mdeath::splatter work for robots - if( ( broken_mon.damage() >= broken_mon.max_damage() ) && g->u.sees( z.pos() ) ) { + Character &player_character = get_player_character(); + if( ( broken_mon.damage() >= broken_mon.max_damage() ) && player_character.sees( z.pos() ) ) { add_msg( m_good, _( "The %s is destroyed!" ), z.name() ); - } else if( g->u.sees( z.pos() ) ) { + } else if( player_character.sees( z.pos() ) ) { add_msg( m_good, _( "The %s collapses!" ), z.name() ); } } void mdeath::ratking( monster &z ) { - g->u.remove_effect( effect_rat ); - if( g->u.sees( z ) ) { + Character &player_character = get_player_character(); + player_character.remove_effect( effect_rat ); + if( player_character.sees( z ) ) { add_msg( m_warning, _( "Rats suddenly swarm into view." ) ); } @@ -697,8 +713,9 @@ void mdeath::ratking( monster &z ) void mdeath::darkman( monster &z ) { - g->u.remove_effect( effect_darkness ); - if( g->u.sees( z ) ) { + Character &player_character = get_player_character(); + player_character.remove_effect( effect_darkness ); + if( player_character.sees( z ) ) { add_msg( m_good, _( "The %s melts away." ), z.name() ); } } @@ -707,21 +724,22 @@ void mdeath::gas( monster &z ) { std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); - g->m.emit_field( z.pos(), emit_id( "emit_toxic_blast" ) ); + get_map().emit_field( z.pos(), emit_id( "emit_toxic_blast" ) ); } void mdeath::smokeburst( monster &z ) { std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); - g->m.emit_field( z.pos(), emit_id( "emit_smoke_blast" ) ); + get_map().emit_field( z.pos(), emit_id( "emit_smoke_blast" ) ); } void mdeath::fungalburst( monster &z ) { + map &here = get_map(); // If the fungus died from anti-fungal poison, don't pouf - if( g->m.get_field_intensity( z.pos(), fd_fungicidal_gas ) ) { - if( g->u.sees( z ) ) { + if( here.get_field_intensity( z.pos(), fd_fungicidal_gas ) ) { + if( get_player_character().sees( z ) ) { add_msg( m_good, _( "The %s inflates and melts away." ), z.name() ); } return; @@ -729,12 +747,12 @@ void mdeath::fungalburst( monster &z ) std::string explode = string_format( _( "a %s explodes!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); - g->m.emit_field( z.pos(), emit_id( "emit_fungal_blast" ) ); + here.emit_field( z.pos(), emit_id( "emit_fungal_blast" ) ); } void mdeath::jabberwock( monster &z ) { - player *ch = dynamic_cast( z.get_killer() ); + Character *ch = dynamic_cast( z.get_killer() ); bool vorpal = ch && ch->is_player() && ch->weapon.has_flag( "DIAMOND" ) && @@ -756,7 +774,7 @@ void mdeath::jabberwock( monster &z ) void mdeath::gameover( monster &z ) { add_msg( m_bad, _( "The %s was destroyed! GAME OVER!" ), z.name() ); - g->u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + get_player_character().set_part_hp_cur( bodypart_id( "torso" ), 0 ); } void mdeath::kill_breathers( monster &/*z*/ ) @@ -771,7 +789,7 @@ void mdeath::kill_breathers( monster &/*z*/ ) void mdeath::broken_ammo( monster &z ) { - if( g->u.sees( z.pos() ) ) { + if( get_player_character().sees( z.pos() ) ) { //~ %s is the possessive form of the monster's name add_msg( m_info, _( "The %s's interior compartment sizzles with destructive energy." ), z.name() ); @@ -791,15 +809,16 @@ void make_mon_corpse( monster &z, int damageLvl ) if( z.has_effect( effect_no_ammo ) ) { corpse.set_var( "no_ammo", "no_ammo" ); } - g->m.add_item_or_charges( z.pos(), corpse ); + get_map().add_item_or_charges( z.pos(), corpse ); } void mdeath::preg_roach( monster &z ) { + Character &player_character = get_player_character(); int num_roach = rng( 1, 3 ); while( num_roach > 0 && g->place_critter_around( mon_giant_cockroach_nymph, z.pos(), 1 ) ) { num_roach--; - if( g->u.sees( z ) ) { + if( player_character.sees( z ) ) { add_msg( m_warning, _( "A cockroach nymph crawls out of the pregnant giant cockroach corpse." ) ); } } @@ -808,7 +827,7 @@ void mdeath::preg_roach( monster &z ) void mdeath::fireball( monster &z ) { if( one_in( 10 ) ) { - g->m.propagate_field( z.pos(), fd_fire, 15, 3 ); + get_map().propagate_field( z.pos(), fd_fire, 15, 3 ); std::string explode = string_format( _( "an explosion of tank of the %s's flamethrower!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "default" ); @@ -820,8 +839,9 @@ void mdeath::fireball( monster &z ) void mdeath::conflagration( monster &z ) { - for( const auto &dest : g->m.points_in_radius( z.pos(), 1 ) ) { - g->m.propagate_field( dest, fd_fire, 18, 3 ); + map &here = get_map(); + for( const auto &dest : here.points_in_radius( z.pos(), 1 ) ) { + here.propagate_field( dest, fd_fire, 18, 3 ); } const std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); @@ -830,20 +850,21 @@ void mdeath::conflagration( monster &z ) void mdeath::necro_boomer( monster &z ) { + map &here = get_map(); std::string explode = string_format( _( "a %s explodes!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); - for( const tripoint &aoe : g->m.points_in_radius( z.pos(), 10 ) ) { - for( item &corpse : g->m.i_at( aoe ) ) { + for( const tripoint &aoe : here.points_in_radius( z.pos(), 10 ) ) { + for( item &corpse : here.i_at( aoe ) ) { if( !corpse.is_corpse() ) { continue; } if( g->revive_corpse( aoe, corpse ) ) { - g->m.i_rem( aoe, &corpse ); + here.i_rem( aoe, &corpse ); break; } } } - for( const tripoint &aoe : g->m.points_in_radius( z.pos(), 10 ) ) { + for( const tripoint &aoe : here.points_in_radius( z.pos(), 10 ) ) { monster *mon = g->critter_at( aoe ); if( mon != nullptr && one_in( 10 ) ) { mon->allow_upgrade(); diff --git a/src/mondefense.cpp b/src/mondefense.cpp index b38dad3d0be35..f0f3186e6401e 100644 --- a/src/mondefense.cpp +++ b/src/mondefense.cpp @@ -10,9 +10,9 @@ #include #include -#include "avatar.h" #include "ballistics.h" #include "bodypart.h" +#include "character.h" #include "creature.h" #include "damage.h" #include "dispersion.h" @@ -56,8 +56,9 @@ void mdefense::zapback( monster &m, Creature *const source, if( const player *const foe = dynamic_cast( source ) ) { // Players/NPCs can avoid the shock if they wear non-conductive gear on their hands for( const item &i : foe->worn ) { - if( ( i.covers( bodypart_id( "hand_l" ) ) || i.covers( bodypart_id( "hand_r" ) ) ) && - !i.conductive() && i.get_coverage() >= 95 ) { + if( !i.conductive() + && ( ( i.get_coverage( bodypart_id( "hand_l" ) ) >= 95 ) || + i.get_coverage( bodypart_id( "hand_r" ) ) >= 95 ) ) { return; } } @@ -76,8 +77,9 @@ void mdefense::zapback( monster &m, Creature *const source, return; } - if( get_avatar().sees( source->pos() ) ) { - const auto msg_type = source == &get_avatar() ? m_bad : m_info; + + if( get_player_character().sees( source->pos() ) ) { + const auto msg_type = source->is_avatar() ? m_bad : m_info; add_msg( msg_type, _( "Striking the %1$s shocks %2$s!" ), m.name(), source->disp_name() ); } @@ -125,7 +127,7 @@ void mdefense::acidsplash( monster &m, Creature *const source, } // Don't splatter directly on the `m`, that doesn't work well - std::vector pts = closest_tripoints_first( source->pos(), 1 ); + std::vector pts = closest_points_first( source->pos(), 1 ); pts.erase( std::remove( pts.begin(), pts.end(), m.pos() ), pts.end() ); projectile prj; @@ -139,7 +141,7 @@ void mdefense::acidsplash( monster &m, Creature *const source, projectile_attack( prj, m.pos(), target, dispersion_sources{ 1200 }, &m ); } - if( get_avatar().sees( m.pos() ) ) { + if( get_player_character().sees( m.pos() ) ) { add_msg( m_warning, _( "Acid sprays out of %s as it is hit!" ), m.disp_name() ); } } diff --git a/src/monexamine.cpp b/src/monexamine.cpp index 81ebdd3976f62..698ba83495cce 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -70,6 +70,7 @@ bool monexamine::pet_menu( monster &z ) attach_bag, remove_bag, drop_all, + push_monster, give_items, mon_armor_add, mon_harness_remove, @@ -98,7 +99,9 @@ bool monexamine::pet_menu( monster &z ) amenu.text = string_format( _( "What to do with your %s?" ), pet_name ); amenu.addentry( swap_pos, true, 's', _( "Swap positions" ) ); + amenu.addentry( push_monster, true, 'p', _( "Push %s" ), pet_name ); amenu.addentry( rename, true, 'e', _( "Rename" ) ); + Character &player_character = get_player_character(); if( z.has_effect( effect_has_bag ) ) { amenu.addentry( give_items, true, 'g', _( "Place items into bag" ) ); amenu.addentry( remove_bag, true, 'b', _( "Remove bag from %s" ), pet_name ); @@ -123,7 +126,7 @@ bool monexamine::pet_menu( monster &z ) if( z.has_effect( effect_tied ) ) { amenu.addentry( rope, true, 't', _( "Untie" ) ); } else if( !z.has_flag( MF_RIDEABLE_MECH ) ) { - std::vector rope_inv = g->u.items_with( []( const item & itm ) { + std::vector rope_inv = player_character.items_with( []( const item & itm ) { return itm.has_flag( "TIE_UP" ); } ); if( !rope_inv.empty() ) { @@ -151,7 +154,7 @@ bool monexamine::pet_menu( monster &z ) available = false; } if( available ) { - if( g->u.has_quality( qual_SHEAR, 1 ) ) { + if( player_character.has_quality( qual_SHEAR, 1 ) ) { amenu.addentry( shear, true, 'S', _( "Shear %s." ), pet_name ); } else { amenu.addentry( shear, false, 'S', _( "You cannot shear this animal without shears." ) ); @@ -159,29 +162,32 @@ bool monexamine::pet_menu( monster &z ) } } if( z.has_flag( MF_PET_MOUNTABLE ) && !z.has_effect( effect_monster_saddled ) && - g->u.has_item_with_flag( "TACK" ) && g->u.get_skill_level( skill_survival ) >= 1 ) { + player_character.has_item_with_flag( "TACK" ) && + player_character.get_skill_level( skill_survival ) >= 1 ) { amenu.addentry( attach_saddle, true, 'h', _( "Tack up %s" ), pet_name ); } else if( z.has_flag( MF_PET_MOUNTABLE ) && z.has_effect( effect_monster_saddled ) ) { amenu.addentry( remove_saddle, true, 'h', _( "Remove tack from %s" ), pet_name ); } else if( z.has_flag( MF_PET_MOUNTABLE ) && !z.has_effect( effect_monster_saddled ) && - g->u.has_item_with_flag( "TACK" ) && g->u.get_skill_level( skill_survival ) < 1 ) { + player_character.has_item_with_flag( "TACK" ) && + player_character.get_skill_level( skill_survival ) < 1 ) { amenu.addentry( remove_saddle, false, 'h', _( "You don't know how to saddle %s" ), pet_name ); } if( z.has_flag( MF_PAY_BOT ) ) { amenu.addentry( pay, true, 'f', _( "Manage your friendship with %s" ), pet_name ); } if( !z.has_flag( MF_RIDEABLE_MECH ) ) { - if( z.has_flag( MF_PET_MOUNTABLE ) && g->u.can_mount( z ) ) { + if( z.has_flag( MF_PET_MOUNTABLE ) && player_character.can_mount( z ) ) { amenu.addentry( mount, true, 'r', _( "Mount %s" ), pet_name ); } else if( !z.has_flag( MF_PET_MOUNTABLE ) ) { amenu.addentry( mount, false, 'r', _( "%s cannot be mounted" ), pet_name ); - } else if( z.get_size() <= g->u.get_size() ) { + } else if( z.get_size() <= player_character.get_size() ) { amenu.addentry( mount, false, 'r', _( "%s is too small to carry your weight" ), pet_name ); - } else if( g->u.get_skill_level( skill_survival ) < 1 ) { + } else if( player_character.get_skill_level( skill_survival ) < 1 ) { amenu.addentry( mount, false, 'r', _( "You have no knowledge of riding at all" ) ); - } else if( g->u.get_weight() >= z.get_weight() * z.get_mountable_weight_ratio() ) { + } else if( player_character.get_weight() >= z.get_weight() * z.get_mountable_weight_ratio() ) { amenu.addentry( mount, false, 'r', _( "You are too heavy to mount %s" ), pet_name ); - } else if( !z.has_effect( effect_monster_saddled ) && g->u.get_skill_level( skill_survival ) < 4 ) { + } else if( !z.has_effect( effect_monster_saddled ) && + player_character.get_skill_level( skill_survival ) < 4 ) { amenu.addentry( mount, false, 'r', _( "You are not skilled enough to ride without a saddle" ) ); } } else { @@ -195,16 +201,16 @@ bool monexamine::pet_menu( monster &z ) } amenu.addentry( check_bat, false, 'c', _( "%s battery level is %d%%" ), z.get_name(), static_cast( charge_percent ) ); - if( g->u.weapon.is_null() && z.battery_item ) { + if( player_character.weapon.is_null() && z.battery_item ) { amenu.addentry( mount, true, 'r', _( "Climb into the mech and take control" ) ); - } else if( !g->u.weapon.is_null() ) { + } else if( !player_character.weapon.is_null() ) { amenu.addentry( mount, false, 'r', _( "You cannot pilot the mech whilst wielding something" ) ); } else if( !z.battery_item ) { amenu.addentry( mount, false, 'r', _( "This mech has a dead battery and won't turn on" ) ); } if( z.battery_item ) { amenu.addentry( remove_bat, true, 'x', _( "Remove the mech's battery pack" ) ); - } else if( g->u.has_amount( z.type->mech_battery, 1 ) ) { + } else if( player_character.has_amount( z.type->mech_battery, 1 ) ) { amenu.addentry( insert_bat, true, 'x', _( "Insert a new battery pack" ) ); } else { amenu.addentry( insert_bat, false, 'x', _( "You need a %s to power this mech" ), type.nname( 1 ) ); @@ -217,6 +223,9 @@ bool monexamine::pet_menu( monster &z ) case swap_pos: swap( z ); break; + case push_monster: + push( z ); + break; case rename: rename_pet( z ); break; @@ -283,17 +292,19 @@ bool monexamine::pet_menu( monster &z ) void monexamine::shear_animal( monster &z ) { - const int moves = to_moves( time_duration::from_minutes( 30 / g->u.max_quality( + Character &player_character = get_player_character(); + const int moves = to_moves( time_duration::from_minutes( 30 / player_character.max_quality( qual_SHEAR ) ) ); - g->u.assign_activity( activity_id( "ACT_SHEAR" ), moves, -1 ); - g->u.activity.coords.push_back( g->m.getabs( z.pos() ) ); + player_character.assign_activity( activity_id( "ACT_SHEAR" ), moves, -1 ); + player_character.activity.coords.push_back( get_map().getabs( z.pos() ) ); // pin the sheep in place if it isn't already if( !z.has_effect( effect_tied ) ) { z.add_effect( effect_tied, 1_turns, num_bp, true ); - g->u.activity.str_values.push_back( "temp_tie" ); + player_character.activity.str_values.push_back( "temp_tie" ); } - g->u.activity.targets.push_back( item_location( g->u, g->u.best_quality_item( qual_SHEAR ) ) ); + player_character.activity.targets.push_back( item_location( player_character, + player_character.best_quality_item( qual_SHEAR ) ) ); add_msg( _( "You start shearing the %s." ), z.get_name() ); } @@ -305,7 +316,7 @@ static item_location pet_armor_loc( monster &z ) z.get_volume() <= it.get_pet_armor_max_vol(); }; - return game_menus::inv::titled_filter_menu( filter, g->u, _( "Pet armor" ) ); + return game_menus::inv::titled_filter_menu( filter, get_avatar(), _( "Pet armor" ) ); } static item_location tack_loc() @@ -314,12 +325,12 @@ static item_location tack_loc() return it.has_flag( "TACK" ); }; - return game_menus::inv::titled_filter_menu( filter, g->u, _( "Tack" ) ); + return game_menus::inv::titled_filter_menu( filter, get_avatar(), _( "Tack" ) ); } void monexamine::remove_battery( monster &z ) { - g->m.add_item_or_charges( g->u.pos(), *z.battery_item ); + get_map().add_item_or_charges( get_player_character().pos(), *z.battery_item ); z.battery_item.reset(); } @@ -329,7 +340,8 @@ void monexamine::insert_battery( monster &z ) // already has a battery, shouldn't be called with one, but just incase. return; } - std::vector bat_inv = g->u.items_with( []( const item & itm ) { + Character &player_character = get_player_character(); + std::vector bat_inv = player_character.items_with( []( const item & itm ) { return itm.has_flag( "MECH_BAT" ); } ); if( bat_inv.empty() ) { @@ -351,24 +363,22 @@ void monexamine::insert_battery( monster &z ) return; } item *bat_item = bat_inv[index - 1]; - int item_pos = g->u.get_item_position( bat_item ); - if( item_pos != INT_MIN ) { - z.battery_item = cata::make_value( *bat_item ); - g->u.i_rem( item_pos ); - } + z.battery_item = cata::make_value( *bat_item ); + player_character.i_rem( bat_item ); } bool monexamine::mech_hack( monster &z ) { + Character &player_character = get_player_character(); itype_id card_type = itype_id_military; - if( g->u.has_amount( card_type, 1 ) ) { + if( player_character.has_amount( card_type, 1 ) ) { if( query_yn( _( "Swipe your ID card into the mech's security port?" ) ) ) { - g->u.mod_moves( -100 ); + player_character.mod_moves( -100 ); z.add_effect( effect_pet, 1_turns, num_bp, true ); z.friendly = -1; add_msg( m_good, _( "The %s whirs into life and opens its restraints to accept a pilot." ), z.get_name() ); - g->u.use_amount( card_type, 1 ); + player_character.use_amount( card_type, 1 ); return true; } } else { @@ -392,8 +402,9 @@ static int prompt_for_amount( const char *const msg, const int max ) bool monexamine::pay_bot( monster &z ) { + Character &player_character = get_player_character(); time_duration friend_time = z.get_effect_dur( effect_pet ); - const int charge_count = g->u.charges_of( itype_cash_card ); + const int charge_count = player_character.charges_of( itype_cash_card ); int amount = 0; uilist bot_menu; @@ -414,7 +425,7 @@ bool monexamine::pay_bot( monster &z ) "How much friendship do you get? Max: %d minutes.", charge_count / 10 ), charge_count / 10 ); if( amount > 0 ) { time_duration time_bought = time_duration::from_minutes( amount ); - g->u.use_charges( itype_cash_card, amount * 10 ); + player_character.use_charges( itype_cash_card, amount * 10 ); z.add_effect( effect_pet, time_bought ); z.add_effect( effect_paid, time_bought, num_bp, true ); z.friendly = -1; @@ -434,7 +445,7 @@ void monexamine::attach_or_remove_saddle( monster &z ) { if( z.has_effect( effect_monster_saddled ) ) { z.remove_effect( effect_monster_saddled ); - g->u.i_add( *z.tack_item ); + get_player_character().i_add( *z.tack_item ); z.tack_item.reset(); } else { item_location loc = tack_loc(); @@ -452,7 +463,7 @@ void monexamine::attach_or_remove_saddle( monster &z ) bool Character::can_mount( const monster &critter ) const { const auto &avoid = get_path_avoid(); - auto route = g->m.route( pos(), critter.pos(), get_pathfinding_settings(), avoid ); + auto route = get_map().route( pos(), critter.pos(), get_pathfinding_settings(), avoid ); if( route.empty() ) { return false; @@ -466,23 +477,24 @@ bool Character::can_mount( const monster &critter ) const void monexamine::mount_pet( monster &z ) { - g->u.mount_creature( z ); + get_player_character().mount_creature( z ); } void monexamine::swap( monster &z ) { std::string pet_name = z.get_name(); - g->u.moves -= 150; + Character &player_character = get_player_character(); + player_character.moves -= 150; ///\EFFECT_STR increases chance to successfully swap positions with your pet ///\EFFECT_DEX increases chance to successfully swap positions with your pet - if( !one_in( ( g->u.str_cur + g->u.dex_cur ) / 6 ) ) { + if( !one_in( ( player_character.str_cur + player_character.dex_cur ) / 6 ) ) { bool t = z.has_effect( effect_tied ); if( t ) { z.remove_effect( effect_tied ); } - g->swap_critters( g->u, z ); + g->swap_critters( player_character, z ); if( t ) { z.add_effect( effect_tied, 1_turns, num_bp, true ); @@ -496,17 +508,18 @@ void monexamine::swap( monster &z ) void monexamine::push( monster &z ) { std::string pet_name = z.get_name(); - g->u.moves -= 30; + Character &player_character = get_player_character(); + player_character.moves -= 30; ///\EFFECT_STR increases chance to successfully push your pet - if( !one_in( g->u.str_cur ) ) { + if( !one_in( player_character.str_cur ) ) { add_msg( _( "You pushed the %s." ), pet_name ); } else { add_msg( _( "You pushed the %s, but it resisted." ), pet_name ); return; } - point delta( z.posx() - g->u.posx(), z.posy() - g->u.posy() ); + point delta( z.posx() - player_character.posx(), z.posy() - player_character.posy() ); z.move_to( tripoint( z.posx() + delta.x, z.posy() + delta.y, z.posz() ) ); } @@ -529,7 +542,9 @@ void monexamine::attach_bag_to( monster &z ) return it.is_armor() && it.get_total_capacity() > 0_ml; }; - item_location loc = game_menus::inv::titled_filter_menu( filter, g->u, _( "Bag item" ) ); + avatar &player_character = get_avatar(); + item_location loc = game_menus::inv::titled_filter_menu( filter, player_character, + _( "Bag item" ) ); if( !loc ) { add_msg( _( "Never mind." ) ); @@ -539,11 +554,11 @@ void monexamine::attach_bag_to( monster &z ) item &it = *loc; z.storage_item = cata::make_value( it ); add_msg( _( "You mount the %1$s on your %2$s." ), it.display_name(), pet_name ); - g->u.i_rem( &it ); + player_character.i_rem( &it ); z.add_effect( effect_has_bag, 1_turns, num_bp, true ); // Update encumbrance in case we were wearing it - g->u.flag_encumbrance(); - g->u.moves -= 200; + player_character.flag_encumbrance(); + player_character.moves -= 200; } void monexamine::remove_bag_from( monster &z ) @@ -553,10 +568,11 @@ void monexamine::remove_bag_from( monster &z ) if( !z.inv.empty() ) { dump_items( z ); } - g->m.add_item_or_charges( g->u.pos(), *z.storage_item ); + Character &player_character = get_player_character(); + get_map().add_item_or_charges( player_character.pos(), *z.storage_item ); add_msg( _( "You remove the %1$s from %2$s." ), z.storage_item->display_name(), pet_name ); z.storage_item.reset(); - g->u.moves -= 200; + player_character.moves -= 200; } else { add_msg( m_bad, _( "Your %1$s doesn't have a bag!" ), pet_name ); } @@ -566,12 +582,14 @@ void monexamine::remove_bag_from( monster &z ) void monexamine::dump_items( monster &z ) { std::string pet_name = z.get_name(); + Character &player_character = get_player_character(); + map &here = get_map(); for( auto &it : z.inv ) { - g->m.add_item_or_charges( g->u.pos(), it ); + here.add_item_or_charges( player_character.pos(), it ); } z.inv.clear(); add_msg( _( "You dump the contents of the %s's bag on the ground." ), pet_name ); - g->u.moves -= 200; + player_character.moves -= 200; } bool monexamine::give_items_to( monster &z ) @@ -586,7 +604,8 @@ bool monexamine::give_items_to( monster &z ) units::mass max_weight = z.weight_capacity() - z.get_carried_weight(); units::volume max_volume = storage.get_total_capacity() - z.get_carried_volume(); - drop_locations items = game_menus::inv::multidrop( g->u ); + avatar &player_character = get_avatar(); + drop_locations items = game_menus::inv::multidrop( player_character ); drop_locations to_move; for( const drop_location &itq : items ) { const item &it = *itq.first; @@ -605,7 +624,7 @@ bool monexamine::give_items_to( monster &z ) } } z.add_effect( effect_controlled, 5_turns ); - g->u.drop( to_move, z.pos(), true ); + player_character.drop( to_move, z.pos(), true ); return false; } @@ -635,7 +654,7 @@ bool monexamine::add_armor( monster &z ) loc.remove_item(); z.add_effect( effect_monster_armor, 1_turns, num_bp, true ); // TODO: armoring a horse takes a lot longer than 2 seconds. This should be a long action. - g->u.moves -= 200; + get_player_character().moves -= 200; return true; } @@ -650,12 +669,12 @@ void monexamine::remove_armor( monster &z ) std::string pet_name = z.get_name(); if( z.armor_item ) { z.armor_item->erase_var( "pet_armor" ); - g->m.add_item_or_charges( z.pos(), *z.armor_item ); + get_map().add_item_or_charges( z.pos(), *z.armor_item ); add_msg( pgettext( "pet armor", "You remove the %1$s from %2$s." ), z.armor_item->display_name(), pet_name ); z.armor_item.reset(); // TODO: removing armor from a horse takes a lot longer than 2 seconds. This should be a long action. - g->u.moves -= 200; + get_player_character().moves -= 200; } else { add_msg( m_bad, _( "Your %1$s isn't wearing armor!" ), pet_name ); } @@ -665,34 +684,38 @@ void monexamine::remove_armor( monster &z ) void monexamine::play_with( monster &z ) { std::string pet_name = z.get_name(); - g->u.assign_activity( ACT_PLAY_WITH_PET, rng( 50, 125 ) * 100 ); - g->u.activity.str_values.push_back( pet_name ); + Character &player_character = get_player_character(); + player_character.assign_activity( ACT_PLAY_WITH_PET, rng( 50, 125 ) * 100 ); + player_character.activity.str_values.push_back( pet_name ); } void monexamine::kill_zslave( monster &z ) { - z.apply_damage( &g->u, bodypart_id( "torso" ), 100 ); // damage the monster (and its corpse) - z.die( &g->u ); // and make sure it's really dead + avatar &player_character = get_avatar(); + z.apply_damage( &player_character, bodypart_id( "torso" ), + 100 ); // damage the monster (and its corpse) + z.die( &player_character ); // and make sure it's really dead - g->u.moves -= 150; + player_character.moves -= 150; if( !one_in( 3 ) ) { - g->u.add_msg_if_player( _( "You tear out the pheromone ball from the zombie slave." ) ); + player_character.add_msg_if_player( _( "You tear out the pheromone ball from the zombie slave." ) ); item ball( "pheromone", 0 ); - iuse::pheromone( &g->u, &ball, true, g->u.pos() ); + iuse::pheromone( &player_character, &ball, true, player_character.pos() ); } } void monexamine::tie_or_untie( monster &z ) { + Character &player_character = get_player_character(); if( z.has_effect( effect_tied ) ) { z.remove_effect( effect_tied ); if( z.tied_item ) { - g->u.i_add( *z.tied_item ); + player_character.i_add( *z.tied_item ); z.tied_item.reset(); } } else { - std::vector rope_inv = g->u.items_with( []( const item & itm ) { + std::vector rope_inv = player_character.items_with( []( const item & itm ) { return itm.has_flag( "TIE_UP" ); } ); if( rope_inv.empty() ) { @@ -713,12 +736,9 @@ void monexamine::tie_or_untie( monster &z ) return; } item *rope_item = rope_inv[index - 1]; - int item_pos = g->u.get_item_position( rope_item ); - if( item_pos != INT_MIN ) { - z.tied_item = cata::make_value( *rope_item ); - g->u.i_rem( item_pos ); - z.add_effect( effect_tied, 1_turns, num_bp, true ); - } + z.tied_item = cata::make_value( *rope_item ); + player_character.i_rem( rope_item ); + z.add_effect( effect_tied, 1_turns, num_bp, true ); } } @@ -732,13 +752,14 @@ void monexamine::milk_source( monster &source_mon ) } if( milkable_ammo->second > 0 ) { const int moves = to_moves( time_duration::from_minutes( milkable_ammo->second / 2 ) ); - g->u.assign_activity( ACT_MILK, moves, -1 ); - g->u.activity.coords.push_back( g->m.getabs( source_mon.pos() ) ); + Character &player_character = get_player_character(); + player_character.assign_activity( ACT_MILK, moves, -1 ); + player_character.activity.coords.push_back( get_map().getabs( source_mon.pos() ) ); // pin the cow in place if it isn't already bool temp_tie = !source_mon.has_effect( effect_tied ); if( temp_tie ) { source_mon.add_effect( effect_tied, 1_turns, num_bp, true ); - g->u.activity.str_values.push_back( "temp_tie" ); + player_character.activity.str_values.push_back( "temp_tie" ); } add_msg( _( "You milk the %s." ), source_mon.get_name() ); } else { diff --git a/src/monmove.cpp b/src/monmove.cpp index 3bf63ea95b2ef..c7b5f7c7cffcd 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -12,7 +12,6 @@ #include #include -#include "avatar.h" #include "behavior.h" #include "bionics.h" #include "cata_utility.h" @@ -36,7 +35,6 @@ #include "npc.h" #include "pathfinding.h" #include "pimpl.h" -#include "player.h" #include "rng.h" #include "scent_map.h" #include "sounds.h" @@ -116,25 +114,26 @@ static bool z_is_valid( int z ) bool monster::will_move_to( const tripoint &p ) const { - if( g->m.impassable( p ) ) { + map &here = get_map(); + if( here.impassable( p ) ) { if( digging() ) { - if( !g->m.has_flag( "BURROWABLE", p ) ) { + if( !here.has_flag( "BURROWABLE", p ) ) { return false; } - } else if( !( can_climb() && g->m.has_flag( "CLIMBABLE", p ) ) ) { + } else if( !( can_climb() && here.has_flag( "CLIMBABLE", p ) ) ) { return false; } } - if( ( !can_submerge() && !flies() ) && g->m.has_flag( TFLAG_DEEP_WATER, p ) ) { + if( ( !can_submerge() && !flies() ) && here.has_flag( TFLAG_DEEP_WATER, p ) ) { return false; } - if( digs() && !g->m.has_flag( "DIGGABLE", p ) && !g->m.has_flag( "BURROWABLE", p ) ) { + if( digs() && !here.has_flag( "DIGGABLE", p ) && !here.has_flag( "BURROWABLE", p ) ) { return false; } - if( has_flag( MF_AQUATIC ) && !g->m.has_flag( "SWIMMABLE", p ) ) { + if( has_flag( MF_AQUATIC ) && !here.has_flag( "SWIMMABLE", p ) ) { return false; } @@ -142,7 +141,7 @@ bool monster::will_move_to( const tripoint &p ) const return false; } - if( get_size() > creature_size::medium && g->m.has_flag_ter( TFLAG_SMALL_PASSAGE, p ) ) { + if( get_size() > creature_size::medium && here.has_flag_ter( TFLAG_SMALL_PASSAGE, p ) ) { return false; // if a large critter, can't move through tight passages } @@ -169,7 +168,7 @@ bool monster::will_move_to( const tripoint &p ) const // technically this will shortcut in evaluation from fire or fall // before hitting simple or complex but this is more explicit if( avoid_fire || avoid_fall || avoid_simple || avoid_complex ) { - const ter_id target = g->m.ter( p ); + const ter_id target = here.ter( p ); // Don't enter lava if we have any concept of heat being bad if( avoid_fire && target == t_lava ) { @@ -178,7 +177,7 @@ bool monster::will_move_to( const tripoint &p ) const if( avoid_fall ) { // Don't throw ourselves off cliffs if we have a concept of falling - if( !g->m.has_floor( p ) && !flies() ) { + if( !here.has_floor( p ) && !flies() ) { return false; } @@ -190,15 +189,15 @@ bool monster::will_move_to( const tripoint &p ) const } // Some things are only avoided if we're not attacking - if( attitude( &g->u ) != MATT_ATTACK ) { + if( attitude( &get_player_character() ) != MATT_ATTACK ) { // Sharp terrain is ignored while attacking - if( avoid_simple && g->m.has_flag( "SHARP", p ) && + if( avoid_simple && here.has_flag( "SHARP", p ) && !( type->size == creature_size::tiny || flies() ) ) { return false; } } - const field &target_field = g->m.field_at( p ); + const field &target_field = here.field_at( p ); // Higher awareness is needed for identifying these as threats. if( avoid_complex ) { @@ -207,8 +206,8 @@ bool monster::will_move_to( const tripoint &p ) const return false; } // Don't step on any traps (if we can see) - const trap &target_trap = g->m.tr_at( p ); - if( has_flag( MF_SEES ) && !target_trap.is_benign() && g->m.has_floor( p ) ) { + const trap &target_trap = here.tr_at( p ); + if( has_flag( MF_SEES ) && !target_trap.is_benign() && here.has_floor( p ) ) { return false; } } @@ -227,13 +226,17 @@ bool monster::will_move_to( const tripoint &p ) const bool monster::can_reach_to( const tripoint &p ) const { + map &here = get_map(); if( p.z > pos().z && z_is_valid( pos().z ) ) { - if( !g->m.has_flag( TFLAG_GOES_UP, pos() ) && !g->m.has_flag( TFLAG_NO_FLOOR, p ) ) { + if( here.has_flag( TFLAG_RAMP_UP, tripoint( p.xy(), p.z - 1 ) ) ) { + return true; + } + if( !here.has_flag( TFLAG_GOES_UP, pos() ) && !here.has_flag( TFLAG_NO_FLOOR, p ) ) { // can't go through the roof return false; } } else if( p.z < pos().z && z_is_valid( pos().z ) ) { - if( !g->m.has_flag( TFLAG_GOES_DOWN, pos() ) ) { + if( !here.has_flag( TFLAG_GOES_DOWN, pos() ) ) { // can't go through the floor // you would fall anyway if there was no floor, so no need to check for that here return false; @@ -322,12 +325,12 @@ void monster::plan() bool group_morale = has_flag( MF_GROUP_MORALE ) && morale < type->morale; bool swarms = has_flag( MF_SWARMS ); auto mood = attitude(); - + Character &player_character = get_player_character(); // If we can see the player, move toward them or flee, simpleminded animals are too dumb to follow the player. - if( friendly == 0 && sees( g->u ) && !has_flag( MF_PET_WONT_FOLLOW ) ) { - dist = rate_target( g->u, dist, smart_planning ); - fleeing = fleeing || is_fleeing( g->u ); - target = &g->u; + if( friendly == 0 && sees( player_character ) && !has_flag( MF_PET_WONT_FOLLOW ) ) { + dist = rate_target( player_character, dist, smart_planning ); + fleeing = fleeing || is_fleeing( player_character ); + target = &player_character; if( dist <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; @@ -352,7 +355,7 @@ void monster::plan() for( monster &tmp : g->all_monsters() ) { if( type->baby_monster == tmp.type->id ) { // baby nearby; is the player too close? - dist = tmp.rate_target( g->u, dist, smart_planning ); + dist = tmp.rate_target( player_character, dist, smart_planning ); if( dist <= 3 ) { //proximity to baby; monster gets furious and less likely to flee anger += angers_cub_threatened; @@ -500,11 +503,12 @@ void monster::plan() } } + map &here = get_map(); // Operating monster keep you safe while they operate, how nice.... if( type->has_special_attack( "OPERATE" ) ) { if( has_effect( effect_operating ) ) { friendly = 100; - for( auto critter : g->m.get_creatures_in_radius( pos(), 6 ) ) { + for( auto critter : here.get_creatures_in_radius( pos(), 6 ) ) { monster *mon = dynamic_cast( critter ); if( mon != nullptr && mon->type->in_species( species_ZOMBIE ) ) { anger = 100; @@ -522,9 +526,9 @@ void monster::plan() bool found_path_to_couch = false; tripoint tmp( pos() + point( 12, 12 ) ); tripoint couch_loc; - for( const auto &couch_pos : g->m.find_furnitures_with_flag_in_radius( pos(), 10, + for( const auto &couch_pos : here.find_furnitures_with_flag_in_radius( pos(), 10, flag_AUTODOC_COUCH ) ) { - if( g->m.clear_path( pos(), couch_pos, 10, 0, 100 ) ) { + if( here.clear_path( pos(), couch_pos, 10, 0, 100 ) ) { if( rl_dist( pos(), couch_pos ) < rl_dist( pos(), tmp ) ) { tmp = couch_pos; found_path_to_couch = true; @@ -559,9 +563,9 @@ void monster::plan() } else if( friendly > 0 && one_in( 3 ) ) { // Grow restless with no targets friendly--; - } else if( friendly < 0 && sees( g->u ) ) { - if( rl_dist( pos(), g->u.pos() ) > 2 ) { - set_dest( g->u.pos() ); + } else if( friendly < 0 && sees( player_character ) ) { + if( rl_dist( pos(), player_character.pos() ) > 2 ) { + set_dest( player_character.pos() ); } else { unset_dest(); } @@ -594,15 +598,16 @@ static float get_stagger_adjust( const tripoint &source, const tripoint &destina */ bool monster::is_aquatic_danger( const tripoint &at_pos ) { - return g->m.has_flag_ter( TFLAG_DEEP_WATER, at_pos ) && g->m.has_flag( flag_LIQUID, at_pos ) && - can_drown() && !g->m.veh_at( at_pos ).part_with_feature( "BOARDABLE", false ); + map &here = get_map(); + return here.has_flag_ter( TFLAG_DEEP_WATER, at_pos ) && here.has_flag( flag_LIQUID, at_pos ) && + can_drown() && !here.veh_at( at_pos ).part_with_feature( "BOARDABLE", false ); } bool monster::die_if_drowning( const tripoint &at_pos, const int chance ) { if( is_aquatic_danger( at_pos ) && one_in( chance ) ) { die( nullptr ); - if( g->u.sees( at_pos ) ) { + if( get_player_character().sees( at_pos ) ) { add_msg( _( "The %s drowns!" ), name() ); } return true; @@ -629,6 +634,8 @@ void monster::move() die( nullptr ); return; } + map &here = get_map(); + Character &player_character = get_player_character(); behavior::monster_oracle_t oracle( this ); behavior::tree goals; @@ -638,12 +645,12 @@ void monster::move() //If there are. Consume them. // TODO: Stick this in a map and dispatch to it via the action string. if( action == "consume_items" ) { - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( _( "The %s flows around the objects on the floor and they are quickly dissolved!" ), name() ); } static const auto volume_per_hp = 250_ml; - for( item &elem : g->m.i_at( pos() ) ) { + for( item &elem : here.i_at( pos() ) ) { hp += elem.volume() / volume_per_hp; // Yeah this means it can get more HP than normal. if( has_flag( MF_ABSORBS_SPLITS ) ) { while( hp / 2 > type->hp ) { @@ -654,13 +661,13 @@ void monster::move() hp -= type->hp; //this is a new copy of the monster. Ideally we should copy the stats/effects that affect the parent spawn->make_ally( *this ); - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( _( "The %s splits in two!" ), name() ); } } } } - g->m.i_clear( pos() ); + here.i_clear( pos() ); } else if( action == "eat_crop" ) { // TODO: Create a special attacks whitelist unordered map instead of an if chain. std::map::const_iterator attack = @@ -672,7 +679,7 @@ void monster::move() } } // record position before moving to put the player there if we're dragging - tripoint drag_to = g->m.getabs( pos() ); + tripoint drag_to = here.getabs( pos() ); const bool pacified = has_effect( effect_pacified ); @@ -715,8 +722,8 @@ void monster::move() nursebot_operate( dragged_foe ); // The monster can sometimes hang in air due to last fall being blocked - if( !flies() && g->m.has_flag( TFLAG_NO_FLOOR, pos() ) ) { - g->m.creature_on_trap( *this, false ); + if( !flies() && here.has_flag( TFLAG_NO_FLOOR, pos() ) ) { + here.creature_on_trap( *this, false ); if( is_dead() ) { return; } @@ -751,8 +758,8 @@ void monster::move() } // don't move if a passenger in a moving vehicle - auto vp = g->m.veh_at( pos() ); - bool harness_part = static_cast( g->m.veh_at( pos() ).part_with_feature( "ANIMAL_CTRL", + auto vp = here.veh_at( pos() ); + bool harness_part = static_cast( here.veh_at( pos() ).part_with_feature( "ANIMAL_CTRL", true ) ); if( vp && vp->vehicle().is_moving() && vp->vehicle().get_pet( vp->part_index() ) ) { moves = 0; @@ -768,8 +775,8 @@ void monster::move() // Set attitude to attitude to our current target monster_attitude current_attitude = attitude( nullptr ); if( !wander() ) { - if( goal == g->u.pos() ) { - current_attitude = attitude( &g->u ); + if( goal == player_character.pos() ) { + current_attitude = attitude( &player_character ); } else { for( const npc &guy : g->all_npcs() ) { if( goal == guy.pos() ) { @@ -800,7 +807,7 @@ void monster::move() if( pf_settings.max_dist >= rl_dist( pos(), goal ) && ( path.empty() || rl_dist( pos(), path.front() ) >= 2 || path.back() != goal ) ) { // We need a new path - path = g->m.route( pos(), goal, pf_settings, get_path_avoid() ); + path = here.route( pos(), goal, pf_settings, get_path_avoid() ); } // Try to respect old paths, even if we can't pathfind at the moment @@ -832,7 +839,7 @@ void monster::move() } } - if( !g->m.has_zlevels() ) { + if( !here.has_zlevels() ) { // Otherwise weird things happen destination.z = posz(); } @@ -865,19 +872,28 @@ void monster::move() // This is a float and using trig_dist() because that Does the Right Thing(tm) // in both circular and roguelike distance modes. const float distance_to_target = trig_dist( pos(), destination ); - for( const tripoint &candidate : squares_closer_to( pos(), destination ) ) { - tripoint candidate_abs = g->m.getabs( candidate ); + for( tripoint &candidate : squares_closer_to( pos(), destination ) ) { + bool via_ramp = false; + if( here.has_flag( TFLAG_RAMP_UP, candidate ) ) { + via_ramp = true; + candidate.z += 1; + } else if( here.has_flag( TFLAG_RAMP_DOWN, candidate ) ) { + via_ramp = true; + candidate.z -= 1; + } + tripoint candidate_abs = get_map().getabs( candidate ); + if( candidate.z != posz() ) { bool can_z_move = true; - if( !g->m.valid_move( pos(), candidate, false, true ) ) { + if( !here.valid_move( pos(), candidate, false, true, via_ramp ) ) { // Can't phase through floor can_z_move = false; } // If we're trying to go up but can't fly, check if we can climb. If we can't, then don't // This prevents non-climb/fly enemies running up walls - if( candidate.z > posz() && !flies() ) { - if( !can_climb() || !g->m.has_floor_or_support( candidate ) ) { + if( candidate.z > posz() && !( via_ramp || flies() ) ) { + if( !can_climb() || !here.has_floor_or_support( candidate ) ) { // Can't "jump" up a whole z-level can_z_move = false; } @@ -890,7 +906,7 @@ void monster::move() posy() / ( SEEY * 2 ) == candidate.y / ( SEEY * 2 ) ) { const tripoint &upper = candidate.z > posz() ? candidate : pos(); const tripoint &lower = candidate.z > posz() ? pos() : candidate; - if( g->m.has_flag( TFLAG_GOES_DOWN, upper ) && g->m.has_flag( TFLAG_GOES_UP, lower ) ) { + if( here.has_flag( TFLAG_GOES_DOWN, upper ) && here.has_flag( TFLAG_GOES_UP, lower ) ) { can_z_move = true; } } @@ -931,7 +947,7 @@ void monster::move() if( !can_bash ) { continue; } - const int estimate = g->m.bash_rating( bash_estimate(), candidate ); + const int estimate = here.bash_rating( bash_estimate(), candidate ); if( estimate <= 0 ) { continue; } @@ -963,10 +979,10 @@ void monster::move() // Finished logic section. By this point, we should have chosen a square to // move to (moved = true). if( moved ) { // Actual effects of moving to the square we've chosen - const tripoint local_next_step = g->m.getlocal( next_step ); + const tripoint local_next_step = here.getlocal( next_step ); const bool did_something = ( !pacified && attack_at( local_next_step ) ) || - ( !pacified && can_open_doors && g->m.open_door( local_next_step, !g->m.is_outside( pos() ) ) ) || + ( !pacified && can_open_doors && here.open_door( local_next_step, !here.is_outside( pos() ) ) ) || ( !pacified && bash_at( local_next_step ) ) || ( !pacified && push_to( local_next_step, 0, 0 ) ) || move_to( local_next_step, false, false, get_stagger_adjust( pos(), destination, local_next_step ) ); @@ -979,9 +995,9 @@ void monster::move() if( !dragged_foe->has_effect( effect_grabbed ) ) { dragged_foe = nullptr; remove_effect( effect_dragging ); - } else if( g->m.getlocal( drag_to ) != pos() && - g->critter_at( g->m.getlocal( drag_to ) ) == nullptr ) { - dragged_foe->setpos( g->m.getlocal( drag_to ) ); + } else if( here.getlocal( drag_to ) != pos() && + g->critter_at( here.getlocal( drag_to ) ) == nullptr ) { + dragged_foe->setpos( here.getlocal( drag_to ) ); } } } else { @@ -1026,7 +1042,7 @@ void monster::nursebot_operate( player *dragged_foe ) return; } - if( rl_dist( pos(), goal ) == 1 && !g->m.has_flag_furn( flag_AUTODOC_COUCH, goal ) && + if( rl_dist( pos(), goal ) == 1 && !get_map().has_flag_furn( flag_AUTODOC_COUCH, goal ) && !has_effect( effect_operating ) ) { if( dragged_foe->has_effect( effect_grabbed ) && !has_effect( effect_countdown ) && ( g->critter_at( goal ) == nullptr || g->critter_at( goal ) == dragged_foe ) ) { @@ -1057,7 +1073,7 @@ void monster::nursebot_operate( player *dragged_foe ) const float adjusted_skill = static_cast( 77 ) - std::min( static_cast( 40 ), static_cast( 77 ) - static_cast( 77 ) / static_cast( 10.0 ) ); - g->u.uninstall_bionic( target_cbm, *this, *dragged_foe, adjusted_skill ); + get_player_character().uninstall_bionic( target_cbm, *this, *dragged_foe, adjusted_skill ); dragged_foe->remove_effect( effect_grabbed ); remove_effect( effect_dragging ); @@ -1106,7 +1122,7 @@ void monster::footsteps( const tripoint &p ) if( volume == 0 ) { return; } - int dist = rl_dist( p, g->u.pos() ); + int dist = rl_dist( p, get_player_character().pos() ); sounds::add_footstep( p, volume, dist, this, type->get_footsteps() ); } @@ -1129,7 +1145,8 @@ tripoint monster::scent_move() smell_threshold = 400; } - const bool fleeing = is_fleeing( g->u ); + Character &player_character = get_player_character(); + const bool fleeing = is_fleeing( player_character ); if( fleeing ) { bestsmell = g->scent.get( pos() ); } @@ -1140,7 +1157,8 @@ tripoint monster::scent_move() return next; } const bool can_bash = bash_skill() > 0; - for( const auto &dest : g->m.points_in_radius( pos(), 1, SCENT_MAP_Z_REACH ) ) { + map &here = get_map(); + for( const auto &dest : here.points_in_radius( pos(), 1, SCENT_MAP_Z_REACH ) ) { int smell = g->scent.get( dest ); const scenttype_id &type_scent = g->scent.get_type( dest ); @@ -1168,9 +1186,9 @@ tripoint monster::scent_move() if( ( !fleeing && smell < bestsmell ) || ( fleeing && smell > bestsmell ) || !right_scent ) { continue; } - if( g->m.valid_move( pos(), dest, can_bash, true ) && - ( can_move_to( dest ) || ( dest == g->u.pos() ) || - ( can_bash && g->m.bash_rating( bash_estimate(), dest ) > 0 ) ) ) { + if( here.valid_move( pos(), dest, can_bash, true ) && + ( can_move_to( dest ) || ( dest == player_character.pos() ) || + ( can_bash && here.bash_rating( bash_estimate(), dest ) > 0 ) ) ) { if( ( !fleeing && smell > bestsmell ) || ( fleeing && smell < bestsmell ) ) { smoves.clear(); smoves.push_back( dest ); @@ -1188,46 +1206,47 @@ int monster::calc_movecost( const tripoint &f, const tripoint &t ) const { int movecost = 0; - const int source_cost = g->m.move_cost( f ); - const int dest_cost = g->m.move_cost( t ); + map &here = get_map(); + const int source_cost = here.move_cost( f ); + const int dest_cost = here.move_cost( t ); // Digging and flying monsters ignore terrain cost - if( flies() || ( digging() && g->m.has_flag( "DIGGABLE", t ) ) ) { + if( flies() || ( digging() && here.has_flag( "DIGGABLE", t ) ) ) { movecost = 100; // Swimming monsters move super fast in water } else if( swims() ) { - if( g->m.has_flag( "SWIMMABLE", f ) ) { + if( here.has_flag( "SWIMMABLE", f ) ) { movecost += 25; } else { - movecost += 50 * g->m.move_cost( f ); + movecost += 50 * here.move_cost( f ); } - if( g->m.has_flag( "SWIMMABLE", t ) ) { + if( here.has_flag( "SWIMMABLE", t ) ) { movecost += 25; } else { - movecost += 50 * g->m.move_cost( t ); + movecost += 50 * here.move_cost( t ); } } else if( can_submerge() ) { // No-breathe monsters have to walk underwater slowly - if( g->m.has_flag( "SWIMMABLE", f ) ) { + if( here.has_flag( "SWIMMABLE", f ) ) { movecost += 250; } else { - movecost += 50 * g->m.move_cost( f ); + movecost += 50 * here.move_cost( f ); } - if( g->m.has_flag( "SWIMMABLE", t ) ) { + if( here.has_flag( "SWIMMABLE", t ) ) { movecost += 250; } else { - movecost += 50 * g->m.move_cost( t ); + movecost += 50 * here.move_cost( t ); } movecost /= 2; } else if( climbs() ) { - if( g->m.has_flag( "CLIMBABLE", f ) ) { + if( here.has_flag( "CLIMBABLE", f ) ) { movecost += 150; } else { - movecost += 50 * g->m.move_cost( f ); + movecost += 50 * here.move_cost( f ); } - if( g->m.has_flag( "CLIMBABLE", t ) ) { + if( here.has_flag( "CLIMBABLE", t ) ) { movecost += 150; } else { - movecost += 50 * g->m.move_cost( t ); + movecost += 50 * here.move_cost( t ); } movecost /= 2; } else { @@ -1243,8 +1262,9 @@ int monster::calc_climb_cost( const tripoint &f, const tripoint &t ) const return 100; } - if( climbs() && !g->m.has_flag( TFLAG_NO_FLOOR, t ) ) { - const int diff = g->m.climb_difficulty( f ); + map &here = get_map(); + if( climbs() && !here.has_flag( TFLAG_NO_FLOOR, t ) ) { + const int diff = here.climb_difficulty( f ); if( diff <= 10 ) { return 150; } @@ -1306,14 +1326,15 @@ bool monster::bash_at( const tripoint &p ) return false; } - bool can_bash = g->m.is_bashable( p ) && bash_skill() > 0; + map &here = get_map(); + bool can_bash = here.is_bashable( p ) && bash_skill() > 0; if( !can_bash ) { return false; } - bool flat_ground = g->m.has_flag( "ROAD", p ) || g->m.has_flag( "FLAT", p ); + bool flat_ground = here.has_flag( "ROAD", p ) || here.has_flag( "FLAT", p ); if( flat_ground ) { - bool can_bash_ter = g->m.is_bashable_ter( p ); + bool can_bash_ter = here.is_bashable_ter( p ); bool try_bash_ter = one_in( 50 ); if( !( can_bash_ter && try_bash_ter ) ) { return false; @@ -1321,7 +1342,7 @@ bool monster::bash_at( const tripoint &p ) } int bashskill = group_bash_skill( p ); - g->m.bash( p, bashskill ); + here.bash( p, bashskill ); moves -= 100; return true; } @@ -1394,8 +1415,9 @@ bool monster::attack_at( const tripoint &p ) return false; } - if( p == g->u.pos() ) { - melee_attack( g->u ); + Character &player_character = get_player_character(); + if( p == player_character.pos() ) { + melee_attack( player_character ); return true; } @@ -1439,8 +1461,9 @@ bool monster::attack_at( const tripoint &p ) static tripoint find_closest_stair( const tripoint &near_this, const ter_bitflags stair_type ) { - for( const tripoint &candidate : closest_tripoints_first( near_this, 10 ) ) { - if( g->m.has_flag( stair_type, candidate ) ) { + map &here = get_map(); + for( const tripoint &candidate : closest_points_first( near_this, 10 ) ) { + if( here.has_flag( stair_type, candidate ) ) { return candidate; } } @@ -1457,38 +1480,40 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, const bool going_up = p.z > pos().z; tripoint destination = p; + map &here = get_map(); // This is stair teleportation hackery. // TODO: Remove this in favor of stair alignment if( going_up ) { - if( g->m.has_flag( TFLAG_GOES_UP, pos() ) ) { + if( here.has_flag( TFLAG_GOES_UP, pos() ) ) { destination = find_closest_stair( p, TFLAG_GOES_DOWN ); } } else if( z_move ) { - if( g->m.has_flag( TFLAG_GOES_DOWN, pos() ) ) { + if( here.has_flag( TFLAG_GOES_DOWN, pos() ) ) { destination = find_closest_stair( p, TFLAG_GOES_UP ); } } + Character &player_character = get_player_character(); // Allows climbing monsters to move on terrain with movecost <= 0 Creature *critter = g->critter_at( destination, is_hallucination() ); - if( g->m.has_flag( "CLIMBABLE", destination ) ) { - if( g->m.impassable( destination ) && critter == nullptr ) { + if( here.has_flag( "CLIMBABLE", destination ) ) { + if( here.impassable( destination ) && critter == nullptr ) { if( flies() ) { moves -= 100; force = true; - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( _( "The %1$s flies over the %2$s." ), name(), - g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ) : - g->m.tername( p ) ); + here.has_flag_furn( "CLIMBABLE", p ) ? here.furnname( p ) : + here.tername( p ) ); } } else if( climbs() ) { moves -= 150; force = true; - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( _( "The %1$s climbs over the %2$s." ), name(), - g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ) : - g->m.tername( p ) ); + here.has_flag_furn( "CLIMBABLE", p ) ? here.furnname( p ) : + here.tername( p ) ); } } } @@ -1510,7 +1535,7 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, // Note: Keep this as float here or else it will cancel valid moves const float cost = stagger_adjustment * static_cast( climbs() && - g->m.has_flag( TFLAG_NO_FLOOR, p ) ? calc_climb_cost( pos(), destination ) : calc_movecost( pos(), + here.has_flag( TFLAG_NO_FLOOR, p ) ? calc_climb_cost( pos(), destination ) : calc_movecost( pos(), destination ) ); if( cost > 0.0f ) { moves -= static_cast( std::ceil( cost ) ); @@ -1520,28 +1545,28 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, } //Check for moving into/out of water - bool was_water = g->m.is_divable( pos() ); - bool will_be_water = on_ground && can_submerge() && g->m.is_divable( destination ); + bool was_water = here.is_divable( pos() ); + bool will_be_water = on_ground && can_submerge() && here.is_divable( destination ); //Birds and other flying creatures flying over the deep water terrain - if( was_water && flies() && g->u.sees( *this ) ) { + if( was_water && flies() && player_character.sees( *this ) ) { if( one_in( 4 ) ) { add_msg( m_warning, _( "A %1$s flies over the %2$s!" ), name(), - g->m.tername( pos() ) ); + here.tername( pos() ) ); } - } else if( was_water && !will_be_water && g->u.sees( *this ) ) { + } else if( was_water && !will_be_water && player_character.sees( *this ) ) { // Use more dramatic messages for swimming monsters //~ Message when a monster emerges from water //~ %1$s: monster name, %2$s: leaps/emerges, %3$s: terrain name add_msg( m_warning, pgettext( "monster movement", "A %1$s %2$s from the %3$s!" ), name(), swims() || has_flag( MF_AQUATIC ) ? _( "leaps" ) : _( "emerges" ), - g->m.tername( pos() ) ); - } else if( !was_water && will_be_water && g->u.sees( *this ) ) { + here.tername( pos() ) ); + } else if( !was_water && will_be_water && player_character.sees( *this ) ) { //~ Message when a monster enters water //~ %1$s: monster name, %2$s: dives/sinks, %3$s: terrain name add_msg( m_warning, pgettext( "monster movement", "A %1$s %2$s into the %3$s!" ), name(), swims() || has_flag( MF_AQUATIC ) ? _( "dives" ) : _( "sinks" ), - g->m.tername( destination ) ); + here.tername( destination ) ); } setpos( destination ); @@ -1555,37 +1580,37 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, if( type->size != creature_size::tiny && on_ground ) { const int sharp_damage = rng( 1, 10 ); const int rough_damage = rng( 1, 2 ); - if( g->m.has_flag( "SHARP", pos() ) && !one_in( 4 ) && + if( here.has_flag( "SHARP", pos() ) && !one_in( 4 ) && get_armor_cut( bodypart_id( "torso" ) ) < sharp_damage ) { apply_damage( nullptr, bodypart_id( "torso" ), sharp_damage ); } - if( g->m.has_flag( "ROUGH", pos() ) && one_in( 6 ) && + if( here.has_flag( "ROUGH", pos() ) && one_in( 6 ) && get_armor_cut( bodypart_id( "torso" ) ) < rough_damage ) { apply_damage( nullptr, bodypart_id( "torso" ), rough_damage ); } } - if( g->m.has_flag( "UNSTABLE", destination ) && on_ground ) { + if( here.has_flag( "UNSTABLE", destination ) && on_ground ) { add_effect( effect_bouldering, 1_turns, num_bp, true ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } - if( g->m.has_flag_ter_or_furn( TFLAG_NO_SIGHT, destination ) && on_ground ) { + if( here.has_flag_ter_or_furn( TFLAG_NO_SIGHT, destination ) && on_ground ) { add_effect( effect_no_sight, 1_turns, num_bp, true ); } else if( has_effect( effect_no_sight ) ) { remove_effect( effect_no_sight ); } - g->m.creature_on_trap( *this ); + here.creature_on_trap( *this ); if( is_dead() ) { return true; } if( !will_be_water && ( digs() || can_dig() ) ) { - underwater = g->m.has_flag( "DIGGABLE", pos() ); + underwater = here.has_flag( "DIGGABLE", pos() ); } // Diggers turn the dirt into dirtmound - if( digging() && g->m.has_flag( "DIGGABLE", pos() ) ) { + if( digging() && here.has_flag( "DIGGABLE", pos() ) ) { int factor = 0; switch( type->size ) { case creature_size::tiny: @@ -1606,26 +1631,26 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, } // TODO: make this take terrain type into account so diggers traveling under sand will create mounds of sand etc. if( one_in( factor ) ) { - g->m.ter_set( pos(), t_dirtmound ); + here.ter_set( pos(), t_dirtmound ); } } // Acid trail monsters leave... a trail of acid if( has_flag( MF_ACIDTRAIL ) ) { - g->m.add_field( pos(), fd_acid, 3 ); + here.add_field( pos(), fd_acid, 3 ); } // Not all acid trail monsters leave as much acid. Every time this monster takes a step, there is a 1/5 chance it will drop a puddle. if( has_flag( MF_SHORTACIDTRAIL ) ) { if( one_in( 5 ) ) { - g->m.add_field( pos(), fd_acid, 3 ); + here.add_field( pos(), fd_acid, 3 ); } } if( has_flag( MF_SLUDGETRAIL ) ) { - for( const tripoint &sludge_p : g->m.points_in_radius( pos(), 1 ) ) { + for( const tripoint &sludge_p : here.points_in_radius( pos(), 1 ) ) { const int fstr = 3 - ( std::abs( sludge_p.x - posx() ) + std::abs( sludge_p.y - posy() ) ); if( fstr >= 2 ) { - g->m.add_field( sludge_p, fd_sludge, fstr ); + here.add_field( sludge_p, fd_sludge, fstr ); } } } @@ -1634,7 +1659,7 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, if( one_in( 10 ) ) { // if it has more napalm, drop some and reduce ammo in tank if( ammo[itype_pressurized_tank] > 0 ) { - g->m.add_item_or_charges( pos(), item( "napalm", calendar::turn, 50 ) ); + here.add_item_or_charges( pos(), item( "napalm", calendar::turn, 50 ) ); ammo[itype_pressurized_tank] -= 50; } else { // TODO: remove MF_DRIPS_NAPALM flag since no more napalm in tank @@ -1645,7 +1670,7 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, if( has_flag( MF_DRIPS_GASOLINE ) ) { if( one_in( 5 ) ) { // TODO: use same idea that limits napalm dripping - g->m.add_item_or_charges( pos(), item( "gasoline" ) ); + here.add_item_or_charges( pos(), item( "gasoline" ) ); } } return true; @@ -1687,7 +1712,8 @@ bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) return false; } - const int movecost_from = 50 * g->m.move_cost( p ); + map &here = get_map(); + const int movecost_from = 50 * here.move_cost( p ); const int movecost_attacker = std::max( movecost_from, 200 - 10 * ( attack - defend ) ); const tripoint dir = p - pos(); @@ -1707,10 +1733,10 @@ bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) } tripoint dest( p + d ); - const int dest_movecost_from = 50 * g->m.move_cost( dest ); + const int dest_movecost_from = 50 * here.move_cost( dest ); // Pushing into cars/windows etc. is harder - const int movecost_penalty = g->m.move_cost( dest ) - 2; + const int movecost_penalty = here.move_cost( dest ) - 2; if( movecost_penalty <= -2 ) { // Can't push into unpassable terrain continue; @@ -1768,8 +1794,9 @@ bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) g->swap_critters( *critter, *this ); critter->add_effect( effect_stunned, rng( 0_turns, 2_turns ) ); + Character &player_character = get_player_character(); // Only print the message when near player or it can get spammy - if( rl_dist( g->u.pos(), pos() ) < 4 && g->u.sees( *critter ) ) { + if( rl_dist( player_character.pos(), pos() ) < 4 && player_character.sees( *critter ) ) { add_msg( m_warning, _( "The %1$s tramples %2$s" ), name(), critter->disp_name() ); } @@ -1794,18 +1821,25 @@ void monster::stumble() return; } + map &here = get_map(); std::vector valid_stumbles; valid_stumbles.reserve( 11 ); const bool avoid_water = has_flag( MF_NO_BREATHE ) && !swims() && !has_flag( MF_AQUATIC ); - for( const tripoint &dest : g->m.points_in_radius( pos(), 1 ) ) { + for( const tripoint &dest : here.points_in_radius( pos(), 1 ) ) { if( dest != pos() ) { - valid_stumbles.push_back( dest ); + if( here.has_flag( TFLAG_RAMP_DOWN, dest ) ) { + valid_stumbles.push_back( tripoint( dest.xy(), dest.z - 1 ) ); + } else if( here.has_flag( TFLAG_RAMP_UP, dest ) ) { + valid_stumbles.push_back( tripoint( dest.xy(), dest.z + 1 ) ); + } else { + valid_stumbles.push_back( dest ); + } } } - if( g->m.has_zlevels() ) { + if( here.has_zlevels() ) { tripoint below( posx(), posy(), posz() - 1 ); - if( g->m.valid_move( pos(), below, false, true ) ) { + if( here.valid_move( pos(), below, false, true ) ) { valid_stumbles.push_back( below ); } } @@ -1816,8 +1850,8 @@ void monster::stumble() //(Unless they can swim/are aquatic) //But let them wander OUT of water if they are there. !( avoid_water && - g->m.has_flag( TFLAG_SWIMMABLE, dest ) && - !g->m.has_flag( TFLAG_SWIMMABLE, pos() ) ) && + here.has_flag( TFLAG_SWIMMABLE, dest ) && + !here.has_flag( TFLAG_SWIMMABLE, pos() ) ) && ( g->critter_at( dest, is_hallucination() ) == nullptr ) ) { if( move_to( dest, true, false ) ) { break; @@ -1837,7 +1871,7 @@ void monster::knock_back_to( const tripoint &to ) return; } - bool u_see = g->u.sees( to ); + bool u_see = get_player_character().sees( to ); // First, see if we hit another monster if( monster *const z = g->critter_at( to ) ) { @@ -1883,14 +1917,15 @@ void monster::knock_back_to( const tripoint &to ) } } - if( g->m.impassable( to ) ) { + map &here = get_map(); + if( here.impassable( to ) ) { // It's some kind of wall. apply_damage( nullptr, bodypart_id( "torso" ), static_cast( type->size ) ); add_effect( effect_stunned, 2_turns ); if( u_see ) { add_msg( _( "The %1$s bounces off a %2$s." ), name(), - g->m.obstacle_name( to ) ); + here.obstacle_name( to ) ); } } else { // It's no wall @@ -1907,7 +1942,7 @@ void monster::knock_back_to( const tripoint &to ) */ bool monster::will_reach( const point &p ) { - monster_attitude att = attitude( &g->u ); + monster_attitude att = attitude( &get_player_character() ); if( att != MATT_FOLLOW && att != MATT_ATTACK && att != MATT_FRIEND ) { return false; } @@ -1920,7 +1955,7 @@ bool monster::will_reach( const point &p ) return false; } - auto path = g->m.route( pos(), tripoint( p, posz() ), get_pathfinding_settings() ); + auto path = get_map().route( pos(), tripoint( p, posz() ), get_pathfinding_settings() ); if( path.empty() ) { return false; } @@ -1944,8 +1979,9 @@ bool monster::will_reach( const point &p ) int monster::turns_to_reach( const point &p ) { + map &here = get_map(); // HACK: This function is a(n old) temporary hack that should soon be removed - auto path = g->m.route( pos(), tripoint( p, posz() ), get_pathfinding_settings() ); + auto path = here.route( pos(), tripoint( p, posz() ), get_pathfinding_settings() ); if( path.empty() ) { return 999; } @@ -1953,7 +1989,7 @@ int monster::turns_to_reach( const point &p ) double turns = 0.; for( size_t i = 0; i < path.size(); i++ ) { const tripoint &next = path[i]; - if( g->m.impassable( next ) ) { + if( here.impassable( next ) ) { // No bashing through, it looks stupid when you go back and find // the doors intact. return 999; @@ -1970,8 +2006,9 @@ int monster::turns_to_reach( const point &p ) void monster::shove_vehicle( const tripoint &remote_destination, const tripoint &nearby_destination ) { + map &here = get_map(); if( this->has_flag( MF_PUSH_VEH ) ) { - auto vp = g->m.veh_at( nearby_destination ); + auto vp = here.veh_at( nearby_destination ); if( vp ) { vehicle &veh = vp->vehicle(); const units::mass veh_mass = veh.total_mass(); @@ -2015,10 +2052,10 @@ void monster::shove_vehicle( const tripoint &remote_destination, break; } if( shove_velocity > 0 ) { - if( g->u.sees( this->pos() ) ) { + if( get_player_character().sees( this->pos() ) ) { //~ %1$s - monster name, %2$s - vehicle name - g->u.add_msg_if_player( m_bad, _( "%1$s shoves %2$s out of their way!" ), this->disp_name(), - veh.disp_name() ); + add_msg( m_bad, _( "%1$s shoves %2$s out of their way!" ), this->disp_name(), + veh.disp_name() ); } int shove_moves = shove_veh_mass_moves_factor * veh_mass / 10_kilogram; shove_moves = std::max( shove_moves, shove_moves_minimal ); @@ -2033,10 +2070,10 @@ void monster::shove_vehicle( const tripoint &remote_destination, if( shove_destination.z != 0 ) { veh.vertical_velocity = shove_destination.z < 0 ? -shove_velocity : +shove_velocity; } - g->m.move_vehicle( veh, shove_destination, veh.face ); + here.move_vehicle( veh, shove_destination, veh.face ); } veh.move = tileray( destination_delta.xy() ); - veh.smash( g->m, shove_damage_min, shove_damage_max, 0.10F ); + veh.smash( here, shove_damage_min, shove_damage_max, 0.10F ); } } } diff --git a/src/monster.cpp b/src/monster.cpp index c1bdc725fb615..be92a588ef758 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -6,7 +6,6 @@ #include #include -#include "avatar.h" #include "character.h" #include "compatibility.h" #include "coordinate_conversions.h" @@ -45,7 +44,6 @@ #include "output.h" #include "overmapbuffer.h" #include "pimpl.h" -#include "player.h" #include "projectile.h" #include "rng.h" #include "sounds.h" @@ -437,6 +435,7 @@ void monster::try_reproduce() } } + map &here = get_map(); // add a decreasing chance of additional spawns when "catching up" an existing animal int chance = -1; while( true ) { @@ -460,9 +459,9 @@ void monster::try_reproduce() if( season_match && female && one_in( chance ) ) { int spawn_cnt = rng( 1, type->baby_count ); if( type->baby_monster ) { - g->m.add_spawn( type->baby_monster, spawn_cnt, pos() ); + here.add_spawn( type->baby_monster, spawn_cnt, pos() ); } else { - g->m.add_item_or_charges( pos(), item( type->baby_egg, *baby_timer, spawn_cnt ), true ); + here.add_item_or_charges( pos(), item( type->baby_egg, *baby_timer, spawn_cnt ), true ); } } @@ -514,6 +513,7 @@ void monster::try_biosignature() if( !biosig_timer ) { biosig_timer.emplace( calendar::turn + *type->biosig_timer ); } + map &here = get_map(); int counter = 0; while( true ) { // don't catch up too much, otherwise on some scenarios, @@ -521,7 +521,7 @@ void monster::try_biosignature() if( *biosig_timer > calendar::turn || counter > 50 ) { return; } - g->m.add_item_or_charges( pos(), item( type->biosig_item, *biosig_timer, 1 ), true ); + here.add_item_or_charges( pos(), item( type->biosig_item, *biosig_timer, 1 ), true ); *biosig_timer += *type->biosig_timer; counter += 1; } @@ -603,7 +603,7 @@ void monster::get_HP_Bar( nc_color &color, std::string &text ) const std::pair monster::get_attitude() const { - const auto att = attitude_names.at( attitude( &g->u ) ); + const auto att = attitude_names.at( attitude( &get_player_character() ) ); return { _( att.first ), all_colors.get( att.second ) @@ -661,9 +661,10 @@ int monster::print_info( const catacurses::window &w, int vStart, int vLines, in mvwprintz( w, point( column, ++vStart ), att.second, att.first ); // Awareness indicator in the third line. - std::string senses_str = sees( g->u ) ? _( "Can see to your current location" ) : + bool sees_player = sees( get_player_character() ); + std::string senses_str = sees_player ? _( "Can see to your current location" ) : _( "Can't see to your current location" ); - mvwprintz( w, point( column, ++vStart ), sees( g->u ) ? c_red : c_green, senses_str ); + mvwprintz( w, point( column, ++vStart ), sees_player ? c_red : c_green, senses_str ); // Monster description on following lines. std::vector lines = foldstring( type->get_description(), max_width ); @@ -784,8 +785,7 @@ std::string monster::extended_description() const describe_flags( _( "In fight it can %s." ), { {m_flag::MF_GRABS, pgettext( "Grab as an action", "grab" )}, {m_flag::MF_VENOM, pgettext( "Poison as an action", "poison" )}, - {m_flag::MF_PARALYZE, pgettext( "Paralyze as an action", "paralyze" )}, - {m_flag::MF_BLEED, _( "cause bleed" )} + {m_flag::MF_PARALYZE, pgettext( "Paralyze as an action", "paralyze" )} } ); if( !type->has_flag( m_flag::MF_NOHEAD ) ) { @@ -982,7 +982,7 @@ Creature *monster::attack_target() return target; } -bool monster::is_fleeing( player &u ) const +bool monster::is_fleeing( Character &u ) const { if( effect_cache[FLEEING] ) { return true; @@ -997,7 +997,7 @@ bool monster::is_fleeing( player &u ) const Creature::Attitude monster::attitude_to( const Creature &other ) const { const monster *m = other.is_monster() ? static_cast< const monster *>( &other ) : nullptr; - const player *p = other.as_player(); + const Character *p = other.as_character(); if( m != nullptr ) { if( m == this ) { return Attitude::FRIENDLY; @@ -1020,7 +1020,7 @@ Creature::Attitude monster::attitude_to( const Creature &other ) const return Attitude::HOSTILE; } } else if( p != nullptr ) { - switch( attitude( const_cast( p ) ) ) { + switch( attitude( p ) ) { case MATT_FRIEND: return Attitude::FRIENDLY; case MATT_FPASSIVE: @@ -1045,16 +1045,19 @@ monster_attitude monster::attitude( const Character *u ) const if( has_effect( effect_docile ) ) { return MATT_FPASSIVE; } - if( u == &g->u ) { - return MATT_FRIEND; - } - // Zombies don't understand not attacking NPCs, but dogs and bots should. - const npc *np = dynamic_cast< const npc * >( u ); - if( np != nullptr && np->get_attitude() != NPCATT_KILL && !type->in_species( species_ZOMBIE ) ) { - return MATT_FRIEND; - } - if( np != nullptr && np->is_hallucination() ) { - return MATT_IGNORE; + if( u != nullptr ) { + if( u->is_avatar() ) { + return MATT_FRIEND; + } + if( u->is_npc() ) { + // Zombies don't understand not attacking NPCs, but dogs and bots should. + if( u->get_attitude() != NPCATT_KILL && !type->in_species( species_ZOMBIE ) ) { + return MATT_FRIEND; + } + if( u->is_hallucination() ) { + return MATT_IGNORE; + } + } } } if( effect_cache[FLEEING] ) { @@ -1170,8 +1173,9 @@ void monster::process_triggers() process_trigger( mon_trigger::FIRE, [this]() { int ret = 0; - for( const auto &p : g->m.points_in_radius( pos(), 3 ) ) { - ret += 5 * g->m.get_field_intensity( p, fd_fire ); + map &here = get_map(); + for( const auto &p : here.points_in_radius( pos(), 3 ) ) { + ret += 5 * here.get_field_intensity( p, fd_fire ); } return ret; } ); @@ -1359,8 +1363,9 @@ void monster::melee_attack( Creature &target, float accuracy ) return; } + Character &player_character = get_player_character(); if( target.is_player() || - ( target.is_npc() && g->u.attitude_to( target ) == Attitude::FRIENDLY ) ) { + ( target.is_npc() && player_character.attitude_to( target ) == Attitude::FRIENDLY ) ) { // Make us a valid target for a few turns add_effect( effect_hit_by_player, 3_turns ); } @@ -1369,7 +1374,7 @@ void monster::melee_attack( Creature &target, float accuracy ) add_effect( effect_run, 4_turns ); } - const bool u_see_me = g->u.sees( *this ); + const bool u_see_me = player_character.sees( *this ); damage_instance damage = !is_hallucination() ? type->melee_damage : damage_instance(); if( !is_hallucination() && type->melee_dice > 0 ) { @@ -1409,7 +1414,8 @@ void monster::melee_attack( Creature &target, float accuracy ) add_msg( m_bad, _( "The %1$s hits your %2$s." ), name(), body_part_name_accusative( dealt_dam.bp_hit ) ); } else if( target.is_npc() ) { - if( has_effect( effect_ridden ) && has_flag( MF_RIDEABLE_MECH ) && pos() == g->u.pos() ) { + if( has_effect( effect_ridden ) && has_flag( MF_RIDEABLE_MECH ) && + pos() == player_character.pos() ) { //~ %1$s: name of your mount, %2$s: target NPC name, %3$d: damage value add_msg( m_good, _( "Your %1$s hits %2$s for %3$d damage!" ), name(), target.disp_name(), total_dealt ); @@ -1420,7 +1426,8 @@ void monster::melee_attack( Creature &target, float accuracy ) body_part_name_accusative( dealt_dam.bp_hit ) ); } } else { - if( has_effect( effect_ridden ) && has_flag( MF_RIDEABLE_MECH ) && pos() == g->u.pos() ) { + if( has_effect( effect_ridden ) && has_flag( MF_RIDEABLE_MECH ) && + pos() == player_character.pos() ) { //~ %1$s: name of your mount, %2$s: target creature name, %3$d: damage value add_msg( m_good, _( "Your %1$s hits %2$s for %3$d damage!" ), get_name(), target.disp_name(), total_dealt ); @@ -1503,16 +1510,6 @@ void monster::melee_attack( Creature &target, float accuracy ) target.add_msg_if_player( m_bad, _( "You feel venom enter your body!" ) ); target.add_effect( effect_paralyzepoison, 10_minutes ); } - - if( total_dealt > 6 && stab_cut > 0 && has_flag( MF_BLEED ) ) { - // Maybe should only be if DT_CUT > 6... Balance question - if( target.is_player() || target.is_npc() ) { - target.as_character()->make_bleed( dealt_dam.bp_hit, 6_minutes ); - } else { - target.add_effect( effect_bleed, 6_minutes, dealt_dam.bp_hit->token ); - } - - } } void monster::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack, @@ -1648,7 +1645,8 @@ bool monster::move_effects( bool ) return true; } - bool u_see_me = g->u.sees( *this ); + map &here = get_map(); + bool u_see_me = get_player_character().sees( *this ); if( has_effect( effect_tied ) ) { // friendly pet, will stay tied down and obey. if( friendly == -1 ) { @@ -1668,7 +1666,7 @@ bool monster::move_effects( bool ) if( u_see_me ) { add_msg( _( "The %s easily slips out of its bonds." ), name() ); } - g->m.add_item_or_charges( pos(), *tied_item ); + here.add_item_or_charges( pos(), *tied_item ); tied_item.reset(); } } else { @@ -1676,7 +1674,7 @@ bool monster::move_effects( bool ) const bool broken = rng( type->melee_dice * type->melee_sides, std::min( 10000, type->melee_dice * type->melee_sides * 250 ) ) > 800; if( !broken ) { - g->m.add_item_or_charges( pos(), *tied_item ); + here.add_item_or_charges( pos(), *tied_item ); } tied_item.reset(); if( u_see_me ) { @@ -1716,8 +1714,8 @@ bool monster::move_effects( bool ) if( has_effect( effect_lightsnare ) ) { if( x_in_y( type->melee_dice * type->melee_sides, 12 ) ) { remove_effect( effect_lightsnare ); - g->m.spawn_item( pos(), "string_36" ); - g->m.spawn_item( pos(), "snare_trigger" ); + here.spawn_item( pos(), "string_36" ); + here.spawn_item( pos(), "snare_trigger" ); if( u_see_me ) { add_msg( _( "The %s escapes the light snare!" ), name() ); } @@ -1728,8 +1726,8 @@ bool monster::move_effects( bool ) if( type->melee_dice * type->melee_sides >= 7 ) { if( x_in_y( type->melee_dice * type->melee_sides, 32 ) ) { remove_effect( effect_heavysnare ); - g->m.spawn_item( pos(), "rope_6" ); - g->m.spawn_item( pos(), "snare_trigger" ); + here.spawn_item( pos(), "rope_6" ); + here.spawn_item( pos(), "snare_trigger" ); if( u_see_me ) { add_msg( _( "The %s escapes the heavy snare!" ), name() ); } @@ -1741,7 +1739,7 @@ bool monster::move_effects( bool ) if( type->melee_dice * type->melee_sides >= 18 ) { if( x_in_y( type->melee_dice * type->melee_sides, 200 ) ) { remove_effect( effect_beartrap ); - g->m.spawn_item( pos(), "beartrap" ); + here.spawn_item( pos(), "beartrap" ); if( u_see_me ) { add_msg( _( "The %s escapes the bear trap!" ), name() ); } @@ -1986,7 +1984,7 @@ int monster::impact( const int force, const tripoint &p ) const float mod = fall_damage_mod(); int total_dealt = 0; - if( g->m.has_flag( TFLAG_SHARP, p ) ) { + if( get_map().has_flag( TFLAG_SHARP, p ) ) { const int cut_damage = std::max( 0.0f, 10 * mod - get_armor_cut( bodypart_id( "torso" ) ) ); apply_damage( nullptr, bodypart_id( "torso" ), cut_damage ); total_dealt += 10 * mod; @@ -2066,6 +2064,7 @@ void monster::decrement_summon_timer() void monster::process_turn() { + map &here = get_map(); decrement_summon_timer(); if( !is_hallucination() ) { for( const std::pair &e : type->emit_fields ) { @@ -2077,11 +2076,11 @@ void monster::process_turn() if( has_effect( effect_emp ) ) { continue; // don't emit electricity while EMPed } else if( has_effect( effect_supercharged ) ) { - g->m.emit_field( pos(), emit_id( "emit_shock_cloud_big" ) ); + here.emit_field( pos(), emit_id( "emit_shock_cloud_big" ) ); continue; } } - g->m.emit_field( pos(), emid ); + here.emit_field( pos(), emid ); } } @@ -2104,7 +2103,7 @@ void monster::process_turn() } // Persist grabs as long as there's an adjacent target. if( has_effect( effect_grabbing ) ) { - for( auto &dest : g->m.points_in_radius( pos(), 1, 0 ) ) { + for( auto &dest : here.points_in_radius( pos(), 1, 0 ) ) { const player *const p = g->critter_at( dest ); if( p && p->has_effect( effect_grabbed ) ) { add_effect( effect_grabbing, 2_turns ); @@ -2118,12 +2117,13 @@ void monster::process_turn() sounds::sound( pos(), 5, sounds::sound_t::combat, _( "hummmmm." ), false, "humming", "electric" ); } } else { - for( const tripoint &zap : g->m.points_in_radius( pos(), 1 ) ) { - const bool player_sees = g->u.sees( zap ); - const map_stack items = g->m.i_at( zap ); + Character &player_character = get_player_character(); + for( const tripoint &zap : here.points_in_radius( pos(), 1 ) ) { + const bool player_sees = player_character.sees( zap ); + const map_stack items = here.i_at( zap ); for( const auto &item : items ) { if( item.made_of( phase_id::LIQUID ) && item.flammable() ) { // start a fire! - g->m.add_field( zap, fd_fire, 2, 1_minutes ); + here.add_field( zap, fd_fire, 2, 1_minutes ); sounds::sound( pos(), 30, sounds::sound_t::combat, _( "fwoosh!" ), false, "fire", "ignition" ); break; } @@ -2131,33 +2131,33 @@ void monster::process_turn() if( zap != pos() ) { explosion_handler::emp_blast( zap ); // Fries electronics due to the intensity of the field } - const auto t = g->m.ter( zap ); + const auto t = here.ter( zap ); if( t == ter_str_id( "t_gas_pump" ) || t == ter_str_id( "t_gas_pump_a" ) ) { if( one_in( 4 ) ) { explosion_handler::explosion( pos(), 40, 0.8, true ); if( player_sees ) { - add_msg( m_warning, _( "The %s explodes in a fiery inferno!" ), g->m.tername( zap ) ); + add_msg( m_warning, _( "The %s explodes in a fiery inferno!" ), here.tername( zap ) ); } } else { if( player_sees ) { add_msg( m_warning, _( "Lightning from %1$s engulfs the %2$s!" ), name(), - g->m.tername( zap ) ); + here.tername( zap ) ); } - g->m.add_field( zap, fd_fire, 1, 2_turns ); + here.add_field( zap, fd_fire, 1, 2_turns ); } } } if( g->weather.lightning_active && !has_effect( effect_supercharged ) && - g->m.is_outside( pos() ) ) { + here.is_outside( pos() ) ) { g->weather.lightning_active = false; // only one supercharge per strike sounds::sound( pos(), 300, sounds::sound_t::combat, _( "BOOOOOOOM!!!" ), false, "environment", "thunder_near" ); sounds::sound( pos(), 20, sounds::sound_t::combat, _( "vrrrRRRUUMMMMMMMM!" ), false, "explosion", "default" ); - if( g->u.sees( pos() ) ) { + if( player_character.sees( pos() ) ) { add_msg( m_bad, _( "Lightning strikes the %s!" ), name() ); add_msg( m_bad, _( "Your vision goes white!" ) ); - g->u.add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); + player_character.add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); } add_effect( effect_supercharged, 12_hours ); } else if( has_effect( effect_supercharged ) && calendar::once_every( 5_turns ) ) { @@ -2225,15 +2225,16 @@ void monster::die( Creature *nkiller ) if( has_effect( effect_beartrap ) ) { add_item( item( "beartrap", 0 ) ); } + map &here = get_map(); if( has_effect( effect_grabbing ) ) { remove_effect( effect_grabbing ); - for( auto &player_pos : g->m.points_in_radius( pos(), 1, 0 ) ) { + for( auto &player_pos : here.points_in_radius( pos(), 1, 0 ) ) { player *p = g->critter_at( player_pos ); if( !p || !p->has_effect( effect_grabbed ) ) { continue; } bool grabbed = false; - for( auto &mon_pos : g->m.points_in_radius( player_pos, 1, 0 ) ) { + for( auto &mon_pos : here.points_in_radius( player_pos, 1, 0 ) ) { const monster *const mon = g->critter_at( mon_pos ); if( mon && mon->has_effect( effect_grabbing ) ) { grabbed = true; @@ -2249,7 +2250,7 @@ void monster::die( Creature *nkiller ) } if( !is_hallucination() ) { for( const auto &it : inv ) { - g->m.add_item_or_charges( pos(), it ); + here.add_item_or_charges( pos(), it ); } } @@ -2257,7 +2258,7 @@ void monster::die( Creature *nkiller ) if( !is_hallucination() && has_flag( MF_QUEEN ) ) { // The submap coordinates of this monster, monster groups coordinates are // submap coordinates. - const tripoint abssub = ms_to_sm_copy( g->m.getabs( pos() ) ); + const tripoint abssub = ms_to_sm_copy( here.getabs( pos() ) ); // Do it for overmap above/below too for( const tripoint &p : points_in_radius( abssub, HALF_MAPSIZE, 1 ) ) { for( auto &mgp : overmap_buffer.groups_at( p ) ) { @@ -2300,7 +2301,7 @@ void monster::die( Creature *nkiller ) continue; } - if( g->m.sees( critter.pos(), pos(), light ) ) { + if( here.sees( critter.pos(), pos(), light ) ) { critter.morale += morale_adjust; critter.anger += anger_adjust; } @@ -2368,7 +2369,7 @@ void monster::drop_items_on_death() items = remaining; } - const auto dropped = g->m.spawn_items( pos(), items ); + const auto dropped = get_map().spawn_items( pos(), items ); if( has_flag( MF_FILTHY ) ) { for( const auto &it : dropped ) { @@ -2427,6 +2428,12 @@ void monster::process_one_effect( effect &it, bool is_new ) effect_cache[FLEEING] = true; } else if( id == effect_no_sight || id == effect_blind ) { effect_cache[VISION_IMPAIRED] = true; + } else if( id == effect_bleed && x_in_y( it.get_intensity(), it.get_max_intensity() ) ) { + // monsters are simplified so they just take damage from bleeding + apply_damage( nullptr, bodypart_id( "torso" ), 1 ); + // this is for balance only + it.mod_duration( -rng( 1_turns, it.get_int_dur_factor() / 2 ) ); + bleed(); } } @@ -2445,9 +2452,10 @@ void monster::process_effects() set_speed_bonus( min_speed_bonus ); } + Character &player_character = get_player_character(); //If this monster has the ability to heal in combat, do it now. const int healed_amount = heal( type->regenerates ); - if( healed_amount > 0 && one_in( 2 ) && g->u.sees( *this ) ) { + if( healed_amount > 0 && one_in( 2 ) && player_character.sees( *this ) ) { std::string healing_format_string; if( healed_amount >= 50 ) { healing_format_string = _( "The %s is visibly regenerating!" ); @@ -2460,10 +2468,10 @@ void monster::process_effects() } if( type->regenerates_in_dark ) { - const float light = g->m.ambient_light_at( pos() ); + const float light = get_map().ambient_light_at( pos() ); // Magic number 10000 was chosen so that a floodlight prevents regeneration in a range of 20 tiles if( heal( static_cast( 50.0 * std::exp( - light * light / 10000 ) ) > 0 && one_in( 2 ) && - g->u.sees( *this ) ) ) { + player_character.sees( *this ) ) ) { add_msg( m_warning, _( "The %s uses the darkness to regenerate." ), name() ); } } @@ -2471,7 +2479,7 @@ void monster::process_effects() //Monster will regen morale and aggression if it is on max HP //It regens more morale and aggression if is currently fleeing. if( type->regen_morale && hp >= type->hp ) { - if( is_fleeing( g->u ) ) { + if( is_fleeing( player_character ) ) { morale = type->morale; anger = type->agro; } @@ -2491,7 +2499,7 @@ void monster::process_effects() // If this critter dies in sunlight, check & assess damage. if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( pos() ) ) { - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name() ); } apply_damage( nullptr, bodypart_id( "torso" ), 100 ); @@ -2587,7 +2595,7 @@ bool monster::make_fungus() return false; } - if( g->u.sees( pos() ) ) { + if( get_player_character().sees( pos() ) ) { add_msg( m_info, _( "The spores transform %1$s into a %2$s!" ), old_name, name() ); } @@ -2654,7 +2662,7 @@ units::volume monster::get_volume() const void monster::add_msg_if_npc( const std::string &msg ) const { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( replace_with_npc_name( msg ) ); } } @@ -2662,14 +2670,14 @@ void monster::add_msg_if_npc( const std::string &msg ) const void monster::add_msg_player_or_npc( const std::string &/*player_msg*/, const std::string &npc_msg ) const { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( replace_with_npc_name( npc_msg ) ); } } void monster::add_msg_if_npc( const game_message_params ¶ms, const std::string &msg ) const { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( params, replace_with_npc_name( msg ) ); } } @@ -2677,7 +2685,7 @@ void monster::add_msg_if_npc( const game_message_params ¶ms, const std::stri void monster::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &/*player_msg*/, const std::string &npc_msg ) const { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( params, replace_with_npc_name( npc_msg ) ); } } @@ -2816,12 +2824,13 @@ void monster::on_hit( Creature *source, bodypart_id, if( anger_adjust != 0 || morale_adjust != 0 ) { int light = g->light_level( posz() ); + map &here = get_map(); for( monster &critter : g->all_monsters() ) { if( !critter.type->same_species( *type ) ) { continue; } - if( g->m.sees( critter.pos(), pos(), light ) ) { + if( here.sees( critter.pos(), pos(), light ) ) { critter.morale += morale_adjust; critter.anger += anger_adjust; } @@ -2918,7 +2927,7 @@ bool monster::will_join_horde( int size ) return false; } else if( mha == MHA_ALWAYS ) { return true; - } else if( g->m.has_flag( TFLAG_INDOORS, pos() ) && ( mha == MHA_OUTDOORS || + } else if( get_map().has_flag( TFLAG_INDOORS, pos() ) && ( mha == MHA_OUTDOORS || mha == MHA_OUTDOORS_AND_LARGE ) ) { return false; } else if( size < 3 && ( mha == MHA_LARGE || mha == MHA_OUTDOORS_AND_LARGE ) ) { diff --git a/src/monster.h b/src/monster.h index d4e71015b717f..418bddec9373c 100644 --- a/src/monster.h +++ b/src/monster.h @@ -295,7 +295,7 @@ class monster : public Creature void knock_back_to( const tripoint &to ) override; // Combat - bool is_fleeing( player &u ) const; // True if we're fleeing + bool is_fleeing( Character &u ) const; monster_attitude attitude( const Character *u = nullptr ) const; // See the enum above Attitude attitude_to( const Creature &other ) const override; void process_triggers(); // Process things that anger/scare us diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 0cee9fdacbe01..23f8aef98bab1 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -84,7 +84,6 @@ std::string enum_to_string( m_flag data ) case MF_VENOM: return "VENOM"; case MF_BADVENOM: return "BADVENOM"; case MF_PARALYZE: return "PARALYZEVENOM"; - case MF_BLEED: return "BLEED"; case MF_WEBWALK: return "WEBWALK"; case MF_DIGS: return "DIGS"; case MF_CAN_DIG: return "CAN_DIG"; diff --git a/src/mtype.h b/src/mtype.h index 1cfa99b46a2ed..d38234fa0f9ba 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -81,7 +81,6 @@ enum m_flag : int { MF_VENOM, // Attack may poison the player MF_BADVENOM, // Attack may SEVERELY poison the player MF_PARALYZE, // Attack may paralyze the player with venom - MF_BLEED, // Causes player to bleed MF_WEBWALK, // Doesn't destroy webs MF_DIGS, // Digs through the ground MF_CAN_DIG, // Can dig and walk diff --git a/src/mutation.cpp b/src/mutation.cpp index 137b6b0158bb4..0f5080298b279 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -151,7 +151,7 @@ void Character::set_mutation( const trait_id &trait ) cached_mutations.push_back( &trait.obj() ); mutation_effect( trait ); recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); } void Character::unset_mutation( const trait_id &trait_ ) @@ -170,7 +170,7 @@ void Character::unset_mutation( const trait_id &trait_ ) my_mutations.erase( iter ); mutation_loss_effect( trait ); recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); } void Character::switch_mutations( const trait_id &switched, const trait_id &target, @@ -402,7 +402,7 @@ void Character::mutation_effect( const trait_id &mut ) _( "Your %s is pushed off!" ), _( "'s %s is pushed off!" ), armor.tname() ); - g->m.add_item_or_charges( pos(), armor ); + get_map().add_item_or_charges( pos(), armor ); } return true; } ); @@ -608,7 +608,7 @@ void Character::activate_mutation( const trait_id &mut ) } if( mut == trait_WEB_WEAVER ) { - g->m.add_field( pos(), fd_web, 1 ); + get_map().add_field( pos(), fd_web, 1 ); add_msg_if_player( _( "You start spinning web with your spinnerets!" ) ); } else if( mut == trait_BURROW ) { tdata.powered = false; @@ -668,8 +668,9 @@ void Character::activate_mutation( const trait_id &mut ) } // Check for adjacent trees. bool adjacent_tree = false; - for( const tripoint &p2 : g->m.points_in_radius( pos(), 1 ) ) { - if( g->m.has_flag( "TREE", p2 ) ) { + map &here = get_map(); + for( const tripoint &p2 : here.points_in_radius( pos(), 1 ) ) { + if( here.has_flag( "TREE", p2 ) ) { adjacent_tree = true; } } @@ -718,7 +719,7 @@ void Character::activate_mutation( const trait_id &mut ) return; } else if( !mdata.ranged_mutation.is_empty() ) { add_msg_if_player( mdata.ranged_mutation_message() ); - avatar_action::fire_ranged_mutation( g->u, item( mdata.ranged_mutation ) ); + avatar_action::fire_ranged_mutation( *this, item( mdata.ranged_mutation ) ); tdata.powered = false; return; } @@ -1431,7 +1432,7 @@ static mutagen_rejection try_reject_mutagen( Character &guy, const item &it, boo if( guy.has_trait( trait_M_SPORES ) || guy.has_trait( trait_M_FERTILE ) || guy.has_trait( trait_M_BLOSSOMS ) || guy.has_trait( trait_M_BLOOM ) ) { guy.add_msg_if_player( m_good, _( "We decontaminate it with spores." ) ); - g->m.ter_set( guy.pos(), t_fungus ); + get_map().ter_set( guy.pos(), t_fungus ); if( guy.is_avatar() ) { g->memorial().add( pgettext( "memorial_male", "Destroyed a harmful invader." ), diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 1ad16e7d335c2..fb035bf7172b0 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -45,6 +45,7 @@ #include "pldata.h" #include "popup.h" #include "profession.h" +#include "proficiency.h" #include "recipe.h" #include "recipe_dictionary.h" #include "rng.h" @@ -591,6 +592,10 @@ bool avatar::create( character_type type, const std::string &tempname ) // Adjust current energy level to maximum set_power_level( get_max_power_level() ); + for( const proficiency_id &pri : prof->proficiencies() ) { + add_proficiency( pri ); + } + for( const trait_id &t : get_base_traits() ) { std::vector styles; for( const matype_id &s : t->initial_ma_styles ) { @@ -1553,6 +1558,17 @@ tab_direction set_profession( avatar &u, points_left &points, } } } + // Proficiencies + const std::string newline = "\n"; + std::vector prof_proficiencies = sorted_profs[cur_id]->proficiencies(); + buffer += colorize( _( "Profession proficiencies:" ), c_light_blue ) + newline; + if( prof_proficiencies.empty() ) { + buffer += pgettext( "Profession has no proficiencies", "None" ) + newline; + } else { + for( const proficiency_id &prof : prof_proficiencies ) { + buffer += prof->name() + newline; + } + } // Profession pet if( !sorted_profs[cur_id]->pets().empty() ) { buffer += colorize( _( "Pets:" ), c_light_blue ) + "\n"; @@ -2187,8 +2203,7 @@ tab_direction set_scenario( avatar &u, points_left &points, wprintz( w_flags, c_light_gray, _( "Fungal infected player" ) ); wprintz( w_flags, c_light_gray, ( "\n" ) ); } - if( get_option( "STARTING_NPC" ) == "scenario" && - sorted_scens[cur_id]->has_flag( "LONE_START" ) ) { + if( sorted_scens[cur_id]->has_flag( "LONE_START" ) ) { wprintz( w_flags, c_light_gray, _( "No starting NPC" ) ); wprintz( w_flags, c_light_gray, ( "\n" ) ); } @@ -2559,15 +2574,15 @@ tab_direction set_description( avatar &you, const bool allow_reroll, } wnoutrefresh( w_guide ); - //We draw this stuff every loop because this is user-editable + wclear( w_name ); mvwprintz( w_name, point_zero, current_selector == char_creation::NAME ? h_light_gray : c_light_gray, _( "Name:" ) ); if( no_name_entered ) { - mvwprintz( w_name, point( namebar_pos, 0 ), h_light_gray, _( "_______NO NAME ENTERED!_______" ) ); + mvwprintz( w_name, point( namebar_pos, 0 ), h_light_gray, _( "--- NO NAME ENTERED ---" ) ); + } else if( you.name.empty() ) { + mvwprintz( w_name, point( namebar_pos, 0 ), c_light_gray, _( "--- RANDOM NAME ---" ) ); } else { - mvwprintz( w_name, point( namebar_pos, 0 ), c_light_gray, "_______________________________" ); mvwprintz( w_name, point( namebar_pos, 0 ), c_white, you.name ); - wprintz( w_name, h_light_gray, "_" ); } if( !MAP_SHARING::isSharing() ) { // no random names when sharing maps @@ -2819,7 +2834,7 @@ tab_direction set_description( avatar &you, const bool allow_reroll, .only_digits( true ); const int result = popup.query_int(); if( result != 0 ) { - you.set_base_age( clamp( popup.query_int(), 16, 55 ) ); + you.set_base_age( clamp( result, 16, 55 ) ); } break; } @@ -2829,40 +2844,33 @@ tab_direction set_description( avatar &you, const bool allow_reroll, .only_digits( true ); const int result = popup.query_int(); if( result != 0 ) { - you.set_base_height( clamp( popup.query_int(), 145, 200 ) ); + you.set_base_height( clamp( result, 145, 200 ) ); } break; } case char_creation::BLOOD: { - popup.title( _( "Enter blood type (omit Rh):" ) ) - .text( io::enum_to_string( you.my_blood_type ) ) - .only_digits( false ); - std::string answer = popup.query_string(); - if( answer == "O" || answer == "o" || answer == "0" ) { - you.my_blood_type = blood_type::blood_O; - } else if( answer == "A" || answer == "a" ) { - you.my_blood_type = blood_type::blood_A; - } else if( answer == "B" || answer == "b" ) { - you.my_blood_type = blood_type::blood_B; - } else if( answer == "AB" || answer == "ab" ) { - you.my_blood_type = blood_type::blood_AB; - } else { - popup_getkey( "%s", _( "Invalid blood type." ) ); + uilist btype; + btype.text = _( "Select blood type" ); + btype.addentry( static_cast( blood_type::blood_O ), true, '1', "O" ); + btype.addentry( static_cast( blood_type::blood_A ), true, '2', "A" ); + btype.addentry( static_cast( blood_type::blood_B ), true, '3', "B" ); + btype.addentry( static_cast( blood_type::blood_AB ), true, '4', "AB" ); + btype.query(); + if( btype.ret < 0 ) { break; } - string_input_popup popup2; - popup2.title( _( "Enter Rh factor:" ) ) - .text( you.blood_rh_factor ? "+" : "-" ) - .only_digits( false ); - answer = popup2.query_string(); - if( answer == "+" || answer == "plus" || answer == "positive" ) { - you.blood_rh_factor = true; - } else if( answer == "-" || answer == "minus" || answer == "negative" ) { - you.blood_rh_factor = false; - } else { - popup_getkey( "%s", _( "Invalid blood type." ) ); + + uilist bfac; + bfac.text = _( "Select Rh factor" ); + bfac.addentry( 0, true, '-', _( "negative" ) ); + bfac.addentry( 1, true, '+', _( "positive" ) ); + bfac.query(); + if( bfac.ret < 0 ) { break; } + + you.my_blood_type = static_cast( btype.ret ); + you.blood_rh_factor = static_cast( bfac.ret ); break; } } @@ -2915,8 +2923,8 @@ void Character::add_traits() void Character::add_traits( points_left &points ) { - // TODO: get rid of using g->u here, use `this` instead - for( const trait_id &tr : g->u.prof->get_locked_traits() ) { + // TODO: get rid of using get_avatar() here, use `this` instead + for( const trait_id &tr : get_avatar().prof->get_locked_traits() ) { if( !has_trait( tr ) ) { toggle_trait( tr ); } else { diff --git a/src/npc.cpp b/src/npc.cpp index 27758bf59d125..a436ac15786ad 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -63,6 +63,8 @@ #include "sounds.h" #include "stomach.h" #include "string_formatter.h" +#include "talker.h" +#include "talker_npc.h" #include "text_snippets.h" #include "tileray.h" #include "trait_group.h" @@ -752,7 +754,7 @@ void npc::place_on_map() return; } - for( const tripoint &p : closest_tripoints_first( pos(), SEEX + 1 ) ) { + for( const tripoint &p : closest_points_first( pos(), SEEX + 1 ) ) { if( g->is_empty( p ) ) { setpos( p ); return; @@ -909,7 +911,8 @@ void npc::finish_read( item &book ) const skill_id &skill = reading->skill; // NPCs don't need to identify the book or learn recipes yet. // NPCs don't read to other NPCs yet. - const bool display_messages = my_fac->id == faction_id( "your_followers" ) && g->u.sees( pos() ); + const bool display_messages = my_fac->id == faction_id( "your_followers" ) && + get_player_character().sees( pos() ); bool continuous = false; //whether to continue reading or not if( book_fun_for( book, *this ) != 0 ) { @@ -1028,7 +1031,7 @@ void npc::do_npc_read() } item &chosen = *loc.obtain( *ch ); if( can_read( chosen, fail_reasons ) ) { - if( g->u.sees( pos() ) ) { + if( get_player_character().sees( pos() ) ) { add_msg( m_info, _( "%s starts reading." ), disp_name() ); } start_read( chosen, pl ); @@ -1054,11 +1057,9 @@ bool npc::wear_if_wanted( const item &it, std::string &reason ) // Splints ignore limits, but only when being equipped on a broken part // TODO: Drop splints when healed if( it.has_flag( "SPLINT" ) ) { - for( int i = 0; i < num_hp_parts; i++ ) { - hp_part hpp = static_cast( i ); - body_part bp = player::hp_to_bp( hpp ); - if( is_limb_broken( convert_bp( bp ) ) && !has_effect( effect_mending, bp ) && - it.covers( convert_bp( bp ).id() ) ) { + for( const bodypart_id &bp : get_all_body_parts( true ) ) { + if( is_limb_broken( bp ) && !has_effect( effect_mending, bp->token ) && + it.covers( bp ) ) { reason = _( "Thanks, I'll wear that now." ); return !!wear_item( it, false ); } @@ -1108,9 +1109,10 @@ bool npc::wear_if_wanted( const item &it, std::string &reason ) void npc::stow_item( item &it ) { + bool avatar_sees = get_player_character().sees( pos() ); if( wear_item( weapon, false ) ) { // Wearing the item was successful, remove weapon and post message. - if( g->u.sees( pos() ) ) { + if( avatar_sees ) { add_msg_if_npc( m_info, _( " wears the %s." ), weapon.tname() ); } remove_weapon(); @@ -1121,7 +1123,7 @@ void npc::stow_item( item &it ) } for( auto &e : worn ) { if( e.can_holster( it ) ) { - if( g->u.sees( pos() ) ) { + if( avatar_sees ) { //~ %1$s: weapon name, %2$s: holster name add_msg_if_npc( m_info, _( " puts away the %1$s in the %2$s." ), weapon.tname(), e.tname() ); @@ -1132,16 +1134,16 @@ void npc::stow_item( item &it ) } } if( volume_carried() + weapon.volume() <= volume_capacity() ) { - if( g->u.sees( pos() ) ) { + if( avatar_sees ) { add_msg_if_npc( m_info, _( " puts away the %s." ), weapon.tname() ); } i_add( remove_weapon() ); moves -= 15; } else { // No room for weapon, so we drop it - if( g->u.sees( pos() ) ) { + if( avatar_sees ) { add_msg_if_npc( m_info, _( " drops the %s." ), weapon.tname() ); } - g->m.add_item_or_charges( pos(), remove_weapon() ); + get_map().add_item_or_charges( pos(), remove_weapon() ); } } @@ -1185,7 +1187,7 @@ bool npc::wield( item &it ) g->events().send( getID(), weapon.typeId() ); - if( g->u.sees( pos() ) ) { + if( get_player_character().sees( pos() ) ) { add_msg_if_npc( m_info, _( " wields a %s." ), weapon.tname() ); } invalidate_range_cache(); @@ -1339,7 +1341,7 @@ void npc::mutiny() if( !my_fac || !is_player_ally() ) { return; } - const bool seen = g->u.sees( pos() ); + const bool seen = get_player_character().sees( pos() ); if( seen ) { add_msg( m_bad, _( "%s is tired of your incompetent leadership and abuse!" ), disp_name() ); } @@ -1370,7 +1372,7 @@ float npc::vehicle_danger( int radius ) const { const tripoint from( posx() - radius, posy() - radius, posz() ); const tripoint to( posx() + radius, posy() + radius, posz() ); - VehicleList vehicles = g->m.get_vehicles( from, to ); + VehicleList vehicles = get_map().get_vehicles( from, to ); int danger = 0; @@ -1479,6 +1481,25 @@ std::vector npc::styles_offered_to( const player &p ) const return p.martial_arts_data.get_unknown_styles( martial_arts_data ); } +std::vector npc::spells_offered_to( player &p ) +{ + std::vector teachable; + for( const spell_id &sp : magic.spells() ) { + const spell &teacher_spell = magic.get_spell( sp ); + if( p.magic.can_learn_spell( p, sp ) ) { + if( p.magic.knows_spell( sp ) ) { + const spell &student_spell = p.magic.get_spell( sp ); + if( student_spell.is_max_level() || + student_spell.get_level() >= teacher_spell.get_level() ) { + continue; + } + } + teachable.emplace_back( sp ); + } + } + return teachable; +} + void npc::decide_needs() { double needrank[num_needs]; @@ -1541,13 +1562,14 @@ void npc::decide_needs() void npc::say( const std::string &line, const sounds::sound_t spriority ) const { std::string formatted_line = line; - parse_tags( formatted_line, g->u, *this ); + Character &player_character = get_player_character(); + parse_tags( formatted_line, player_character, *this ); if( has_trait( trait_MUTE ) ) { return; } std::string sound = string_format( _( "%1$s saying \"%2$s\"" ), name, formatted_line ); - if( g->u.sees( *this ) && g->u.is_deaf() ) { + if( player_character.sees( *this ) && player_character.is_deaf() ) { add_msg( m_warning, _( "%1$s says something but you can't hear it!" ), name ); } // Hallucinations don't make noise when they speak @@ -1953,7 +1975,7 @@ bool npc::has_faction_relationship( const player &p, const npc_factions::relatio return my_fac->has_relationship( p_fac->id, flag ); } -bool npc::is_ally( const player &p ) const +bool npc::is_ally( const Character &p ) const { if( p.getID() == getID() ) { return true; @@ -1977,7 +1999,8 @@ bool npc::is_ally( const player &p ) const return true; } if( faction_api_version < 2 ) { - if( is_ally( g->u ) && guy.is_ally( g->u ) ) { + Character &player_character = get_player_character(); + if( is_ally( player_character ) && guy.is_ally( player_character ) ) { return true; } else if( get_attitude_group( get_attitude() ) == guy.get_attitude_group( guy.get_attitude() ) ) { @@ -1990,10 +2013,10 @@ bool npc::is_ally( const player &p ) const bool npc::is_player_ally() const { - return is_ally( g->u ); + return is_ally( get_player_character() ); } -bool npc::is_friendly( const player &p ) const +bool npc::is_friendly( const Character &p ) const { return is_ally( p ) || ( p.is_player() && ( is_walking_with() || is_player_ally() ) ); } @@ -2013,7 +2036,7 @@ bool npc::is_walking_with() const return attitude == NPCATT_FOLLOW || attitude == NPCATT_LEAD || attitude == NPCATT_WAIT; } -bool npc::is_obeying( const player &p ) const +bool npc::is_obeying( const Character &p ) const { return ( p.is_player() && is_walking_with() && is_player_ally() ) || ( is_ally( p ) && is_stationary( true ) ); @@ -2089,14 +2112,15 @@ Creature::Attitude npc::attitude_to( const Creature &other ) const } } + Character &player_character = get_player_character(); if( is_player_ally() ) { // Friendly NPCs share player's alliances - return g->u.attitude_to( other ); + return player_character.attitude_to( other ); } if( other.is_npc() ) { // Hostile NPCs are also hostile towards player's allies - if( is_enemy() && other.attitude_to( g->u ) == Attitude::FRIENDLY ) { + if( is_enemy() && other.attitude_to( player_character ) == Attitude::FRIENDLY ) { return Attitude::HOSTILE; } @@ -2134,7 +2158,7 @@ void npc::npc_dismount() return; } cata::optional pnt; - for( const auto &elem : g->m.points_in_radius( pos(), 1 ) ) { + for( const auto &elem : get_map().points_in_radius( pos(), 1 ) ) { if( g->is_empty( elem ) ) { pnt = elem; break; @@ -2201,11 +2225,13 @@ bool npc::is_active() const int npc::follow_distance() const { + Character &player_character = get_player_character(); + map &here = get_map(); // HACK: If the player is standing on stairs, follow closely // This makes the stair hack less painful to use if( is_walking_with() && - ( g->m.has_flag( TFLAG_GOES_DOWN, g->u.pos() ) || - g->m.has_flag( TFLAG_GOES_UP, g->u.pos() ) ) ) { + ( here.has_flag( TFLAG_GOES_DOWN, player_character.pos() ) || + here.has_flag( TFLAG_GOES_UP, player_character.pos() ) ) ) { return 1; } // Uses ally_rule follow_distance_2 to determine if should follow by 2 or 4 tiles @@ -2213,7 +2239,7 @@ int npc::follow_distance() const return 2; } // If NPC doesn't see player, change follow distance to 2 - if( !sees( g->u ) ) { + if( !sees( player_character ) ) { return 2; } return 4; @@ -2255,15 +2281,16 @@ int npc::print_info( const catacurses::window &w, int line, int vLines, int colu trim_and_print( w, point( column + bar.first.length() + 1, line ), iWidth, basic_symbol_color(), name ); + Character &player_character = get_player_character(); // Hostility indicator in the second line. - Attitude att = attitude_to( g->u ); + Attitude att = attitude_to( player_character ); const std::pair res = Creature::get_attitude_ui_data( att ); mvwprintz( w, point( column, ++line ), res.second, res.first.translated() ); // Awareness indicator on the third line. - std::string senses_str = sees( g->u ) ? _( "Aware of your presence" ) : + std::string senses_str = sees( player_character ) ? _( "Aware of your presence" ) : _( "Unaware of you" ); - mvwprintz( w, point( column, ++line ), sees( g->u ) ? c_yellow : c_green, senses_str ); + mvwprintz( w, point( column, ++line ), sees( player_character ) ? c_yellow : c_green, senses_str ); // Print what item the NPC is holding if any on the fourth line. if( is_armed() ) { @@ -2290,8 +2317,8 @@ int npc::print_info( const catacurses::window &w, int line, int vLines, int colu // 3 perception and 3 distance would see all mutations - cap 0 // 3 perception and 15 distance - cap 5, some mutations visible // 3 perception and 20 distance would be barely able to discern huge antlers on a person - cap 10 - const int per = g->u.get_per(); - const int dist = rl_dist( g->u.pos(), pos() ); + const int per = player_character.get_per(); + const int dist = rl_dist( player_character.pos(), pos() ); int visibility_cap; if( per <= 1 ) { visibility_cap = INT_MAX; @@ -2476,7 +2503,7 @@ void npc::die( Creature *nkiller ) // Need to unboard from vehicle before dying, otherwise // the vehicle code cannot find us if( in_vehicle ) { - g->m.unboard_vehicle( pos(), true ); + get_map().unboard_vehicle( pos(), true ); } if( is_mounted() ) { monster *critter = mounted_creature.get(); @@ -2499,14 +2526,15 @@ void npc::die( Creature *nkiller ) dead = true; Character::die( nkiller ); + Character &player_character = get_player_character(); if( is_hallucination() ) { - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( _( "%s disappears." ), name.c_str() ); } return; } - if( g->u.sees( *this ) ) { + if( player_character.sees( *this ) ) { add_msg( _( "%s dies!" ), name ); } @@ -2514,15 +2542,15 @@ void npc::die( Creature *nkiller ) g->events().send( ch->getID(), getID(), get_name() ); } - if( killer == &g->u && ( !guaranteed_hostile() || hit_by_player ) ) { - bool cannibal = g->u.has_trait( trait_CANNIBAL ); - bool psycho = g->u.has_trait( trait_PSYCHOPATH ); - if( g->u.has_trait( trait_SAPIOVORE ) || psycho ) { + if( killer == &player_character && ( !guaranteed_hostile() || hit_by_player ) ) { + bool cannibal = player_character.has_trait( trait_CANNIBAL ); + bool psycho = player_character.has_trait( trait_PSYCHOPATH ); + if( player_character.has_trait( trait_SAPIOVORE ) || psycho ) { // No morale effect } else if( cannibal ) { - g->u.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours ); + player_character.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours ); } else { - g->u.add_morale( MORALE_KILLED_INNOCENT, -100, 0, 2_days, 3_hours ); + player_character.add_morale( MORALE_KILLED_INNOCENT, -100, 0, 2_days, 3_hours ); } } @@ -2625,7 +2653,7 @@ void npc::add_msg_if_npc( const std::string &msg ) const void npc::add_msg_player_or_npc( const std::string &/*player_msg*/, const std::string &npc_msg ) const { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( replace_with_npc_name( npc_msg ) ); } } @@ -2639,7 +2667,7 @@ void npc::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &/*player_msg*/, const std::string &npc_msg ) const { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( params, replace_with_npc_name( npc_msg ) ); } } @@ -2724,14 +2752,15 @@ void npc::on_load() // Not necessarily true, but it's not a bad idea to set this has_new_items = true; + map &here = get_map(); // for spawned npcs - if( g->m.has_flag( "UNSTABLE", pos() ) ) { + if( here.has_flag( "UNSTABLE", pos() ) ) { add_effect( effect_bouldering, 1_turns, num_bp, true ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } - if( g->m.veh_at( pos() ).part_with_feature( VPFLAG_BOARDABLE, true ) && !in_vehicle ) { - g->m.board_vehicle( pos(), this ); + if( here.veh_at( pos() ).part_with_feature( VPFLAG_BOARDABLE, true ) && !in_vehicle ) { + here.board_vehicle( pos(), this ); } if( has_effect( effect_riding ) && !mounted_creature ) { if( const monster *const mon = g->critter_at( pos() ) ) { @@ -2803,7 +2832,7 @@ bool npc::dispose_item( item_location &&obj, const std::string & ) if( opts.empty() ) { // Drop it - g->m.add_item_or_charges( pos(), *obj ); + get_map().add_item_or_charges( pos(), *obj ); obj.remove_item(); return true; } @@ -2904,7 +2933,7 @@ bool npc::will_accept_from_player( const item &it ) const return false; } - if( is_minion() || g->u.has_trait( trait_DEBUG_MIND_CONTROL ) || + if( is_minion() || get_player_character().has_trait( trait_DEBUG_MIND_CONTROL ) || it.has_flag( flag_NPC_SAFE ) ) { return true; } @@ -2951,16 +2980,17 @@ std::set npc::get_path_avoid() const // TODO: Cache this somewhere ret.insert( critter.pos() ); } + map &here = get_map(); if( rules.has_flag( ally_rule::avoid_doors ) ) { - for( const tripoint &p : g->m.points_in_radius( pos(), 30 ) ) { - if( g->m.open_door( p, true, true ) ) { + for( const tripoint &p : here.points_in_radius( pos(), 30 ) ) { + if( here.open_door( p, true, true ) ) { ret.insert( p ); } } } if( rules.has_flag( ally_rule::hold_the_line ) ) { - for( const tripoint &p : g->m.points_in_radius( g->u.pos(), 1 ) ) { - if( g->m.close_door( p, true, true ) || g->m.move_cost( p ) > 2 ) { + for( const tripoint &p : here.points_in_radius( get_player_character().pos(), 1 ) ) { + if( here.close_door( p, true, true ) || here.move_cost( p ) > 2 ) { ret.insert( p ); } } @@ -3175,7 +3205,7 @@ void npc::set_attitude( npc_attitude new_attitude ) name, npc_attitude_id( attitude ), npc_attitude_id( new_attitude ) ); attitude_group new_group = get_attitude_group( new_attitude ); attitude_group old_group = get_attitude_group( attitude ); - if( new_group != old_group && !is_fake() && g->u.sees( *this ) ) { + if( new_group != old_group && !is_fake() && get_player_character().sees( *this ) ) { switch( new_group ) { case attitude_group::hostile: add_msg_if_npc( m_bad, _( " gets angry!" ) ); @@ -3336,3 +3366,37 @@ int npc::get_thirst() const { return Character::get_thirst() - units::to_milliliter( stomach.get_water() ) / 5; } + +std::string npc::describe_mission() const +{ + switch( mission ) { + case NPC_MISSION_SHELTER: + return string_format( _( "I'm holing up here for safety. Long term, %s" ), + myclass.obj().get_job_description() ); + case NPC_MISSION_SHOPKEEP: + return _( "I run the shop here." ); + case NPC_MISSION_GUARD: + case NPC_MISSION_GUARD_ALLY: + case NPC_MISSION_GUARD_PATROL: + return string_format( _( "Currently, I'm guarding this location. Overall, %s" ), + myclass.obj().get_job_description() ); + case NPC_MISSION_ACTIVITY: + return string_format( _( "Right now, I'm . In general, %s" ), + myclass.obj().get_job_description() ); + case NPC_MISSION_TRAVELLING: + case NPC_MISSION_NULL: + return myclass.obj().get_job_description(); + default: + return string_format( "ERROR: Someone forgot to code an npc_mission text for " + "mission: %d.", static_cast( mission ) ); + } // switch (mission) +} + +std::unique_ptr get_talker_for( npc &guy ) +{ + return std::make_unique( &guy ); +} +std::unique_ptr get_talker_for( npc *guy ) +{ + return std::make_unique( guy ); +} diff --git a/src/npc.h b/src/npc.h index 48136e010532d..d0a3e1dabad74 100644 --- a/src/npc.h +++ b/src/npc.h @@ -49,6 +49,7 @@ class mission; class monfaction; class monster; class npc_class; +class talker; class vehicle; struct bionic_data; struct mission_type; @@ -853,6 +854,7 @@ class npc : public player int print_info( const catacurses::window &w, int line, int vLines, int column ) const override; std::string opinion_text() const; int faction_display( const catacurses::window &fac_w, int width ) const; + std::string describe_mission() const; // Interaction with the player void form_opinion( const player &u ); @@ -882,23 +884,28 @@ class npc : public player * Martial art styles that we known, but the player p doesn't. */ std::vector styles_offered_to( const player &p ) const; + /** + * Spells that the NPC knows but that the player p doesn't. + * not const because get_spell isn't const and both this and p call it + */ + std::vector spells_offered_to( player &p ); // State checks // We want to kill/mug/etc the player bool is_enemy() const; // Traveling w/ player (whether as a friend or a slave) bool is_following() const; - bool is_obeying( const player &p ) const; + bool is_obeying( const Character &p ) const; bool is_hallucination() const override; // true if the NPC isn't actually real // Ally of or traveling with p - bool is_friendly( const player &p ) const; + bool is_friendly( const Character &p ) const; // Leading the player bool is_leader() const; // Leading, following, or waiting for the player bool is_walking_with() const; // In the same faction - bool is_ally( const player &p ) const; + bool is_ally( const Character &p ) const; // Is an ally of the player bool is_player_ally() const; // Isn't moving @@ -925,8 +932,6 @@ class npc : public player // How closely do we follow the player? int follow_distance() const; - // Dialogue and bartering--see npctalk.cpp - void talk_to_u( bool text_only = false, bool radio_contact = false ); // Re-roll the inventory of a shopkeeper void shop_restock(); // Use and assessment of items @@ -955,7 +960,7 @@ class npc : public player bool has_painkiller(); bool took_painkiller() const; void use_painkiller(); - void activate_item( int item_index ); + void activate_item( item &it ); bool has_identified( const itype_id & ) const override { return true; } @@ -1185,8 +1190,8 @@ class npc : public player void heal_player( player &patient ); void heal_self(); void pretend_heal( player &patient, item used ); // healing action of hallucinations - void mug_player( player &mark ); - void look_for_player( const player &sought ); + void mug_player( Character &mark ); + void look_for_player( const Character &sought ); // Do we have an idea of where u are? bool saw_player_recently() const; /** Returns true if food was consumed, false otherwise. */ @@ -1243,7 +1248,7 @@ class npc : public player */ void setpos( const tripoint &pos ) override; void travel_overmap( const tripoint &pos ); - npc_attitude get_attitude() const; + npc_attitude get_attitude() const override; void set_attitude( npc_attitude new_attitude ); void set_mission( npc_mission new_mission ); bool has_activity() const; @@ -1433,5 +1438,6 @@ std::ostream &operator<< ( std::ostream &os, const npc_need &need ); /** Opens a menu and allows player to select a friendly NPC. */ npc *pick_follower(); - +std::unique_ptr get_talker_for( npc &guy ); +std::unique_ptr get_talker_for( npc *guy ); #endif // CATA_SRC_NPC_H diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 8c5aaa03396f6..ebc24c555f300 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -70,6 +70,8 @@ #include "vpart_position.h" #include "vpart_range.h" +class talker; + static const activity_id ACT_OPERATION( "ACT_OPERATION" ); static const activity_id ACT_PULP( "ACT_PULP" ); @@ -108,6 +110,7 @@ static const efftype_id effect_catch_up( "catch_up" ); static const efftype_id effect_disinfected( "disinfected" ); static const efftype_id effect_hallu( "hallu" ); static const efftype_id effect_hit_by_player( "hit_by_player" ); +static const efftype_id effect_hypovolemia( "hypovolemia" ); static const efftype_id effect_infected( "infected" ); static const efftype_id effect_lying_down( "lying_down" ); static const efftype_id effect_no_sight( "no_sight" ); @@ -198,8 +201,6 @@ void print_action( const char *prepend, npc_action action ); bool compare_sound_alert( const dangerous_sound &sound_a, const dangerous_sound &sound_b ); -hp_part most_damaged_hp_part( const Character &c ); - bool compare_sound_alert( const dangerous_sound &sound_a, const dangerous_sound &sound_b ) { if( sound_a.type != sound_b.type ) { @@ -216,7 +217,7 @@ static bool clear_shot_reach( const tripoint &from, const tripoint &to, bool che Creature *inter = g->critter_at( p ); if( check_ally && inter != nullptr ) { return false; - } else if( g->m.impassable( p ) ) { + } else if( get_map().impassable( p ) ) { return false; } } @@ -226,6 +227,7 @@ static bool clear_shot_reach( const tripoint &from, const tripoint &to, bool che tripoint npc::good_escape_direction( bool include_pos ) { + map &here = get_map(); if( path.empty() ) { zone_type_id retreat_zone = zone_type_id( "NPC_RETREAT" ); const tripoint &abs_pos = global_square_location(); @@ -233,7 +235,7 @@ tripoint npc::good_escape_direction( bool include_pos ) cata::optional retreat_target = mgr.get_nearest( retreat_zone, abs_pos, 60, fac_id ); if( retreat_target && *retreat_target != abs_pos ) { - update_path( g->m.getlocal( *retreat_target ) ); + update_path( here.getlocal( *retreat_target ) ); if( !path.empty() ) { return path[0]; } @@ -247,7 +249,7 @@ tripoint npc::good_escape_direction( bool include_pos ) return MAX_FLOAT; } float rating = threat_val; - for( const auto &e : g->m.field_at( pt ) ) { + for( const auto &e : here.field_at( pt ) ) { if( is_dangerous_field( e.second ) ) { // TODO: Rate fire higher than smoke rating += e.second.get_field_intensity(); @@ -277,12 +279,13 @@ tripoint npc::good_escape_direction( bool include_pos ) bool npc::sees_dangerous_field( const tripoint &p ) const { - return is_dangerous_fields( g->m.field_at( p ) ); + return is_dangerous_fields( get_map().field_at( p ) ); } bool npc::could_move_onto( const tripoint &p ) const { - if( !g->m.passable( p ) ) { + map &here = get_map(); + if( !here.passable( p ) ) { return false; } @@ -290,8 +293,8 @@ bool npc::could_move_onto( const tripoint &p ) const return true; } - const auto fields_here = g->m.field_at( pos() ); - for( const auto &e : g->m.field_at( p ) ) { + const auto fields_here = here.field_at( pos() ); + for( const auto &e : here.field_at( p ) ) { if( !is_dangerous_field( e.second ) ) { continue; } @@ -309,7 +312,7 @@ std::vector npc::find_dangerous_explosives() const { std::vector result; - const auto active_items = g->m.get_active_items_in_radius( pos(), MAX_VIEW_DISTANCE, + const auto active_items = get_map().get_active_items_in_radius( pos(), MAX_VIEW_DISTANCE, special_item_type::explosive ); for( const auto &elem : active_items ) { @@ -371,8 +374,9 @@ void npc::assess_danger() invalidate_range_cache(); max_range = *confident_range_cache; } - const auto ok_by_rules = [max_range, def_radius, this]( const Creature & c, int dist, - int scaled_dist ) { + Character &player_character = get_player_character(); + const auto ok_by_rules = [max_range, def_radius, this, &player_character]( const Creature & c, + int dist, int scaled_dist ) { // If we're forbidden to attack, no need to check engagement rules if( rules.has_flag( ally_rule::forbid_engage ) ) { return false; @@ -383,7 +387,7 @@ void npc::assess_danger() case combat_engagement::CLOSE: // Either close to player or close enough that we can reach it and close to us return ( dist <= max_range && scaled_dist <= def_radius * 0.5 ) || - too_close( c.pos(), g->u.pos(), def_radius ); + too_close( c.pos(), player_character.pos(), def_radius ); case combat_engagement::WEAK: return c.get_hp() <= average_damage_dealt(); case combat_engagement::HIT: @@ -403,13 +407,14 @@ void npc::assess_danger() for( direction threat_dir : npc_threat_dir ) { cur_threat_map[ threat_dir ] = 0.25f * ai_cache.threat_map[ threat_dir ]; } + map &here = get_map(); // first, check if we're about to be consumed by fire // TODO: Use the field cache - for( const tripoint &pt : g->m.points_in_radius( pos(), 6 ) ) { - if( pt == pos() || g->m.has_flag( TFLAG_FIRE_CONTAINER, pt ) ) { + for( const tripoint &pt : here.points_in_radius( pos(), 6 ) ) { + if( pt == pos() || here.has_flag( TFLAG_FIRE_CONTAINER, pt ) ) { continue; } - if( g->m.get_field( pt, fd_fire ) != nullptr ) { + if( here.get_field( pt, fd_fire ) != nullptr ) { int dist = rl_dist( pos(), pt ); cur_threat_map[direction_from( pos(), pt )] += 2.0f * ( NPC_DANGER_MAX - dist ); if( dist < 3 && !has_effect( effect_npc_fire_bad ) ) { @@ -435,11 +440,11 @@ void npc::assess_danger() hostile_guys.emplace_back( g->shared_from( guy ) ); } } - if( sees( g->u.pos() ) ) { + if( sees( player_character.pos() ) ) { if( is_enemy() ) { - hostile_guys.emplace_back( g->shared_from( g->u ) ); - } else if( is_friendly( g->u ) ) { - ai_cache.friends.emplace_back( g->shared_from( g->u ) ); + hostile_guys.emplace_back( g->shared_from( player_character ) ); + } else if( is_friendly( player_character ) ) { + ai_cache.friends.emplace_back( g->shared_from( player_character ) ); } } @@ -511,7 +516,7 @@ void npc::assess_danger() ai_cache.danger_assessment = assessment; return; } - const auto handle_hostile = [&]( const player & foe, float foe_threat, + const auto handle_hostile = [&]( const Character & foe, float foe_threat, const std::string & bogey, const std::string & warning ) { int dist = rl_dist( pos(), foe.pos() ); if( foe_threat > ( 8.0f + personality.bravery + rng( 0, 5 ) ) ) { @@ -564,16 +569,16 @@ void npc::assess_danger() assessment = std::max( min_danger, assessment - guy_threat * 0.5f ); } - if( sees( g->u.pos() ) ) { + if( sees( player_character.pos() ) ) { // Mod for the player // cap player difficulty at 150 - float player_diff = evaluate_enemy( g->u ); + float player_diff = evaluate_enemy( player_character ); if( is_enemy() ) { - assessment += handle_hostile( g->u, player_diff, "maniac", "kill_player" ); - } else if( is_friendly( g->u ) ) { + assessment += handle_hostile( player_character, player_diff, "maniac", "kill_player" ); + } else if( is_friendly( player_character ) ) { float min_danger = assessment >= NPC_DANGER_VERY_LOW ? NPC_DANGER_VERY_LOW : -10.0f; assessment = std::max( min_danger, assessment - player_diff * 0.5f ); - ai_cache.friends.emplace_back( g->shared_from( g->u ) ); + ai_cache.friends.emplace_back( g->shared_from( player_character ) ); } } assessment *= 0.1f; @@ -626,11 +631,12 @@ float npc::character_danger( const Character &uc ) const void npc::regen_ai_cache() { + map &here = get_map(); auto i = std::begin( ai_cache.sound_alerts ); while( i != std::end( ai_cache.sound_alerts ) ) { - if( sees( g->m.getlocal( i->abs_pos ) ) ) { + if( sees( here.getlocal( i->abs_pos ) ) ) { // if they were responding to a call for guards because of thievery - npc *const sound_source = g->critter_at( g->m.getlocal( i->abs_pos ) ); + npc *const sound_source = g->critter_at( here.getlocal( i->abs_pos ) ); if( sound_source ) { if( my_fac == sound_source->my_fac && sound_source->known_stolen_item ) { sound_source->known_stolen_item = nullptr; @@ -663,6 +669,7 @@ void npc::regen_ai_cache() } // Non-allied NPCs with a completed mission should move to the player if( !is_player_ally() && !is_stationary( true ) ) { + Character &player_character = get_player_character(); for( auto &miss : chatbin.missions_assigned ) { if( miss->is_complete( getID() ) ) { // unless the player found an item and already told the NPC he wanted to keep it @@ -672,8 +679,8 @@ void npc::regen_ai_cache() has_effect( effect_npc_player_still_looking ) ) { continue; } - if( global_omt_location() != g->u.global_omt_location() ) { - goal = g->u.global_omt_location(); + if( global_omt_location() != player_character.global_omt_location() ) { + goal = player_character.global_omt_location(); } set_attitude( NPCATT_TALK ); break; @@ -709,8 +716,9 @@ void npc::move() name, target_name, ai_cache.danger, weapon.is_gun() ? confident_shoot_range( weapon, recoil_total() ) : weapon.reach_range( *this ) ); + Character &player_character = get_player_character(); //faction opinion determines if it should consider you hostile - if( !is_enemy() && guaranteed_hostile() && sees( g->u ) ) { + if( !is_enemy() && guaranteed_hostile() && sees( player_character ) ) { if( is_player_ally() ) { mutiny(); } @@ -747,12 +755,13 @@ void npc::move() if( is_enemy() && vehicle_danger( avoidance_vehicles_radius ) > 0 ) { // TODO: Think about how this actually needs to work, for now assume flee from player - ai_cache.target = g->shared_from( g->u ); + ai_cache.target = g->shared_from( player_character ); } + map &here = get_map(); if( !ai_cache.dangerous_explosives.empty() ) { action = npc_escape_explosion; - } else if( target == &g->u && attitude == NPCATT_FLEE_TEMP ) { + } else if( target == &player_character && attitude == NPCATT_FLEE_TEMP ) { action = method_of_fleeing(); } else if( has_effect( effect_npc_run_away ) ) { action = method_of_fleeing(); @@ -765,7 +774,7 @@ void npc::move() } else if( !ai_cache.sound_alerts.empty() && !is_walking_with() ) { tripoint cur_s_abs_pos = ai_cache.s_abs_pos; if( !ai_cache.guard_pos ) { - ai_cache.guard_pos = g->m.getabs( pos() ); + ai_cache.guard_pos = here.getabs( pos() ); } if( ai_cache.sound_alerts.size() > 1 ) { std::sort( ai_cache.sound_alerts.begin(), ai_cache.sound_alerts.end(), @@ -810,7 +819,7 @@ void npc::move() } if( action == npc_undecided && is_walking_with() && rules.has_flag( ally_rule::follow_close ) && - rl_dist( pos(), g->u.pos() ) > follow_distance() ) { + rl_dist( pos(), player_character.pos() ) > follow_distance() ) { action = npc_follow_player; } @@ -829,7 +838,7 @@ void npc::move() if( !activity_route.empty() && !has_destination_activity() ) { tripoint final_destination; if( destination_point ) { - final_destination = g->m.getlocal( *destination_point ); + final_destination = here.getlocal( *destination_point ); } else { final_destination = activity_route.back(); } @@ -850,7 +859,7 @@ void npc::move() // an interrupted activity can cause this situation. stops allied NPCs zooming off like random NPCs if( attitude == NPCATT_ACTIVITY && !activity ) { revert_after_activity(); - if( is_ally( g->u ) ) { + if( is_ally( player_character ) ) { attitude = NPCATT_FOLLOW; mission = NPC_MISSION_NULL; } @@ -882,7 +891,7 @@ void npc::move() } // check if in vehicle before rushing off to fetch things - if( is_walking_with() && g->u.in_vehicle ) { + if( is_walking_with() && player_character.in_vehicle ) { action = npc_follow_embarked; } else if( fetching_item ) { // Set to true if find_item() found something @@ -911,7 +920,8 @@ void npc::move() ( ( action == npc_follow_embarked && in_vehicle ) || ( action == npc_follow_player && - ( rl_dist( pos(), g->u.pos() ) <= follow_distance() || posz() != g->u.posz() ) ) + ( rl_dist( pos(), player_character.pos() ) <= follow_distance() || + posz() != player_character.posz() ) ) ) ) { action = method_of_attack(); } @@ -935,6 +945,8 @@ void npc::execute_action( npc_action action ) name, target, npc_action_name(action)); */ + Character &player_character = get_player_character(); + map &here = get_map(); switch( action ) { case npc_pause: move_pause(); @@ -949,7 +961,7 @@ void npc::execute_action( npc_action action ) case npc_investigate_sound: { tripoint cur_pos = pos(); - update_path( g->m.getlocal( ai_cache.s_abs_pos ) ); + update_path( here.getlocal( ai_cache.s_abs_pos ) ); move_to_next(); if( pos() == cur_pos ) { ai_cache.stuck += 1; @@ -958,7 +970,7 @@ void npc::execute_action( npc_action action ) break; case npc_return_to_guard_pos: { - const tripoint local_guard_pos = g->m.getlocal( *ai_cache.guard_pos ); + const tripoint local_guard_pos = here.getlocal( *ai_cache.guard_pos ); update_path( local_guard_pos ); if( pos() == local_guard_pos || path.empty() ) { move_pause(); @@ -975,7 +987,7 @@ void npc::execute_action( npc_action action ) // Find a nice spot to sleep int best_sleepy = sleep_spot( pos() ); tripoint best_spot = pos(); - for( const tripoint &p : closest_tripoints_first( pos(), 6 ) ) { + for( const tripoint &p : closest_points_first( pos(), 6 ) ) { if( !could_move_onto( p ) || !g->is_empty( p ) ) { continue; } @@ -997,7 +1009,7 @@ void npc::execute_action( npc_action action ) if( !has_effect( effect_lying_down ) ) { activate_bionic_by_id( bio_soporific ); add_effect( effect_lying_down, 30_minutes, num_bp, false, 1 ); - if( g->u.sees( *this ) && !g->u.in_sleep_state() ) { + if( player_character.sees( *this ) && !player_character.in_sleep_state() ) { add_msg( _( "%s lies down to sleep." ), name ); } } @@ -1055,7 +1067,7 @@ void npc::execute_action( npc_action action ) melee_attack( *cur, true ); } } else { - look_for_player( g->u ); + look_for_player( player_character ); } break; @@ -1087,7 +1099,7 @@ void npc::execute_action( npc_action action ) update_path( *last_player_seen_pos ); move_to_next(); } else { - look_for_player( g->u ); + look_for_player( player_character ); } break; @@ -1107,9 +1119,9 @@ void npc::execute_action( npc_action action ) break; } case npc_follow_player: - update_path( g->u.pos() ); + update_path( player_character.pos() ); if( static_cast( path.size() ) <= follow_distance() && - g->u.posz() == posz() ) { // We're close enough to u. + player_character.posz() == posz() ) { // We're close enough to u. move_pause(); } else if( !path.empty() ) { move_to_next(); @@ -1121,7 +1133,7 @@ void npc::execute_action( npc_action action ) break; case npc_follow_embarked: { - const optional_vpart_position vp = g->m.veh_at( g->u.pos() ); + const optional_vpart_position vp = here.veh_at( player_character.pos() ); if( !vp ) { debugmsg( "Following an embarked player with no vehicle at their location?" ); @@ -1134,7 +1146,7 @@ void npc::execute_action( npc_action action ) // Try to find the last destination // This is mount point, not actual position point last_dest( INT_MIN, INT_MIN ); - if( !path.empty() && veh_pointer_or_null( g->m.veh_at( path[path.size() - 1] ) ) == veh ) { + if( !path.empty() && veh_pointer_or_null( here.veh_at( path[path.size() - 1] ) ) == veh ) { last_dest = vp->mount(); } @@ -1226,12 +1238,12 @@ void npc::execute_action( npc_action action ) break; case npc_talk_to_player: - talk_to_u(); + g->u.talk_to( get_talker_for( this ) ); moves = 0; break; case npc_mug_player: - mug_player( g->u ); + mug_player( player_character ); break; case npc_goto_destination: @@ -1759,6 +1771,7 @@ healing_options npc::patient_assessment( const Character &c ) npc_action npc::address_needs( float danger ) { + Character &player_character = get_player_character(); // rng because NPCs are not meant to be hypervigilant hawks that notice everything // and swing into action with alarming alacrity. // no sometimes they are just looking the other way, sometimes they hestitate. @@ -1777,11 +1790,11 @@ npc_action npc::address_needs( float danger ) } if( get_skill_level( skill_firstaid ) > 0 ) { if( is_player_ally() ) { - healing_options try_to_fix_other = patient_assessment( g->u ); + healing_options try_to_fix_other = patient_assessment( player_character ); if( try_to_fix_other.any_true() ) { ai_cache.can_heal = has_healing_options( try_to_fix_other ); if( ai_cache.can_heal.any_true() ) { - ai_cache.ally = g->shared_from( g->u ); + ai_cache.ally = g->shared_from( player_character ); return npc_heal_player; } } @@ -1833,8 +1846,8 @@ npc_action npc::address_needs( float danger ) } } //Does the hallucination needs to disappear ? - if( is_hallucination() && g->u.sees( *this ) ) { - if( !g->u.has_effect( effect_hallu ) ) { + if( is_hallucination() && player_character.sees( *this ) ) { + if( !player_character.has_effect( effect_hallu ) ) { die( nullptr ); } } @@ -1872,7 +1885,7 @@ npc_action npc::address_needs( float danger ) if( danger <= 0.01 ) { if( get_fatigue() >= fatigue_levels::TIRED ) { return true; - } else if( is_walking_with() && g->u.in_sleep_state() && + } else if( is_walking_with() && player_character.in_sleep_state() && get_fatigue() > ( fatigue_levels::TIRED / 2 ) ) { return true; } @@ -1889,7 +1902,7 @@ npc_action npc::address_needs( float danger ) if( rules.has_flag( ally_rule::allow_sleep ) || get_fatigue() > fatigue_levels::MASSIVE_FATIGUE ) { return npc_sleep; - } else if( g->u.in_sleep_state() ) { + } else if( player_character.in_sleep_state() ) { // TODO: "Guard me while I sleep" command return npc_sleep; } @@ -1902,12 +1915,13 @@ npc_action npc::address_needs( float danger ) npc_action npc::address_player() { - if( ( attitude == NPCATT_TALK || attitude == NPCATT_RECOVER_GOODS ) && sees( g->u ) ) { - if( g->u.in_sleep_state() ) { + Character &player_character = get_player_character(); + if( ( attitude == NPCATT_TALK || attitude == NPCATT_RECOVER_GOODS ) && sees( player_character ) ) { + if( player_character.in_sleep_state() ) { // Leave sleeping characters alone. return npc_undecided; } - if( rl_dist( pos(), g->u.pos() ) <= 6 ) { + if( rl_dist( pos(), player_character.pos() ) <= 6 ) { return npc_talk_to_player; // Close enough to talk to you } else { if( one_in( 10 ) ) { @@ -1917,7 +1931,7 @@ npc_action npc::address_player() } } - if( attitude == NPCATT_MUG && sees( g->u ) ) { + if( attitude == NPCATT_MUG && sees( player_character ) ) { if( one_in( 3 ) ) { say( _( "Don't move a muscle…" ) ); } @@ -1939,7 +1953,7 @@ npc_action npc::address_player() } if( attitude == NPCATT_LEAD ) { - if( rl_dist( pos(), g->u.pos() ) >= 12 || !sees( g->u ) ) { + if( rl_dist( pos(), player_character.pos() ) >= 12 || !sees( player_character ) ) { int intense = get_effect_int( effect_catch_up ); if( intense < 10 ) { say( "" ); @@ -2152,7 +2166,8 @@ bool npc::update_path( const tripoint &p, const bool no_bashing, bool force ) } } - auto new_path = g->m.route( pos(), p, get_pathfinding_settings( no_bashing ), get_path_avoid() ); + auto new_path = get_map().route( pos(), p, get_pathfinding_settings( no_bashing ), + get_path_avoid() ); if( new_path.empty() ) { if( !ai_cache.sound_alerts.empty() ) { ai_cache.sound_alerts.erase( ai_cache.sound_alerts.begin() ); @@ -2177,27 +2192,29 @@ bool npc::update_path( const tripoint &p, const bool no_bashing, bool force ) bool npc::can_open_door( const tripoint &p, const bool inside ) const { - return !rules.has_flag( ally_rule::avoid_doors ) && g->m.open_door( p, inside, true ); + return !rules.has_flag( ally_rule::avoid_doors ) && get_map().open_door( p, inside, true ); } bool npc::can_move_to( const tripoint &p, bool no_bashing ) const { + map &here = get_map(); // Allow moving into any bashable spots, but penalize them during pathing // Doors are not passable for hallucinations - return( rl_dist( pos(), p ) <= 1 && g->m.has_floor( p ) && !g->is_dangerous_tile( p ) && - ( g->m.passable( p ) || ( can_open_door( p, !g->m.is_outside( pos() ) ) && !is_hallucination() ) || - ( !no_bashing && g->m.bash_rating( smash_ability(), p ) > 0 ) ) + return( rl_dist( pos(), p ) <= 1 && here.has_floor( p ) && !g->is_dangerous_tile( p ) && + ( here.passable( p ) || ( can_open_door( p, !here.is_outside( pos() ) ) && !is_hallucination() ) || + ( !no_bashing && here.bash_rating( smash_ability(), p ) > 0 ) ) ); } void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomove ) { tripoint p = pt; + map &here = get_map(); if( sees_dangerous_field( p ) || ( nomove != nullptr && nomove->find( p ) != nomove->end() ) ) { // Move to a neighbor field instead, if possible. // Maybe this code already exists somewhere? - auto other_points = g->m.get_dir_circle( pos(), p ); + auto other_points = here.get_dir_circle( pos(), p ); for( const tripoint &ot : other_points ) { if( could_move_onto( ot ) && ( nomove == nullptr || nomove->find( ot ) == nomove->end() ) ) { @@ -2256,7 +2273,7 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo return; } - if( critter == &g->u ) { + if( critter->is_avatar() ) { say( "" ); } @@ -2284,7 +2301,7 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo if( !activity_route.empty() && !np->has_destination_activity() ) { tripoint final_destination; if( destination_point ) { - final_destination = g->m.getlocal( *destination_point ); + final_destination = here.getlocal( *destination_point ); } else { final_destination = activity_route.back(); } @@ -2301,8 +2318,8 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo // Boarding moving vehicles is fine, unboarding isn't bool moved = false; - if( const optional_vpart_position vp = g->m.veh_at( pos() ) ) { - const optional_vpart_position ovp = g->m.veh_at( p ); + if( const optional_vpart_position vp = here.veh_at( pos() ) ) { + const optional_vpart_position ovp = here.veh_at( p ); if( vp->vehicle().is_moving() && ( veh_pointer_or_null( ovp ) != veh_pointer_or_null( vp ) || !ovp.part_with_feature( VPFLAG_BOARDABLE, true ) ) ) { @@ -2321,10 +2338,10 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo } moves -= 100; moved = true; - } else if( g->m.passable( p ) && !g->m.has_flag( "DOOR", p ) ) { + } else if( here.passable( p ) && !here.has_flag( "DOOR", p ) ) { bool diag = trigdist && posx() != p.x && posy() != p.y; if( is_mounted() ) { - const double base_moves = run_cost( g->m.combined_movecost( pos(), p ), + const double base_moves = run_cost( here.combined_movecost( pos(), p ), diag ) * 100.0 / mounted_creature->get_speed(); const double encumb_moves = get_weight() / 4800.0_gram; moves -= static_cast( std::ceil( base_moves + encumb_moves ) ); @@ -2332,33 +2349,33 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo mounted_creature->use_mech_power( -1 ); } } else { - moves -= run_cost( g->m.combined_movecost( pos(), p ), diag ); + moves -= run_cost( here.combined_movecost( pos(), p ), diag ); } moved = true; - } else if( g->m.open_door( p, !g->m.is_outside( pos() ), true ) ) { + } else if( here.open_door( p, !here.is_outside( pos() ), true ) ) { if( !is_hallucination() ) { // hallucinations don't open doors - g->m.open_door( p, !g->m.is_outside( pos() ) ); + here.open_door( p, !here.is_outside( pos() ) ); moves -= 100; } else { // hallucinations teleport through doors moves -= 100; moved = true; } - } else if( get_dex() > 1 && g->m.has_flag_ter_or_furn( "CLIMBABLE", p ) ) { + } else if( get_dex() > 1 && here.has_flag_ter_or_furn( "CLIMBABLE", p ) ) { ///\EFFECT_DEX_NPC increases chance to climb CLIMBABLE furniture or terrain int climb = get_dex(); if( one_in( climb ) ) { add_msg_if_npc( m_neutral, _( "%1$s tries to climb the %2$s but slips." ), name, - g->m.tername( p ) ); + here.tername( p ) ); moves -= 400; } else { - add_msg_if_npc( m_neutral, _( "%1$s climbs over the %2$s." ), name, g->m.tername( p ) ); + add_msg_if_npc( m_neutral, _( "%1$s climbs over the %2$s." ), name, here.tername( p ) ); moves -= ( 500 - ( rng( 0, climb ) * 20 ) ); moved = true; } - } else if( !no_bashing && smash_ability() > 0 && g->m.is_bashable( p ) && - g->m.bash_rating( smash_ability(), p ) > 0 ) { + } else if( !no_bashing && smash_ability() > 0 && here.is_bashable( p ) && + here.bash_rating( smash_ability(), p ) > 0 ) { moves -= !is_armed() ? 80 : weapon.attack_time() * 0.8; - g->m.bash( p, smash_ability() ); + here.bash( p, smash_ability() ); } else { if( attitude == NPCATT_MUG || attitude == NPCATT_KILL || @@ -2382,37 +2399,37 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo mounted_creature->setpos( pos() ); mounted_creature->facing = facing; mounted_creature->process_triggers(); - g->m.creature_in_field( *mounted_creature ); - g->m.creature_on_trap( *mounted_creature ); + here.creature_in_field( *mounted_creature ); + here.creature_on_trap( *mounted_creature ); } } - if( g->m.has_flag( "UNSTABLE", pos() ) ) { + if( here.has_flag( "UNSTABLE", pos() ) ) { add_effect( effect_bouldering, 1_turns, num_bp, true ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } - if( g->m.has_flag_ter_or_furn( TFLAG_NO_SIGHT, pos() ) ) { + if( here.has_flag_ter_or_furn( TFLAG_NO_SIGHT, pos() ) ) { add_effect( effect_no_sight, 1_turns, num_bp, true ); } else if( has_effect( effect_no_sight ) ) { remove_effect( effect_no_sight ); } if( in_vehicle ) { - g->m.unboard_vehicle( old_pos ); + here.unboard_vehicle( old_pos ); } // Close doors behind self (if you can) if( ( rules.has_flag( ally_rule::close_doors ) && is_player_ally() ) && !is_hallucination() ) { - doors::close_door( g->m, *this, old_pos ); + doors::close_door( here, *this, old_pos ); } - if( g->m.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ) ) { - g->m.board_vehicle( p, this ); + if( here.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ) ) { + here.board_vehicle( p, this ); } - g->m.creature_on_trap( *this ); - g->m.creature_in_field( *this ); + here.creature_on_trap( *this ); + here.creature_in_field( *this ); } } @@ -2452,7 +2469,7 @@ void npc::avoid_friendly_fire() center.y = std::round( center.y / friend_count ); center.z = std::round( center.z / friend_count ); - std::vector candidates = closest_tripoints_first( pos(), 1 ); + std::vector candidates = closest_points_first( pos(), 1 ); candidates.erase( candidates.begin() ); std::sort( candidates.begin(), candidates.end(), [&tar, ¢er]( const tripoint & l, const tripoint & r ) { @@ -2495,7 +2512,8 @@ void npc::move_away_from( const tripoint &pt, bool no_bash_atk, std::setm.points_in_radius( pos(), 1 ) ) { + map &here = get_map(); + for( const tripoint &p : here.points_in_radius( pos(), 1 ) ) { if( nomove != nullptr && nomove->find( p ) != nomove->end() ) { continue; } @@ -2504,11 +2522,11 @@ void npc::move_away_from( const tripoint &pt, bool no_bash_atk, std::setu.pos() ) { + if( p == get_player_character().pos() ) { continue; } - const int cost = g->m.combined_movecost( pos(), p ); + const int cost = here.combined_movecost( pos(), p ); if( cost <= 0 ) { continue; } @@ -2548,17 +2566,18 @@ bool npc::find_job_to_perform() void npc::worker_downtime() { + map &here = get_map(); // are we already in a chair - if( g->m.has_flag_furn( "CAN_SIT", pos() ) ) { + if( here.has_flag_furn( "CAN_SIT", pos() ) ) { // just chill here move_pause(); return; } // already know of a chair, go there if( chair_pos != no_goal_point ) { - if( g->m.has_flag_furn( "CAN_SIT", g->m.getlocal( chair_pos ) ) ) { - update_path( g->m.getlocal( chair_pos ) ); - if( pos() == g->m.getlocal( chair_pos ) || path.empty() ) { + if( here.has_flag_furn( "CAN_SIT", here.getlocal( chair_pos ) ) ) { + update_path( here.getlocal( chair_pos ) ); + if( pos() == here.getlocal( chair_pos ) || path.empty() ) { move_pause(); path.clear(); } else { @@ -2572,11 +2591,11 @@ void npc::worker_downtime() } else { // find a chair if( !is_mounted() ) { - for( const tripoint &elem : g->m.points_in_radius( pos(), 30 ) ) { - if( g->m.has_flag_furn( "CAN_SIT", elem ) && !g->critter_at( elem ) && could_move_onto( elem ) && - g->m.point_within_camp( g->m.getabs( elem ) ) ) { + for( const tripoint &elem : here.points_in_radius( pos(), 30 ) ) { + if( here.has_flag_furn( "CAN_SIT", elem ) && !g->critter_at( elem ) && could_move_onto( elem ) && + here.point_within_camp( here.getabs( elem ) ) ) { // this one will do - chair_pos = g->m.getabs( elem ); + chair_pos = here.getabs( elem ); return; } } @@ -2585,8 +2604,8 @@ void npc::worker_downtime() // we got here if there are no chairs available. // wander back to near the bulletin board of the camp. if( wander_pos != no_goal_point ) { - update_path( g->m.getlocal( wander_pos ) ); - if( pos() == g->m.getlocal( wander_pos ) || path.empty() ) { + update_path( here.getlocal( wander_pos ) ); + if( pos() == here.getlocal( wander_pos ) || path.empty() ) { move_pause(); path.clear(); if( one_in( 30 ) ) { @@ -2606,16 +2625,16 @@ void npc::worker_downtime() } basecamp *temp_camp = *bcp; std::vector pts; - for( const tripoint &elem : g->m.points_in_radius( g->m.getlocal( temp_camp->get_bb_pos() ), + for( const tripoint &elem : here.points_in_radius( here.getlocal( temp_camp->get_bb_pos() ), 10 ) ) { - if( g->critter_at( elem ) || !could_move_onto( elem ) || g->m.has_flag( TFLAG_DEEP_WATER, elem ) || - !g->m.has_floor( elem ) || g->is_dangerous_tile( elem ) ) { + if( g->critter_at( elem ) || !could_move_onto( elem ) || here.has_flag( TFLAG_DEEP_WATER, elem ) || + !here.has_floor( elem ) || g->is_dangerous_tile( elem ) ) { continue; } pts.push_back( elem ); } if( !pts.empty() ) { - wander_pos = g->m.getabs( random_entry( pts ) ); + wander_pos = here.getabs( random_entry( pts ) ); return; } } @@ -2653,19 +2672,20 @@ void npc::move_pause() static cata::optional nearest_passable( const tripoint &p, const tripoint &closest_to ) { - if( g->m.passable( p ) ) { + map &here = get_map(); + if( here.passable( p ) ) { return p; } // We need to path to adjacent tile, not the exact one // Let's pick the closest one to us that is passable - std::vector candidates = closest_tripoints_first( p, 1 ); + std::vector candidates = closest_points_first( p, 1 ); std::sort( candidates.begin(), candidates.end(), [ closest_to ]( const tripoint & l, const tripoint & r ) { return rl_dist( closest_to, l ) < rl_dist( closest_to, r ); } ); - auto iter = std::find_if( candidates.begin(), candidates.end(), []( const tripoint & pt ) { - return g->m.passable( pt ); + auto iter = std::find_if( candidates.begin(), candidates.end(), [&here]( const tripoint & pt ) { + return here.passable( pt ); } ); if( iter != candidates.end() ) { return *iter; @@ -2690,13 +2710,14 @@ void npc::move_away_from( const std::vector &spheres, bool no_bashing ) maxp.y = std::max( maxp.y, elem.center.y + elem.radius ); } - const tripoint_range range( minp, maxp ); + const tripoint_range range( minp, maxp ); std::vector escape_points; + map &here = get_map(); std::copy_if( range.begin(), range.end(), std::back_inserter( escape_points ), - [&]( const tripoint & elem ) { - return g->m.passable( elem ); + [&here]( const tripoint & elem ) { + return here.passable( elem ); } ); cata::sort_by_rating( escape_points.begin(), escape_points.end(), [&]( const tripoint & elem ) { @@ -2706,7 +2727,7 @@ void npc::move_away_from( const std::vector &spheres, bool no_bashing ) } ); const int distance = rl_dist( pos(), elem ); - const int move_cost = g->m.move_cost( elem ); + const int move_cost = here.move_cost( elem ); return std::make_tuple( danger, distance, move_cost ); } ); @@ -2728,9 +2749,10 @@ void npc::move_away_from( const std::vector &spheres, bool no_bashing ) void npc::see_item_say_smth( const itype_id &object, const std::string &smth ) { - for( const tripoint &p : closest_tripoints_first( pos(), 6 ) ) { - if( g->m.sees_some_items( p, *this ) && sees( p ) ) { - for( const item &it : g->m.i_at( p ) ) { + map &here = get_map(); + for( const tripoint &p : closest_points_first( pos(), 6 ) ) { + if( here.sees_some_items( p, *this ) && sees( p ) ) { + for( const item &it : here.i_at( p ) ) { if( one_in( 100 ) && ( it.typeId() == object ) ) { say( smth ); } @@ -2788,8 +2810,10 @@ void npc::find_item() npc *npc_to_add = npc_to_get.get(); followers.push_back( npc_to_add ); } + Character &player_character = get_player_character(); for( auto &elem : followers ) { - if( !it.is_owned_by( *this, true ) && ( g->u.sees( this->pos() ) || g->u.sees( wanted_item_pos ) || + if( !it.is_owned_by( *this, true ) && ( player_character.sees( this->pos() ) || + player_character.sees( wanted_item_pos ) || elem->sees( this->pos() ) || elem->sees( wanted_item_pos ) ) ) { return; } @@ -2810,16 +2834,17 @@ void npc::find_item() } }; + map &here = get_map(); // Harvest item doesn't exist, so we'll be checking by its name std::string wanted_name; const auto consider_terrain = - [ this, whitelisting, volume_allowed, &wanted, &wanted_name ]( const tripoint & p ) { + [ this, whitelisting, volume_allowed, &wanted, &wanted_name, &here ]( const tripoint & p ) { // We only want to pick plants when there are no items to pick if( !whitelisting || wanted != nullptr || !wanted_name.empty() || volume_allowed < 250_ml ) { return; } - const auto harvest = g->m.get_harvest_names( p ); + const auto &harvest = here.get_harvest_names( p ); for( const auto &entry : harvest ) { if( item_name_whitelisted( entry ) ) { wanted_name = entry; @@ -2829,7 +2854,7 @@ void npc::find_item() } }; - for( const tripoint &p : closest_tripoints_first( pos(), range ) ) { + for( const tripoint &p : closest_points_first( pos(), range ) ) { // TODO: Make this sight check not overdraw nearby tiles // TODO: Optimize that zone check if( is_player_ally() && g->check_zone( zone_type_no_npc_pickup, p ) ) { @@ -2839,9 +2864,9 @@ void npc::find_item() const tripoint abs_p = global_square_location() - pos() + p; const int prev_num_items = ai_cache.searched_tiles.get( abs_p, -1 ); // Prefetch the number of items present so we can bail out if we already checked here. - const map_stack m_stack = g->m.i_at( p ); + const map_stack m_stack = here.i_at( p ); int num_items = m_stack.size(); - const optional_vpart_position vp = g->m.veh_at( p ); + const optional_vpart_position vp = here.veh_at( p ); if( vp ) { const cata::optional cargo = vp.part_with_feature( VPFLAG_CARGO, true ); if( cargo ) { @@ -2858,7 +2883,7 @@ void npc::find_item() } }; bool can_see = false; - if( g->m.sees_some_items( p, *this ) && sees( p ) ) { + if( here.sees_some_items( p, *this ) && sees( p ) ) { can_see = true; for( const item &it : m_stack ) { consider_item( it, p ); @@ -2935,12 +2960,13 @@ void npc::pick_up_item() return; } - const cata::optional vp = g->m.veh_at( wanted_item_pos ).part_with_feature( + map &here = get_map(); + const cata::optional vp = here.veh_at( wanted_item_pos ).part_with_feature( VPFLAG_CARGO, false ); const bool has_cargo = vp && !vp->has_feature( "LOCKED" ); - if( ( !g->m.has_items( wanted_item_pos ) && !has_cargo && - !g->m.is_harvestable( wanted_item_pos ) && sees( wanted_item_pos ) ) || + if( ( !here.has_items( wanted_item_pos ) && !has_cargo && + !here.is_harvestable( wanted_item_pos ) && sees( wanted_item_pos ) ) || ( is_player_ally() && g->check_zone( zone_type_id( "NO_NPC_PICKUP" ), wanted_item_pos ) ) ) { // Items we wanted no longer exist and we can see it // Or player who is leading us doesn't want us to pick it up @@ -2980,16 +3006,17 @@ void npc::pick_up_item() if( picked_up.empty() ) { // Last chance: plant harvest - if( g->m.is_harvestable( wanted_item_pos ) ) { - g->m.examine( *this, wanted_item_pos ); + if( here.is_harvestable( wanted_item_pos ) ) { + here.examine( *this, wanted_item_pos ); // Note: we didn't actually pick up anything, just spawned items // but we want the item picker to find new items fetching_item = false; return; } } + Character &player_character = get_player_character(); // Describe the pickup to the player - bool u_see = g->u.sees( *this ) || g->u.sees( wanted_item_pos ); + bool u_see = player_character.sees( *this ) || player_character.sees( wanted_item_pos ); if( u_see ) { if( picked_up.size() == 1 ) { add_msg( _( "%1$s picks up a %2$s." ), name, picked_up.front().tname() ); @@ -3066,7 +3093,7 @@ std::list npc_pickup_from_stack( npc &who, T &items ) std::list npc::pick_up_item_map( const tripoint &where ) { - map_stack stack = g->m.i_at( where ); + map_stack stack = get_map().i_at( where ); return npc_pickup_from_stack( *this, stack ); } @@ -3135,6 +3162,7 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ } } + map &here = get_map(); std::string item_name; // For description below int num_items_dropped = 0; // For description below // Now, drop items, starting from the top of each list @@ -3172,7 +3200,7 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ } weight_dropped += slice[index]->front().weight(); volume_dropped += slice[index]->front().volume(); - item dropped = i_rem( index ); + item dropped = i_rem( &i_at( index ) ); num_items_dropped++; if( num_items_dropped == 1 ) { item_name += dropped.tname(); @@ -3180,11 +3208,11 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ item_name += _( " and " ) + dropped.tname(); } if( !is_hallucination() ) { // hallucinations can't drop real items - g->m.add_item_or_charges( pos(), dropped ); + here.add_item_or_charges( pos(), dropped ); } } // Finally, describe the action if u can see it - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { if( num_items_dropped >= 3 ) { add_msg( ngettext( "%s drops %d item.", "%s drops %d items.", num_items_dropped ), name, num_items_dropped ); @@ -3197,20 +3225,23 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ bool npc::find_corpse_to_pulp() { - if( ( is_player_ally() && ( !rules.has_flag( ally_rule::allow_pulp ) || g->u.in_vehicle ) ) || + Character &player_character = get_player_character(); + if( ( is_player_ally() && ( !rules.has_flag( ally_rule::allow_pulp ) || + player_character.in_vehicle ) ) || is_hallucination() ) { return false; } + map &here = get_map(); // Pathing with overdraw can get expensive, limit it int path_counter = 4; - const auto check_tile = [this, &path_counter]( const tripoint & p ) -> const item * { - if( !g->m.sees_some_items( p, *this ) || !sees( p ) ) + const auto check_tile = [this, &path_counter, &here]( const tripoint & p ) -> const item * { + if( !here.sees_some_items( p, *this ) || !sees( p ) ) { return nullptr; } - const map_stack items = g->m.i_at( p ); + const map_stack items = here.i_at( p ); const item *found = nullptr; for( const item &it : items ) { @@ -3250,8 +3281,8 @@ bool npc::find_corpse_to_pulp() if( corpse == nullptr ) { // If we're following the player, don't wander off to pulp corpses - const tripoint &around = is_walking_with() ? g->u.pos() : pos(); - for( const item_location &location : g->m.get_active_items_in_radius( around, range, + const tripoint &around = is_walking_with() ? player_character.pos() : pos(); + for( const item_location &location : here.get_active_items_in_radius( around, range, special_item_type::corpse ) ) { corpse = check_tile( location.position() ); @@ -3285,7 +3316,7 @@ bool npc::do_pulp() // TODO: Don't recreate the activity every time int old_moves = moves; assign_activity( ACT_PULP, calendar::INDEFINITELY_LONG, 0 ); - activity.placement = g->m.getabs( *pulp_location ); + activity.placement = get_map().getabs( *pulp_location ); activity.do_turn( *this ); return moves != old_moves; } @@ -3426,9 +3457,9 @@ bool npc::scan_new_items() // TODO: Armor? } -static void npc_throw( npc &np, item &it, int index, const tripoint &pos ) +static void npc_throw( npc &np, item &it, const tripoint &pos ) { - if( g->u.sees( np ) ) { + if( get_player_character().sees( np ) ) { add_msg( _( "%1$s throws a %2$s." ), np.name, it.tname() ); } @@ -3442,7 +3473,7 @@ static void npc_throw( npc &np, item &it, int index, const tripoint &pos ) } // Throw a single charge of a stacking object. if( stack_size == -1 || stack_size == 1 ) { - np.i_rem( index ); + np.i_rem( &it ); } else { it.charges = stack_size - 1; } @@ -3507,15 +3538,9 @@ bool npc::alt_attack() return false; } - int weapon_index = get_item_position( used ); - if( weapon_index == INT_MIN ) { - debugmsg( "npc::alt_attack() couldn't find expected item %s", used->tname() ); - return false; - } - // Are we going to throw this item? if( !used->active && used->has_flag( "NPC_ACTIVATE" ) ) { - activate_item( weapon_index ); + activate_item( *used ); // Note: intentional lack of return here // We want to ignore player-centric rules to avoid carrying live explosives // TODO: Non-grenades @@ -3525,7 +3550,7 @@ bool npc::alt_attack() int conf = confident_throw_range( *used, critter ); const bool wont_hit = wont_hit_friend( tar, *used, true ); if( dist <= conf && wont_hit ) { - npc_throw( *this, *used, weapon_index, tar ); + npc_throw( *this, *used, tar ); return true; } @@ -3543,9 +3568,10 @@ bool npc::alt_attack() return true; } + map &here = get_map(); // We need to throw this live (grenade, etc) NOW! Pick another target? for( int dist = 2; dist <= conf; dist++ ) { - for( const tripoint &pt : g->m.points_in_radius( pos(), dist ) ) { + for( const tripoint &pt : here.points_in_radius( pos(), dist ) ) { const monster *const target_ptr = g->critter_at( pt ); int newdist = rl_dist( pos(), pt ); // TODO: Change "newdist >= 2" to "newdist >= safe_distance(used)" @@ -3569,7 +3595,7 @@ bool npc::alt_attack() */ int best_dist = 0; for( int dist = 2; dist <= conf; dist++ ) { - for( const tripoint &pt : g->m.points_in_radius( pos(), dist ) ) { + for( const tripoint &pt : here.points_in_radius( pos(), dist ) ) { int new_dist = rl_dist( pos(), pt ); if( new_dist > best_dist && wont_hit_friend( pt, *used, true ) ) { best_dist = new_dist; @@ -3581,14 +3607,13 @@ bool npc::alt_attack() * should be equal to the original location of our target, and risking friendly * fire is better than holding on to a live grenade / whatever. */ - npc_throw( *this, *used, weapon_index, tar ); + npc_throw( *this, *used, tar ); return true; } -void npc::activate_item( int item_index ) +void npc::activate_item( item &it ) { const int oldmoves = moves; - item &it = i_at( item_index ); if( it.is_tool() || it.is_food() ) { it.type->invoke( *this, it, pos() ); } @@ -3611,8 +3636,9 @@ void npc::heal_player( player &patient ) return; } + Character &player_character = get_player_character(); // Close enough to heal! - bool u_see = g->u.sees( *this ) || g->u.sees( patient ); + bool u_see = player_character.sees( *this ) || player_character.sees( patient ); if( u_see ) { add_msg( _( "%1$s heals %2$s." ), disp_name(), patient.disp_name() ); } @@ -3633,7 +3659,7 @@ void npc::heal_player( player &patient ) void npc:: pretend_heal( player &patient, item used ) { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( _( "%1$s heals %2$s." ), disp_name(), patient.disp_name() ); // you can tell that it's not real by looking at your HP though } @@ -3667,7 +3693,7 @@ void npc::heal_self() return; } - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( _( "%s applies a %s" ), disp_name(), used.tname() ); } warn_about( "heal_self", 1_turns ); @@ -3687,7 +3713,7 @@ void npc::use_painkiller() debugmsg( "NPC tried to use painkillers, but has none!" ); move_pause(); } else { - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( _( "%1$s takes some %2$s." ), disp_name(), it->tname() ); } item_location loc = item_location( *this, it ); @@ -3789,8 +3815,9 @@ bool npc::consume_food_from_camp() if( !is_player_ally() ) { return false; } + Character &player_character = get_player_character(); cata::optional potential_bc; - for( const tripoint &camp_pos : g->u.camps ) { + for( const tripoint &camp_pos : player_character.camps ) { if( rl_dist( camp_pos, global_omt_location() ) < 3 ) { potential_bc = overmap_buffer.find_camp( camp_pos.xy() ); if( potential_bc ) { @@ -3807,7 +3834,7 @@ bool npc::consume_food_from_camp() set_thirst( 0 ); return true; } - faction *yours = g->u.get_faction(); + faction *yours = player_character.get_faction(); int camp_kcals = std::min( std::max( 0, 19 * get_healthy_kcal() / 20 - get_stored_kcal() - stomach.get_calories() ), yours->food_supply ); if( camp_kcals > 0 ) { @@ -3862,7 +3889,7 @@ bool npc::consume_food() return consumed; } -void npc::mug_player( player &mark ) +void npc::mug_player( Character &mark ) { if( mark.is_armed() ) { make_angry(); @@ -3874,7 +3901,8 @@ void npc::mug_player( player &mark ) return; } - const bool u_see = g->u.sees( *this ) || g->u.sees( mark ); + Character &player_character = get_player_character(); + const bool u_see = player_character.sees( *this ) || player_character.sees( mark ); if( mark.cash > 0 ) { if( !is_hallucination() ) { // hallucinations can't take items cash += mark.cash; @@ -3940,7 +3968,7 @@ void npc::mug_player( player &mark ) } } -void npc::look_for_player( const player &sought ) +void npc::look_for_player( const Character &sought ) { complain_about( "look_for_player", 5_minutes, "", false ); update_path( sought.pos() ); @@ -3983,7 +4011,8 @@ void npc::look_for_player( const player &sought ) bool npc::saw_player_recently() const { - return last_player_seen_pos && g->m.inbounds( *last_player_seen_pos ) && last_seen_player_turn > 0; + return last_player_seen_pos && get_map().inbounds( *last_player_seen_pos ) && + last_seen_player_turn > 0; } bool npc::has_omt_destination() const @@ -3996,13 +4025,15 @@ void npc::reach_omt_destination() if( !omt_path.empty() ) { omt_path.clear(); } + map &here = get_map(); if( is_travelling() ) { - guard_pos = g->m.getabs( pos() ); + guard_pos = here.getabs( pos() ); goal = no_goal_point; if( is_player_ally() ) { + Character &player_character = get_player_character(); talk_function::assign_guard( *this ); - if( rl_dist( g->u.pos(), pos() ) > SEEX * 2 || !g->u.sees( pos() ) ) { - if( g->u.has_item_with_flag( "TWO_WAY_RADIO", true ) && + if( rl_dist( player_character.pos(), pos() ) > SEEX * 2 || !player_character.sees( pos() ) ) { + if( player_character.has_item_with_flag( "TWO_WAY_RADIO", true ) && has_item_with_flag( "TWO_WAY_RADIO", true ) ) { add_msg( m_info, _( "From your two-way radio you hear %s reporting in, " "'I've arrived, boss!'" ), disp_name() ); @@ -4029,7 +4060,7 @@ void npc::reach_omt_destination() } // If we are guarding, remember our position in case we get forcibly moved goal = global_omt_location(); - if( guard_pos == g->m.getabs( pos() ) ) { + if( guard_pos == here.getabs( pos() ) ) { // This is the specific point return; } @@ -4038,10 +4069,10 @@ void npc::reach_omt_destination() // No point recalculating the path to get home move_to_next(); } else if( guard_pos != no_goal_point ) { - update_path( g->m.getlocal( guard_pos ) ); + update_path( here.getlocal( guard_pos ) ); move_to_next(); } else { - guard_pos = g->m.getabs( pos() ); + guard_pos = here.getabs( pos() ); } } @@ -4065,7 +4096,7 @@ void npc::set_omt_destination() // all of the following luxuries are at ground level. // so please wallow in hunger & fear if below ground. - if( posz() != 0 && !g->m.has_zlevels() ) { + if( posz() != 0 && !get_map().has_zlevels() ) { goal = no_goal_point; return; } @@ -4135,8 +4166,9 @@ void npc::set_omt_destination() void npc::go_to_omt_destination() { + map &here = get_map(); if( ai_cache.guard_pos ) { - if( g->m.getabs( pos() ) == *ai_cache.guard_pos ) { + if( here.getabs( pos() ) == *ai_cache.guard_pos ) { path.clear(); ai_cache.guard_pos = cata::nullopt; move_pause(); @@ -4178,18 +4210,18 @@ void npc::go_to_omt_destination() return; } } - tripoint sm_tri = g->m.getlocal( sm_to_ms_copy( omt_to_sm_copy( omt_path.back() ) ) ); + tripoint sm_tri = here.getlocal( sm_to_ms_copy( omt_to_sm_copy( omt_path.back() ) ) ); tripoint centre_sub = sm_tri + point( SEEX, SEEY ); - if( !g->m.passable( centre_sub ) ) { - auto candidates = g->m.points_in_radius( centre_sub, 2 ); + if( !here.passable( centre_sub ) ) { + auto candidates = here.points_in_radius( centre_sub, 2 ); for( const auto &elem : candidates ) { - if( g->m.passable( elem ) ) { + if( here.passable( elem ) ) { centre_sub = elem; break; } } } - path = g->m.route( pos(), centre_sub, get_pathfinding_settings(), get_path_avoid() ); + path = here.route( pos(), centre_sub, get_pathfinding_settings(), get_path_avoid() ); add_msg( m_debug, "%s going (%d,%d,%d)->(%d,%d,%d)", name, omt_pos.x, omt_pos.y, omt_pos.z, goal.x, goal.y, goal.z ); @@ -4203,7 +4235,7 @@ void npc::go_to_omt_destination() void npc::guard_current_pos() { goal = global_omt_location(); - guard_pos = g->m.getabs( pos() ); + guard_pos = get_map().getabs( pos() ); } std::string npc_action_name( npc_action action ) @@ -4402,7 +4434,7 @@ bool npc::complain_about( const std::string &issue, const time_duration &dur, // Don't wake player up with non-serious complaints // Stop complaining while asleep const bool do_complain = force || ( rules.has_flag( ally_rule::allow_complain ) && - !g->u.in_sleep_state() && !in_sleep_state() ); + !get_player_character().in_sleep_state() && !in_sleep_state() ); if( complain_since( issue, dur ) && do_complain ) { say( speech, priority ); @@ -4418,11 +4450,12 @@ bool npc::complain() static const std::string fatigue_string = "fatigue"; static const std::string bite_string = "bite"; static const std::string bleed_string = "bleed"; + static const std::string hypovolemia_string = "hypovolemia"; static const std::string radiation_string = "radiation"; static const std::string hunger_string = "hunger"; static const std::string thirst_string = "thirst"; - if( !is_player_ally() || !g->u.sees( *this ) ) { + if( !is_player_ally() || !get_player_character().sees( *this ) ) { return false; } @@ -4487,8 +4520,23 @@ bool npc::complain() //Bleeding every 5 minutes if( has_effect( effect_bleed ) ) { const bodypart_id &bp = convert_bp( bp_affected( *this, effect_bleed ) ); - std::string speech = string_format( _( "My %s is bleeding!" ), body_part_name( bp ) ); - if( complain_about( bleed_string, 5_minutes, speech ) ) { + std::string speech; + time_duration often; + if( get_effect( effect_bleed, bp->token ).get_intensity() < 10 ) { + speech = string_format( _( "My %s is bleeding!" ), body_part_name( bp ) ); + often = 5_minutes; + } else { + speech = string_format( _( "My %s is bleeding badly!" ), body_part_name( bp ) ); + often = 1_minutes; + } + if( complain_about( bleed_string, often, speech ) ) { + return true; + } + } + + if( has_effect( effect_hypovolemia ) ) { + std::string speech = _( "I've lost lot of blood." ); + if( complain_about( hypovolemia_string, 10_minutes, speech ) ) { return true; } } @@ -4524,7 +4572,7 @@ void npc::do_reload( const item &it ) moves -= reload_time; recoil = MAX_RECOIL; - if( g->u.sees( *this ) ) { + if( get_player_character().sees( *this ) ) { add_msg( _( "%1$s reloads their %2$s." ), name, it.tname() ); sfx::play_variant_sound( "reload", it.typeId().str(), sfx::get_heard_volume( pos() ), sfx::get_heard_angle( pos() ) ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index dc02ddef94c2e..12a819cf3d5eb 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -69,6 +69,7 @@ #include "string_formatter.h" #include "string_id.h" #include "string_input_popup.h" +#include "talker.h" #include "text_snippets.h" #include "translations.h" #include "ui.h" @@ -87,11 +88,7 @@ static const activity_id ACT_WAIT_NPC( "ACT_WAIT_NPC" ); static const efftype_id effect_lying_down( "lying_down" ); static const efftype_id effect_narcosis( "narcosis" ); -static const efftype_id effect_npc_suspend( "npc_suspend" ); -static const efftype_id effect_pacified( "pacified" ); -static const efftype_id effect_pet( "pet" ); static const efftype_id effect_riding( "riding" ); -static const efftype_id effect_sleep( "sleep" ); static const efftype_id effect_under_operation( "under_operation" ); static const itype_id fuel_type_animal( "animal" ); @@ -101,19 +98,11 @@ static const zone_type_id zone_type_NPC_NO_INVESTIGATE( "NPC_NO_INVESTIGATE" ); static const skill_id skill_speech( "speech" ); -static const bionic_id bio_armor_eyes( "bio_armor_eyes" ); -static const bionic_id bio_deformity( "bio_deformity" ); -static const bionic_id bio_face_mask( "bio_face_mask" ); -static const bionic_id bio_voice( "bio_voice" ); - static const trait_id trait_DEBUG_MIND_CONTROL( "DEBUG_MIND_CONTROL" ); static const trait_id trait_PROF_FOODP( "PROF_FOODP" ); static std::map json_talk_topics; -// Every OWED_VAL that the NPC owes you counts as +1 towards convincing -static constexpr int OWED_VAL = 1000; - #define dbg(x) DebugLog((x),D_GAME) << __FILE__ << ":" << __LINE__ << ": " int topic_category( const talk_topic &the_topic ); @@ -138,7 +127,7 @@ std::string talk_trial::name() const /** Time (in turns) and cost (in cent) for training: */ time_duration calc_skill_training_time( const npc &p, const skill_id &skill ) { - return 1_minutes + 30_seconds * g->u.get_skill_level( skill ) - + return 1_minutes + 30_seconds * get_player_character().get_skill_level( skill ) - 1_seconds * p.get_skill_level( skill ); } @@ -148,7 +137,8 @@ int calc_skill_training_cost( const npc &p, const skill_id &skill ) return 0; } - return 1000 * ( 1 + g->u.get_skill_level( skill ) ) * ( 1 + g->u.get_skill_level( skill ) ); + int skill_level = get_player_character().get_skill_level( skill ); + return 1000 * ( 1 + skill_level ) * ( 1 + skill_level ); } // TODO: all styles cost the same and take the same time to train, @@ -256,7 +246,7 @@ static void npc_temp_orders_menu( const std::vector &npc_list ) return; } npc *guy = npc_list.front(); - + Character &player_character = get_player_character(); bool done = false; uilist nmenu; @@ -282,7 +272,7 @@ static void npc_temp_orders_menu( const std::vector &npc_list ) nmenu.reset(); nmenu.text = _( "Issue what temporary order?" ); nmenu.desc_enabled = true; - parse_tags( output_string, g->u, *guy ); + parse_tags( output_string, player_character, *guy ); nmenu.footer_text = output_string; nmenu.addentry( NPC_CHAT_DONE, true, 'd', _( "Done issuing orders" ) ); nmenu.addentry( NPC_CHAT_FORBID_ENGAGE, true, 'f', @@ -340,9 +330,10 @@ static void npc_temp_orders_menu( const std::vector &npc_list ) static void tell_veh_stop_following() { - for( wrapped_vehicle &veh : g->m.get_vehicles() ) { + Character &player_character = get_player_character(); + for( wrapped_vehicle &veh : get_map().get_vehicles() ) { vehicle *v = veh.v; - if( v->has_engine_type( fuel_type_animal, false ) && v->is_owned_by( g->u ) ) { + if( v->has_engine_type( fuel_type_animal, false ) && v->is_owned_by( player_character ) ) { v->is_following = false; v->engine_on = false; } @@ -351,9 +342,10 @@ static void tell_veh_stop_following() static void assign_veh_to_follow() { - for( wrapped_vehicle &veh : g->m.get_vehicles() ) { + Character &player_character = get_player_character(); + for( wrapped_vehicle &veh : get_map().get_vehicles() ) { vehicle *v = veh.v; - if( v->has_engine_type( fuel_type_animal, false ) && v->is_owned_by( g->u ) ) { + if( v->has_engine_type( fuel_type_animal, false ) && v->is_owned_by( player_character ) ) { v->activate_animal_follow(); } } @@ -361,12 +353,13 @@ static void assign_veh_to_follow() static void tell_magic_veh_to_follow() { - for( wrapped_vehicle &veh : g->m.get_vehicles() ) { + Character &player_character = get_player_character(); + for( wrapped_vehicle &veh : get_map().get_vehicles() ) { vehicle *v = veh.v; if( v->magic ) { for( const vpart_reference &vp : v->get_all_parts() ) { const vpart_info &vpi = vp.info(); - if( vpi.has_flag( "MAGIC_FOLLOW" ) && v->is_owned_by( g->u ) ) { + if( vpi.has_flag( "MAGIC_FOLLOW" ) && v->is_owned_by( player_character ) ) { v->activate_magical_follow(); break; } @@ -377,7 +370,7 @@ static void tell_magic_veh_to_follow() static void tell_magic_veh_stop_following() { - for( wrapped_vehicle &veh : g->m.get_vehicles() ) { + for( wrapped_vehicle &veh : get_map().get_vehicles() ) { vehicle *v = veh.v; if( v->magic ) { for( const vpart_reference &vp : v->get_all_parts() ) { @@ -394,7 +387,8 @@ static void tell_magic_veh_stop_following() void game::chat() { - int volume = g->u.get_shout_volume(); + Character &player_character = get_player_character(); + int volume = player_character.get_shout_volume(); const std::vector available = get_npcs_if( [&]( const npc & guy ) { // TODO: Get rid of the z-level check when z-level vision gets "better" @@ -413,18 +407,20 @@ void game::chat() } ); const int guard_count = guards.size(); - if( g->u.has_trait( trait_PROF_FOODP ) && !( g->u.is_wearing( itype_id( "foodperson_mask" ) ) || - g->u.is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { - g->u.add_msg_if_player( m_warning, _( "You can't speak without your face!" ) ); + if( player_character.has_trait( trait_PROF_FOODP ) && + !( player_character.is_wearing( itype_id( "foodperson_mask" ) ) || + player_character.is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { + add_msg( m_warning, _( "You can't speak without your face!" ) ); return; } std::vector animal_vehicles; std::vector following_vehicles; std::vector magic_vehicles; std::vector magic_following_vehicles; - for( auto &veh : g->m.get_vehicles() ) { + for( auto &veh : get_map().get_vehicles() ) { auto &v = veh.v; - if( v->has_engine_type( fuel_type_animal, false ) && v->is_owned_by( g->u ) ) { + if( v->has_engine_type( fuel_type_animal, false ) && + v->is_owned_by( player_character ) ) { animal_vehicles.push_back( v ); if( v->is_following ) { following_vehicles.push_back( v ); @@ -506,7 +502,7 @@ void game::chat() if( npcselect < 0 ) { return; } - available[npcselect]->talk_to_u(); + g->u.talk_to( get_talker_for( *available[npcselect] ) ); break; } case NPC_CHAT_YELL: @@ -627,14 +623,16 @@ void game::chat() void npc::handle_sound( const sounds::sound_t spriority, const std::string &description, int heard_volume, const tripoint &spos ) { - const tripoint s_abs_pos = g->m.getabs( spos ); - const tripoint my_abs_pos = g->m.getabs( pos() ); + const map &here = get_map(); + const tripoint s_abs_pos = here.getabs( spos ); + const tripoint my_abs_pos = here.getabs( pos() ); add_msg( m_debug, "%s heard '%s', priority %d at volume %d from %d:%d, my pos %d:%d", disp_name(), description, static_cast( spriority ), heard_volume, s_abs_pos.x, s_abs_pos.y, my_abs_pos.x, my_abs_pos.y ); - bool player_ally = g->u.pos() == spos && is_player_ally(); + Character &player_character = get_player_character(); + bool player_ally = player_character.pos() == spos && is_player_ally(); player *const sound_source = g->critter_at( spos ); bool npc_ally = sound_source && sound_source->is_npc() && is_ally( *sound_source ); @@ -660,7 +658,7 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc } // discount if sound source is player, or seen by player, // and listener is friendly and sound source is combat or alert only. - if( spriority < sounds::sound_t::alarm && g->u.sees( spos ) ) { + if( spriority < sounds::sound_t::alarm && player_character.sees( spos ) ) { if( is_player_ally() ) { add_msg( m_debug, "NPC %s ignored low priority noise that player can see", name ); return; @@ -729,140 +727,34 @@ void npc_chatbin::check_missions() ma.erase( last, ma.end() ); } -void npc::talk_to_u( bool text_only, bool radio_contact ) +void avatar::talk_to( std::unique_ptr talk_with, bool text_only, bool radio_contact ) { - if( g->u.is_dead_state() ) { - set_attitude( NPCATT_NULL ); + const bool has_mind_control = has_trait( trait_DEBUG_MIND_CONTROL ); + if( !talk_with->will_talk_to_u( *this, has_mind_control ) ) { return; } - const bool has_mind_control = g->u.has_trait( trait_DEBUG_MIND_CONTROL ); - // This is necessary so that we don't bug the player over and over - if( get_attitude() == NPCATT_TALK ) { - set_attitude( NPCATT_NULL ); - } else if( !has_mind_control && ( get_attitude() == NPCATT_FLEE || - get_attitude() == NPCATT_FLEE_TEMP ) ) { - add_msg( _( "%s is fleeing from you!" ), name ); - return; - } else if( !has_mind_control && get_attitude() == NPCATT_KILL ) { - add_msg( _( "%s is hostile!" ), name ); - return; - } - if( get_faction() ) { - get_faction()->known_by_u = true; - } - set_known_to_u( true ); dialogue d; - d.alpha = &g->u; - d.beta = this; - - chatbin.check_missions(); - - // For each active mission we have, let the mission know we talked to this NPC. - for( auto &mission : g->u.get_active_missions() ) { - mission->on_talk_with_npc( this->getID() ); - } - - for( auto &mission : chatbin.missions_assigned ) { - if( mission->get_assigned_player_id() == g->u.getID() ) { + d.alpha = get_talker_for( *this ); + d.beta = std::move( talk_with ); + d.by_radio = radio_contact; + dialogue_by_radio = radio_contact; + d.beta->check_missions(); + for( auto &mission : d.beta->assigned_missions() ) { + if( mission->get_assigned_player_id() == getID() ) { d.missions_assigned.push_back( mission ); } } - d.add_topic( chatbin.first_topic ); - if( radio_contact ) { - d.add_topic( "TALK_RADIO" ); - d.by_radio = true; - } else if( is_leader() ) { - d.add_topic( "TALK_LEADER" ); - } else if( is_player_ally() && ( is_walking_with() || has_activity() ) ) { - d.add_topic( "TALK_FRIEND" ); - } else if( get_attitude() == NPCATT_RECOVER_GOODS ) { - d.add_topic( "TALK_STOLE_ITEM" ); - } - g->u.dialogue_by_radio = d.by_radio; - int most_difficult_mission = 0; - for( auto &mission : chatbin.missions ) { - const auto &type = mission->get_type(); - if( type.urgent && type.difficulty > most_difficult_mission ) { - d.add_topic( "TALK_MISSION_DESCRIBE_URGENT" ); - chatbin.mission_selected = mission; - most_difficult_mission = type.difficulty; - } - } - most_difficult_mission = 0; - bool chosen_urgent = false; - for( auto &mission : chatbin.missions_assigned ) { - if( mission->get_assigned_player_id() != g->u.getID() ) { - // Not assigned to the player that is currently talking to the npc - continue; - } - const auto &type = mission->get_type(); - if( ( type.urgent && !chosen_urgent ) || ( type.difficulty > most_difficult_mission && - ( type.urgent || !chosen_urgent ) ) ) { - chosen_urgent = type.urgent; - d.add_topic( "TALK_MISSION_INQUIRE" ); - chatbin.mission_selected = mission; - most_difficult_mission = type.difficulty; - } - } - - // Needs - if( has_effect( effect_npc_suspend ) ) { - d.add_topic( "TALK_REBOOT" ); - } - if( has_effect( effect_sleep ) || has_effect( effect_lying_down ) ) { - if( has_effect( effect_narcosis ) ) { - d.add_topic( "TALK_SEDATED" ); - } else { - d.add_topic( "TALK_WAKE_UP" ); - } - } - - if( d.topic_stack.back().id == "TALK_NONE" ) { - d.topic_stack.back() = talk_topic( pick_talk_topic( g->u ) ); + for( const std::string &topic_id : d.beta->get_topics( radio_contact ) ) { + d.add_topic( topic_id ); } - - moves -= 100; - - if( g->u.is_deaf() ) { - if( d.topic_stack.back().id == "TALK_MUG" || - d.topic_stack.back().id == "TALK_STRANGER_AGGRESSIVE" ) { - make_angry(); - d.add_topic( "TALK_DEAF_ANGRY" ); - } else { - d.add_topic( "TALK_DEAF" ); - } + for( const std::string &topic_id : d.alpha->get_topics( radio_contact ) ) { + d.add_topic( topic_id ); } - - if( g->u.has_trait( trait_PROF_FOODP ) && !( g->u.is_wearing( itype_id( "foodperson_mask" ) ) || - g->u.is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { - d.add_topic( "TALK_NOFACE" ); - } - - if( has_trait( trait_PROF_FOODP ) && !( is_wearing( itype_id( "foodperson_mask" ) ) || - is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { - d.add_topic( "TALK_NPC_NOFACE" ); - } - - decide_needs(); - dialogue_window d_win; d_win.open_dialogue( text_only ); // Main dialogue loop do { - if( chatbin.mission_selected != nullptr ) { - if( chatbin.mission_selected->get_assigned_player_id() != g->u.getID() ) { - // Don't talk about a mission that is assigned to someone else. - chatbin.mission_selected = nullptr; - } - } - if( chatbin.mission_selected == nullptr ) { - // if possible, select a mission to talk about - if( !chatbin.missions.empty() ) { - chatbin.mission_selected = chatbin.missions.front(); - } else if( !d.missions_assigned.empty() ) { - chatbin.mission_selected = d.missions_assigned.front(); - } - } + d.beta->update_missions( d.missions_assigned, getID() ); const talk_topic next = d.opt( d_win, name, d.topic_stack.back() ); if( next.id == "TALK_NONE" ) { int cat = topic_category( d.topic_stack.back() ); @@ -878,19 +770,18 @@ void npc::talk_to_u( bool text_only, bool radio_contact ) } } while( !d.done ); - if( g->u.activity.id() == ACT_AIM && !g->u.has_weapon() ) { - g->u.cancel_activity(); + if( activity.id() == ACT_AIM && !has_weapon() ) { + cancel_activity(); // don't query certain activities that are started from dialogue - } else if( g->u.activity.id() == ACT_TRAIN || - g->u.activity.id() == ACT_WAIT_NPC || - g->u.activity.id() == ACT_SOCIALIZE || - g->u.activity.index == getID().get_value() ) { + } else if( activity.id() == ACT_TRAIN || activity.id() == ACT_WAIT_NPC || + activity.id() == ACT_SOCIALIZE || activity.index == d.beta->getID().get_value() ) { return; } - if( !g->u.has_effect( effect_under_operation ) ) { + if( !d.beta->has_effect( effect_under_operation ) ) { g->cancel_activity_or_ignore_query( distraction_type::talked_to, - string_format( _( "%s talked to you." ), name ) ); + string_format( _( "%s talked to you." ), + d.beta->disp_name() ) ); } } @@ -911,7 +802,7 @@ std::string dialogue::dynamic_line( const talk_topic &the_topic ) const } if( topic == "TALK_NPC_NOFACE" ) { - return string_format( _( "&%s stays silent." ), beta->name ); + return string_format( _( "&%s stays silent." ), beta->disp_name() ); } if( topic == "TALK_NOFACE" ) { @@ -922,16 +813,18 @@ std::string dialogue::dynamic_line( const talk_topic &the_topic ) const } else if( topic == "TALK_DEAF_ANGRY" ) { return string_format( _( "&You are deaf and can't talk. When you don't respond, %s becomes angry!" ), - beta->name ); + beta->disp_name() ); } if( topic == "TALK_SEDATED" ) { - return string_format( - _( "%1$s is sedated and can't be moved or woken up until the medication or sedation wears off.\nYou estimate it will wear off in %2$s." ), - beta->name, to_string_approx( g->u.estimate_effect_dur( skill_id( "firstaid" ), effect_narcosis, - 15_minutes, 6, *beta ) ) ); + return string_format( _( "%1$s is sedated and can't be moved or woken up until the " + "medication or sedation wears off.\nYou estimate it will wear " + "off in %2$s." ), + beta->disp_name(), + to_string_approx( g->u.estimate_effect_dur( skill_id( "firstaid" ), + effect_narcosis, 15_minutes, 6, + *beta->get_npc() ) ) ); } - const auto &p = beta; // for compatibility, later replace it in the code below // Those topics are handled by the mission system, see there. static const std::unordered_set mission_topics = { { "TALK_MISSION_DESCRIBE", "TALK_MISSION_DESCRIBE_URGENT", @@ -941,10 +834,10 @@ std::string dialogue::dynamic_line( const talk_topic &the_topic ) const } }; if( mission_topics.count( topic ) > 0 ) { - if( p->chatbin.mission_selected == nullptr ) { + mission *miss = beta->selected_mission(); + if( miss == nullptr ) { return "mission_selected == nullptr; BUG! (npctalk.cpp:dynamic_line)"; } - mission *miss = p->chatbin.mission_selected; const auto &type = miss->get_type(); // TODO: make it a member of the mission class, maybe at mission instance specific data const std::string &ret = miss->dialogue_for_topic( topic ); @@ -973,61 +866,17 @@ std::string dialogue::dynamic_line( const talk_topic &the_topic ) const } else if( topic == "TALK_TRAIN" ) { if( !g->u.backlog.empty() && g->u.backlog.front().id() == ACT_TRAIN ) { return _( "Shall we resume?" ); - } - std::vector trainable = p->skills_offered_to( g->u ); - std::vector styles = p->styles_offered_to( g->u ); - const std::vector spells = p->magic.spells(); - std::vector teachable_spells; - for( const spell_id &sp : spells ) { - if( g->u.magic.can_learn_spell( g->u, sp ) ) { - teachable_spells.emplace_back( sp ); - } - } - if( trainable.empty() && styles.empty() && teachable_spells.empty() ) { + } else if( beta->skills_offered_to( *alpha ).empty() && + beta->styles_offered_to( *alpha ).empty() && + beta->spells_offered_to( *alpha ).empty() ) { return _( "Sorry, but it doesn't seem I have anything to teach you." ); } else { return _( "Here's what I can teach you…" ); } } else if( topic == "TALK_HOW_MUCH_FURTHER" ) { - // TODO: this ignores the z-component - const tripoint player_pos = p->global_omt_location(); - int dist = rl_dist( player_pos, p->goal ); - std::string response; - dist *= 100; - if( dist >= 1300 ) { - int miles = dist / 25; // *100, e.g. quarter mile is "25" - miles -= miles % 25; // Round to nearest quarter-mile - int fullmiles = ( miles - miles % 100 ) / 100; // Left of the decimal point - if( fullmiles < 0 ) { - fullmiles = 0; - } - response = string_format( _( "%d.%d miles." ), fullmiles, miles ); - } else { - response = string_format( ngettext( "%d foot.", "%d feet.", dist ), dist ); - } - return response; + return beta->distance_to_goal(); } else if( topic == "TALK_DESCRIBE_MISSION" ) { - switch( p->mission ) { - case NPC_MISSION_SHELTER: - return string_format( _( "I'm holing up here for safety. Long term, %s" ), - p->myclass.obj().get_job_description() ); - case NPC_MISSION_SHOPKEEP: - return _( "I run the shop here." ); - case NPC_MISSION_GUARD: - case NPC_MISSION_GUARD_ALLY: - case NPC_MISSION_GUARD_PATROL: - return string_format( _( "Currently, I'm guarding this location. Overall, %s" ), - p->myclass.obj().get_job_description() ); - case NPC_MISSION_ACTIVITY: - return string_format( _( "Right now, I'm . In general, %s" ), - p->myclass.obj().get_job_description() ); - case NPC_MISSION_TRAVELLING: - case NPC_MISSION_NULL: - return p->myclass.obj().get_job_description(); - default: - return string_format( "ERROR: Someone forgot to code an npc_mission text for " - "mission: %d.", static_cast( p->mission ) ); - } // switch (p->mission) + return beta->get_job_description(); } else if( topic == "TALK_SHOUT" ) { alpha->shout(); if( alpha->is_deaf() ) { @@ -1036,88 +885,13 @@ std::string dialogue::dynamic_line( const talk_topic &the_topic ) const return _( "&You yell." ); } } else if( topic == "TALK_SIZE_UP" ) { - ///\EFFECT_PER affects whether player can size up NPCs - - ///\EFFECT_INT slightly affects whether player can size up NPCs - int ability = g->u.per_cur * 3 + g->u.int_cur; - if( ability <= 10 ) { - return _( "&You can't make anything out." ); - } - - if( p->is_player_ally() || ability > 100 ) { - ability = 100; - } - - std::string info = "&"; - int str_range = static_cast( 100 / ability ); - int str_min = static_cast( p->str_max / str_range ) * str_range; - info += string_format( _( "Str %d - %d" ), str_min, str_min + str_range ); - - if( ability >= 40 ) { - int dex_range = static_cast( 160 / ability ); - int dex_min = static_cast( p->dex_max / dex_range ) * dex_range; - info += string_format( _( " Dex %d - %d" ), dex_min, dex_min + dex_range ); - } - - if( ability >= 50 ) { - int int_range = static_cast( 200 / ability ); - int int_min = static_cast( p->int_max / int_range ) * int_range; - info += string_format( _( " Int %d - %d" ), int_min, int_min + int_range ); - } - - if( ability >= 60 ) { - int per_range = static_cast( 240 / ability ); - int per_min = static_cast( p->per_max / per_range ) * per_range; - info += string_format( _( " Per %d - %d" ), per_min, per_min + per_range ); - } - - needs_rates rates = p->calc_needs_rates(); - if( ability >= 100 - ( p->get_fatigue() / 10 ) ) { - std::string how_tired; - if( p->get_fatigue() > fatigue_levels::EXHAUSTED ) { - how_tired = _( "Exhausted" ); - } else if( p->get_fatigue() > fatigue_levels::DEAD_TIRED ) { - how_tired = _( "Dead tired" ); - } else if( p->get_fatigue() > fatigue_levels::TIRED ) { - how_tired = _( "Tired" ); - } else { - how_tired = _( "Not tired" ); - if( ability >= 100 ) { - time_duration sleep_at = 5_minutes * ( fatigue_levels::TIRED - p->get_fatigue() ) / - rates.fatigue; - how_tired += _( ". Will need sleep in " ) + to_string_approx( sleep_at ); - } - } - info += "\n" + how_tired; - } - if( ability >= 100 ) { - if( p->get_thirst() < 100 ) { - time_duration thirst_at = 5_minutes * ( 100 - p->get_thirst() ) / rates.thirst; - if( thirst_at > 1_hours ) { - info += _( "\nWill need water in " ) + to_string_approx( thirst_at ); - } - } else { - info += _( "\nThirsty" ); - } - if( p->get_hunger() < 100 ) { - time_duration hunger_at = 5_minutes * ( 100 - p->get_hunger() ) / rates.hunger; - if( hunger_at > 1_hours ) { - info += _( "\nWill need food in " ) + to_string_approx( hunger_at ); - } - } else { - info += _( "\nHungry" ); - } - } - return info; + return beta->evaluation_by( *alpha ); } else if( topic == "TALK_LOOK_AT" ) { - return "&" + p->short_description(); + return "&" + beta->short_description(); } else if( topic == "TALK_OPINION" ) { - return "&" + p->opinion_text(); + return "&" + beta->opinion_text(); } else if( topic == "TALK_MIND_CONTROL" ) { - bool not_following = g->get_follower_list().count( p->getID() ) == 0; - p->companion_mission_role_id.clear(); - talk_function::follow( *p ); - if( not_following ) { + if( beta->enslave_mind() ) { return _( "YES, MASTER!" ); } } @@ -1234,11 +1008,8 @@ talk_response &dialogue::add_response( const std::string &text, const std::strin void dialogue::gen_responses( const talk_topic &the_topic ) { - const auto &topic = the_topic.id; // for compatibility, later replace it in the code below - const auto p = beta; // for compatibility, later replace it in the code below - auto &ret = responses; // for compatibility, later replace it in the code below - ret.clear(); - const auto iter = json_talk_topics.find( topic ); + responses.clear(); + const auto iter = json_talk_topics.find( the_topic.id ); if( iter != json_talk_topics.end() ) { json_talk_topic &jtt = iter->second; if( jtt.gen_responses( *this ) ) { @@ -1246,16 +1017,16 @@ void dialogue::gen_responses( const talk_topic &the_topic ) } } - if( topic == "TALK_MISSION_LIST" ) { - if( p->chatbin.missions.size() == 1 ) { + if( the_topic.id == "TALK_MISSION_LIST" ) { + if( beta->available_missions().size() == 1 ) { add_response( _( "Tell me about it." ), "TALK_MISSION_OFFER", - p->chatbin.missions.front(), true ); + beta->available_missions().front(), true ); } else { - for( auto &mission : p->chatbin.missions ) { + for( auto &mission : beta->available_missions() ) { add_response( mission->get_type().tname(), "TALK_MISSION_OFFER", mission, true ); } } - } else if( topic == "TALK_MISSION_LIST_ASSIGNED" ) { + } else if( the_topic.id == "TALK_MISSION_LIST_ASSIGNED" ) { if( missions_assigned.size() == 1 ) { add_response( _( "I have news." ), "TALK_MISSION_INQUIRE", missions_assigned.front() ); } else { @@ -1263,9 +1034,9 @@ void dialogue::gen_responses( const talk_topic &the_topic ) add_response( miss_it->get_type().tname(), "TALK_MISSION_INQUIRE", miss_it ); } } - } else if( topic == "TALK_TRAIN" ) { + } else if( the_topic.id == "TALK_TRAIN" ) { if( !g->u.backlog.empty() && g->u.backlog.front().id() == ACT_TRAIN && - g->u.backlog.front().index == p->getID().get_value() ) { + g->u.backlog.front().index == beta->getID().get_value() ) { player_activity &backlog = g->u.backlog.front(); const skill_id skillt( backlog.name ); // TODO: This is potentially dangerous. A skill and a martial art @@ -1274,194 +1045,93 @@ void dialogue::gen_responses( const talk_topic &the_topic ) const matype_id styleid = matype_id( backlog.name ); if( !styleid.is_valid() ) { const spell_id &sp_id = spell_id( backlog.name ); - if( p->magic.knows_spell( sp_id ) ) { - add_response( string_format( _( "Yes, let's resume training %s" ), sp_id->name ), - "TALK_TRAIN_START", sp_id ); + if( beta->knows_spell( sp_id ) ) { + add_response( string_format( _( "Yes, let's resume training %s" ), + sp_id->name ), "TALK_TRAIN_START", sp_id ); } } else { const martialart &style = styleid.obj(); - add_response( string_format( _( "Yes, let's resume training %s" ), style.name ), "TALK_TRAIN_START", - style ); + add_response( string_format( _( "Yes, let's resume training %s" ), + style.name ), "TALK_TRAIN_START", style ); } } else { add_response( string_format( _( "Yes, let's resume training %s" ), skillt->name() ), "TALK_TRAIN_START", skillt ); } } - std::vector styles = p->styles_offered_to( g->u ); - std::vector trainable = p->skills_offered_to( g->u ); - const std::vector spells = p->magic.spells(); - std::vector teachable_spells; - for( const spell_id &sp : spells ) { - const spell &temp_spell = p->magic.get_spell( sp ); - if( g->u.magic.can_learn_spell( g->u, sp ) ) { - if( g->u.magic.knows_spell( sp ) ) { - const spell &player_spell = g->u.magic.get_spell( sp ); - if( player_spell.is_max_level() || player_spell.get_level() >= temp_spell.get_level() ) { - continue; - } - } - teachable_spells.emplace_back( sp ); - } - } - if( trainable.empty() && styles.empty() && teachable_spells.empty() ) { + const std::vector &styles = beta->styles_offered_to( *alpha ); + const std::vector &trainable = beta->skills_offered_to( *alpha ); + const std::vector &teachable = beta->spells_offered_to( *alpha ); + if( trainable.empty() && styles.empty() && teachable.empty() ) { add_response_none( _( "Oh, okay." ) ); return; } - for( const spell_id &sp : teachable_spells ) { - const spell &temp_spell = p->magic.get_spell( sp ); - const bool knows = g->u.magic.knows_spell( sp ); - const int cost = p->calc_spell_training_cost( knows, temp_spell.get_difficulty(), - temp_spell.get_level() ); - std::string text; - if( knows ) { - text = string_format( _( "%s: 1 hour lesson (cost %s)" ), temp_spell.name(), - format_money( cost ) ); - } else { - text = string_format( _( "%s: teaching spell knowledge (cost %s)" ), temp_spell.name(), - format_money( cost ) ); + for( const spell_id &sp : teachable ) { + const std::string &text = beta->spell_training_text( *alpha, sp ); + if( !text.empty() ) { + add_response( text, "TALK_TRAIN_START", sp ); + } + } + for( const matype_id &style_id : styles ) { + const std::string &text = beta->style_training_text( *alpha, style_id ); + if( !text.empty() ) { + add_response( text, "TALK_TRAIN_START", style_id.obj() ); + } + } + for( const skill_id &trained : trainable ) { + const std::string &text = beta->skill_training_text( *alpha, trained ); + if( !text.empty() ) { + add_response( text, "TALK_TRAIN_START", trained ); } - add_response( text, "TALK_TRAIN_START", sp ); - } - for( auto &style_id : styles ) { - auto &style = style_id.obj(); - const int cost = calc_ma_style_training_cost( *p, style.id ); - //~Martial art style (cost in dollars) - const std::string text = string_format( cost > 0 ? _( "%s ( cost $%d )" ) : "%s", - style.name, cost / 100 ); - add_response( text, "TALK_TRAIN_START", style ); - } - for( auto &trained : trainable ) { - const int cost = calc_skill_training_cost( *p, trained ); - SkillLevel skill_level_obj = g->u.get_skill_level_object( trained ); - const int cur_level = skill_level_obj.level(); - const int cur_level_exercise = skill_level_obj.exercise(); - skill_level_obj.train( 100 ); - const int next_level = skill_level_obj.level(); - const int next_level_exercise = skill_level_obj.exercise(); - - //~Skill name: current level (exercise) -> next level (exercise) (cost in dollars) - std::string text = string_format( cost > 0 ? _( "%s: %d (%d%%) -> %d (%d%%) (cost $%d)" ) : - _( "%s: %d (%d%%) -> %d (%d%%)" ), - trained.obj().name(), cur_level, cur_level_exercise, - next_level, next_level_exercise, cost / 100 ); - add_response( text, "TALK_TRAIN_START", trained ); } add_response_none( _( "Eh, never mind." ) ); - } else if( topic == "TALK_HOW_MUCH_FURTHER" ) { + } else if( the_topic.id == "TALK_HOW_MUCH_FURTHER" ) { add_response_none( _( "Okay, thanks." ) ); add_response_done( _( "Let's keep moving." ) ); } - if( g->u.has_trait( trait_DEBUG_MIND_CONTROL ) && !p->is_player_ally() ) { + if( alpha->has_trait( trait_DEBUG_MIND_CONTROL ) && !beta->is_player_ally() ) { add_response( _( "OBEY ME!" ), "TALK_MIND_CONTROL" ); add_response_done( _( "Bye." ) ); } - if( ret.empty() ) { + if( responses.empty() ) { add_response_done( _( "Bye." ) ); } } static int parse_mod( const dialogue &d, const std::string &attribute, const int factor ) { - player &u = *d.alpha; - npc &p = *d.beta; - int modifier = 0; - if( attribute == "ANGER" ) { - modifier = p.op_of_u.anger; - } else if( attribute == "FEAR" ) { - modifier = p.op_of_u.fear; - } else if( attribute == "TRUST" ) { - modifier = p.op_of_u.trust; - } else if( attribute == "VALUE" ) { - modifier = p.op_of_u.value; - } else if( attribute == "POS_FEAR" ) { - modifier = std::max( 0, p.op_of_u.fear ); - } else if( attribute == "AGGRESSION" ) { - modifier = p.personality.aggression; - } else if( attribute == "ALTRUISM" ) { - modifier = p.personality.altruism; - } else if( attribute == "BRAVERY" ) { - modifier = p.personality.bravery; - } else if( attribute == "COLLECTOR" ) { - modifier = p.personality.collector; - } else if( attribute == "MISSIONS" ) { - modifier = p.assigned_missions_value() / OWED_VAL; - } else if( attribute == "U_INTIMIDATE" ) { - modifier = u.intimidation(); - } else if( attribute == "NPC_INTIMIDATE" ) { - modifier = p.intimidation(); - } - modifier *= factor; - return modifier; + return d.beta->parse_mod( attribute, factor ) + d.alpha->parse_mod( attribute, factor ); } int talk_trial::calc_chance( const dialogue &d ) const { - player &u = *d.alpha; - if( u.has_trait( trait_DEBUG_MIND_CONTROL ) ) { + if( d.alpha->has_trait( trait_DEBUG_MIND_CONTROL ) ) { return 100; } - const social_modifiers &u_mods = u.get_mutation_social_mods(); - - npc &p = *d.beta; int chance = difficulty; switch( type ) { case NUM_TALK_TRIALS: dbg( D_ERROR ) << "called calc_chance with invalid talk_trial value: " << type; break; - case TALK_TRIAL_LIE: - chance += u.talk_skill() - p.talk_skill() + p.op_of_u.trust * 3; - chance += u_mods.lie; - - //come on, who would suspect a robot of lying? - if( u.has_bionic( bio_voice ) ) { - chance += 10; - } - if( u.has_bionic( bio_face_mask ) ) { - chance += 20; - } - break; - case TALK_TRIAL_PERSUADE: - chance += u.talk_skill() - static_cast( p.talk_skill() / 2 ) + - p.op_of_u.trust * 2 + p.op_of_u.value; - chance += u_mods.persuade; - - if( u.has_bionic( bio_face_mask ) ) { - chance += 10; - } - if( u.has_bionic( bio_deformity ) ) { - chance -= 50; - } - if( u.has_bionic( bio_voice ) ) { - chance -= 20; - } - break; - case TALK_TRIAL_INTIMIDATE: - chance += u.intimidation() - p.intimidation() + p.op_of_u.fear * 2 - - p.personality.bravery * 2; - chance += u_mods.intimidate; - - if( u.has_bionic( bio_face_mask ) ) { - chance += 10; - } - if( u.has_bionic( bio_armor_eyes ) ) { - chance += 10; - } - if( u.has_bionic( bio_deformity ) ) { - chance += 20; - } - if( u.has_bionic( bio_voice ) ) { - chance += 20; - } - break; case TALK_TRIAL_NONE: chance = 100; break; case TALK_TRIAL_CONDITION: chance = condition( d ) ? 100 : 0; break; + case TALK_TRIAL_LIE: + chance += d.alpha->trial_chance_mod( "lie" ) + d.beta->trial_chance_mod( "lie" ); + break; + case TALK_TRIAL_PERSUADE: + chance += d.alpha->trial_chance_mod( "persuade" ) + + d.beta->trial_chance_mod( "persuade" ); + break; + case TALK_TRIAL_INTIMIDATE: + chance += d.alpha->trial_chance_mod( "intimidate" ) + + d.beta->trial_chance_mod( "intimidate" ); + break; } for( const auto &this_mod : modifiers ) { chance += parse_mod( d, this_mod.first, this_mod.second ); @@ -1472,16 +1142,18 @@ int talk_trial::calc_chance( const dialogue &d ) const bool talk_trial::roll( dialogue &d ) const { - player &u = *d.alpha; - if( type == TALK_TRIAL_NONE || u.has_trait( trait_DEBUG_MIND_CONTROL ) ) { + if( type == TALK_TRIAL_NONE || d.alpha->has_trait( trait_DEBUG_MIND_CONTROL ) ) { return true; } const int chance = calc_chance( d ); const bool success = rng( 0, 99 ) < chance; - if( success ) { - u.practice( skill_speech, ( 100 - chance ) / 10 ); - } else { - u.practice( skill_speech, ( 100 - chance ) / 7 ); + if( d.alpha->get_character() ) { + player &u = *d.alpha->get_character(); + if( success ) { + u.practice( skill_speech, ( 100 - chance ) / 10 ); + } else { + u.practice( skill_speech, ( 100 - chance ) / 7 ); + } } return success; } @@ -1671,7 +1343,8 @@ talk_data talk_response::create_option_line( const dialogue &d, const char lette ftext = string_format( pgettext( "talk option", "%1$c: [%2$s %3$d%%] %4$s" ), letter, trial.name(), trial.calc_chance( d ), text ); } - parse_tags( ftext, *d.alpha, *d.beta, success.next_topic.item_type ); + parse_tags( ftext, *d.alpha->get_character(), *d.beta->get_npc(), + success.next_topic.item_type ); nc_color color; std::set consequences = get_consequences( d ); @@ -1704,7 +1377,7 @@ std::set talk_response::get_consequences( const dialogue & dialogue_consequence talk_effect_t::get_consequence( const dialogue &d ) const { - if( d.beta->op_of_u.anger + opinion.anger >= d.beta->hostile_anger_level() ) { + if( d.beta->check_hostile_response( opinion.anger ) ) { return dialogue_consequence::hostile; } return guaranteed_consequence; @@ -1741,7 +1414,7 @@ talk_topic dialogue::opt( dialogue_window &d_win, const std::string &npc_name, } // Parse any tags in challenge - parse_tags( challenge, *alpha, *beta, topic.item_type ); + parse_tags( challenge, *alpha->get_character(), *beta->get_npc(), topic.item_type ); capitalize_letter( challenge ); // Prepend "My Name: " @@ -1749,10 +1422,10 @@ talk_topic dialogue::opt( dialogue_window &d_win, const std::string &npc_name, // No name prepended! challenge = challenge.substr( 1 ); } else if( challenge[0] == '*' ) { - challenge = string_format( pgettext( "npc does something", "%s %s" ), beta->name, + challenge = string_format( pgettext( "npc does something", "%s %s" ), beta->disp_name(), challenge.substr( 1 ) ); } else { - challenge = string_format( pgettext( "npc says something", "%s: %s" ), beta->name, + challenge = string_format( pgettext( "npc says something", "%s: %s" ), beta->disp_name(), challenge ); } @@ -1832,24 +1505,12 @@ talk_topic dialogue::opt( dialogue_window &d_win, const std::string &npc_name, d_win.add_to_history( response_printed ); if( chosen.mission_selected != nullptr ) { - beta->chatbin.mission_selected = chosen.mission_selected; + beta->select_mission( chosen.mission_selected ); } // We can't set both skill and style or training will bug out // TODO: Allow setting both skill and style - if( chosen.skill ) { - beta->chatbin.skill = chosen.skill; - beta->chatbin.style = matype_id::NULL_ID(); - beta->chatbin.dialogue_spell = spell_id(); - } else if( chosen.style ) { - beta->chatbin.style = chosen.style; - beta->chatbin.skill = skill_id::NULL_ID(); - beta->chatbin.dialogue_spell = spell_id(); - } else if( chosen.dialogue_spell != spell_id() ) { - beta->chatbin.style = matype_id::NULL_ID(); - beta->chatbin.skill = skill_id::NULL_ID(); - beta->chatbin.dialogue_spell = chosen.dialogue_spell; - } + beta->store_chosen_training( chosen.skill, chosen.style, chosen.dialogue_spell ); const bool success = chosen.trial.roll( *this ); const auto &effects = success ? chosen.success : chosen.failure; return effects.apply( *this ); @@ -1898,16 +1559,18 @@ static talk_topic load_inline_topic( const JsonObject &jo ) talk_effect_fun_t::talk_effect_fun_t( const talkfunction_ptr &ptr ) { function = [ptr]( const dialogue & d ) { - npc &p = *d.beta; - ptr( p ); + if( d.beta->get_npc() ) { + ptr( *d.beta->get_npc() ); + } }; } talk_effect_fun_t::talk_effect_fun_t( const std::function &ptr ) { function = [ptr]( const dialogue & d ) { - npc &p = *d.beta; - ptr( p ); + if( d.beta->get_npc() ) { + ptr( *d.beta->get_npc() ); + } }; } @@ -1921,9 +1584,7 @@ talk_effect_fun_t::talk_effect_fun_t( const std::functionset_companion_mission( role_id ); }; } @@ -1944,11 +1605,7 @@ void talk_effect_fun_t::set_add_effect( const JsonObject &jo, const std::string duration = time_duration::from_turns( jo.get_int( "duration" ) ); } function = [is_npc, new_effect, duration, permanent]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - actor->add_effect( efftype_id( new_effect ), duration, num_bp, permanent ); + d.actor( is_npc )->add_effect( efftype_id( new_effect ), duration, permanent ); }; } @@ -1957,11 +1614,7 @@ void talk_effect_fun_t::set_remove_effect( const JsonObject &jo, const std::stri { std::string old_effect = jo.get_string( member ); function = [is_npc, old_effect]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - actor->remove_effect( efftype_id( old_effect ), num_bp ); + d.actor( is_npc )->remove_effect( efftype_id( old_effect ) ); }; } @@ -1970,11 +1623,7 @@ void talk_effect_fun_t::set_add_trait( const JsonObject &jo, const std::string & { std::string new_trait = jo.get_string( member ); function = [is_npc, new_trait]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - actor->set_mutation( trait_id( new_trait ) ); + d.actor( is_npc )->set_mutation( trait_id( new_trait ) ); }; } @@ -1983,24 +1632,22 @@ void talk_effect_fun_t::set_remove_trait( const JsonObject &jo, const std::strin { std::string old_trait = jo.get_string( member ); function = [is_npc, old_trait]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - actor->unset_mutation( trait_id( old_trait ) ); + d.actor( is_npc )->unset_mutation( trait_id( old_trait ) ); }; } void talk_effect_fun_t::set_add_var( const JsonObject &jo, const std::string &member, bool is_npc ) { const std::string var_name = get_talk_varname( jo, member ); - const std::string &value = jo.get_string( "value" ); - function = [is_npc, var_name, value]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); + const bool time_check = jo.has_member( "time" ) && jo.get_bool( "time" ); + const std::string &value = time_check ? "" : jo.get_string( "value" ); + function = [is_npc, var_name, value, time_check]( const dialogue & d ) { + talker *actor = d.actor( is_npc ); + if( time_check ) { + actor->set_value( var_name, string_format( "%d", to_turn( calendar::turn ) ) ); + } else { + actor->set_value( var_name, value ); } - actor->set_value( var_name, value ); }; } @@ -2009,11 +1656,7 @@ void talk_effect_fun_t::set_remove_var( const JsonObject &jo, const std::string { const std::string var_name = get_talk_varname( jo, member, false ); function = [is_npc, var_name]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - actor->remove_value( var_name ); + d.actor( is_npc )->remove_value( var_name ); }; } @@ -2023,19 +1666,14 @@ void talk_effect_fun_t::set_adjust_var( const JsonObject &jo, const std::string const std::string var_name = get_talk_varname( jo, member, false ); const int value = jo.get_int( "adjustment" ); function = [is_npc, var_name, value]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } - int adjusted_value = value; - const std::string &var = actor->get_value( var_name ); + const std::string &var = d.actor( is_npc )->get_value( var_name ); if( !var.empty() ) { adjusted_value += std::stoi( var ); } - actor->set_value( var_name, std::to_string( adjusted_value ) ); + d.actor( is_npc )->set_value( var_name, std::to_string( adjusted_value ) ); }; } @@ -2043,9 +1681,7 @@ void talk_effect_fun_t::set_u_buy_item( const itype_id &item_name, int cost, int const std::string &container_name ) { function = [item_name, cost, count, container_name]( const dialogue & d ) { - npc &p = *d.beta; - player &u = *d.alpha; - if( !npc_trading::pay_npc( p, cost ) ) { + if( !d.beta->buy_from( cost ) ) { popup( _( "You can't afford it!" ) ); return; } @@ -2053,25 +1689,27 @@ void talk_effect_fun_t::set_u_buy_item( const itype_id &item_name, int cost, int item new_item = item( item_name, calendar::turn ); if( new_item.count_by_charges() ) { new_item.mod_charges( count - 1 ); - u.i_add( new_item ); + d.alpha->i_add( new_item ); } else { for( int i_cnt = 0; i_cnt < count; i_cnt++ ) { - u.i_add( new_item ); + d.alpha->i_add( new_item ); } } if( count == 1 ) { //~ %1%s is the NPC name, %2$s is an item - popup( _( "%1$s gives you a %2$s." ), p.name, new_item.tname() ); + popup( _( "%1$s gives you a %2$s." ), d.beta->disp_name(), new_item.tname() ); } else { //~ %1%s is the NPC name, %2$d is a number of items, %3$s are items - popup( _( "%1$s gives you %2$d %3$s." ), p.name, count, new_item.tname() ); + popup( _( "%1$s gives you %2$d %3$s." ), d.beta->disp_name(), count, + new_item.tname() ); } } else { item container( container_name, calendar::turn ); - container.put_in( item( item_name, calendar::turn, count ), item_pocket::pocket_type::CONTAINER ); - u.i_add( container ); + container.put_in( item( item_name, calendar::turn, count ), + item_pocket::pocket_type::CONTAINER ); + d.alpha->i_add( container ); //~ %1%s is the NPC name, %2$s is an item - popup( _( "%1$s gives you a %2$s." ), p.name, container.tname() ); + popup( _( "%1$s gives you a %2$s." ), d.beta->disp_name(), container.tname() ); } }; @@ -2084,15 +1722,13 @@ void talk_effect_fun_t::set_u_buy_item( const itype_id &item_name, int cost, int void talk_effect_fun_t::set_u_sell_item( const itype_id &item_name, int cost, int count ) { function = [item_name, cost, count]( const dialogue & d ) { - npc &p = *d.beta; - player &u = *d.alpha; - if( item::count_by_charges( item_name ) && u.has_charges( item_name, count ) ) { - for( const item &it : u.use_charges( item_name, count ) ) { - p.i_add( it ); + if( item::count_by_charges( item_name ) && d.alpha->has_charges( item_name, count ) ) { + for( const item &it : d.alpha->use_charges( item_name, count ) ) { + d.beta->i_add( it ); } - } else if( u.has_amount( item_name, count ) ) { - for( const item &it : u.use_amount( item_name, count ) ) { - p.i_add( it ); + } else if( d.alpha->has_amount( item_name, count ) ) { + for( const item &it : d.alpha->use_amount( item_name, count ) ) { + d.beta->i_add( it ); } } else { //~ %1$s is a translated item name @@ -2101,12 +1737,13 @@ void talk_effect_fun_t::set_u_sell_item( const itype_id &item_name, int cost, in } if( count == 1 ) { //~ %1%s is the NPC name, %2$s is an item - popup( _( "You give %1$s a %2$s." ), p.name, item::nname( item_name ) ); + popup( _( "You give %1$s a %2$s." ), d.beta->disp_name(), item::nname( item_name ) ); } else { //~ %1%s is the NPC name, %2$d is a number of items, %3$s are items - popup( _( "You give %1$s %2$d %3$s." ), p.name, count, item::nname( item_name, count ) ); + popup( _( "You give %1$s %2$d %3$s." ), d.beta->disp_name(), count, + item::nname( item_name, count ) ); } - p.op_of_u.owed += cost; + d.beta->add_debt( cost ); }; } @@ -2118,7 +1755,7 @@ void talk_effect_fun_t::set_consume_item( const JsonObject &jo, const std::strin jo.read( member, item_name, true ); function = [is_npc, item_name, count]( const dialogue & d ) { // this is stupid, but I couldn't get the assignment to work - const auto consume_item = [&]( player & p, const itype_id & item_name, int count ) { + const auto consume_item = [&]( talker & p, const itype_id & item_name, int count ) { item old_item( item_name ); if( p.has_charges( item_name, count ) ) { p.use_charges( item_name, count ); @@ -2142,12 +1779,8 @@ void talk_effect_fun_t::set_remove_item_with( const JsonObject &jo, const std::s { const std::string &item_name = jo.get_string( member ); function = [is_npc, item_name]( const dialogue & d ) { - player *actor = d.alpha; - if( is_npc ) { - actor = dynamic_cast( d.beta ); - } itype_id item_id = itype_id( item_name ); - actor->remove_items_with( [item_id]( const item & it ) { + d.actor( is_npc )->remove_items_with( [item_id]( const item & it ) { return it.typeId() == item_id; } ); }; @@ -2156,35 +1789,28 @@ void talk_effect_fun_t::set_remove_item_with( const JsonObject &jo, const std::s void talk_effect_fun_t::set_u_spend_cash( int amount ) { function = [amount]( const dialogue & d ) { - npc &np = *d.beta; - npc_trading::pay_npc( np, amount ); + d.beta->buy_from( amount ); }; } void talk_effect_fun_t::set_npc_change_faction( const std::string &faction_name ) { function = [faction_name]( const dialogue & d ) { - npc &p = *d.beta; - p.set_fac( faction_id( faction_name ) ); + d.beta->set_fac( faction_id( faction_name ) ); }; } void talk_effect_fun_t::set_npc_change_class( const std::string &class_name ) { function = [class_name]( const dialogue & d ) { - npc &p = *d.beta; - p.myclass = npc_class_id( class_name ); + d.beta->set_class( npc_class_id( class_name ) ); }; } void talk_effect_fun_t::set_change_faction_rep( int rep_change ) { function = [rep_change]( const dialogue & d ) { - npc &p = *d.beta; - if( p.get_faction()->id != faction_id( "no_faction" ) ) { - p.get_faction()->likes_u += rep_change; - p.get_faction()->respects_u += rep_change; - } + d.beta->add_faction_rep( rep_change ); }; } @@ -2199,85 +1825,56 @@ void talk_effect_fun_t::set_add_debt( const std::vector &debt_modifie debt += parse_mod( d, this_mod.first, this_mod.second ); } } - d.beta->op_of_u += npc_opinion( 0, 0, 0, 0, debt ); + d.beta->add_debt( debt ); }; } void talk_effect_fun_t::set_toggle_npc_rule( const std::string &rule ) { function = [rule]( const dialogue & d ) { - auto toggle = ally_rule_strs.find( rule ); - if( toggle == ally_rule_strs.end() ) { - return; - } - d.beta->rules.toggle_flag( toggle->second.rule ); - d.beta->wield_better_weapon(); + d.beta->toggle_ai_rule( "ally_rule", rule ); }; } void talk_effect_fun_t::set_set_npc_rule( const std::string &rule ) { function = [rule]( const dialogue & d ) { - auto flag = ally_rule_strs.find( rule ); - if( flag == ally_rule_strs.end() ) { - return; - } - d.beta->rules.set_flag( flag->second.rule ); - d.beta->wield_better_weapon(); + d.beta->set_ai_rule( "ally_rule", rule ); }; } void talk_effect_fun_t::set_clear_npc_rule( const std::string &rule ) { function = [rule]( const dialogue & d ) { - auto flag = ally_rule_strs.find( rule ); - if( flag == ally_rule_strs.end() ) { - return; - } - d.beta->rules.clear_flag( flag->second.rule ); - d.beta->wield_better_weapon(); + d.beta->clear_ai_rule( "ally_rule", rule ); }; } void talk_effect_fun_t::set_npc_engagement_rule( const std::string &setting ) { function = [setting]( const dialogue & d ) { - auto rule = combat_engagement_strs.find( setting ); - if( rule != combat_engagement_strs.end() ) { - d.beta->rules.engagement = rule->second; - d.beta->invalidate_range_cache(); - } + d.beta->set_ai_rule( "engagement_rule", setting ); }; } void talk_effect_fun_t::set_npc_aim_rule( const std::string &setting ) { function = [setting]( const dialogue & d ) { - auto rule = aim_rule_strs.find( setting ); - if( rule != aim_rule_strs.end() ) { - d.beta->rules.aim = rule->second; - d.beta->invalidate_range_cache(); - } + d.beta->set_ai_rule( "aim_rule", setting ); }; } void talk_effect_fun_t::set_npc_cbm_reserve_rule( const std::string &setting ) { function = [setting]( const dialogue & d ) { - auto rule = cbm_reserve_strs.find( setting ); - if( rule != cbm_reserve_strs.end() ) { - d.beta->rules.cbm_reserve = rule->second; - } + d.beta->set_ai_rule( "cbm_reserve_rule", setting ); }; } void talk_effect_fun_t::set_npc_cbm_recharge_rule( const std::string &setting ) { function = [setting]( const dialogue & d ) { - auto rule = cbm_recharge_strs.find( setting ); - if( rule != cbm_recharge_strs.end() ) { - d.beta->rules.cbm_recharge = rule->second; - } + d.beta->set_ai_rule( "cbm_recharge_rule", setting ); }; } @@ -2296,10 +1893,10 @@ void talk_effect_fun_t::set_mapgen_update( const JsonObject &jo, const std::stri function = [target_params, update_ids]( const dialogue & d ) { mission_target_params update_params = target_params; - update_params.guy = d.beta; + update_params.guy = d.beta->get_npc(); const tripoint omt_pos = mission_util::get_om_terrain_pos( update_params ); for( const std::string &mapgen_update_id : update_ids ) { - run_mapgen_update_func( mapgen_update_id, omt_pos, d.beta->chatbin.mission_selected ); + run_mapgen_update_func( mapgen_update_id, omt_pos, d.beta->selected_mission() ); } }; } @@ -2307,17 +1904,13 @@ void talk_effect_fun_t::set_mapgen_update( const JsonObject &jo, const std::stri void talk_effect_fun_t::set_bulk_trade_accept( bool is_trade, bool is_npc ) { function = [is_trade, is_npc]( const dialogue & d ) { - player *seller = d.alpha; - player *buyer = dynamic_cast( d.beta ); - if( is_npc ) { - seller = dynamic_cast( d.beta ); - buyer = d.alpha; - } + const std::unique_ptr &seller = is_npc ? d.beta : d.alpha; + const std::unique_ptr &buyer = is_npc ? d.alpha : d.beta; int seller_has = seller->charges_of( d.cur_item ); item tmp( d.cur_item ); tmp.charges = seller_has; if( is_trade ) { - int price = tmp.price( true ) * ( is_npc ? -1 : 1 ) + d.beta->op_of_u.owed; + int price = tmp.price( true ) * ( is_npc ? -1 : 1 ) + d.beta->debt(); if( d.beta->get_faction() && !d.beta->get_faction()->currency.is_empty() ) { const itype_id &pay_in = d.beta->get_faction()->currency; item pay( pay_in ); @@ -2330,11 +1923,11 @@ void talk_effect_fun_t::set_bulk_trade_accept( bool is_trade, bool is_npc ) } else { if( buyer_has == 1 ) { //~ %1%s is the NPC name, %2$s is an item - popup( _( "%1$s gives you a %2$s." ), d.beta->disp_name(), + popup( _( "%1$s gives you a %2$s." ), seller->disp_name(), pay.tname() ); } else if( buyer_has > 1 ) { //~ %1%s is the NPC name, %2$d is a number of items, %3$s are items - popup( _( "%1$s gives you %2$d %3$s." ), d.beta->disp_name(), buyer_has, + popup( _( "%1$s gives you %2$d %3$s." ), seller->disp_name(), buyer_has, pay.tname() ); } } @@ -2343,7 +1936,7 @@ void talk_effect_fun_t::set_bulk_trade_accept( bool is_trade, bool is_npc ) price -= d.beta->value( pay ); } } - d.beta->op_of_u.owed += price; + d.beta->add_debt( price ); } } seller->use_charges( d.cur_item, seller_has ); @@ -2354,17 +1947,14 @@ void talk_effect_fun_t::set_bulk_trade_accept( bool is_trade, bool is_npc ) void talk_effect_fun_t::set_npc_gets_item( bool to_use ) { function = [to_use]( const dialogue & d ) { - d.reason = give_item_to( *( d.beta ), to_use ); + d.reason = d.beta->give_item_to( to_use ); }; } void talk_effect_fun_t::set_add_mission( const std::string &mission_id ) { function = [mission_id]( const dialogue & d ) { - npc &p = *d.beta; - mission *miss = mission::reserve_new( mission_type_id( mission_id ), p.getID() ); - miss->assign( g->u ); - p.chatbin.missions_assigned.push_back( miss ); + d.beta->add_mission( mission_type_id( mission_id ) ); }; } @@ -2376,50 +1966,18 @@ const std::vector> &talk_effect_fun_t::get_likely_rewar void talk_effect_fun_t::set_u_buy_monster( const std::string &monster_type_id, int cost, int count, bool pacified, const translation &name ) { - function = [monster_type_id, cost, count, pacified, name]( const dialogue & d ) { - npc &p = *d.beta; - player &u = *d.alpha; - if( !npc_trading::pay_npc( p, cost ) ) { - popup( _( "You can't afford it!" ) ); - return; - } + function = [monster_type_id, cost, count, pacified, name]( const dialogue & d ) { const mtype_id mtype( monster_type_id ); - - for( int i = 0; i < count; i++ ) { - monster *const mon_ptr = g->place_critter_around( mtype, u.pos(), 3 ); - if( !mon_ptr ) { - add_msg( m_debug, "Cannot place u_buy_monster, no valid placement locations." ); - break; - } - monster &tmp = *mon_ptr; - // Our monster is always a pet. - tmp.friendly = -1; - tmp.add_effect( effect_pet, 1_turns, num_bp, true ); - - if( pacified ) { - tmp.add_effect( effect_pacified, 1_turns, num_bp, true ); - } - - if( !name.empty() ) { - tmp.unique_name = name.translated(); - } - - } - - if( name.empty() ) { - popup( _( "%1$s gives you %2$d %3$s." ), p.name, count, mtype.obj().nname( count ) ); - } else { - popup( _( "%1$s gives you %2$s." ), p.name, name ); - } + d.alpha->buy_monster( *d.beta, mtype, cost, count, pacified, name ); }; } void talk_effect_fun_t::set_u_learn_recipe( const std::string &learned_recipe_id ) { - function = [learned_recipe_id]( const dialogue & d ) { + function = [learned_recipe_id]( const dialogue & ) { const recipe &r = recipe_id( learned_recipe_id ).obj(); - d.alpha->learn_recipe( &r ); + g->u.learn_recipe( &r ); popup( _( "You learn how to craft %s." ), r.result_name() ); }; } @@ -2462,24 +2020,20 @@ void talk_effect_t::set_effect( talkfunction_ptr ptr ) talk_topic talk_effect_t::apply( dialogue &d ) const { // Need to get a reference to the mission before effects are applied, because effects can remove the mission - mission *miss = d.beta->chatbin.mission_selected; + mission *miss = d.beta->selected_mission(); for( const talk_effect_fun_t &effect : effects ) { effect( d ); } - d.beta->op_of_u += opinion; + d.beta->add_opinion( opinion.trust, opinion.fear, opinion.value, opinion.anger, opinion.owed ); if( miss && ( mission_opinion.trust || mission_opinion.fear || mission_opinion.value || mission_opinion.anger ) ) { - int m_value = npc_trading::cash_to_favor( *d.beta, miss->get_value() ); - npc_opinion mod = npc_opinion( mission_opinion.trust ? - m_value / mission_opinion.trust : 0, - mission_opinion.fear ? - m_value / mission_opinion.fear : 0, - mission_opinion.value ? - m_value / mission_opinion.value : 0, - mission_opinion.anger ? - m_value / mission_opinion.anger : 0, 0 ); - d.beta->op_of_u += mod; + int m_value = d.beta->cash_to_favor( miss->get_value() ); + d.beta->add_opinion( mission_opinion.trust ? m_value / mission_opinion.trust : 0, + mission_opinion.fear ? m_value / mission_opinion.fear : 0, + mission_opinion.value ? m_value / mission_opinion.value : 0, + mission_opinion.anger ? m_value / mission_opinion.anger : 0, + 0 ); } if( d.beta->turned_hostile() ) { d.beta->make_angry(); @@ -2491,7 +2045,7 @@ talk_topic talk_effect_t::apply( dialogue &d ) const auto &ma = d.missions_assigned; ma.clear(); // Update the missions we can talk about (must only be current, non-complete ones) - for( auto &mission : d.beta->chatbin.missions_assigned ) { + for( auto &mission : d.beta->assigned_missions() ) { if( mission->get_assigned_player_id() == d.alpha->getID() ) { ma.push_back( mission ); } @@ -3159,10 +2713,7 @@ bool json_talk_topic::gen_responses( dialogue &d ) const switch_done |= r.gen_responses( d, switch_done ); } for( const json_talk_repeat_response &repeat : repeat_responses ) { - player *actor = d.alpha; - if( repeat.is_npc ) { - actor = dynamic_cast( d.beta ); - } + std::unique_ptr &actor = repeat.is_npc ? d.beta : d.alpha; std::function filter = return_true; for( const itype_id &item_id : repeat.for_item ) { if( actor->charges_of( item_id ) > 0 || actor->has_amount( item_id, 1 ) ) { @@ -3250,185 +2801,6 @@ std::string npc::pick_talk_topic( const player &/*u*/ ) return "TALK_STRANGER_NEUTRAL"; } -enum consumption_result { - REFUSED = 0, - CONSUMED_SOME, // Consumption didn't fail, but don't delete the item - CONSUMED_ALL // Consumption succeeded, delete the item -}; - -// Returns true if we destroyed the item through consumption -// does not try to consume contents -static consumption_result try_consume( npc &p, item &it, std::string &reason ) -{ - // TODO: Unify this with 'player::consume_item()' - item &to_eat = it; - if( to_eat.is_null() ) { - debugmsg( "Null item to try_consume." ); - return REFUSED; - } - const auto &comest = to_eat.get_comestible(); - if( !comest ) { - // Don't inform the player that we don't want to eat the lighter - return REFUSED; - } - - if( !p.will_accept_from_player( it ) ) { - reason = _( "I don't trust you enough to eat THIS…" ); - return REFUSED; - } - - // TODO: Make it not a copy+paste from player::consume_item - int amount_used = 1; - if( to_eat.is_food() ) { - if( !p.can_consume( to_eat ) ) { - reason = _( "It doesn't look like a good idea to consume this…" ); - return REFUSED; - } else { - const time_duration &consume_time = p.get_consume_time( to_eat ); - p.moves -= to_moves( consume_time ); - p.consume( to_eat ); - reason = _( "Thanks, that hit the spot." ); - - } - } else if( to_eat.is_medication() ) { - if( !comest->tool.is_null() ) { - bool has = p.has_amount( comest->tool, 1 ); - if( item::count_by_charges( comest->tool ) ) { - has = p.has_charges( comest->tool, 1 ); - } - if( !has ) { - reason = string_format( _( "I need a %s to consume that!" ), - item::nname( comest->tool ) ); - return REFUSED; - } - p.use_charges( comest->tool, 1 ); - reason = _( "Thanks, I feel better already." ); - } - if( to_eat.type->has_use() ) { - amount_used = to_eat.type->invoke( p, to_eat, p.pos() ); - if( amount_used <= 0 ) { - reason = _( "It doesn't look like a good idea to consume this…" ); - return REFUSED; - } - reason = _( "Thanks, I used it." ); - } - - to_eat.charges -= amount_used; - p.consume_effects( to_eat ); - p.moves -= 250; - } else { - debugmsg( "Unknown comestible type of item: %s\n", to_eat.tname() ); - } - - if( to_eat.charges > 0 ) { - return CONSUMED_SOME; - } - - // If not consuming contents and charge <= 0, we just ate the last charge from the stack - return CONSUMED_ALL; -} - -std::string give_item_to( npc &p, bool allow_use ) -{ - if( p.is_hallucination() ) { - return _( "No thanks, I'm good." ); - } - item_location loc = game_menus::inv::titled_menu( g->u, _( "Offer what?" ), - _( "You have no items to offer." ) ); - if( !loc ) { - return _( "Changed your mind?" ); - } - item &given = *loc; - - if( ( &given == &g->u.weapon && given.has_flag( "NO_UNWIELD" ) ) || ( g->u.is_worn( given ) && - given.has_flag( "NO_TAKEOFF" ) ) ) { - // Bionic weapon or shackles - return _( "How?" ); - } - - if( given.is_dangerous() && !g->u.has_trait( trait_DEBUG_MIND_CONTROL ) ) { - return _( "Are you insane!?" ); - } - - bool taken = false; - std::string reason = _( "Nope." ); - int our_ammo = p.ammo_count_for( p.weapon ); - int new_ammo = p.ammo_count_for( given ); - const double new_weapon_value = p.weapon_value( given, new_ammo ); - const double cur_weapon_value = p.weapon_value( p.weapon, our_ammo ); - add_msg( m_debug, "NPC evaluates own %s (%d ammo): %0.1f", - p.weapon.typeId().str(), our_ammo, cur_weapon_value ); - add_msg( m_debug, "NPC evaluates your %s (%d ammo): %0.1f", - given.typeId().str(), new_ammo, new_weapon_value ); - if( allow_use ) { - // Eating first, to avoid evaluating bread as a weapon - const auto consume_res = try_consume( p, given, reason ); - if( consume_res != REFUSED ) { - if( consume_res == CONSUMED_ALL ) { - g->u.i_rem( &given ); - } - g->u.moves -= 100; - if( given.is_container() ) { - given.on_contents_changed(); - } - }// wield it if its a weapon - else if( new_weapon_value > cur_weapon_value ) { - p.wield( given ); - reason = _( "Thanks, I'll wield that now." ); - taken = true; - }// HACK: is_gun here is a hack to prevent NPCs wearing guns if they don't want to use them - else if( !given.is_gun() && given.is_armor() ) { - //if it is impossible to wear return why - ret_val can_wear = p.can_wear( given, true ); - if( !can_wear.success() ) { - reason = can_wear.str(); - } else { - //if we can wear it with equip changes prompt first - can_wear = p.can_wear( given ); - if( ( can_wear.success() || - query_yn( can_wear.str() + _( " Should I take something off?" ) ) ) - && p.wear_if_wanted( given, reason ) ) { - taken = true; - } else { - reason = can_wear.str(); - } - } - } else { - reason += string_format( - _( "My current weapon is better than this.\n(new weapon value: %.1f vs %.1f)." ), new_weapon_value, - cur_weapon_value ); - } - } else {//allow_use is false so try to carry instead - if( p.can_pickVolume( given ) && p.can_pickWeight( given ) ) { - reason = _( "Thanks, I'll carry that now." ); - taken = true; - p.i_add( given ); - } else { - if( !p.can_pickVolume( given ) ) { - const units::volume free_space = p.volume_capacity() - p.volume_carried(); - reason += "\n" + std::string( _( "I have no space to store it." ) ) + "\n"; - if( free_space > 0_ml ) { - reason += string_format( _( "I can only store %s %s more." ), - format_volume( free_space ), volume_units_long() ); - } else { - reason += _( "…or to store anything else for that matter." ); - } - } - if( !p.can_pickWeight( given ) ) { - reason += std::string( "\n" ) + _( "It is too heavy for me to carry." ); - } - } - } - - if( taken ) { - g->u.i_rem( &given ); - g->u.moves -= 100; - p.has_new_items = true; - } - - return reason; -} - bool npc::has_item_whitelist() const { return is_player_ally() && !rules.pickup_whitelist->empty(); diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 4b4a773920587..3a4f3067ae35c 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -103,7 +103,7 @@ void talk_function::assign_mission( npc &p ) debugmsg( "assign_mission: mission_selected == nullptr" ); return; } - miss->assign( g->u ); + miss->assign( get_avatar() ); p.chatbin.missions_assigned.push_back( miss ); const auto it = std::find( p.chatbin.missions.begin(), p.chatbin.missions.end(), miss ); p.chatbin.missions.erase( it ); @@ -302,7 +302,8 @@ void talk_function::goto_location( npc &p ) selection_menu.text = _( "Select a destination" ); std::vector camps; tripoint destination; - for( auto elem : g->u.camps ) { + Character &player_character = get_player_character(); + for( auto elem : player_character.camps ) { if( elem == p.global_omt_location() ) { continue; } @@ -328,7 +329,7 @@ void talk_function::goto_location( npc &p ) return; } if( index == static_cast( camps.size() ) ) { - destination = g->u.global_omt_location(); + destination = player_character.global_omt_location(); } else { auto selected_camp = camps[index]; destination = selected_camp->camp_omt_pos(); @@ -449,7 +450,8 @@ void talk_function::insult_combat( npc &p ) void talk_function::bionic_install( npc &p ) { - item_location bionic = game_menus::inv::install_bionic( g->u, g->u, true ); + avatar &player_character = get_avatar(); + item_location bionic = game_menus::inv::install_bionic( player_character, player_character, true ); if( !bionic ) { return; @@ -464,15 +466,16 @@ void talk_function::bionic_install( npc &p ) } //Makes the doctor awesome at installing but not perfect - if( g->u.can_install_bionics( it, p, false, 20 ) ) { + if( player_character.can_install_bionics( it, p, false, 20 ) ) { bionic.remove_item(); - g->u.install_bionics( it, p, false, 20 ); + player_character.install_bionics( it, p, false, 20 ); } } void talk_function::bionic_remove( npc &p ) { - const bionic_collection all_bio = *g->u.my_bionics; + Character &player_character = get_player_character(); + const bionic_collection all_bio = *player_character.my_bionics; if( all_bio.empty() ) { popup( _( "You don't have any bionics installed…" ) ); return; @@ -515,9 +518,11 @@ void talk_function::bionic_remove( npc &p ) } //Makes the doctor awesome at installing but not perfect - if( g->u.can_uninstall_bionic( bionic_id( bionic_types[bionic_index].str() ), p, false ) ) { - g->u.amount_of( bionic_types[bionic_index] ); // ??? this does nothing, it just queries the count - g->u.uninstall_bionic( bionic_id( bionic_types[bionic_index].str() ), p, false ); + if( player_character.can_uninstall_bionic( bionic_id( bionic_types[bionic_index].str() ), p, + false ) ) { + player_character.amount_of( + bionic_types[bionic_index] ); // ??? this does nothing, it just queries the count + player_character.uninstall_bionic( bionic_id( bionic_types[bionic_index].str() ), p, false ); } } @@ -545,8 +550,9 @@ void talk_function::give_equipment( npc &p ) item it = *giving[chosen].loc.get_item(); giving[chosen].loc.remove_item(); popup( _( "%1$s gives you a %2$s" ), p.name, it.tname() ); - it.set_owner( g->u ); - g->u.i_add( it ); + Character &player_character = get_player_character(); + it.set_owner( player_character ); + player_character.i_add( it ); p.op_of_u.owed -= giving[chosen].price; p.add_effect( effect_asked_for_item, 3_hours ); } @@ -554,22 +560,22 @@ void talk_function::give_equipment( npc &p ) void talk_function::give_aid( npc &p ) { p.add_effect( effect_currently_busy, 30_minutes ); - for( int i = 0; i < num_hp_parts; i++ ) { - const body_part bp_healed = player::hp_to_bp( static_cast( i ) ); - g->u.heal( convert_bp( bp_healed ), 5 * rng( 2, 5 ) ); - if( g->u.has_effect( effect_bite, bp_healed ) ) { - g->u.remove_effect( effect_bite, bp_healed ); + Character &player_character = get_player_character(); + for( const bodypart_id &bp : player_character.get_all_body_parts( true ) ) { + player_character.heal( bp, 5 * rng( 2, 5 ) ); + if( player_character.has_effect( effect_bite, bp->token ) ) { + player_character.remove_effect( effect_bite, bp->token ); } - if( g->u.has_effect( effect_bleed, bp_healed ) ) { - g->u.remove_effect( effect_bleed, bp_healed ); + if( player_character.has_effect( effect_bleed, bp->token ) ) { + player_character.remove_effect( effect_bleed, bp->token ); } - if( g->u.has_effect( effect_infected, bp_healed ) ) { - g->u.remove_effect( effect_infected, bp_healed ); + if( player_character.has_effect( effect_infected, bp->token ) ) { + player_character.remove_effect( effect_infected, bp->token ); } } const int moves = to_moves( 100_minutes ); - g->u.assign_activity( ACT_WAIT_NPC, moves ); - g->u.activity.str_values.push_back( p.name ); + player_character.assign_activity( ACT_WAIT_NPC, moves ); + player_character.activity.str_values.push_back( p.name ); } void talk_function::give_all_aid( npc &p ) @@ -577,18 +583,17 @@ void talk_function::give_all_aid( npc &p ) p.add_effect( effect_currently_busy, 30_minutes ); give_aid( p ); for( npc &guy : g->all_npcs() ) { - if( guy.is_walking_with() && rl_dist( guy.pos(), g->u.pos() ) < PICKUP_RANGE ) { - for( int i = 0; i < num_hp_parts; i++ ) { - const body_part bp_healed = player::hp_to_bp( static_cast( i ) ); - guy.heal( convert_bp( bp_healed ), 5 * rng( 2, 5 ) ); - if( guy.has_effect( effect_bite, bp_healed ) ) { - guy.remove_effect( effect_bite, bp_healed ); + if( guy.is_walking_with() && rl_dist( guy.pos(), get_player_character().pos() ) < PICKUP_RANGE ) { + for( const bodypart_id &bp : guy.get_all_body_parts( true ) ) { + guy.heal( bp, 5 * rng( 2, 5 ) ); + if( guy.has_effect( effect_bite, bp->token ) ) { + guy.remove_effect( effect_bite, bp->token ); } - if( guy.has_effect( effect_bleed, bp_healed ) ) { - guy.remove_effect( effect_bleed, bp_healed ); + if( guy.has_effect( effect_bleed, bp->token ) ) { + guy.remove_effect( effect_bleed, bp->token ); } - if( guy.has_effect( effect_infected, bp_healed ) ) { - guy.remove_effect( effect_infected, bp_healed ); + if( guy.has_effect( effect_infected, bp->token ) ) { + guy.remove_effect( effect_infected, bp->token ); } } } @@ -608,9 +613,10 @@ static void generic_barber( const std::string &mut_type ) int index = 0; hair_menu.addentry( index, true, 'q', _( "Actually… I've changed my mind." ) ); std::vector hair_muts = get_mutations_in_type( mut_type ); + Character &player_character = get_player_character(); trait_id cur_hair; for( const trait_id &elem : hair_muts ) { - if( g->u.has_trait( elem ) ) { + if( player_character.has_trait( elem ) ) { cur_hair = elem; } index += 1; @@ -619,10 +625,10 @@ static void generic_barber( const std::string &mut_type ) hair_menu.query(); int choice = hair_menu.ret; if( choice != 0 ) { - if( g->u.has_trait( cur_hair ) ) { - g->u.remove_mutation( cur_hair, true ); + if( player_character.has_trait( cur_hair ) ) { + player_character.remove_mutation( cur_hair, true ); } - g->u.set_mutation( hair_muts[ choice - 1 ] ); + player_character.set_mutation( hair_muts[ choice - 1 ] ); add_msg( m_info, _( "You get a trendy new cut!" ) ); } } @@ -639,41 +645,44 @@ void talk_function::barber_hair( npc &/*p*/ ) void talk_function::buy_haircut( npc &p ) { - g->u.add_morale( MORALE_HAIRCUT, 5, 5, 720_minutes, 3_minutes ); + Character &player_character = get_player_character(); + player_character.add_morale( MORALE_HAIRCUT, 5, 5, 720_minutes, 3_minutes ); const int moves = to_moves( 20_minutes ); - g->u.assign_activity( ACT_WAIT_NPC, moves ); - g->u.activity.str_values.push_back( p.name ); + player_character.assign_activity( ACT_WAIT_NPC, moves ); + player_character.activity.str_values.push_back( p.name ); add_msg( m_good, _( "%s gives you a decent haircut…" ), p.name ); } void talk_function::buy_shave( npc &p ) { - g->u.add_morale( MORALE_SHAVE, 10, 10, 360_minutes, 3_minutes ); + Character &player_character = get_player_character(); + player_character.add_morale( MORALE_SHAVE, 10, 10, 360_minutes, 3_minutes ); const int moves = to_moves( 5_minutes ); - g->u.assign_activity( ACT_WAIT_NPC, moves ); - g->u.activity.str_values.push_back( p.name ); + player_character.assign_activity( ACT_WAIT_NPC, moves ); + player_character.activity.str_values.push_back( p.name ); add_msg( m_good, _( "%s gives you a decent shave…" ), p.name ); } void talk_function::morale_chat( npc &p ) { - g->u.add_morale( MORALE_CHAT, rng( 3, 10 ), 10, 200_minutes, 5_minutes / 2 ); + get_player_character().add_morale( MORALE_CHAT, rng( 3, 10 ), 10, 200_minutes, 5_minutes / 2 ); add_msg( m_good, _( "That was a pleasant conversation with %s…" ), p.disp_name() ); } void talk_function::morale_chat_activity( npc &p ) { + Character &player_character = get_player_character(); const int moves = to_moves( 10_minutes ); - g->u.assign_activity( ACT_SOCIALIZE, moves ); - g->u.activity.str_values.push_back( p.name ); + player_character.assign_activity( ACT_SOCIALIZE, moves ); + player_character.activity.str_values.push_back( p.name ); add_msg( m_good, _( "That was a pleasant conversation with %s." ), p.disp_name() ); - g->u.add_morale( MORALE_CHAT, rng( 3, 10 ), 10, 200_minutes, 5_minutes / 2 ); + player_character.add_morale( MORALE_CHAT, rng( 3, 10 ), 10, 200_minutes, 5_minutes / 2 ); } void talk_function::buy_10_logs( npc &p ) { std::vector places = overmap_buffer.find_all( - g->u.global_omt_location(), "ranch_camp_67", 1, false ); + get_player_character().global_omt_location(), "ranch_camp_67", 1, false ); if( places.empty() ) { debugmsg( "Couldn't find %s", "ranch_camp_67" ); return; @@ -699,7 +708,7 @@ void talk_function::buy_10_logs( npc &p ) void talk_function::buy_100_logs( npc &p ) { std::vector places = overmap_buffer.find_all( - g->u.global_omt_location(), "ranch_camp_67", 1, false ); + get_player_character().global_omt_location(), "ranch_camp_67", 1, false ); if( places.empty() ) { debugmsg( "Couldn't find %s", "ranch_camp_67" ); return; @@ -727,7 +736,7 @@ void talk_function::follow( npc &p ) g->add_npc_follower( p.getID() ); p.set_attitude( NPCATT_FOLLOW ); p.set_fac( faction_id( "your_followers" ) ); - g->u.cash += p.cash; + get_player_character().cash += p.cash; p.cash = 0; } @@ -767,7 +776,7 @@ void talk_function::hostile( npc &p ) return; } - if( p.sees( g->u ) ) { + if( p.sees( get_player_character() ) ) { add_msg( _( "%s turns hostile!" ), p.name ); } @@ -823,20 +832,21 @@ void talk_function::stranger_neutral( npc &p ) void talk_function::drop_stolen_item( npc &p ) { + Character &player_character = get_player_character(); map &here = get_map(); - for( auto &elem : g->u.inv_dump() ) { + for( auto &elem : player_character.inv_dump() ) { if( elem->is_old_owner( p ) ) { - item to_drop = g->u.i_rem( elem ); + item to_drop = player_character.i_rem( elem ); to_drop.remove_old_owner(); to_drop.set_owner( p ); - here.add_item_or_charges( g->u.pos(), to_drop ); + here.add_item_or_charges( player_character.pos(), to_drop ); } } if( p.known_stolen_item ) { p.known_stolen_item = nullptr; } - if( g->u.is_hauling() ) { - g->u.stop_hauling(); + if( player_character.is_hauling() ) { + player_character.stop_hauling(); } p.set_attitude( NPCATT_NULL ); } @@ -871,19 +881,21 @@ void talk_function::drop_weapon( npc &p ) void talk_function::player_weapon_away( npc &/*p*/ ) { - g->u.i_add( g->u.remove_weapon() ); + Character &player_character = get_player_character(); + player_character.i_add( player_character.remove_weapon() ); } void talk_function::player_weapon_drop( npc &/*p*/ ) { - get_map().add_item_or_charges( g->u.pos(), g->u.remove_weapon() ); + Character &player_character = get_player_character(); + get_map().add_item_or_charges( player_character.pos(), player_character.remove_weapon() ); } void talk_function::lead_to_safety( npc &p ) { const auto mission = mission::reserve_new( mission_type_id( "MISSION_REACH_SAFETY" ), character_id() ); - mission->assign( g->u ); + mission->assign( get_avatar() ); p.goal = mission->get_target(); p.set_attitude( NPCATT_LEAD ); } @@ -907,21 +919,24 @@ void talk_function::start_training( npc &p ) const matype_id &style = p.chatbin.style; const spell_id &sp_id = p.chatbin.dialogue_spell; int expert_multiplier = 1; - if( skill.is_valid() && g->u.get_skill_level( skill ) < p.get_skill_level( skill ) ) { + Character &player_character = get_player_character(); + if( skill.is_valid() && player_character.get_skill_level( skill ) < p.get_skill_level( skill ) ) { cost = calc_skill_training_cost( p, skill ); time = calc_skill_training_time( p, skill ); name = skill.str(); - } else if( p.chatbin.style.is_valid() && !g->u.martial_arts_data.has_martialart( style ) ) { + } else if( p.chatbin.style.is_valid() && + !player_character.martial_arts_data.has_martialart( style ) ) { cost = calc_ma_style_training_cost( p, style ); time = calc_ma_style_training_time( p, style ); name = p.chatbin.style.str(); // already checked if can learn this spell in npctalk.cpp } else if( p.chatbin.dialogue_spell.is_valid() ) { const spell &temp_spell = p.magic.get_spell( sp_id ); - const bool knows = g->u.magic.knows_spell( sp_id ); + const bool knows = player_character.magic.knows_spell( sp_id ); cost = p.calc_spell_training_cost( knows, temp_spell.get_difficulty(), temp_spell.get_level() ); name = temp_spell.id().str(); - expert_multiplier = knows ? temp_spell.get_level() - g->u.magic.get_spell( sp_id ).get_level() : 1; + expert_multiplier = knows ? temp_spell.get_level() - player_character.magic.get_spell( + sp_id ).get_level() : 1; // quicker to learn with instruction as opposed to books. // if this is a known spell, then there is a set time to gain some exp. // if player doesn't know this spell, then the NPC will teach all of it @@ -931,7 +946,8 @@ void talk_function::start_training( npc &p ) if( knows ) { time = 1_hours; } else { - time = time_duration::from_seconds( clamp( g->u.magic.time_to_learn_spell( g->u, sp_id ) / 50, 7200, + time = time_duration::from_seconds( clamp( player_character.magic.time_to_learn_spell( + player_character, sp_id ) / 50, 7200, 21600 ) ); } } else { @@ -940,8 +956,8 @@ void talk_function::start_training( npc &p ) } mission *miss = p.chatbin.mission_selected; - if( miss != nullptr && miss->get_assigned_player_id() == g->u.getID() && - miss->is_complete( g->u.getID() ) ) { + if( miss != nullptr && miss->get_assigned_player_id() == player_character.getID() && + miss->is_complete( player_character.getID() ) ) { clear_mission( p ); } else if( !npc_trading::pay_npc( p, cost ) ) { return; @@ -949,7 +965,7 @@ void talk_function::start_training( npc &p ) player_activity act = player_activity( ACT_TRAIN, to_moves( time ), p.getID().get_value(), 0, name ); act.values.push_back( expert_multiplier ); - g->u.assign_activity( act ); + player_character.assign_activity( act ); p.add_effect( effect_asked_to_train, 6_hours ); } @@ -960,7 +976,7 @@ npc *pick_follower() std::vector locations; for( npc &guy : g->all_npcs() ) { - if( guy.is_player_ally() && g->u.sees( guy ) ) { + if( guy.is_player_ally() && get_player_character().sees( guy ) ) { followers.push_back( &guy ); locations.push_back( guy.pos() ); } diff --git a/src/options.cpp b/src/options.cpp index f7c9cc54535f7..6419e39c0453a 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -2042,9 +2042,9 @@ void options_manager::add_options_world_default() 0.01, 10.0, 1.0, 0.01 ); - add( "NPC_DENSITY", "world_default", translate_marker( "NPC spawn rate scaling factor" ), - translate_marker( "A scaling factor that determines density of dynamic NPC spawns." ), - 0.0, 100.0, 0.1, 0.01 + add( "NPC_SPAWNTIME", "world_default", translate_marker( "Random NPC spawn time" ), + translate_marker( "Baseline average number of days between random NPC spawns. Average duration goes up with the number of NPCs already spawned. Set to 0 days to disable random NPCs." ), + 0.0, 100.0, 4.0, 0.01 ); add( "MONSTER_UPGRADE_FACTOR", "world_default", @@ -2118,26 +2118,6 @@ void options_manager::add_options_world_default() add_empty_line(); - add( "STATIC_NPC", "world_default", translate_marker( "Static NPCs" ), - translate_marker( "If true, static NPCs will spawn at pre-defined locations. Requires world reset." ), - true - ); - - add( "STARTING_NPC", "world_default", translate_marker( "Starting NPCs spawn" ), - translate_marker( "Determines whether starting NPCs should spawn, and if they do, how exactly." ), - { { "never", translate_marker( "Never" ) }, { "always", translate_marker( "Always" ) }, { "scenario", translate_marker( "Scenario-based" ) } }, - "scenario" - ); - - get_option( "STARTING_NPC" ).setPrerequisite( "STATIC_NPC" ); - - add( "RANDOM_NPC", "world_default", translate_marker( "Random NPCs" ), - translate_marker( "If true, the game will randomly spawn NPCs during gameplay." ), - false - ); - - add_empty_line(); - add( "RAD_MUTATION", "world_default", translate_marker( "Mutations by radiation" ), translate_marker( "If true, radiation causes the player to mutate." ), true @@ -2145,13 +2125,6 @@ void options_manager::add_options_world_default() add_empty_line(); - add( "ZLEVELS", "world_default", translate_marker( "Z-levels" ), - translate_marker( "If true, enables several features related to vertical movement, such as hauling items up stairs, climbing downspouts, and flying aircraft. May cause problems if toggled mid-game." ), - true - ); - - add_empty_line(); - add( "CHARACTER_POINT_POOLS", "world_default", translate_marker( "Character point pools" ), translate_marker( "Allowed point pools for character generation." ), { { "any", translate_marker( "Any" ) }, { "multi_pool", translate_marker( "Multi-pool only" ) }, { "no_freeform", translate_marker( "No freeform" ) } }, diff --git a/src/overmap.cpp b/src/overmap.cpp index d64ef6cddd869..02f7bc2afa154 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -1487,6 +1487,14 @@ void overmap::generate( const overmap *north, const overmap *east, requires_sub = generate_sub( z ); } while( requires_sub && ( --z >= -OVERMAP_DEPTH ) ); + // Always need at least one overlevel, but how many more + z = 1; + bool requires_over = false; + do { + requires_over = generate_over( z ); + } while( requires_over && ( ++z <= OVERMAP_HEIGHT ) ); + + // Place the monsters, now that the terrain is laid out place_mongroups(); place_radios(); @@ -1762,6 +1770,77 @@ bool overmap::generate_sub( const int z ) return requires_sub; } +bool overmap::generate_over( const int z ) +{ + bool requires_over = false; + std::vector bridge_points; + + // These are so common that it's worth checking first as int. + const std::set skip_below = { + oter_id( "empty_rock" ), oter_id( "forest" ), oter_id( "field" ), + oter_id( "forest_thick" ), oter_id( "forest_water" ) + }; + + if( z == 1 ) { + for( int i = 0; i < OMAPX; i++ ) { + for( int j = 0; j < OMAPY; j++ ) { + tripoint p( i, j, z ); + const oter_id oter_below = ter( p + tripoint_below ); + const oter_id oter_ground = ter( tripoint( p.xy(), 0 ) ); + + // implicitly skip skip_below oter_ids + if( skip_below.find( oter_below ) != skip_below.end() ) { + continue; + } + + if( is_ot_match( "bridge", oter_ground, ot_match_type::type ) ) { + ter_set( p, oter_id( "bridge_road" + oter_get_rotation_string( oter_ground ) ) ); + bridge_points.emplace_back( i, j ); + } + } + } + } + + generate_bridgeheads( bridge_points ); + + return requires_over; +} + +void overmap::generate_bridgeheads( const std::vector &bridge_points ) +{ + std::vector> bridgehead_points; + for( const point &bp : bridge_points ) { + //const oter_id oter_ground = ter( tripoint( bp, 0 ) ); + const oter_id oter_ground_north = ter( tripoint( bp, 0 ) + tripoint_north ); + const oter_id oter_ground_south = ter( tripoint( bp, 0 ) + tripoint_south ); + const oter_id oter_ground_east = ter( tripoint( bp, 0 ) + tripoint_east ); + const oter_id oter_ground_west = ter( tripoint( bp, 0 ) + tripoint_west ); + const bool is_bridge_north = is_ot_match( "bridge", oter_ground_north, ot_match_type::type ); + const bool is_bridge_south = is_ot_match( "bridge", oter_ground_south, ot_match_type::type ); + const bool is_bridge_east = is_ot_match( "bridge", oter_ground_east, ot_match_type::type ); + const bool is_bridge_west = is_ot_match( "bridge", oter_ground_west, ot_match_type::type ); + + if( is_bridge_north ^ is_bridge_south || is_bridge_east ^ is_bridge_west ) { + std::string ramp_facing; + if( is_bridge_north ) { + ramp_facing = "_south"; + } else if( is_bridge_south ) { + ramp_facing = "_north"; + } else if( is_bridge_east ) { + ramp_facing = "_west"; + } else { + ramp_facing = "_east"; + } + bridgehead_points.emplace_back( bp, ramp_facing ); + } + } + for( const std::pair &bhp : bridgehead_points ) { + tripoint p( bhp.first, 0 ); + ter_set( p, oter_id( "bridgehead_ground" + bhp.second ) ); + ter_set( p + tripoint_above, oter_id( "bridgehead_ramp" + bhp.second ) ); + } +} + std::vector overmap::find_terrain( const std::string &term, int zlevel ) { std::vector found; @@ -2244,7 +2323,7 @@ void overmap::place_forest_trailheads() const auto trailhead_close_to_road = [&]( const tripoint & trailhead ) { bool close = false; - for( const tripoint &nearby_point : closest_tripoints_first( + for( const tripoint &nearby_point : closest_points_first( trailhead, settings.forest_trail.trailhead_road_distance ) ) { @@ -2930,7 +3009,7 @@ void overmap::build_city_street( const overmap_connection &connection, const poi return; } - const pf::path street_path = lay_out_street( connection, p, dir, cs + 1 ); + const pf::path street_path = lay_out_street( connection, p, dir, cs + 1 ); if( street_path.nodes.size() <= 1 ) { return; // Don't bother. @@ -3320,10 +3399,11 @@ void overmap::build_mine( const tripoint &origin, int s ) ter_set( p, mine_finale_or_down ); } -pf::path overmap::lay_out_connection( const overmap_connection &connection, const point &source, - const point &dest, int z, const bool must_be_unexplored ) const +pf::path overmap::lay_out_connection( + const overmap_connection &connection, const point &source, const point &dest, int z, + const bool must_be_unexplored ) const { - const auto estimate = [&]( const pf::node & cur, const pf::node * prev ) { + const auto estimate = [&]( const pf::node &cur, const pf::node *prev ) { const auto &id( ter( tripoint( cur.pos, z ) ) ); const overmap_connection::subtype *subtype = connection.pick_subtype_for( id ); @@ -3371,8 +3451,8 @@ pf::path overmap::lay_out_connection( const overmap_connection &connection, cons return pf::find_path( source, dest, point( OMAPX, OMAPY ), estimate ); } -pf::path overmap::lay_out_street( const overmap_connection &connection, const point &source, - om_direction::type dir, size_t len ) const +pf::path overmap::lay_out_street( const overmap_connection &connection, const point &source, + om_direction::type dir, size_t len ) const { const tripoint from( source, 0 ); // See if we need to make another one "step" further. @@ -3434,8 +3514,8 @@ pf::path overmap::lay_out_street( const overmap_connection &connection, const po return pf::straight_path( source, static_cast( dir ), actual_len ); } -void overmap::build_connection( const overmap_connection &connection, const pf::path &path, int z, - const om_direction::type &initial_dir ) +void overmap::build_connection( const overmap_connection &connection, const pf::path &path, + int z, const om_direction::type &initial_dir ) { if( path.nodes.empty() ) { return; @@ -3443,8 +3523,8 @@ void overmap::build_connection( const overmap_connection &connection, const pf:: om_direction::type prev_dir = initial_dir; - const pf::node start = path.nodes.front(); - const pf::node end = path.nodes.back(); + const pf::node start = path.nodes.front(); + const pf::node end = path.nodes.back(); for( const auto &node : path.nodes ) { const tripoint pos( node.pos, z ); diff --git a/src/overmap.h b/src/overmap.h index c77e5e716d540..1277b2bb806fa 100644 --- a/src/overmap.h +++ b/src/overmap.h @@ -40,6 +40,7 @@ class overmap_connection; namespace pf { +template struct path; } // namespace pf @@ -387,6 +388,9 @@ class overmap const overmap *south, const overmap *west, overmap_special_batch &enabled_specials ); bool generate_sub( int z ); + bool generate_over( int z ); + // Check and put bridgeheads + void generate_bridgeheads( const std::vector &bridge_points ); const city &get_nearest_city( const tripoint &p ) const; @@ -429,13 +433,15 @@ class overmap void build_mine( const tripoint &origin, int s ); // Connection laying - pf::path lay_out_connection( const overmap_connection &connection, const point &source, - const point &dest, int z, bool must_be_unexplored ) const; - pf::path lay_out_street( const overmap_connection &connection, const point &source, - om_direction::type dir, size_t len ) const; - - void build_connection( const overmap_connection &connection, const pf::path &path, int z, - const om_direction::type &initial_dir = om_direction::type::invalid ); + pf::path lay_out_connection( + const overmap_connection &connection, const point &source, + const point &dest, int z, bool must_be_unexplored ) const; + pf::path lay_out_street( const overmap_connection &connection, const point &source, + om_direction::type dir, size_t len ) const; + + void build_connection( + const overmap_connection &connection, const pf::path &path, int z, + const om_direction::type &initial_dir = om_direction::type::invalid ); void build_connection( const point &source, const point &dest, int z, const overmap_connection &connection, bool must_be_unexplored, const om_direction::type &initial_dir = om_direction::type::invalid ); diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 8468e86d9a50b..85311fe3a4fec 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -129,12 +129,12 @@ static std::tuple get_note_display_info( const std::stri static std::array, npm_width *npm_height> get_overmap_neighbors( const tripoint ¤t ) { - const bool has_debug_vision = g->u.has_trait( trait_DEBUG_NIGHTVISION ); + const bool has_debug_vision = get_player_character().has_trait( trait_DEBUG_NIGHTVISION ); std::array, npm_width *npm_height> map_around; int index = 0; const point shift( npm_width / 2, npm_height / 2 ); - for( const tripoint &dest : tripoint_range( current - shift, current + shift ) ) { + for( const tripoint &dest : tripoint_range( current - shift, current + shift ) ) { nc_color ter_color = c_black; std::string ter_sym = " "; const bool see = has_debug_vision || overmap_buffer.seen( dest ); @@ -197,10 +197,10 @@ static void update_note_preview( const std::string ¬e, wnoutrefresh( *w_preview_map ); } -static weather_type get_weather_at_point( const tripoint &pos ) +static weather_type_id get_weather_at_point( const tripoint &pos ) { // Weather calculation is a bit expensive, so it's cached here. - static std::map weather_cache; + static std::map weather_cache; static time_point last_weather_display = calendar::before_time_starts; if( last_weather_display != calendar::turn ) { last_weather_display = calendar::turn; @@ -446,7 +446,7 @@ static point draw_notes( const tripoint &origin ) const std::string note_symbol = std::string( 1, std::get<0>( om_symbol ) ); const std::string note_text = note.substr( std::get<2>( om_symbol ), std::string::npos ); point p_omt( p ); - const point p_player = g->u.global_omt_location().xy(); + const point p_player = get_player_character().global_omt_location().xy(); const int distance_player = rl_dist( p_player, p_omt ); const point sm_pos = omt_to_sm_copy( p_omt ); const point p_om = omt_to_om_remain( p_omt ); @@ -486,17 +486,18 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr const int om_half_height = om_map_height / 2; const bool viewing_weather = ( ( data.debug_weather || data.visible_weather ) && center.z == 10 ); + avatar &player_character = get_avatar(); // Target of current mission - const tripoint target = g->u.get_active_mission_target(); + const tripoint target = player_character.get_active_mission_target(); const bool has_target = target != overmap::invalid_tripoint; // seen status & terrain of center position bool csee = false; oter_id ccur_ter = oter_str_id::NULL_ID(); // Debug vision allows seeing everything - const bool has_debug_vision = g->u.has_trait( trait_DEBUG_NIGHTVISION ); + const bool has_debug_vision = player_character.has_trait( trait_DEBUG_NIGHTVISION ); // sight_points is hoisted for speed reasons. const int sight_points = !has_debug_vision ? - g->u.overmap_sight_range( g->light_level( g->u.posz() ) ) : + player_character.overmap_sight_range( g->light_level( player_character.posz() ) ) : 100; // Whether showing hordes is currently enabled const bool showhordes = uistate.overmap_show_hordes; @@ -634,8 +635,8 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr } } } - for( auto &elem : g->u.omt_path ) { - tripoint tri_to_add = tripoint( elem.xy(), g->u.posz() ); + for( auto &elem : player_character.omt_path ) { + tripoint tri_to_add = tripoint( elem.xy(), player_character.posz() ); player_path_route.push_back( tri_to_add ); } for( const auto &np : followers ) { @@ -672,8 +673,8 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr } // Check if location is within player line-of-sight - const bool los = see && g->u.overmap_los( omp, sight_points ); - const bool los_sky = g->u.overmap_los( omp, sight_points * 2 ); + const bool los = see && player_character.overmap_los( omp, sight_points ); + const bool los_sky = player_character.overmap_los( omp, sight_points * 2 ); int mycount = std::count( path_route.begin(), path_route.end(), omp ); bool player_path_count = false; std::vector::iterator it; @@ -683,12 +684,12 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr } if( blink && omp == orig ) { // Display player pos, should always be visible - ter_color = g->u.symbol_color(); + ter_color = player_character.symbol_color(); ter_sym = "@"; } else if( viewing_weather && ( data.debug_weather || los_sky ) ) { - const weather_type type = get_weather_at_point( omp ); - ter_color = weather::map_color( type ); - ter_sym = weather::glyph( type ); + const weather_type_id type = get_weather_at_point( omp ); + ter_color = type->map_color; + ter_sym = type->glyph; } else if( data.debug_scent && get_scent_glyph( omp, ter_color, ter_sym ) ) { // get_scent_glyph has changed ter_color and ter_sym if omp has a scent } else if( blink && has_target && omp.xy() == target.xy() ) { @@ -968,11 +969,11 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr } } else if( viewing_weather ) { const bool weather_is_visible = ( data.debug_weather || - g->u.overmap_los( center, sight_points * 2 ) ); + player_character.overmap_los( center, sight_points * 2 ) ); if( weather_is_visible ) { - weather_datum weather = weather_data( get_weather_at_point( center ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) - mvwprintz( wbar, point( 1, 1 ), weather.color, weather.name ); + mvwprintz( wbar, point( 1, 1 ), get_weather_at_point( center )->color, + get_weather_at_point( center )->name ); } else { // NOLINTNEXTLINE(cata-use-named-point-constants) mvwprintz( wbar, point( 1, 1 ), c_dark_gray, _( "# Unexplored" ) ); @@ -1006,7 +1007,7 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr } //Show mission targets on this location - for( auto &mission : g->u.get_active_missions() ) { + for( auto &mission : player_character.get_active_missions() ) { if( mission->get_target() == center ) { mvwprintz( wbar, point( 1, ++lines ), c_white, mission->name() ); } @@ -1539,9 +1540,10 @@ static tripoint display( const tripoint &orig, const draw_data_t &data = draw_da path_type ptype; ptype.only_known_by_player = true; ptype.avoid_danger = true; - bool in_vehicle = g->u.in_vehicle && g->u.controlling_vehicle; + avatar &player_character = get_avatar(); + bool in_vehicle = player_character.in_vehicle && player_character.controlling_vehicle; map &here = get_map(); - const optional_vpart_position vp = here.veh_at( g->u.pos() ); + const optional_vpart_position vp = here.veh_at( player_character.pos() ); if( vp && in_vehicle ) { vehicle &veh = vp->vehicle(); if( veh.can_float() && veh.is_watercraft() && veh.is_in_water() ) { @@ -1554,37 +1556,37 @@ static tripoint display( const tripoint &orig, const draw_data_t &data = draw_da } else { const oter_id oter = overmap_buffer.ter( curs ); // going to or coming from a water tile - if( is_river_or_lake( oter ) || here.has_flag( "SWIMMABLE", g->u.pos() ) ) { + if( is_river_or_lake( oter ) || here.has_flag( "SWIMMABLE", player_character.pos() ) ) { ptype.amphibious = true; } } - const tripoint player_omt_pos = g->u.global_omt_location(); - if( !g->u.omt_path.empty() && g->u.omt_path.front() == curs ) { + const tripoint player_omt_pos = player_character.global_omt_location(); + if( !player_character.omt_path.empty() && player_character.omt_path.front() == curs ) { std::string confirm_msg; - if( g->u.weight_carried() > g->u.weight_capacity() ) { + if( player_character.weight_carried() > player_character.weight_capacity() ) { confirm_msg = _( "You are overburdened, are you sure you want to travel (it may be painful)?" ); } else { confirm_msg = _( "Travel to this point?" ); } if( query_yn( confirm_msg ) ) { // renew the path incase of a leftover dangling path point - g->u.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, ptype ); - if( g->u.in_vehicle && g->u.controlling_vehicle ) { - vehicle *player_veh = veh_pointer_or_null( here.veh_at( g->u.pos() ) ); - player_veh->omt_path = g->u.omt_path; + player_character.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, ptype ); + if( player_character.in_vehicle && player_character.controlling_vehicle ) { + vehicle *player_veh = veh_pointer_or_null( here.veh_at( player_character.pos() ) ); + player_veh->omt_path = player_character.omt_path; player_veh->is_autodriving = true; - g->u.assign_activity( ACT_AUTODRIVE ); + player_character.assign_activity( ACT_AUTODRIVE ); } else { - g->u.reset_move_mode(); - g->u.assign_activity( ACT_TRAVELLING ); + player_character.reset_move_mode(); + player_character.assign_activity( ACT_TRAVELLING ); } action = "QUIT"; } } if( curs == player_omt_pos ) { - g->u.omt_path.clear(); + player_character.omt_path.clear(); } else { - g->u.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, ptype ); + player_character.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, ptype ); } } else if( action == "TOGGLE_BLINKING" ) { uistate.overmap_blinking = !uistate.overmap_blinking; @@ -1643,21 +1645,21 @@ static tripoint display( const tripoint &orig, const draw_data_t &data = draw_da void ui::omap::display() { - overmap_ui::display( g->u.global_omt_location(), overmap_ui::draw_data_t() ); + overmap_ui::display( get_player_character().global_omt_location(), overmap_ui::draw_data_t() ); } void ui::omap::display_hordes() { overmap_ui::draw_data_t data; data.debug_mongroup = true; - overmap_ui::display( g->u.global_omt_location(), data ); + overmap_ui::display( get_player_character().global_omt_location(), data ); } void ui::omap::display_weather() { overmap_ui::draw_data_t data; data.debug_weather = true; - tripoint pos = g->u.global_omt_location(); + tripoint pos = get_player_character().global_omt_location(); pos.z = 10; overmap_ui::display( pos, data ); } @@ -1666,7 +1668,7 @@ void ui::omap::display_visible_weather() { overmap_ui::draw_data_t data; data.visible_weather = true; - tripoint pos = g->u.global_omt_location(); + tripoint pos = get_player_character().global_omt_location(); pos.z = 10; overmap_ui::display( pos, data ); } @@ -1675,14 +1677,14 @@ void ui::omap::display_scents() { overmap_ui::draw_data_t data; data.debug_scent = true; - overmap_ui::display( g->u.global_omt_location(), data ); + overmap_ui::display( get_player_character().global_omt_location(), data ); } void ui::omap::display_editor() { overmap_ui::draw_data_t data; data.debug_editor = true; - overmap_ui::display( g->u.global_omt_location(), data ); + overmap_ui::display( get_player_character().global_omt_location(), data ); } void ui::omap::display_zones( const tripoint ¢er, const tripoint &select, const int iZoneIndex ) @@ -1695,7 +1697,7 @@ void ui::omap::display_zones( const tripoint ¢er, const tripoint &select, co tripoint ui::omap::choose_point() { - return overmap_ui::display( g->u.global_omt_location() ); + return overmap_ui::display( get_player_character().global_omt_location() ); } tripoint ui::omap::choose_point( const tripoint &origin ) @@ -1705,7 +1707,7 @@ tripoint ui::omap::choose_point( const tripoint &origin ) tripoint ui::omap::choose_point( int z ) { - tripoint loc = g->u.global_omt_location(); + tripoint loc = get_player_character().global_omt_location(); loc.z = z; return overmap_ui::display( loc ); } diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index 209ecdd9b7778..9e210862e1eae 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -7,10 +7,10 @@ #include #include -#include "avatar.h" #include "basecamp.h" #include "calendar.h" #include "cata_utility.h" +#include "character.h" #include "character_id.h" #include "color.h" #include "common_types.h" @@ -482,7 +482,7 @@ void overmapbuffer::process_mongroups() { // arbitrary radius to include nearby overmaps (aside from the current one) const auto radius = MAPSIZE * 2; - const auto center = g->u.global_sm_location(); + const auto center = get_player_character().global_sm_location(); for( auto &om : get_overmaps_near( center, radius ) ) { om->process_mongroups(); } @@ -492,7 +492,7 @@ void overmapbuffer::move_hordes() { // arbitrary radius to include nearby overmaps (aside from the current one) const auto radius = MAPSIZE * 2; - const auto center = g->u.global_sm_location(); + const auto center = get_player_character().global_sm_location(); for( auto &om : get_overmaps_near( center, radius ) ) { om->move_hordes(); } @@ -564,7 +564,7 @@ void overmapbuffer::set_scent( const tripoint &loc, int strength ) void overmapbuffer::move_vehicle( vehicle *veh, const point &old_msp ) { - const point new_msp = g->m.getabs( veh->global_pos3().xy() ); + const point new_msp = get_map().getabs( veh->global_pos3().xy() ); const point old_omt = ms_to_omt_copy( old_msp ); const point new_omt = ms_to_omt_copy( new_msp ); const overmap_with_local_coords old_om_loc = get_om_global( old_omt ); @@ -592,14 +592,14 @@ void overmapbuffer::remove_camp( const basecamp &camp ) void overmapbuffer::remove_vehicle( const vehicle *veh ) { - const point omt = ms_to_omt_copy( g->m.getabs( veh->global_pos3().xy() ) ); + const point omt = ms_to_omt_copy( get_map().getabs( veh->global_pos3().xy() ) ); const overmap_with_local_coords om_loc = get_om_global( omt ); om_loc.om->vehicles.erase( veh->om_id ); } void overmapbuffer::add_vehicle( vehicle *veh ) { - const point abs_pos = g->m.getabs( veh->global_pos3().xy() ); + const point abs_pos = get_map().getabs( veh->global_pos3().xy() ); const point omt = ms_to_omt_copy( abs_pos ); const overmap_with_local_coords om_loc = get_om_global( omt ); int id = om_loc.om->vehicles.size() + 1; @@ -708,7 +708,7 @@ std::vector overmapbuffer::get_npc_path( const tripoint &src, const tr const auto get_ter_at = [&]( const point & p ) { return ter( base + p ); }; - const auto estimate = [&]( const pf::node & cur, const pf::node * ) { + const auto estimate = [&]( const pf::node &cur, const pf::node * ) { const tripoint convert_result = base + tripoint( cur.pos, 0 ); if( ptype.only_known_by_player && !seen( convert_result ) ) { return pf::rejected; @@ -759,7 +759,7 @@ std::vector overmapbuffer::get_npc_path( const tripoint &src, const tr return res; }; - pf::path route = pf::find_path( start, finish, point( 2 * O.x, 2 * O.y ), estimate ); + pf::path route = pf::find_path( start, finish, point( 2 * O.x, 2 * O.y ), estimate ); for( auto node : route.nodes ) { tripoint convert_result = base + tripoint( node.pos, 0 ); convert_result.z = base.z; @@ -796,7 +796,7 @@ bool overmapbuffer::reveal_route( const tripoint &source, const tripoint &dest, return false; } - const auto estimate = [&]( const pf::node & cur, const pf::node * ) { + const auto estimate = [&]( const pf::node &cur, const pf::node * ) { int res = 0; const oter_id oter = get_ter_at( cur.pos ); @@ -994,7 +994,7 @@ std::vector overmapbuffer::find_all( const tripoint &origin, const int min_dist = params.min_distance; const int max_dist = params.search_range ? params.search_range : OMAPX; - for( const tripoint &loc : closest_tripoints_first( origin, min_dist, max_dist ) ) { + for( const tripoint &loc : closest_points_first( origin, min_dist, max_dist ) ) { if( is_findable_location( loc, params ) ) { result.push_back( loc ); } @@ -1073,11 +1073,11 @@ shared_ptr_fast overmapbuffer::remove_npc( const character_id &id ) std::vector> overmapbuffer::get_npcs_near_player( int radius ) { - tripoint plpos = g->u.global_omt_location(); + tripoint plpos = get_player_character().global_omt_location(); // get_npcs_near needs submap coordinates omt_to_sm( plpos.x, plpos.y ); // INT_MIN is a (a bit ugly) way to inform get_npcs_near not to filter by z-level - const int zpos = g->m.has_zlevels() ? INT_MIN : plpos.z; + const int zpos = get_map().has_zlevels() ? INT_MIN : plpos.z; return get_npcs_near( tripoint( plpos.xy(), zpos ), radius ); } @@ -1179,7 +1179,7 @@ static radio_tower_reference create_radio_tower_reference( const overmap &om, ra radio_tower_reference overmapbuffer::find_radio_station( const int frequency ) { - const auto center = g->u.global_sm_location(); + const auto center = get_player_character().global_sm_location(); for( auto &om : get_overmaps_near( center, RADIO_MAX_STRENGTH ) ) { for( auto &tower : om->radios ) { const auto rref = create_radio_tower_reference( *om, tower, center ); @@ -1194,7 +1194,7 @@ radio_tower_reference overmapbuffer::find_radio_station( const int frequency ) std::vector overmapbuffer::find_all_radio_stations() { std::vector result; - const auto center = g->u.global_sm_location(); + const auto center = get_player_character().global_sm_location(); // perceived signal strength is distance (in submaps) - signal strength, so towers // further than RADIO_MAX_STRENGTH submaps away can never be received at all. const int radius = RADIO_MAX_STRENGTH; @@ -1370,9 +1370,10 @@ void overmapbuffer::spawn_monster( const tripoint &p ) assert( ms.x >= 0 && ms.x < SEEX ); assert( ms.y >= 0 && ms.y < SEEX ); ms += sm_to_ms_copy( p.xy() ); + const map &here = get_map(); // The monster position must be local to the main map when added to the game - const tripoint local = tripoint( g->m.getlocal( ms ), p.z ); - assert( g->m.inbounds( local ) ); + const tripoint local = tripoint( here.getlocal( ms ), p.z ); + assert( here.inbounds( local ) ); monster *const placed = g->place_critter_at( make_shared_fast( this_monster ), local ); if( placed ) { @@ -1385,7 +1386,7 @@ void overmapbuffer::spawn_monster( const tripoint &p ) void overmapbuffer::despawn_monster( const monster &critter ) { // Get absolute coordinates of the monster in map squares, translate to submap position - tripoint sm = ms_to_sm_copy( g->m.getabs( critter.pos() ) ); + tripoint sm = ms_to_sm_copy( get_map().getabs( critter.pos() ) ); // Get the overmap coordinates and get the overmap, sm is now local to that overmap const point omp = sm_to_om_remain( sm.x, sm.y ); overmap &om = get( omp ); diff --git a/src/panels.cpp b/src/panels.cpp index 459f366f047ec..532566d129a75 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -863,7 +863,7 @@ static int get_int_digits( const int &digits ) // panels code // =============================== -static void draw_limb_health( avatar &u, const catacurses::window &w, int limb_index ) +static void draw_limb_health( avatar &u, const catacurses::window &w, bodypart_id bp ) { const bool no_feeling = u.has_trait( trait_NOPAIN ); const bool is_self_aware = u.has_trait( trait_SELFAWARE ) && !no_feeling; @@ -873,9 +873,8 @@ static void draw_limb_health( avatar &u, const catacurses::window &w, int limb_i wprintz( w, color, sym ); } }; - const bodypart_id bp = convert_bp( avatar::hp_to_bp( static_cast( limb_index ) ) ).id(); - if( u.is_limb_broken( bp.id() ) && ( limb_index >= hp_arm_l && - limb_index <= hp_leg_r ) ) { + + if( u.is_limb_broken( bp ) && bp->is_limb ) { //Limb is broken std::string limb = "~~%~~"; nc_color color = c_light_red; @@ -925,27 +924,24 @@ static void draw_limb_health( avatar &u, const catacurses::window &w, int limb_i static void draw_limb2( avatar &u, const catacurses::window &w ) { - static std::array part = { { - bodypart_id( "head" ), bodypart_id( "torso" ), bodypart_id( "arm_l" ), bodypart_id( "arm_r" ), bodypart_id( "leg_l" ), bodypart_id( "leg_r" ) - } - }; - werase( w ); - // print limb health - for( int i = 0; i < num_hp_parts; i++ ) { - const std::string str = body_part_hp_bar_ui_text( part[i] ); + // print bodypart health + int i = 0; + for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { + const std::string str = body_part_hp_bar_ui_text( bp ); if( i % 2 == 0 ) { wmove( w, point( 0, i / 2 ) ); } else { wmove( w, point( 11, i / 2 ) ); } - wprintz( w, u.limb_color( part[i], true, true, true ), str ); + wprintz( w, u.limb_color( bp, true, true, true ), str ); if( i % 2 == 0 ) { wmove( w, point( 5, i / 2 ) ); } else { wmove( w, point( 16, i / 2 ) ); } - draw_limb_health( u, w, i ); + draw_limb_health( u, w, bp ); + i++; } // print mood @@ -1126,7 +1122,8 @@ static void draw_limb_narrow( avatar &u, const catacurses::window &w ) { werase( w ); int ny2 = 0; - for( int i = 0; i < num_hp_parts; i++ ) { + int i = 0; + for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { int ny; int nx; if( i < 3 ) { @@ -1137,16 +1134,14 @@ static void draw_limb_narrow( avatar &u, const catacurses::window &w ) nx = 26; } wmove( w, point( nx, ny ) ); - draw_limb_health( u, w, i ); + draw_limb_health( u, w, bp ); + i++; } // display limbs status - static std::array part = { { - bodypart_id( "head" ), bodypart_id( "torso" ), bodypart_id( "arm_l" ), bodypart_id( "arm_r" ), bodypart_id( "leg_l" ), bodypart_id( "leg_r" ) - } - }; ny2 = 0; - for( size_t i = 0; i < part.size(); i++ ) { + i = 0; + for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { int ny; int nx; if( i < 3 ) { @@ -1157,34 +1152,29 @@ static void draw_limb_narrow( avatar &u, const catacurses::window &w ) nx = 19; } - std::string str = body_part_hp_bar_ui_text( part[i] ); + std::string str = body_part_hp_bar_ui_text( bp ); wmove( w, point( nx, ny ) ); str = left_justify( str, 5 ); - wprintz( w, u.limb_color( part[i], true, true, true ), str + ":" ); + wprintz( w, u.limb_color( bp, true, true, true ), str + ":" ); + i++; } wnoutrefresh( w ); } static void draw_limb_wide( avatar &u, const catacurses::window &w ) { - const std::vector> parts = { - {bodypart_id( "arm_l" ), 2}, - {bodypart_id( "head" ), 0}, - {bodypart_id( "arm_r" ), 3}, - {bodypart_id( "leg_l" ), 4}, - {bodypart_id( "torso" ), 1}, - {bodypart_id( "leg_r" ), 5} - }; werase( w ); - for( int i = 0; i < num_hp_parts; i++ ) { + int i = 0; + for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { int offset = i * 15; int ny = offset / 45; int nx = offset % 45; std::string str = string_format( " %s: ", - left_justify( body_part_hp_bar_ui_text( parts[i].first ), 5 ) ); - nc_color part_color = u.limb_color( parts[i].first, true, true, true ); + left_justify( body_part_hp_bar_ui_text( bp ), 5 ) ); + nc_color part_color = u.limb_color( bp, true, true, true ); print_colored_text( w, point( nx, ny ), part_color, c_white, str ); - draw_limb_health( u, w, parts[i].second ); + draw_limb_health( u, w, bp ); + i++; } wnoutrefresh( w ); } @@ -1336,8 +1326,7 @@ static void draw_loc_labels( const avatar &u, const catacurses::window &w, bool } else { // NOLINTNEXTLINE(cata-use-named-point-constants) mvwprintz( w, point( 1, 1 ), c_light_gray, _( "Sky :" ) ); - const weather_datum wdata = weather_data( get_weather().weather ); - wprintz( w, wdata.color, " %s", wdata.name ); + wprintz( w, get_weather().weather_id->color, " %s", get_weather().weather_id->name ); } // display lighting const std::pair ll = get_light_level( @@ -1503,8 +1492,7 @@ static void draw_env_compact( avatar &u, const catacurses::window &w ) if( g->get_levz() < 0 ) { mvwprintz( w, point( 8, 3 ), c_light_gray, _( "Underground" ) ); } else { - const weather_datum wdata = weather_data( g->weather.weather ); - mvwprintz( w, point( 8, 3 ), wdata.color, wdata.name ); + mvwprintz( w, point( 8, 3 ), get_weather().weather_id->color, get_weather().weather_id->name ); } // display lighting const std::pair ll = get_light_level( @@ -1551,11 +1539,6 @@ static void draw_wind_padding( avatar &u, const catacurses::window &w ) static void draw_health_classic( avatar &u, const catacurses::window &w ) { - static std::array part = { { - bodypart_id( "head" ), bodypart_id( "torso" ), bodypart_id( "arm_l" ), bodypart_id( "arm_r" ), bodypart_id( "leg_l" ), bodypart_id( "leg_r" ) - } - }; - vehicle *veh = g->remoteveh(); if( veh == nullptr && u.in_vehicle ) { veh = veh_pointer_or_null( get_map().veh_at( u.pos() ) ); @@ -1567,12 +1550,14 @@ static void draw_health_classic( avatar &u, const catacurses::window &w ) draw_rectangle( w, c_light_gray, point_zero, point( 6, 6 ) ); // print limb health - for( int i = 0; i < num_hp_parts; i++ ) { - const std::string str = body_part_hp_bar_ui_text( part[i] ); + int i = 0; + for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { + const std::string str = body_part_hp_bar_ui_text( bp ); wmove( w, point( 8, i ) ); - wprintz( w, u.limb_color( part[i], true, true, true ), str ); + wprintz( w, u.limb_color( bp, true, true, true ), str ); wmove( w, point( 14, i ) ); - draw_limb_health( u, w, i ); + draw_limb_health( u, w, bp ); + i++; } // needs @@ -1850,9 +1835,8 @@ static void draw_weather_classic( avatar &, const catacurses::window &w ) if( g->get_levz() < 0 ) { mvwprintz( w, point_zero, c_light_gray, _( "Underground" ) ); } else { - const weather_datum wdata = weather_data( get_weather().weather ); mvwprintz( w, point_zero, c_light_gray, _( "Weather :" ) ); - mvwprintz( w, point( 10, 0 ), wdata.color, wdata.name ); + mvwprintz( w, point( 10, 0 ), get_weather().weather_id->color, get_weather().weather_id->name ); } mvwprintz( w, point( 31, 0 ), c_light_gray, _( "Moon :" ) ); nc_color clr = c_white; diff --git a/src/pathfinding.cpp b/src/pathfinding.cpp index 333fe4aa06328..8e0ac223a2144 100644 --- a/src/pathfinding.cpp +++ b/src/pathfinding.cpp @@ -465,6 +465,27 @@ std::vector map::route( const tripoint &f, const tripoint &t, cur, above ); } } + if( cur.z < maxz && parent_terrain.has_flag( TFLAG_RAMP_UP ) && + valid_move( cur, tripoint( cur.xy(), cur.z + 1 ), false, true, true ) ) { + auto &layer = pf.get_layer( cur.z + 1 ); + for( size_t it = 0; it < 8; it++ ) { + const tripoint above( cur.x + x_offset[it], cur.y + y_offset[it], cur.z + 1 ); + pf.add_point( layer.gscore[parent_index] + 4, + layer.score[parent_index] + 4 + 2 * rl_dist( above, t ), + cur, above ); + } + } + if( cur.z > minz && parent_terrain.has_flag( TFLAG_RAMP_DOWN ) && + valid_move( cur, tripoint( cur.xy(), cur.z - 1 ), false, true, true ) ) { + auto &layer = pf.get_layer( cur.z - 1 ); + for( size_t it = 0; it < 8; it++ ) { + const tripoint below( cur.x + x_offset[it], cur.y + y_offset[it], cur.z - 1 ); + pf.add_point( layer.gscore[parent_index] + 4, + layer.score[parent_index] + 4 + 2 * rl_dist( below, t ), + cur, below ); + } + } + } while( !done && !pf.empty() ); if( done ) { diff --git a/src/pickup.cpp b/src/pickup.cpp index c143686030031..df5b82f176331 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -140,7 +140,7 @@ static pickup_answer handle_problematic_pickup( const item &it, bool &offered_sw return CANCEL; } - player &u = g->u; + Character &u = get_player_character(); uilist amenu; @@ -149,7 +149,7 @@ static pickup_answer handle_problematic_pickup( const item &it, bool &offered_sw offered_swap = true; // TODO: Gray out if not enough hands if( u.is_armed() ) { - amenu.addentry( WIELD, !u.weapon.has_flag( "NO_UNWIELD" ), 'w', + amenu.addentry( WIELD, u.can_unwield( u.weapon ).success(), 'w', _( "Dispose of %s and wield %s" ), u.weapon.display_name(), it.display_name() ); } else { @@ -175,7 +175,7 @@ static pickup_answer handle_problematic_pickup( const item &it, bool &offered_sw bool Pickup::query_thief() { - player &u = g->u; + Character &u = get_player_character(); const bool force_uc = get_option( "FORCE_CAPITAL_YN" ); const auto &allow_key = force_uc ? input_context::disallow_lower_case : input_context::allow_all_keys; @@ -219,7 +219,7 @@ bool Pickup::query_thief() bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offered_swap, PickupMap &mapPickup, bool autopickup ) { - player &u = g->u; + player &u = get_avatar(); int moves_taken = 100; bool picked_up = false; pickup_answer option = CANCEL; @@ -231,11 +231,8 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer item &it = *newloc.get_item(); //new item (copy) item newit = it; - item leftovers = newit; - const auto wield_check = u.can_wield( newit ); - - if( !newit.is_owned_by( g->u, true ) ) { + if( !newit.is_owned_by( u, true ) ) { // Has the player given input on if stealing is ok? if( u.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { Pickup::query_thief(); @@ -253,12 +250,9 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer // Handle charges, quantity == 0 means move all if( quantity != 0 && newit.count_by_charges() ) { - leftovers.charges = newit.charges - quantity; - if( leftovers.charges > 0 ) { + if( newit.charges > quantity ) { newit.charges = quantity; } - } else { - leftovers.charges = 0; } bool did_prompt = false; @@ -309,7 +303,8 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer case WEAR: picked_up = !!u.wear_item( newit ); break; - case WIELD: + case WIELD: { + const auto wield_check = u.can_wield( it ); if( wield_check.success() ) { //using original item, possibly modifying it picked_up = u.wield( it ); @@ -326,6 +321,7 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer add_msg( m_neutral, wield_check.c_str() ); } break; + } case SPILL: if( newit.is_container_empty() ) { debugmsg( "Tried to spill contents from an empty container" ); @@ -356,14 +352,16 @@ bool pick_one_up( item_location &loc, int quantity, bool &got_water, bool &offer } if( picked_up ) { - // If we picked up a whole stack, remove the original item - // Otherwise, replace the item with the leftovers - if( leftovers.charges > 0 ) { - *loc.get_item() = std::move( leftovers ); + item &orig_it = *loc.get_item(); + // Subtract moved charges instead of assigning leftover charges, + // since the total charges of the original item may have changed + // due to merging. + if( orig_it.charges > newit.charges ) { + orig_it.charges -= newit.charges; } else { loc.remove_item(); } - g->u.moves -= moves_taken; + u.moves -= moves_taken; } return picked_up || !did_prompt; @@ -416,7 +414,8 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) { int cargo_part = -1; - const optional_vpart_position vp = g->m.veh_at( p ); + map &local = get_map(); + const optional_vpart_position vp = local.veh_at( p ); vehicle *const veh = veh_pointer_or_null( vp ); bool from_vehicle = false; @@ -424,7 +423,7 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) if( veh != nullptr && get_items_from == prompt ) { const cata::optional carg = vp.part_with_feature( "CARGO", false ); const bool veh_has_items = carg && !veh->get_items( carg->part_index() ).empty(); - const bool map_has_items = g->m.has_items( p ); + const bool map_has_items = local.has_items( p ); if( veh_has_items && map_has_items ) { uilist amenu( _( "Get items from where?" ), { _( "Get items from vehicle cargo" ), _( "Get items on the ground" ) } ); if( amenu.ret == UILIST_CANCEL ) { @@ -441,20 +440,20 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) from_vehicle = cargo_part >= 0; } else { // Nothing to change, default is to pick from ground anyway. - if( g->m.has_flag( "SEALED", p ) ) { + if( local.has_flag( "SEALED", p ) ) { return; } } } if( !from_vehicle ) { - bool isEmpty = ( g->m.i_at( p ).empty() ); + bool isEmpty = ( local.i_at( p ).empty() ); // Hide the pickup window if this is a toilet and there's nothing here // but non-frozen water. - if( ( !isEmpty ) && g->m.furn( p ) == f_toilet ) { + if( ( !isEmpty ) && local.furn( p ) == f_toilet ) { isEmpty = true; - for( const item &maybe_water : g->m.i_at( p ) ) { + for( const item &maybe_water : local.i_at( p ) ) { if( maybe_water.typeId() != itype_water || maybe_water.is_frozen_liquid() ) { isEmpty = false; break; @@ -475,7 +474,7 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) here.push_back( it ); } } else { - map_stack mapitems = g->m.i_at( p ); + map_stack mapitems = local.i_at( p ); for( item_stack::iterator it = mapitems.begin(); it != mapitems.end(); ++it ) { here.push_back( it ); } @@ -498,7 +497,7 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) // Bail out if this square cannot be auto-picked-up if( g->check_zone( zone_type_id( "NO_AUTO_PICKUP" ), p ) ) { return; - } else if( g->m.has_flag( "SEALED", p ) ) { + } else if( local.has_flag( "SEALED", p ) ) { return; } } diff --git a/src/pixel_minimap.cpp b/src/pixel_minimap.cpp index e48725537c7d4..6fde954b06de6 100644 --- a/src/pixel_minimap.cpp +++ b/src/pixel_minimap.cpp @@ -14,7 +14,6 @@ #include #include -#include "avatar.h" #include "cata_utility.h" #include "character.h" #include "color.h" @@ -101,7 +100,7 @@ SDL_Color get_critter_color( Creature *critter, int flicker, int mixture ) if( const monster *m = dynamic_cast( critter ) ) { //faction status (attacking or tracking) determines if red highlights get applied to creature - const monster_attitude matt = m->attitude( &get_avatar() ); + const monster_attitude matt = m->attitude( &get_player_character() ); if( MATT_ATTACK == matt || MATT_FOLLOW == matt ) { const SDL_Color red_pixel = SDL_Color{ 0xFF, 0x0, 0x0, 0xFF }; @@ -296,7 +295,7 @@ void pixel_minimap::update_cache_at( const tripoint &sm_pos ) { const map &here = get_map(); const level_cache &access_cache = here.access_cache( sm_pos.z ); - const bool nv_goggle = get_avatar().get_vision_modes()[NV_GOGGLES]; + const bool nv_goggle = get_player_character().get_vision_modes()[NV_GOGGLES]; submap_cache &cache_item = get_cache_at( here.get_abs_sub() + sm_pos ); const tripoint ms_pos = sm_to_ms_copy( sm_pos ); @@ -514,7 +513,7 @@ void pixel_minimap::render_critters( const tripoint ¢er ) const auto critter = g->critter_at( p, true ); - if( critter == nullptr || !get_avatar().sees( *critter ) ) { + if( critter == nullptr || !get_player_character().sees( *critter ) ) { continue; } diff --git a/src/player.cpp b/src/player.cpp index 747ccab813796..8a149a52fdc66 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -88,6 +88,7 @@ static const efftype_id effect_adrenaline( "adrenaline" ); static const efftype_id effect_bite( "bite" ); +static const efftype_id effect_bleed( "bleed" ); static const efftype_id effect_blind( "blind" ); static const efftype_id effect_bloodworms( "bloodworms" ); static const efftype_id effect_boomered( "boomered" ); @@ -191,6 +192,7 @@ static const trait_id trait_WEB_WEAVER( "WEB_WEAVER" ); static const std::string flag_SPLINT( "SPLINT" ); static const skill_id skill_dodge( "dodge" ); +static const skill_id skill_firstaid( "firstaid" ); static const skill_id skill_gun( "gun" ); static const skill_id skill_swimming( "swimming" ); @@ -278,7 +280,7 @@ player::player() } recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); } player::~player() = default; @@ -558,7 +560,7 @@ double player::recoil_vehicle() const // TODO: vary penalty dependent upon vehicle part on which player is boarded if( in_vehicle ) { - if( const optional_vpart_position vp = g->m.veh_at( pos() ) ) { + if( const optional_vpart_position vp = get_map().veh_at( pos() ) ) { return static_cast( std::abs( vp->vehicle().velocity ) ) * 3 / 100; } } @@ -751,6 +753,7 @@ void player::pause() moves = 0; recoil = MAX_RECOIL; + map &here = get_map(); // Train swimming if underwater if( !in_vehicle ) { if( underwater ) { @@ -761,7 +764,7 @@ void player::pause() bodypart_str_id( "foot_l" ), bodypart_str_id( "foot_r" ), bodypart_str_id( "hand_l" ), bodypart_str_id( "hand_r" ) } }, true ); - } else if( g->m.has_flag( TFLAG_DEEP_WATER, pos() ) ) { + } else if( here.has_flag( TFLAG_DEEP_WATER, pos() ) ) { practice( skill_swimming, 1 ); // Same as above, except no head/eyes/mouth drench( 100, { { @@ -770,7 +773,7 @@ void player::pause() bodypart_str_id( "hand_r" ) } }, true ); - } else if( g->m.has_flag( "SWIMMABLE", pos() ) ) { + } else if( here.has_flag( "SWIMMABLE", pos() ) ) { drench( 40, { { bodypart_str_id( "foot_l" ), bodypart_str_id( "foot_r" ), bodypart_str_id( "leg_l" ), bodypart_str_id( "leg_r" ) } }, false ); } @@ -796,7 +799,7 @@ void player::pause() } // Don't drop on the ground when the ground is on fire - if( total_left > 1_minutes && !is_dangerous_fields( g->m.field_at( pos() ) ) ) { + if( total_left > 1_minutes && !is_dangerous_fields( here.field_at( pos() ) ) ) { add_effect( effect_downed, 2_turns, num_bp, false, 0, true ); add_msg_player_or_npc( m_warning, _( "You roll on the ground, trying to smother the fire!" ), @@ -807,7 +810,39 @@ void player::pause() _( " attempts to put out the fire on them!" ) ); } } + // put pressure on bleeding wound, prioritizing most severe bleeding + if( !is_armed() && has_effect( effect_bleed ) ) { + int most = 0; + bodypart_id bp_id; + for( const body_part bp : all_body_parts ) { + if( most <= get_effect_int( effect_bleed, bp ) ) { + most = get_effect_int( effect_bleed, bp ); + bp_id = convert_bp( bp ); + } + } + effect &e = get_effect( effect_bleed, bp_id->token ); + time_duration penalty = 1_turns * ( encumb( bodypart_id( "hand_r" ) ) + encumb( + bodypart_id( "hand_l" ) ) ); + time_duration benefit = 5_turns + 10_turns * get_skill_level( skill_firstaid ); + if( is_limb_broken( bodypart_id( "arm_l" ) ) || is_limb_broken( bodypart_id( "arm_r" ) ) ) { + add_msg_player_or_npc( m_warning, + _( "Your broken limb significantly hampers your efforts to puting pressure on the bleeding wound!" ), + _( "'s broken limb significantly hampers efforts of putting pressure on the bleeding wound!" ) ); + e.mod_duration( -1_turns ); + } else if( benefit <= penalty ) { + add_msg_player_or_npc( m_warning, + _( "Your hands are too encumbred to effectivly put pressure on the bleeding wound!" ), + _( "'s hands are too encumbred to effectivly put pressure on the bleeding wound!" ) ); + e.mod_duration( -1_turns ); + } else { + e.mod_duration( - ( benefit - penalty ) ); + add_msg_player_or_npc( m_warning, + _( "You attempt to put pressure on the bleeding wound!" ), + _( " attempts to put pressure on the bleeding wound!" ) ); + practice( skill_firstaid, 1 ); + } + } // on-pause effects for martial arts martial_arts_data.ma_onpause_effects( *this ); @@ -818,7 +853,7 @@ void player::pause() } if( in_vehicle && one_in( 8 ) ) { - VehicleList vehs = g->m.get_vehicles(); + VehicleList vehs = here.get_vehicles(); vehicle *veh = nullptr; for( auto &v : vehs ) { veh = v.v; @@ -844,17 +879,16 @@ void player::search_surroundings() if( controlling_vehicle ) { return; } + map &here = get_map(); // Search for traps in a larger area than before because this is the only // way we can "find" traps that aren't marked as visible. // Detection formula takes care of likelihood of seeing within this range. - for( const tripoint &tp : g->m.points_in_radius( pos(), 5 ) ) { - const trap &tr = g->m.tr_at( tp ); + for( const tripoint &tp : here.points_in_radius( pos(), 5 ) ) { + const trap &tr = here.tr_at( tp ); if( tr.is_null() || tp == pos() ) { continue; } - if( has_active_bionic( bio_ground_sonar ) && !knows_trap( tp ) && - ( tr.loadid == tr_beartrap_buried || - tr.loadid == tr_landmine_buried || tr.loadid == tr_sinkhole ) ) { + if( has_active_bionic( bio_ground_sonar ) && !knows_trap( tp ) && tr.detected_by_ground_sonar() ) { const std::string direction = direction_name( direction_from( pos(), tp ) ); add_msg_if_player( m_warning, _( "Your ground sonar detected a %1$s to the %2$s!" ), tr.name(), direction ); @@ -863,13 +897,13 @@ void player::search_surroundings() if( !sees( tp ) ) { continue; } - if( tr.is_always_invisible() || tr.can_see( tp, *this ) ) { + if( tr.can_see( tp, *this ) ) { // Already seen, or can never be seen continue; } // Chance to detect traps we haven't yet seen. if( tr.detect_trap( tp, *this ) ) { - if( tr.get_visibility() > 0 ) { + if( !tr.is_trivial_to_spot() ) { // Only bug player about traps that aren't trivial to spot. const std::string direction = direction_name( direction_from( pos(), tp ) ); @@ -929,7 +963,7 @@ void player::on_hit( Creature *source, bodypart_id bp_hit, return; } - bool u_see = g->u.sees( *this ); + bool u_see = get_player_character().sees( *this ); if( has_active_bionic( bionic_id( "bio_ods" ) ) && get_power_level() > 5_kJ ) { if( is_player() ) { add_msg( m_good, _( "Your offensive defense system shocks %s in mid-attack!" ), @@ -1035,12 +1069,6 @@ int player::get_lift_assist() const return result; } -int player::get_num_crafting_helpers( int max ) const -{ - std::vector helpers = get_crafting_helpers(); - return std::min( max, static_cast( helpers.size() ) ); -} - bool player::immune_to( const bodypart_id &bp, damage_unit dam ) const { if( has_trait( trait_DEBUG_NODMG ) || is_immune_damage( dam.type ) ) { @@ -1050,7 +1078,7 @@ bool player::immune_to( const bodypart_id &bp, damage_unit dam ) const passive_absorb_hit( bp, dam ); for( const item &cloth : worn ) { - if( cloth.get_coverage() == 100 && cloth.covers( bp ) ) { + if( cloth.get_coverage( bp ) == 100 && cloth.covers( bp ) ) { cloth.mitigate_damage( dam ); } } @@ -1119,8 +1147,9 @@ float player::fall_damage_mod() const /** @EFFECT_DODGE decreases damage from falling */ float dex_dodge = dex_cur / 2.0 + get_skill_level( skill_dodge ); // Penalize for wearing heavy stuff - const float average_leg_encumb = ( encumb( bp_leg_l ) + encumb( bp_leg_r ) ) / 2.0; - dex_dodge -= ( average_leg_encumb + encumb( bp_torso ) ) / 10; + const float average_leg_encumb = ( encumb( bodypart_id( "leg_l" ) ) + encumb( + bodypart_id( "leg_r" ) ) ) / 2.0; + dex_dodge -= ( average_leg_encumb + encumb( bodypart_id( "torso" ) ) ) / 10; // But prevent it from increasing damage dex_dodge = std::max( 0.0f, dex_dodge ); // 100% damage at 0, 75% at 10, 50% at 20 and so on @@ -1160,6 +1189,7 @@ int player::impact( const int force, const tripoint &p ) const bool slam = p != pos(); std::string target_name = "a swarm of bugs"; Creature *critter = g->critter_at( p ); + map &here = get_map(); if( critter != this && critter != nullptr ) { target_name = critter->disp_name(); // Slamming into creatures and NPCs @@ -1168,7 +1198,7 @@ int player::impact( const int force, const tripoint &p ) // TODO: Modify based on something? mod = 1.0f; effective_force = force; - } else if( const optional_vpart_position vp = g->m.veh_at( p ) ) { + } else if( const optional_vpart_position vp = here.veh_at( p ) ) { // Slamming into vehicles // TODO: Integrate it with vehicle collision function somehow target_name = vp->vehicle().disp_name(); @@ -1186,20 +1216,20 @@ int player::impact( const int force, const tripoint &p ) } } else { // Slamming into terrain/furniture - target_name = g->m.disp_name( p ); - int hard_ground = g->m.has_flag( TFLAG_DIGGABLE, p ) ? 0 : 3; + target_name = here.disp_name( p ); + int hard_ground = here.has_flag( TFLAG_DIGGABLE, p ) ? 0 : 3; armor_eff = 0.25f; // Not much // Get cut by stuff // This isn't impalement on metal wreckage, more like flying through a closed window - cut = g->m.has_flag( TFLAG_SHARP, p ) ? 5 : 0; + cut = here.has_flag( TFLAG_SHARP, p ) ? 5 : 0; effective_force = force + hard_ground; mod = slam ? 1.0f : fall_damage_mod(); - if( g->m.has_furn( p ) ) { + if( here.has_furn( p ) ) { // TODO: Make furniture matter - } else if( g->m.has_flag( TFLAG_SWIMMABLE, p ) ) { + } else if( here.has_flag( TFLAG_SWIMMABLE, p ) ) { const int swim_skill = get_skill_level( skill_swimming ); effective_force /= 4.0f + 0.1f * swim_skill; - if( g->m.has_flag( TFLAG_DEEP_WATER, p ) ) { + if( here.has_flag( TFLAG_DEEP_WATER, p ) ) { effective_force /= 1.5f; mod /= 1.0f + ( 0.1f * swim_skill ); } @@ -1238,8 +1268,7 @@ int player::impact( const int force, const tripoint &p ) int total_dealt = 0; if( mod * effective_force >= 5 ) { - for( int i = 0; i < num_hp_parts; i++ ) { - const bodypart_id bp = convert_bp( hp_to_bp( static_cast( i ) ) ).id(); + for( const bodypart_id &bp : get_all_body_parts( true ) ) { const int bash = effective_force * rng( 60, 100 ) / 100; damage_instance di; di.add_damage( DT_BASH, bash, 0, armor_eff, mod ); @@ -1315,20 +1344,21 @@ void player::knock_back_to( const tripoint &to ) return; } + map &here = get_map(); // If we're still in the function at this point, we're actually moving a tile! - if( g->m.has_flag( "LIQUID", to ) && g->m.has_flag( TFLAG_DEEP_WATER, to ) ) { + if( here.has_flag( "LIQUID", to ) && here.has_flag( TFLAG_DEEP_WATER, to ) ) { if( !is_npc() ) { - avatar_action::swim( g->m, g->u, to ); + avatar_action::swim( here, get_avatar(), to ); } // TODO: NPCs can't swim! - } else if( g->m.impassable( to ) ) { // Wait, it's a wall + } else if( here.impassable( to ) ) { // Wait, it's a wall // It's some kind of wall. // TODO: who knocked us back? Maybe that creature should be the source of the damage? apply_damage( nullptr, bodypart_id( "torso" ), 3 ); add_effect( effect_stunned, 2_turns ); add_msg_player_or_npc( _( "You bounce off a %s!" ), _( " bounces off a %s!" ), - g->m.obstacle_name( to ) ); + here.obstacle_name( to ) ); } else { // It's no wall setpos( to ); @@ -1787,29 +1817,20 @@ void player::process_items() // Active item processing done, now we're recharging. item *cloak = nullptr; item *power_armor = nullptr; - std::vector active_worn_items; - bool weapon_active = weapon.has_flag( "USE_UPS" ) && - weapon.charges < weapon.type->maximum_charges(); - std::vector active_held_items; int ch_UPS = 0; - for( size_t index = 0; index < inv.size(); index++ ) { - item &it = inv.find_item( index ); - itype_id identifier = it.type->get_id(); + const auto inv_is_ups = items_with( []( const item & itm ) { + return itm.has_flag( "IS_UPS" ); + } ); + for( auto &it : inv_is_ups ) { + itype_id identifier = it->type->get_id(); if( identifier == itype_UPS_off ) { - ch_UPS += it.ammo_remaining(); + ch_UPS += it->ammo_remaining(); } else if( identifier == itype_adv_UPS_off ) { - ch_UPS += it.ammo_remaining() / 0.6; - } - if( it.has_flag( "USE_UPS" ) && it.charges < it.type->maximum_charges() ) { - active_held_items.push_back( index ); + ch_UPS += it->ammo_remaining() / 0.6; } } bool update_required = get_check_encumbrance(); for( item &w : worn ) { - if( w.has_flag( "USE_UPS" ) && - w.charges < w.type->maximum_charges() ) { - active_worn_items.push_back( &w ); - } if( w.active ) { if( cloak == nullptr && w.has_flag( "ACTIVE_CLOAKING" ) ) { cloak = &w; @@ -1832,7 +1853,7 @@ void player::process_items() w.encumbrance_update_ = false; } if( update_required ) { - reset_encumbrance(); + calc_encumbrance(); } if( has_active_bionic( bionic_id( "bio_ups" ) ) ) { ch_UPS += units::to_kilojoule( get_power_level() ); @@ -1876,46 +1897,22 @@ void player::process_items() // Load all items that use the UPS to their minimal functional charge, // The tool is not really useful if its charges are below charges_to_use - for( size_t index : active_held_items ) { - if( ch_UPS_used >= ch_UPS ) { - break; - } - item &it = inv.find_item( index ); - ch_UPS_used++; - it.charges++; - } - if( weapon_active && ch_UPS_used < ch_UPS ) { - ch_UPS_used++; - weapon.charges++; - } - for( item *worn_item : active_worn_items ) { - if( ch_UPS_used >= ch_UPS ) { + const auto inv_use_ups = items_with( []( const item & itm ) { + return itm.has_flag( "USE_UPS" ); + } ); + for( auto &it : inv_use_ups ) { + if( ch_UPS_used >= ch_UPS || + it->ammo_remaining() >= it->ammo_capacity( ammotype( "battery" ) ) ) { break; } ch_UPS_used++; - worn_item->charges++; + it->ammo_set( itype_battery, it->ammo_remaining() + 1 ); } if( ch_UPS_used > 0 ) { use_charges( itype_UPS, ch_UPS_used ); } } -item player::reduce_charges( int position, int quantity ) -{ - item &it = i_at( position ); - if( it.is_null() ) { - debugmsg( "invalid item position %d for reduce_charges", position ); - return item(); - } - if( it.charges <= quantity ) { - return i_rem( position ); - } - it.mod_charges( -quantity ); - item tmp( it ); - tmp.charges = quantity; - return tmp; -} - item player::reduce_charges( item *it, int quantity ) { if( !has_item( *it ) ) { @@ -2037,13 +2034,14 @@ item::reload_option player::select_ammo( const item &base, std::transform( opts.begin(), opts.end(), std::back_inserter( where ), [this]( const item::reload_option & e ) { bool is_ammo_container = e.ammo->is_ammo_container(); + Character &player_character = get_player_character(); if( is_ammo_container || e.ammo->is_container() ) { if( is_ammo_container && is_worn( *e.ammo ) ) { return e.ammo->type_name(); } - return string_format( _( "%s, %s" ), e.ammo->type_name(), e.ammo.describe( &g->u ) ); + return string_format( _( "%s, %s" ), e.ammo->type_name(), e.ammo.describe( &player_character ) ); } - return e.ammo.describe( &g->u ); + return e.ammo.describe( &player_character ); } ); // Pads elements to match longest member and return length @@ -2309,59 +2307,6 @@ item::reload_option player::select_ammo( const item &base, bool prompt, bool emp return select_ammo( base, std::move( ammo_list ) ); } -ret_val player::can_wield( const item &it ) const -{ - if( it.made_of_from_type( phase_id::LIQUID ) ) { - return ret_val::make_failure( _( "Can't wield spilt liquids." ) ); - } - - if( get_working_arm_count() <= 0 ) { - return ret_val::make_failure( - _( "You need at least one arm to even consider wielding something." ) ); - } - - if( is_armed() && weapon.has_flag( "NO_UNWIELD" ) ) { - return ret_val::make_failure( _( "The %s is preventing you from wielding the %s." ), - weapname(), it.tname() ); - } - - if( it.is_two_handed( *this ) && ( !has_two_arms() || worn_with_flag( "RESTRICT_HANDS" ) ) ) { - if( worn_with_flag( "RESTRICT_HANDS" ) ) { - return ret_val::make_failure( - _( "Something you are wearing hinders the use of both hands." ) ); - } else if( it.has_flag( "ALWAYS_TWOHAND" ) ) { - return ret_val::make_failure( _( "The %s can't be wielded with only one arm." ), - it.tname() ); - } else { - return ret_val::make_failure( _( "You are too weak to wield %s with only one arm." ), - it.tname() ); - } - } - - return ret_val::make_success(); -} - -bool player::unwield() -{ - if( weapon.is_null() ) { - return true; - } - - if( !can_unwield( weapon ).success() ) { - return false; - } - - const std::string query = string_format( _( "Stop wielding %s?" ), weapon.tname() ); - - if( !dispose_item( item_location( *this, &weapon ), query ) ) { - return false; - } - - inv.unsort(); - - return true; -} - // ids of martial art styles that are available with the bio_cqb bionic. static const std::vector bio_cqb_styles{ { matype_id{ "style_aikido" }, @@ -2791,7 +2736,7 @@ bool player::takeoff( item &it, std::list *res ) mod_moves( -250 ); recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); return true; } @@ -2831,7 +2776,7 @@ bool player::add_or_drop_with_msg( item &it, const bool /*unloading*/, const ite return true; } -bool player::unload( item_location &loc ) +bool player::unload( item_location &loc, bool bypass_activity ) { item &it = *loc; // Unload a container consuming moves per item successfully removed @@ -2917,23 +2862,21 @@ bool player::unload( item_location &loc ) } ); if( target->is_magazine() ) { - player_activity unload_mag_act( activity_id( "ACT_UNLOAD_MAG" ) ); - assign_activity( unload_mag_act ); - activity.targets.emplace_back( loc ); - - // Calculate the time to remove the contained ammo (consuming half as much time as required to load the magazine) - int mv = 0; - for( const item *content : target->contents.all_items_top() ) { - mv += this->item_reload_cost( it, *content, content->charges ) / 2; - } - activity.moves_left += mv; - - // I think this means if unload is not done on ammo-belt, it takes as long as it takes to reload a mag. - if( !it.is_ammo_belt() ) { - activity.moves_left += mv; + item_location targloc = item_location( loc, target ); + if( bypass_activity ) { + unload_mag_activity_actor::unload( *this, targloc ); + } else { + int mv = 0; + for( const item *content : target->contents.all_items_top() ) { + // We use the same cost for both reloading and unloading + mv += this->item_reload_cost( it, *content, content->charges ); + } + if( it.is_ammo_belt() ) { + // Disassembling ammo belts is easier than assembling them + mv /= 2; + } + assign_activity( player_activity( unload_mag_activity_actor( mv, targloc ) ) ); } - activity.auto_resume = true; - return true; } else if( target->magazine_current() ) { @@ -2950,15 +2893,6 @@ bool player::unload( item_location &loc ) } else if( target->ammo_remaining() ) { int qty = target->ammo_remaining(); - if( target->ammo_current() == itype_plut_cell ) { - if( qty / PLUTONIUM_CHARGES > 0 ) { - add_msg( _( "You recover %i unused plutonium." ), qty / PLUTONIUM_CHARGES ); - } else { - add_msg( m_info, _( "You can't remove partially depleted plutonium!" ) ); - return false; - } - } - // Construct a new ammo item and try to drop it item ammo( target->ammo_current(), calendar::turn, qty ); if( target->is_filthy() ) { @@ -3110,7 +3044,7 @@ bool player::gunmod_remove( item &gun, item &mod ) } item_location loc = item_location( *this, &mod ); - if( mod.ammo_remaining() && !g->unload( loc ) ) { + if( mod.ammo_remaining() && !unload( loc, true ) ) { return false; } @@ -3342,98 +3276,13 @@ int player::book_fun_for( const item &book, const player &p ) const return fun_bonus; } -bool player::studied_all_recipes( const itype &book ) const -{ - if( !book.book ) { - return true; - } - for( auto &elem : book.book->recipes ) { - if( !knows_recipe( elem.recipe ) ) { - return false; - } - } - return true; -} - -const recipe_subset &player::get_learned_recipes() const -{ - // Cache validity check - if( *_skills != *valid_autolearn_skills ) { - for( const auto &r : recipe_dict.all_autolearn() ) { - if( meets_skill_requirements( r->autolearn_requirements ) ) { - learned_recipes->include( r ); - } - } - *valid_autolearn_skills = *_skills; // Reassign the validity stamp - } - - return *learned_recipes; -} - -recipe_subset player::get_recipes_from_books( const inventory &crafting_inv ) const -{ - recipe_subset res; - - for( const auto &stack : crafting_inv.const_slice() ) { - const item &candidate = stack->front(); - - for( std::pair recipe_entry : - candidate.get_available_recipes( *this ) ) { - res.include( recipe_entry.first, recipe_entry.second ); - } - } - - return res; -} - -std::set player::get_books_for_recipe( const inventory &crafting_inv, - const recipe *r ) const -{ - std::set book_ids; - const int skill_level = get_skill_level( r->skill_used ); - for( auto &book_lvl : r->booksets ) { - itype_id book_id = book_lvl.first; - int required_skill_level = book_lvl.second; - // NPCs don't need to identify books - if( !has_identified( book_id ) ) { - continue; - } - - if( skill_level >= required_skill_level && crafting_inv.amount_of( book_id ) > 0 ) { - book_ids.insert( book_id ); - } - } - return book_ids; -} - -recipe_subset player::get_available_recipes( const inventory &crafting_inv, - const std::vector *helpers ) const -{ - recipe_subset res( get_learned_recipes() ); - - res.include( get_recipes_from_books( crafting_inv ) ); - - if( helpers != nullptr ) { - for( npc *np : *helpers ) { - // Directly form the helper's inventory - res.include( get_recipes_from_books( np->inv ) ); - // Being told what to do - res.include_if( np->get_learned_recipes(), [ this ]( const recipe & r ) { - return get_skill_level( r.skill_used ) >= static_cast( r.difficulty * - 0.8f ); // Skilled enough to understand - } ); - } - } - - return res; -} - void player::try_to_sleep( const time_duration &dur ) { - const optional_vpart_position vp = g->m.veh_at( pos() ); - const trap &trap_at_pos = g->m.tr_at( pos() ); - const ter_id ter_at_pos = g->m.ter( pos() ); - const furn_id furn_at_pos = g->m.furn( pos() ); + map &here = get_map(); + const optional_vpart_position vp = here.veh_at( pos() ); + const trap &trap_at_pos = here.tr_at( pos() ); + const ter_id ter_at_pos = here.ter( pos() ); + const furn_id furn_at_pos = here.furn( pos() ); bool plantsleep = false; bool fungaloid_cosplay = false; bool websleep = false; @@ -3458,7 +3307,7 @@ void player::try_to_sleep( const time_duration &dur ) } } else if( has_trait( trait_M_SKIN3 ) ) { fungaloid_cosplay = true; - if( g->m.has_flag_ter_or_furn( "FUNGUS", pos() ) ) { + if( here.has_flag_ter_or_furn( "FUNGUS", pos() ) ) { add_msg_if_player( m_good, _( "Our fibers meld with the ground beneath us. The gills on our neck begin to seed the air with spores as our awareness fades." ) ); } @@ -3472,7 +3321,7 @@ void player::try_to_sleep( const time_duration &dur ) webforce = true; } if( websleep || webforce ) { - int web = g->m.get_field_intensity( pos(), fd_web ); + int web = here.get_field_intensity( pos(), fd_web ); if( !webforce ) { // At this point, it's kinda weird, but surprisingly comfy... if( web >= 3 ) { @@ -3482,7 +3331,7 @@ void player::try_to_sleep( const time_duration &dur ) } else if( web > 0 ) { add_msg_if_player( m_info, _( "You try to sleep, but the webs get in the way. You brush them aside." ) ); - g->m.remove_field( pos(), fd_web ); + here.remove_field( pos(), fd_web ); } } else { // Here, you're just not comfortable outside a nice thick web. @@ -3505,7 +3354,7 @@ void player::try_to_sleep( const time_duration &dur ) add_msg_if_player( m_good, _( "You lay beneath the waves' embrace, gazing up through the water's surface…" ) ); watersleep = true; - } else if( g->m.has_flag_ter( "SWIMMABLE", pos() ) ) { + } else if( here.has_flag_ter( "SWIMMABLE", pos() ) ) { add_msg_if_player( m_good, _( "You settle into the water and begin to drowse…" ) ); watersleep = true; } @@ -3581,7 +3430,7 @@ int player::sleep_spot( const tripoint &p ) const // Mousefolk can sleep just about anywhere. sleepy += 40; } - if( watersleep && g->m.has_flag_ter( "SWIMMABLE", pos() ) ) { + if( watersleep && get_map().has_flag_ter( "SWIMMABLE", pos() ) ) { sleepy += 10; //comfy water! } @@ -3639,176 +3488,6 @@ bool player::can_sleep() return result; } -// Returned values range from 1.0 (unimpeded vision) to 11.0 (totally blind). -// 1.0 is LIGHT_AMBIENT_LIT or brighter -// 4.0 is a dark clear night, barely bright enough for reading and crafting -// 6.0 is LIGHT_AMBIENT_DIM -// 7.3 is LIGHT_AMBIENT_MINIMAL, a dark cloudy night, unlit indoors -// 11.0 is zero light or blindness -float player::fine_detail_vision_mod( const tripoint &p ) const -{ - // PER_SLIME_OK implies you can get enough eyes around the bile - // that you can generally see. There still will be the haze, but - // it's annoying rather than limiting. - if( is_blind() || - ( ( has_effect( effect_boomered ) || has_effect( effect_darkness ) ) && - !has_trait( trait_PER_SLIME_OK ) ) ) { - return 11.0; - } - // Scale linearly as light level approaches LIGHT_AMBIENT_LIT. - // If we're actually a source of light, assume we can direct it where we need it. - // Therefore give a hefty bonus relative to ambient light. - float own_light = std::max( 1.0f, LIGHT_AMBIENT_LIT - active_light() - 2.0f ); - - // Same calculation as above, but with a result 3 lower. - float ambient_light = std::max( 1.0f, - LIGHT_AMBIENT_LIT - g->m.ambient_light_at( p == tripoint_zero ? pos() : p ) + 1.0f ); - - return std::min( own_light, ambient_light ); -} - -void player::practice( const skill_id &id, int amount, int cap, bool suppress_warning ) -{ - SkillLevel &level = get_skill_level_object( id ); - const Skill &skill = id.obj(); - if( !level.can_train() && !in_sleep_state() ) { - // If leveling is disabled, don't train, don't drain focus, don't print anything - // Leaving as a skill method rather than global for possible future skill cap setting - return; - } - - const auto highest_skill = [&]() { - std::pair result( skill_id::NULL_ID(), -1 ); - for( const auto &pair : *_skills ) { - const SkillLevel &lobj = pair.second; - if( lobj.level() > result.second ) { - result = std::make_pair( pair.first, lobj.level() ); - } - } - return result.first; - }; - - const bool isSavant = has_trait( trait_SAVANT ); - const skill_id savantSkill = isSavant ? highest_skill() : skill_id::NULL_ID(); - - amount = adjust_for_focus( amount ); - - if( has_trait( trait_PACIFIST ) && skill.is_combat_skill() ) { - if( !one_in( 3 ) ) { - amount = 0; - } - } - if( has_trait_flag( "PRED2" ) && skill.is_combat_skill() ) { - if( one_in( 3 ) ) { - amount *= 2; - } - } - if( has_trait_flag( "PRED3" ) && skill.is_combat_skill() ) { - amount *= 2; - } - - if( has_trait_flag( "PRED4" ) && skill.is_combat_skill() ) { - amount *= 3; - } - - if( isSavant && id != savantSkill ) { - amount /= 2; - } - - if( amount > 0 && get_skill_level( id ) > cap ) { //blunt grinding cap implementation for crafting - amount = 0; - if( !suppress_warning ) { - handle_skill_warning( id, false ); - } - } - if( amount > 0 && level.isTraining() ) { - int oldLevel = get_skill_level( id ); - get_skill_level_object( id ).train( amount ); - int newLevel = get_skill_level( id ); - std::string skill_name = skill.name(); - if( newLevel > oldLevel ) { - g->events().send( getID(), id, newLevel ); - } - if( is_player() && newLevel > oldLevel ) { - add_msg( m_good, _( "Your skill in %s has increased to %d!" ), skill_name, newLevel ); - } - if( is_player() && newLevel > cap ) { - //inform player immediately that the current recipe can't be used to train further - add_msg( m_info, _( "You feel that %s tasks of this level are becoming trivial." ), - skill_name ); - } - - int chance_to_drop = focus_pool; - focus_pool -= chance_to_drop / 100; - // Apex Predators don't think about much other than killing. - // They don't lose Focus when practicing combat skills. - if( ( rng( 1, 100 ) <= ( chance_to_drop % 100 ) ) && ( !( has_trait_flag( "PRED4" ) && - skill.is_combat_skill() ) ) ) { - focus_pool--; - } - } - - get_skill_level_object( id ).practice(); -} - -void player::handle_skill_warning( const skill_id &id, bool force_warning ) -{ - //remind the player intermittently that no skill gain takes place - if( is_player() && ( force_warning || one_in( 5 ) ) ) { - SkillLevel &level = get_skill_level_object( id ); - - const Skill &skill = id.obj(); - std::string skill_name = skill.name(); - int curLevel = level.level(); - - add_msg( m_info, _( "This task is too simple to train your %s beyond %d." ), - skill_name, curLevel ); - } -} - -int player::exceeds_recipe_requirements( const recipe &rec ) const -{ - return get_all_skills().exceeds_recipe_requirements( rec ); -} - -bool player::has_recipe_requirements( const recipe &rec ) const -{ - return get_all_skills().has_recipe_requirements( rec ); -} - -bool player::can_decomp_learn( const recipe &rec ) const -{ - return !rec.learn_by_disassembly.empty() && - meets_skill_requirements( rec.learn_by_disassembly ); -} - -bool player::knows_recipe( const recipe *rec ) const -{ - return get_learned_recipes().contains( rec ); -} - -int player::has_recipe( const recipe *r, const inventory &crafting_inv, - const std::vector &helpers ) const -{ - if( !r->skill_used ) { - return 0; - } - - if( knows_recipe( r ) ) { - return r->difficulty; - } - - const auto available = get_available_recipes( crafting_inv, &helpers ); - return available.contains( r ) ? available.get_custom_difficulty( r ) : -1; -} - -void player::learn_recipe( const recipe *const rec ) -{ - if( rec->never_learn ) { - return; - } - learned_recipes->include( rec ); -} bool player::has_gun_for_ammo( const ammotype &at ) const { @@ -3829,36 +3508,6 @@ bool player::has_magazine_for_ammo( const ammotype &at ) const } ); } -std::string player::weapname() const -{ - if( weapon.is_gun() ) { - std::string gunmode; - // only required for empty mags and empty guns - std::string mag_ammo; - if( weapon.gun_all_modes().size() > 1 ) { - gunmode = weapon.gun_current_mode().tname(); - } - - if( weapon.ammo_remaining() == 0 ) { - if( weapon.magazine_current() != nullptr ) { - const item *mag = weapon.magazine_current(); - mag_ammo = string_format( " (0/%d)", - mag->ammo_capacity( item( mag->ammo_default() ).ammo_type() ) ); - } else { - mag_ammo = _( " (empty)" ); - } - } - - return string_format( "%s%s%s", gunmode, weapon.display_name(), mag_ammo ); - - } else if( !is_armed() ) { - return _( "fists" ); - - } else { - return weapon.tname(); - } -} - bool player::wield_contents( item &container, item *internal_item, bool penalties, int base_cost ) { // if index not specified and container has multiple items then ask the player to choose one @@ -3935,7 +3584,7 @@ void player::store( item &container, item &put, bool penalties, int base_cost, { moves -= item_store_cost( put, container, penalties, base_cost ); container.put_in( i_rem( &put ), pk_type ); - reset_encumbrance(); + calc_encumbrance(); } nc_color encumb_color( int level ) @@ -3962,8 +3611,8 @@ float player::get_melee() const bool player::uncanny_dodge() { - bool is_u = this == &g->u; - bool seen = g->u.sees( *this ); + bool is_u = is_avatar();; + bool seen = get_player_character().sees( *this ); if( this->get_power_level() < 74_kJ || !this->has_active_bionic( bio_uncanny_dodge ) ) { return false; } @@ -3990,11 +3639,12 @@ bool player::uncanny_dodge() int player::climbing_cost( const tripoint &from, const tripoint &to ) const { - if( !g->m.valid_move( from, to, false, true ) ) { + map &here = get_map(); + if( !here.valid_move( from, to, false, true ) ) { return 0; } - const int diff = g->m.climb_difficulty( from ); + const int diff = here.climb_difficulty( from ); if( diff > 5 ) { return 0; @@ -4021,7 +3671,7 @@ void player::environmental_revert_effect() set_rad( 0 ); recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); } //message related stuff diff --git a/src/player.h b/src/player.h index 8816647beb6bf..001a8a0ec2a93 100644 --- a/src/player.h +++ b/src/player.h @@ -52,8 +52,6 @@ struct requirement_data; enum class recipe_filter_flags : int; struct itype; -static const std::string DEFAULT_HOTKEYS( "1234567890abcdefghijklmnopqrstuvwxyz" ); - class recipe_subset; enum action_id : int; @@ -373,13 +371,6 @@ class player : public Character */ ret_val can_takeoff( const item &it, const std::list *res = nullptr ); - /** - * Check player capable of wielding an item. - * @param it Thing to be wielded - */ - ret_val can_wield( const item &it ) const; - - bool unwield(); /** * Attempt to mend an item (fix any current faults) @@ -412,7 +403,11 @@ class player : public Character */ bool add_or_drop_with_msg( item &it, bool unloading = false, const item *avoid = nullptr ); - bool unload( item_location &loc ); + /** + * Unload item. + * @param bypass_activity If item requires an activity for its unloading, unload item immediately instead. + */ + bool unload( item_location &loc, bool bypass_activity = false ); /** * Try to wield a contained item consuming moves proportional to weapon skill and volume. @@ -458,8 +453,6 @@ class player : public Character void toolmod_add( item_location tool, item_location mod ); bool fun_to_read( const item &book ) const; - /** Note that we've read a book at least once. **/ - virtual bool has_identified( const itype_id &item_id ) const = 0; /** Handles sleep attempts by the player, starts ACT_TRY_SLEEP activity */ void try_to_sleep( const time_duration &dur ); @@ -474,13 +467,6 @@ class player : public Character bool bio_soporific_powered_at_last_sleep_check; public: - /** Returns a value from 1.0 to 5.0 that acts as a multiplier - * for the time taken to perform tasks that require detail vision, - * above 4.0 means these activities cannot be performed. - * takes pos as a parameter so that remote spots can be judged - * if they will potentially have enough light when player gets there */ - float fine_detail_vision_mod( const tripoint &p = tripoint_zero ) const; - //returns true if the warning is now beyond final and results in hostility. bool add_faction_warning( const faction_id &id ); int current_warnings_fac( const faction_id &id ); @@ -490,33 +476,19 @@ class player : public Character int kcal_speed_penalty() const; /** Returns the penalty to speed from thirst */ static int thirst_speed_penalty( int thirst ); - /** This handles giving xp for a skill */ - void practice( const skill_id &id, int amount, int cap = 99, bool suppress_warning = false ); - /** This handles warning the player that there current activity will not give them xp */ - void handle_skill_warning( const skill_id &id, bool force_warning = false ); void on_worn_item_transform( const item &old_it, const item &new_it ); - /** Get the formatted name of the currently wielded item (if any) with current gun mode (if gun) */ - std::string weapname() const; - void process_items(); /** - * Remove charges from a specific item (given by its item position). + * Remove charges from a specific item. * The item must exist and it must be counted by charges. - * @param position Item position of the item. + * @param it A pointer to the item, it *must* exist. * @param quantity The number of charges to remove, must not be larger than * the current charges of the item. * @return An item that contains the removed charges, it's effectively a * copy of the item with the proper charges. */ - item reduce_charges( int position, int quantity ); - /** - * Remove charges from a specific item (given by a pointer to it). - * Otherwise identical to @ref reduce_charges(int,int) - * @param it A pointer to the item, it *must* exist. - * @param quantity How many charges to remove - */ item reduce_charges( item *it, int quantity ); /** @@ -532,150 +504,8 @@ class player : public Character bool has_gun_for_ammo( const ammotype &at ) const; bool has_magazine_for_ammo( const ammotype &at ) const; - // Checks crafting inventory for books providing the requested recipe. - // Then checks nearby NPCs who could provide it too. - // Returns -1 to indicate recipe not found, otherwise difficulty to learn. - int has_recipe( const recipe *r, const inventory &crafting_inv, - const std::vector &helpers ) const; - bool knows_recipe( const recipe *rec ) const; - void learn_recipe( const recipe *rec ); - int exceeds_recipe_requirements( const recipe &rec ) const; - bool has_recipe_requirements( const recipe &rec ) const; - bool can_decomp_learn( const recipe &rec ) const; - - bool studied_all_recipes( const itype &book ) const; - - /** Returns all known recipes. */ - const recipe_subset &get_learned_recipes() const; - /** Returns all recipes that are known from the books (either in inventory or nearby). */ - recipe_subset get_recipes_from_books( const inventory &crafting_inv ) const; - /** - * Returns all available recipes (from books and npc companions) - * @param crafting_inv Current available items to craft - * @param helpers List of NPCs that could help with crafting. - */ - recipe_subset get_available_recipes( const inventory &crafting_inv, - const std::vector *helpers = nullptr ) const; - /** - * Returns the set of book types in crafting_inv that provide the - * given recipe. - * @param crafting_inv Current available items that may contain readable books - * @param r Recipe to search for in the available books - */ - std::set get_books_for_recipe( const inventory &crafting_inv, - const recipe *r ) const; - - // crafting.cpp - float morale_crafting_speed_multiplier( const recipe &rec ) const; - float lighting_craft_speed_multiplier( const recipe &rec ) const; - float crafting_speed_multiplier( const recipe &rec, bool in_progress = false ) const; - /** For use with in progress crafts */ - float crafting_speed_multiplier( const item &craft, const tripoint &loc ) const; - int available_assistant_count( const recipe &rec ) const; - /** - * Time to craft not including speed multiplier - */ - int base_time_to_craft( const recipe &rec, int batch_size = 1 ) const; - /** - * Expected time to craft a recipe, with assumption that multipliers stay constant. - */ - int expected_time_to_craft( const recipe &rec, int batch_size = 1, bool in_progress = false ) const; - std::vector get_eligible_containers_for_crafting() const; - bool check_eligible_containers_for_crafting( const recipe &rec, int batch_size = 1 ) const; - bool can_make( const recipe *r, int batch_size = 1 ); // have components? - /** - * Returns true if the player can start crafting the recipe with the given batch size - * The player is not required to have enough tool charges to finish crafting, only to - * complete the first step (total / 20 + total % 20 charges) - */ - bool can_start_craft( const recipe *rec, recipe_filter_flags, int batch_size = 1 ); - bool making_would_work( const recipe_id &id_to_make, int batch_size ); - - /** - * Start various types of crafts - * @param loc the location of the workbench. tripoint_zero indicates crafting from inventory. - */ - void craft( const tripoint &loc = tripoint_zero ); - void recraft( const tripoint &loc = tripoint_zero ); - void long_craft( const tripoint &loc = tripoint_zero ); - void make_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); - void make_all_craft( const recipe_id &id, int batch_size, const tripoint &loc = tripoint_zero ); - /** consume components and create an active, in progress craft containing them */ - void start_craft( craft_command &command, const tripoint &loc ); - /** - * Calculate a value representing the success of the player at crafting the given recipe, - * taking player skill, recipe difficulty, npc helpers, and player mutations into account. - * @param making the recipe for which to calculate - * @return a value >= 0.0 with >= 1.0 representing unequivocal success - */ - double crafting_success_roll( const recipe &making ) const; - void complete_craft( item &craft, const tripoint &loc = tripoint_zero ); - /** - * Check if the player meets the requirements to continue the in progress craft and if - * unable to continue print messages explaining the reason. - * If the craft is missing components due to messing up, prompt to consume new ones to - * allow the craft to be continued. - * @param craft the currently in progress craft - * @return if the craft can be continued - */ - bool can_continue_craft( item &craft ); - /** Returns nearby NPCs ready and willing to help with crafting. */ - std::vector get_crafting_helpers() const; - int get_num_crafting_helpers( int max ) const; - /** - * Handle skill gain for player and followers during crafting - * @param craft the currently in progress craft - * @param multiplier what factor to multiply the base skill gain by. This is used to apply - * multiple steps of incremental skill gain simultaneously if needed. - */ - void craft_skill_gain( const item &craft, const int &multiplier ); - /** - * Check if the player can disassemble an item using the current crafting inventory - * @param obj Object to check for disassembly - * @param inv current crafting inventory - */ - ret_val can_disassemble( const item &obj, const inventory &inv ) const; - - bool disassemble(); - bool disassemble( item_location target, bool interactive = true ); - void disassemble_all( bool one_pass ); // Disassemble all items on the tile - void complete_disassemble(); - void complete_disassemble( item_location &target, const recipe &dis ); - - const requirement_data *select_requirements( - const std::vector &, int batch, const inventory &, - const std::function &filter ) const; - comp_selection - select_item_component( const std::vector &components, - int batch, inventory &map_inv, bool can_cancel = false, - const std::function &filter = return_true, bool player_inv = true ); - std::list consume_items( const comp_selection &is, int batch, - const std::function &filter = return_true ); - std::list consume_items( map &m, const comp_selection &is, int batch, - const std::function &filter = return_true, - const tripoint &origin = tripoint_zero, int radius = PICKUP_RANGE ); - std::list consume_items( const std::vector &components, int batch = 1, - const std::function &filter = return_true ); - comp_selection - select_tool_component( const std::vector &tools, int batch, inventory &map_inv, - const std::string &hotkeys = DEFAULT_HOTKEYS, - bool can_cancel = false, bool player_inv = true, - std::function charges_required_modifier = []( int i ) { - return i; - } ); - /** Consume tools for the next multiplier * 5% progress of the craft */ - bool craft_consume_tools( item &craft, int mulitplier, bool start_craft ); - void consume_tools( const comp_selection &tool, int batch ); - void consume_tools( map &m, const comp_selection &tool, int batch, - const tripoint &origin = tripoint_zero, int radius = PICKUP_RANGE, - basecamp *bcp = nullptr ); - void consume_tools( const std::vector &tools, int batch = 1, - const std::string &hotkeys = DEFAULT_HOTKEYS ); - // ---------------VALUES----------------- tripoint view_offset; - // Is currently in control of a vehicle - bool controlling_vehicle; // Relative direction of a grab, add to posx, posy to get the coordinates of the grabbed thing. tripoint grab_point; int volume; @@ -696,14 +526,6 @@ class player : public Character vproto_id starting_vehicle; std::vector starting_pets; - void make_craft_with_command( const recipe_id &id_to_make, int batch_size, bool is_long = false, - const tripoint &loc = tripoint_zero ); - pimpl last_craft; - - recipe_id lastrecipe; - int last_batch; - itype_id lastconsumed; //used in crafting.cpp and construction.cpp - std::set follower_ids; void mod_stat( const std::string &stat, float modifier ) override; @@ -757,13 +579,5 @@ class player : public Character /** warnings from a faction about bad behavior */ std::map> warning_record; - protected: - - /** Subset of learned recipes. Needs to be mutable for lazy initialization. */ - mutable pimpl learned_recipes; - - /** Stamp of skills. @ref learned_recipes are valid only with this set of skills. */ - mutable decltype( _skills ) valid_autolearn_skills; }; - #endif // CATA_SRC_PLAYER_H diff --git a/src/player_activity.cpp b/src/player_activity.cpp index d23501835c0fd..913aef93cde31 100644 --- a/src/player_activity.cpp +++ b/src/player_activity.cpp @@ -76,6 +76,13 @@ void player_activity::set_to_null() sfx::end_activity_sounds(); // kill activity sounds when activity is nullified } +void player_activity::sychronize_type_with_actor() +{ + if( actor && type != activity_id::NULL_ID() ) { + type = actor->get_type(); + } +} + bool player_activity::rooted() const { return type->rooted(); @@ -177,13 +184,17 @@ void player_activity::start_or_resume( Character &who, bool resuming ) if( actor && !resuming ) { actor->start( *this, who ); } - if( rooted() ) { + if( !type.is_null() && rooted() ) { who.rooted_message(); } + // last, as start function may have changed the type + sychronize_type_with_actor(); } void player_activity::do_turn( player &p ) { + // first to ensure sync with actor + sychronize_type_with_actor(); // Should happen before activity or it may fail du to 0 moves if( *this && type->will_refuel_fires() ) { try_fuel_fire( *this, p ); @@ -241,6 +252,7 @@ void player_activity::do_turn( player &p ) const bool travel_activity = id() == ACT_TRAVELLING; // This might finish the activity (set it to null) if( actor ) { + p.increase_activity_level( actor->get_type()->exertion_level() ); actor->do_turn( *this, p ); } else { // Use the legacy turn function @@ -254,7 +266,13 @@ void player_activity::do_turn( player &p ) // to simulate that the next step will surely use up some stamina anyway // this is to ensure that resting will occur when traveling overburdened const int adjusted_stamina = travel_activity ? p.get_stamina() - 1 : p.get_stamina(); - if( adjusted_stamina < previous_stamina && p.get_stamina() < p.get_stamina_max() / 3 ) { + activity_id act_id = actor ? actor->get_type() : type; + bool excluded = act_id == activity_id( "ACT_WORKOUT_HARD" ) || + act_id == activity_id( "ACT_WORKOUT_ACTIVE" ) || + act_id == activity_id( "ACT_WORKOUT_MODERATE" ) || + act_id == activity_id( "ACT_WORKOUT_LIGHT" ); + if( !excluded && adjusted_stamina < previous_stamina && + p.get_stamina() < p.get_stamina_max() / 3 ) { if( one_in( 50 ) ) { p.add_msg_if_player( _( "You pause for a moment to catch your breath." ) ); } @@ -280,6 +298,7 @@ void player_activity::do_turn( player &p ) set_to_null(); } } + p.reset_activity_level(); } if( !*this ) { // Make sure data of previous activity is cleared diff --git a/src/player_activity.h b/src/player_activity.h index 419d8c66e4b88..39b14c00ed80e 100644 --- a/src/player_activity.h +++ b/src/player_activity.h @@ -93,6 +93,11 @@ class player_activity /** This replaces the former usage `act.type = ACT_NULL` */ void set_to_null(); + // This makes player_activity's activity type inherit activity_actor's activity type, + // in order to synchronize both, due to possible variablility of actor's activity type + // allowed via override of activity_actor::get_type() + void sychronize_type_with_actor(); + const activity_id &id() const { return type; } diff --git a/src/player_display.cpp b/src/player_display.cpp index e3557d751c564..725c0bfa6f6e1 100644 --- a/src/player_display.cpp +++ b/src/player_display.cpp @@ -20,6 +20,7 @@ #include "options.h" #include "output.h" #include "profession.h" +#include "proficiency.h" #include "skill.h" #include "string_formatter.h" #include "string_id.h" @@ -38,6 +39,7 @@ static const std::string title_SPEED = translate_marker( "SPEED" ); static const std::string title_SKILLS = translate_marker( "SKILLS" ); static const std::string title_BIONICS = translate_marker( "BIONICS" ); static const std::string title_TRAITS = translate_marker( "TRAITS" ); +static const std::string title_PROFICIENCIES = translate_marker( "PROFICIENCIES" ); // use this instead of having to type out 26 spaces like before static const std::string header_spaces( 26, ' ' ); @@ -48,35 +50,37 @@ static int temperature_print_rescaling( int temp ) return ( temp / 100.0 ) * 2 - 100; } -static body_part other_part( body_part bp ) +static bodypart_id other_part( const bodypart_id &bp ) { - return static_cast( bp_aiOther[bp] ); + return bp->opposite_part; } -static bool should_combine_bps( const player &p, body_part l, body_part r, +static bool should_combine_bps( const player &p, const bodypart_id &l, const bodypart_id &r, const item *selected_clothing ) { - const auto enc_data = p.get_encumbrance(); + const encumbrance_data enc_l = p.get_part_encumbrance_data( l ); + const encumbrance_data enc_r = p.get_part_encumbrance_data( r ); + return l != r && // are different parts l == other_part( r ) && r == other_part( l ) && // are complementary parts // same encumberance & temperature - enc_data[l] == enc_data[r] && - temperature_print_rescaling( p.temp_conv[l] ) == temperature_print_rescaling( p.temp_conv[r] ) && + enc_l == enc_r && + temperature_print_rescaling( p.temp_conv[l->token] ) == temperature_print_rescaling( + p.temp_conv[r->token] ) && // selected_clothing covers both or neither parts ( !selected_clothing || - ( selected_clothing->covers( convert_bp( l ).id() ) == selected_clothing->covers( convert_bp( - r ).id() ) ) ); + ( selected_clothing->covers( l ) == selected_clothing->covers( r ) ) ); } -static std::vector> list_and_combine_bps( const player &p, +static std::vector> list_and_combine_bps( const player &p, const item *selected_clothing ) { // bool represents whether the part has been combined with its other half - std::vector> bps; - for( auto bp : all_body_parts ) { + std::vector> bps; + for( const bodypart_id &bp : p.get_all_body_parts() ) { // assuming that a body part has at most one other half if( other_part( other_part( bp ) ) != bp ) { - debugmsg( "Bodypart %d has more than one other half!", bp ); + debugmsg( "Bodypart %d has more than one other half!", bp.id().c_str() ); } if( should_combine_bps( p, bp, other_part( bp ), selected_clothing ) ) { if( bp < other_part( bp ) ) { @@ -94,7 +98,7 @@ void player::print_encumbrance( const catacurses::window &win, const int line, const item *const selected_clothing ) const { // bool represents whether the part has been combined with its other half - const std::vector> bps = list_and_combine_bps( *this, + const std::vector> bps = list_and_combine_bps( *this, selected_clothing ); // width/height excluding title & scrollbar @@ -109,7 +113,6 @@ void player::print_encumbrance( const catacurses::window &win, const int line, *** for displaying triple digit encumbrance, due to new encumbrance system. *** *** If the player wants to see the total without having to do them maths, the *** *** armor layers ui shows everything they want :-) -Davek ***/ - const auto enc_data = get_encumbrance(); for( int i = 0; i < height; ++i ) { int thisline = firstline + i; if( thisline < 0 ) { @@ -118,12 +121,11 @@ void player::print_encumbrance( const catacurses::window &win, const int line, if( static_cast( thisline ) >= bps.size() ) { break; } - const body_part bp = bps[thisline].first; + const bodypart_id bp = bps[thisline].first; const bool combine = bps[thisline].second; - const encumbrance_data &e = enc_data[bp]; - const bool highlighted = selected_clothing ? selected_clothing->covers( convert_bp( - bp ).id() ) : false; - std::string out = body_part_name_as_heading( convert_bp( bp ).id(), combine ? 2 : 1 ); + const encumbrance_data &e = get_part_encumbrance_data( bp ); + const bool highlighted = selected_clothing ? selected_clothing->covers( bp ) : false; + std::string out = body_part_name_as_heading( bp, combine ? 2 : 1 ); if( utf8_width( out ) > 7 ) { out = utf8_truncate( out, 7 ); } @@ -142,8 +144,8 @@ void player::print_encumbrance( const catacurses::window &win, const int line, // take into account the new encumbrance system for layers mvwprintz( win, point( 12, 1 + i ), encumb_color( e.encumbrance ), "%-3d", e.layer_penalty ); // print warmth, tethered to right hand side of the window - mvwprintz( win, point( width - 6, 1 + i ), bodytemp_color( bp ), "(% 3d)", - temperature_print_rescaling( temp_conv[bp] ) ); + mvwprintz( win, point( width - 6, 1 + i ), bodytemp_color( bp->token ), "(% 3d)", + temperature_print_rescaling( temp_conv[bp->token] ) ); } if( draw_scrollbar ) { @@ -196,21 +198,22 @@ static std::string dodge_skill_text( double mod ) return string_format( _( "Dodge skill: %+.1f\n" ), mod ); } -static int get_encumbrance( const player &p, body_part bp, bool combine ) +static int get_encumbrance( const player &p, const bodypart_id &bp, bool combine ) { // Body parts that can't combine with anything shouldn't print double values on combine // This shouldn't happen, but handle this, just in case - const bool combines_with_other = static_cast( bp_aiOther[bp] ) != bp; + const bool combines_with_other = bp->opposite_part != bp.id(); return p.encumb( bp ) * ( ( combine && combines_with_other ) ? 2 : 1 ); } -static std::string get_encumbrance_description( const player &p, body_part bp, bool combine ) +static std::string get_encumbrance_description( const player &p, const bodypart_id bp, + bool combine ) { std::string s; const int eff_encumbrance = get_encumbrance( p, bp, combine ); - switch( bp ) { + switch( bp->token ) { case bp_torso: { const int melee_roll_pen = std::max( -eff_encumbrance, -80 ); s += string_format( _( "Melee attack rolls: %+d%%\n" ), melee_roll_pen ); @@ -290,6 +293,7 @@ enum class player_display_tab : int { traits, bionics, effects, + proficiencies, num_tabs, }; } // namespace @@ -312,6 +316,50 @@ static player_display_tab prev_tab( const player_display_tab tab ) } } +static std::vector sorted_proficiencies( const Character &guy ) +{ + std::vector ret; + for( const proficiency_id &id : guy.proficiencies() ) { + ret.emplace_back( id->name() ); + } + std::sort( ret.begin(), ret.end(), localized_compare ); + return ret; +} + +static void draw_proficiencies_tab( const catacurses::window &win, const unsigned line, + const Character &guy, const player_display_tab curtab ) +{ + werase( win ); + const bool focused = curtab == player_display_tab::proficiencies; + const nc_color title_color = focused ? h_light_gray : c_light_gray; + center_print( win, 0, title_color, _( title_PROFICIENCIES ) ); + const std::vector &profs = sorted_proficiencies( guy ); + const int height = getmaxy( win ) - 1; + const int width = getmaxx( win ) - 1; + bool draw_scrollbar = profs.size() > static_cast( height ); + int y = 1; + int start = draw_scrollbar ? line : 0; + for( size_t i = start; i < profs.size(); ++i ) { + if( y > height ) { + break; + } + y += fold_and_print( win, point( 1, y ), width, c_white, profs[i] ); + } + + if( draw_scrollbar ) { + scrollbar() + .offset_x( width ) + .offset_y( 1 ) + .content_size( profs.size() ) + .viewport_pos( line ) + .viewport_size( height ) + .scroll_to_last( false ) + .apply( win ); + } + + wnoutrefresh( win ); +} + static void draw_stats_tab( const catacurses::window &w_stats, const player &you, const unsigned int line, const player_display_tab curtab ) { @@ -478,10 +526,10 @@ static void draw_encumbrance_tab( const catacurses::window &w_encumb, static void draw_encumbrance_info( const catacurses::window &w_info, const player &you, const unsigned int line ) { - const std::vector> bps = list_and_combine_bps( you, nullptr ); + const std::vector> bps = list_and_combine_bps( you, nullptr ); werase( w_info ); - body_part bp = num_bp; + bodypart_id bp; bool combined_here = false; if( line < bps.size() ) { bp = bps[line].first; @@ -905,6 +953,10 @@ static void draw_info_window( const catacurses::window &w_info, const player &yo case player_display_tab::effects: draw_effects_info( w_info, line, effect_name_and_text ); break; + case player_display_tab::proficiencies: + werase( w_info ); + wnoutrefresh( w_info ); + break; case player_display_tab::num_tabs: abort(); } @@ -943,13 +995,11 @@ static void draw_tip( const catacurses::window &w_tip, const player &you, } static bool handle_player_display_action( player &you, unsigned int &line, - player_display_tab &curtab, input_context &ctxt, - const ui_adaptor &ui_tip, const ui_adaptor &ui_info, - const ui_adaptor &ui_stats, const ui_adaptor &ui_encumb, - const ui_adaptor &ui_traits, const ui_adaptor &ui_bionics, - const ui_adaptor &ui_effects, const ui_adaptor &ui_skills, - const std::vector &traitslist, - const std::vector &bionicslist, + player_display_tab &curtab, input_context &ctxt, const ui_adaptor &ui_tip, + const ui_adaptor &ui_info, const ui_adaptor &ui_stats, const ui_adaptor &ui_encumb, + const ui_adaptor &ui_traits, const ui_adaptor &ui_bionics, const ui_adaptor &ui_effects, + const ui_adaptor &ui_skills, const ui_adaptor &ui_proficiencies, + const std::vector &traitslist, const std::vector &bionicslist, const std::vector> &effect_name_and_text, const std::vector &skillslist ) { @@ -973,6 +1023,9 @@ static bool handle_player_display_action( player &you, unsigned int &line, case player_display_tab::skills: ui_skills.invalidate_ui(); break; + case player_display_tab::proficiencies: + ui_proficiencies.invalidate_ui(); + break; case player_display_tab::num_tabs: abort(); } @@ -985,7 +1038,7 @@ static bool handle_player_display_action( player &you, unsigned int &line, line_end = 8; break; case player_display_tab::encumbrance: { - const std::vector> bps = list_and_combine_bps( you, nullptr ); + const std::vector> bps = list_and_combine_bps( you, nullptr ); line_end = bps.size(); break; } @@ -1002,6 +1055,9 @@ static bool handle_player_display_action( player &you, unsigned int &line, line_beg = 1; // skip first header line_end = skillslist.size(); break; + case player_display_tab::proficiencies: + line_end = sorted_proficiencies( you ).size(); + break; case player_display_tab::num_tabs: abort(); } @@ -1137,10 +1193,8 @@ void player::disp_info() effect_name_and_text.push_back( { starvation_name, starvation_text } ); } - if( ( has_trait( trait_id( "TROGLO" ) ) && g->is_in_sunlight( pos() ) && - g->weather.weather == WEATHER_SUNNY ) || - ( has_trait( trait_id( "TROGLO2" ) ) && g->is_in_sunlight( pos() ) && - g->weather.weather != WEATHER_SUNNY ) ) { + if( has_trait( trait_id( "TROGLO" ) ) && g->is_in_sunlight( pos() ) && + get_weather().weather_id->sun_intensity >= sun_intensity_type::high ) { effect_name_and_text.push_back( { _( "In Sunlight" ), _( "The sunlight irritates you.\n" "Strength - 1; Dexterity - 1; Intelligence - 1; Perception - 1" ) @@ -1369,8 +1423,8 @@ void player::disp_info() ui_effects.on_screen_resize( [&]( ui_adaptor & ui_effects ) { w_effects = catacurses::newwin( effect_win_size_y, grid_width, point( grid_width * 2 + 2, infooffsetybottom ) ); - w_effects_border = catacurses::newwin( effect_win_size_y + 1, grid_width + 1, - point( grid_width * 2 + 2, infooffsetybottom ) ); + w_effects_border = catacurses::newwin( effect_win_size_y + 1, grid_width + 2, + point( grid_width * 2 + 1, infooffsetybottom ) ); border_effects.set( point( grid_width * 2 + 1, infooffsetybottom - 1 ), point( grid_width + 2, effect_win_size_y + 2 ) ); ui_effects.position_from_window( w_effects_border ); @@ -1382,23 +1436,29 @@ void player::disp_info() draw_effects_tab( w_effects, line, curtab, effect_name_and_text, effect_win_size_y ); } ); - catacurses::window w_speed; - catacurses::window w_speed_border; - border_helper::border_info &border_speed = borders.add_border(); - ui_adaptor ui_speed; - ui_speed.on_screen_resize( [&]( ui_adaptor & ui_speed ) { - w_speed = catacurses::newwin( grid_height, grid_width, point( grid_width * 2 + 2, 1 ) ); - w_speed_border = catacurses::newwin( grid_height + 1, grid_width + 1, - point( grid_width * 2 + 2, 1 ) ); - border_speed.set( point( grid_width * 2 + 1, 0 ), - point( grid_width + 2, grid_height + 2 ) ); - ui_speed.position_from_window( w_speed_border ); + unsigned int proficiency_win_size_y = 0; + const point profstart = point( grid_width * 2 + 2, infooffsetybottom + effect_win_size_y + 1 ); + catacurses::window w_proficiencies; + catacurses::window w_proficiencies_border; + border_helper::border_info &border_proficiencies = borders.add_border(); + ui_adaptor ui_proficiencies; + ui_proficiencies.on_screen_resize( [&]( ui_adaptor & ui_proficiencies ) { + const unsigned int maxy = static_cast( TERMY ); + proficiency_win_size_y = std::min( _proficiencies.size(), + static_cast( maxy - ( infooffsetybottom + effect_win_size_y ) ) ) + 1; + w_proficiencies = catacurses::newwin( proficiency_win_size_y, grid_width, + profstart ); + w_proficiencies_border = catacurses::newwin( proficiency_win_size_y + 1, grid_width + 2, + profstart + point_west ); + border_proficiencies.set( profstart + point_north_west, point( grid_width + 2, + proficiency_win_size_y + 2 ) ); + ui_proficiencies.position_from_window( w_proficiencies_border ); } ); - ui_speed.mark_resize(); - ui_speed.on_redraw( [&]( const ui_adaptor & ) { - borders.draw_border( w_speed_border ); - wnoutrefresh( w_speed_border ); - draw_speed_tab( w_speed, *this, speed_effects ); + ui_proficiencies.mark_resize(); + ui_proficiencies.on_redraw( [&]( const ui_adaptor & ) { + borders.draw_border( w_proficiencies_border ); + wnoutrefresh( w_proficiencies_border ); + draw_proficiencies_tab( w_proficiencies, line, *this, curtab ); } ); unsigned int skill_win_size_y = 0; @@ -1448,13 +1508,32 @@ void player::disp_info() traitslist, bionicslist, effect_name_and_text, skillslist ); } ); + catacurses::window w_speed; + catacurses::window w_speed_border; + border_helper::border_info &border_speed = borders.add_border(); + ui_adaptor ui_speed; + ui_speed.on_screen_resize( [&]( ui_adaptor & ui_speed ) { + w_speed = catacurses::newwin( grid_height, grid_width, point( grid_width * 2 + 2, 1 ) ); + w_speed_border = catacurses::newwin( grid_height + 1, grid_width + 1, + point( grid_width * 2 + 2, 1 ) ); + border_speed.set( point( grid_width * 2 + 1, 0 ), + point( grid_width + 2, grid_height + 2 ) ); + ui_speed.position_from_window( w_speed_border ); + } ); + ui_speed.mark_resize(); + ui_speed.on_redraw( [&]( const ui_adaptor & ) { + borders.draw_border( w_speed_border ); + wnoutrefresh( w_speed_border ); + draw_speed_tab( w_speed, *this, speed_effects ); + } ); + bool done = false; do { ui_manager::redraw_invalidated(); - done = handle_player_display_action( *this, line, curtab, ctxt, ui_tip, ui_info, - ui_stats, ui_encumb, ui_traits, ui_bionics, ui_effects, ui_skills, - traitslist, bionicslist, effect_name_and_text, skillslist ); + done = handle_player_display_action( *this, line, curtab, ctxt, ui_tip, ui_info, ui_stats, + ui_encumb, ui_traits, ui_bionics, ui_effects, ui_skills, ui_proficiencies, traitslist, bionicslist, + effect_name_and_text, skillslist ); } while( !done ); } diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp index f3bb49fccfbb7..842b55eb174cf 100644 --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp @@ -6,7 +6,7 @@ #include #include "activity_handlers.h" -#include "avatar.h" +#include "character.h" #include "effect.h" #include "enums.h" #include "event.h" @@ -29,6 +29,7 @@ #include "translations.h" #include "units.h" #include "weather.h" +#include "vitamin.h" #if defined(TILES) # if defined(_MSC_VER) && defined(USE_VCPKG) @@ -46,6 +47,7 @@ static const activity_id ACT_FIRSTAID( "ACT_FIRSTAID" ); static const efftype_id effect_adrenaline( "adrenaline" ); static const efftype_id effect_alarm_clock( "alarm_clock" ); static const efftype_id effect_antibiotic( "antibiotic" ); +static const efftype_id effect_anemia( "anemia" ); static const efftype_id effect_asthma( "asthma" ); static const efftype_id effect_attention( "attention" ); static const efftype_id effect_bite( "bite" ); @@ -67,6 +69,7 @@ static const efftype_id effect_grabbed( "grabbed" ); static const efftype_id effect_grabbing( "grabbing" ); static const efftype_id effect_hallu( "hallu" ); static const efftype_id effect_hot( "hot" ); +static const efftype_id effect_hypovolemia( "hypovolemia" ); static const efftype_id effect_infected( "infected" ); static const efftype_id effect_lying_down( "lying_down" ); static const efftype_id effect_mending( "mending" ); @@ -78,6 +81,7 @@ static const efftype_id effect_paincysts( "paincysts" ); static const efftype_id effect_panacea( "panacea" ); static const efftype_id effect_rat( "rat" ); static const efftype_id effect_recover( "recover" ); +static const efftype_id effect_redcells_anemia( "redcells_anemia" ); static const efftype_id effect_shakes( "shakes" ); static const efftype_id effect_sleep( "sleep" ); static const efftype_id effect_slept_through_alarm( "slept_through_alarm" ); @@ -92,8 +96,10 @@ static const efftype_id effect_toxin_buildup( "toxin_buildup" ); static const efftype_id effect_valium( "valium" ); static const efftype_id effect_visuals( "visuals" ); static const efftype_id effect_weak_antibiotic( "weak_antibiotic" ); +static const efftype_id effect_winded( "winded" ); -static const vitamin_id vitamin_iron( "iron" ); +static const vitamin_id vitamin_blood( "blood" ); +static const vitamin_id vitamin_redcells( "redcells" ); static const mongroup_id GROUP_NETHER( "GROUP_NETHER" ); @@ -114,6 +120,8 @@ static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); +static const std::string flag_TOURNIQUET( "TOURNIQUET" ); + static void eff_fun_onfire( player &u, effect &it ) { const int intense = it.get_intensity(); @@ -182,8 +190,9 @@ static void eff_fun_fungus( player &u, effect &it ) _( " vomits thousands of live spores!" ) ); u.moves = -500; - fungal_effects fe( *g, g->m ); - for( const tripoint &sporep : g->m.points_in_radius( u.pos(), 1 ) ) { + map &here = get_map(); + fungal_effects fe( *g, here ); + for( const tripoint &sporep : here.points_in_radius( u.pos(), 1 ) ) { if( sporep == u.pos() ) { continue; } @@ -239,14 +248,20 @@ static void eff_fun_bleed( player &u, effect &it ) // on the wound or otherwise suppressing the flow. (Kits contain either // QuikClot or bandages per the recipe.) const int intense = it.get_intensity(); - if( one_in( 36 / intense ) && u.activity.id() != ACT_FIRSTAID ) { - u.add_msg_player_or_npc( m_bad, _( "You lose some blood." ), - _( " loses some blood." ) ); + // tourniquet reduces effective bleeding by 2/3 but doesn't modify the effect's intensity + bool tourniquet = u.worn_with_flag( flag_TOURNIQUET, convert_bp( it.get_bp() ) ); + if( !( tourniquet && one_in( 3 ) ) && u.activity.id() != ACT_FIRSTAID ) { // Prolonged hemorrhage is a significant risk for developing anemia - u.vitamin_mod( vitamin_iron, rng( -1, -4 ) ); - u.mod_pain( 1 ); - u.apply_damage( nullptr, convert_bp( it.get_bp() ).id(), 1 ); - u.bleed(); + u.vitamin_mod( vitamin_redcells, -intense ); + u.vitamin_mod( vitamin_blood, -intense ); + if( one_in( 400 / intense ) ) { + u.mod_pain( 1 ); + } + if( one_in( 120 / intense ) ) { + u.bleed(); + u.add_msg_player_or_npc( m_bad, _( "You lose some blood." ), + _( " loses some blood." ) ); + } } } static void eff_fun_hallu( player &u, effect &it ) @@ -489,6 +504,8 @@ void player::hardcoded_effects( effect &it ) int intense = it.get_intensity(); const bodypart_id &bp = convert_bp( it.get_bp() ).id(); bool sleeping = has_effect( effect_sleep ); + map &here = get_map(); + Character &player_character = get_player_character(); if( id == effect_dermatik ) { bool triggered = false; int formication_chance = 3600; @@ -537,8 +554,8 @@ void player::hardcoded_effects( effect &it ) //~ %s is bodypart in accusative. add_msg( m_warning, _( "You start scratching your %s!" ), body_part_name_accusative( bp ) ); - g->u.cancel_activity(); - } else if( g->u.sees( pos() ) ) { + player_character.cancel_activity(); + } else if( player_character.sees( pos() ) ) { //~ 1$s is NPC name, 2$s is bodypart in accusative. add_msg( _( "%1$s starts scratching their %2$s!" ), name, body_part_name_accusative( bp ) ); @@ -588,13 +605,13 @@ void player::hardcoded_effects( effect &it ) tries++; } while( g->critter_at( dest ) && tries < 10 ); if( tries < 10 ) { - if( g->m.impassable( dest ) ) { - g->m.make_rubble( dest, f_rubble_rock, true ); + if( here.impassable( dest ) ) { + here.make_rubble( dest, f_rubble_rock, true ); } MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( GROUP_NETHER ); g->place_critter_at( spawn_details.name, dest ); - if( g->u.sees( dest ) ) { + if( player_character.sees( dest ) ) { g->cancel_activity_or_ignore_query( distraction_type::hostile_spotted_far, _( "A monster appears nearby!" ) ); add_msg_if_player( m_warning, _( "A portal opens nearby, and a monster crawls through!" ) ); @@ -627,9 +644,9 @@ void player::hardcoded_effects( effect &it ) } } else if( id == effect_tindrift ) { add_msg_if_player( m_bad, _( "You are beset with a vision of a prowling beast." ) ); - for( const tripoint &dest : g->m.points_in_radius( pos(), 6 ) ) { - if( g->m.is_cornerfloor( dest ) ) { - g->m.add_field( dest, fd_tindalos_rift, 3 ); + for( const tripoint &dest : here.points_in_radius( pos(), 6 ) ) { + if( here.is_cornerfloor( dest ) ) { + here.add_field( dest, fd_tindalos_rift, 3 ); add_msg_if_player( m_info, _( "Your surroundings are permeated with a foul scent." ) ); //Remove the effect, since it's done all it needs to do to the target. remove_effect( effect_tindrift ); @@ -691,13 +708,13 @@ void player::hardcoded_effects( effect &it ) } } while( g->critter_at( dest ) ); if( tries < 10 ) { - if( g->m.impassable( dest ) ) { - g->m.make_rubble( dest, f_rubble_rock, true ); + if( here.impassable( dest ) ) { + here.make_rubble( dest, f_rubble_rock, true ); } MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( GROUP_NETHER ); g->place_critter_at( spawn_details.name, dest ); - if( g->u.sees( dest ) ) { + if( player_character.sees( dest ) ) { g->cancel_activity_or_ignore_query( distraction_type::hostile_spotted_far, _( "A monster appears nearby!" ) ); add_msg( m_warning, _( "A portal opens nearby, and a monster crawls through!" ) ); @@ -885,10 +902,234 @@ void player::hardcoded_effects( effect &it ) g->events().send( getID(), id ); set_part_hp_cur( bodypart_id( "torso" ), 0 ); } + } else if( id == effect_hypovolemia ) { + // hypovolemia and dehydration are closely related so it will pull water + // from your system to replenish blood quantity + if( calendar::once_every( -vitamin_rate( vitamin_blood ) ) && one_in( 5 ) && get_thirst() <= 240 ) { + mod_thirst( rng( 0, intense ) ); + } + // bleed out lambda + auto bleed_out = [&] { + if( has_effect( effect_bleed ) ) + { + add_msg_player_or_npc( m_bad, + _( "You bleed to death!" ), + _( " bleeds to death!" ) ); + g->events().send( getID() ); + } else + { + add_msg_player_or_npc( m_bad, + _( "Your heart can't keep up the pace and fails!" ), + _( " has a sudden heart attack!" ) ); + g->events().send( getID() ); + } + set_part_hp_cur( bodypart_id( "torso" ), 0 ); + }; + // this goes first because beyond minimum threshold you just die without delay, + // while stage 4 is on a timer check with an rng grace period + + if( vitamin_get( vitamin_blood ) == vitamin_blood->min() ) { + bleed_out(); + } + + // Hypovolemic shock + // stage 1 - early symptoms include headache, fatigue, weakness, thirst, and dizziness. + // stage 2 - person may begin sweating and feeling more anxious and restless. + // stage 3 - heart rate will increase to over 120 bpm; rapid breathing + // mental distress, including anxiety and agitation; skin is pale and cold + cyanosis, sweating + // stage 4 is a life threatening condition; extremely rapid heart rate, breathing very fast and difficult + // drifting in and out of consciousness, sweating heavily, feeling cool to the touch, looking extremely pale + + if( one_in( 1200 / intense ) && !in_sleep_state() ) { + std::string warning; + + if( one_in( 5 ) ) { + // no-effect message block + if( intense == 1 ) { + warning = _( "Your skin looks pale and you feel anxious and thirsty. Blood loss?" ); + } else if( intense == 2 ) { + warning = _( "Your pale skin is sweating, your heart beats fast and you feel restless. Maybe you lost too much blood?" ); + } else if( intense == 3 ) { + warning = _( "You're unsettlingly white, but your fingetips are bluish. You are agitated and your heart is racing. Your blood loss must be serious." ); + } else { //intense == 4 + warning = _( "You are pale as a ghost, dripping wet from the sweat, and sluggish despite your heart racing like a train. You are on a brink of colapse from effects of a bood loss." ); + } + add_msg_if_player( m_bad, warning ); + } else { + // effect dice, with progresion of effects, 3 possible effects per tier + int dice_roll = rng( 0, 2 ) + intense; + switch( dice_roll ) { + case 1: + warning = _( "You feel dizzy and lightheaded." ); + add_effect( effect_stunned, rng( 5_seconds * intense, 2_minutes * intense ) ); + break; + case 2: + warning = _( "You feel tired and you breathe heavily." ); + mod_fatigue( 3 * intense ); + break; + case 3: + warning = _( "You are anxcious and cannot collect your thoughts." ); + focus_pool -= rng( 1, focus_pool * intense / it.get_max_intensity() ); + break; + case 4: + warning = _( "You are sweating profusely, but you feel cold." ); + temp_conv[bp_hand_l] -= 1000 * intense; + temp_conv[bp_hand_r] -= 1000 * intense; + temp_conv[bp_foot_l] -= 1000 * intense; + temp_conv[bp_foot_r] -= 1000 * intense; + break; + case 5: + warning = _( "You huff and puff. Your breath is rapid and shallow." ); + mod_stamina( -500 * intense ); + break; + case 6: + if( one_in( 2 ) ) { + warning = _( "You drop to the ground, fighting to keep yourself conscious." ); + add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); + break; + } else { + warning = _( "Your mind slips away." ); + fall_asleep( rng( 2_minutes, 5_minutes ) ); + break; + } + } + add_msg_if_player( m_bad, warning ); + } + } + // this goes last because we don't want in_sleep_state to prevent you from dying + if( intense == 4 && one_in( 900 ) && + rng( 1, -vitamin_blood->min() * 3 / 5 ) > ( -vitamin_blood->min() + vitamin_get( + vitamin_blood ) ) ) { + bleed_out(); + } + } else if( id == effect_anemia ) { + // effects: reduces effective redcells regen and depletes redcells at high intensity + if( calendar::once_every( vitamin_rate( vitamin_redcells ) ) ) { + vitamin_mod( vitamin_redcells, -rng( 0, intense ) ); + } + } else if( id == effect_redcells_anemia ) { + // Lack of iron impairs production of hemoglobin and therefore ability to carry + // oxygen by red blood cells. Alternatively hemorrage causes physical loss of red blood cells. + // This triggers veriety of symptoms, focusing on weakness, + // fatigue, cold limbs, later in dizzyness, soreness, breathlessness, + // and severe maiaise and lethargy. + // Base anemia symptoms: fatigue, loss of stamina, loss of strength, impact on health + // are placed in effect JSON + + // you can only lose as much red blood cells before your body fails to function + if( vitamin_get( vitamin_redcells ) <= vitamin_redcells->min() + 5 ) { + add_msg_player_or_npc( m_bad, + _( "You cannot breathe and your body gives out!" ), + _( " gasps for air and dies!" ) ); + g->events().send( getID() ); + set_part_hp_cur( bodypart_id( "torso" ), 0 ); + } + if( one_in( 900 / intense ) && !in_sleep_state() ) { + // level 1 symptoms are cold limbs, pale skin, and weakness + switch( dice( 1, 9 ) ) { + case 1: + add_msg_if_player( m_bad, _( "Your hands feel unusually cold." ) ); + temp_conv[bp_hand_l] -= 2000; + temp_conv[bp_hand_r] -= 2000; + break; + case 2: + add_msg_if_player( m_bad, _( "Your feet feel unusualy cold." ) ); + temp_conv[bp_foot_l] -= 2000; + temp_conv[bp_foot_r] -= 2000; + break; + case 3: + add_msg_if_player( m_bad, _( "Your skin looks very pale." ) ); + break; + case 4: + add_msg_if_player( m_bad, _( "You feel weak. Where has your strength gone?" ) ); + break; + case 5: + add_msg_if_player( m_bad, _( "You feel feeble. A gust of wind could make you stumble." ) ); + break; + case 6: + add_msg_if_player( m_bad, _( "There is an overwhelming aura of tiredness inside of you." ) ); + mod_fatigue( intense * 3 ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + // level 2 anemia introduces dizzynes, shakes, headaches, cravings for non-comestibles, + // mouth and tongue soreness + if( intense > 1 ) { + switch( dice( 1, 9 ) ) { + case 1: + add_msg_if_player( m_bad, _( "Rest is what you want. Rest is what you need." ) ); + break; + case 2: + add_msg_if_player( m_bad, _( "You feel dizzy and can't coordinate movement of your feet." ) ); + add_effect( effect_stunned, rng( 1_minutes, 2_minutes ) ); + break; + case 3: + add_msg_if_player( m_bad, _( "Your muscles are quivering." ) ); + add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); + break; + case 4: + add_msg_if_player( m_bad, _( "You crave for ice. Dirt under your feet looks tasty too." ) ); + break; + case 5: + add_msg_if_player( m_bad, _( "Your whole mouth is sore, and your tongue is swollen." ) ); + break; + case 6: + add_msg_if_player( m_bad, _( "You feel lightheaded. And a migrane follows." ) ); + mod_pain( intense * 9 ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + } + // level 3 anemia introduces restless legs, severe tiredness, breathlessness + if( intense > 2 ) { + switch( dice( 1, 9 ) ) { + case 1: + add_msg_if_player( m_bad, _( "Your legs are restless. Urge to move them is so strong." ) ); + break; + case 2: + add_msg_if_player( m_bad, _( "You feel like you'd sleep on a rock." ) ); + mod_fatigue( intense * 3 ); + break; + case 3: + add_msg_if_player( m_bad, _( "You gasp for air!" ) ); + set_stamina( 0 ); + add_effect( effect_winded, rng( 30_seconds, 3_minutes ) ); + break; + case 4: + add_msg_if_player( m_bad, _( "Can't breathe. Must rest." ) ); + set_stamina( 0 ); + break; + case 5: + add_msg_if_player( m_bad, _( "You can't take it any more. Rest first, everything else later." ) ); + add_effect( effect_lying_down, rng( 2_minutes, 5_minutes ) ); + break; + case 6: + add_msg_if_player( m_bad, _( "You must sit down for a moment. Just a moment." ) ); + add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + } + } } else if( id == effect_grabbed ) { set_num_blocks_bonus( get_num_blocks_bonus() - 1 ); int zed_number = 0; - for( auto &dest : g->m.points_in_radius( pos(), 1, 0 ) ) { + for( auto &dest : here.points_in_radius( pos(), 1, 0 ) ) { const monster *const mon = g->critter_at( dest ); if( mon && mon->has_effect( effect_grabbing ) ) { zed_number += mon->get_grab_strength(); @@ -1068,18 +1309,13 @@ void player::hardcoded_effects( effect &it ) } // TODO: Move this to update_needs when NPCs can mutate - bool compatible_weather_types = g->weather.weather == WEATHER_CLEAR || - g->weather.weather == WEATHER_SUNNY - || g->weather.weather == WEATHER_DRIZZLE || g->weather.weather == WEATHER_RAINY || - g->weather.weather == WEATHER_FLURRIES - || g->weather.weather == WEATHER_CLOUDY || g->weather.weather == WEATHER_SNOW; - if( calendar::once_every( 10_minutes ) && ( has_trait( trait_CHLOROMORPH ) || has_trait( trait_M_SKIN3 ) || has_trait( trait_WATERSLEEP ) ) && - g->m.is_outside( pos() ) ) { + here.is_outside( pos() ) ) { if( has_trait( trait_CHLOROMORPH ) ) { // Hunger and thirst fall before your Chloromorphic physiology! - if( g->natural_light_level( posz() ) >= 12 && compatible_weather_types ) { + if( g->natural_light_level( posz() ) >= 12 && + get_weather().weather_id->sun_intensity >= sun_intensity_type::light ) { if( get_hunger() >= -30 ) { mod_hunger( -5 ); // photosynthesis warrants absorbing kcal directly @@ -1092,7 +1328,7 @@ void player::hardcoded_effects( effect &it ) } if( has_trait( trait_M_SKIN3 ) ) { // Spores happen! - if( g->m.has_flag_ter_or_furn( "FUNGUS", pos() ) ) { + if( here.has_flag_ter_or_furn( "FUNGUS", pos() ) ) { if( get_fatigue() >= 0 ) { mod_fatigue( -5 ); // Local guides need less sleep on fungal soil } @@ -1150,7 +1386,7 @@ void player::hardcoded_effects( effect &it ) trait_SEESLEEP ) ) { // People who can see while sleeping are acclimated to the light. if( has_trait( trait_HEAVYSLEEPER2 ) && !has_trait( trait_HIBERNATE ) ) { // So you can too sleep through noon - if( ( tirednessVal * 1.25 ) < g->m.ambient_light_at( pos() ) && ( get_fatigue() < 10 || + if( ( tirednessVal * 1.25 ) < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || one_in( get_fatigue() / 2 ) ) ) { add_msg_if_player( _( "It's too bright to sleep." ) ); // Set ourselves up for removal @@ -1159,14 +1395,14 @@ void player::hardcoded_effects( effect &it ) } // Ursine hibernators would likely do so indoors. Plants, though, might be in the sun. } else if( has_trait( trait_HIBERNATE ) ) { - if( ( tirednessVal * 5 ) < g->m.ambient_light_at( pos() ) && ( get_fatigue() < 10 || + if( ( tirednessVal * 5 ) < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || one_in( get_fatigue() / 2 ) ) ) { add_msg_if_player( _( "It's too bright to sleep." ) ); // Set ourselves up for removal it.set_duration( 0_turns ); woke_up = true; } - } else if( tirednessVal < g->m.ambient_light_at( pos() ) && ( get_fatigue() < 10 || + } else if( tirednessVal < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || one_in( get_fatigue() / 2 ) ) ) { add_msg_if_player( _( "It's too bright to sleep." ) ); // Set ourselves up for removal @@ -1222,12 +1458,12 @@ void player::hardcoded_effects( effect &it ) } else { int max_count = rng( 1, 3 ); int count = 0; - for( const tripoint &mp : g->m.points_in_radius( pos(), 1 ) ) { + for( const tripoint &mp : here.points_in_radius( pos(), 1 ) ) { if( mp == pos() ) { continue; } - if( g->m.has_flag( "FLAT", mp ) && - g->m.pl_sees( mp, 2 ) ) { + if( here.has_flag( "FLAT", mp ) && + here.pl_sees( mp, 2 ) ) { g->spawn_hallucination( mp ); if( ++count > max_count ) { break; @@ -1295,9 +1531,9 @@ void player::hardcoded_effects( effect &it ) } } else { if( dur == 1_turns ) { - if( g->u.has_alarm_clock() ) { - sounds::sound( g->u.pos(), 16, sounds::sound_t::alarm, _( "beep-beep-beep!" ), false, "tool", - "alarm_clock" ); + if( player_character.has_alarm_clock() ) { + sounds::sound( player_character.pos(), 16, sounds::sound_t::alarm, + _( "beep-beep-beep!" ), false, "tool", "alarm_clock" ); const std::string alarm = _( "Your alarm is going off." ); g->cancel_activity_or_ignore_query( distraction_type::noise, alarm ); add_msg( _( "Your alarm went off." ) ); diff --git a/src/pldata.h b/src/pldata.h index e6012f5b35fcc..ffd2ec0294ca2 100644 --- a/src/pldata.h +++ b/src/pldata.h @@ -41,21 +41,6 @@ struct enum_traits { static constexpr add_type last = add_type::NUM_ADD_TYPES; }; -enum hp_part : int { - hp_head = 0, - hp_torso, - hp_arm_l, - hp_arm_r, - hp_leg_l, - hp_leg_r, - num_hp_parts -}; - -template<> -struct enum_traits { - static constexpr hp_part last = num_hp_parts; -}; - class addiction { public: diff --git a/src/point.cpp b/src/point.cpp index 56600f031a731..e2f9d33c5cb73 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -80,12 +80,12 @@ point clamp( const point &p, const inclusive_rectangle &r ) return point( clamp( p.x, r.p_min.x, r.p_max.x ), clamp( p.y, r.p_min.y, r.p_max.y ) ); } -std::vector closest_tripoints_first( const tripoint ¢er, int max_dist ) +std::vector closest_points_first( const tripoint ¢er, int max_dist ) { - return closest_tripoints_first( center, 0, max_dist ); + return closest_points_first( center, 0, max_dist ); } -std::vector closest_tripoints_first( const tripoint ¢er, int min_dist, int max_dist ) +std::vector closest_points_first( const tripoint ¢er, int min_dist, int max_dist ) { const std::vector points = closest_points_first( center.xy(), min_dist, max_dist ); diff --git a/src/point.h b/src/point.h index 4649d6b1fdfee..32248ad071ed1 100644 --- a/src/point.h +++ b/src/point.h @@ -33,6 +33,8 @@ class JsonOut; // NOLINTNEXTLINE(cata-xy) struct point { + static constexpr int dimension = 2; + int x = 0; int y = 0; constexpr point() = default; @@ -104,6 +106,9 @@ struct point { std::string to_string() const; + void serialize( JsonOut &jsout ) const; + void deserialize( JsonIn &jsin ); + friend inline constexpr bool operator<( const point &a, const point &b ) { return a.x < b.x || ( a.x == b.x && a.y < b.y ); } @@ -120,11 +125,29 @@ struct point { #endif }; -void serialize( const point &p, JsonOut &jsout ); -void deserialize( point &p, JsonIn &jsin ); +inline int divide_round_to_minus_infinity( int n, int d ) +{ + if( n >= 0 ) { + return n / d; + } + return ( n - d + 1 ) / d; +} + +inline point multiply_xy( const point &p, int f ) +{ + return point( p.x * f, p.y * f ); +} + +inline point divide_xy_round_to_minus_infinity( const point &p, int d ) +{ + return point( divide_round_to_minus_infinity( p.x, d ), + divide_round_to_minus_infinity( p.y, d ) ); +} // NOLINTNEXTLINE(cata-xy) struct tripoint { + static constexpr int dimension = 3; + int x = 0; int y = 0; int z = 0; @@ -228,6 +251,18 @@ struct tripoint { } }; +inline tripoint multiply_xy( const tripoint &p, int f ) +{ + return tripoint( p.x * f, p.y * f, p.z ); +} + +inline tripoint divide_xy_round_to_minus_infinity( const tripoint &p, int d ) +{ + return tripoint( divide_round_to_minus_infinity( p.x, d ), + divide_round_to_minus_infinity( p.y, d ), + p.z ); +} + struct rectangle { point p_min; point p_max; @@ -337,8 +372,8 @@ struct sphere { * Following functions return points in a spiral pattern starting at center_x/center_y until it hits the radius. Clockwise fashion. * Credit to Tom J Nowell; http://stackoverflow.com/a/1555236/1269969 */ -std::vector closest_tripoints_first( const tripoint ¢er, int max_dist ); -std::vector closest_tripoints_first( const tripoint ¢er, int min_dist, int max_dist ); +std::vector closest_points_first( const tripoint ¢er, int max_dist ); +std::vector closest_points_first( const tripoint ¢er, int min_dist, int max_dist ); std::vector closest_points_first( const point ¢er, int max_dist ); std::vector closest_points_first( const point ¢er, int min_dist, int max_dist ); diff --git a/src/point_traits.h b/src/point_traits.h new file mode 100644 index 0000000000000..215e15fd120c7 --- /dev/null +++ b/src/point_traits.h @@ -0,0 +1,56 @@ +#ifndef CATA_SRC_POINT_TRAITS_H +#define CATA_SRC_POINT_TRAITS_H + +#include + +struct point; +struct tripoint; + +template +struct point_traits { + static int &x( Point &p ) { + return p.x(); + } + static int x( const Point &p ) { + return p.x(); + } + static int &y( Point &p ) { + return p.y(); + } + static int y( const Point &p ) { + return p.y(); + } + static int &z( Point &p ) { + return p.z(); + } + static int z( const Point &p ) { + return p.z(); + } +}; + +template +struct point_traits < + Point, + std::enable_if_t < std::is_same::value || std::is_same::value > + > { + static int &x( Point &p ) { + return p.x; + } + static const int &x( const Point &p ) { + return p.x; + } + static int &y( Point &p ) { + return p.y; + } + static const int &y( const Point &p ) { + return p.y; + } + static int &z( Point &p ) { + return p.z; + } + static const int &z( const Point &p ) { + return p.z; + } +}; + +#endif // CATA_SRC_POINT_TRAITS_H diff --git a/src/profession.cpp b/src/profession.cpp index aa04dd14be116..554764565b470 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -221,6 +221,7 @@ void profession::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "addictions", _starting_addictions, addiction_reader {} ); // TODO: use string_id or so optional( jo, was_loaded, "CBMs", _starting_CBMs, auto_flags_reader {} ); + optional( jo, was_loaded, "proficiencies", _starting_proficiencies ); // TODO: use string_id or so optional( jo, was_loaded, "traits", _starting_traits, auto_flags_reader {} ); optional( jo, was_loaded, "forbidden_traits", _forbidden_traits, auto_flags_reader {} ); @@ -299,6 +300,12 @@ void profession::check_definition() const } } + for( const proficiency_id &pid : _starting_proficiencies ) { + if( !pid.is_valid() ) { + debugmsg( "proficiency %s for profession %s does not exist", pid.str(), id.str() ); + } + } + for( auto &t : _starting_traits ) { if( !t.is_valid() ) { debugmsg( "trait %s for profession %s does not exist", t.c_str(), id.c_str() ); @@ -462,6 +469,11 @@ std::vector profession::CBMs() const return _starting_CBMs; } +std::vector profession::proficiencies() const +{ + return _starting_proficiencies; +} + std::vector profession::get_locked_traits() const { return _starting_traits; diff --git a/src/profession.h b/src/profession.h index 94e9c7cf01a23..76c7237bf930b 100644 --- a/src/profession.h +++ b/src/profession.h @@ -64,6 +64,7 @@ class profession std::vector _starting_addictions; std::vector _starting_CBMs; + std::vector _starting_proficiencies; std::vector _starting_traits; std::set _forbidden_traits; std::vector _starting_pets; @@ -105,6 +106,7 @@ class profession vproto_id vehicle() const; std::vector pets() const; std::vector CBMs() const; + std::vector proficiencies() const; StartingSkillList skills() const; std::map spells() const; diff --git a/src/proficiency.cpp b/src/proficiency.cpp new file mode 100644 index 0000000000000..280f43af96e7e --- /dev/null +++ b/src/proficiency.cpp @@ -0,0 +1,40 @@ +#include "proficiency.h" + +#include "generic_factory.h" + +namespace +{ +generic_factory proficiency_factory( "proficiency" ); +} // namespace + +template<> +const proficiency &proficiency_id::obj() const +{ + return proficiency_factory.obj( *this ); +} + +template<> +bool proficiency_id::is_valid() const +{ + return proficiency_factory.is_valid( *this ); +} + +void proficiency::load_proficiencies( const JsonObject &jo, const std::string &src ) +{ + proficiency_factory.load( jo, src ); +} + +void proficiency::reset() +{ + proficiency_factory.reset(); +} + +void proficiency::load( const JsonObject &jo, const std::string & ) +{ + mandatory( jo, was_loaded, "name", _name ); +} + +std::string proficiency::name() const +{ + return _name.translated(); +} diff --git a/src/proficiency.h b/src/proficiency.h new file mode 100644 index 0000000000000..103b26825dfac --- /dev/null +++ b/src/proficiency.h @@ -0,0 +1,29 @@ +#pragma once +#ifndef CATA_SRC_PROFICIENCY_H +#define CATA_SRC_PROFICIENCY_H + +#include "json.h" +#include "translations.h" +#include "type_id.h" + +template +class generic_factory; + +class proficiency +{ + friend class generic_factory; + + proficiency_id id; + bool was_loaded = false; + + translation _name; + + public: + static void load_proficiencies( const JsonObject &jo, const std::string &src ); + static void reset(); + void load( const JsonObject &jo, const std::string &src ); + + std::string name() const; +}; + +#endif // CATA_SRC_PROFICIENCY_H diff --git a/src/ranged.cpp b/src/ranged.cpp index 88cd6da579413..9f28a8e586fbe 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -680,7 +680,8 @@ bool player::handle_gun_damage( item &it ) void npc::pretend_fire( npc *source, int shots, item &gun ) { int curshot = 0; - if( g->u.sees( *source ) && one_in( 50 ) ) { + Character &player_character = get_player_character(); + if( player_character.sees( *source ) && one_in( 50 ) ) { add_msg( m_info, _( "%s shoots something." ), source->disp_name() ); } while( curshot != shots ) { @@ -692,7 +693,7 @@ void npc::pretend_fire( npc *source, int shots, item &gun ) item *weapon = &gun; const auto data = weapon->gun_noise( shots > 1 ); - if( g->u.sees( *source ) ) { + if( player_character.sees( *source ) ) { add_msg( m_warning, _( "You hear %s." ), data.sound ); } curshot++; @@ -730,10 +731,11 @@ int player::fire_gun( const tripoint &target, int shots, item &gun ) debugmsg( "Attempted to fire zero or negative shots using %s", gun.tname() ); } + map &here = get_map(); // usage of any attached bipod is dependent upon terrain - bool bipod = g->m.has_flag_ter_or_furn( "MOUNTABLE", pos() ); + bool bipod = here.has_flag_ter_or_furn( "MOUNTABLE", pos() ); if( !bipod ) { - if( const optional_vpart_position vp = g->m.veh_at( pos() ) ) { + if( const optional_vpart_position vp = here.veh_at( pos() ) ) { bipod = vp->vehicle().has_part( pos(), "MOUNTABLE" ); } } @@ -765,7 +767,7 @@ int player::fire_gun( const tripoint &target, int shots, item &gun ) dispersion.add_range( recoil_total() ); // If this is a vehicle mounted turret, which vehicle is it mounted on? - const vehicle *in_veh = has_effect( effect_on_roof ) ? veh_pointer_or_null( g->m.veh_at( + const vehicle *in_veh = has_effect( effect_on_roof ) ? veh_pointer_or_null( here.veh_at( pos() ) ) : nullptr; auto shot = projectile_attack( make_gun_projectile( gun ), pos(), aim, dispersion, this, in_veh ); @@ -861,8 +863,8 @@ int throw_cost( const player &c, const item &to_throw ) const int skill_cost = static_cast( ( base_move_cost * ( 20 - throw_skill ) / 20 ) ); ///\EFFECT_DEX increases throwing speed const int dexbonus = c.get_dex(); - const int encumbrance_penalty = c.encumb( bp_torso ) + - ( c.encumb( bp_hand_l ) + c.encumb( bp_hand_r ) ) / 2; + const int encumbrance_penalty = c.encumb( bodypart_id( "torso" ) ) + + ( c.encumb( bodypart_id( "hand_l" ) ) + c.encumb( bodypart_id( "hand_r" ) ) ) / 2; const float stamina_ratio = static_cast( c.get_stamina() ) / c.get_stamina_max(); const float stamina_penalty = 1.0 + std::max( ( 0.25f - stamina_ratio ) * 4.0f, 0.0f ); @@ -883,7 +885,8 @@ int Character::throw_dispersion_per_dodge( bool add_encumbrance ) const // +100 at 8, +80 at 12, +66.6 at 16, +57 at 20, +50 at 24 // Each 10 encumbrance on either hand is like -1 dex (can bring penalty to +400 per dodge) // Maybe TODO: Only use one hand - const int encumbrance = add_encumbrance ? encumb( bp_hand_l ) + encumb( bp_hand_r ) : 0; + const int encumbrance = add_encumbrance ? encumb( bodypart_id( "hand_l" ) ) + encumb( + bodypart_id( "hand_r" ) ) : 0; ///\EFFECT_DEX increases throwing accuracy against targets with good dodge stat float effective_dex = 2 + get_dex() / 4.0f - ( encumbrance ) / 40.0f; return static_cast( 100.0f / std::max( 1.0f, effective_dex ) ); @@ -925,7 +928,7 @@ int Character::throwing_dispersion( const item &to_throw, Creature *critter, } // 1 perception per 1 eye encumbrance ///\EFFECT_PER decreases throwing accuracy penalty from eye encumbrance - dispersion += std::max( 0, ( encumb( bp_eyes ) - get_per() ) * 10 ); + dispersion += std::max( 0, ( encumb( bodypart_id( "eyes" ) ) - get_per() ) * 10 ); // If throwing blind, we're assuming they mechanically can't achieve the // accuracy of a normal throw. @@ -1537,16 +1540,17 @@ int time_to_attack( const Character &p, const itype &firing ) static void cycle_action( item &weap, const tripoint &pos ) { + map &here = get_map(); // eject casings and linkages in random direction avoiding walls using player position as fallback - std::vector tiles = closest_tripoints_first( pos, 1 ); + std::vector tiles = closest_points_first( pos, 1 ); tiles.erase( tiles.begin() ); tiles.erase( std::remove_if( tiles.begin(), tiles.end(), [&]( const tripoint & e ) { - return !g->m.passable( e ); + return !here.passable( e ); } ), tiles.end() ); tripoint eject = tiles.empty() ? pos : random_entry( tiles ); // for turrets try and drop casings or linkages directly to any CARGO part on the same tile - const optional_vpart_position vp = g->m.veh_at( pos ); + const optional_vpart_position vp = here.veh_at( pos ); std::vector cargo; if( vp && weap.has_flag( "VEHICLE" ) ) { cargo = vp->vehicle().get_parts_at( pos, "CARGO", part_status_flag::any ); @@ -1558,7 +1562,7 @@ static void cycle_action( item &weap, const tripoint &pos ) weap.put_in( item( casing ).set_flag( "CASING" ), item_pocket::pocket_type::CONTAINER ); } else { if( cargo.empty() ) { - g->m.add_item_or_charges( eject, item( casing ) ); + here.add_item_or_charges( eject, item( casing ) ); } else { vp->vehicle().add_item( *cargo.front(), item( casing ) ); } @@ -1576,7 +1580,7 @@ static void cycle_action( item &weap, const tripoint &pos ) linkage.set_flag( "CASING" ); weap.put_in( linkage, item_pocket::pocket_type::CONTAINER ); } else if( cargo.empty() ) { - g->m.add_item_or_charges( eject, linkage ); + here.add_item_or_charges( eject, linkage ); } else { vp->vehicle().add_item( *cargo.front(), linkage ); } @@ -1670,7 +1674,7 @@ item::sound_data item::gun_noise( const bool burst ) const static bool is_driving( const player &p ) { - const optional_vpart_position vp = g->m.veh_at( p.pos() ); + const optional_vpart_position vp = get_map().veh_at( p.pos() ); return vp && vp->vehicle().is_moving() && vp->vehicle().player_in_control( p ); } @@ -1703,7 +1707,8 @@ dispersion_sources player::get_weapon_dispersion( const item &obj ) const dispersion_sources dispersion( weapon_dispersion ); dispersion.add_range( ranged_dex_mod() ); - dispersion.add_range( ( encumb( bp_arm_l ) + encumb( bp_arm_r ) ) / 5.0 ); + dispersion.add_range( ( encumb( bodypart_id( "arm_l" ) ) + encumb( bodypart_id( "arm_r" ) ) ) / + 5.0 ); if( is_driving( *this ) ) { // get volume of gun (or for auxiliary gunmods the parent gun) @@ -1794,7 +1799,8 @@ double player::gun_value( const item &weap, int ammo ) const int move_cost = time_to_attack( *this, *weap.type ); if( gun.clip != 0 && gun.clip < 10 ) { // TODO: RELOAD_ONE should get a penalty here - int reload_cost = gun.reload_time + encumb( bp_hand_l ) + encumb( bp_hand_r ); + int reload_cost = gun.reload_time + encumb( bodypart_id( "hand_l" ) ) + encumb( + bodypart_id( "hand_r" ) ); reload_cost /= gun.clip; move_cost += reload_cost; } @@ -1876,8 +1882,9 @@ target_handler::trajectory target_ui::run() sight_dispersion = you->effective_dispersion( relevant->sight_dispersion() ); } + map &here = get_map(); // Load settings - allow_zlevel_shift = g->m.has_zlevels() && get_option( "FOV_3D" ); + allow_zlevel_shift = here.has_zlevels() && get_option( "FOV_3D" ); snap_to_target = get_option( "SNAP_TO_TARGET" ); if( mode == TargetMode::Turrets ) { // Due to how cluttered the display would become, disable it by default @@ -1885,10 +1892,11 @@ target_handler::trajectory target_ui::run() draw_turret_lines = vturrets->size() == 1; } - on_out_of_scope cleanup( []() { - g->m.invalidate_map_cache( g->u.pos().z + g->u.view_offset.z ); + avatar &player_character = get_avatar(); + on_out_of_scope cleanup( [&here, &player_character]() { + here.invalidate_map_cache( player_character.pos().z + player_character.view_offset.z ); } ); - restore_on_out_of_scope view_offset_prev( g->u.view_offset ); + restore_on_out_of_scope view_offset_prev( player_character.view_offset ); shared_ptr_fast target_ui_cb = make_shared_fast( [&]() { @@ -2228,13 +2236,14 @@ bool target_ui::set_cursor_pos( const tripoint &new_pos ) // Make sure new position is valid or find a closest valid position std::vector new_traj; tripoint valid_pos = new_pos; + map &here = get_map(); if( new_pos != src ) { // On Z axis, make sure we do not exceed map boundaries valid_pos.z = clamp( valid_pos.z, -OVERMAP_DEPTH, OVERMAP_HEIGHT ); // Or current view range valid_pos.z = clamp( valid_pos.z - src.z, -fov_3d_z_range, fov_3d_z_range ) + src.z; - new_traj = g->m.find_clear_path( src, valid_pos ); + new_traj = here.find_clear_path( src, valid_pos ); if( range == 1 ) { // We should always be able to hit adjacent squares if( square_dist( src, valid_pos ) > 1 ) { @@ -2280,7 +2289,7 @@ bool target_ui::set_cursor_pos( const tripoint &new_pos ) traj = new_traj; } else { dst = valid_pos; - traj = g->m.find_clear_path( src, dst ); + traj = here.find_clear_path( src, dst ); } if( snap_to_target ) { @@ -2363,13 +2372,14 @@ void target_ui::update_target_list() bool target_ui::choose_initial_target( bool reentered, tripoint &new_dst ) { + map &here = get_map(); // Determine if we had a target and it is still visible if( !you->last_target.expired() ) { Creature *cr = you->last_target.lock().get(); if( pl_can_target( cr ) ) { // There it is! new_dst = cr->pos(); - you->last_target_pos = g->m.getabs( new_dst ); + you->last_target_pos = here.getabs( new_dst ); return true; } } @@ -2378,7 +2388,7 @@ bool target_ui::choose_initial_target( bool reentered, tripoint &new_dst ) // and still can aim at that tile. cata::optional local_last_tgt_pos = cata::nullopt; if( you->last_target_pos ) { - tripoint local = g->m.getlocal( *you->last_target_pos ); + tripoint local = here.getlocal( *you->last_target_pos ); if( dist_fn( local ) > range ) { // No luck you->last_target_pos = cata::nullopt; @@ -2400,10 +2410,10 @@ bool target_ui::choose_initial_target( bool reentered, tripoint &new_dst ) // Try to find at least something if( targets.empty() ) { // The closest practice target - const std::vector nearby = closest_tripoints_first( src, range ); + const std::vector nearby = closest_points_first( src, range ); const auto target_spot = std::find_if( nearby.begin(), nearby.end(), - [this]( const tripoint & pt ) { - return g->m.tr_at( pt ).id == tr_practice_target && this->you->sees( pt ); + [this, &here]( const tripoint & pt ) { + return here.tr_at( pt ).id == tr_practice_target && this->you->sees( pt ); } ); if( target_spot != nearby.end() ) { @@ -2455,7 +2465,7 @@ bool target_ui::pl_can_target( const Creature *cr ) void target_ui::set_last_target() { - you->last_target_pos = g->m.getabs( dst ); + you->last_target_pos = get_map().getabs( dst ); if( dst_critter ) { you->last_target = g->shared_from( *dst_critter ); } else { @@ -2520,7 +2530,7 @@ void target_ui::set_view_offset( const tripoint &new_offset ) if( changed_z ) { // We need to do a bunch of cache updates since we're // looking at a different z-level. - g->m.invalidate_map_cache( new_.z ); + get_map().invalidate_map_cache( new_.z ); } } @@ -2550,7 +2560,7 @@ void target_ui::recalc_aim_turning_penalty() if( lt_ptr ) { curr_recoil_pos = lt_ptr->pos(); } else if( you->last_target_pos ) { - curr_recoil_pos = g->m.getlocal( *you->last_target_pos ); + curr_recoil_pos = get_map().getlocal( *you->last_target_pos ); } else { curr_recoil_pos = src; } @@ -2731,7 +2741,7 @@ void target_ui::draw_terrain_overlay() g->draw_highlight( tile ); } else { #endif - g->m.drawsq( g->w_terrain, *you, tile, true, true, center ); + get_map().drawsq( g->w_terrain, *you, tile, true, true, center ); #ifdef TILES } #endif diff --git a/src/recipe.cpp b/src/recipe.cpp index 14a33433bcbff..dff3a2d14af99 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -20,6 +20,7 @@ #include "optional.h" #include "output.h" #include "player.h" +#include "proficiency.h" #include "skill.h" #include "string_formatter.h" #include "string_id.h" @@ -35,12 +36,31 @@ extern bool test_mode; recipe::recipe() : skill_used( skill_id::NULL_ID() ) {} -time_duration recipe::batch_duration( int batch, float multiplier, size_t assistants ) const +time_duration recipe::batch_duration( const Character &guy, int batch, float multiplier, + size_t assistants ) const { - return time_duration::from_turns( batch_time( batch, multiplier, assistants ) / 100 ); + return time_duration::from_turns( batch_time( guy, batch, multiplier, assistants ) / 100 ); } -int recipe::batch_time( int batch, float multiplier, size_t assistants ) const +time_duration recipe::time_to_craft( const Character &guy ) const +{ + return time_duration::from_seconds( time_to_craft_moves( guy ) / 100 ); +} + +int recipe::time_to_craft_moves( const Character &guy ) const +{ + int ret = time; + for( const recipe_proficiency &prof : proficiencies ) { + if( !prof.required ) { + if( !guy.has_proficiency( prof.id ) ) { + ret *= prof.time_multiplier; + } + } + } + return ret; +} + +int recipe::batch_time( const Character &guy, int batch, float multiplier, size_t assistants ) const { // 1.0f is full speed // 0.33f is 1/3 speed @@ -49,7 +69,7 @@ int recipe::batch_time( int batch, float multiplier, size_t assistants ) const multiplier = 1.0f; } - const float local_time = static_cast( time ) / multiplier; + const float local_time = static_cast( time_to_craft_moves( guy ) ) / multiplier; // if recipe does not benefit from batching and we have no assistants, don't do unnecessary additional calculations if( batch_rscale == 0.0 && assistants == 0 ) { @@ -150,6 +170,8 @@ void recipe::load( const JsonObject &jo, const std::string &src ) } } + jo.read( "proficiencies", proficiencies ); + // simplified autolearn sets requirements equal to required skills at finalization if( jo.has_bool( "autolearn" ) ) { assign( jo, "autolearn", autolearn ); @@ -334,6 +356,39 @@ void recipe::finalize() container = item::find_type( result_ )->default_container.value_or( "null" ); } + std::set required; + std::set used; + for( const recipe_proficiency &rpof : proficiencies ) { + if( !rpof.id.is_valid() ) { + debugmsg( "proficiency %s does not exist in recipe %s", rpof.id.str(), ident_.str() ); + } + + if( rpof.required && rpof.time_multiplier != 1.0f ) { + debugmsg( "proficiencies in recipes cannot be both required and provide a malus in %s", + rpof.id.str(), ident_.str() ); + } + if( required.count( rpof.id ) || used.count( rpof.id ) ) { + debugmsg( "proficiency %s listed twice recipe %s", rpof.id.str(), + ident_.str() ); + } + + if( rpof.time_multiplier < 1.0f ) { + debugmsg( "proficiency %s provides a bonus for not being known in recipe %s", rpof.id.str(), + ident_.str() ); + } + if( rpof.fail_multiplier < 1.0f ) { + debugmsg( "proficiency %s provides a bonus for not being known in recipe %s", rpof.id.str(), + ident_.str() ); + } + // Now that we've done the error checking, log that a proficiency with this id is used + if( rpof.required ) { + required.insert( rpof.id ); + } else { + used.insert( rpof.id ); + } + } + + if( autolearn && autolearn_requirements.empty() ) { autolearn_requirements = required_skills; if( skill_used ) { @@ -479,6 +534,67 @@ bool recipe::has_byproducts() const return !byproducts.empty(); } +std::string recipe::required_proficiencies_string( const Character &c ) const +{ + std::vector required_profs; + std::vector> used_profs; + + for( const recipe_proficiency &rec : proficiencies ) { + if( rec.required ) { + required_profs.push_back( rec.id ); + } else { + used_profs.push_back( { rec.id, rec.time_multiplier } ); + } + } + std::string required = enumerate_as_string( required_profs.begin(), + required_profs.end(), [&]( const proficiency_id & id ) { + const nc_color color = c.has_proficiency( id ) ? c_green : c_red; + return colorize( id->name(), color ); + } ); + + std::string used = enumerate_as_string( used_profs.begin(), + used_profs.end(), [&]( const std::pair &pair ) { + const std::string color = c.has_proficiency( pair.first ) ? "white" : "yellow"; + return string_format( "%s %gx", pair.first->name(), color, + pair.second ); + } ); + used = string_format( _( "Proficiencies Used: %s" ), used ); + + return string_format( "%s\n%s", required, used ); +} + +std::set recipe::required_proficiencies() const +{ + std::set ret; + for( const recipe_proficiency &rec : proficiencies ) { + if( rec.required ) { + ret.insert( rec.id ); + } + } + return ret; +} + +bool recipe::character_has_required_proficiencies( const Character &c ) const +{ + for( const proficiency_id &id : required_proficiencies() ) { + if( !c.has_proficiency( id ) ) { + return false; + } + } + return true; +} + +std::set recipe::assist_proficiencies() const +{ + std::set ret; + for( const recipe_proficiency &rec : proficiencies ) { + if( !rec.required ) { + ret.insert( rec.id ); + } + } + return ret; +} + // Format a std::pair for the crafting menu. // skill colored green (or yellow if beyond characters skill) // optionally with the skill level (player / difficulty) @@ -764,3 +880,16 @@ bool recipe::hot_result() const } return false; } + +void recipe_proficiency::deserialize( JsonIn &jsin ) +{ + load( jsin.get_object() ); +} + +void recipe_proficiency::load( const JsonObject &jo ) +{ + jo.read( "proficiency", id ); + jo.read( "required", required ); + jo.read( "time_multiplier", time_multiplier ); + jo.read( "fail_multiplier", fail_multiplier ); +} diff --git a/src/recipe.h b/src/recipe.h index 65e81e55cf408..752b98ee86617 100644 --- a/src/recipe.h +++ b/src/recipe.h @@ -31,6 +31,16 @@ inline constexpr recipe_filter_flags operator&( recipe_filter_flags l, recipe_fi static_cast( l ) & static_cast( r ) ); } +struct recipe_proficiency { + proficiency_id id; + bool required = false; + float time_multiplier = 1.0f; + float fail_multiplier = 2.5f; + + void load( const JsonObject &jo ); + void deserialize( JsonIn &jsin ); +}; + class recipe { friend class recipe_dictionary; @@ -38,6 +48,8 @@ class recipe private: itype_id result_ = itype_id::NULL_ID(); + int time = 0; // in movement points (100 per turn) + public: recipe(); @@ -56,7 +68,6 @@ class recipe translation description; - int time = 0; // in movement points (100 per turn) int difficulty = 0; /** Fetch combined requirement data (inline and via "using" syntax). @@ -106,6 +117,7 @@ class recipe skill_id skill_used; std::map required_skills; + std::vector proficiencies; std::map autolearn_requirements; // Skill levels required to autolearn std::map learn_by_disassembly; // Skill levels required to learn by disassembly @@ -124,6 +136,14 @@ class recipe // menu which includes the primary skill. std::string required_skills_string( const Character *, bool include_primary_skill, bool print_skill_level ) const; + // Format the proficiencies string. + std::string required_proficiencies_string( const Character &c ) const; + // Required proficiencies + std::set required_proficiencies() const; + // + bool character_has_required_proficiencies( const Character &c ) const; + // Helpful proficiencies + std::set assist_proficiencies() const; // This is used by the basecamp bulletin board. std::string required_all_skills_string() const; @@ -142,10 +162,13 @@ class recipe bool has_byproducts() const; - int batch_time( int batch, float multiplier, size_t assistants ) const; - time_duration batch_duration( int batch = 1, float multiplier = 1.0, + int batch_time( const Character &guy, int batch, float multiplier, size_t assistants ) const; + time_duration batch_duration( const Character &guy, int batch = 1, float multiplier = 1.0, size_t assistants = 0 ) const; + time_duration time_to_craft( const Character &guy ) const; + int time_to_craft_moves( const Character &guy ) const; + bool has_flag( const std::string &flag_name ) const; bool is_reversible() const { diff --git a/src/relic.cpp b/src/relic.cpp index 8ac680402e865..c71be68ade887 100644 --- a/src/relic.cpp +++ b/src/relic.cpp @@ -4,12 +4,56 @@ #include #include "creature.h" +#include "enum_traits.h" +#include "generic_factory.h" #include "json.h" #include "magic.h" #include "magic_enchantment.h" #include "translations.h" #include "type_id.h" +namespace io +{ + // *INDENT-OFF* + template<> + std::string enum_to_string( relic_procgen_data::type data ) + { + switch( data ) { + case relic_procgen_data::type::active_enchantment: return "active_enchantment"; + case relic_procgen_data::type::hit_me: return "hit_me"; + case relic_procgen_data::type::hit_you: return "hit_you"; + case relic_procgen_data::type::passive_enchantment_add: return "passive_enchantment_add"; + case relic_procgen_data::type::passive_enchantment_mult: return "passive_enchantment_mult"; + case relic_procgen_data::type::last: break; + } + debugmsg( "Invalid enchantment::has" ); + abort(); + } + // *INDENT-ON* +} // namespace io + +namespace +{ +generic_factory relic_procgen_data_factory( "relic_procgen_data" ); +} // namespace + +template<> +const relic_procgen_data &string_id::obj() const +{ + return relic_procgen_data_factory.obj( *this ); +} + +template<> +bool string_id::is_valid() const +{ + return relic_procgen_data_factory.is_valid( *this ); +} + +void relic_procgen_data::load_relic_procgen_data( const JsonObject &jo, const std::string &src ) +{ + relic_procgen_data_factory.load( jo, src ); +} + void relic::add_active_effect( const fake_spell &sp ) { active_effects.emplace_back( sp ); @@ -25,6 +69,84 @@ void relic::add_passive_effect( const enchantment &nench ) passive_effects.emplace_back( nench ); } +template +void relic_procgen_data::enchantment_value_passive::load( const JsonObject &jo ) +{ + mandatory( jo, was_loaded, "type", type ); + optional( jo, was_loaded, "power_per_increment", power_per_increment, 1 ); + optional( jo, was_loaded, "increment", increment, 1 ); + optional( jo, was_loaded, "min_value", min_value, 0 ); + optional( jo, was_loaded, "max_value", max_value, 0 ); +} + +template +void relic_procgen_data::enchantment_value_passive::deserialize( JsonIn &jsin ) +{ + JsonObject jobj = jsin.get_object(); + load( jobj ); +} + +void relic_procgen_data::enchantment_active::load( const JsonObject &jo ) +{ + mandatory( jo, was_loaded, "spell_id", activated_spell ); + optional( jo, was_loaded, "base_power", base_power, 0 ); + optional( jo, was_loaded, "power_per_increment", power_per_increment, 1 ); + optional( jo, was_loaded, "increment", increment, 1 ); + optional( jo, was_loaded, "min_level", min_level, 0 ); + optional( jo, was_loaded, "max_level", max_level, 0 ); +} + +void relic_procgen_data::enchantment_active::deserialize( JsonIn &jsin ) +{ + JsonObject jobj = jsin.get_object(); + load( jobj ); +} + +void relic_procgen_data::load( const JsonObject &jo, const std::string & ) +{ + for( const JsonObject &jo_inner : jo.get_array( "passive_add_procgen_values" ) ) { + int weight = 0; + mandatory( jo_inner, was_loaded, "weight", weight ); + relic_procgen_data::enchantment_value_passive val; + val.load( jo_inner ); + + passive_add_procgen_values.add( val, weight ); + } + + for( const JsonObject &jo_inner : jo.get_array( "passive_mult_procgen_values" ) ) { + int weight = 0; + mandatory( jo_inner, was_loaded, "weight", weight ); + relic_procgen_data::enchantment_value_passive val; + val.load( jo_inner ); + + passive_mult_procgen_values.add( val, weight ); + } + + for( const JsonObject &jo_inner : jo.get_array( "type_weights" ) ) { + int weight = 0; + mandatory( jo_inner, was_loaded, "weight", weight ); + relic_procgen_data::type val; + mandatory( jo_inner, was_loaded, "value", val ); + + type_weights.add( val, weight ); + } + + for( const JsonObject &jo_inner : jo.get_array( "items" ) ) { + int weight = 0; + mandatory( jo_inner, was_loaded, "weight", weight ); + itype_id it; + mandatory( jo_inner, was_loaded, "item", it ); + + item_weights.add( it, weight ); + } +} + +void relic_procgen_data::deserialize( JsonIn &jsin ) +{ + JsonObject jobj = jsin.get_object(); + load( jobj ); +} + void relic::load( const JsonObject &jo ) { if( jo.has_array( "active_effects" ) ) { @@ -121,3 +243,203 @@ std::vector relic::get_enchantments() const { return passive_effects; } + +int relic::power_level( const relic_procgen_id &ruleset ) const +{ + int total_power_level = 0; + for( const enchantment &ench : passive_effects ) { + total_power_level += ruleset->power_level( ench ); + } + for( const fake_spell &sp : active_effects ) { + total_power_level += ruleset->power_level( sp ); + } + return total_power_level; +} + +int relic_procgen_data::power_level( const enchantment &ench ) const +{ + int power = 0; + + for( const weighted_object> + &add_val_passive : passive_add_procgen_values ) { + int val = ench.get_value_add( add_val_passive.obj.type ); + if( val != 0 ) { + power += static_cast( add_val_passive.obj.power_per_increment ) / + static_cast( add_val_passive.obj.increment ) * val; + } + } + + for( const weighted_object> + &mult_val_passive : passive_mult_procgen_values ) { + float val = ench.get_value_multiply( mult_val_passive.obj.type ); + if( val != 0.0f ) { + power += mult_val_passive.obj.power_per_increment / mult_val_passive.obj.increment * val; + } + } + + return power; +} + +int relic_procgen_data::power_level( const fake_spell &sp ) const +{ + for( const weighted_object &vals : + active_procgen_values ) { + if( vals.obj.activated_spell == sp.id ) { + return vals.obj.calc_power( sp.level ); + } + } + return 0; +} + +item relic_procgen_data::create_item( const relic_procgen_data::generation_rules &rules ) const +{ + const itype_id *it_id = item_weights.pick(); + if( it_id == nullptr ) { + debugmsg( "ERROR: %s procgen data does not have items", id.c_str() ); + return null_item_reference(); + } + + item it( *it_id, calendar::turn ); + + it.overwrite_relic( generate( rules, *it_id ) ); + + return it; +} + +relic relic_procgen_data::generate( const relic_procgen_data::generation_rules &rules, + const itype_id &it_id ) const +{ + relic ret; + int num_attributes = 0; + int negative_attribute_power = 0; + const bool is_armor = item( it_id ).is_armor(); + + while( rules.max_attributes > num_attributes && rules.power_level > ret.power_level( id ) ) { + switch( *type_weights.pick() ) { + case relic_procgen_data::type::active_enchantment: { + const relic_procgen_data::enchantment_active *active = active_procgen_values.pick(); + if( active != nullptr ) { + fake_spell active_sp; + active_sp.id = active->activated_spell; + active_sp.level = rng( active->min_level, active->max_level ); + num_attributes++; + int power = power_level( active_sp ); + if( power < 0 ) { + if( rules.max_negative_power > negative_attribute_power ) { + break; + } + negative_attribute_power += power; + } + ret.add_active_effect( active_sp ); + } + break; + } + case relic_procgen_data::type::passive_enchantment_add: { + const relic_procgen_data::enchantment_value_passive *add = passive_add_procgen_values.pick(); + if( add != nullptr ) { + enchantment ench; + int value = rng( add->min_value, add->max_value ); + if( value == 0 ) { + break; + } + ench.add_value_add( add->type, value ); + num_attributes++; + int negative_ench_attribute = power_level( ench ); + if( negative_ench_attribute < 0 ) { + if( rules.max_negative_power > negative_attribute_power ) { + break; + } + negative_attribute_power += negative_ench_attribute; + } + if( is_armor ) { + ench.set_has( enchantment::has::WORN ); + } else { + ench.set_has( enchantment::has::WIELD ); + } + ret.add_passive_effect( ench ); + } + break; + } + case relic_procgen_data::type::passive_enchantment_mult: { + const relic_procgen_data::enchantment_value_passive *mult = + passive_mult_procgen_values.pick(); + if( mult != nullptr ) { + enchantment ench; + float value = rng( mult->min_value, mult->max_value ); + ench.add_value_mult( mult->type, value ); + num_attributes++; + int negative_ench_attribute = power_level( ench ); + if( negative_ench_attribute < 0 ) { + if( rules.max_negative_power > negative_attribute_power ) { + break; + } + negative_attribute_power += negative_ench_attribute; + } + if( is_armor ) { + ench.set_has( enchantment::has::WORN ); + } else { + ench.set_has( enchantment::has::WIELD ); + } + ret.add_passive_effect( ench ); + } + break; + } + case relic_procgen_data::type::hit_me: { + const relic_procgen_data::enchantment_active *active = passive_hit_me.pick(); + if( active != nullptr ) { + fake_spell active_sp; + active_sp.id = active->activated_spell; + active_sp.level = rng( active->min_level, active->max_level ); + num_attributes++; + enchantment ench; + ench.add_hit_me( active_sp ); + int power = power_level( ench ); + if( power < 0 ) { + if( rules.max_negative_power > negative_attribute_power ) { + break; + } + negative_attribute_power += power; + } + if( is_armor ) { + ench.set_has( enchantment::has::WORN ); + } else { + ench.set_has( enchantment::has::WIELD ); + } + ret.add_passive_effect( ench ); + } + break; + } + case relic_procgen_data::type::hit_you: { + const relic_procgen_data::enchantment_active *active = passive_hit_you.pick(); + if( active != nullptr ) { + fake_spell active_sp; + active_sp.id = active->activated_spell; + active_sp.level = rng( active->min_level, active->max_level ); + num_attributes++; + enchantment ench; + ench.add_hit_you( active_sp ); + int power = power_level( ench ); + if( power < 0 ) { + if( rules.max_negative_power > negative_attribute_power ) { + break; + } + negative_attribute_power += power; + } + if( is_armor ) { + ench.set_has( enchantment::has::WORN ); + } else { + ench.set_has( enchantment::has::WIELD ); + } + ret.add_passive_effect( ench ); + } + break; + } + case relic_procgen_data::type::last: { + debugmsg( "ERROR: invalid relic procgen type" ); + break; + } + } + } + + return ret; +} diff --git a/src/relic.h b/src/relic.h index 7d50c5391ee5c..90c3f923a43da 100644 --- a/src/relic.h +++ b/src/relic.h @@ -8,13 +8,117 @@ #include "magic.h" #include "magic_enchantment.h" #include "translations.h" +#include "weighted_list.h" class Creature; class JsonIn; class JsonObject; class JsonOut; +class relic; +class relic_procgen_data; struct tripoint; +using relic_procgen_id = string_id; + +class relic_procgen_data +{ + public: + + /* + * various procgen values for passive enchantment values + * this is a template for the ability to write a little bit + * less code and easier maintainability for additional values + */ + template + struct enchantment_value_passive { + enchant_vals::mod type; + // THIS CANNOT BE 0 + int power_per_increment = 1; + // whatever increment is used for the point values + // THIS CANNOT BE 0 + T increment = 1; + T min_value = 0; + T max_value = 0; + + int calc_power( T level ) const { + return std::round( level * static_cast( power_per_increment ) / + static_cast( increment ) ); + } + + bool was_loaded = false; + + void load( const JsonObject &jo ); + void deserialize( JsonIn &jsin ); + }; + + struct enchantment_active { + spell_id activated_spell; + // power cost of spell at level 0 + int base_power = 0; + // power cost increment per spell level increment + int power_per_increment = 1; + // number of spell levels that give the power per increment at + int increment = 1; + // min level of the spell allowed + int min_level = 0; + // max level of the spell allowed + int max_level = 0; + + int calc_power( int level ) const { + return base_power + std::round( level * + static_cast( power_per_increment ) / static_cast( increment ) ); + } + + bool was_loaded = false; + + void load( const JsonObject &jo ); + void deserialize( JsonIn &jsin ); + }; + + struct generation_rules { + // the desired power level for the generated artifact + int power_level = 0; + // the most negative (total) attributes a generated artifact can have + int max_negative_power = 0; + // the maximum number of attributes a generated artifact can have + int max_attributes = INT_MAX; + }; + + enum type { + passive_enchantment_add, + passive_enchantment_mult, + hit_you, + hit_me, + active_enchantment, + last + }; + private: + + weighted_int_list> passive_add_procgen_values; + weighted_int_list> passive_mult_procgen_values; + weighted_int_list passive_hit_you; + weighted_int_list passive_hit_me; + weighted_int_list active_procgen_values; + weighted_int_list type_weights; + weighted_int_list item_weights; + + public: + relic_procgen_id id; + + int power_level( const enchantment &ench ) const; + // power level of the active spell + int power_level( const fake_spell &sp ) const; + + item create_item( const relic_procgen_data::generation_rules &rules ) const; + relic generate( const generation_rules &rules, const itype_id &it_id ) const; + + bool was_loaded; + + static void load_relic_procgen_data( const JsonObject &jo, const std::string &src ); + void load( const JsonObject &jo, const std::string & = "" ); + void deserialize( JsonIn &jsin ); +}; + class relic { private: @@ -43,6 +147,16 @@ class relic std::vector get_enchantments() const; int modify_value( enchant_vals::mod value_type, int value ) const; + + // what is the power level of this artifact, given a specific ruleset + int power_level( const relic_procgen_id &ruleset ) const; +}; + +template struct enum_traits; + +template<> +struct enum_traits { + static constexpr relic_procgen_data::type last = relic_procgen_data::type::last; }; #endif // CATA_SRC_RELIC_H diff --git a/src/requirements.cpp b/src/requirements.cpp index 1f4328bd7e44e..2980fd08dc7f8 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -12,8 +12,8 @@ #include #include -#include "avatar.h" #include "cata_utility.h" +#include "character.h" #include "color.h" #include "debug.h" #include "game.h" @@ -643,7 +643,7 @@ std::vector requirement_data::get_folded_tools_list( int width, nc_ bool requirement_data::can_make_with_inventory( const inventory &crafting_inv, const std::function &filter, int batch, craft_flags flags ) const { - if( g->u.has_trait( trait_DEBUG_HS ) ) { + if( get_player_character().has_trait( trait_DEBUG_HS ) ) { return true; } @@ -705,7 +705,7 @@ bool quality_requirement::has( const inventory &crafting_inv, const std::function &, int, craft_flags, const std::function & ) const { - if( g->u.has_trait( trait_DEBUG_HS ) ) { + if( get_player_character().has_trait( trait_DEBUG_HS ) ) { return true; } return crafting_inv.has_quality( type, level, count ); @@ -724,7 +724,7 @@ bool tool_comp::has( const inventory &crafting_inv, const std::function &filter, int batch, craft_flags flags, const std::function &visitor ) const { - if( g->u.has_trait( trait_DEBUG_HS ) ) { + if( get_player_character().has_trait( trait_DEBUG_HS ) ) { return true; } if( !by_charges() ) { @@ -756,7 +756,7 @@ bool item_comp::has( const inventory &crafting_inv, const std::function &filter, int batch, craft_flags, const std::function & ) const { - if( g->u.has_trait( trait_DEBUG_HS ) ) { + if( get_player_character().has_trait( trait_DEBUG_HS ) ) { return true; } const int cnt = std::abs( count ) * batch; @@ -1454,14 +1454,14 @@ std::vector deduped_requirement_data::feasible_alterna } const requirement_data *deduped_requirement_data::select_alternative( - player &crafter, const std::function &filter, int batch, + Character &crafter, const std::function &filter, int batch, craft_flags flags ) const { return select_alternative( crafter, crafter.crafting_inventory(), filter, batch, flags ); } const requirement_data *deduped_requirement_data::select_alternative( - player &crafter, const inventory &inv, const std::function &filter, + Character &crafter, const inventory &inv, const std::function &filter, int batch, craft_flags flags ) const { const std::vector all_reqs = diff --git a/src/requirements.h b/src/requirements.h index a8bcefd880106..ecb8067770860 100644 --- a/src/requirements.h +++ b/src/requirements.h @@ -436,11 +436,11 @@ class deduped_requirement_data int batch = 1, craft_flags = craft_flags::none ) const; const requirement_data *select_alternative( - player &, const std::function &filter, int batch = 1, + Character &, const std::function &filter, int batch = 1, craft_flags = craft_flags::none ) const; const requirement_data *select_alternative( - player &, const inventory &, const std::function &filter, + Character &, const inventory &, const std::function &filter, int batch = 1, craft_flags = craft_flags::none ) const; bool can_make_with_inventory( diff --git a/src/rng.h b/src/rng.h index b4c07aa7e7b55..b98d2461d317e 100644 --- a/src/rng.h +++ b/src/rng.h @@ -160,13 +160,14 @@ inline V random_entry_removed( C &container ) return result; } class map; +template class tripoint_range; struct tripoint; /// Returns a range enclosing all valid points of the map. -tripoint_range points_in_range( const map &m ); +tripoint_range points_in_range( const map &m ); /// Returns a random point in the given range that satisfies the given predicate ( if any ). -cata::optional random_point( const tripoint_range &range, +cata::optional random_point( const tripoint_range &range, const std::function &predicate ); /// Same as other random_point with a range enclosing all valid points of the map. cata::optional random_point( const map &m, diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index fa3367e55eb09..bc2f4f7285b8e 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -8,8 +8,8 @@ #include #include -#include "avatar.h" #include "cata_utility.h" +#include "character.h" #include "color.h" #include "compatibility.h" #include "cursesdef.h" @@ -121,6 +121,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); } + Character &player_character = get_player_character(); ui.on_redraw( [&]( const ui_adaptor & ) { draw_border( w_border, BORDER_COLOR, custom_name_in ); @@ -201,7 +202,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) auto ¤t_tab = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; - if( tab == CHARACTER_TAB && g->u.name.empty() ) { + if( tab == CHARACTER_TAB && player_character.name.empty() ) { character_rules.clear(); mvwprintz( w, point( 15, 8 ), c_white, _( "Please load a character first to use this page!" ) ); } else if( empty() ) { @@ -269,7 +270,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } } else if( action == "QUIT" ) { break; - } else if( tab == CHARACTER_TAB && g->u.name.empty() ) { + } else if( tab == CHARACTER_TAB && player_character.name.empty() ) { //Only allow loaded games to use the char sheet } else if( action == "DOWN" ) { line++; @@ -308,7 +309,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) current_tab.push_back( current_tab[line] ); line = current_tab.size() - 1; } else if( action == "SWAP_RULE_GLOBAL_CHAR" && !current_tab.empty() ) { - if( ( tab == GLOBAL_TAB && !g->u.name.empty() ) || tab == CHARACTER_TAB ) { + if( ( tab == GLOBAL_TAB && !player_character.name.empty() ) || tab == CHARACTER_TAB ) { changes_made = true; //copy over auto &temp_rules_from = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; @@ -467,7 +468,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) if( query_yn( _( "Save changes?" ) ) ) { if( is_safemode_in ) { save_global(); - if( !g->u.name.empty() ) { + if( !player_character.name.empty() ) { save_character(); } } else { @@ -489,7 +490,8 @@ void safemode::test_pattern( const int tab_in, const int row_in ) return; } - if( g->u.name.empty() ) { + Character &player_character = get_player_character(); + if( player_character.name.empty() ) { popup( _( "No monsters loaded. Please start a game first." ) ); return; } diff --git a/src/savegame.cpp b/src/savegame.cpp index 28ff9e50bb914..f0c2d207e9ffe 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -53,7 +53,7 @@ extern std::map> quick_shortcuts_map; * Changes that break backwards compatibility should bump this number, so the game can * load a legacy format loader. */ -const int savegame_version = 29; +const int savegame_version = 30; /* * This is a global set by detected version header in .sav, maps.txt, or overmap. @@ -336,6 +336,7 @@ bool overmap::obsolete_terrain( const std::string &ter ) */ void overmap::convert_terrain( const std::unordered_map &needs_conversion ) { + std::vector bridge_points; for( const auto &convert : needs_conversion ) { const tripoint pos = convert.first; const std::string old = convert.second; @@ -350,14 +351,19 @@ void overmap::convert_terrain( const std::unordered_map & std::vector nearby; std::vector> convert_unrelated_adjacent_tiles; - if( old == "rural_house" || old == "rural_house_north" ) { - ter_set( pos, oter_id( "rural_house1_north" ) ); - } else if( old == "rural_house_south" ) { - ter_set( pos, oter_id( "rural_house1_south" ) ); - } else if( old == "rural_house_east" ) { - ter_set( pos, oter_id( "rural_house1_east" ) ); - } else if( old == "rural_house_west" ) { - ter_set( pos, oter_id( "rural_house1_west" ) ); + if( old == "fema" || old == "fema_entrance" || old == "fema_1_3" || + old == "fema_2_1" || old == "fema_2_2" || old == "fema_2_3" || + old == "fema_3_1" || old == "fema_3_2" || old == "fema_3_3" ) { + ter_set( pos, oter_id( old + "_north" ) ); + } else if( old.compare( 0, 6, "bridge" ) == 0 ) { + ter_set( pos, oter_id( old ) ); + const oter_id oter_ground = ter( tripoint( pos.xy(), 0 ) ); + const oter_id oter_above = ter( pos + tripoint_above ); + if( is_ot_match( "bridge", oter_ground, ot_match_type::type ) && + !is_ot_match( "bridge_road", oter_above, ot_match_type::type ) ) { + ter_set( pos + tripoint_above, oter_id( "bridge_road" + oter_get_rotation_string( oter_ground ) ) ); + bridge_points.emplace_back( pos.xy() ); + } } else if( old.compare( 0, 10, "mass_grave" ) == 0 ) { ter_set( pos, oter_id( "field" ) ); } @@ -376,6 +382,8 @@ void overmap::convert_terrain( const std::unordered_map & ter_set( pos + conv.first, oter_id( conv.second ) ); } } + + generate_bridgeheads( bridge_points ); } void overmap::load_monster_groups( JsonIn &jsin ) diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 67c4aa268a39d..199c386a60b45 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -197,14 +197,12 @@ void item_contents::deserialize( JsonIn &jsin ) void item_pocket::serialize( JsonOut &json ) const { - if( !contents.empty() ) { - json.start_object(); - json.member( "pocket_type", data->type ); - json.member( "contents", contents ); - json.member( "_sealed", _sealed ); - json.member( "favorite_settings", this->settings ); - json.end_object(); - } + json.start_object(); + json.member( "pocket_type", data->type ); + json.member( "contents", contents ); + json.member( "_sealed", _sealed ); + json.member( "favorite_settings", this->settings ); + json.end_object(); } void item_pocket::deserialize( JsonIn &jsin ) @@ -513,9 +511,10 @@ void Character::load( const JsonObject &data ) JsonObject vits = data.get_object( "vitamin_levels" ); for( const std::pair &v : vitamin::all() ) { - int lvl = vits.get_int( v.first.str(), 0 ); - lvl = std::max( std::min( lvl, v.first.obj().max() ), v.first.obj().min() ); - vitamin_levels[v.first] = lvl; + if( vits.has_member( v.first.str() ) ) { + int lvl = vits.get_int( v.first.str() ); + vitamin_levels[v.first] = clamp( lvl, v.first->min(), v.first->max() ); + } } data.read( "consumption_history", consumption_history ); data.read( "activity", activity ); @@ -544,7 +543,6 @@ void Character::load( const JsonObject &data ) // health data.read( "healthy", healthy ); data.read( "healthy_mod", healthy_mod ); - data.read( "healed_24h", healed_total ); // status temp_cur.fill( 5000 ); @@ -559,14 +557,16 @@ void Character::load( const JsonObject &data ) body_wetness.fill( 0 ); data.read( "body_wetness", body_wetness ); + // Remove check after 0.F + if( savegame_loading_version >= 30 ) { + data.read( "proficiencies", _proficiencies ); + } + //energy data.read( "stim", stim ); data.read( "stamina", stamina ); - data.read( "damage_bandaged", damage_bandaged ); - data.read( "damage_disinfected", damage_disinfected ); data.read( "magic", magic ); - JsonArray parray; data.read( "underwater", underwater ); @@ -575,6 +575,10 @@ void Character::load( const JsonObject &data ) const auto &tid = *it; if( tid.is_valid() ) { ++it; + // Remove after 0.F + } else if( tid == trait_id( "PROF_HELI_PILOT" ) ) { + it = my_traits.erase( it ); + add_proficiency( proficiency_id( "prof_helicopter_pilot" ) ); } else { debugmsg( "character %s has invalid trait %s, it will be ignored", name, tid.c_str() ); my_traits.erase( it++ ); @@ -606,6 +610,10 @@ void Character::load( const JsonObject &data ) on_mutation_gain( mid ); cached_mutations.push_back( &mid.obj() ); ++it; + // Remove after 0.F + } else if( mid == trait_id( "PROF_HELI_PILOT" ) ) { + it = my_mutations.erase( it ); + add_proficiency( proficiency_id( "prof_helicopter_pilot" ) ); } else { debugmsg( "character %s has invalid mutation %s, it will be ignored", name, mid.c_str() ); it = my_mutations.erase( it ); @@ -645,7 +653,42 @@ void Character::load( const JsonObject &data ) set_part_hp_cur( bodypart_id( "leg_r" ), hp_cur[5] ); set_part_hp_max( bodypart_id( "leg_r" ), hp_max[5] ); } - + if( data.has_array( "damage_bandaged" ) ) { + set_anatomy( anatomy_id( "human_anatomy" ) ); + set_body(); + std::array damage_bandaged; + data.read( "damage_bandaged", damage_bandaged ); + set_part_damage_bandaged( bodypart_id( "head" ), damage_bandaged[0] ); + set_part_damage_bandaged( bodypart_id( "torso" ), damage_bandaged[1] ); + set_part_damage_bandaged( bodypart_id( "arm_l" ), damage_bandaged[2] ); + set_part_damage_bandaged( bodypart_id( "arm_r" ), damage_bandaged[3] ); + set_part_damage_bandaged( bodypart_id( "leg_l" ), damage_bandaged[4] ); + set_part_damage_bandaged( bodypart_id( "leg_r" ), damage_bandaged[5] ); + } + if( data.has_array( "damage_disinfected" ) ) { + set_anatomy( anatomy_id( "human_anatomy" ) ); + set_body(); + std::array damage_disinfected; + data.read( "damage_disinfected", damage_disinfected ); + set_part_damage_disinfected( bodypart_id( "head" ), damage_disinfected[0] ); + set_part_damage_disinfected( bodypart_id( "torso" ), damage_disinfected[1] ); + set_part_damage_disinfected( bodypart_id( "arm_l" ), damage_disinfected[2] ); + set_part_damage_disinfected( bodypart_id( "arm_r" ), damage_disinfected[3] ); + set_part_damage_disinfected( bodypart_id( "leg_l" ), damage_disinfected[4] ); + set_part_damage_disinfected( bodypart_id( "leg_r" ), damage_disinfected[5] ); + } + if( data.has_array( "healed_24h" ) ) { + set_anatomy( anatomy_id( "human_anatomy" ) ); + set_body(); + std::array healed_total; + data.read( "healed_24h", healed_total ); + set_part_healed_total( bodypart_id( "head" ), healed_total[0] ); + set_part_healed_total( bodypart_id( "torso" ), healed_total[1] ); + set_part_healed_total( bodypart_id( "arm_l" ), healed_total[2] ); + set_part_healed_total( bodypart_id( "arm_r" ), healed_total[3] ); + set_part_healed_total( bodypart_id( "leg_l" ), healed_total[4] ); + set_part_healed_total( bodypart_id( "leg_r" ), healed_total[5] ); + } inv.clear(); if( data.has_member( "inv" ) ) { @@ -696,7 +739,7 @@ void Character::load( const JsonObject &data ) on_stat_change( "pkill", pkill ); on_stat_change( "perceived_pain", get_perceived_pain() ); recalc_sight_limits(); - reset_encumbrance(); + calc_encumbrance(); assign( data, "power_level", power_level, false, 0_kJ ); assign( data, "max_power_level", max_power_level, false, 0_kJ ); @@ -771,7 +814,6 @@ void Character::store( JsonOut &json ) const // health json.member( "healthy", healthy ); json.member( "healthy_mod", healthy_mod ); - json.member( "healed_24h", healed_total ); // status json.member( "temp_cur", temp_cur ); @@ -840,6 +882,8 @@ void Character::store( JsonOut &json ) const } json.end_object(); + json.member( "proficiencies", _proficiencies ); + // npc; unimplemented if( power_level < 1_J ) { json.member( "power_level", to_string( units::to_millijoule( power_level ) ) + " mJ" ); @@ -901,9 +945,6 @@ void player::store( JsonOut &json ) const json.member( "in_vehicle", in_vehicle ); json.member( "id", getID() ); - // potential incompatibility with future expansion - json.member( "damage_bandaged", damage_bandaged ); - json.member( "damage_disinfected", damage_disinfected ); // "Looks like I picked the wrong week to quit smoking." - Steve McCroskey json.member( "addictions", addictions ); json.member( "followers", follower_ids ); @@ -1108,6 +1149,8 @@ void avatar::store( JsonOut &json ) const json.member( "invcache" ); inv.json_save_invcache( json ); + + json.member( "calorie_diary", calorie_diary ); } void avatar::deserialize( JsonIn &jsin ) @@ -1256,6 +1299,8 @@ void avatar::load( const JsonObject &data ) JsonIn *jip = data.get_raw( "invcache" ); inv.json_load_invcache( *jip ); } + + data.read( "calorie_diary", calorie_diary ); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2406,6 +2451,8 @@ void item::deserialize( JsonIn &jsin ) } else { item_contents read_contents; data.read( "contents", read_contents ); + contents.read_mods( read_contents ); + update_modified_pockets(); contents.combine( read_contents ); if( data.has_object( "contents" ) && data.get_object( "contents" ).has_array( "items" ) ) { @@ -2515,6 +2562,14 @@ void vehicle_part::deserialize( JsonIn &jsin ) data.read( "enabled", enabled ); data.read( "flags", flags ); data.read( "passenger_id", passenger_id ); + if( data.has_int( "z_offset" ) ) { + int z_offset = data.get_int( "z_offset" ); + if( std::abs( z_offset ) > 10 ) { + data.throw_error( "z_offset out of range", "z_offset" ); + } + precalc[0].z = z_offset; + precalc[1].z = z_offset; + } JsonArray ja = data.get_array( "carry" ); // count down from size - 1, then stop after unsigned long 0 - 1 becomes MAX_INT for( size_t index = ja.size() - 1; index < ja.size(); index-- ) { @@ -2588,6 +2643,9 @@ void vehicle_part::serialize( JsonOut &json ) const } json.member( "passenger_id", passenger_id ); json.member( "crew_id", crew_id ); + if( precalc[0].z ) { + json.member( "z_offset", precalc[0].z ); + } json.member( "items", items ); if( target.first != tripoint_min ) { json.member( "target_first_x", target.first.x ); @@ -2606,20 +2664,20 @@ void vehicle_part::serialize( JsonOut &json ) const /* * label */ -static void deserialize( label &val, JsonIn &jsin ) +void label::deserialize( JsonIn &jsin ) { JsonObject data = jsin.get_object(); - data.read( "x", val.x ); - data.read( "y", val.y ); - data.read( "text", val.text ); + data.read( "x", x ); + data.read( "y", y ); + data.read( "text", text ); } -static void serialize( const label &val, JsonOut &json ) +void label::serialize( JsonOut &json ) const { json.start_object(); - json.member( "x", val.x ); - json.member( "y", val.y ); - json.member( "text", val.text ); + json.member( "x", x ); + json.member( "y", y ); + json.member( "text", text ); json.end_object(); } @@ -3288,19 +3346,19 @@ void map_memory::load( const JsonObject &jsin ) } } -void deserialize( point &p, JsonIn &jsin ) +void point::deserialize( JsonIn &jsin ) { jsin.start_array(); - p.x = jsin.get_int(); - p.y = jsin.get_int(); + x = jsin.get_int(); + y = jsin.get_int(); jsin.end_array(); } -void serialize( const point &p, JsonOut &jsout ) +void point::serialize( JsonOut &jsout ) const { jsout.start_array(); - jsout.write( p.x ); - jsout.write( p.y ); + jsout.write( x ); + jsout.write( y ); jsout.end_array(); } diff --git a/src/scent_map.cpp b/src/scent_map.cpp index a29c807c3a438..905b685bea3c0 100644 --- a/src/scent_map.cpp +++ b/src/scent_map.cpp @@ -134,7 +134,7 @@ bool scent_map::inbounds( const tripoint &p ) const const int levz = gm.get_levz(); const bool scent_map_z_level_inbounds = ( p.z == levz ) || ( std::abs( p.z - levz ) == SCENT_MAP_Z_REACH && - gm.m.valid_move( p, tripoint( p.xy(), levz ), false, true ) ); + get_map().valid_move( p, tripoint( p.xy(), levz ), false, true ) ); if( !scent_map_z_level_inbounds ) { return false; } diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index 033ac1fe16bcb..646187eaa54e5 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -1250,7 +1250,7 @@ void cata_cursesport::curses_drawwindow( const catacurses::window &w ) clear_window_area( w ); tilecontext->draw_minimap( point( win->pos.x * fontwidth, win->pos.y * fontheight ), - tripoint( g->u.pos().xy(), g->ter_view_p.z ), + tripoint( get_player_character().pos().xy(), g->ter_view_p.z ), win->width * font->fontwidth, win->height * font->fontheight ); update = true; @@ -1854,7 +1854,8 @@ input_context touch_input_context; std::string get_quick_shortcut_name( const std::string &category ) { - if( category == "DEFAULTMODE" && g->check_zone( zone_type_id( "NO_AUTO_PICKUP" ), g->u.pos() ) && + if( category == "DEFAULTMODE" && + g->check_zone( zone_type_id( "NO_AUTO_PICKUP" ), get_player_character().pos() ) && get_option( "ANDROID_SHORTCUT_ZONE" ) ) { return "DEFAULTMODE____SHORTCUTS"; } @@ -2112,10 +2113,11 @@ void remove_stale_inventory_quick_shortcuts() valid = inv_chars.valid( key ); in_inventory = false; if( valid ) { - in_inventory = g->u.inv.invlet_to_position( key ) != INT_MIN; + Character &player_character = get_player_character(); + in_inventory = player_character.inv.invlet_to_position( key ) != INT_MIN; if( !in_inventory ) { // We couldn't find this item in the inventory, let's check worn items - for( const auto &item : g->u.worn ) { + for( const auto &item : player_character.worn ) { if( item.invlet == key ) { in_inventory = true; break; @@ -2124,7 +2126,7 @@ void remove_stale_inventory_quick_shortcuts() } if( !in_inventory ) { // We couldn't find it in worn items either, check weapon held - if( g->u.weapon.invlet == key ) { + if( player_character.weapon.invlet == key ) { in_inventory = true; } } @@ -2244,11 +2246,13 @@ void draw_quick_shortcuts() std::string hint_text; if( show_hint ) { if( touch_input_context.get_category() == "INVENTORY" && inv_chars.valid( key ) ) { + Character &player_character = get_player_character(); // Special case for inventory items - show the inventory item name as help text - hint_text = g->u.inv.find_item( g->u.inv.invlet_to_position( key ) ).display_name(); + hint_text = player_character.inv.find_item( player_character.inv.invlet_to_position( + key ) ).display_name(); if( hint_text == "none" ) { // We couldn't find this item in the inventory, let's check worn items - for( const auto &item : g->u.worn ) { + for( const auto &item : player_character.worn ) { if( item.invlet == key ) { hint_text = item.display_name(); break; @@ -2257,8 +2261,8 @@ void draw_quick_shortcuts() } if( hint_text == "none" ) { // We couldn't find it in worn items either, must be weapon held - if( g->u.weapon.invlet == key ) { - hint_text = g->u.weapon.display_name(); + if( player_character.weapon.invlet == key ) { + hint_text = player_character.weapon.display_name(); } } } else { @@ -2627,24 +2631,25 @@ static void CheckMessages() // Actions to remove - we only want to remove things that we're 100% sure won't be useful to players otherwise std::set actions_remove; + Character &player_character = get_player_character(); // Check if we're in a potential combat situation, if so, sort a few actions to the top. - if( !g->u.get_hostile_creatures( 60 ).empty() ) { + if( !player_character.get_hostile_creatures( 60 ).empty() ) { // Only prioritize movement options if we're not driving. - if( !g->u.controlling_vehicle ) { + if( !player_character.controlling_vehicle ) { actions.insert( ACTION_CYCLE_MOVE ); } // Only prioritize fire weapon options if we're wielding a ranged weapon. - if( g->u.weapon.is_gun() || g->u.weapon.has_flag( "REACH_ATTACK" ) ) { + if( player_character.weapon.is_gun() || player_character.weapon.has_flag( "REACH_ATTACK" ) ) { actions.insert( ACTION_FIRE ); } } // If we're already running, make it simple to toggle running to off. - if( g->u.is_running() ) { + if( player_character.is_running() ) { actions.insert( ACTION_TOGGLE_RUN ); } // If we're already crouching, make it simple to toggle crouching to off. - if( g->u.is_crouching() ) { + if( player_character.is_crouching() ) { actions.insert( ACTION_TOGGLE_CROUCH ); } @@ -2658,9 +2663,9 @@ static void CheckMessages() // display that action at the top of the list. for( int dx = -1; dx <= 1; dx++ ) { for( int dy = -1; dy <= 1; dy++ ) { - int x = g->u.posx() + dx; - int y = g->u.posy() + dy; - int z = g->u.posz(); + int x = player_character.posx() + dx; + int y = player_character.posy() + dy; + int z = player_character.posz(); const tripoint pos( x, y, z ); // Check if we're near a vehicle, if so, vehicle controls should be top. @@ -2757,12 +2762,12 @@ static void CheckMessages() } // Check if we're significantly hungry or thirsty - if so, add eat - if( g->u.get_hunger() > 100 || g->u.get_thirst() > 40 ) { + if( player_character.get_hunger() > 100 || player_character.get_thirst() > 40 ) { actions.insert( ACTION_EAT ); } // Check if we're dead tired - if so, add sleep - if( g->u.get_fatigue() > fatigue_levels::DEAD_TIRED ) { + if( player_character.get_fatigue() > fatigue_levels::DEAD_TIRED ) { actions.insert( ACTION_SLEEP ); } diff --git a/src/shadowcasting.h b/src/shadowcasting.h index 2ab0fa3311935..a3be0fd69f467 100644 --- a/src/shadowcasting.h +++ b/src/shadowcasting.h @@ -50,7 +50,7 @@ struct four_quadrants { friend four_quadrants operator*( const four_quadrants &l, const four_quadrants &r ) { four_quadrants result; std::transform( l.values.begin(), l.values.end(), r.values.begin(), - result.values.begin(), std::multiplies() ); + result.values.begin(), std::multiplies<>() ); return result; } diff --git a/src/simple_pathfinding.h b/src/simple_pathfinding.h index a9dabd0c6f551..1afdc3a7163f1 100644 --- a/src/simple_pathfinding.h +++ b/src/simple_pathfinding.h @@ -8,18 +8,20 @@ #include "enums.h" #include "point.h" +#include "point_traits.h" namespace pf { static const int rejected = std::numeric_limits::min(); +template struct node { - point pos; + Point pos; int dir; int priority; - node( const point &p, int dir, int priority = 0 ) : + node( const Point &p, int dir, int priority = 0 ) : pos( p ), dir( dir ), priority( priority ) {} @@ -30,8 +32,9 @@ struct node { } }; +template struct path { - std::vector nodes; + std::vector> nodes; }; /** @@ -42,21 +45,26 @@ struct path { * integer estimation (smaller - better) for the current node or a negative value * if the node is unsuitable. */ -template -path find_path( const point &source, - const point &dest, - const point &max, - BinaryPredicate estimator ) +template +path find_path( const Point &source, + const Point &dest, + const Point &max, + BinaryPredicate estimator ) { - const auto inbounds = [ max ]( const point & p ) { - return p.x >= 0 && p.x < max.x && p.y >= 0 && p.y < max.y; + static_assert( Point::dimension == 2, "This pathfinding function doesn't work for tripoints" ); + using Traits = point_traits; + using Node = node; + + const auto inbounds = [ max ]( const Point & p ) { + return Traits::x( p ) >= 0 && Traits::x( p ) < Traits::x( max ) && + Traits::y( p ) >= 0 && Traits::y( p ) < Traits::y( max ); }; - const auto map_index = [ max ]( const point & p ) { - return p.y * max.x + p.x; + const auto map_index = [ max ]( const Point & p ) { + return Traits::y( p ) * Traits::x( max ) + Traits::x( p ); }; - path res; + path res; if( source == dest ) { return res; @@ -66,18 +74,18 @@ path find_path( const point &source, return res; } - const node first_node( source, 5, 1000 ); + const Node first_node( source, 5, 1000 ); if( estimator( first_node, nullptr ) == rejected ) { return res; } - const size_t map_size = max.x * max.y; + const size_t map_size = Traits::x( max ) * Traits::y( max ); std::vector closed( map_size, false ); std::vector open( map_size, 0 ); std::vector dirs( map_size, 0 ); - std::priority_queue> nodes[2]; + std::priority_queue> nodes[2]; int i = 0; nodes[i].push( first_node ); @@ -85,7 +93,7 @@ path find_path( const point &source, // use A* to find the shortest path from (x1,y1) to (x2,y2) while( !nodes[i].empty() ) { - const node mn( nodes[i].top() ); // get the best-looking node + const Node mn( nodes[i].top() ); // get the best-looking node nodes[i].pop(); // mark it visited @@ -93,7 +101,7 @@ path find_path( const point &source, // if we've reached the end, draw the path and return if( mn.pos == dest ) { - point p = mn.pos; + Point p = mn.pos; res.nodes.reserve( nodes[i].size() ); @@ -110,7 +118,7 @@ path find_path( const point &source, } for( int dir = 0; dir < 4; dir++ ) { - const point p = mn.pos + four_adjacent_offsets[dir]; + const Point p = mn.pos + four_adjacent_offsets[dir]; const int n = map_index( p ); // don't allow: // * out of bounds @@ -119,7 +127,7 @@ path find_path( const point &source, continue; } - node cn( p, dir ); + Node cn( p, dir ); cn.priority = estimator( cn, &mn ); if( cn.priority == rejected ) { @@ -154,17 +162,16 @@ path find_path( const point &source, return res; } -inline path straight_path( const point &source, - int dir, - size_t len ) +template +inline path straight_path( const Point &source, int dir, size_t len ) { - path res; + path res; if( len == 0 ) { return res; } - point p = source; + Point p = source; res.nodes.reserve( len ); diff --git a/src/sounds.cpp b/src/sounds.cpp index 0d48fc898703e..c12da23fb3722 100644 --- a/src/sounds.cpp +++ b/src/sounds.cpp @@ -11,9 +11,9 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" +#include "character.h" #include "coordinate_conversions.h" #include "creature.h" #include "debug.h" @@ -61,7 +61,7 @@ # define dbg(x) DebugLog((x),D_SDL) << __FILE__ << ":" << __LINE__ << ": " #endif -weather_type previous_weather; +weather_type_id previous_weather; int prev_hostiles = 0; int previous_speed = 0; int previous_gear = 0; @@ -278,7 +278,7 @@ static int get_signal_for_hordes( const centroid ¢r ) { //Volume in tiles. Signal for hordes in submaps //modify vol using weather vol.Weather can reduce monster hearing - const int vol = centr.volume - weather::sound_attn( get_weather().weather ); + const int vol = centr.volume - get_weather().weather_id->sound_attn; const int min_vol_cap = 60; //Hordes can't hear volume lower than this const int underground_div = 2; //Coefficient for volume reduction underground const int hordes_sig_div = SEEX; //Divider coefficient for hordes @@ -302,7 +302,7 @@ static int get_signal_for_hordes( const centroid ¢r ) void sounds::process_sounds() { std::vector sound_clusters = cluster_sounds( recent_sounds ); - const int weather_vol = weather::sound_attn( get_weather().weather ); + const int weather_vol = get_weather().weather_id->sound_attn; for( const auto &this_centroid : sound_clusters ) { // Since monsters don't go deaf ATM we can just use the weather modified volume // If they later get physical effects from loud noises we'll have to change this @@ -384,7 +384,7 @@ void sounds::process_sound_markers( player *p ) { bool is_deaf = p->is_deaf(); const float volume_multiplier = p->hearing_ability(); - const int weather_vol = weather::sound_attn( get_weather().weather ); + const int weather_vol = get_weather().weather_id->sound_attn; for( const auto &sound_event_pair : sounds_since_last_turn ) { const tripoint &pos = sound_event_pair.first; const sound_event &sound = sound_event_pair.second; @@ -647,7 +647,7 @@ int sfx::set_channel_volume( channel channel, int volume ) void sfx::do_vehicle_engine_sfx() { static const channel ch = channel::interior_engine_sound; - const avatar &player_character = get_avatar(); + const Character &player_character = get_player_character(); if( !player_character.in_vehicle ) { fade_audio_channel( ch, 300 ); add_msg( m_debug, "STOP interior_engine_sound, OUT OF CAR" ); @@ -768,7 +768,7 @@ void sfx::do_vehicle_exterior_engine_sfx() { static const channel ch = channel::exterior_engine_sound; static const int ch_int = static_cast( ch ); - const avatar &player_character = get_avatar(); + const Character &player_character = get_player_character(); // early bail-outs for efficiency if( player_character.in_vehicle ) { fade_audio_channel( ch, 300 ); @@ -855,7 +855,7 @@ void sfx::do_vehicle_exterior_engine_sfx() void sfx::do_ambient() { - const avatar &player_character = get_avatar(); + const Character &player_character = get_player_character(); if( player_character.in_sleep_state() && !audio_muted ) { fade_audio_channel( channel::any, 300 ); audio_muted = true; @@ -868,7 +868,7 @@ void sfx::do_ambient() const int heard_volume = get_heard_volume( player_character.pos() ); const bool is_underground = player_character.pos().z < 0; const bool is_sheltered = g->is_sheltered( player_character.pos() ); - const bool weather_changed = get_weather().weather != previous_weather; + const bool weather_changed = get_weather().weather_id != previous_weather; // Step in at night time / we are not indoors if( is_night( calendar::turn ) && !is_sheltered && !is_channel_playing( channel::nighttime_outdoors_env ) && !is_deaf ) { @@ -900,15 +900,15 @@ void sfx::do_ambient() play_ambient_variant_sound( "environment", "indoors", heard_volume, channel::indoors_env, 1000 ); } - weather_type current_weather = get_weather().weather; // We are indoors and it is also raining - if( current_weather >= WEATHER_DRIZZLE && current_weather <= WEATHER_ACID_RAIN && - !is_underground - && is_sheltered && !is_channel_playing( channel::indoors_rain_env ) ) { + if( get_weather().weather_id->rains && + get_weather().weather_id->precip != precip_class::very_light && + !is_underground && is_sheltered && !is_channel_playing( channel::indoors_rain_env ) ) { play_ambient_variant_sound( "environment", "indoors_rain", heard_volume, channel::indoors_rain_env, 1000 ); } - if( ( !is_sheltered && current_weather != WEATHER_CLEAR && !is_deaf && + if( ( !is_sheltered && + get_weather().weather_id->sound_category != weather_sound_category::silent && !is_deaf && !is_channel_playing( channel::outdoors_snow_env ) && !is_channel_playing( channel::outdoors_flurry_env ) && !is_channel_playing( channel::outdoors_thunderstorm_env ) && @@ -919,51 +919,45 @@ void sfx::do_ambient() weather_changed && !is_deaf ) ) { fade_audio_group( group::weather, 1000 ); // We are outside and there is precipitation - switch( current_weather ) { - case WEATHER_ACID_DRIZZLE: - case WEATHER_DRIZZLE: - case WEATHER_LIGHT_DRIZZLE: + switch( get_weather().weather_id->sound_category ) { + case weather_sound_category::drizzle: play_ambient_variant_sound( "environment", "WEATHER_DRIZZLE", heard_volume, channel::outdoors_drizzle_env, 1000 ); break; - case WEATHER_RAINY: + case weather_sound_category::rainy: play_ambient_variant_sound( "environment", "WEATHER_RAINY", heard_volume, channel::outdoors_rain_env, 1000 ); break; - case WEATHER_ACID_RAIN: - case WEATHER_THUNDER: - case WEATHER_LIGHTNING: + case weather_sound_category::thunder: play_ambient_variant_sound( "environment", "WEATHER_THUNDER", heard_volume, channel::outdoors_thunderstorm_env, 1000 ); break; - case WEATHER_FLURRIES: + case weather_sound_category::flurries: play_ambient_variant_sound( "environment", "WEATHER_FLURRIES", heard_volume, channel::outdoors_flurry_env, 1000 ); break; - case WEATHER_CLEAR: - case WEATHER_SUNNY: - case WEATHER_CLOUDY: - case WEATHER_SNOWSTORM: + case weather_sound_category::snowstorm: play_ambient_variant_sound( "environment", "WEATHER_SNOWSTORM", heard_volume, channel::outdoor_blizzard, 1000 ); break; - case WEATHER_SNOW: + case weather_sound_category::snow: play_ambient_variant_sound( "environment", "WEATHER_SNOW", heard_volume, channel::outdoors_snow_env, 1000 ); break; - case WEATHER_NULL: - case NUM_WEATHER_TYPES: - // nothing here, those are pseudo-types, they should not be active at all. + case weather_sound_category::silent: + break; + case weather_sound_category::last: + debugmsg( "Invalid weather sound category." ); break; } } // Keep track of weather to compare for next iteration - previous_weather = current_weather; + previous_weather = get_weather().weather_id; } // firing is the item that is fired. It may be the wielded gun, but it can also be an attached @@ -986,7 +980,7 @@ void sfx::generate_gun_sound( const player &source_arg, const item &firing ) int angle = 0; int distance = 0; std::string selected_sound; - const avatar &player_character = get_avatar(); + const Character &player_character = get_player_character(); // this does not mean p == avatar (it could be a vehicle turret) if( player_character.pos() == source ) { selected_sound = "fire_gun"; @@ -1066,9 +1060,10 @@ sfx::sound_thread::sound_thread( const tripoint &source, const tripoint &target, { // This is function is run in the main thread. const int heard_volume = get_heard_volume( source ); - const player *p = g->critter_at( source ); - if( !p ) { - p = &g->u; + npc *np = g->critter_at( source ); + const player &p = np ? static_cast( *np ) : + dynamic_cast( get_player_character() ); + if( !p.is_npc() ) { // sound comes from the same place as the player is, calculation of angle wouldn't work ang_src = 0; vol_src = heard_volume; @@ -1079,8 +1074,8 @@ sfx::sound_thread::sound_thread( const tripoint &source, const tripoint &target, vol_targ = std::max( heard_volume - 20, 0 ); } ang_targ = get_heard_angle( target ); - weapon_skill = p->weapon.melee_skill(); - weapon_volume = p->weapon.volume() / units::legacy_volume_factor; + weapon_skill = p.weapon.melee_skill(); + weapon_volume = p.weapon.volume() / units::legacy_volume_factor; } // Operator overload required for thread API. @@ -1167,7 +1162,7 @@ void sfx::do_projectile_hit( const Creature &target ) play_variant_sound( "bullet_hit", "hit_flesh", heard_volume, angle, 0.8, 1.2 ); } -void sfx::do_player_death_hurt( const player &target, bool death ) +void sfx::do_player_death_hurt( const Character &target, bool death ) { int heard_volume = get_heard_volume( target.pos() ); const bool male = target.male; @@ -1184,7 +1179,7 @@ void sfx::do_player_death_hurt( const player &target, bool death ) void sfx::do_danger_music() { - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); if( player_character.in_sleep_state() && !audio_muted ) { fade_audio_channel( channel::any, 100 ); audio_muted = true; @@ -1235,7 +1230,7 @@ void sfx::do_danger_music() void sfx::do_fatigue() { - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); /*15: Stamina 75% 16: Stamina 50% 17: Stamina 25%*/ @@ -1315,7 +1310,7 @@ void sfx::do_footstep() end_sfx_timestamp = std::chrono::high_resolution_clock::now(); sfx_time = end_sfx_timestamp - start_sfx_timestamp; if( std::chrono::duration_cast ( sfx_time ).count() > 400 ) { - const avatar &player_character = get_avatar(); + const Character &player_character = get_player_character(); int heard_volume = sfx::get_heard_volume( player_character.pos() ); const auto terrain = get_map().ter( player_character.pos() ).id(); static const std::set grass = { @@ -1446,7 +1441,7 @@ void sfx::do_footstep() void sfx::do_obstacle( const std::string &obst ) { - int heard_volume = sfx::get_heard_volume( get_avatar().pos() ); + int heard_volume = sfx::get_heard_volume( get_player_character().pos() ); if( sfx::has_variant_sound( "plmove", obst ) ) { play_variant_sound( "plmove", obst, heard_volume, 0, 0.8, 1.2 ); } else if( ter_str_id( obst ).is_valid() && @@ -1460,7 +1455,7 @@ void sfx::do_obstacle( const std::string &obst ) void sfx::play_activity_sound( const std::string &id, const std::string &variant, int volume ) { - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); if( act != player_character.activity.id() ) { act = player_character.activity.id(); play_ambient_variant_sound( id, variant, volume, channel::player_activities, 0 ); @@ -1513,7 +1508,7 @@ bool sfx::has_variant_sound( const std::string &, const std::string & ) } void sfx::stop_sound_effect_fade( channel, int ) { } void sfx::stop_sound_effect_timed( channel, int ) {} -void sfx::do_player_death_hurt( const player &, bool ) { } +void sfx::do_player_death_hurt( const Character &, bool ) { } void sfx::do_fatigue() { } void sfx::do_obstacle( const std::string & ) { } /*@}*/ @@ -1525,7 +1520,7 @@ void sfx::do_obstacle( const std::string & ) { } /*@{*/ int sfx::get_heard_volume( const tripoint &source ) { - int distance = sound_distance( get_avatar().pos(), source ); + int distance = sound_distance( get_player_character().pos(), source ); // fract = -100 / 24 const float fract = -4.166666; int heard_volume = fract * distance - 1 + 100; @@ -1538,7 +1533,7 @@ int sfx::get_heard_volume( const tripoint &source ) int sfx::get_heard_angle( const tripoint &source ) { - int angle = coord_to_angle( get_avatar().pos(), source ) + 90; + int angle = coord_to_angle( get_player_character().pos(), source ) + 90; //add_msg(m_warning, "angle: %i", angle); return ( angle ); } diff --git a/src/sounds.h b/src/sounds.h index 1420f41702410..e33d1ab20fd1c 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -6,6 +6,7 @@ #include #include +class Character; class Creature; class JsonObject; class item; @@ -157,7 +158,7 @@ bool has_variant_sound( const std::string &id, const std::string &variant ); void stop_sound_effect_fade( channel channel, int duration ); void stop_sound_effect_timed( channel channel, int time ); int set_channel_volume( channel channel, int volume ); -void do_player_death_hurt( const player &target, bool death ); +void do_player_death_hurt( const Character &target, bool death ); void do_fatigue(); // @param obst should be string id of obstacle terrain or vehicle part void do_obstacle( const std::string &obst = "" ); diff --git a/src/start_location.cpp b/src/start_location.cpp index f4d7060f2c1be..17060dc6a3d2d 100644 --- a/src/start_location.cpp +++ b/src/start_location.cpp @@ -117,7 +117,7 @@ static void add_boardable( const map &m, const tripoint &p, std::vector &range ) { std::vector furnitures1; std::vector furnitures2; @@ -159,9 +159,10 @@ static void board_up( map &m, const tripoint_range &range ) continue; } // If the furniture is movable and the character can move it, use it to barricade - // g->u is workable here as NPCs by definition are not starting the game. (Let's hope.) + // is workable here as NPCs by definition are not starting the game. (Let's hope.) ///\EFFECT_STR determines what furniture might be used as a starting area barricade - if( m.furn( p ).obj().is_movable() && m.furn( p ).obj().move_str_req < g->u.get_str() ) { + if( m.furn( p ).obj().is_movable() && + m.furn( p ).obj().move_str_req < get_player_character().get_str() ) { if( m.furn( p ).obj().movecost == 0 ) { // Obstacles are better, prefer them furnitures1.push_back( p ); @@ -288,13 +289,13 @@ static int rate_location( map &m, const tripoint &p, const bool must_be_inside, void start_location::place_player( player &u ) const { // Need the "real" map with it's inside/outside cache and the like. - map &m = g->m; + map &here = get_map(); // Start us off somewhere in the center of the map u.setx( HALF_MAPSIZE_X ); u.sety( HALF_MAPSIZE_Y ); u.setz( g->get_levz() ); - m.invalidate_map_cache( m.get_abs_sub().z ); - m.build_map_cache( m.get_abs_sub().z ); + here.invalidate_map_cache( here.get_abs_sub().z ); + here.build_map_cache( here.get_abs_sub().z ); const bool must_be_inside = flags().count( "ALLOW_OUTSIDE" ) == 0; ///\EFFECT_STR allows player to start behind less-bashable furniture and terrain // TODO: Allow using items here @@ -315,7 +316,7 @@ void start_location::place_player( player &u ) const int tries = 0; const auto check_spot = [&]( const tripoint & pt ) { tries++; - const int rate = rate_location( m, pt, must_be_inside, bash, tries, checked ); + const int rate = rate_location( here, pt, must_be_inside, bash, tries, checked ); if( best_rate < rate ) { best_rate = rate; u.setpos( pt ); @@ -355,7 +356,8 @@ void start_location::burn( const tripoint &omtstart, const size_t count, const i tinymap m; m.load( player_location, false ); m.build_outside_cache( m.get_abs_sub().z ); - const point u( g->u.posx() % HALF_MAPSIZE_X, g->u.posy() % HALF_MAPSIZE_Y ); + point player_pos = get_player_character().pos().xy(); + const point u( player_pos.x % HALF_MAPSIZE_X, player_pos.y % HALF_MAPSIZE_Y ); std::vector valid; for( const tripoint &p : m.points_on_zlevel() ) { if( !( m.has_flag_ter( "DOOR", p ) || diff --git a/src/stomach.cpp b/src/stomach.cpp index a3c31c9ecbb64..3c5c24c9b99f7 100644 --- a/src/stomach.cpp +++ b/src/stomach.cpp @@ -18,6 +18,16 @@ static const trait_id trait_GOURMAND( "GOURMAND" ); static const trait_id trait_HIBERNATE( "HIBERNATE" ); static const trait_id trait_SLIMESPAWNER( "SLIMESPAWNER" ); +//size mutations now affect this, so we have to define them first +static const trait_id trait_SMALL( "SMALL" ); +static const trait_id trait_SMALL2( "SMALL2" ); +static const trait_id trait_SMALL_OK( "SMALL_OK" ); +static const trait_id trait_LARGE( "LARGE" ); +static const trait_id trait_LARGE_OK( "LARGE_OK" ); +static const trait_id trait_HUGE( "HUGE" ); +static const trait_id trait_HUGE_OK( "HUGE_OK" ); +//done defining, the new things start at line 184 + void nutrients::min_in_place( const nutrients &r ) { kcal = std::min( kcal, r.kcal ); @@ -170,6 +180,30 @@ units::volume stomach_contents::capacity( const Character &owner ) const if( owner.has_trait( trait_SLIMESPAWNER ) ) { max_mod *= 3; } + + //Huge, for example, makes you roughly x2 larger, so stomach size is doubled + //The scientifically correct approach would be x8 stomach size, due to square-cube law, but that would break the game + //The same 'square-cube law is ignored for balance' reasoning is applied to the other size category mutations + // -ungen + + //else if because they're mutually exclusive, that way we save a lot of uneccesary checks -ungen + if( owner.has_trait( trait_SMALL_OK ) ) { + max_mod *= 0.5; + } else if( owner.has_trait( trait_SMALL2 ) ) { + max_mod *= 0.5; + } else if( owner.has_trait( trait_SMALL ) ) { + max_mod *= 0.75; + } else if( owner.has_trait( trait_LARGE ) ) { + max_mod *= 1.5; + } else if( owner.has_trait( trait_LARGE_OK ) ) { + max_mod *= 1.5; + } else if( owner.has_trait( trait_HUGE ) ) { + max_mod *= 2; + } else if( owner.has_trait( trait_HUGE_OK ) ) { + max_mod *= 2; + } + //I thought this would be a lot harder to code, boy I was wrong -ungen + return max_volume * max_mod; } diff --git a/src/submap.cpp b/src/submap.cpp index f01fda2f6a081..bffdd1c0d00e3 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -160,7 +160,7 @@ void submap::update_legacy_computer() if( legacy_computer ) { for( int x = 0; x < SEEX; ++x ) { for( int y = 0; y < SEEY; ++y ) { - if( ter[x][y] == t_console ) { + if( frn[x][y] == furn_str_id( "f_console" ) ) { computers.emplace( point( x, y ), *legacy_computer ); } } @@ -171,7 +171,8 @@ void submap::update_legacy_computer() bool submap::has_computer( const point &p ) const { - return computers.find( p ) != computers.end() || ( legacy_computer && ter[p.x][p.y] == t_console ); + return computers.find( p ) != computers.end() || ( legacy_computer && frn[p.x][p.y] + == furn_str_id( "f_console" ) ); } const computer *submap::get_computer( const point &p ) const @@ -182,7 +183,7 @@ const computer *submap::get_computer( const point &p ) const if( it != computers.end() ) { return &it->second; } - if( legacy_computer && ter[p.x][p.y] == t_console ) { + if( legacy_computer && frn[p.x][p.y] == furn_str_id( "f_console" ) ) { return legacy_computer.get(); } return nullptr; @@ -192,7 +193,7 @@ computer *submap::get_computer( const point &p ) { // need to update to std::map first so modifications to the returned object // only affects the exact point p - update_legacy_computer(); + //update_legacy_computer(); const auto it = computers.find( p ); if( it != computers.end() ) { return &it->second; @@ -202,7 +203,7 @@ computer *submap::get_computer( const point &p ) void submap::set_computer( const point &p, const computer &c ) { - update_legacy_computer(); + //update_legacy_computer(); const auto it = computers.find( p ); if( it != computers.end() ) { it->second = c; diff --git a/src/suffer.cpp b/src/suffer.cpp index 481490761e772..e55970da33e56 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -13,7 +13,6 @@ #include #include "addiction.h" -#include "avatar.h" #include "bodypart.h" #include "calendar.h" #include "cata_utility.h" @@ -166,6 +165,7 @@ static const std::string flag_BLIND( "BLIND" ); static const std::string flag_PLOWABLE( "PLOWABLE" ); static const std::string flag_RAD_RESIST( "RAD_RESIST" ); static const std::string flag_SUN_GLASSES( "SUN_GLASSES" ); +static const std::string flag_TOURNIQUET( "TOURNIQUET" ); static float addiction_scaling( float at_min, float at_max, float add_lvl ) { @@ -262,7 +262,7 @@ void Character::suffer_while_underwater() apply_damage( nullptr, bodypart_id( "torso" ), rng( 1, 4 ) ); } } - if( has_trait( trait_FRESHWATEROSMOSIS ) && !g->m.has_flag_ter( "SALT_WATER", pos() ) && + if( has_trait( trait_FRESHWATEROSMOSIS ) && !get_map().has_flag_ter( "SALT_WATER", pos() ) && get_thirst() > -60 ) { mod_thirst( -1 ); } @@ -630,9 +630,11 @@ void Character::suffer_from_asthma( const int current_stim ) add_msg_player_or_npc( m_bad, _( "You have an asthma attack!" ), " starts wheezing and coughing." ); + map &here = get_map(); if( in_sleep_state() && !has_effect( effect_narcosis ) ) { inventory map_inv; - map_inv.form_from_map( g->u.pos(), 2, &g->u ); + Character &player_character = get_player_character(); + map_inv.form_from_map( player_character.pos(), 2, &player_character ); // check if an inhaler is somewhere near bool nearby_use = auto_use || oxygenator || map_inv.has_charges( itype_inhaler, 1 ) || map_inv.has_charges( itype_oxygen_tank, 1 ) || @@ -653,10 +655,10 @@ void Character::suffer_from_asthma( const int current_stim ) } else if( nearby_use ) { // create new variable to resolve a reference issue int amount = 1; - if( !g->m.use_charges( g->u.pos(), 2, itype_inhaler, amount ).empty() ) { + if( !here.use_charges( player_character.pos(), 2, itype_inhaler, amount ).empty() ) { add_msg_if_player( m_info, _( "You use your inhaler and go back to sleep." ) ); - } else if( !g->m.use_charges( g->u.pos(), 2, itype_oxygen_tank, amount ).empty() || - !g->m.use_charges( g->u.pos(), 2, itype_smoxygen_tank, amount ).empty() ) { + } else if( !here.use_charges( player_character.pos(), 2, itype_oxygen_tank, amount ).empty() || + !here.use_charges( player_character.pos(), 2, itype_smoxygen_tank, amount ).empty() ) { add_msg_if_player( m_info, _( "You take a deep breath from your oxygen tank " "and go back to sleep." ) ); } @@ -718,10 +720,10 @@ void Character::suffer_in_sunlight() const bool leafier = has_trait( trait_LEAVES2 ) || has_trait( trait_LEAVES3 ); const bool leafiest = has_trait( trait_LEAVES3 ); int sunlight_nutrition = 0; - if( leafy && g->m.is_outside( pos() ) && ( g->light_level( pos().z ) >= 40 ) ) { - const float weather_factor = ( g->weather.weather == WEATHER_CLEAR || - g->weather.weather == WEATHER_SUNNY ) ? 1.0 : 0.5; - const int player_local_temp = g->weather.get_temperature( pos() ); + if( leafy && get_map().is_outside( pos() ) && ( g->light_level( pos().z ) >= 40 ) ) { + const float weather_factor = ( get_weather().weather_id->sun_intensity >= + sun_intensity_type::normal ) ? 1.0 : 0.5; + const int player_local_temp = get_weather().get_temperature( pos() ); int flux = ( player_local_temp - 65 ) / 2; if( !has_hat ) { sunlight_nutrition += ( 100 + flux ) * weather_factor; @@ -764,7 +766,7 @@ void Character::suffer_in_sunlight() } if( ( has_trait( trait_TROGLO ) || has_trait( trait_TROGLO2 ) ) && - g->weather.weather == WEATHER_SUNNY ) { + get_weather().weather_id->sun_intensity >= sun_intensity_type::high ) { mod_str_bonus( -1 ); mod_dex_bonus( -1 ); add_miss_reason( _( "The sunlight distracts you." ), 1 ); @@ -829,7 +831,7 @@ void Character::suffer_from_albinism() continue; } //percent of "not covered skin" - float p = 1.0 - i.get_coverage() / 100.0; + float p = 1.0 - i.get_coverage( bp ) / 100.0; open_percent[bp->token] = open_percent[bp->token] * p; } } @@ -882,9 +884,10 @@ void Character::suffer_from_albinism() void Character::suffer_from_other_mutations() { + map &here = get_map(); if( has_trait( trait_SHARKTEETH ) && one_turn_in( 24_hours ) ) { add_msg_if_player( m_neutral, _( "You shed a tooth!" ) ); - g->m.spawn_item( pos(), "bone", 1 ); + here.spawn_item( pos(), "bone", 1 ); } if( has_active_mutation( trait_WINGS_INSECT ) ) { @@ -896,7 +899,7 @@ void Character::suffer_from_other_mutations() bool wearing_shoes = is_wearing_shoes( side::LEFT ) || is_wearing_shoes( side::RIGHT ); int root_vitamins = 0; int root_water = 0; - if( has_trait( trait_ROOTS3 ) && g->m.has_flag( flag_PLOWABLE, pos() ) && !wearing_shoes ) { + if( has_trait( trait_ROOTS3 ) && here.has_flag( flag_PLOWABLE, pos() ) && !wearing_shoes ) { root_vitamins += 1; if( get_thirst() <= -2000 ) { root_water += 51; @@ -917,8 +920,8 @@ void Character::suffer_from_other_mutations() } if( has_trait( trait_SORES ) ) { - for( const body_part bp : all_body_parts ) { - if( bp == bp_head ) { + for( const bodypart_id bp : get_all_body_parts() ) { + if( bp == bodypart_id( "head" ) ) { continue; } int sores_pain = 5 + 0.4 * std::abs( encumb( bp ) ); @@ -930,7 +933,7 @@ void Character::suffer_from_other_mutations() //Web Weavers...weave web if( has_active_mutation( trait_WEB_WEAVER ) && !in_vehicle ) { // this adds intensity to if its not already there. - g->m.add_field( pos(), fd_web, 1 ); + here.add_field( pos(), fd_web, 1 ); } @@ -955,7 +958,7 @@ void Character::suffer_from_other_mutations() if( has_trait( trait_WEB_SPINNER ) && !in_vehicle && one_in( 3 ) ) { // this adds intensity to if its not already there. - g->m.add_field( pos(), fd_web, 1 ); + here.add_field( pos(), fd_web, 1 ); } bool should_mutate = has_trait( trait_UNSTABLE ) && !has_trait( trait_CHAOTIC_BAD ) && @@ -990,9 +993,10 @@ void Character::suffer_from_other_mutations() void Character::suffer_from_radiation() { + map &here = get_map(); // checking for radioactive items in inventory const int item_radiation = leak_level( "RADIOACTIVE" ); - const int map_radiation = g->m.get_radiation( pos() ); + const int map_radiation = here.get_radiation( pos() ); float rads = map_radiation / 100.0f + item_radiation / 10.0f; int rad_mut = 0; @@ -1025,8 +1029,8 @@ void Character::suffer_from_radiation() // If you can't, irradiate the player instead tripoint rad_point = pos() + point( rng( -3, 3 ), rng( -3, 3 ) ); // TODO: Radioactive vehicles? - if( g->m.get_radiation( rad_point ) < rad_mut ) { - g->m.adjust_radiation( rad_point, 1 ); + if( here.get_radiation( rad_point ) < rad_mut ) { + here.adjust_radiation( rad_point, 1 ); } else { rads += rad_mut; } @@ -1186,7 +1190,7 @@ void Character::suffer_from_bad_bionics() add_msg_if_player( m_bad, _( "You suffer a burning acidic discharge!" ) ); hurtall( 1, nullptr ); sfx::play_variant_sound( "bionics", "acid_discharge", 100 ); - sfx::do_player_death_hurt( g->u, false ); + sfx::do_player_death_hurt( get_player_character(), false ); } if( has_bionic( bio_drain ) && get_power_level() > 24_kJ && one_turn_in( 1_hours ) ) { add_msg_if_player( m_bad, _( "Your batteries discharge slightly." ) ); @@ -1259,9 +1263,9 @@ void Character::suffer_from_artifacts() } if( has_artifact_with( AEP_BAD_WEATHER ) && calendar::once_every( 1_minutes ) && - g->weather.weather != WEATHER_SNOWSTORM ) { - g->weather.weather_override = WEATHER_SNOWSTORM; - g->weather.set_nextweather( calendar::turn ); + get_weather().weather_id->precip < precip_class::heavy ) { + get_weather().weather_override = get_bad_weather(); + get_weather().set_nextweather( calendar::turn ); } if( has_artifact_with( AEP_MUTAGENIC ) && one_turn_in( 48_hours ) ) { @@ -1421,6 +1425,18 @@ void Character::suffer_without_sleep( const int sleep_deprivation ) } } +void Character::suffer_from_tourniquet() +{ + for( const bodypart_id &bp : get_all_body_parts( true ) ) { + if( worn_with_flag( flag_TOURNIQUET, bp ) && one_turn_in( 30_seconds ) ) { + mod_pain( 1 ); + apply_damage( nullptr, bp, 1, true ); + add_msg_player_or_npc( m_bad, _( "Your tourniquet hurts you." ), + _( " is hurting from the tourniquet." ) ); + } + } +} + void Character::suffer_from_pain() { } @@ -1482,6 +1498,7 @@ void Character::suffer() } suffer_without_sleep( sleep_deprivation ); + suffer_from_tourniquet(); suffer_from_pain(); } diff --git a/src/talker.h b/src/talker.h new file mode 100644 index 0000000000000..16bce5b90040a --- /dev/null +++ b/src/talker.h @@ -0,0 +1,302 @@ +#pragma once +#ifndef CATA_SRC_TALKER_H +#define CATA_SRC_TALKER_H + +class faction; +class item; +class mission; +class npc; +class player; +class recipe; +struct tripoint; +class vehicle; + +/* + * Talker is an entity independent way of providing a participant in a dialogue. + * Talker is a virtual abstract class and should never really be used. Instead, + * entity specific talker child classes such as character_talker should be used. + */ +class talker +{ + public: + virtual ~talker() = default; + // virtual member accessor functions + virtual player *get_character() { + return nullptr; + } + virtual player *get_character() const { + return nullptr; + } + virtual npc *get_npc() { + return nullptr; + } + virtual npc *get_npc() const { + return nullptr; + } + + // identity and location + virtual std::string disp_name() const { + return ""; + } + virtual character_id getID() const { + return character_id( 0 ); + } + virtual bool is_male() const { + return false; + } + virtual std::vector get_grammatical_genders() const { + return {}; + } + virtual int posx() const = 0; + virtual int posy() const = 0; + virtual int posz() const = 0; + virtual tripoint pos() const = 0; + virtual tripoint global_omt_location() const = 0; + virtual std::string distance_to_goal() const { + return ""; + } + + // mandatory functions for starting a dialogue + virtual bool will_talk_to_u( const player &, bool ) { + return false; + } + virtual std::vector get_topics( bool ) { + return {}; + } + virtual void check_missions() {} + virtual void update_missions( const std::vector &, const character_id & ) {} + virtual bool check_hostile_response( int ) const { + return false; + } + virtual int parse_mod( const std::string &, int ) const { + return 0; + } + virtual int trial_chance_mod( const std::string & ) const { + return 0; + } + + // stats, skills, traits, bionics, and magic + virtual int str_cur() const { + return 0; + } + virtual int dex_cur() const { + return 0; + } + virtual int int_cur() const { + return 0; + } + virtual int per_cur() const { + return 0; + } + virtual int get_skill_level( const skill_id & ) const { + return false; + } + virtual bool has_trait( const trait_id & ) const { + return false; + } + virtual void set_mutation( const trait_id & ) {} + virtual void unset_mutation( const trait_id & ) {} + virtual bool has_trait_flag( const std::string & ) const { + return false; + } + virtual bool crossed_threshold() const { + return false; + } + virtual int num_bionics() const { + return 0; + } + virtual bool has_max_power() const { + return false; + } + virtual bool has_bionic( const bionic_id & ) const { + return false; + } + virtual bool knows_spell( const spell_id & ) const { + return false; + } + virtual std::vector skills_offered_to( const talker & ) const { + return {}; + } + virtual std::string skill_training_text( const talker &, const skill_id & ) const { + return {}; + } + virtual std::vector styles_offered_to( const talker & ) const { + return {}; + } + virtual std::string style_training_text( const talker &, const matype_id & ) const { + return {}; + } + virtual std::vector spells_offered_to( talker & ) { + return {}; + } + virtual std::string spell_training_text( talker &, const spell_id & ) { + return {}; + } + virtual void store_chosen_training( const skill_id &, const matype_id &, + const spell_id & ) { + } + + // effects and values + virtual bool has_effect( const efftype_id & ) const { + return false; + } + virtual bool is_deaf() const { + return false; + } + virtual void add_effect( const efftype_id &, const time_duration &, bool ) {} + virtual void remove_effect( const efftype_id & ) {} + virtual std::string get_value( const std::string & ) const { + return ""; + } + virtual void set_value( const std::string &, const std::string & ) {} + virtual void remove_value( const std::string & ) {} + + // inventory, buying, and selling + virtual bool is_wearing( const itype_id & ) const { + return false; + } + virtual int charges_of( const itype_id & ) const { + return 0; + } + virtual bool has_charges( const itype_id &, int ) const { + return false; + } + virtual std::list use_charges( const itype_id &, int ) { + return {}; + } + virtual bool has_amount( const itype_id &, int ) const { + return false; + } + virtual std::list use_amount( const itype_id &, int ) { + return {}; + } + virtual int value( const item & ) { + return 0; + } + virtual int cash() const { + return 0; + } + virtual int debt() const { + return 0; + } + virtual void add_debt( int ) {} + virtual std::vector items_with( const std::function & ) const { + return {}; + }; + virtual void i_add( const item & ) {} + virtual void remove_items_with( const std::function & ) {} + virtual bool unarmed_attack() const { + return false; + } + virtual bool can_stash_weapon() const { + return false; + } + virtual bool has_stolen_item( const talker & ) const { + return false; + } + virtual int cash_to_favor( int ) const { + return 0; + } + virtual std::string give_item_to( bool ) { + return _( "Nope." ); + } + virtual bool buy_from( int ) { + return false; + } + virtual void buy_monster( talker &, const mtype_id &, int, int, bool, + const translation & ) {} + + // missions + virtual std::vector available_missions() const { + return {}; + } + virtual std::vector assigned_missions() const { + return {}; + } + virtual mission *selected_mission() const { + return nullptr; + } + virtual void select_mission( mission * ) { + } + virtual void add_mission( const mission_type_id & ) {} + virtual void set_companion_mission( const std::string & ) {} + + // factions and alliances + virtual faction *get_faction() const { + return nullptr; + } + virtual void set_fac( const faction_id & ) {} + virtual void add_faction_rep( int ) {} + virtual bool is_following() const { + return false; + } + virtual bool is_friendly( const Character & ) const { + return false; + } + virtual bool is_player_ally() const { + return false; + } + virtual bool turned_hostile() const { + return false; + } + virtual bool is_enemy() const { + return false; + } + virtual void make_angry() {} + + // ai rules + virtual bool has_ai_rule( const std::string &, const std::string & ) const { + return false; + } + virtual void toggle_ai_rule( const std::string &, const std::string & ) {} + virtual void set_ai_rule( const std::string &, const std::string & ) {} + virtual void clear_ai_rule( const std::string &, const std::string & ) {} + + // other descriptors + virtual std::string get_job_description() const { + return ""; + } + virtual std::string evaluation_by( const talker & ) const { + return ""; + } + virtual std::string short_description() const { + return ""; + } + virtual bool has_activity() const { + return false; + } + virtual bool is_mounted() const { + return false; + } + virtual bool is_myclass( const npc_class_id & ) const { + return false; + } + virtual void set_class( const npc_class_id & ) {} + virtual int get_fatigue() const { + return 0; + } + virtual int get_hunger() const { + return 0; + } + virtual int get_thirst() const { + return 0; + } + virtual bool is_in_control_of( const vehicle & ) const { + return false; + } + + // speaking + virtual void say( const std::string & ) {} + virtual void shout( const std::string & = "", bool = false ) {} + + // miscellaneous + virtual bool enslave_mind() { + return false; + } + virtual std::string opinion_text() const { + return ""; + } + virtual void add_opinion( int /*trust*/, int /*fear*/, int /*value*/, int /*anger*/, + int /*debt*/ ) {} +}; +#endif // CATA_SRC_TALKER_H diff --git a/src/talker_avatar.cpp b/src/talker_avatar.cpp new file mode 100644 index 0000000000000..157547464c3a2 --- /dev/null +++ b/src/talker_avatar.cpp @@ -0,0 +1,130 @@ +#include "avatar.h" +#include "game.h" +#include "game_constants.h" +#include "messages.h" +#include "monster.h" +#include "mtype.h" +#include "npc.h" +#include "npctrade.h" +#include "output.h" +#include "player.h" +#include "talker_avatar.h" + +static const efftype_id effect_pacified( "pacified" ); +static const efftype_id effect_pet( "pet" ); + +static const skill_id skill_speech( "speech" ); + +static const bionic_id bio_armor_eyes( "bio_armor_eyes" ); +static const bionic_id bio_deformity( "bio_deformity" ); +static const bionic_id bio_face_mask( "bio_face_mask" ); +static const bionic_id bio_voice( "bio_voice" ); + +static const trait_id trait_PROF_FOODP( "PROF_FOODP" ); + +std::vector talker_avatar::get_topics( bool ) +{ + std::vector add_topics; + if( has_trait( trait_PROF_FOODP ) && !( is_wearing( itype_id( "foodperson_mask" ) ) || + is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { + add_topics.push_back( "TALK_NOFACE" ); + } + return add_topics; +} + +int talker_avatar::parse_mod( const std::string &attribute, const int factor ) const +{ + int modifier = 0; + if( attribute == "U_INTIMIDATE" ) { + modifier = me_chr->intimidation(); + } + modifier *= factor; + return modifier; +} + +int talker_avatar::trial_chance_mod( const std::string &trial_type ) const +{ + int chance = 0; + const social_modifiers &me_mods = me_chr->get_mutation_social_mods(); + if( trial_type == "lie" ) { + chance += me_chr->talk_skill() + me_mods.lie; + + //come on, who would suspect a robot of lying? + if( me_chr->has_bionic( bio_voice ) ) { + chance += 10; + } + if( me_chr->has_bionic( bio_face_mask ) ) { + chance += 20; + } + } else if( trial_type == "persuade" ) { + chance += me_chr->talk_skill() + me_mods.persuade; + + if( me_chr->has_bionic( bio_face_mask ) ) { + chance += 10; + } + if( me_chr->has_bionic( bio_deformity ) ) { + chance -= 50; + } + if( me_chr->has_bionic( bio_voice ) ) { + chance -= 20; + } + } else if( trial_type == "intimidate" ) { + chance += me_chr->intimidation() + me_mods.intimidate; + + if( me_chr->has_bionic( bio_face_mask ) ) { + chance += 10; + } + if( me_chr->has_bionic( bio_armor_eyes ) ) { + chance += 10; + } + if( me_chr->has_bionic( bio_deformity ) ) { + chance += 20; + } + if( me_chr->has_bionic( bio_voice ) ) { + chance += 20; + } + } + return chance; +} + +void talker_avatar::buy_monster( talker &seller, const mtype_id &mtype, int cost, + int count, bool pacified, const translation &name ) +{ + npc *seller_guy = seller.get_npc(); + if( !seller_guy ) { + popup( _( "%s can't sell you any %s" ), seller.disp_name(), mtype.obj().nname( 2 ) ); + return; + } + if( !npc_trading::pay_npc( *seller_guy, cost ) ) { + popup( _( "You can't afford it!" ) ); + return; + } + + for( int i = 0; i < count; i++ ) { + monster *const mon_ptr = g->place_critter_around( mtype, me_chr->pos(), 3 ); + if( !mon_ptr ) { + add_msg( m_debug, "Cannot place u_buy_monster, no valid placement locations." ); + break; + } + monster &tmp = *mon_ptr; + // Our monster is always a pet. + tmp.friendly = -1; + tmp.add_effect( effect_pet, 1_turns, num_bp, true ); + + if( pacified ) { + tmp.add_effect( effect_pacified, 1_turns, num_bp, true ); + } + + if( !name.empty() ) { + tmp.unique_name = name.translated(); + } + + } + + if( name.empty() ) { + popup( _( "%1$s gives you %2$d %3$s." ), seller_guy->name, + count, mtype.obj().nname( count ) ); + } else { + popup( _( "%1$s gives you %2$s." ), seller_guy->name, name ); + } +} diff --git a/src/talker_avatar.h b/src/talker_avatar.h new file mode 100644 index 0000000000000..53f7fff71bff7 --- /dev/null +++ b/src/talker_avatar.h @@ -0,0 +1,29 @@ +#pragma once +#ifndef CATA_SRC_TALKER_AVATAR_H +#define CATA_SRC_TALKER_AVATAR_H + +#include "talker.h" +#include "talker_character.h" + +class avatar; +/* + * Talker wrapper class for avatar. + */ +class talker_avatar: public talker_character +{ + public: + talker_avatar( avatar *new_me ) : talker_character( new_me ) { + } + ~talker_avatar() override = default; + + // mandatory functions for starting a dialogue + std::vector get_topics( bool ) override; + int parse_mod( const std::string &attribute, int factor ) const override; + int trial_chance_mod( const std::string &trial_type ) const override; + + // inventory and such + void buy_monster( talker &seller, const mtype_id &mtype, int cost, + int count, bool pacified, const translation &name ) override; +}; +#endif // CATA_SRC_TALKER_AVATAR_H + diff --git a/src/talker_character.cpp b/src/talker_character.cpp new file mode 100644 index 0000000000000..11e71f4291170 --- /dev/null +++ b/src/talker_character.cpp @@ -0,0 +1,293 @@ +#include "game.h" +#include "game_constants.h" +#include "messages.h" +#include "monster.h" +#include "mtype.h" +#include "npc.h" +#include "npctrade.h" +#include "output.h" +#include "player.h" +#include "talker_character.h" +#include "vehicle.h" + +static const efftype_id effect_pacified( "pacified" ); +static const efftype_id effect_pet( "pet" ); + +static const skill_id skill_speech( "speech" ); + +static const bionic_id bio_armor_eyes( "bio_armor_eyes" ); +static const bionic_id bio_deformity( "bio_deformity" ); +static const bionic_id bio_face_mask( "bio_face_mask" ); +static const bionic_id bio_voice( "bio_voice" ); + +static const trait_id trait_PROF_FOODP( "PROF_FOODP" ); + +std::string talker_character::disp_name() const +{ + return me_chr->disp_name(); +} + +character_id talker_character::getID() const +{ + return me_chr->getID(); +} + +bool talker_character::is_male() const +{ + return me_chr->male; +} + +std::vector talker_character::get_grammatical_genders() const +{ + return me_chr->get_grammatical_genders(); +} + +int talker_character::posx() const +{ + return me_chr->posx(); +} + +int talker_character::posy() const +{ + return me_chr->posy(); +} + +int talker_character::posz() const +{ + return me_chr->posz(); +} + +tripoint talker_character::pos() const +{ + return me_chr->pos(); +} + +tripoint talker_character::global_omt_location() const +{ + return me_chr->global_omt_location(); +} + +int talker_character::str_cur() const +{ + return me_chr->str_cur; +} + +int talker_character::dex_cur() const +{ + return me_chr->dex_cur; +} + +int talker_character::int_cur() const +{ + return me_chr->int_cur; +} + +int talker_character::per_cur() const +{ + return me_chr->per_cur; +} + +bool talker_character::has_trait( const trait_id &trait_to_check ) const +{ + return me_chr->has_trait( trait_to_check ); +} + +bool talker_character::is_deaf() const +{ + return me_chr->is_deaf(); +} + +void talker_character::set_mutation( const trait_id &new_trait ) +{ + me_chr->set_mutation( new_trait ); +} + +void talker_character::unset_mutation( const trait_id &old_trait ) +{ + me_chr->unset_mutation( old_trait ); +} + +bool talker_character::has_trait_flag( const std::string &trait_flag_to_check ) const +{ + return me_chr->has_trait_flag( trait_flag_to_check ); +} + +bool talker_character::crossed_threshold() const +{ + return me_chr->crossed_threshold(); +} + +int talker_character::num_bionics() const +{ + return me_chr->num_bionics(); +} + +bool talker_character::has_max_power() const +{ + return me_chr->has_max_power(); +} + +bool talker_character::has_bionic( const bionic_id &bionics_id ) const +{ + return me_chr->has_bionic( bionics_id ); +} + +bool talker_character::knows_spell( const spell_id &sp ) const +{ + return me_chr->magic.knows_spell( sp ); +} + +int talker_character::get_skill_level( const skill_id &skill ) const +{ + return me_chr->get_skill_level( skill ); +} + +bool talker_character::has_effect( const efftype_id &effect_id ) const +{ + return me_chr->has_effect( effect_id ); +} + +void talker_character::add_effect( const efftype_id &new_effect, const time_duration &dur, + bool permanent ) +{ + me_chr->add_effect( new_effect, dur, num_bp, permanent ); +} + +void talker_character::remove_effect( const efftype_id &old_effect ) +{ + me_chr->remove_effect( old_effect, num_bp ); +} + +std::string talker_character:: get_value( const std::string &var_name ) const +{ + return me_chr->get_value( var_name ); +} + +void talker_character::set_value( const std::string &var_name, const std::string &value ) +{ + me_chr->set_value( var_name, value ); +} + +void talker_character::remove_value( const std::string &var_name ) +{ + me_chr->remove_value( var_name ); +} + +bool talker_character::is_wearing( const itype_id &item_id ) const +{ + return me_chr->is_wearing( item_id ); +} + +int talker_character::charges_of( const itype_id &item_id ) const +{ + return me_chr->charges_of( item_id ); +} + +bool talker_character::has_charges( const itype_id &item_id, int count ) const +{ + return me_chr->has_charges( item_id, count ); +} + +std::list talker_character::use_charges( const itype_id &item_name, const int count ) +{ + return me_chr->use_charges( item_name, count ); +} + +std::list talker_character::use_amount( const itype_id &item_name, const int count ) +{ + return me_chr->use_amount( item_name, count ); +} + +bool talker_character::has_amount( const itype_id &item_id, int count ) const +{ + return me_chr->has_amount( item_id, count ); +} + +int talker_character::cash() const +{ + return me_chr->cash; +} + +std::vector talker_character::items_with( const std::function + &filter ) const +{ + return me_chr->items_with( filter ); +} + +void talker_character::i_add( const item &new_item ) +{ + me_chr->i_add( new_item ); +} + +void talker_character::remove_items_with( const std::function &filter ) +{ + me_chr->remove_items_with( filter ); +} + +bool talker_character::unarmed_attack() const +{ + return me_chr->unarmed_attack(); +} + +bool talker_character::can_stash_weapon() const +{ + return me_chr->can_pickVolume( me_chr->weapon ); +} + +bool talker_character::has_stolen_item( const talker &guy ) const +{ + const player *owner = guy.get_character(); + if( owner ) { + for( auto &elem : me_chr->inv_dump() ) { + if( elem->is_old_owner( *owner, true ) ) { + return true; + } + } + } + return false; +} + +faction *talker_character::get_faction() const +{ + return me_chr->get_faction(); +} + +std::string talker_character::short_description() const +{ + return me_chr->short_description(); +} + +bool talker_character::has_activity() const +{ + return !me_chr->activity.is_null(); +} + +bool talker_character::is_mounted() const +{ + return me_chr->is_mounted(); +} + +int talker_character::get_fatigue() const +{ + return me_chr->get_fatigue(); +} + +int talker_character::get_hunger() const +{ + return me_chr->get_hunger(); +} + +int talker_character::get_thirst() const +{ + return me_chr->get_thirst(); +} + +bool talker_character::is_in_control_of( const vehicle &veh ) const +{ + return veh.player_in_control( *me_chr ); +} + +void talker_character::shout( const std::string &speech, bool order ) +{ + me_chr->shout( speech, order ); +} diff --git a/src/talker_character.h b/src/talker_character.h new file mode 100644 index 0000000000000..105c6bc3a979c --- /dev/null +++ b/src/talker_character.h @@ -0,0 +1,103 @@ +#pragma once +#ifndef CATA_SRC_TALKER_CHARACTER_H +#define CATA_SRC_TALKER_CHARACTER_H + +#include "talker.h" + +class player; +class faction; +class item; +class mission; +class npc; +struct tripoint; +class vehicle; +/* + * Talker wrapper class for Character. well, ideally, but since Character is such a mess, + * it's the wrapper class for player + * Should never be invoked directly. Only talker_avatar and talker_npc are really valid. + */ +class talker_character: public talker +{ + public: + talker_character( player *new_me ): me_chr( new_me ) { + } + ~talker_character() override = default; + + // underlying element accessor functions + player *get_character() override { + return me_chr; + } + player *get_character() const override { + return me_chr; + } + // identity and location + std::string disp_name() const override; + character_id getID() const override; + bool is_male() const override; + std::vector get_grammatical_genders() const override; + int posx() const override; + int posy() const override; + int posz() const override; + tripoint pos() const override; + tripoint global_omt_location() const override; + + // stats, skills, traits, bionics, and magic + int str_cur() const override; + int dex_cur() const override; + int int_cur() const override; + int per_cur() const override; + bool has_trait( const trait_id &trait_to_check ) const override; + void set_mutation( const trait_id &new_trait ) override; + void unset_mutation( const trait_id &old_trait ) override; + bool has_trait_flag( const std::string &trait_flag_to_check ) const override; + bool crossed_threshold() const override; + int num_bionics() const override; + bool has_max_power() const override; + bool has_bionic( const bionic_id &bionics_id ) const override; + bool knows_spell( const spell_id &sp ) const override; + int get_skill_level( const skill_id &skill ) const override; + + // effects and values + bool has_effect( const efftype_id &effect_id ) const override; + bool is_deaf() const override; + void add_effect( const efftype_id &new_effect, const time_duration &dur, + bool permanent ) override; + void remove_effect( const efftype_id &old_effect ) override; + std::string get_value( const std::string &var_name ) const override; + void set_value( const std::string &var_name, const std::string &value ) override; + void remove_value( const std::string &var_name ) override; + + // inventory, buying, and selling + bool is_wearing( const itype_id &item_id ) const override; + int charges_of( const itype_id &item_id ) const override; + bool has_charges( const itype_id &item_id, int count ) const override; + std::list use_charges( const itype_id &item_name, int count ) override; + bool has_amount( const itype_id &item_id, int count ) const override; + std::list use_amount( const itype_id &item_name, int count ) override; + int cash() const override; + std::vector items_with( const std::function &filter ) const override; + void i_add( const item &new_item ) override; + void remove_items_with( const std::function &filter ) override; + bool unarmed_attack() const override; + bool can_stash_weapon() const override; + bool has_stolen_item( const talker &guy ) const override; + + // factions and alliances + faction *get_faction() const override; + + // other descriptors + std::string short_description() const override; + bool has_activity() const override; + bool is_mounted() const override; + int get_fatigue() const override; + int get_hunger() const override; + int get_thirst() const override; + bool is_in_control_of( const vehicle &veh ) const override; + + // speaking + void shout( const std::string &speech = "", bool order = false ) override; + + protected: + player *me_chr; +}; +#endif // CATA_SRC_TALKER_CHARACTER_H diff --git a/src/talker_npc.cpp b/src/talker_npc.cpp new file mode 100644 index 0000000000000..ca48809c742b7 --- /dev/null +++ b/src/talker_npc.cpp @@ -0,0 +1,832 @@ +#include "avatar.h" +#include "game.h" +#include "game_constants.h" +#include "game_inventory.h" +#include "item.h" +#include "itype.h" +#include "item_location.h" +#include "line.h" +#include "martialarts.h" +#include "messages.h" +#include "mission.h" +#include "mission_companion.h" +#include "player.h" +#include "npc.h" +#include "npctalk.h" +#include "npctrade.h" +#include "skill.h" +#include "talker_npc.h" +#include "talker_character.h" + +class Character; + +static const efftype_id effect_lying_down( "lying_down" ); +static const efftype_id effect_narcosis( "narcosis" ); +static const efftype_id effect_npc_suspend( "npc_suspend" ); +static const efftype_id effect_sleep( "sleep" ); + +static const trait_id trait_DEBUG_MIND_CONTROL( "DEBUG_MIND_CONTROL" ); +static const trait_id trait_PROF_FOODP( "PROF_FOODP" ); + +std::string talker_npc::distance_to_goal() const +{ + // TODO: this ignores the z-component + int dist = rl_dist( me_npc->global_omt_location(), me_npc->goal ); + std::string response; + dist *= 100; + if( dist >= 1300 ) { + int miles = dist / 25; // *100, e.g. quarter mile is "25" + miles -= miles % 25; // Round to nearest quarter-mile + int fullmiles = ( miles - miles % 100 ) / 100; // Left of the decimal point + if( fullmiles < 0 ) { + fullmiles = 0; + } + response = string_format( _( "%d.%d miles." ), fullmiles, miles ); + } else { + response = string_format( ngettext( "%d foot.", "%d feet.", dist ), dist ); + } + return response; +} + +bool talker_npc::will_talk_to_u( const player &u, bool force ) +{ + if( u.is_dead_state() ) { + me_npc->set_attitude( NPCATT_NULL ); + return false; + } + if( g->u.getID() == u.getID() ) { + if( me_npc->get_faction() ) { + me_npc->get_faction()->known_by_u = true; + } + me_npc->set_known_to_u( true ); + } + // This is necessary so that we don't bug the player over and over + if( me_npc->get_attitude() == NPCATT_TALK ) { + me_npc->set_attitude( NPCATT_NULL ); + } else if( !force && ( me_npc->get_attitude() == NPCATT_FLEE || + me_npc-> get_attitude() == NPCATT_FLEE_TEMP ) ) { + add_msg( _( "%s is fleeing from you!" ), disp_name() ); + return false; + } else if( !force && me_npc->get_attitude() == NPCATT_KILL ) { + add_msg( _( "%s is hostile!" ), disp_name() ); + return false; + } + return true; +} + +std::vector talker_npc::get_topics( bool radio_contact ) +{ + std::vector add_topics; + // For each active mission we have, let the mission know we talked to this NPC. + for( auto &mission : g->u.get_active_missions() ) { + mission->on_talk_with_npc( me_npc->getID() ); + } + + add_topics.push_back( me_npc->chatbin.first_topic ); + if( radio_contact ) { + add_topics.push_back( "TALK_RADIO" ); + } else if( me_npc->is_leader() ) { + add_topics.push_back( "TALK_LEADER" ); + } else if( me_npc->is_player_ally() && ( me_npc->is_walking_with() || me_npc->has_activity() ) ) { + add_topics.push_back( "TALK_FRIEND" ); + } else if( me_npc->get_attitude() == NPCATT_RECOVER_GOODS ) { + add_topics.push_back( "TALK_STOLE_ITEM" ); + } + int most_difficult_mission = 0; + for( auto &mission : me_npc->chatbin.missions ) { + const auto &type = mission->get_type(); + if( type.urgent && type.difficulty > most_difficult_mission ) { + add_topics.push_back( "TALK_MISSION_DESCRIBE_URGENT" ); + me_npc->chatbin.mission_selected = mission; + most_difficult_mission = type.difficulty; + } + } + most_difficult_mission = 0; + bool chosen_urgent = false; + for( auto &mission : me_npc->chatbin.missions_assigned ) { + if( mission->get_assigned_player_id() != g->u.getID() ) { + // Not assigned to the player that is currently talking to the npc + continue; + } + const auto &type = mission->get_type(); + if( ( type.urgent && !chosen_urgent ) || ( type.difficulty > most_difficult_mission && + ( type.urgent || !chosen_urgent ) ) ) { + chosen_urgent = type.urgent; + add_topics.push_back( "TALK_MISSION_INQUIRE" ); + me_npc->chatbin.mission_selected = mission; + most_difficult_mission = type.difficulty; + } + } + + // Needs + if( me_npc->has_effect( effect_npc_suspend ) ) { + add_topics.push_back( "TALK_REBOOT" ); + } + if( me_npc->has_effect( effect_sleep ) || me_npc->has_effect( effect_lying_down ) ) { + if( me_npc->has_effect( effect_narcosis ) ) { + add_topics.push_back( "TALK_SEDATED" ); + } else { + add_topics.push_back( "TALK_WAKE_UP" ); + } + } + + if( add_topics.back() == "TALK_NONE" ) { + add_topics.back() = me_npc->pick_talk_topic( g->u ); + } + me_npc->moves -= 100; + + if( g->u.is_deaf() ) { + if( add_topics.back() == "TALK_MUG" || + add_topics.back() == "TALK_STRANGER_AGGRESSIVE" ) { + me_npc->make_angry(); + add_topics.push_back( "TALK_DEAF_ANGRY" ); + } else { + add_topics.push_back( "TALK_DEAF" ); + } + } + + if( me_npc->has_trait( trait_PROF_FOODP ) && + !( me_npc->is_wearing( itype_id( "foodperson_mask_on" ) ) || + me_npc->is_wearing( itype_id( "foodperson_mask" ) ) ) ) { + add_topics.push_back( "TALK_NPC_NOFACE" ); + } + me_npc->decide_needs(); + + return add_topics; +} + +void talker_npc::check_missions() +{ + me_npc->chatbin.check_missions(); +} + +void talker_npc::update_missions( const std::vector &missions_assigned, + const character_id &charID ) +{ + if( me_npc->chatbin.mission_selected != nullptr ) { + if( me_npc->chatbin.mission_selected->get_assigned_player_id() != charID ) { + // Don't talk about a mission that is assigned to someone else. + me_npc->chatbin.mission_selected = nullptr; + } + } + if( me_npc->chatbin.mission_selected == nullptr ) { + // if possible, select a mission to talk about + if( !me_npc->chatbin.missions.empty() ) { + me_npc->chatbin.mission_selected = me_npc->chatbin.missions.front(); + } else if( !missions_assigned.empty() ) { + me_npc->chatbin.mission_selected = missions_assigned.front(); + } + } +} + +bool talker_npc::check_hostile_response( const int anger ) const +{ + return me_npc->op_of_u.anger + anger > me_npc->hostile_anger_level(); +} + +// Every OWED_VAL that the NPC owes you counts as +1 towards convincing +static constexpr int OWED_VAL = 1000; +int talker_npc::parse_mod( const std::string &attribute, const int factor ) const +{ + int modifier = 0; + if( attribute == "ANGER" ) { + modifier = me_npc->op_of_u.anger; + } else if( attribute == "FEAR" ) { + modifier = me_npc->op_of_u.fear; + } else if( attribute == "TRUST" ) { + modifier = me_npc->op_of_u.trust; + } else if( attribute == "VALUE" ) { + modifier = me_npc->op_of_u.value; + } else if( attribute == "POS_FEAR" ) { + modifier = std::max( 0, me_npc->op_of_u.fear ); + } else if( attribute == "AGGRESSION" ) { + modifier = me_npc->personality.aggression; + } else if( attribute == "ALTRUISM" ) { + modifier = me_npc->personality.altruism; + } else if( attribute == "BRAVERY" ) { + modifier = me_npc->personality.bravery; + } else if( attribute == "COLLECTOR" ) { + modifier = me_npc->personality.collector; + } else if( attribute == "MISSIONS" ) { + modifier = me_npc->assigned_missions_value() / OWED_VAL; + } else if( attribute == "NPC_INTIMIDATE" ) { + modifier = me_npc->intimidation(); + } + modifier *= factor; + return modifier; +} + +int talker_npc::trial_chance_mod( const std::string &trial_type ) const +{ + int chance = 0; + if( trial_type == "lie" ) { + chance += - me_npc->talk_skill() + me_npc->op_of_u.trust * 3; + } else if( trial_type == "persuade" ) { + chance += - static_cast( me_npc->talk_skill() * 0.5 ) + + me_npc->op_of_u.trust * 2 + me_npc->op_of_u.value; + } else if( trial_type == "intimidate" ) { + chance += - me_npc->intimidation() + me_npc->op_of_u.fear * 2 - + me_npc->personality.bravery * 2; + } + return chance; +} + +std::vector talker_npc::skills_offered_to( const talker &student ) const +{ + if( student.get_character() ) { + return me_npc->skills_offered_to( *student.get_character() ); + } else { + return {}; + } +} + +std::string talker_npc::skill_training_text( const talker &student, + const skill_id &skill ) const +{ + const player *pupil = student.get_character(); + if( !pupil ) { + return ""; + } + const int cost = me_npc->is_ally( *pupil ) ? 0 : 1000 * + ( 1 + pupil->get_skill_level( skill ) ) * + ( 1 + pupil->get_skill_level( skill ) ); + SkillLevel skill_level_obj = pupil->get_skill_level_object( skill ); + const int cur_level = skill_level_obj.level(); + const int cur_level_exercise = skill_level_obj.exercise(); + skill_level_obj.train( 100 ); + const int next_level = skill_level_obj.level(); + const int next_level_exercise = skill_level_obj.exercise(); + + //~Skill name: current level (exercise) -> next level (exercise) (cost in dollars) + return string_format( cost > 0 ? _( "%s: %d (%d%%) -> %d (%d%%) (cost $%d)" ) : + _( "%s: %d (%d%%) -> %d (%d%%)" ), skill.obj().name(), cur_level, + cur_level_exercise, next_level, next_level_exercise, cost / 100 ); +} + +std::vector talker_npc::styles_offered_to( const talker &student ) const +{ + if( student.get_character() ) { + return me_npc->styles_offered_to( *student.get_character() ); + } else { + return {}; + } +} + +std::string talker_npc::style_training_text( const talker &student, + const matype_id &style ) const +{ + if( !student.get_character() ) { + return ""; + } else if( me_npc->is_ally( *student.get_character() ) ) { + return string_format( "%s", style.obj().name ); + } else { + return string_format( _( "%s ( cost $%d )" ), style.obj().name, 8 ); + } +} + +std::vector talker_npc::spells_offered_to( talker &student ) +{ + if( student.get_character() ) { + return me_npc->spells_offered_to( *student.get_character() ); + } else { + return {}; + } +} + +std::string talker_npc::spell_training_text( talker &student, const spell_id &sp ) +{ + player *pupil = student.get_character(); + if( !pupil ) { + return ""; + } + const spell &temp_spell = me_npc->magic.get_spell( sp ); + const bool knows = pupil->magic.knows_spell( sp ); + const int cost = me_npc->calc_spell_training_cost( knows, temp_spell.get_difficulty(), + temp_spell.get_level() ); + std::string text; + if( knows ) { + text = string_format( _( "%s: 1 hour lesson (cost %s)" ), temp_spell.name(), + format_money( cost ) ); + } else { + text = string_format( _( "%s: teaching spell knowledge (cost %s)" ), + temp_spell.name(), format_money( cost ) ); + } + return text; +} + +void talker_npc::store_chosen_training( const skill_id &c_skill, const matype_id &c_style, + const spell_id &c_spell ) +{ + if( c_skill ) { + me_npc->chatbin.skill = c_skill; + me_npc->chatbin.style = matype_id::NULL_ID(); + me_npc->chatbin.dialogue_spell = spell_id(); + } else if( c_style ) { + me_npc->chatbin.style = c_style; + me_npc->chatbin.skill = skill_id::NULL_ID(); + me_npc->chatbin.dialogue_spell = spell_id(); + } else if( c_spell != spell_id() ) { + me_npc->chatbin.style = matype_id::NULL_ID(); + me_npc->chatbin.skill = skill_id::NULL_ID(); + me_npc->chatbin.dialogue_spell = c_spell; + } +} + +int talker_npc::debt() const +{ + return me_npc->op_of_u.owed; +} + +void talker_npc::add_debt( const int cost ) +{ + me_npc->op_of_u.owed += cost; +} + +int talker_npc::cash_to_favor( const int value ) const +{ + return npc_trading::cash_to_favor( *me_npc, value ); +} + +enum consumption_result { + REFUSED = 0, + CONSUMED_SOME, // Consumption didn't fail, but don't delete the item + CONSUMED_ALL // Consumption succeeded, delete the item +}; + +// Returns true if we destroyed the item through consumption +// does not try to consume contents +static consumption_result try_consume( npc &p, item &it, std::string &reason ) +{ + // TODO: Unify this with 'player::consume_item()' + item &to_eat = it; + if( to_eat.is_null() ) { + debugmsg( "Null item to try_consume." ); + return REFUSED; + } + const auto &comest = to_eat.get_comestible(); + if( !comest ) { + // Don't inform the player that we don't want to eat the lighter + return REFUSED; + } + + if( !p.will_accept_from_player( it ) ) { + reason = _( "I don't trust you enough to eat THIS…" ); + return REFUSED; + } + + // TODO: Make it not a copy+paste from player::consume_item + int amount_used = 1; + if( to_eat.is_food() ) { + if( !p.can_consume( to_eat ) ) { + reason = _( "It doesn't look like a good idea to consume this…" ); + return REFUSED; + } else { + const time_duration &consume_time = p.get_consume_time( to_eat ); + p.moves -= to_moves( consume_time ); + p.consume( to_eat ); + reason = _( "Thanks, that hit the spot." ); + + } + } else if( to_eat.is_medication() ) { + if( !comest->tool.is_null() ) { + bool has = p.has_amount( comest->tool, 1 ); + if( item::count_by_charges( comest->tool ) ) { + has = p.has_charges( comest->tool, 1 ); + } + if( !has ) { + reason = string_format( _( "I need a %s to consume that!" ), + item::nname( comest->tool ) ); + return REFUSED; + } + p.use_charges( comest->tool, 1 ); + reason = _( "Thanks, I feel better already." ); + } + if( to_eat.type->has_use() ) { + amount_used = to_eat.type->invoke( p, to_eat, p.pos() ); + if( amount_used <= 0 ) { + reason = _( "It doesn't look like a good idea to consume this…" ); + return REFUSED; + } + reason = _( "Thanks, I used it." ); + } + + to_eat.charges -= amount_used; + p.consume_effects( to_eat ); + p.moves -= 250; + } else { + debugmsg( "Unknown comestible type of item: %s\n", to_eat.tname() ); + } + + if( to_eat.charges > 0 ) { + return CONSUMED_SOME; + } + + // If not consuming contents and charge <= 0, we just ate the last charge from the stack + return CONSUMED_ALL; +} + +std::string talker_npc::give_item_to( const bool to_use ) +{ + avatar &u = get_avatar(); + if( me_npc->is_hallucination() ) { + return _( "No thanks, I'm good." ); + } + item_location loc = game_menus::inv::titled_menu( g->u, _( "Offer what?" ), + _( "You have no items to offer." ) ); + if( !loc ) { + return _( "Changed your mind?" ); + } + item &given = *loc; + + if( ( &given == &u.weapon && given.has_flag( "NO_UNWIELD" ) ) || + ( u.is_worn( given ) && given.has_flag( "NO_TAKEOFF" ) ) ) { + // Bionic weapon or shackles + return _( "How?" ); + } + + if( given.is_dangerous() && !u.has_trait( trait_DEBUG_MIND_CONTROL ) ) { + return _( "Are you insane!?" ); + } + + bool taken = false; + std::string reason = _( "Nope." ); + int our_ammo = me_npc->ammo_count_for( me_npc->weapon ); + int new_ammo = me_npc->ammo_count_for( given ); + const double new_weapon_value = me_npc->weapon_value( given, new_ammo ); + const double cur_weapon_value = me_npc->weapon_value( me_npc->weapon, our_ammo ); + add_msg( m_debug, "NPC evaluates own %s (%d ammo): %0.1f", + me_npc->weapon.typeId().str(), our_ammo, cur_weapon_value ); + add_msg( m_debug, "NPC evaluates your %s (%d ammo): %0.1f", + given.typeId().str(), new_ammo, new_weapon_value ); + if( to_use ) { + // Eating first, to avoid evaluating bread as a weapon + const consumption_result consume_res = try_consume( *me_npc, given, reason ); + if( consume_res != REFUSED ) { + if( consume_res == CONSUMED_ALL ) { + u.i_rem( &given ); + } + u.moves -= 100; + if( given.is_container() ) { + given.on_contents_changed(); + } + }// wield it if its a weapon + else if( new_weapon_value > cur_weapon_value ) { + me_npc->wield( given ); + reason = _( "Thanks, I'll wield that now." ); + taken = true; + }// HACK: is_gun here is a hack to prevent NPCs wearing guns if they don't want to use them + else if( !given.is_gun() && given.is_armor() ) { + //if it is impossible to wear return why + ret_val can_wear = me_npc->can_wear( given, true ); + if( !can_wear.success() ) { + reason = can_wear.str(); + } else { + //if we can wear it with equip changes prompt first + can_wear = me_npc->can_wear( given ); + if( ( can_wear.success() || + query_yn( can_wear.str() + _( " Should I take something off?" ) ) ) + && me_npc->wear_if_wanted( given, reason ) ) { + taken = true; + } else { + reason = can_wear.str(); + } + } + } else { + reason += string_format( _( "My current weapon is better than this.\n" + "(new weapon value: %.1f vs %.1f)." ), new_weapon_value, + cur_weapon_value ); + } + } else {//allow_use is false so try to carry instead + if( me_npc->can_pickVolume( given ) && me_npc->can_pickWeight( given ) ) { + reason = _( "Thanks, I'll carry that now." ); + taken = true; + me_npc->i_add( given ); + } else { + if( !me_npc->can_pickVolume( given ) ) { + const units::volume free_space = me_npc->volume_capacity() - + me_npc->volume_carried(); + reason += "\n" + std::string( _( "I have no space to store it." ) ) + "\n"; + if( free_space > 0_ml ) { + reason += string_format( _( "I can only store %s %s more." ), + format_volume( free_space ), volume_units_long() ); + } else { + reason += _( "…or to store anything else for that matter." ); + } + } + if( !me_npc->can_pickWeight( given ) ) { + reason += std::string( "\n" ) + _( "It is too heavy for me to carry." ); + } + } + } + + + if( taken ) { + u.i_rem( &given ); + u.moves -= 100; + me_npc->has_new_items = true; + } + + return reason; +} + +bool talker_npc::buy_from( const int amount ) +{ + return npc_trading::pay_npc( *me_npc, amount ); +} + +std::vector talker_npc::available_missions() const +{ + return me_npc->chatbin.missions; +} + +std::vector talker_npc::assigned_missions() const +{ + return me_npc->chatbin.missions_assigned; +} + +mission *talker_npc::selected_mission() const +{ + return me_npc->chatbin.mission_selected; +} + +void talker_npc::select_mission( mission *selected ) +{ + me_npc->chatbin.mission_selected = selected; +} + +void talker_npc::add_mission( const mission_type_id &mission_id ) +{ + mission *miss = mission::reserve_new( mission_id, me_npc->getID() ); + miss->assign( get_avatar() ); + me_npc->chatbin.missions_assigned.push_back( miss ); +} + +void talker_npc::set_companion_mission( const std::string &role_id ) +{ + me_npc->companion_mission_role_id = role_id; + talk_function::companion_mission( *me_npc ); +} + +void talker_npc::set_fac( const faction_id &new_fac_name ) +{ + me_npc->set_fac( new_fac_name ); +} + +void talker_npc::add_faction_rep( const int rep_change ) +{ + if( me_npc->get_faction()-> id != faction_id( "no_faction" ) ) { + me_npc->get_faction()->likes_u += rep_change; + me_npc->get_faction()->respects_u += rep_change; + } +} + +bool talker_npc::is_following() const +{ + return me_npc->is_following(); +} + +bool talker_npc::is_friendly( const Character &guy ) const +{ + return me_npc->is_friendly( guy ); +} + +bool talker_npc::is_enemy() const +{ + return me_npc->is_enemy(); +} + +bool talker_npc::is_player_ally() const +{ + return me_npc->is_player_ally(); +} + +bool talker_npc::turned_hostile() const +{ + return me_npc->turned_hostile(); +} + +void talker_npc::make_angry() +{ + me_npc->make_angry(); +} + +bool talker_npc::has_ai_rule( const std::string &type, + const std::string &rule ) const +{ + if( type == "aim_rule" ) { + auto rule_val = aim_rule_strs.find( rule ); + if( rule_val != aim_rule_strs.end() ) { + return me_npc->rules.aim == rule_val->second; + } + } else if( type == "engagement_rule" ) { + auto rule_val = combat_engagement_strs.find( rule ); + if( rule_val != combat_engagement_strs.end() ) { + return me_npc->rules.engagement == rule_val->second; + } + } else if( type == "cbm_reserve_rule" ) { + auto rule_val = cbm_reserve_strs.find( rule ); + if( rule_val != cbm_reserve_strs.end() ) { + return me_npc->rules.cbm_reserve == rule_val->second; + } + } else if( type == "cbm_recharge_rule" ) { + auto rule_val = cbm_recharge_strs.find( rule ); + if( rule_val != cbm_recharge_strs.end() ) { + return me_npc->rules.cbm_recharge == rule_val->second; + } + } else if( type == "ally_rule" ) { + auto rule_val = ally_rule_strs.find( rule ); + if( rule_val != ally_rule_strs.end() ) { + return me_npc->rules.has_flag( rule_val->second.rule ); + } + } else if( type == "ally_override" ) { + auto rule_val = ally_rule_strs.find( rule ); + if( rule_val != ally_rule_strs.end() ) { + return me_npc->rules.has_override_enable( rule_val->second.rule ); + } + } else if( type == "pickup_rule" ) { + if( rule == "any" ) { + return !me_npc->rules.pickup_whitelist->empty(); + } + } + + return false; +} + +void talker_npc::toggle_ai_rule( const std::string &, const std::string &rule ) +{ + auto toggle = ally_rule_strs.find( rule ); + if( toggle == ally_rule_strs.end() ) { + return; + } + me_npc->rules.toggle_flag( toggle->second.rule ); + me_npc->invalidate_range_cache(); + me_npc->wield_better_weapon(); +} + +void talker_npc::set_ai_rule( const std::string &type, const std::string &rule ) +{ + if( type == "aim_rule" ) { + auto rule_val = aim_rule_strs.find( rule ); + if( rule_val != aim_rule_strs.end() ) { + me_npc->rules.aim = rule_val->second; + me_npc->invalidate_range_cache(); + } + } else if( type == "engagement_rule" ) { + auto rule_val = combat_engagement_strs.find( rule ); + if( rule_val != combat_engagement_strs.end() ) { + me_npc->rules.engagement = rule_val->second; + me_npc->invalidate_range_cache(); + me_npc->wield_better_weapon(); + } + } else if( type == "cbm_reserve_rule" ) { + auto rule_val = cbm_reserve_strs.find( rule ); + if( rule_val != cbm_reserve_strs.end() ) { + me_npc->rules.cbm_reserve = rule_val->second; + } + } else if( type == "cbm_recharge_rule" ) { + auto rule_val = cbm_recharge_strs.find( rule ); + if( rule_val != cbm_recharge_strs.end() ) { + me_npc->rules.cbm_recharge = rule_val->second; + } + } else if( type == "ally_rule" ) { + auto toggle = ally_rule_strs.find( rule ); + if( toggle == ally_rule_strs.end() ) { + return; + } + me_npc->rules.set_flag( toggle->second.rule ); + me_npc->invalidate_range_cache(); + me_npc->wield_better_weapon(); + } +} + +void talker_npc::clear_ai_rule( const std::string &, const std::string &rule ) +{ + auto toggle = ally_rule_strs.find( rule ); + if( toggle == ally_rule_strs.end() ) { + return; + } + me_npc->rules.clear_flag( toggle->second.rule ); + me_npc->invalidate_range_cache(); + me_npc->wield_better_weapon(); +} + +std::string talker_npc::get_job_description() const +{ + return me_npc->describe_mission(); +} + +std::string talker_npc::evaluation_by( const talker &alpha ) const +{ + ///\EFFECT_PER affects whether player can size up NPCs + + ///\EFFECT_INT slightly affects whether player can size up NPCs + int ability = alpha.per_cur() * 3 + alpha.int_cur(); + if( ability <= 10 ) { + return _( "&You can't make anything out." ); + } + + if( is_player_ally() || ability > 100 ) { + ability = 100; + } + + std::string info = "&"; + int str_range = static_cast( 100 / ability ); + int str_min = static_cast( me_npc->str_max / str_range ) * str_range; + info += string_format( _( "Str %d - %d" ), str_min, str_min + str_range ); + + if( ability >= 40 ) { + int dex_range = static_cast( 160 / ability ); + int dex_min = static_cast( me_npc->dex_max / dex_range ) * dex_range; + info += string_format( _( " Dex %d - %d" ), dex_min, dex_min + dex_range ); + } + + if( ability >= 50 ) { + int int_range = static_cast( 200 / ability ); + int int_min = static_cast( me_npc->int_max / int_range ) * int_range; + info += string_format( _( " Int %d - %d" ), int_min, int_min + int_range ); + } + + if( ability >= 60 ) { + int per_range = static_cast( 240 / ability ); + int per_min = static_cast( me_npc->per_max / per_range ) * per_range; + info += string_format( _( " Per %d - %d" ), per_min, per_min + per_range ); + } + needs_rates rates = me_npc->calc_needs_rates(); + if( ability >= 100 - ( get_fatigue() / 10 ) ) { + std::string how_tired; + if( get_fatigue() > fatigue_levels::EXHAUSTED ) { + how_tired = _( "Exhausted" ); + } else if( get_fatigue() > fatigue_levels::DEAD_TIRED ) { + how_tired = _( "Dead tired" ); + } else if( get_fatigue() > fatigue_levels::TIRED ) { + how_tired = _( "Tired" ); + } else { + how_tired = _( "Not tired" ); + if( ability >= 100 ) { + time_duration sleep_at = 5_minutes * ( fatigue_levels::TIRED - + get_fatigue() ) / rates.fatigue; + how_tired += _( ". Will need sleep in " ) + to_string_approx( sleep_at ); + } + } + info += "\n" + how_tired; + } + if( ability >= 100 ) { + if( get_thirst() < 100 ) { + time_duration thirst_at = 5_minutes * ( 100 - get_thirst() ) / rates.thirst; + if( thirst_at > 1_hours ) { + info += _( "\nWill need water in " ) + to_string_approx( thirst_at ); + } + } else { + info += _( "\nThirsty" ); + } + if( get_hunger() < 100 ) { + time_duration hunger_at = 5_minutes * ( 100 - get_hunger() ) / rates.hunger; + if( hunger_at > 1_hours ) { + info += _( "\nWill need food in " ) + to_string_approx( hunger_at ); + } + } else { + info += _( "\nHungry" ); + } + } + return info; + +} + +bool talker_npc::has_activity() const +{ + return !me_npc->activity.is_null(); +} + +bool talker_npc::is_myclass( const npc_class_id &class_to_check ) const +{ + return me_npc->myclass == class_to_check; +} + +void talker_npc::set_class( const npc_class_id &new_class ) +{ + me_npc->myclass = new_class; +} + +void talker_npc::say( const std::string &speech ) +{ + me_npc->say( speech ); +} + +std::string talker_npc::opinion_text() const +{ + return me_npc->opinion_text(); +} + +void talker_npc::add_opinion( const int trust, const int fear, const int value, + const int anger, const int debt ) +{ + me_npc->op_of_u += npc_opinion( trust, fear, value, anger, debt ); +} + +bool talker_npc::enslave_mind() +{ + bool not_following = g->get_follower_list().count( me_npc->getID() ) == 0; + me_npc->companion_mission_role_id.clear(); + talk_function::follow( *me_npc ); + return not_following; +} diff --git a/src/talker_npc.h b/src/talker_npc.h new file mode 100644 index 0000000000000..6b90de18b340d --- /dev/null +++ b/src/talker_npc.h @@ -0,0 +1,106 @@ +#pragma once +#ifndef CATA_SRC_TALKER_NPC_H +#define CATA_SRC_TALKER_NPC_H + +#include "talker.h" +#include "talker_character.h" + +class Character; +class faction; +class item; +class mission; +class npc; +class player; +class recipe; +struct tripoint; +class vehicle; + +/* + */ +class talker_npc : public talker_character +{ + public: + talker_npc( npc *new_me ): talker_character( new_me ), me_npc( new_me ) { + } + ~talker_npc() override = default; + + npc *get_npc() override { + return me_npc; + } + npc *get_npc() const override { + return me_npc; + } + + // identity and location + std::string distance_to_goal() const override; + + // mandatory functions for starting a dialogue + bool will_talk_to_u( const player &u, bool force ) override; + std::vector get_topics( bool radio_contact ) override; + void check_missions() override; + void update_missions( const std::vector &missions_assigned, + const character_id &charID ) override; + bool check_hostile_response( int anger ) const override; + int parse_mod( const std::string &attribute, int factor ) const override; + int trial_chance_mod( const std::string &trial_type ) const override; + + // stats, skills, traits, bionics, and magic + std::vector skills_offered_to( const talker &student ) const override; + std::string skill_training_text( const talker &, const skill_id & ) const override; + std::vector styles_offered_to( const talker &student ) const override; + std::string style_training_text( const talker &, const matype_id & ) const override; + std::vector spells_offered_to( talker &student ) override; + std::string spell_training_text( talker &, const spell_id & ) override; + void store_chosen_training( const skill_id &c_skill, const matype_id &c_style, + const spell_id &c_spell ) override; + + // inventory, buying, and selling + void add_debt( int cost ) override; + int debt() const override; + int cash_to_favor( int value ) const override; + std::string give_item_to( bool to_use ) override; + bool buy_from( int amount ) override; + + // missions + std::vector available_missions() const override; + std::vector assigned_missions() const override; + mission *selected_mission() const override; + void select_mission( mission *selected ) override; + void add_mission( const mission_type_id &mission_id ) override; + void set_companion_mission( const std::string &role_id ) override; + + // factions and alliances + void set_fac( const faction_id &new_fac_name ) override; + void add_faction_rep( int rep_change ) override; + bool is_following() const override; + bool is_friendly( const Character &guy ) const override; + bool is_enemy() const override; + bool is_player_ally() const override; + bool turned_hostile() const override; + void make_angry() override; + + // ai rules + bool has_ai_rule( const std::string &type, const std::string &rule ) const override; + void toggle_ai_rule( const std::string &type, const std::string &rule ) override; + void set_ai_rule( const std::string &type, const std::string &rule ) override; + void clear_ai_rule( const std::string &type, const std::string &rule ) override; + + // other descriptors + std::string get_job_description() const override; + std::string evaluation_by( const talker &alpha ) const override; + bool has_activity() const override; + bool is_myclass( const npc_class_id &class_to_check ) const override; + void set_class( const npc_class_id &new_class ) override; + + // speaking + void say( const std::string &speech ) override; + + // miscellaneous + std::string opinion_text() const override; + void add_opinion( int trust, int fear, int value, int anger, int debt ) override; + bool enslave_mind() override; + + protected: + npc *me_npc; +}; +#endif // CATA_SRC_TALKER_NPC_H diff --git a/src/teleport.cpp b/src/teleport.cpp index 732bf41e5b8d8..c420880121dd6 100644 --- a/src/teleport.cpp +++ b/src/teleport.cpp @@ -3,9 +3,9 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" +#include "character.h" #include "creature.h" #include "debug.h" #include "enums.h" @@ -14,7 +14,6 @@ #include "game.h" #include "map.h" #include "messages.h" -#include "player.h" #include "point.h" #include "rng.h" #include "translations.h" @@ -30,8 +29,8 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, debugmsg( "ERROR: Function teleport::teleport called with invalid arguments." ); return false; } - player *const p = critter.as_player(); - const bool c_is_u = p != nullptr && p == &g->u; + Character *const p = critter.as_character(); + const bool c_is_u = p != nullptr && p->is_avatar(); int tries = 0; tripoint origin = critter.pos(); tripoint new_pos = origin; @@ -67,7 +66,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, } //handles telefragging other creatures if( Creature *const poor_soul = g->critter_at( new_pos ) ) { - player *const poor_player = dynamic_cast( poor_soul ); + Character *const poor_player = dynamic_cast( poor_soul ); if( safe ) { if( c_is_u ) { add_msg( m_bad, _( "You cannot teleport safely." ) ); @@ -78,7 +77,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, poor_player->add_msg_if_player( m_warning, _( "You feel disjointed." ) ); return false; } else { - const bool poor_soul_is_u = ( poor_soul == &g->u ); + const bool poor_soul_is_u = poor_soul->is_avatar(); if( poor_soul_is_u ) { add_msg( m_bad, _( "…" ) ); add_msg( m_bad, _( "You explode into thousands of fragments." ) ); @@ -90,7 +89,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, poor_soul->disp_name() ); g->events().send( p->getID(), poor_soul->get_name() ); } else { - if( g->u.sees( *poor_soul ) ) { + if( get_player_character().sees( *poor_soul ) ) { add_msg( m_good, _( "%1$s teleports into %2$s, killing them!" ), critter.disp_name(), poor_soul->disp_name() ); } diff --git a/src/timed_event.cpp b/src/timed_event.cpp index 4d0ca8439bff2..1fd1e629d68e8 100644 --- a/src/timed_event.cpp +++ b/src/timed_event.cpp @@ -49,20 +49,22 @@ timed_event::timed_event( timed_event_type e_t, const time_point &w, int f_id, t void timed_event::actualize() { + avatar &player_character = get_avatar(); + map &here = get_map(); switch( type ) { case timed_event_type::HELP: debugmsg( "Currently disabled while NPC and monster factions are being rewritten." ); break; case timed_event_type::ROBOT_ATTACK: { - const auto u_pos = g->u.global_sm_location(); + const auto u_pos = player_character.global_sm_location(); if( rl_dist( u_pos, map_point ) <= 4 ) { const mtype_id &robot_type = one_in( 2 ) ? mon_copbot : mon_riotbot; - g->events().send( g->u.getID() ); + g->events().send( player_character.getID() ); point rob( u_pos.x > map_point.x ? 0 - SEEX * 2 : SEEX * 4, u_pos.y > map_point.y ? 0 - SEEY * 2 : SEEY * 4 ); - g->place_critter_at( robot_type, tripoint( rob, g->u.posz() ) ); + g->place_critter_at( robot_type, tripoint( rob, player_character.posz() ) ); } } break; @@ -76,17 +78,18 @@ void timed_event::actualize() pgettext( "memorial_female", "Drew the attention of more dark wyrms!" ) ); int num_wyrms = rng( 1, 4 ); for( int i = 0; i < num_wyrms; i++ ) { - if( monster *const mon = g->place_critter_around( mon_dark_wyrm, g->u.pos(), 2 ) ) { - g->m.ter_set( mon->pos(), t_rock_floor ); + if( monster *const mon = g->place_critter_around( mon_dark_wyrm, player_character.pos(), 2 ) ) { + here.ter_set( mon->pos(), t_rock_floor ); } } // You could drop the flag, you know. - if( g->u.has_amount( itype_petrified_eye, 1 ) ) { - sounds::sound( g->u.pos(), 60, sounds::sound_t::alert, _( "a tortured scream!" ), false, "shout", + if( player_character.has_amount( itype_petrified_eye, 1 ) ) { + sounds::sound( player_character.pos(), 60, sounds::sound_t::alert, _( "a tortured scream!" ), false, + "shout", "scream_tortured" ); - if( !g->u.is_deaf() ) { + if( !player_character.is_deaf() ) { add_msg( _( "The eye you're carrying lets out a tortured scream!" ) ); - g->u.add_morale( MORALE_SCREAM, -15, 0, 30_minutes, 30_seconds ); + player_character.add_morale( MORALE_SCREAM, -15, 0, 30_minutes, 30_seconds ); } } // They just keep coming! @@ -102,20 +105,20 @@ void timed_event::actualize() int num_horrors = rng( 3, 5 ); cata::optional fault_point; bool horizontal = false; - for( const tripoint &p : g->m.points_on_zlevel() ) { - if( g->m.ter( p ) == t_fault ) { + for( const tripoint &p : here.points_on_zlevel() ) { + if( here.ter( p ) == t_fault ) { fault_point = p; - horizontal = g->m.ter( p + tripoint_east ) == t_fault || g->m.ter( p + tripoint_west ) == t_fault; + horizontal = here.ter( p + tripoint_east ) == t_fault || here.ter( p + tripoint_west ) == t_fault; break; } } for( int i = 0; fault_point && i < num_horrors; i++ ) { for( int tries = 0; tries < 10; ++tries ) { - tripoint monp = g->u.pos(); + tripoint monp = player_character.pos(); if( horizontal ) { monp.x = rng( fault_point->x, fault_point->x + 2 * SEEX - 8 ); for( int n = -1; n <= 1; n++ ) { - if( g->m.ter( point( monp.x, fault_point->y + n ) ) == t_rock_floor ) { + if( here.ter( point( monp.x, fault_point->y + n ) ) == t_rock_floor ) { monp.y = fault_point->y + n; } } @@ -123,7 +126,7 @@ void timed_event::actualize() // Vertical fault monp.y = rng( fault_point->y, fault_point->y + 2 * SEEY - 8 ); for( int n = -1; n <= 1; n++ ) { - if( g->m.ter( point( fault_point->x + n, monp.y ) ) == t_rock_floor ) { + if( here.ter( point( fault_point->x + n, monp.y ) ) == t_rock_floor ) { monp.x = fault_point->x + n; } } @@ -138,9 +141,9 @@ void timed_event::actualize() case timed_event_type::ROOTS_DIE: g->events().send(); - for( const tripoint &p : g->m.points_on_zlevel() ) { - if( g->m.ter( p ) == t_root_wall && one_in( 3 ) ) { - g->m.ter_set( p, t_underbrush ); + for( const tripoint &p : here.points_on_zlevel() ) { + if( here.ter( p ) == t_root_wall && one_in( 3 ) ) { + here.ter_set( p, t_underbrush ); } } break; @@ -148,10 +151,10 @@ void timed_event::actualize() case timed_event_type::TEMPLE_OPEN: { g->events().send(); bool saw_grate = false; - for( const tripoint &p : g->m.points_on_zlevel() ) { - if( g->m.ter( p ) == t_grate ) { - g->m.ter_set( p, t_stairs_down ); - if( !saw_grate && g->u.sees( p ) ) { + for( const tripoint &p : here.points_on_zlevel() ) { + if( here.ter( p ) == t_grate ) { + here.ter_set( p, t_stairs_down ); + if( !saw_grate && player_character.sees( p ) ) { saw_grate = true; } } @@ -166,14 +169,14 @@ void timed_event::actualize() bool flooded = false; ter_id flood_buf[MAPSIZE_X][MAPSIZE_Y]; - for( const tripoint &p : g->m.points_on_zlevel() ) { - flood_buf[p.x][p.y] = g->m.ter( p ); + for( const tripoint &p : here.points_on_zlevel() ) { + flood_buf[p.x][p.y] = here.ter( p ); } - for( const tripoint &p : g->m.points_on_zlevel() ) { - if( g->m.ter( p ) == t_water_sh ) { + for( const tripoint &p : here.points_on_zlevel() ) { + if( here.ter( p ) == t_water_sh ) { bool deepen = false; for( const tripoint &w : points_in_radius( p, 1 ) ) { - if( g->m.ter( w ) == t_water_dp ) { + if( here.ter( w ) == t_water_dp ) { deepen = true; break; } @@ -182,10 +185,10 @@ void timed_event::actualize() flood_buf[p.x][p.y] = t_water_dp; flooded = true; } - } else if( g->m.ter( p ) == t_rock_floor ) { + } else if( here.ter( p ) == t_rock_floor ) { bool flood = false; for( const tripoint &w : points_in_radius( p, 1 ) ) { - if( g->m.ter( w ) == t_water_dp || g->m.ter( w ) == t_water_sh ) { + if( here.ter( w ) == t_water_dp || here.ter( w ) == t_water_sh ) { flood = true; break; } @@ -201,8 +204,9 @@ void timed_event::actualize() return; } // Check if we should print a message - if( flood_buf[g->u.posx()][g->u.posy()] != g->m.ter( g->u.pos() ) ) { - if( flood_buf[g->u.posx()][g->u.posy()] == t_water_sh ) { + if( flood_buf[player_character.posx()][player_character.posy()] != here.ter( + player_character.pos() ) ) { + if( flood_buf[player_character.posx()][player_character.posy()] == t_water_sh ) { add_msg( m_warning, _( "Water quickly floods up to your knees." ) ); g->memorial().add( pgettext( "memorial_male", "Water level reached knees." ), @@ -213,12 +217,12 @@ void timed_event::actualize() g->memorial().add( pgettext( "memorial_male", "Water level reached the ceiling." ), pgettext( "memorial_female", "Water level reached the ceiling." ) ); - avatar_action::swim( g->m, g->u, g->u.pos() ); + avatar_action::swim( here, player_character, player_character.pos() ); } } - // flood_buf is filled with correct tiles; now copy them back to g->m - for( const tripoint &p : g->m.points_on_zlevel() ) { - g->m.ter_set( p, flood_buf[p.x][p.y] ); + // flood_buf is filled with correct tiles; now copy them back to here + for( const tripoint &p : here.points_on_zlevel() ) { + here.ter_set( p, flood_buf[p.x][p.y] ); } g->timed_events.add( timed_event_type::TEMPLE_FLOOD, calendar::turn + rng( 2_turns, 3_turns ) ); @@ -231,7 +235,7 @@ void timed_event::actualize() } }; const mtype_id &montype = random_entry( temple_monsters ); - g->place_critter_around( montype, g->u.pos(), 2 ); + g->place_critter_around( montype, player_character.pos(), 2 ); } break; @@ -243,17 +247,19 @@ void timed_event::actualize() void timed_event::per_turn() { + Character &player_character = get_player_character(); + map &here = get_map(); switch( type ) { case timed_event_type::WANTED: { // About once every 5 minutes. Suppress in classic zombie mode. if( g->get_levz() >= 0 && one_in( 50 ) && !get_option( "DISABLE_ROBOT_RESPONSE" ) ) { - point place = g->m.random_outdoor_tile(); + point place = here.random_outdoor_tile(); if( place.x == -1 && place.y == -1 ) { // We're safely indoors! return; } - g->place_critter_at( mon_eyebot, tripoint( place, g->u.posz() ) ); - if( g->u.sees( tripoint( place, g->u.posz() ) ) ) { + g->place_critter_at( mon_eyebot, tripoint( place, player_character.posz() ) ); + if( player_character.sees( tripoint( place, player_character.posz() ) ) ) { add_msg( m_warning, _( "An eyebot swoops down nearby!" ) ); } // One eyebot per trigger is enough, really @@ -267,7 +273,7 @@ void timed_event::per_turn() when -= 1_turns; return; } - if( calendar::once_every( 3_turns ) && !g->u.is_deaf() ) { + if( calendar::once_every( 3_turns ) && !player_character.is_deaf() ) { add_msg( m_warning, _( "You hear screeches from the rock above and around you!" ) ); } break; @@ -302,7 +308,7 @@ void timed_event_manager::process() void timed_event_manager::add( const timed_event_type type, const time_point &when, const int faction_id ) { - add( type, when, faction_id, g->u.global_sm_location() ); + add( type, when, faction_id, get_player_character().global_sm_location() ); } void timed_event_manager::add( const timed_event_type type, const time_point &when, diff --git a/src/trap.cpp b/src/trap.cpp index 3fe2a01f2a700..4a58c4a9c0046 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -190,6 +190,18 @@ void trap::reset() trap_factory.reset(); } +bool trap::is_trivial_to_spot() const +{ + // @TODO technically the trap may not be detected even with visibility == 0, see trap::detect_trap + return visibility <= 0 && !is_always_invisible(); +} + +bool trap::detected_by_ground_sonar() const +{ + // @TODO make this a property + return loadid == tr_beartrap_buried || loadid == tr_landmine_buried || loadid == tr_sinkhole; +} + bool trap::detect_trap( const tripoint &pos, const Character &p ) const { // Some decisions are based around: @@ -200,7 +212,7 @@ bool trap::detect_trap( const tripoint &pos, const Character &p ) const // noticing a buried landmine if standing right next to it. // Effective Perception... ///\EFFECT_PER increases chance of detecting a trap - return p.per_cur - p.encumb( bp_eyes ) / 10 + + return p.per_cur - p.encumb( bodypart_id( "eyes" ) ) / 10 + // ...small bonus from stimulants... ( p.get_stim() > 10 ? rng( 1, 2 ) : 0 ) + // ...bonus from trap skill... @@ -226,11 +238,27 @@ bool trap::can_see( const tripoint &pos, const Character &p ) const // There is no trap at all, so logically one can not see it. return false; } + if( is_always_invisible() ) { + return false; + } return visibility < 0 || p.knows_trap( pos ); } +void trap::trigger( const tripoint &pos, Creature &creature ) const +{ + return trigger( pos, &creature, nullptr ); +} + +void trap::trigger( const tripoint &pos, item &item ) const +{ + return trigger( pos, nullptr, &item ); +} + void trap::trigger( const tripoint &pos, Creature *creature, item *item ) const { + if( is_null() ) { + return; + } const bool is_real_creature = creature != nullptr && !creature->is_hallucination(); if( is_real_creature || item != nullptr ) { bool triggered = act( pos, creature, item ); @@ -274,26 +302,9 @@ void trap::on_disarmed( map &m, const tripoint &p ) const // convenient int-lookup names for hard-coded functions trap_id tr_null, -tr_bubblewrap, -tr_glass, -tr_cot, -tr_funnel, -tr_metal_funnel, -tr_makeshift_funnel, -tr_leather_funnel, -tr_rollmat, -tr_fur_rollmat, -tr_beartrap, tr_beartrap_buried, -tr_nailboard, -tr_caltrops, -tr_caltrops_glass, -tr_tripwire, -tr_crossbow, tr_shotgun_2, -tr_shotgun_2_1, tr_shotgun_1, -tr_engine, tr_blade, tr_landmine, tr_landmine_buried, @@ -302,19 +313,16 @@ tr_goo, tr_dissector, tr_sinkhole, tr_pit, -tr_spike_pit, tr_lava, tr_portal, tr_ledge, -tr_boobytrap, tr_temple_flood, tr_temple_toggle, tr_glow, tr_hum, tr_shadow, tr_drain, -tr_snake, -tr_glass_pit; +tr_snake; void trap::check_consistency() { @@ -328,6 +336,16 @@ void trap::check_consistency() } } +bool trap::easy_take_down() const +{ + return avoidance == 0 && difficulty == 0; +} + +bool trap::can_not_be_disarmed() const +{ + return difficulty >= 99; +} + void trap::finalize() { for( const trap &t_const : trap_factory.get_all() ) { @@ -342,26 +360,9 @@ void trap::finalize() return trap_str_id( id ).id(); }; tr_null = trap_str_id::NULL_ID().id(); - tr_bubblewrap = trapfind( "tr_bubblewrap" ); - tr_glass = trapfind( "tr_glass" ); - tr_cot = trapfind( "tr_cot" ); - tr_funnel = trapfind( "tr_funnel" ); - tr_metal_funnel = trapfind( "tr_metal_funnel" ); - tr_makeshift_funnel = trapfind( "tr_makeshift_funnel" ); - tr_leather_funnel = trapfind( "tr_leather_funnel" ); - tr_rollmat = trapfind( "tr_rollmat" ); - tr_fur_rollmat = trapfind( "tr_fur_rollmat" ); - tr_beartrap = trapfind( "tr_beartrap" ); tr_beartrap_buried = trapfind( "tr_beartrap_buried" ); - tr_nailboard = trapfind( "tr_nailboard" ); - tr_caltrops = trapfind( "tr_caltrops" ); - tr_caltrops_glass = trapfind( "tr_caltrops_glass" ); - tr_tripwire = trapfind( "tr_tripwire" ); - tr_crossbow = trapfind( "tr_crossbow" ); tr_shotgun_2 = trapfind( "tr_shotgun_2" ); - tr_shotgun_2_1 = trapfind( "tr_shotgun_2_1" ); tr_shotgun_1 = trapfind( "tr_shotgun_1" ); - tr_engine = trapfind( "tr_engine" ); tr_blade = trapfind( "tr_blade" ); tr_landmine = trapfind( "tr_landmine" ); tr_landmine_buried = trapfind( "tr_landmine_buried" ); @@ -370,11 +371,9 @@ void trap::finalize() tr_dissector = trapfind( "tr_dissector" ); tr_sinkhole = trapfind( "tr_sinkhole" ); tr_pit = trapfind( "tr_pit" ); - tr_spike_pit = trapfind( "tr_spike_pit" ); tr_lava = trapfind( "tr_lava" ); tr_portal = trapfind( "tr_portal" ); tr_ledge = trapfind( "tr_ledge" ); - tr_boobytrap = trapfind( "tr_boobytrap" ); tr_temple_flood = trapfind( "tr_temple_flood" ); tr_temple_toggle = trapfind( "tr_temple_toggle" ); tr_glow = trapfind( "tr_glow" ); @@ -382,5 +381,10 @@ void trap::finalize() tr_shadow = trapfind( "tr_shadow" ); tr_drain = trapfind( "tr_drain" ); tr_snake = trapfind( "tr_snake" ); - tr_glass_pit = trapfind( "tr_glass_pit" ); +} + +std::string trap::debug_describe() const +{ + return string_format( _( "Visible: %d\nAvoidance: %d\nDifficulty: %d\nBenign: %s" ), visibility, + avoidance, difficulty, is_benign() ? _( "Yes" ) : _( "No" ) ); } diff --git a/src/trap.h b/src/trap.h index 3ee31bfc1318a..5a5b199de84fe 100644 --- a/src/trap.h +++ b/src/trap.h @@ -83,6 +83,26 @@ struct vehicle_handle_trap_data { using trap_function = std::function; +/** + * Some traps aren't actually traps in the usual sense of the word. We use traps to implement + * funnels (the main map keeps a list of traps and we iterate over that list during rain + * in order to fill the containers with water). + * Use @ref is_benign to check for that kind of "non-dangerous" traps. Traps that are not benign + * are considered dangerous. + * + * Some traps are always invisible. They are never revealed as such to the player. + * They can still be triggered. Use @ref is_always_invisible to check for that. + * + * Traps names can be empty. This usually applies to always invisible traps. + * + * Some traps are always revealed to the player (e.g. funnels). Other traps can be spotted when + * the player is close (also needs perception stat). + * + * Use @ref map::can_see_trap_at or @ref trap::can_see to check whether a creature knows about a + * given trap. Monsters / NPCs should base their behavior on that information and not on a simple + * check for any trap being there (e.g. don't use `map::tr_at(...).is_null()` - that would reveal + * the existence of the trap). + */ struct trap { trap_str_id id; trap_id loadid; @@ -92,11 +112,21 @@ struct trap { int sym = 0; nc_color color; private: - // 1 to ??, affects detection + /** + * How easy it is to spot the trap. Smaller values means it's easier to spot. + * 1 to ??, affects detection + */ + // @TODO it can be negative (?) + // @TODO Add checks for it having proper values + // @TODO check usage in combination with is_always_invisible int visibility = 1; // 0 to ??, affects avoidance int avoidance = 0; - // 0 to ??, difficulty of assembly & disassembly + /* + * This is used when disarming the trap. A value of 0 means disarming will always work + * (e.g. for funnels), a values of 99 means it can not be disarmed at all. Smaller values + * makes it easier to disarm the trap. + */ int difficulty = 0; // 0 to ??, trap radius int trap_radius = 0; @@ -127,12 +157,22 @@ struct trap { bool is_always_invisible() const { return always_invisible; } + + bool operator==( const trap_id &id ) const { + return loadid == id; + } + bool operator!=( const trap_id &id ) const { + return loadid != id; + } + /** - * How easy it is to spot the trap. Smaller values means it's easier to spot. + * Called when the player examines a tile. This is supposed to handled + * all kind of interaction of the player with the trap, including removal. + * It also handles visibility of the trap, and it does nothing when + * called on the null trap. */ - int get_visibility() const { - return visibility; - } + // Implemented for historical reasons in iexamine.cpp + void examine( const tripoint &examp ) const; std::string map_regen_target() const; @@ -144,14 +184,6 @@ struct trap { int get_avoidance() const { return avoidance; } - /** - * This is used when disarming the trap. A value of 0 means disarming will always work - * (e.g. for funnels), a values of 99 means it can not be disarmed at all. Smaller values - * makes it easier to disarm the trap. - */ - int get_difficulty() const { - return difficulty; - } /** * If true, this is not really a trap and there won't be any safety queries before stepping * onto it (e.g. for funnels). @@ -159,6 +191,24 @@ struct trap { bool is_benign() const { return benign; } + /** + * @return True for traps that can simply be taken down without any skill check or similar. + * This usually applies to traps like funnels, rollmat. + */ + bool easy_take_down() const; + + bool is_trivial_to_spot() const; + + /** + * Some traps are part of the terrain (e.g. pits) and can therefor not be disarmed + * via the usual mechanics. They can be "disarmed" by changing the terrain they are part of. + */ + bool can_not_be_disarmed() const; + + /** + * Whether this kind of trap will be detected by ground sonar (e.g. via the bionic). + */ + bool detected_by_ground_sonar() const; /** Player has not yet seen the trap and returns the variable chance, at this moment, of whether the trap is seen or not. */ bool detect_trap( const tripoint &pos, const Character &p ) const; @@ -167,6 +217,7 @@ struct trap { * the trap) or by the visibility of the trap (the trap is not hidden at all)? */ bool can_see( const tripoint &pos, const Character &p ) const; + private: /** * Trigger trap effects. * @param creature The creature that triggered the trap, it does not necessarily have to @@ -176,11 +227,27 @@ struct trap { * @param pos The location of the trap in the main map. * @param item The item that triggered the trap */ - void trigger( const tripoint &pos, Creature *creature = nullptr, item *item = nullptr ) const; + // Don't call from outside this class. Add a wrapper like the ones below instead. + void trigger( const tripoint &pos, Creature *creature, item *item ) const; + public: + /*@{*/ + /** + * This applies the effects of the trap to the world and + * possibly to the triggering object (creature, item). + * + * The function assumes the + * caller has already checked whether the trap should be activated + * (e.g. the creature has had a chance to avoid the trap, but it failed). + */ + void trigger( const tripoint &pos, Creature &creature ) const; + void trigger( const tripoint &pos, item &item ) const; + /*@}*/ + /** * If the given item is throw onto the trap, does it trigger the trap? */ bool triggered_by_item( const item &itm ) const; + /** * Called when a trap at the given point in the map has been disarmed. * It should spawn trap items (if any) and remove the trap from the map via @@ -202,6 +269,8 @@ struct trap { */ void load( const JsonObject &jo, const std::string &src ); + std::string debug_describe() const; + /*@{*/ /** * @name Funnels @@ -254,26 +323,9 @@ const trap_function &trap_function_from_string( const std::string &function_name extern trap_id tr_null, -tr_bubblewrap, -tr_glass, -tr_cot, -tr_funnel, -tr_metal_funnel, -tr_makeshift_funnel, -tr_leather_funnel, -tr_rollmat, -tr_fur_rollmat, -tr_beartrap, tr_beartrap_buried, -tr_nailboard, -tr_caltrops, -tr_caltrops_glass, -tr_tripwire, -tr_crossbow, tr_shotgun_2, -tr_shotgun_2_1, tr_shotgun_1, -tr_engine, tr_blade, tr_landmine, tr_landmine_buried, @@ -282,12 +334,9 @@ tr_goo, tr_dissector, tr_sinkhole, tr_pit, -tr_spike_pit, -tr_glass_pit, tr_lava, tr_portal, tr_ledge, -tr_boobytrap, tr_temple_flood, tr_temple_toggle, tr_glow, diff --git a/src/trapfunc.cpp b/src/trapfunc.cpp index 96b57b3b0af00..fb1144d3d8bf5 100644 --- a/src/trapfunc.cpp +++ b/src/trapfunc.cpp @@ -67,7 +67,7 @@ static const mtype_id mon_shadow_snake( "mon_shadow_snake" ); static float pit_effectiveness( const tripoint &p ) { units::volume corpse_volume = 0_ml; - for( item &pit_content : g->m.i_at( p ) ) { + for( item &pit_content : get_map().i_at( p ) ) { if( pit_content.is_corpse() ) { corpse_volume += pit_content.volume(); } @@ -98,7 +98,7 @@ bool trapfunc::bubble( const tripoint &p, Creature *c, item * ) } } sounds::sound( p, 18, sounds::sound_t::alarm, _( "Pop!" ), false, "trap", "bubble_wrap" ); - g->m.remove_trap( p ); + get_map().remove_trap( p ); return true; } @@ -124,7 +124,7 @@ bool trapfunc::glass( const tripoint &p, Creature *c, item * ) } } sounds::sound( p, 10, sounds::sound_t::combat, _( "glass cracking!" ), false, "trap", "glass" ); - g->m.remove_trap( p ); + get_map().remove_trap( p ); return true; } @@ -147,7 +147,8 @@ bool trapfunc::beartrap( const tripoint &p, Creature *c, item * ) return false; } sounds::sound( p, 8, sounds::sound_t::combat, _( "SNAP!" ), false, "trap", "bear_trap" ); - g->m.remove_trap( p ); + map &here = get_map(); + here.remove_trap( p ); if( c != nullptr ) { // What got hit? const bodypart_id hit = one_in( 2 ) ? bodypart_id( "leg_l" ) : bodypart_id( "leg_r" ); @@ -176,7 +177,7 @@ bool trapfunc::beartrap( const tripoint &p, Creature *c, item * ) } c->check_dead_state(); } else { - g->m.spawn_item( p, "beartrap" ); + here.spawn_item( p, "beartrap" ); } return true; } @@ -197,7 +198,7 @@ bool trapfunc::board( const tripoint &, Creature *c, item * ) if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_warning, _( "Your %s stepped on a spiked board!" ), c->get_name() ); - g->u.moves -= 80; + get_player_character().moves -= 80; } else { z->moves -= 80; } @@ -232,7 +233,7 @@ bool trapfunc::caltrops( const tripoint &, Creature *c, item * ) if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_warning, _( "Your %s steps on a sharp metal caltrop!" ), c->get_name() ); - g->u.moves -= 80; + get_player_character().moves -= 80; } else { z->moves -= 80; } @@ -267,12 +268,12 @@ bool trapfunc::caltrops_glass( const tripoint &p, Creature *c, item * ) c->deal_damage( nullptr, bodypart_id( "foot_r" ), damage_instance( DT_CUT, rng( 9, 30 ) ) ); } c->check_dead_state(); - if( g->u.sees( p ) ) { + if( get_player_character().sees( p ) ) { add_msg( _( "The shards shatter!" ) ); sounds::sound( p, 8, sounds::sound_t::combat, _( "glass cracking!" ), false, "trap", "glass_caltrops" ); } - g->m.remove_trap( p ); + get_map().remove_trap( p ); return true; } @@ -289,21 +290,24 @@ bool trapfunc::tripwire( const tripoint &p, Creature *c, item * ) _( " trips over a tripwire!" ) ); monster *z = dynamic_cast( c ); player *n = dynamic_cast( c ); + + Character &player_character = get_player_character(); + map &here = get_map(); if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_bad, _( "Your %s trips over a tripwire!" ), z->get_name() ); std::vector valid; - for( const tripoint &jk : g->m.points_in_radius( p, 1 ) ) { + for( const tripoint &jk : here.points_in_radius( p, 1 ) ) { if( g->is_empty( jk ) ) { valid.push_back( jk ); } } if( !valid.empty() ) { - g->u.setpos( random_entry( valid ) ); - z->setpos( g->u.pos() ); + player_character.setpos( random_entry( valid ) ); + z->setpos( player_character.pos() ); } - g->u.moves -= 150; - g->update_map( g->u ); + player_character.moves -= 150; + g->update_map( player_character ); } else { z->stumble(); } @@ -312,7 +316,7 @@ bool trapfunc::tripwire( const tripoint &p, Creature *c, item * ) } } else if( n != nullptr ) { std::vector valid; - for( const tripoint &jk : g->m.points_in_radius( p, 1 ) ) { + for( const tripoint &jk : here.points_in_radius( p, 1 ) ) { if( g->is_empty( jk ) ) { valid.push_back( jk ); } @@ -321,8 +325,8 @@ bool trapfunc::tripwire( const tripoint &p, Creature *c, item * ) n->setpos( random_entry( valid ) ); } n->moves -= 150; - if( c == &g->u ) { - g->update_map( g->u ); + if( c->is_avatar() ) { + g->update_map( player_character ); } if( !n->is_mounted() ) { ///\EFFECT_DEX decreases chance of taking damage from a tripwire trap @@ -387,7 +391,7 @@ bool trapfunc::crossbow( const tripoint &p, Creature *c, item * ) _( " dodges the shot!" ) ); } } else if( z != nullptr ) { - bool seen = g->u.sees( *z ); + bool seen = get_player_character().sees( *z ); int chance = 0; // adapted from shotgun code - chance of getting hit depends on size switch( z->type->size ) { @@ -419,19 +423,21 @@ bool trapfunc::crossbow( const tripoint &p, Creature *c, item * ) } c->check_dead_state(); } - g->m.remove_trap( p ); - g->m.spawn_item( p, "crossbow" ); - g->m.spawn_item( p, "string_36" ); + map &here = get_map(); + here.remove_trap( p ); + here.spawn_item( p, "crossbow" ); + here.spawn_item( p, "string_36" ); if( add_bolt ) { - g->m.spawn_item( p, "bolt_steel", 1, 1 ); + here.spawn_item( p, "bolt_steel", 1, 1 ); } return true; } bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) { + map &here = get_map(); sounds::sound( p, 60, sounds::sound_t::combat, _( "Kerblam!" ), false, "fire_gun", - g->m.tr_at( p ).loadid == tr_shotgun_1 ? "shotgun_s" : "shotgun_d" ); + here.tr_at( p ) == tr_shotgun_1 ? "shotgun_s" : "shotgun_d" ); int shots = 1; if( c != nullptr ) { if( c->has_effect( effect_ridden ) ) { @@ -444,7 +450,7 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) if( n != nullptr ) { ///\EFFECT_STR_MAX increases chance of two shots from shotgun trap shots = ( one_in( 8 ) || one_in( 20 - n->str_max ) ? 2 : 1 ); - if( g->m.tr_at( p ).loadid != tr_shotgun_2 ) { + if( here.tr_at( p ) != tr_shotgun_2 ) { shots = 1; } ///\EFFECT_DODGE reduces chance of being hit by shotgun trap @@ -486,7 +492,7 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) _( " dodges the shot!" ) ); } } else if( z != nullptr ) { - bool seen = g->u.sees( *z ); + bool seen = get_player_character().sees( *z ); int chance = 0; switch( z->type->size ) { case creature_size::tiny: @@ -506,7 +512,7 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) break; } shots = ( one_in( 8 ) || one_in( chance ) ? 2 : 1 ); - if( g->m.tr_at( p ).loadid != tr_shotgun_2 ) { + if( here.tr_at( p ) != tr_shotgun_2 ) { shots = 1; } if( seen ) { @@ -518,9 +524,9 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) c->check_dead_state(); } - g->m.spawn_item( p, g->m.tr_at( p ).loadid == tr_shotgun_1 ? "shotgun_s" : "shotgun_d" ); - g->m.spawn_item( p, "string_36" ); - g->m.remove_trap( p ); + here.spawn_item( p, here.tr_at( p ) == tr_shotgun_1 ? "shotgun_s" : "shotgun_d" ); + here.spawn_item( p, "string_36" ); + here.remove_trap( p ); return true; } @@ -545,7 +551,7 @@ bool trapfunc::blade( const tripoint &, Creature *c, item * ) bool trapfunc::snare_light( const tripoint &p, Creature *c, item * ) { sounds::sound( p, 2, sounds::sound_t::combat, _( "Snap!" ), false, "trap", "snare" ); - g->m.remove_trap( p ); + get_map().remove_trap( p ); if( c == nullptr ) { return false; } @@ -571,7 +577,7 @@ bool trapfunc::snare_light( const tripoint &p, Creature *c, item * ) bool trapfunc::snare_heavy( const tripoint &p, Creature *c, item * ) { sounds::sound( p, 4, sounds::sound_t::combat, _( "Snap!" ), false, "trap", "snare" ); - g->m.remove_trap( p ); + get_map().remove_trap( p ); if( c == nullptr ) { return false; } @@ -622,7 +628,7 @@ bool trapfunc::landmine( const tripoint &p, Creature *c, item * ) _( " triggers a land mine!" ) ); } explosion_handler::explosion( p, 18, 0.5, false, 8 ); - g->m.remove_trap( p ); + get_map().remove_trap( p ); return true; } @@ -633,7 +639,7 @@ bool trapfunc::boobytrap( const tripoint &p, Creature *c, item * ) _( " triggers a booby trap!" ) ); } explosion_handler::explosion( p, 18, 0.6, false, 12 ); - g->m.remove_trap( p ); + get_map().remove_trap( p ); return true; } @@ -644,10 +650,10 @@ bool trapfunc::telepad( const tripoint &p, Creature *c, item * ) if( c == nullptr ) { return false; } - if( c == &g->u ) { + if( c->is_avatar() ) { c->add_msg_if_player( m_warning, _( "The air shimmers around you…" ) ); } else { - if( g->u.sees( p ) ) { + if( get_player_character().sees( p ) ) { add_msg( _( "The air shimmers around %s…" ), c->disp_name() ); } } @@ -657,7 +663,7 @@ bool trapfunc::telepad( const tripoint &p, Creature *c, item * ) bool trapfunc::goo( const tripoint &p, Creature *c, item * ) { - g->m.remove_trap( p ); + get_map().remove_trap( p ); if( c == nullptr ) { return false; } @@ -677,7 +683,7 @@ bool trapfunc::goo( const tripoint &p, Creature *c, item * ) return true; } else if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { - g->u.forced_dismount(); + get_player_character().forced_dismount(); } //All monsters except for blobs get a speed decrease if( z->type->id != mon_blob ) { @@ -703,6 +709,7 @@ bool trapfunc::dissector( const tripoint &p, Creature *c, item * ) return false; } monster *z = dynamic_cast( c ); + bool player_sees = get_player_character().sees( p ); if( z != nullptr ) { if( z->type->in_species( species_ROBOT ) ) { //The monster is a robot. So the dissector should not try to dissect the monsters flesh. @@ -726,7 +733,7 @@ bool trapfunc::dissector( const tripoint &p, Creature *c, item * ) ch->deal_damage( nullptr, bodypart_id( "leg_r" ), damage_instance( DT_CUT, 12 ) ); ch->deal_damage( nullptr, bodypart_id( "foot_l" ), damage_instance( DT_CUT, 10 ) ); ch->deal_damage( nullptr, bodypart_id( "foot_r" ), damage_instance( DT_CUT, 10 ) ); - if( g->u.sees( p ) ) { + if( player_sees ) { ch->add_msg_player_or_npc( m_bad, _( "Electrical beams emit from the floor and slice your flesh!" ), _( "Electrical beams emit from the floor and slice s flesh!" ) ); } @@ -736,7 +743,7 @@ bool trapfunc::dissector( const tripoint &p, Creature *c, item * ) //~ the sound of a dissector dissecting sounds::sound( p, 10, sounds::sound_t::combat, _( "BRZZZAP!" ), false, "trap", "dissector" ); - if( g->u.sees( p ) ) { + if( player_sees ) { add_msg( m_bad, _( "Electrical beams emit from the floor and slice the %s!" ), c->get_name() ); } c->deal_damage( nullptr, bodypart_id( "head" ), damage_instance( DT_CUT, 15 ) ); @@ -792,7 +799,7 @@ bool trapfunc::pit( const tripoint &p, Creature *c, item * ) } else if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_bad, _( "Your %s falls into a pit!" ), z->get_name() ); - g->u.forced_dismount(); + get_player_character().forced_dismount(); } z->deal_damage( nullptr, bodypart_id( "leg_l" ), damage_instance( DT_BASH, eff * rng( 10, 20 ) ) ); z->deal_damage( nullptr, bodypart_id( "leg_r" ), damage_instance( DT_BASH, eff * rng( 10, 20 ) ) ); @@ -815,6 +822,7 @@ bool trapfunc::pit_spikes( const tripoint &p, Creature *c, item * ) c->add_effect( effect_in_pit, 1_turns, num_bp, true ); monster *z = dynamic_cast( c ); player *n = dynamic_cast( c ); + Character &player_character = get_player_character(); if( n != nullptr ) { int dodge = n->get_dodge(); int damage = pit_effectiveness( p ) * rng( 20, 50 ); @@ -864,20 +872,21 @@ bool trapfunc::pit_spikes( const tripoint &p, Creature *c, item * ) } else if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_bad, _( "Your %s falls into a pit!" ), z->get_name() ); - g->u.forced_dismount(); + player_character.forced_dismount(); } z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_CUT, rng( 20, 50 ) ) ); } c->check_dead_state(); if( one_in( 4 ) ) { - if( g->u.sees( p ) ) { + if( player_character.sees( p ) ) { add_msg( _( "The spears break!" ) ); } - g->m.ter_set( p, t_pit ); + map &here = get_map(); + here.ter_set( p, t_pit ); // 4 spears to a pit for( int i = 0; i < 4; i++ ) { if( one_in( 3 ) ) { - g->m.spawn_item( p, "pointy_stick" ); + here.spawn_item( p, "pointy_stick" ); } } } @@ -898,6 +907,7 @@ bool trapfunc::pit_glass( const tripoint &p, Creature *c, item * ) c->add_effect( effect_in_pit, 1_turns, num_bp, true ); monster *z = dynamic_cast( c ); player *n = dynamic_cast( c ); + Character &player_character = get_player_character(); if( n != nullptr ) { int dodge = n->get_dodge(); int damage = pit_effectiveness( p ) * rng( 15, 35 ); @@ -951,20 +961,21 @@ bool trapfunc::pit_glass( const tripoint &p, Creature *c, item * ) } else if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_bad, _( "Your %s falls into a pit!" ), z->get_name() ); - g->u.forced_dismount(); + player_character.forced_dismount(); } z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_CUT, rng( 20, 50 ) ) ); } c->check_dead_state(); if( one_in( 5 ) ) { - if( g->u.sees( p ) ) { + if( player_character.sees( p ) ) { add_msg( _( "The shards shatter!" ) ); } - g->m.ter_set( p, t_pit ); + map &here = get_map(); + here.ter_set( p, t_pit ); // 20 shards in a pit. for( int i = 0; i < 20; i++ ) { if( one_in( 3 ) ) { - g->m.spawn_item( p, "glass_shard" ); + here.spawn_item( p, "glass_shard" ); } } } @@ -977,7 +988,7 @@ bool trapfunc::lava( const tripoint &p, Creature *c, item * ) return false; } c->add_msg_player_or_npc( m_bad, _( "The %s burns you horribly!" ), _( "The %s burns !" ), - g->m.tername( p ) ); + get_map().tername( p ) ); monster *z = dynamic_cast( c ); player *n = dynamic_cast( c ); if( n != nullptr ) { @@ -1032,39 +1043,40 @@ static tripoint random_neighbor( tripoint center ) return center; } -static bool sinkhole_safety_roll( player *p, const itype_id &itemname, const int diff ) +static bool sinkhole_safety_roll( player &p, const itype_id &itemname, const int diff ) { ///\EFFECT_STR increases chance to attach grapnel, bullwhip, or rope when falling into a sinkhole ///\EFFECT_DEX increases chance to attach grapnel, bullwhip, or rope when falling into a sinkhole ///\EFFECT_THROW increases chance to attach grapnel, bullwhip, or rope when falling into a sinkhole - const int throwing_skill_level = p->get_skill_level( skill_throw ); - const int roll = rng( throwing_skill_level, throwing_skill_level + p->str_cur + p->dex_cur ); + const int throwing_skill_level = p.get_skill_level( skill_throw ); + const int roll = rng( throwing_skill_level, throwing_skill_level + p.str_cur + p.dex_cur ); + map &here = get_map(); if( roll < diff ) { - p->add_msg_if_player( m_bad, _( "You fail to attach it…" ) ); - p->use_amount( itemname, 1 ); - g->m.spawn_item( random_neighbor( p->pos() ), itemname ); + p.add_msg_if_player( m_bad, _( "You fail to attach it…" ) ); + p.use_amount( itemname, 1 ); + here.spawn_item( random_neighbor( p.pos() ), itemname ); return false; } std::vector safe; - for( const tripoint &tmp : g->m.points_in_radius( p->pos(), 1 ) ) { - if( g->m.passable( tmp ) && g->m.tr_at( tmp ).loadid != tr_pit ) { + for( const tripoint &tmp : here.points_in_radius( p.pos(), 1 ) ) { + if( here.passable( tmp ) && here.tr_at( tmp ) != tr_pit ) { safe.push_back( tmp ); } } if( safe.empty() ) { - p->add_msg_if_player( m_bad, _( "There's nowhere to pull yourself to, and you sink!" ) ); - p->use_amount( itemname, 1 ); - g->m.spawn_item( random_neighbor( p->pos() ), itemname ); + p.add_msg_if_player( m_bad, _( "There's nowhere to pull yourself to, and you sink!" ) ); + p.use_amount( itemname, 1 ); + here.spawn_item( random_neighbor( p.pos() ), itemname ); return false; } else { - p->add_msg_player_or_npc( m_good, _( "You pull yourself to safety!" ), - _( " steps on a sinkhole, but manages to pull themselves to safety." ) ); - p->setpos( random_entry( safe ) ); - if( p == &g->u ) { - g->update_map( *p ); + p.add_msg_player_or_npc( m_good, _( "You pull yourself to safety!" ), + _( " steps on a sinkhole, but manages to pull themselves to safety." ) ); + p.setpos( random_entry( safe ) ); + if( p.is_avatar() ) { + g->update_map( p ); } return true; @@ -1079,29 +1091,30 @@ bool trapfunc::sinkhole( const tripoint &p, Creature *c, item *i ) } monster *z = dynamic_cast( c ); player *pl = dynamic_cast( c ); + map &here = get_map(); if( z != nullptr ) { if( z->has_effect( effect_ridden ) ) { add_msg( m_bad, _( "Your %s falls into a sinkhole!" ), z->get_name() ); - g->u.forced_dismount(); + get_player_character().forced_dismount(); } } else if( pl != nullptr ) { bool success = false; if( query_for_item( pl, itype_grapnel, _( "You step into a sinkhole! Throw your grappling hook out to try to catch something?" ) ) ) { - success = sinkhole_safety_roll( pl, itype_grapnel, 6 ); + success = sinkhole_safety_roll( *pl, itype_grapnel, 6 ); } else if( query_for_item( pl, itype_bullwhip, _( "You step into a sinkhole! Throw your whip out to try and snag something?" ) ) ) { - success = sinkhole_safety_roll( pl, itype_bullwhip, 8 ); + success = sinkhole_safety_roll( *pl, itype_bullwhip, 8 ); } else if( query_for_item( pl, itype_rope_30, _( "You step into a sinkhole! Throw your rope out to try to catch something?" ) ) ) { - success = sinkhole_safety_roll( pl, itype_rope_30, 12 ); + success = sinkhole_safety_roll( *pl, itype_rope_30, 12 ); } pl->add_msg_player_or_npc( m_warning, _( "The sinkhole collapses!" ), _( "A sinkhole under collapses!" ) ); if( success ) { - g->m.remove_trap( p ); - g->m.ter_set( p, t_pit ); + here.remove_trap( p ); + here.ter_set( p, t_pit ); return true; } pl->add_msg_player_or_npc( m_bad, _( "You fall into the sinkhole!" ), @@ -1109,8 +1122,8 @@ bool trapfunc::sinkhole( const tripoint &p, Creature *c, item *i ) } else { return false; } - g->m.remove_trap( p ); - g->m.ter_set( p, t_pit ); + here.remove_trap( p ); + here.ter_set( p, t_pit ); c->moves -= 100; pit( p, c, i ); return true; @@ -1125,18 +1138,19 @@ bool trapfunc::ledge( const tripoint &p, Creature *c, item * ) if( m != nullptr && m->flies() ) { return false; } - if( !g->m.has_zlevels() ) { - if( c == &g->u ) { + map &here = get_map(); + if( !here.has_zlevels() ) { + if( c->is_avatar() ) { add_msg( m_warning, _( "You fall down a level!" ) ); g->vertical_move( -1, true ); - if( g->u.has_trait( trait_WINGS_BIRD ) || ( one_in( 2 ) && - g->u.has_trait( trait_WINGS_BUTTERFLY ) ) ) { + if( c->has_trait( trait_WINGS_BIRD ) || ( one_in( 2 ) && + c->has_trait( trait_WINGS_BUTTERFLY ) ) ) { add_msg( _( "You flap your wings and flutter down gracefully." ) ); - } else if( g->u.has_active_bionic( bio_shock_absorber ) ) { + } else if( c->as_character()->has_active_bionic( bio_shock_absorber ) ) { add_msg( m_info, _( "You hit the ground hard, but your shock absorbers handle the impact admirably!" ) ); } else { - g->u.impact( 20, p ); + c->as_avatar()->impact( 20, p ); } } else { c->add_msg_if_npc( _( " falls down a level!" ) ); @@ -1156,7 +1170,7 @@ bool trapfunc::ledge( const tripoint &p, Creature *c, item * ) tripoint where = p; tripoint below = where; below.z--; - while( g->m.valid_move( where, below, false, true ) ) { + while( here.valid_move( where, below, false, true ) ) { where.z--; if( g->critter_at( where ) != nullptr ) { where.z++; @@ -1175,7 +1189,7 @@ bool trapfunc::ledge( const tripoint &p, Creature *c, item * ) } std::vector valid; - for( const tripoint &pt : g->m.points_in_radius( below, 1 ) ) { + for( const tripoint &pt : here.points_in_radius( below, 1 ) ) { if( g->is_empty( pt ) ) { valid.push_back( pt ); } @@ -1224,16 +1238,20 @@ bool trapfunc::ledge( const tripoint &p, Creature *c, item * ) bool trapfunc::temple_flood( const tripoint &p, Creature *c, item * ) { + if( c == nullptr ) { + return false; + } // Monsters and npcs are completely ignored here, should they? - if( c == &g->u ) { + if( c->is_avatar() ) { add_msg( m_warning, _( "You step on a loose tile, and water starts to flood the room!" ) ); tripoint tmp = p; int &i = tmp.x; int &j = tmp.y; + map &here = get_map(); for( i = 0; i < MAPSIZE_X; i++ ) { for( j = 0; j < MAPSIZE_Y; j++ ) { - if( g->m.tr_at( tmp ).loadid == tr_temple_flood ) { - g->m.remove_trap( tmp ); + if( here.tr_at( tmp ) == tr_temple_flood ) { + here.remove_trap( tmp ); } } } @@ -1245,32 +1263,36 @@ bool trapfunc::temple_flood( const tripoint &p, Creature *c, item * ) bool trapfunc::temple_toggle( const tripoint &p, Creature *c, item * ) { + if( c == nullptr ) { + return false; + } // Monsters and npcs are completely ignored here, should they? - if( c == &g->u ) { + if( c->is_avatar() ) { add_msg( _( "You hear the grinding of shifting rock." ) ); - const ter_id type = g->m.ter( p ); + map &here = get_map(); + const ter_id type = here.ter( p ); tripoint tmp = p; int &i = tmp.x; int &j = tmp.y; for( i = 0; i < MAPSIZE_X; i++ ) { for( j = 0; j < MAPSIZE_Y; j++ ) { if( type == t_floor_red ) { - if( g->m.ter( tmp ) == t_rock_green ) { - g->m.ter_set( tmp, t_floor_green ); - } else if( g->m.ter( tmp ) == t_floor_green ) { - g->m.ter_set( tmp, t_rock_green ); + if( here.ter( tmp ) == t_rock_green ) { + here.ter_set( tmp, t_floor_green ); + } else if( here.ter( tmp ) == t_floor_green ) { + here.ter_set( tmp, t_rock_green ); } } else if( type == t_floor_green ) { - if( g->m.ter( tmp ) == t_rock_blue ) { - g->m.ter_set( tmp, t_floor_blue ); - } else if( g->m.ter( tmp ) == t_floor_blue ) { - g->m.ter_set( tmp, t_rock_blue ); + if( here.ter( tmp ) == t_rock_blue ) { + here.ter_set( tmp, t_floor_blue ); + } else if( here.ter( tmp ) == t_floor_blue ) { + here.ter_set( tmp, t_rock_blue ); } } else if( type == t_floor_blue ) { - if( g->m.ter( tmp ) == t_rock_red ) { - g->m.ter_set( tmp, t_floor_red ); - } else if( g->m.ter( tmp ) == t_floor_red ) { - g->m.ter_set( tmp, t_rock_red ); + if( here.ter( tmp ) == t_rock_red ) { + here.ter_set( tmp, t_floor_red ); + } else if( here.ter( tmp ) == t_floor_red ) { + here.ter_set( tmp, t_rock_red ); } } } @@ -1295,7 +1317,7 @@ bool trapfunc::glow( const tripoint &p, Creature *c, item * ) if( z->has_effect( effect_ridden ) ) { if( one_in( 3 ) ) { add_msg( m_bad, _( "You're bathed in radiation!" ) ); - g->u.irradiate( rng( 10, 30 ) ); + get_player_character().irradiate( rng( 10, 30 ) ); } else if( one_in( 4 ) ) { add_msg( m_bad, _( "A blinding flash strikes you!" ) ); explosion_handler::flashbang( p ); @@ -1342,9 +1364,10 @@ bool trapfunc::hum( const tripoint &p, Creature *, item * ) bool trapfunc::shadow( const tripoint &p, Creature *c, item * ) { - if( c != &g->u ) { + if( c == nullptr || !c->is_avatar() ) { return false; } + map &here = get_map(); // Monsters and npcs are completely ignored here, should they? for( int tries = 0; tries < 10; tries++ ) { tripoint monp = p; @@ -1355,13 +1378,13 @@ bool trapfunc::shadow( const tripoint &p, Creature *c, item * ) monp.x = p.x + ( one_in( 2 ) ? -5 : +5 ); monp.y = p.y + rng( -5, +5 ); } - if( !g->m.sees( monp, p, 10 ) ) { + if( !here.sees( monp, p, 10 ) ) { continue; } if( monster *const spawned = g->place_critter_at( mon_shadow, monp ) ) { spawned->add_msg_if_npc( m_warning, _( "A shadow forms nearby." ) ); spawned->reset_special_rng( "DISAPPEAR" ); - g->m.remove_trap( p ); + here.remove_trap( p ); break; } } @@ -1373,15 +1396,16 @@ bool trapfunc::map_regen( const tripoint &p, Creature *c, item * ) if( c ) { player *n = dynamic_cast( c ); if( n ) { + map &here = get_map(); n->add_msg_if_player( m_warning, _( "Your surroundings shift!" ) ); const tripoint &omt_pos = n->global_omt_location(); - const std::string ®en_mapgen = g->m.tr_at( p ).map_regen_target(); - g->m.remove_trap( p ); + const std::string ®en_mapgen = here.tr_at( p ).map_regen_target(); + here.remove_trap( p ); if( !run_mapgen_update_func( regen_mapgen, omt_pos, nullptr, false ) ) { popup( _( "Failed to generate the new map" ) ); return false; } - g->m.set_transparency_cache_dirty( p.z ); + here.set_transparency_cache_dirty( p.z ); return true; } } @@ -1410,11 +1434,12 @@ bool trapfunc::cast_spell( const tripoint &p, Creature *critter, item * ) if( critter == nullptr ) { return false; } - const spell trap_spell = g->m.tr_at( p ).spell_data.get_spell( 0 ); + map &here = get_map(); + const spell trap_spell = here.tr_at( p ).spell_data.get_spell( 0 ); npc dummy; trap_spell.cast_all_effects( dummy, critter->pos() ); trap_spell.make_sound( p, 20 ); - g->m.remove_trap( p ); + here.remove_trap( p ); return true; } @@ -1422,8 +1447,9 @@ bool trapfunc::snake( const tripoint &p, Creature *, item * ) { //~ the sound a snake makes sounds::sound( p, 10, sounds::sound_t::movement, _( "ssssssss" ), false, "misc", "snake_hiss" ); + map &here = get_map(); if( one_in( 6 ) ) { - g->m.remove_trap( p ); + here.remove_trap( p ); } if( one_in( 3 ) ) { for( int tries = 0; tries < 10; tries++ ) { @@ -1435,13 +1461,13 @@ bool trapfunc::snake( const tripoint &p, Creature *, item * ) monp.x = p.x + ( one_in( 2 ) ? -5 : +5 ); monp.y = p.y + rng( -5, +5 ); } - if( !g->m.sees( monp, p, 10 ) ) { + if( !here.sees( monp, p, 10 ) ) { continue; } if( monster *const spawned = g->place_critter_at( mon_shadow_snake, monp ) ) { spawned->add_msg_if_npc( m_warning, _( "A shadowy snake forms nearby." ) ); spawned->reset_special_rng( "DISAPPEAR" ); - g->m.remove_trap( p ); + here.remove_trap( p ); break; } } diff --git a/src/turret.cpp b/src/turret.cpp index 8ecd3c4463af7..77c1760dc98a5 100644 --- a/src/turret.cpp +++ b/src/turret.cpp @@ -291,17 +291,21 @@ void turret_data::post_fire( player &p, int shots ) veh->drain( fuel_type_battery, mode->get_gun_ups_drain() * shots ); } -int turret_data::fire( player &p, const tripoint &target ) +int turret_data::fire( Character &c, const tripoint &target ) { if( !veh || !part ) { return 0; } int shots = 0; auto mode = base()->gun_current_mode(); + player *player_character = c.as_player(); + if( player_character == nullptr ) { + return 0; + } - prepare_fire( p ); - shots = p.fire_gun( target, mode.qty, *mode ); - post_fire( p, shots ); + prepare_fire( *player_character ); + shots = player_character->fire_gun( target, mode.qty, *mode ); + post_fire( *player_character, shots ); return shots; } @@ -392,8 +396,10 @@ bool vehicle::turrets_aim( std::vector &turrets ) t->reset_target( global_part_pos3( *t ) ); } + avatar &player_character = get_avatar(); // Get target - target_handler::trajectory trajectory = target_handler::mode_turrets( g->u, *this, turrets ); + target_handler::trajectory trajectory = target_handler::mode_turrets( player_character, *this, + turrets ); bool got_target = !trajectory.empty(); if( got_target ) { @@ -406,7 +412,8 @@ bool vehicle::turrets_aim( std::vector &turrets ) } ///\EFFECT_INT speeds up aiming of vehicle turrets - g->u.moves = std::min( 0, g->u.moves - 100 + ( 5 * g->u.int_cur ) ); + player_character.moves = std::min( 0, + player_character.moves - 100 + ( 5 * player_character.int_cur ) ); } return got_target; } @@ -563,7 +570,8 @@ int vehicle::automatic_fire_turret( vehicle_part &pt ) area += area == 1 ? 1 : 2; } - const bool u_see = g->u.sees( pos ); + Character &player_character = get_player_character(); + const bool u_see = player_character.sees( pos ); // The current target of the turret. auto &target = pt.target; if( target.first == target.second ) { @@ -612,7 +620,7 @@ int vehicle::automatic_fire_turret( vehicle_part &pt ) shots = gun.fire( cpu, targ ); - if( shots && u_see && !g->u.sees( targ ) ) { + if( shots && u_see && !player_character.sees( targ ) ) { add_msg( _( "The %1$s fires its %2$s!" ), name, pt.name() ); } diff --git a/src/type_id.h b/src/type_id.h index 16243d48fd54a..2bf368c2fc427 100644 --- a/src/type_id.h +++ b/src/type_id.h @@ -144,6 +144,9 @@ using start_location_id = string_id; class move_mode; using move_mode_id = string_id; +class proficiency; +using proficiency_id = string_id; + struct ter_t; using ter_id = int_id; using ter_str_id = string_id; @@ -179,6 +182,9 @@ using vpart_id = string_id; struct vehicle_prototype; using vproto_id = string_id; +struct weather_type; +using weather_type_id = string_id; + class zone_type; using zone_type_id = string_id; diff --git a/src/ui.cpp b/src/ui.cpp index 41eed88461d57..0f344af8d2e90 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -917,10 +917,11 @@ struct pointmenu_cb::impl_t { pointmenu_cb::impl_t::impl_t( const std::vector &pts ) : points( pts ) { last = INT_MIN; - last_view = g->u.view_offset; - terrain_draw_cb = make_shared_fast( [this]() { + avatar &player_character = get_avatar(); + last_view = player_character.view_offset; + terrain_draw_cb = make_shared_fast( [this, &player_character]() { if( last >= 0 && static_cast( last ) < points.size() ) { - g->draw_trail_to_square( g->u.view_offset, true ); + g->draw_trail_to_square( player_character.view_offset, true ); } } ); g->add_draw_callback( terrain_draw_cb ); @@ -928,7 +929,7 @@ pointmenu_cb::impl_t::impl_t( const std::vector &pts ) : points( pts ) pointmenu_cb::impl_t::~impl_t() { - g->u.view_offset = last_view; + get_avatar().view_offset = last_view; } void pointmenu_cb::impl_t::select( uilist *const menu ) @@ -937,13 +938,14 @@ void pointmenu_cb::impl_t::select( uilist *const menu ) return; } last = menu->selected; + avatar &player_character = get_avatar(); if( menu->selected < 0 || menu->selected >= static_cast( points.size() ) ) { - g->u.view_offset = tripoint_zero; + player_character.view_offset = tripoint_zero; } else { const tripoint ¢er = points[menu->selected]; - g->u.view_offset = center - g->u.pos(); + player_character.view_offset = center - player_character.pos(); // TODO: Remove this line when it's safe - g->u.view_offset.z = 0; + player_character.view_offset.z = 0; } g->invalidate_main_ui_adaptor(); } diff --git a/src/units.h b/src/units.h index 9cf336d95ee6b..32dd9c55d3d8a 100644 --- a/src/units.h +++ b/src/units.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -582,6 +583,14 @@ inline std::ostream &operator<<( std::ostream &o, const quantity +inline std::string quantity_to_string( const quantity &v ) +{ + std::ostringstream os; + os << v; + return os.str(); +} + inline std::string display( const units::energy v ) { const int kj = units::to_kilojoule( v ); diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 051bb37277794..9980fc2b07f0c 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -118,27 +118,28 @@ player_activity veh_interact::serialize_activity() return player_activity(); } + avatar &player_character = get_avatar(); int time = 1000; switch( sel_cmd ) { case 'i': - time = vp->install_time( g->u ); + time = vp->install_time( player_character ); break; case 'r': if( pt != nullptr ) { if( pt->is_broken() ) { - time = vp->install_time( g->u ); + time = vp->install_time( player_character ); } else if( pt->base.max_damage() > 0 ) { - time = vp->repair_time( g->u ) * pt->base.damage() / pt->base.max_damage(); + time = vp->repair_time( player_character ) * pt->base.damage() / pt->base.max_damage(); } } break; case 'o': - time = vp->removal_time( g->u ); + time = vp->removal_time( player_character ); break; default: break; } - if( g->u.has_trait( trait_DEBUG_HS ) ) { + if( player_character.has_trait( trait_DEBUG_HS ) ) { time = 1; } player_activity res( ACT_VEHICLE, time, static_cast( sel_cmd ) ); @@ -147,11 +148,12 @@ player_activity veh_interact::serialize_activity() // otherwise (e.g. installing a new frame), just use part 0 const point q = veh->coord_translate( pt ? pt->mount : veh->part( 0 ).mount ); const vehicle_part *vpt = pt ? pt : &veh->part( 0 ); + map &here = get_map(); for( const tripoint &p : veh->get_points( true ) ) { - res.coord_set.insert( g->m.getabs( p ) ); + res.coord_set.insert( here.getabs( p ) ); } - res.values.push_back( g->m.getabs( veh->global_pos3() ).x + q.x ); // values[0] - res.values.push_back( g->m.getabs( veh->global_pos3() ).y + q.y ); // values[1] + res.values.push_back( here.getabs( veh->global_pos3() ).x + q.x ); // values[0] + res.values.push_back( here.getabs( veh->global_pos3() ).y + q.y ); // values[1] res.values.push_back( dd.x ); // values[2] res.values.push_back( dd.y ); // values[3] res.values.push_back( -dd.x ); // values[4] @@ -295,7 +297,8 @@ void veh_interact::allocate_windows() bool veh_interact::format_reqs( std::string &msg, const requirement_data &reqs, const std::map &skills, int moves ) const { - const inventory &inv = g->u.crafting_inventory(); + Character &player_character = get_player_character(); + const inventory &inv = player_character.crafting_inventory(); bool ok = reqs.can_make_with_inventory( inv, is_crafting_component ); msg += _( "Time required:\n" ); @@ -304,7 +307,7 @@ bool veh_interact::format_reqs( std::string &msg, const requirement_data &reqs, msg += _( "Skills required:\n" ); for( const auto &e : skills ) { - bool hasSkill = g->u.get_skill_level( e.first ) >= e.second; + bool hasSkill = player_character.get_skill_level( e.first ) >= e.second; if( !hasSkill ) { ok = false; } @@ -383,7 +386,9 @@ shared_ptr_fast veh_interact::create_or_get_ui_adaptor() void veh_interact::do_main_loop() { bool finish = false; - const bool owned_by_player = veh->handle_potential_theft( dynamic_cast( g->u ), true ); + Character &player_character = get_player_character(); + const bool owned_by_player = veh->handle_potential_theft( dynamic_cast + ( player_character ), true ); faction *owner_fac; if( veh->has_owner() ) { owner_fac = g->faction_manager_ptr->get( veh->get_owner() ); @@ -403,23 +408,23 @@ void veh_interact::do_main_loop() } else if( action == "QUIT" ) { finish = true; } else if( action == "INSTALL" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { do_install(); } } else if( action == "REPAIR" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { do_repair(); } } else if( action == "MEND" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { do_mend(); } } else if( action == "REFILL" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { do_refill(); } } else if( action == "REMOVE" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { do_remove(); } } else if( action == "RENAME" ) { @@ -431,18 +436,18 @@ void veh_interact::do_main_loop() } } } else if( action == "SIPHON" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { do_siphon(); // Siphoning may have started a player activity. If so, we should close the // vehicle dialog and continue with the activity. - finish = !g->u.activity.is_null(); + finish = !player_character.activity.is_null(); if( !finish ) { // it's possible we just invalidated our crafting inventory cache_tool_availability(); } } } else if( action == "UNLOAD" ) { - if( veh->handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( veh->handle_potential_theft( dynamic_cast( player_character ) ) ) { finish = do_unload(); } } else if( action == "ASSIGN_CREW" ) { @@ -483,23 +488,24 @@ void veh_interact::do_main_loop() void veh_interact::cache_tool_availability() { - crafting_inv = g->u.crafting_inventory(); + Character &player_character = get_player_character(); + crafting_inv = player_character.crafting_inventory(); - cache_tool_availability_update_lifting( g->u.pos() ); + cache_tool_availability_update_lifting( player_character.pos() ); int mech_jack = 0; - if( g->u.is_mounted() ) { - mech_jack = g->u.mounted_creature->mech_str_addition() + 10; + if( player_character.is_mounted() ) { + mech_jack = player_character.mounted_creature->mech_str_addition() + 10; } - int max_quality = std::max( { g->u.max_quality( qual_JACK ), mech_jack, - map_selector( g->u.pos(), PICKUP_RANGE ).max_quality( qual_JACK ), - vehicle_selector( g->u.pos(), 2, true, *veh ).max_quality( qual_JACK ) + int max_quality = std::max( { player_character.max_quality( qual_JACK ), mech_jack, + map_selector( player_character.pos(), PICKUP_RANGE ).max_quality( qual_JACK ), + vehicle_selector( player_character.pos(), 2, true, *veh ).max_quality( qual_JACK ) } ); max_jack = lifting_quality_to_mass( max_quality ); } void veh_interact::cache_tool_availability_update_lifting( const tripoint &world_cursor_pos ) { - max_lift = g->u.best_nearby_lifting_assist( world_cursor_pos ); + max_lift = get_player_character().best_nearby_lifting_assist( world_cursor_pos ); } /** @@ -525,29 +531,30 @@ task_reason veh_interact::cant_do( char mode ) bool has_skill = true; bool enough_light = true; const vehicle_part_range vpr = veh->get_all_parts(); + avatar &player_character = get_avatar(); switch( mode ) { case 'i': // install mode - enough_morale = g->u.has_morale_to_craft(); + enough_morale = player_character.has_morale_to_craft(); valid_target = !can_mount.empty() && 0 == veh->tags.count( "convertible" ); //tool checks processed later - enough_light = g->u.fine_detail_vision_mod() <= 4; + enough_light = player_character.fine_detail_vision_mod() <= 4; has_tools = true; break; case 'r': // repair mode - enough_morale = g->u.has_morale_to_craft(); + enough_morale = player_character.has_morale_to_craft(); valid_target = !need_repair.empty() && cpart >= 0; // checked later has_tools = true; - enough_light = g->u.fine_detail_vision_mod() <= 4; + enough_light = player_character.fine_detail_vision_mod() <= 4; break; case 'm': { // mend mode - enough_morale = g->u.has_morale_to_craft(); - const bool toggling = g->u.has_trait( trait_DEBUG_HS ); + enough_morale = player_character.has_morale_to_craft(); + const bool toggling = player_character.has_trait( trait_DEBUG_HS ); valid_target = std::any_of( vpr.begin(), vpr.end(), [toggling]( const vpart_reference & pt ) { if( toggling ) { return pt.part().is_available() && !pt.part().faults_potential().empty(); @@ -555,7 +562,7 @@ task_reason veh_interact::cant_do( char mode ) return pt.part().is_available() && !pt.part().faults().empty(); } } ); - enough_light = g->u.fine_detail_vision_mod() <= 4; + enough_light = player_character.fine_detail_vision_mod() <= 4; // checked later has_tools = true; } @@ -570,13 +577,13 @@ task_reason veh_interact::cant_do( char mode ) case 'o': // remove mode - enough_morale = g->u.has_morale_to_craft(); + enough_morale = player_character.has_morale_to_craft(); valid_target = cpart >= 0 && 0 == veh->tags.count( "convertible" ); part_free = parts_here.size() > 1 || ( cpart >= 0 && veh->can_unmount( cpart ) ); //tool and skill checks processed later has_tools = true; has_skill = true; - enough_light = g->u.fine_detail_vision_mod() <= 4; + enough_light = player_character.fine_detail_vision_mod() <= 4; break; case 's': @@ -590,7 +597,7 @@ task_reason veh_interact::cant_do( char mode ) break; } } - has_tools = g->u.has_quality( qual_HOSE ); + has_tools = player_character.has_quality( qual_HOSE ); break; case 'd': @@ -623,7 +630,7 @@ task_reason veh_interact::cant_do( char mode ) return task_reason::UNKNOWN_TASK; } - if( std::abs( veh->velocity ) > 100 || g->u.controlling_vehicle ) { + if( std::abs( veh->velocity ) > 100 || player_character.controlling_vehicle ) { return task_reason::MOVING_VEHICLE; } if( !valid_target ) { @@ -740,29 +747,30 @@ bool veh_interact::can_install_part() const auto reqs = sel_vpart_info->install_requirements(); + avatar &player_character = get_avatar(); std::string nmsg; bool ok = format_reqs( nmsg, reqs, sel_vpart_info->install_skills, - sel_vpart_info->install_time( g->u ) ); + sel_vpart_info->install_time( player_character ) ); nmsg += _( "Additional requirements:\n" ); if( dif_eng > 0 ) { - if( g->u.get_skill_level( skill_mechanics ) < dif_eng ) { + if( player_character.get_skill_level( skill_mechanics ) < dif_eng ) { ok = false; } //~ %1$s represents the internal color name which shouldn't be translated, %2$s is skill name, and %3$i is skill level nmsg += string_format( _( "> %1$s%2$s %3$i for extra engines." ), - status_color( g->u.get_skill_level( skill_mechanics ) >= dif_eng ), + status_color( player_character.get_skill_level( skill_mechanics ) >= dif_eng ), skill_mechanics.obj().name(), dif_eng ) + "\n"; } if( dif_steering > 0 ) { - if( g->u.get_skill_level( skill_mechanics ) < dif_steering ) { + if( player_character.get_skill_level( skill_mechanics ) < dif_steering ) { ok = false; } //~ %1$s represents the internal color name which shouldn't be translated, %2$s is skill name, and %3$i is skill level nmsg += string_format( _( "> %1$s%2$s %3$i for extra steering axles." ), - status_color( g->u.get_skill_level( skill_mechanics ) >= dif_steering ), + status_color( player_character.get_skill_level( skill_mechanics ) >= dif_steering ), skill_mechanics.obj().name(), dif_steering ) + "\n"; } @@ -776,7 +784,7 @@ bool veh_interact::can_install_part() lvl = jack_quality( *veh ); str = veh->lift_strength(); use_aid = ( max_jack >= lifting_quality_to_mass( lvl ) ) || can_self_jack(); - use_str = g->u.can_lift( *veh ); + use_str = player_character.can_lift( *veh ); } else { item base( sel_vpart_info->item ); qual = qual_LIFT; @@ -784,7 +792,7 @@ bool veh_interact::can_install_part() lifting_quality_to_mass( 1 ) ); str = base.lift_strength(); use_aid = max_lift >= base.weight(); - use_str = g->u.can_lift( base ); + use_str = player_character.can_lift( base ); } if( !( use_aid || use_str ) ) { @@ -794,7 +802,7 @@ bool veh_interact::can_install_part() nc_color aid_color = use_aid ? c_green : ( use_str ? c_dark_gray : c_red ); nc_color str_color = use_str ? c_green : ( use_aid ? c_dark_gray : c_red ); - const auto helpers = g->u.get_crafting_helpers(); + const auto helpers = player_character.get_crafting_helpers(); std::string str_string; if( !helpers.empty() ) { str_string = string_format( _( "strength ( assisted ) %d" ), str ); @@ -811,7 +819,7 @@ bool veh_interact::can_install_part() sel_vpart_info->format_description( nmsg, c_light_gray, getmaxx( w_msg ) - 4 ); msg = colorize( nmsg, c_light_gray ); - return ok || g->u.has_trait( trait_DEBUG_HS ); + return ok || player_character.has_trait( trait_DEBUG_HS ); } /** @@ -1173,6 +1181,7 @@ void veh_interact::do_repair() restore_on_out_of_scope prev_hilight_part( highlight_part ); + avatar &player_character = get_avatar(); while( true ) { vehicle_part &pt = veh->part( parts_here[need_repair[pos]] ); const vpart_info &vp = pt.info(); @@ -1182,7 +1191,8 @@ void veh_interact::do_repair() // this will always be set, but the gcc thinks that sometimes it won't be bool ok = true; if( pt.is_broken() ) { - ok = format_reqs( nmsg, vp.install_requirements(), vp.install_skills, vp.install_time( g->u ) ); + ok = format_reqs( nmsg, vp.install_requirements(), vp.install_skills, + vp.install_time( player_character ) ); } else { if( vp.has_flag( "NO_REPAIR" ) || vp.repair_requirements().is_empty() || pt.base.max_damage() <= 0 ) { @@ -1204,7 +1214,7 @@ void veh_interact::do_repair() } } else { ok = format_reqs( nmsg, vp.repair_requirements() * pt.base.damage_level( 4 ), vp.repair_skills, - vp.repair_time( g->u ) * pt.base.damage() / pt.base.max_damage() ); + vp.repair_time( player_character ) * pt.base.damage() / pt.base.max_damage() ); } } @@ -1226,7 +1236,7 @@ void veh_interact::do_repair() } sel_vehicle_part = &pt; sel_vpart_info = &vp; - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = player_character.get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); } @@ -1264,7 +1274,8 @@ void veh_interact::do_mend() restore_on_out_of_scope> prev_title( title ); title = _( "Choose a part here to mend:" ); - const bool toggling = g->u.has_trait( trait_DEBUG_HS ); + avatar &player_character = get_avatar(); + const bool toggling = player_character.has_trait( trait_DEBUG_HS ); auto sel = [toggling]( const vehicle_part & pt ) { if( toggling ) { return !pt.faults_potential().empty(); @@ -1274,7 +1285,7 @@ void veh_interact::do_mend() }; auto act = [&]( const vehicle_part & pt ) { - g->u.mend_item( veh->part_base( veh->index_of_part( &pt ) ) ); + player_character.mend_item( veh->part_base( veh->index_of_part( &pt ) ) ); sel_cmd = 'q'; }; @@ -1726,7 +1737,7 @@ vehicle_part *veh_interact::get_most_damaged_part() const vehicle_part *veh_interact::get_most_repariable_part() const { - auto &part = veh_utils::most_repairable_part( *veh, g->u ); + auto &part = veh_utils::most_repairable_part( *veh, get_player_character() ); return part ? &part : nullptr; } @@ -1775,12 +1786,13 @@ bool veh_interact::can_remove_part( int idx, const player &p ) quality_id qual; bool use_aid = false; bool use_str = false; + avatar &player_character = get_avatar(); if( sel_vpart_info->has_flag( "NEEDS_JACKING" ) ) { qual = qual_JACK; lvl = jack_quality( *veh ); str = veh->lift_strength(); use_aid = ( max_jack >= lifting_quality_to_mass( lvl ) ) || can_self_jack(); - use_str = g->u.can_lift( *veh ); + use_str = player_character.can_lift( *veh ); } else { item base( sel_vpart_info->item ); qual = qual_LIFT; @@ -1788,7 +1800,7 @@ bool veh_interact::can_remove_part( int idx, const player &p ) lifting_quality_to_mass( 1 ) ); str = base.lift_strength(); use_aid = max_lift >= base.weight(); - use_str = g->u.can_lift( base ); + use_str = player_character.can_lift( base ); } if( !( use_aid || use_str ) ) { @@ -1796,7 +1808,7 @@ bool veh_interact::can_remove_part( int idx, const player &p ) } nc_color aid_color = use_aid ? c_green : ( use_str ? c_dark_gray : c_red ); nc_color str_color = use_str ? c_green : ( use_aid ? c_dark_gray : c_red ); - const auto helpers = g->u.get_crafting_helpers(); + const auto helpers = player_character.get_crafting_helpers(); //~ %1$s is quality name, %2$d is quality level std::string aid_string = string_format( _( "1 tool with %1$s %2$d" ), qual.obj().name, lvl ); @@ -1821,7 +1833,7 @@ bool veh_interact::can_remove_part( int idx, const player &p ) sel_vehicle_part->info().format_description( nmsg, desc_color, getmaxx( w_msg ) - 4 ); msg = colorize( nmsg, c_light_gray ); - return ok || g->u.has_trait( trait_DEBUG_HS ); + return ok || player_character.has_trait( trait_DEBUG_HS ); } void veh_interact::do_remove() @@ -1836,9 +1848,10 @@ void veh_interact::do_remove() restore_on_out_of_scope> prev_title( title ); title = _( "Choose a part here to remove:" ); + avatar &player_character = get_avatar(); int pos = 0; for( size_t i = 0; i < parts_here.size(); i++ ) { - if( can_remove_part( parts_here[ i ], g->u ) ) { + if( can_remove_part( parts_here[ i ], player_character ) ) { pos = i; break; } @@ -1854,7 +1867,7 @@ void veh_interact::do_remove() while( true ) { int part = parts_here[ pos ]; - bool can_remove = can_remove_part( part, g->u ); + bool can_remove = can_remove_part( part, player_character ); overview_enable = [this, part]( const vehicle_part & pt ) { return &pt == &veh->part( part ); @@ -1896,7 +1909,7 @@ void veh_interact::do_remove() return; } } - const std::vector helpers = g->u.get_crafting_helpers(); + const std::vector helpers = player_character.get_crafting_helpers(); for( const npc *np : helpers ) { add_msg( m_info, _( "%s helps with this task…" ), np->name ); } @@ -2058,7 +2071,7 @@ int veh_interact::part_at( const point &d ) */ bool veh_interact::can_potentially_install( const vpart_info &vpart ) { - return g->u.has_trait( trait_DEBUG_HS ) || + return get_player_character().has_trait( trait_DEBUG_HS ) || vpart.install_requirements().can_make_with_inventory( crafting_inv, is_crafting_component ); } @@ -2082,8 +2095,9 @@ void veh_interact::move_cursor( const point &d, int dstart_at ) const point q = veh->coord_translate( vd ); const tripoint vehp = veh->global_pos3() + q; const bool has_critter = g->critter_at( vehp ); - bool obstruct = g->m.impassable_ter_furn( vehp ); - const optional_vpart_position ovp = g->m.veh_at( vehp ); + map &here = get_map(); + bool obstruct = here.impassable_ter_furn( vehp ); + const optional_vpart_position ovp = here.veh_at( vehp ); if( ovp && &ovp->vehicle() != veh ) { obstruct = true; } @@ -2253,8 +2267,9 @@ void veh_interact::display_veh() const point vd = -dd; const point q = veh->coord_translate( vd ); const tripoint vehp = veh->global_pos3() + q; - bool obstruct = g->m.impassable_ter_furn( vehp ); - const optional_vpart_position ovp = g->m.veh_at( vehp ); + map &here = get_map(); + bool obstruct = here.impassable_ter_furn( vehp ); + const optional_vpart_position ovp = here.veh_at( vehp ); if( ovp && &ovp->vehicle() != veh ) { obstruct = true; } @@ -2530,7 +2545,7 @@ void veh_interact::display_name() mvwprintz( w_name, point( 1, 0 ), c_light_gray, _( "Name: " ) ); mvwprintz( w_name, point( 1 + utf8_width( _( "Name: " ) ), 0 ), - !veh->is_owned_by( g->u, true ) ? c_light_red : c_light_green, + !veh->is_owned_by( get_player_character(), true ) ? c_light_red : c_light_green, string_format( _( "%s (%s)" ), veh->name, veh->get_owner_name() ) ); wnoutrefresh( w_name ); } @@ -2899,6 +2914,7 @@ void act_vehicle_unload_fuel( vehicle *veh ) fuel = fuels.front(); } + Character &player_character = get_player_character(); int qty = veh->fuel_left( fuel ); if( fuel == itype_plut_cell ) { if( qty / PLUTONIUM_CHARGES == 0 ) { @@ -2906,11 +2922,11 @@ void act_vehicle_unload_fuel( vehicle *veh ) return; } item plutonium( fuel, calendar::turn, qty / PLUTONIUM_CHARGES ); - g->u.i_add( plutonium ); + player_character.i_add( plutonium ); veh->drain( fuel, qty - ( qty % PLUTONIUM_CHARGES ) ); } else { item solid_fuel( fuel, calendar::turn, qty ); - g->u.i_add( solid_fuel ); + player_character.i_add( solid_fuel ); veh->drain( fuel, qty ); } @@ -2926,14 +2942,15 @@ void veh_interact::complete_vehicle( player &p ) debugmsg( "Invalid activity ACT_VEHICLE values:%d", p.activity.values.size() ); return; } - optional_vpart_position vp = g->m.veh_at( g->m.getlocal( tripoint( p.activity.values[0], + map &here = get_map(); + optional_vpart_position vp = here.veh_at( here.getlocal( tripoint( p.activity.values[0], p.activity.values[1], p.posz() ) ) ); if( !vp ) { // so the vehicle could have lost some of its parts from other NPCS works during this player/NPCs activity. // check the vehicle points that were stored at beginning of activity. if( !p.activity.coord_set.empty() ) { for( const auto pt : p.activity.coord_set ) { - vp = g->m.veh_at( g->m.getlocal( pt ) ); + vp = here.veh_at( here.getlocal( pt ) ); if( vp ) { break; } @@ -3039,7 +3056,7 @@ void veh_interact::complete_vehicle( player &p ) // TODO: allow boarding for non-players as well. player *const pl = g->critter_at( vehp ); if( vpinfo.has_flag( VPFLAG_BOARDABLE ) && pl ) { - g->m.board_vehicle( vehp, pl ); + here.board_vehicle( vehp, pl ); } p.add_msg_if_player( m_good, _( "You install a %1$s into the %2$s." ), veh->part( partnum ).name(), @@ -3048,7 +3065,7 @@ void veh_interact::complete_vehicle( player &p ) for( const auto &sk : vpinfo.install_skills ) { p.practice( sk.first, veh_utils::calc_xp_gain( vpinfo, sk.first, p ) ); } - g->m.update_vehicle_cache( veh, veh->sm_pos.z ); + here.add_vehicle_to_cache( veh ); break; } @@ -3115,7 +3132,6 @@ void veh_interact::complete_vehicle( player &p ) add_msg( m_info, _( "You don't meet the requirements to remove the %s." ), vpinfo.name() ); break; } - for( const auto &e : reqs.get_components() ) { p.consume_items( e, 1, is_crafting_component ); } @@ -3181,11 +3197,17 @@ void veh_interact::complete_vehicle( player &p ) if( veh->part_count() < 2 ) { p.add_msg_if_player( _( "You completely dismantle the %s." ), veh->name ); p.activity.set_to_null(); - g->m.destroy_vehicle( veh ); + // destroy vehicle clears the cache + here.destroy_vehicle( veh ); } else { + point mount = veh->part( vehicle_part ).mount; + const tripoint &part_pos = veh->global_part_pos3( vehicle_part ); veh->remove_part( vehicle_part ); + // part_removal_cleanup calls refresh, so parts_at_relative is valid veh->part_removal_cleanup(); - g->m.update_vehicle_cache( veh, veh->sm_pos.z ); + if( veh->parts_at_relative( mount, true ).empty() ) { + get_map().clear_vehicle_point_from_cache( veh, part_pos ); + } } // This will be part of an NPC "job" where they need to clean up the acitivty items afterwards if( p.is_npc() ) { @@ -3193,7 +3215,7 @@ void veh_interact::complete_vehicle( player &p ) it.set_var( "activity_var", p.name ); } } - // Finally, put all the reults somewhere (we wanted to wait until this + // Finally, put all the results somewhere (we wanted to wait until this // point because we don't want to put them back into the vehicle part // that just got removed). put_into_vehicle_or_drop( p, item_drop_reason::deliberate, resulting_items ); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index f4954245dc703..b129659941fc0 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -78,6 +78,7 @@ static const itype_id fuel_type_battery( "battery" ); static const itype_id fuel_type_muscle( "muscle" ); static const itype_id fuel_type_plutonium_cell( "plut_cell" ); static const itype_id fuel_type_wind( "wind" ); +static const itype_id fuel_type_mana( "mana" ); static const fault_id fault_engine_belt_drive( "fault_engine_belt_drive" ); static const fault_id fault_engine_filter_air( "fault_engine_filter_air" ); @@ -98,12 +99,11 @@ static const itype_id itype_water_clean( "water_clean" ); static const itype_id itype_water_purifier( "water_purifier" ); static const std::string flag_PERPETUAL( "PERPETUAL" ); +static const std::string flag_E_COMBUSTION( "E_COMBUSTION" ); static bool is_sm_tile_outside( const tripoint &real_global_pos ); static bool is_sm_tile_over_water( const tripoint &real_global_pos ); -static const itype_id fuel_type_mana( "mana" ); - // 1 kJ per battery charge const int bat_energy_j = 1000; @@ -128,37 +128,39 @@ class DefaultRemovePartHandler : public RemovePartHandler ~DefaultRemovePartHandler() override = default; void unboard( const tripoint &loc ) override { - g->m.unboard_vehicle( loc ); + get_map().unboard_vehicle( loc ); } void add_item_or_charges( const tripoint &loc, item it, bool /*permit_oob*/ ) override { - g->m.add_item_or_charges( loc, std::move( it ) ); + get_map().add_item_or_charges( loc, std::move( it ) ); } void set_transparency_cache_dirty( const int z ) override { - g->m.set_transparency_cache_dirty( z ); + get_map().set_transparency_cache_dirty( z ); } void removed( vehicle &veh, const int part ) override { + avatar &player_character = get_avatar(); // If the player is currently working on the removed part, stop them as it's futile now. - const player_activity &act = g->u.activity; + const player_activity &act = player_character.activity; + map &here = get_map(); if( act.id() == ACT_VEHICLE && act.moves_left > 0 && act.values.size() > 6 ) { - if( veh_pointer_or_null( g->m.veh_at( tripoint( act.values[0], act.values[1], - g->u.posz() ) ) ) == &veh ) { + if( veh_pointer_or_null( here.veh_at( tripoint( act.values[0], act.values[1], + player_character.posz() ) ) ) == &veh ) { if( act.values[6] >= part ) { - g->u.cancel_activity(); + player_character.cancel_activity(); add_msg( m_info, _( "The vehicle part you were working on has gone!" ) ); } } } // TODO: maybe do this for all the nearby NPCs as well? - if( g->u.get_grab_type() == object_type::VEHICLE && - g->u.grab_point == veh.global_part_pos3( part ) ) { + if( player_character.get_grab_type() == object_type::VEHICLE && + player_character.grab_point == veh.global_part_pos3( part ) ) { if( veh.parts_at_relative( veh.part( part ).mount, false ).empty() ) { add_msg( m_info, _( "The vehicle part you were holding has been destroyed!" ) ); - g->u.grab( object_type::NONE ); + player_character.grab( object_type::NONE ); } } - g->m.dirty_vehicle_list.insert( &veh ); + here.dirty_vehicle_list.insert( &veh ); } void spawn_animal_from_part( item &base, const tripoint &loc ) override { base.release_monster( loc, 1 ); @@ -258,7 +260,7 @@ vehicle::vehicle() : vehicle( vproto_id() ) vehicle::~vehicle() = default; -bool vehicle::player_in_control( const player &p ) const +bool vehicle::player_in_control( const Character &p ) const { // Debug switch to prevent vehicles from skidding // without having to place the player in them. @@ -266,19 +268,20 @@ bool vehicle::player_in_control( const player &p ) const return true; } - const optional_vpart_position vp = g->m.veh_at( p.pos() ); + const optional_vpart_position vp = get_map().veh_at( p.pos() ); if( vp && &vp->vehicle() == this && + p.controlling_vehicle && ( ( part_with_feature( vp->part_index(), "CONTROL_ANIMAL", true ) >= 0 && has_engine_type( fuel_type_animal, false ) && has_harnessed_animal() ) || - ( part_with_feature( vp->part_index(), VPFLAG_CONTROLS, false ) >= 0 ) ) && - p.controlling_vehicle ) { + ( part_with_feature( vp->part_index(), VPFLAG_CONTROLS, false ) >= 0 ) ) + ) { return true; } return remote_controlled( p ); } -bool vehicle::remote_controlled( const player &p ) const +bool vehicle::remote_controlled( const Character &p ) const { vehicle *veh = g->remoteveh(); if( veh != this ) { @@ -702,13 +705,14 @@ void vehicle::autopilot_patrol() * in a criss-cross fashion. * in an auto-tractor, this would eventually cover the entire rectangle. */ + map &here = get_map(); // if we are close to a waypoint, then return to come back to this function next turn. if( autodrive_local_target != tripoint_zero ) { - if( rl_dist( g->m.getabs( global_pos3() ), autodrive_local_target ) <= 3 ) { + if( rl_dist( here.getabs( global_pos3() ), autodrive_local_target ) <= 3 ) { autodrive_local_target = tripoint_zero; return; } - if( !g->m.inbounds( g->m.getlocal( autodrive_local_target ) ) ) { + if( !here.inbounds( here.getlocal( autodrive_local_target ) ) ) { autodrive_local_target = tripoint_zero; is_patrolling = false; return; @@ -718,7 +722,7 @@ void vehicle::autopilot_patrol() } zone_manager &mgr = zone_manager::get_manager(); const auto &zone_src_set = mgr.get_near( zone_type_id( "VEHICLE_PATROL" ), - g->m.getabs( global_pos3() ), 60 ); + here.getabs( global_pos3() ), 60 ); if( zone_src_set.empty() ) { is_patrolling = false; return; @@ -748,8 +752,8 @@ void vehicle::autopilot_patrol() point_along, min.z ); tripoint chosen_tri = min_tri; - if( rl_dist( max_tri, g->m.getabs( global_pos3() ) ) >= rl_dist( min_tri, - g->m.getabs( global_pos3() ) ) ) { + if( rl_dist( max_tri, here.getabs( global_pos3() ) ) >= rl_dist( min_tri, + here.getabs( global_pos3() ) ) ) { chosen_tri = max_tri; } autodrive_local_target = chosen_tri; @@ -768,10 +772,11 @@ std::set vehicle::immediate_path( int rotate ) adjusted_angle = ( ( adjusted_angle + 15 / 2 ) / 15 ) * 15; tileray collision_vector; collision_vector.init( adjusted_angle ); + map &here = get_map(); point top_left_actual = global_pos3().xy() + coord_translate( front_left ); point top_right_actual = global_pos3().xy() + coord_translate( front_right ); - std::vector front_row = line_to( g->m.getabs( top_left_actual ), - g->m.getabs( top_right_actual ) ); + std::vector front_row = line_to( here.getabs( top_left_actual ), + here.getabs( top_right_actual ) ); for( const point &elem : front_row ) { for( int i = 0; i < distance_to_check; ++i ) { collision_vector.advance( i ); @@ -828,30 +833,32 @@ void vehicle::stop_autodriving() void vehicle::drive_to_local_target( const tripoint &target, bool follow_protocol ) { - if( follow_protocol && g->u.in_vehicle ) { + Character &player_character = get_player_character(); + if( follow_protocol && player_character.in_vehicle ) { stop_autodriving(); return; } refresh(); - tripoint vehpos = g->m.getabs( global_pos3() ); + map &here = get_map(); + tripoint vehpos = here.getabs( global_pos3() ); double angle = get_angle_from_targ( target ); // now we got the angle to the target, we can work out when we are heading towards disaster. // Check the tileray in the direction we need to head towards. std::set points_to_check = immediate_path( angle ); bool stop = false; for( const point &pt_elem : points_to_check ) { - point elem = g->m.getlocal( pt_elem ); + point elem = here.getlocal( pt_elem ); if( stop ) { break; } - const optional_vpart_position ovp = g->m.veh_at( tripoint( elem, sm_pos.z ) ); - if( g->m.impassable_ter_furn( tripoint( elem, sm_pos.z ) ) || ( ovp && + const optional_vpart_position ovp = here.veh_at( tripoint( elem, sm_pos.z ) ); + if( here.impassable_ter_furn( tripoint( elem, sm_pos.z ) ) || ( ovp && &ovp->vehicle() != this ) ) { stop = true; break; } - if( elem == g->u.pos().xy() ) { - if( follow_protocol || g->u.in_vehicle ) { + if( elem == player_character.pos().xy() ) { + if( follow_protocol || player_character.in_vehicle ) { continue; } else { stop = true; @@ -899,14 +906,15 @@ void vehicle::drive_to_local_target( const tripoint &target, bool follow_protoco // we really want to avoid running the player over. // If its a helicopter, we dont need to worry about airborne obstacles so much // And fuel efficiency is terrible at low speeds. - const int safe_player_follow_speed = 400 * g->u.current_movement_mode()->move_speed_mult(); + const int safe_player_follow_speed = 400 * + player_character.current_movement_mode()->move_speed_mult(); if( follow_protocol ) { if( ( ( turn_x > 0 || turn_x < 0 ) && velocity > safe_player_follow_speed ) || - rl_dist( vehpos, g->m.getabs( g->u.pos() ) ) < 7 + ( ( mount_max.y * 3 ) + 4 ) ) { + rl_dist( vehpos, here.getabs( player_character.pos() ) ) < 7 + ( ( mount_max.y * 3 ) + 4 ) ) { accel_y = 1; } if( ( velocity < std::min( safe_velocity(), safe_player_follow_speed ) && turn_x == 0 && - rl_dist( vehpos, g->m.getabs( g->u.pos() ) ) > 8 + ( ( mount_max.y * 3 ) + 4 ) ) || + rl_dist( vehpos, here.getabs( player_character.pos() ) ) > 8 + ( ( mount_max.y * 3 ) + 4 ) ) || velocity < 100 ) { accel_y = -1; } @@ -928,7 +936,7 @@ void vehicle::drive_to_local_target( const tripoint &target, bool follow_protoco double vehicle::get_angle_from_targ( const tripoint &targ ) { - tripoint vehpos = g->m.getabs( global_pos3() ); + tripoint vehpos = get_map().getabs( global_pos3() ); rl_vec2d facevec = face_vec(); point rel_pos_target = targ.xy() - vehpos.xy(); rl_vec2d targetvec = rl_vec2d( rel_pos_target.x, rel_pos_target.y ); @@ -945,12 +953,14 @@ void vehicle::do_autodrive() if( omt_path.empty() ) { stop_autodriving(); } + Character &player_character = get_player_character(); + map &here = get_map(); tripoint vehpos = global_pos3(); - tripoint veh_omt_pos = ms_to_omt_copy( g->m.getabs( vehpos ) ); + tripoint veh_omt_pos = ms_to_omt_copy( here.getabs( vehpos ) ); // we're at or close to the waypoint, pop it out and look for the next one. - if( ( is_autodriving && !g->u.omt_path.empty() && !omt_path.empty() ) && + if( ( is_autodriving && !player_character.omt_path.empty() && !omt_path.empty() ) && veh_omt_pos == omt_path.back() ) { - g->u.omt_path.pop_back(); + player_character.omt_path.pop_back(); omt_path.pop_back(); } if( omt_path.empty() ) { @@ -983,8 +993,8 @@ void vehicle::do_autodrive() tripoint global_a = tripoint( veh_omt_pos.x * ( 2 * SEEX ), veh_omt_pos.y * ( 2 * SEEY ), veh_omt_pos.z ); tripoint autodrive_temp_target = ( global_a + tripoint( side, - sm_pos.z ) - g->m.getabs( vehpos ) ) + vehpos; - autodrive_local_target = g->m.getabs( autodrive_temp_target ); + sm_pos.z ) - here.getabs( vehpos ) ) + vehpos; + autodrive_local_target = here.getabs( autodrive_temp_target ); drive_to_local_target( autodrive_local_target, false ); } @@ -1023,11 +1033,13 @@ void vehicle::smash( map &m, float hp_percent_loss_min, float hp_percent_loss_ma int roll = dice( 1, 1000 ); int pct_af = ( percent_of_parts_to_affect * 1000.0f ); if( roll < pct_af ) { - double dist = damage_size == 0.0 ? 1.0 : - clamp( 1.0 - trig_dist( damage_origin, part.precalc[0] ) / damage_size, 0.0, 1.0 ); + double dist = damage_size == 0.0f ? 1.0f : + clamp( 1.0f - trig_dist( damage_origin, part.precalc[0].xy() ) / + damage_size, 0.0f, 1.0f ); //Everywhere else, drop by 10-120% of max HP (anything over 100 = broken) if( mod_hp( part, 0 - ( rng_float( hp_percent_loss_min * dist, - hp_percent_loss_max * dist ) * part.info().durability ), DT_BASH ) ) { + hp_percent_loss_max * dist ) * + part.info().durability ), DT_BASH ) ) { part.ammo_unset(); } } @@ -1056,7 +1068,7 @@ void vehicle::smash( map &m, float hp_percent_loss_min, float hp_percent_loss_ma // This is a heuristic: we just assume the default handler is good enough when called // on the main game map. And assume that we run from some mapgen code if called on // another instance. - if( g && &g->m == &m ) { + if( g && &get_map() == &m ) { handler_ptr = std::make_unique(); } else { handler_ptr = std::make_unique( m ); @@ -1137,6 +1149,11 @@ bool vehicle::is_engine_type( const int e, const itype_id &ft ) const parts[engines[e]].ammo_current() == ft; } +bool vehicle::is_combustion_engine_type( const int e ) const +{ + return parts[engines[e]].info().has_flag( flag_E_COMBUSTION ); +} + bool vehicle::is_perpetual_type( const int e ) const { const itype_id &ft = part_info( engines[e] ).fuel_type; @@ -1163,8 +1180,9 @@ bool vehicle::is_alternator_on( const int a ) const return std::any_of( engines.begin(), engines.end(), [this, &alt]( int idx ) { auto &eng = parts [ idx ]; //fuel_left checks that the engine can produce power to be absorbed - return eng.is_available() && eng.enabled && fuel_left( eng.fuel_current() ) && - eng.mount == alt.mount && !eng.faults().count( fault_engine_belt_drive ); + return eng.mount == alt.mount && eng.is_available() && eng.enabled && + fuel_left( eng.fuel_current() ) && + !eng.faults().count( fault_engine_belt_drive ); } ); } @@ -1224,12 +1242,13 @@ int vehicle::part_vpower_w( const int index, const bool at_full_hp ) const } } ///\EFFECT_STR increases power produced for MUSCLE_* vehicles - pwr += ( g->u.str_cur - 8 ) * part_info( index ).engine_muscle_power_factor(); + pwr += ( get_player_character().str_cur - 8 ) * part_info( index ).engine_muscle_power_factor(); /// wind-powered vehicles have differing power depending on wind direction if( vp.info().fuel_type == fuel_type_wind ) { - int windpower = g->weather.windspeed; + weather_manager &weather = get_weather(); + int windpower = weather.windspeed; rl_vec2d windvec; - double raddir = ( ( g->weather.winddirection + 180 ) % 360 ) * ( M_PI / 180 ); + double raddir = ( ( weather.winddirection + 180 ) % 360 ) * ( M_PI / 180 ); windvec = windvec.normalized(); windvec.y = -std::cos( raddir ); windvec.x = std::sin( raddir ); @@ -1679,6 +1698,7 @@ int vehicle::install_part( const point &dp, const vehicle_part &new_part ) bool vehicle::try_to_rack_nearby_vehicle( const std::vector> &list_of_racks ) { + map &here = get_map(); for( const auto &this_bike_rack : list_of_racks ) { std::vector carry_vehs; carry_vehs.assign( 4, nullptr ); @@ -1691,7 +1711,7 @@ bool vehicle::try_to_rack_nearby_vehicle( const std::vector> &l int i = 0; for( const point &offset : four_cardinal_directions ) { tripoint search_pos( rack_pos + offset ); - test_veh = veh_pointer_or_null( g->m.veh_at( search_pos ) ); + test_veh = veh_pointer_or_null( here.veh_at( search_pos ) ); if( test_veh == nullptr || test_veh == this ) { continue; } else if( test_veh != carry_vehs[ i ] ) { @@ -1848,11 +1868,12 @@ bool vehicle::merge_rackable_vehicle( vehicle *carry_veh, const std::vector // update when we next interact with them zones_dirty = true; + map &here = get_map(); //~ %1$s is the vehicle being loaded onto the bicycle rack add_msg( _( "You load the %1$s on the rack" ), carry_veh->name ); - g->m.destroy_vehicle( carry_veh ); - g->m.dirty_vehicle_list.insert( this ); - g->m.set_transparency_cache_dirty( sm_pos.z ); + here.destroy_vehicle( carry_veh ); + here.dirty_vehicle_list.insert( this ); + here.set_transparency_cache_dirty( sm_pos.z ); refresh(); } else { //~ %1$s is the vehicle being loaded onto the bicycle rack @@ -1990,12 +2011,15 @@ bool vehicle::remove_part( const int p, RemovePartHandler &handler ) void vehicle::part_removal_cleanup() { bool changed = false; + map &here = get_map(); for( std::vector::iterator it = parts.begin(); it != parts.end(); /* noop */ ) { if( it->removed ) { auto items = get_items( std::distance( parts.begin(), it ) ); while( !items.empty() ) { items.erase( items.begin() ); } + const tripoint &pt = global_part_pos3( *it ); + here.clear_vehicle_point_from_cache( this, pt ); it = parts.erase( it ); changed = true; } else { @@ -2006,10 +2030,10 @@ void vehicle::part_removal_cleanup() if( changed || parts.empty() ) { refresh(); if( parts.empty() ) { - g->m.destroy_vehicle( this ); + here.destroy_vehicle( this ); return; } else { - g->m.update_vehicle_cache( this, sm_pos.z ); + here.add_vehicle_to_cache( this ); } } shift_if_needed(); @@ -2089,7 +2113,8 @@ bool vehicle::remove_carried_vehicle( const std::vector &carried_parts ) new_dir = 180; } } - vehicle *new_vehicle = g->m.add_vehicle( vproto_id( "none" ), new_pos3, new_dir ); + map &here = get_map(); + vehicle *new_vehicle = here.add_vehicle( vproto_id( "none" ), new_pos3, new_dir ); if( new_vehicle == nullptr ) { add_msg( m_debug, "Unable to unload bike rack, host face %d, new_dir %d!", face.dir(), new_dir ); return false; @@ -2149,7 +2174,7 @@ bool vehicle::remove_carried_vehicle( const std::vector &carried_parts ) new_vehicle->toggle_tracking(); //turn on tracking for our newly created vehicle new_vehicle->remove_tracked_flag(); //remove our tracking flags now that the vehicle isn't carried } - g->m.dirty_vehicle_list.insert( this ); + here.dirty_vehicle_list.insert( this ); part_removal_cleanup(); } else { //~ %s is the vehicle being loaded onto the bicycle rack @@ -2270,6 +2295,7 @@ bool vehicle::split_vehicles( const std::vector> &new_vehs, { bool did_split = false; size_t i = 0; + map &here = get_map(); for( i = 0; i < new_vehs.size(); i ++ ) { std::vector split_parts = new_vehs[ i ]; if( split_parts.empty() ) { @@ -2302,7 +2328,7 @@ bool vehicle::split_vehicles( const std::vector> &new_vehs, } new_v_pos3 = global_part_pos3( parts[ split_part0 ] ); mnt_offset = parts[ split_part0 ].mount; - new_vehicle = g->m.add_vehicle( vproto_id( "none" ), new_v_pos3, face.dir() ); + new_vehicle = here.add_vehicle( vproto_id( "none" ), new_v_pos3, face.dir() ); if( new_vehicle == nullptr ) { // the split part was out of the map bounds. continue; @@ -2396,8 +2422,8 @@ bool vehicle::split_vehicles( const std::vector> &new_vehs, // time we interact with them new_vehicle->zones_dirty = true; - g->m.dirty_vehicle_list.insert( new_vehicle ); - g->m.set_transparency_cache_dirty( sm_pos.z ); + here.dirty_vehicle_list.insert( new_vehicle ); + here.set_transparency_cache_dirty( sm_pos.z ); if( !new_labels.empty() ) { new_vehicle->labels = new_labels; } @@ -2610,7 +2636,7 @@ bool vehicle::has_part( const tripoint &pos, const std::string &flag, bool enabl const tripoint relative_pos = pos - global_pos3(); for( const auto &e : parts ) { - if( e.precalc[0].x != relative_pos.x || e.precalc[0].y != relative_pos.y ) { + if( e.precalc[0] != relative_pos ) { continue; } if( !e.removed && ( !enabled || e.enabled ) && !e.is_broken() && e.info().has_flag( flag ) ) { @@ -2626,7 +2652,7 @@ std::vector vehicle::get_parts_at( const tripoint &pos, const st const tripoint relative_pos = pos - global_pos3(); std::vector res; for( auto &e : parts ) { - if( e.precalc[ 0 ].x != relative_pos.x || e.precalc[ 0 ].y != relative_pos.y ) { + if( e.precalc[ 0 ] != relative_pos ) { continue; } if( !e.removed && @@ -2646,7 +2672,7 @@ std::vector vehicle::get_parts_at( const tripoint &pos, const tripoint relative_pos = pos - global_pos3(); std::vector res; for( const auto &e : parts ) { - if( e.precalc[ 0 ].x != relative_pos.x || e.precalc[ 0 ].y != relative_pos.y ) { + if( e.precalc[ 0 ] != relative_pos ) { continue; } if( !e.removed && @@ -2936,7 +2962,7 @@ bool vehicle::part_flag( int part, const vpart_bitflags flag ) const int vehicle::part_at( const point &dp ) const { for( const vpart_reference &vp : get_all_parts() ) { - if( vp.part().precalc[0] == dp && !vp.part().removed ) { + if( vp.part().precalc[0].xy() == dp && !vp.part().removed ) { return static_cast( vp.part_index() ); } } @@ -2988,13 +3014,14 @@ int vehicle::part_displayed_at( const point &dp ) const return -1; } - bool in_vehicle = g->u.in_vehicle; + Character &player_character = get_player_character(); + bool in_vehicle = player_character.in_vehicle; if( in_vehicle ) { // They're in a vehicle, but are they in /this/ vehicle? std::vector psg_parts = boarded_parts(); in_vehicle = false; for( auto &psg_part : psg_parts ) { - if( get_passenger( psg_part ) == &g->u ) { + if( get_passenger( psg_part ) == &player_character ) { in_vehicle = true; break; } @@ -3030,12 +3057,12 @@ int vehicle::roof_at_part( const int part ) const point vehicle::coord_translate( const point &p ) const { - point q; + tripoint q; coord_translate( pivot_rotation[0], pivot_anchor[0], p, q ); - return q; + return q.xy(); } -void vehicle::coord_translate( int dir, const point &pivot, const point &p, point &q ) const +void vehicle::coord_translate( int dir, const point &pivot, const point &p, tripoint &q ) const { tileray tdir( dir ); tdir.advance( p.x - pivot.x ); @@ -3043,7 +3070,7 @@ void vehicle::coord_translate( int dir, const point &pivot, const point &p, poin q.y = tdir.dy() + tdir.ortho_dy( p.y - pivot.y ); } -void vehicle::coord_translate( tileray tdir, const point &pivot, const point &p, point &q ) const +void vehicle::coord_translate( tileray tdir, const point &pivot, const point &p, tripoint &q ) const { tdir.clear_advance(); tdir.advance( p.x - pivot.x ); @@ -3053,9 +3080,9 @@ void vehicle::coord_translate( tileray tdir, const point &pivot, const point &p, point vehicle::rotate_mount( int old_dir, int new_dir, const point &pivot, const point &p ) const { - point q; + tripoint q; coord_translate( new_dir - old_dir, pivot, p, q ); - return q; + return q.xy(); } tripoint vehicle::mount_to_tripoint( const point &mount ) const @@ -3065,7 +3092,7 @@ tripoint vehicle::mount_to_tripoint( const point &mount ) const tripoint vehicle::mount_to_tripoint( const point &mount, const point &offset ) const { - point mnt_translated; + tripoint mnt_translated; coord_translate( pivot_rotation[0], pivot_anchor[ 0 ], mount + offset, mnt_translated ); return global_pos3() + mnt_translated; } @@ -3076,7 +3103,7 @@ void vehicle::precalc_mounts( int idir, int dir, const point &pivot ) idir = 0; } tileray tdir( dir ); - std::unordered_map mount_to_precalc; + std::unordered_map mount_to_precalc; for( auto &p : parts ) { if( p.removed ) { continue; @@ -3152,11 +3179,10 @@ tripoint vehicle::global_part_pos3( const vehicle_part &pt ) const return global_pos3() + pt.precalc[ 0 ]; } -void vehicle::set_submap_moved( const point &p ) +void vehicle::set_submap_moved( const tripoint &p ) { - const point old_msp = g->m.getabs( global_pos3().xy() ); - sm_pos.x = p.x; - sm_pos.y = p.y; + const point old_msp = get_map().getabs( global_pos3().xy() ); + sm_pos = p; if( !tracking_on ) { return; } @@ -3211,22 +3237,25 @@ point vehicle::pivot_displacement() const // the vehicle. // rotate the old pivot point around the new pivot point with the old rotation angle - point dp; + tripoint dp; coord_translate( pivot_rotation[0], pivot_anchor[1], pivot_anchor[0], dp ); - return dp; + return dp.xy(); } int vehicle::fuel_left( const itype_id &ftype, bool recurse ) const { - int fl = std::accumulate( parts.begin(), parts.end(), 0, [&ftype]( const int &lhs, - const vehicle_part & rhs ) { - // don't count frozen liquid - if( rhs.is_tank() && !rhs.base.contents.empty() && - rhs.base.contents.legacy_front().made_of( phase_id::SOLID ) ) { - return lhs; + int fl = 0; + + for( const int i : fuel_containers ) { + const vehicle_part &part = parts[i]; + if( part.ammo_current() != ftype || + // don't count frozen liquid + ( !part.base.contents.empty() && part.is_tank() && + part.base.contents.legacy_front().made_of( phase_id::SOLID ) ) ) { + continue; } - return lhs + ( rhs.ammo_current() == ftype ? rhs.ammo_remaining() : 0 ); - } ); + fl += part.ammo_remaining(); + } if( recurse && ftype == fuel_type_battery ) { auto fuel_counting_visitor = [&]( vehicle const * veh, int amount, int ) { @@ -3241,18 +3270,20 @@ int vehicle::fuel_left( const itype_id &ftype, bool recurse ) const //muscle engines have infinite fuel if( ftype == fuel_type_muscle ) { + Character &player_character = get_player_character(); // TODO: Allow NPCs to power those - const optional_vpart_position vp = g->m.veh_at( g->u.pos() ); - bool player_controlling = player_in_control( g->u ); + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + bool player_controlling = player_in_control( player_character ); //if the engine in the player tile is a muscle engine, and player is controlling vehicle if( vp && &vp->vehicle() == this && player_controlling ) { const int p = avail_part_with_feature( vp->part_index(), VPFLAG_ENGINE, true ); if( p >= 0 && is_part_on( p ) && part_info( p ).fuel_type == fuel_type_muscle ) { //Broken limbs prevent muscle engines from working - if( ( part_info( p ).has_flag( "MUSCLE_LEGS" ) && ( g->u.get_working_leg_count() >= 2 ) ) || + if( ( part_info( p ).has_flag( "MUSCLE_LEGS" ) && + ( player_character.get_working_leg_count() >= 2 ) ) || ( part_info( p ).has_flag( "MUSCLE_ARMS" ) && - ( g->u.get_working_arm_count() >= 2 ) ) ) { + ( player_character.get_working_arm_count() >= 2 ) ) ) { fl += 10; } } @@ -3449,10 +3480,11 @@ bool vehicle::can_use_rails() const if( !can_use ) { return false; } + map &here = get_map(); bool is_wheel_on_rail = false; for( int part_index : rail_wheelcache ) { // at least one wheel should be on track - if( g->m.has_flag_ter_or_furn( TFLAG_RAIL, global_part_pos3( part_index ) ) ) { + if( here.has_flag_ter_or_furn( TFLAG_RAIL, global_part_pos3( part_index ) ) ) { is_wheel_on_rail = true; break; } @@ -3692,14 +3724,16 @@ int vehicle::safe_velocity( const bool fueled ) const bool vehicle::do_environmental_effects() { bool needed = false; + map &here = get_map(); // check for smoking parts for( const vpart_reference &vp : get_all_parts() ) { /* Only lower blood level if: * - The part is outside. * - The weather is any effect that would cause the player to be wet. */ - if( vp.part().blood > 0 && g->m.is_outside( vp.pos() ) ) { + if( vp.part().blood > 0 && here.is_outside( vp.pos() ) ) { needed = true; - if( g->weather.weather >= WEATHER_LIGHT_DRIZZLE && g->weather.weather <= WEATHER_ACID_RAIN ) { + if( get_weather().weather_id->rains && + get_weather().weather_id->precip != precip_class::very_light ) { vp.part().blood--; } } @@ -3714,7 +3748,7 @@ void vehicle::spew_field( double joules, int part, field_type_id type, int inten } intensity = std::max( joules / 10000, static_cast( intensity ) ); const tripoint dest = exhaust_dest( part ); - g->m.mod_field_intensity( dest, type, intensity ); + get_map().mod_field_intensity( dest, type, intensity ); } /** @@ -4092,7 +4126,7 @@ bool vehicle::has_sufficient_rotorlift() const bool vehicle::is_rotorcraft() const { return ( has_part( "ROTOR" ) || has_part( "ROTOR_SIMPLE" ) ) && has_sufficient_rotorlift() && - player_in_control( g->u ); + player_in_control( get_player_character() ); } bool vehicle::is_flyable() const @@ -4416,7 +4450,7 @@ float vehicle::steering_effectiveness() const float vehicle::handling_difficulty() const { const float steer = std::max( 0.0f, steering_effectiveness() ); - const float ktraction = k_traction( g->m.vehicle_wheel_traction( *this ) ); + const float ktraction = k_traction( get_map().vehicle_wheel_traction( *this ) ); const float aligned = std::max( 0.0f, 1.0f - ( face_vec() - dir_vec() ).magnitude() ); // TestVehicle: perfect steering, moving on road at 100 mph (25 tiles per turn) = 0.0 @@ -4428,6 +4462,32 @@ float vehicle::handling_difficulty() const return velocity * diff_mod / vehicles::vmiph_per_tile; } + +int vehicle::engine_fuel_usage( int e ) const +{ + if( !is_engine_on( e ) ) { + return 0; + } + + static const itype_id null_fuel_type( "null" ); + const itype_id &cur_fuel = parts[engines[e]].fuel_current(); + if( cur_fuel == null_fuel_type ) { + return 0; + } + + if( is_perpetual_type( e ) ) { + return 0; + } + const auto &info = part_info( engines[ e ] ); + + int usage = info.energy_consumption; + if( parts[ engines[ e ] ].faults().count( fault_engine_filter_air ) ) { + usage *= 2; + } + + return usage; +} + std::map vehicle::fuel_usage() const { std::map ret; @@ -4439,7 +4499,6 @@ std::map vehicle::fuel_usage() const } const size_t e = engines[ i ]; - const auto &info = part_info( e ); static const itype_id null_fuel_type( "null" ); const itype_id &cur_fuel = parts[ e ].fuel_current(); if( cur_fuel == null_fuel_type ) { @@ -4447,12 +4506,7 @@ std::map vehicle::fuel_usage() const } if( !is_perpetual_type( i ) ) { - int usage = info.energy_consumption; - if( parts[ e ].faults().count( fault_engine_filter_air ) ) { - usage *= 2; - } - - ret[ cur_fuel ] += usage; + ret[cur_fuel] += engine_fuel_usage( i ); } } @@ -4498,7 +4552,9 @@ void vehicle::consume_fuel( int load, const int t_seconds, bool skip_electric ) fuel_remainder[ ft ] = -amnt_precise_j; } } - if( load > 0 && fuel_left( fuel_type_muscle ) > 0 && g->u.has_effect( effect_winded ) ) { + Character &player_character = get_player_character(); + if( load > 0 && fuel_left( fuel_type_muscle ) > 0 && + player_character.has_effect( effect_winded ) ) { cruise_velocity = 0; if( velocity == 0 ) { stop(); @@ -4506,7 +4562,7 @@ void vehicle::consume_fuel( int load, const int t_seconds, bool skip_electric ) } // we want this to update the activity level whenever the engine is running if( load > 0 && fuel_left( fuel_type_muscle ) > 0 ) { - g->u.increase_activity_level( ACTIVE_EXERCISE ); + player_character.increase_activity_level( ACTIVE_EXERCISE ); //do this as a function of current load // But only if the player is actually there! int eff_load = load / 10; @@ -4516,28 +4572,30 @@ void vehicle::consume_fuel( int load, const int t_seconds, bool skip_electric ) base_burn = std::max( eff_load / 3, base_burn ); //charge bionics when using muscle engine const item muscle( "muscle" ); - for( const bionic_id &bid : g->u.get_bionic_fueled_with( muscle ) ) { - if( g->u.has_active_bionic( bid ) ) { // active power gen + for( const bionic_id &bid : player_character.get_bionic_fueled_with( muscle ) ) { + if( player_character.has_active_bionic( bid ) ) { // active power gen // more pedaling = more power - g->u.mod_power_level( units::from_kilojoule( muscle.fuel_energy() ) * bid->fuel_efficiency * - ( load / 1000 ) ); + player_character.mod_power_level( units::from_kilojoule( muscle.fuel_energy() ) * + bid->fuel_efficiency * + ( load / 1000 ) ); mod += eff_load / 5; } else { // passive power gen - g->u.mod_power_level( units::from_kilojoule( muscle.fuel_energy() ) * bid->passive_fuel_efficiency * - ( load / 1000 ) ); + player_character.mod_power_level( units::from_kilojoule( muscle.fuel_energy() ) * + bid->passive_fuel_efficiency * + ( load / 1000 ) ); mod += eff_load / 10; } } // decreased stamina burn scalable with load - if( g->u.has_active_bionic( bio_jointservo ) ) { - g->u.mod_power_level( units::from_kilojoule( -std::max( eff_load / 20, 1 ) ) ); + if( player_character.has_active_bionic( bio_jointservo ) ) { + player_character.mod_power_level( units::from_kilojoule( -std::max( eff_load / 20, 1 ) ) ); mod -= std::max( eff_load / 5, 5 ); } if( one_in( 1000 / load ) && one_in( 10 ) ) { - g->u.mod_thirst( 1 ); - g->u.mod_fatigue( 1 ); + player_character.mod_thirst( 1 ); + player_character.mod_fatigue( 1 ); } - g->u.mod_stamina( -( base_burn + mod ) ); + player_character.mod_stamina( -( base_burn + mod ) ); add_msg( m_debug, "Load: %d", load ); add_msg( m_debug, "Mod: %d", mod ); add_msg( m_debug, "Burn: %d", -( base_burn + mod ) ); @@ -4564,6 +4622,43 @@ int vehicle::total_accessory_epower_w() const return epower; } +std::pair vehicle::battery_power_level() const +{ + int total_epower_capacity = 0; + int remaining_epower = 0; + + for( const int bi : batteries ) { + const vehicle_part &b = parts[bi]; + if( b.is_available() ) { + remaining_epower += b.ammo_remaining(); + total_epower_capacity += b.ammo_capacity( ammotype( "battery" ) ); + } + } + + return std::make_pair( remaining_epower, total_epower_capacity ); +} + +bool vehicle::start_engine( int e, bool turn_on ) +{ + if( parts[engines[e]].enabled == turn_on ) { + return false; + } + bool res = false; + if( turn_on ) { + toggle_specific_engine( e, true ); + // prevent starting of the faulty engines + if( ! start_engine( e ) ) { + toggle_specific_engine( e, false ); + } else { + res = true; + } + } else { + toggle_specific_engine( e, false ); + res = true; + } + return res; +} + int vehicle::total_alternator_epower_w() const { int epower = 0; @@ -4599,12 +4694,13 @@ int vehicle::total_engine_epower_w() const int vehicle::total_solar_epower_w() const { int epower_w = 0; + map &here = get_map(); for( int part : solar_panels ) { if( parts[ part ].is_unavailable() ) { continue; } - if( !is_sm_tile_outside( g->m.getabs( global_part_pos3( part ) ) ) ) { + if( !is_sm_tile_outside( here.getabs( global_part_pos3( part ) ) ) ) { continue; } @@ -4612,7 +4708,7 @@ int vehicle::total_solar_epower_w() const } // Weather doesn't change much across the area of the vehicle, so just // sample it once. - weather_type wtype = current_weather( global_pos3() ); + weather_type_id wtype = current_weather( global_pos3() ); const float tick_sunlight = incident_sunlight( wtype, calendar::turn ); double intensity = tick_sunlight / default_daylight_level(); return epower_w * intensity; @@ -4620,21 +4716,23 @@ int vehicle::total_solar_epower_w() const int vehicle::total_wind_epower_w() const { - const oter_id &cur_om_ter = overmap_buffer.ter( ms_to_omt_copy( g->m.getabs( global_pos3() ) ) ); - const w_point weatherPoint = *g->weather.weather_precise; + map &here = get_map(); + const oter_id &cur_om_ter = overmap_buffer.ter( ms_to_omt_copy( here.getabs( global_pos3() ) ) ); + weather_manager &weather = get_weather(); + const w_point weatherPoint = *weather.weather_precise; int epower_w = 0; for( int part : wind_turbines ) { if( parts[ part ].is_unavailable() ) { continue; } - if( !is_sm_tile_outside( g->m.getabs( global_part_pos3( part ) ) ) ) { + if( !is_sm_tile_outside( here.getabs( global_part_pos3( part ) ) ) ) { continue; } - double windpower = get_local_windpower( g->weather.windspeed, cur_om_ter, global_part_pos3( part ), - g->weather.winddirection, false ); - if( windpower <= ( g->weather.windspeed / 10.0 ) ) { + double windpower = get_local_windpower( weather.windspeed, cur_om_ter, global_part_pos3( part ), + weather.winddirection, false ); + if( windpower <= ( weather.windspeed / 10.0 ) ) { continue; } epower_w += part_epower_w( part ) * windpower; @@ -4645,12 +4743,13 @@ int vehicle::total_wind_epower_w() const int vehicle::total_water_wheel_epower_w() const { int epower_w = 0; + map &here = get_map(); for( int part : water_wheels ) { if( parts[ part ].is_unavailable() ) { continue; } - if( !is_sm_tile_over_water( g->m.getabs( global_part_pos3( part ) ) ) ) { + if( !is_sm_tile_over_water( here.getabs( global_part_pos3( part ) ) ) ) { continue; } @@ -4708,8 +4807,10 @@ void vehicle::power_parts() int epower = engine_epower + total_accessory_epower_w() + total_alternator_epower_w(); int delta_energy_bat = power_to_energy_bat( epower, 1_turns ); - int storage_deficit_bat = std::max( 0, fuel_capacity( fuel_type_battery ) - - fuel_left( fuel_type_battery ) - delta_energy_bat ); + int battery_left, battery_capacity; + std::tie( battery_left, battery_capacity ) = battery_power_level(); + int storage_deficit_bat = std::max( 0, battery_capacity - battery_left - delta_energy_bat ); + Character &player_character = get_player_character(); // Reactors trigger only on demand. If we'd otherwise run out of power, see // if we can spin up the reactors. if( !reactors.empty() && storage_deficit_bat > 0 ) { @@ -4754,7 +4855,7 @@ void vehicle::power_parts() for( auto &elem : reactors ) { parts[ elem ].enabled = false; } - if( player_in_control( g->u ) || g->u.sees( global_pos3() ) ) { + if( player_in_control( player_character ) || player_character.sees( global_pos3() ) ) { add_msg( _( "The %s's reactor dies!" ), name ); } } @@ -4788,13 +4889,13 @@ void vehicle::power_parts() is_alarm_on = false; camera_on = false; - if( player_in_control( g->u ) || g->u.sees( global_pos3() ) ) { + if( player_in_control( player_character ) || player_character.sees( global_pos3() ) ) { add_msg( _( "The %s's battery dies!" ), name ); } if( engine_epower < 0 ) { // Not enough epower to run gas engine ignition system engine_on = false; - if( player_in_control( g->u ) || g->u.sees( global_pos3() ) ) { + if( player_in_control( player_character ) || player_character.sees( global_pos3() ) ) { add_msg( _( "The %s's engine dies!" ), name ); } } @@ -4803,9 +4904,10 @@ void vehicle::power_parts() vehicle *vehicle::find_vehicle( const tripoint &where ) { + map &here = get_map(); // Is it in the reality bubble? - tripoint veh_local = g->m.getlocal( where ); - if( const optional_vpart_position vp = g->m.veh_at( veh_local ) ) { + tripoint veh_local = here.getlocal( where ); + if( const optional_vpart_position vp = here.veh_at( veh_local ) ) { return &vp->vehicle(); } @@ -4859,7 +4961,7 @@ int vehicle::traverse_vehicle_graph( Vehicle *start_veh, int amount, Func action visited_vehs.insert( current_veh ); connected_vehs.pop(); - g->u.add_msg_if_player( m_debug, "Traversing graph with %d power", amount ); + add_msg( m_debug, "Traversing graph with %d power", amount ); for( auto &p : current_veh->loose_parts ) { if( !current_veh->part_info( p ).has_flag( "POWER_TRANSFER" ) ) { @@ -4880,12 +4982,11 @@ int vehicle::traverse_vehicle_graph( Vehicle *start_veh, int amount, Func action connected_vehs.push( std::make_pair( target_veh, target_loss ) ); float loss_amount = ( static_cast( amount ) * static_cast( target_loss ) ) / 100; - g->u.add_msg_if_player( m_debug, "Visiting remote %p with %d power (loss %f, which is %d percent)", - static_cast( target_veh ), amount, loss_amount, target_loss ); + add_msg( m_debug, "Visiting remote %p with %d power (loss %f, which is %d percent)", + static_cast( target_veh ), amount, loss_amount, target_loss ); amount = action( target_veh, amount, static_cast( loss_amount ) ); - g->u.add_msg_if_player( m_debug, "After remote %p, %d power", static_cast( target_veh ), - amount ); + add_msg( m_debug, "After remote %p, %d power", static_cast( target_veh ), amount ); if( amount < 1 ) { break; // No more charge to donate away. @@ -4925,7 +5026,7 @@ int vehicle::charge_battery( int amount, bool include_other_vehicles ) } auto charge_visitor = []( vehicle * veh, int amount, int lost ) { - g->u.add_msg_if_player( m_debug, "CH: %d", amount - lost ); + add_msg( m_debug, "CH: %d", amount - lost ); return veh->charge_battery( amount - lost, false ); }; @@ -4962,7 +5063,7 @@ int vehicle::discharge_battery( int amount, bool recurse ) } auto discharge_visitor = []( vehicle * veh, int amount, int lost ) { - g->u.add_msg_if_player( m_debug, "CH: %d", amount + lost ); + add_msg( m_debug, "CH: %d", amount + lost ); return veh->discharge_battery( amount + lost, false ); }; if( amount > 0 && recurse ) { // need more power! @@ -4989,7 +5090,10 @@ void vehicle::do_engine_damage( size_t e, int strain ) void vehicle::idle( bool on_map ) { + avg_velocity = ( velocity + avg_velocity ) / 2; + power_parts(); + Character &player_character = get_player_character(); if( engine_on && total_power_w() > 0 ) { int idle_rate = alternator_load; if( idle_rate < 10 ) { @@ -5008,7 +5112,7 @@ void vehicle::idle( bool on_map ) noise_and_smoke( idle_rate, 1_turns ); } } else { - if( engine_on && g->u.sees( global_pos3() ) && + if( engine_on && player_character.sees( global_pos3() ) && ( has_engine_type_not( fuel_type_muscle, true ) && has_engine_type_not( fuel_type_animal, true ) && has_engine_type_not( fuel_type_wind, true ) && has_engine_type_not( fuel_type_mana, true ) ) ) { add_msg( _( "The %s's engine dies!" ), name ); @@ -5016,15 +5120,17 @@ void vehicle::idle( bool on_map ) engine_on = false; } - if( !warm_enough_to_plant( g->u.pos() ) ) { + if( !warm_enough_to_plant( player_character.pos() ) ) { for( const vpart_reference &vp : get_enabled_parts( "PLANTER" ) ) { - if( g->u.sees( global_pos3() ) ) { + if( player_character.sees( global_pos3() ) ) { add_msg( _( "The %s's planter turns off due to low temperature." ), name ); } vp.part().enabled = false; } } + smart_controller_handle_turn(); + if( !on_map ) { return; } else { @@ -5068,6 +5174,7 @@ void vehicle::on_move() void vehicle::slow_leak() { + map &here = get_map(); // for each badly damaged tanks (lower than 50% health), leak a small amount for( auto &p : parts ) { auto health = p.health_percent(); @@ -5083,12 +5190,12 @@ void vehicle::slow_leak() // damaged batteries self-discharge without leaking, plutonium leaks slurry if( fuel != fuel_type_battery && fuel != fuel_type_plutonium_cell ) { item leak( fuel, calendar::turn, qty ); - g->m.add_item_or_charges( dest, leak ); + here.add_item_or_charges( dest, leak ); p.ammo_consume( qty, global_part_pos3( p ) ); } else if( fuel == fuel_type_plutonium_cell ) { if( p.ammo_remaining() >= PLUTONIUM_CHARGES / 10 ) { item leak( "plut_slurry_dense", calendar::turn, qty ); - g->m.add_item_or_charges( dest, leak ); + here.add_item_or_charges( dest, leak ); p.ammo_consume( qty * PLUTONIUM_CHARGES / 10, global_part_pos3( p ) ); } else { p.ammo_consume( p.ammo_remaining(), global_part_pos3( p ) ); @@ -5317,7 +5424,7 @@ void vehicle::gain_moves() { fuel_used_last_turn.clear(); check_falling_or_floating(); - const bool pl_control = player_in_control( g->u ); + const bool pl_control = player_in_control( get_player_character() ); if( is_moving() || is_falling ) { if( !loose_parts.empty() ) { shed_loose_parts(); @@ -5371,9 +5478,10 @@ void vehicle::gain_moves() void vehicle::dump_items_from_part( const size_t index ) { + map &here = get_map(); vehicle_part &vp = parts[ index ]; for( item &e : vp.items ) { - g->m.add_item_or_charges( global_part_pos3( vp ), e ); + here.add_item_or_charges( global_part_pos3( vp ), e ); } vp.items.clear(); } @@ -5388,10 +5496,10 @@ bool vehicle::decrement_summon_timer() const size_t p = vp.part_index(); dump_items_from_part( p ); } - if( g->u.sees( global_pos3() ) ) { + if( get_player_character().sees( global_pos3() ) ) { add_msg( m_info, _( "Your %s winks out of existence." ), name ); } - g->m.destroy_vehicle( this ); + get_map().destroy_vehicle( this ); return true; } else { *summon_time_limit -= 1_turns; @@ -5453,6 +5561,9 @@ void vehicle::refresh() steering.clear(); speciality.clear(); floating.clear(); + batteries.clear(); + fuel_containers.clear(); + alternator_load = 0; extra_drag = 0; all_wheels_on_one_axis = true; @@ -5476,6 +5587,9 @@ void vehicle::refresh() int railwheel_xmax = INT_MIN; int railwheel_ymax = INT_MIN; + has_enabled_smart_controller = false; + smart_controller_state = cata::nullopt; + bool refresh_done = false; // Main loop over all vehicle parts. @@ -5522,6 +5636,12 @@ void vehicle::refresh() if( vpi.has_flag( VPFLAG_ROTOR ) || vpi.has_flag( VPFLAG_ROTOR_SIMPLE ) ) { rotors.push_back( p ); } + if( vp.part().is_battery() ) { + batteries.push_back( p ); + } + if( vp.part().is_fuel_store( false ) ) { + fuel_containers.push_back( p ); + } if( vpi.has_flag( "WIND_TURBINE" ) ) { wind_turbines.push_back( p ); } @@ -5543,6 +5663,9 @@ void vehicle::refresh() if( vpi.has_flag( VPFLAG_WHEEL ) ) { wheelcache.push_back( p ); } + if( vpi.has_flag( "SMART_ENGINE_CONTROLLER" ) && vp.part().enabled ) { + has_enabled_smart_controller = true; + } if( vpi.has_flag( VPFLAG_WHEEL ) && vpi.has_flag( VPFLAG_RAIL ) ) { rail_wheelcache.push_back( p ); if( first_wheel_y_mount == INT_MAX ) { @@ -5748,13 +5871,14 @@ void vehicle::do_towing_move() invalidate_towing(); return; } - const tripoint tower_tow_point = g->m.getabs( global_part_pos3( tow_index ) ); - const tripoint towed_tow_point = g->m.getabs( towed_veh->global_part_pos3( other_tow_index ) ); + map &here = get_map(); + const tripoint tower_tow_point = here.getabs( global_part_pos3( tow_index ) ); + const tripoint towed_tow_point = here.getabs( towed_veh->global_part_pos3( other_tow_index ) ); // same as above, but where the pulling vehicle is pulling from double towing_veh_angle = towed_veh->get_angle_from_targ( tower_tow_point ); const bool reverse = towed_veh->tow_data.tow_direction == TOW_BACK; int accel_y = 0; - tripoint vehpos = g->m.getabs( towed_veh->global_pos3() ); + tripoint vehpos = here.getabs( towed_veh->global_pos3() ); int turn_x = get_turn_from_angle( towing_veh_angle, vehpos, tower_tow_point, reverse ); if( rl_dist( towed_tow_point, tower_tow_point ) < 6 ) { accel_y = reverse ? -1 : 1; @@ -5777,21 +5901,21 @@ void vehicle::do_towing_move() towed_veh->autodrive( point( turn_x, accel_y ) ); } else { towed_veh->skidding = true; - std::vector lineto = line_to( g->m.getlocal( towed_tow_point ), - g->m.getlocal( tower_tow_point ) ); + std::vector lineto = line_to( here.getlocal( towed_tow_point ), + here.getlocal( tower_tow_point ) ); tripoint nearby_destination; if( lineto.size() >= 2 ) { nearby_destination = lineto[1]; } else { nearby_destination = tower_tow_point; } - const int destination_delta_x = g->m.getlocal( tower_tow_point ).x - nearby_destination.x; - const int destination_delta_y = g->m.getlocal( tower_tow_point ).y - nearby_destination.y; + const int destination_delta_x = here.getlocal( tower_tow_point ).x - nearby_destination.x; + const int destination_delta_y = here.getlocal( tower_tow_point ).y - nearby_destination.y; const int destination_delta_z = towed_veh->global_pos3().z; const tripoint move_destination( clamp( destination_delta_x, -1, 1 ), clamp( destination_delta_y, -1, 1 ), clamp( destination_delta_z, -1, 1 ) ); - g->m.move_vehicle( *towed_veh, move_destination, towed_veh->face ); + here.move_vehicle( *towed_veh, move_destination, towed_veh->face ); towed_veh->move = tileray( point( destination_delta_x, destination_delta_y ) ); } @@ -5799,8 +5923,9 @@ void vehicle::do_towing_move() bool vehicle::is_external_part( const tripoint &part_pt ) const { - for( const tripoint &elem : g->m.points_in_radius( part_pt, 1 ) ) { - const optional_vpart_position vp = g->m.veh_at( elem ); + map &here = get_map(); + for( const tripoint &elem : here.points_in_radius( part_pt, 1 ) ) { + const optional_vpart_position vp = here.veh_at( elem ); if( !vp ) { return true; } @@ -5920,6 +6045,7 @@ void vehicle::invalidate_towing( bool first_vehicle ) if( other_veh && first_vehicle ) { other_veh->invalidate_towing(); } + map &here = get_map(); for( const vpart_reference &vp : get_all_parts() ) { const size_t p = vp.part_index(); if( vp.part().removed ) { @@ -5930,7 +6056,7 @@ void vehicle::invalidate_towing( bool first_vehicle ) if( first_vehicle ) { vehicle_part *part = &parts[part_with_feature( p, "TOW_CABLE", true )]; item drop = part->properties_to_item(); - g->m.add_item_or_charges( global_part_pos3( *part ), drop ); + here.add_item_or_charges( global_part_pos3( *part ), drop ); } remove_part( part_with_feature( p, "TOW_CABLE", true ) ); break; @@ -5951,7 +6077,8 @@ bool vehicle::tow_cable_too_far() const debugmsg( "towing data exists but no towing part" ); return false; } - tripoint towing_point = g->m.getabs( global_part_pos3( index ) ); + map &here = get_map(); + tripoint towing_point = here.getabs( global_part_pos3( index ) ); if( !tow_data.get_towed_by()->tow_data.get_towed() ) { debugmsg( "vehicle %s has data for a towing vehicle, but that towing vehicle does not have %s listed as towed", disp_name(), disp_name() ); @@ -5962,7 +6089,7 @@ bool vehicle::tow_cable_too_far() const debugmsg( "towing data exists but no towing part" ); return false; } - tripoint towed_point = g->m.getabs( tow_data.get_towed_by()->global_part_pos3( other_index ) ); + tripoint towed_point = here.getabs( tow_data.get_towed_by()->global_part_pos3( other_index ) ); if( towing_point == tripoint_zero || towed_point == tripoint_zero ) { debugmsg( "towing data exists but no towing part" ); return false; @@ -5982,7 +6109,8 @@ bool vehicle::no_towing_slack() const debugmsg( "towing data exists but no towing part" ); return false; } - tripoint towing_point = g->m.getabs( global_part_pos3( index ) ); + map &here = get_map(); + tripoint towing_point = here.getabs( global_part_pos3( index ) ); if( !tow_data.get_towed()->tow_data.get_towed_by() ) { debugmsg( "vehicle %s has data for a towed vehicle, but that towed vehicle does not have %s listed as tower", disp_name(), disp_name() ); @@ -5993,7 +6121,7 @@ bool vehicle::no_towing_slack() const debugmsg( "towing data exists but no towing part" ); return false; } - tripoint towed_point = g->m.getabs( tow_data.get_towed()->global_part_pos3( other_index ) ); + tripoint towed_point = here.getabs( tow_data.get_towed()->global_part_pos3( other_index ) ); if( towing_point == tripoint_zero || towed_point == tripoint_zero ) { debugmsg( "towing data exists but no towing part" ); return false; @@ -6008,7 +6136,7 @@ void vehicle::remove_remote_part( int part_num ) // If the target vehicle is still there, ask it to remove its part if( veh != nullptr ) { - const tripoint local_abs = g->m.getabs( global_part_pos3( part_num ) ); + const tripoint local_abs = get_map().getabs( global_part_pos3( part_num ) ); for( size_t j = 0; j < veh->loose_parts.size(); j++ ) { int remote_partnum = veh->loose_parts[j]; @@ -6024,6 +6152,7 @@ void vehicle::remove_remote_part( int part_num ) void vehicle::shed_loose_parts() { + map &here = get_map(); // remove_part rebuilds the loose_parts vector, when all of those parts have been removed, // it will stay empty. while( !loose_parts.empty() ) { @@ -6043,7 +6172,7 @@ void vehicle::shed_loose_parts() auto part = &parts[elem]; if( !magic ) { item drop = part->properties_to_item(); - g->m.add_item_or_charges( global_part_pos3( *part ), drop ); + here.add_item_or_charges( global_part_pos3( *part ), drop ); } remove_part( elem ); @@ -6122,9 +6251,10 @@ bool vpart_position::is_inside() const void vehicle::unboard_all() { + map &here = get_map(); std::vector bp = boarded_parts(); for( auto &i : bp ) { - g->m.unboard_vehicle( global_part_pos3( i ) ); + here.unboard_vehicle( global_part_pos3( i ) ); } } @@ -6257,7 +6387,7 @@ void vehicle::shift_parts( const point &delta ) pivot_anchor[0] -= delta; refresh(); //Need to also update the map after this - g->m.reset_vehicle_cache( sm_pos.z ); + get_map().reset_vehicle_cache( sm_pos.z ); } /** @@ -6301,20 +6431,22 @@ int vehicle::break_off( int p, int dmg ) if( rng( 0, part_info( p ).durability / 10 ) >= dmg ) { return dmg; } + map &here = get_map(); const tripoint pos = global_part_pos3( p ); const auto scatter_parts = [&]( const vehicle_part & pt ) { for( const item &piece : pt.pieces_for_broken_part() ) { // inside the loop, so each piece goes to a different place // TODO: this may spawn items behind a wall - const tripoint where = random_entry( g->m.points_in_radius( pos, SCATTER_DISTANCE ) ); + const tripoint where = random_entry( here.points_in_radius( pos, SCATTER_DISTANCE ) ); // TODO: balance audit, ensure that less pieces are generated than one would need // to build the component (smash a vehicle box that took 10 lumps of steel, // find 12 steel lumps scattered after atom-smashing it with a tree trunk) if( !magic ) { - g->m.add_item_or_charges( where, piece ); + here.add_item_or_charges( where, piece ); } } }; + Character &player_character = get_player_character(); if( part_info( p ).location == part_location_structure ) { // For structural parts, remove other parts first std::vector parts_in_square = parts_at_relative( parts[p].mount, true ); @@ -6326,26 +6458,26 @@ int vehicle::break_off( int p, int dmg ) if( parts[ parts_in_square[ index ] ].is_broken() ) { // Tearing off a broken part - break it up - if( g->u.sees( pos ) ) { + if( player_character.sees( pos ) ) { add_msg( m_bad, _( "The %s's %s breaks into pieces!" ), name, parts[ parts_in_square[ index ] ].name() ); } scatter_parts( parts[parts_in_square[index]] ); } else { // Intact (but possibly damaged) part - remove it in one piece - if( g->u.sees( pos ) ) { + if( player_character.sees( pos ) ) { add_msg( m_bad, _( "The %1$s's %2$s is torn off!" ), name, parts[ parts_in_square[ index ] ].name() ); } if( !magic ) { item part_as_item = parts[parts_in_square[index]].properties_to_item(); - g->m.add_item_or_charges( pos, part_as_item ); + here.add_item_or_charges( pos, part_as_item ); } } remove_part( parts_in_square[index] ); } // After clearing the frame, remove it. - if( g->u.sees( pos ) ) { + if( player_character.sees( pos ) ) { add_msg( m_bad, _( "The %1$s's %2$s is destroyed!" ), name, parts[ p ].name() ); } scatter_parts( parts[p] ); @@ -6353,7 +6485,7 @@ int vehicle::break_off( int p, int dmg ) find_and_split_vehicles( p ); } else { //Just break it off - if( g->u.sees( pos ) ) { + if( player_character.sees( pos ) ) { add_msg( m_bad, _( "The %1$s's %2$s is destroyed!" ), name, parts[ p ].name() ); } @@ -6402,7 +6534,8 @@ int vehicle::damage_direct( int p, int dmg, damage_type type ) if( is_autodriving ) { stop_autodriving(); } - g->m.set_memory_seen_cache_dirty( global_part_pos3( p ) ); + map &here = get_map(); + here.set_memory_seen_cache_dirty( global_part_pos3( p ) ); if( parts[p].is_broken() ) { return break_off( p, dmg ); } @@ -6431,7 +6564,7 @@ int vehicle::damage_direct( int p, int dmg, damage_type type ) leak_fuel( parts [ p ] ); for( const auto &e : parts[p].items ) { - g->m.add_item_or_charges( global_part_pos3( p ), e ); + here.add_item_or_charges( global_part_pos3( p ), e ); } parts[p].items.clear(); @@ -6445,7 +6578,7 @@ int vehicle::damage_direct( int p, int dmg, damage_type type ) if( parts[p].is_fuel_store() ) { explode_fuel( p, type ); } else if( parts[ p ].is_broken() && part_flag( p, "UNMOUNT_ON_DAMAGE" ) ) { - g->m.spawn_item( global_part_pos3( p ), part_info( p ).item, 1, 0, calendar::turn ); + here.spawn_item( global_part_pos3( p ), part_info( p ).item, 1, 0, calendar::turn ); monster *mon = get_pet( p ); if( mon != nullptr && mon->has_effect( effect_harnessed ) ) { mon->remove_effect( effect_harnessed ); @@ -6467,10 +6600,11 @@ void vehicle::leak_fuel( vehicle_part &pt ) return; } + map &here = get_map(); // leak in random directions but prefer closest tiles and avoid walls or other obstacles - std::vector tiles = closest_tripoints_first( global_part_pos3( pt ), 1 ); - tiles.erase( std::remove_if( tiles.begin(), tiles.end(), []( const tripoint & e ) { - return !g->m.passable( e ); + std::vector tiles = closest_points_first( global_part_pos3( pt ), 1 ); + tiles.erase( std::remove_if( tiles.begin(), tiles.end(), [&here]( const tripoint & e ) { + return !here.passable( e ); } ), tiles.end() ); // leak up to 1/3 of remaining fuel per iteration and continue until the part is empty @@ -6479,7 +6613,7 @@ void vehicle::leak_fuel( vehicle_part &pt ) int qty = pt.ammo_consume( rng( 0, std::max( pt.ammo_remaining() / 3, 1 ) ), global_part_pos3( pt ) ); if( qty > 0 ) { - g->m.add_item_or_charges( random_entry( tiles ), item( fuel, calendar::turn, qty ) ); + here.add_item_or_charges( random_entry( tiles ), item( fuel, calendar::turn, qty ) ); } } @@ -6623,6 +6757,7 @@ void vehicle::update_time( const time_point &update_to ) int exhaust_part; std::tie( exhaust_part, muffle ) = get_exhaust_part(); + map &here = get_map(); // Parts emitting fields for( int idx : emitters ) { const vehicle_part &pt = parts[idx]; @@ -6630,13 +6765,13 @@ void vehicle::update_time( const time_point &update_to ) continue; } for( const emit_id &e : pt.info().emissions ) { - g->m.emit_field( global_part_pos3( pt ), e ); + here.emit_field( global_part_pos3( pt ), e ); } for( const emit_id &e : pt.info().exhaust ) { if( exhaust_part == -1 ) { - g->m.emit_field( global_part_pos3( pt ), e ); + here.emit_field( global_part_pos3( pt ), e ); } else { - g->m.emit_field( exhaust_dest( exhaust_part ), e ); + here.emit_field( exhaust_dest( exhaust_part ), e ); } } discharge_battery( pt.info().epower ); @@ -6666,7 +6801,7 @@ void vehicle::update_time( const time_point &update_to ) return; } // Get one weather data set per vehicle, they don't differ much across vehicle area - auto accum_weather = sum_conditions( update_from, update_to, g->m.getabs( global_pos3() ) ); + auto accum_weather = sum_conditions( update_from, update_to, here.getabs( global_pos3() ) ); // make some reference objects to use to check for reload const item water( "water" ); const item water_clean( "water_clean" ); @@ -6675,7 +6810,7 @@ void vehicle::update_time( const time_point &update_to ) const auto &pt = parts[idx]; // we need an unbroken funnel mounted on the exterior of the vehicle - if( pt.is_unavailable() || !is_sm_tile_outside( g->m.getabs( global_part_pos3( pt ) ) ) ) { + if( pt.is_unavailable() || !is_sm_tile_outside( here.getabs( global_part_pos3( pt ) ) ) ) { continue; } @@ -6713,7 +6848,7 @@ void vehicle::update_time( const time_point &update_to ) continue; } - if( !is_sm_tile_outside( g->m.getabs( global_part_pos3( part ) ) ) ) { + if( !is_sm_tile_outside( here.getabs( global_part_pos3( part ) ) ) ) { continue; } @@ -6830,7 +6965,7 @@ bounding_box vehicle::get_bounding_box() int i_use = 0; for( const tripoint &p : get_points( true ) ) { - const point pt = parts[part_at( p.xy() )].precalc[i_use]; + const point pt = parts[part_at( p.xy() )].precalc[i_use].xy(); if( pt.x < min_x ) { min_x = pt.x; } @@ -6880,23 +7015,74 @@ void vehicle::force_erase_part( int part_num ) parts.erase( parts.begin() + part_num ); } -void vehicle::advance_precalc_mounts( const point &new_pos, int submap_z ) -{ - for( vehicle_part &pt : parts ) { - pt.precalc[0] = pt.precalc[1]; +std::set vehicle::advance_precalc_mounts( const point &new_pos, const tripoint &src, + const tripoint &dp, int ramp_offset, const bool adjust_pos, + std::set parts_to_move ) +{ + map &here = get_map(); + std::set smzs; + // when a vehicle part enters the low end of a down ramp, or the high end of an up ramp, + // it immediately translates down or up a z-level, respectively, ending up on the low + // end of an up ramp or high end of a down ramp, respectively. The two ends are set + // past each other, like so: + // (side view) z+1 Rdh RDl + // z+0 RUh Rul + // A vehicle moving left to right on z+1 drives down to z+0 by entering the ramp down low end. + // A vehicle moving right to left on z+0 drives up to z+1 by entering the ramp up high end. + // A vehicle moving left to right on z+0 should ideally collide into a wall before entering + // the ramp up high end, but even if it does, it briefly transitions to z+1 before returning + // to z0 by entering the ramp down low end. + // A vehicle moving right to left on z+1 drives down to z+0 by entering the ramp down low end, + // then immediately returns to z+1 by entering the ramp up high end. + // When a vehicle's pivot point transitions a z-level via a ramp, all other pre-calc points + // make the opposite transition, so that points that were above an ascending pivot point are + // now level with it, and parts that were level with an ascending pivot point are now below + // it. + // parts that enter the translation portion of a ramp on the same displacement as the + // pivot point stay at the same relative z to the pivot point, as the ramp_offset adjustments + // cancel out. + // if a vehicle manages move partially up or down a ramp and then veers off course, it + // can get split across the z-levels and continue moving, enough though large parts of the + // vehicle are unsupported. In that case, move the unsupported parts down until they are + // supported. + int index = -1; + for( vehicle_part &prt : parts ) { + index += 1; + here.clear_vehicle_point_from_cache( this, src + prt.precalc[0] ); + // no parts means this is a normal horizontal or vertical move + if( parts_to_move.empty() ) { + prt.precalc[0] = prt.precalc[1]; + // partial part movement means we're zero-ing out after missing a ramp + } else if( adjust_pos && parts_to_move.find( index ) == parts_to_move.end() ) { + prt.precalc[0].z -= dp.z; + } else if( !adjust_pos && parts_to_move.find( index ) != parts_to_move.end() ) { + prt.precalc[0].z += dp.z; + } + if( here.has_flag( TFLAG_RAMP_UP, src + dp + prt.precalc[0] ) ) { + prt.precalc[0].z += 1; + } else if( here.has_flag( TFLAG_RAMP_DOWN, src + dp + prt.precalc[0] ) ) { + prt.precalc[0].z -= 1; + } + prt.precalc[0].z -= ramp_offset; + prt.precalc[1].z = prt.precalc[0].z; + smzs.insert( prt.precalc[0].z ); + } + if( adjust_pos ) { + if( parts_to_move.empty() ) { + pivot_anchor[0] = pivot_anchor[1]; + pivot_rotation[0] = pivot_rotation[1]; + } + pos = new_pos; } - pivot_anchor[0] = pivot_anchor[1]; - pivot_rotation[0] = pivot_rotation[1]; - - pos = new_pos; - sm_pos.z = submap_z; // Invalidate vehicle's point cache occupied_cache_time = calendar::before_time_starts; + return smzs; } bool vehicle::refresh_zones() { if( zones_dirty ) { + map &here = get_map(); decltype( loot_zones ) new_zones; for( auto const &z : loot_zones ) { zone_data zone = z.second; @@ -6912,7 +7098,7 @@ bool vehicle::refresh_zones() continue; } tripoint zone_pos = global_part_pos3( part_idx ); - zone_pos = g->m.getabs( zone_pos ); + zone_pos = here.getabs( zone_pos ); //Set the position of the zone to that part zone.set_position( std::pair( zone_pos, zone_pos ), false ); new_zones.emplace( z.first, zone ); diff --git a/src/vehicle.h b/src/vehicle.h index 8b7f5e828454c..234b195b8d5fb 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -101,6 +101,16 @@ enum veh_coll_type : int { num_veh_coll_types }; +struct smart_controller_cache { + time_point created = calendar::turn; + time_point gas_engine_last_turned_on = calendar::start_of_cataclysm; + bool gas_engine_shutdown_forbidden; + int velocity; + int battery_percent; + int battery_net_charge_rate; + float load; +}; + struct veh_collision { //int veh? int part = 0; @@ -365,7 +375,7 @@ struct vehicle_part { /** mount translated to face.dir [0] and turn_dir [1] */ // NOLINTNEXTLINE(cata-use-named-point-constants) - std::array precalc = { { point( -1, -1 ), point( -1, -1 ) } }; + std::array precalc = { { tripoint( -1, -1, 0 ), tripoint( -1, -1, 0 ) } }; /** current part health with range [0,durability] */ int hp() const; @@ -537,7 +547,7 @@ class turret_data * @param target coordinates that will be fired on. * @return the number of shots actually fired (may be zero). */ - int fire( player &p, const tripoint &target ); + int fire( Character &c, const tripoint &target ); bool can_reload() const; bool can_unload() const; @@ -571,6 +581,9 @@ struct label : public point { label( const point &p, std::string text ) : point( p ), text( std::move( text ) ) {} std::string text; + + void deserialize( JsonIn &jsin ); + void serialize( JsonOut &json ) const; }; class RemovePartHandler; @@ -758,9 +771,9 @@ class vehicle bool mod_hp( vehicle_part &pt, int qty, damage_type dt = DT_NULL ); // check if given player controls this vehicle - bool player_in_control( const player &p ) const; + bool player_in_control( const Character &p ) const; // check if player controls this vehicle remotely - bool remote_controlled( const player &p ) const; + bool remote_controlled( const Character &p ) const; // init parts state for randomly generated vehicle void init_state( int init_veh_fuel, int init_veh_status ); @@ -1042,10 +1055,10 @@ class vehicle point coord_translate( const point &p ) const; // Translate mount coordinates "p" into tile coordinates "q" using given pivot direction and anchor - void coord_translate( int dir, const point &pivot, const point &p, point &q ) const; + void coord_translate( int dir, const point &pivot, const point &p, tripoint &q ) const; // Translate mount coordinates "p" into tile coordinates "q" using given tileray and anchor // should be faster than previous call for repeated translations - void coord_translate( tileray tdir, const point &pivot, const point &p, point &q ) const; + void coord_translate( tileray tdir, const point &pivot, const point &p, tripoint &q ) const; // Rotates mount coordinates "p" from old_dir to new_dir along pivot point rotate_mount( int old_dir, int new_dir, const point &pivot, const point &p ) const; @@ -1146,6 +1159,8 @@ class vehicle */ std::map fuel_usage() const; + // current fuel usage for specific engine + int engine_fuel_usage( int e ) const; /** * Get all vehicle lights (excluding any that are destroyed) * @param active if true return only lights which are enabled @@ -1175,6 +1190,9 @@ class vehicle // taken from batteries. void power_parts(); + // Current and total battery power level as a pair + std::pair battery_power_level() const; + /** * Try to charge our (and, optionally, connected vehicles') batteries by the given amount. * @return amount of charge left over. @@ -1387,6 +1405,14 @@ class vehicle // @param z = z thrust for helicopters etc void thrust( int thd, int z = 0 ); + /** + * if smart controller is enabled, turns on and off engines depending on load and battery level + * @param thrusting must be true when called from vehicle::thrust and vehicle is thrusting + * @param k_traction_cache cached value of vehicle::k_traction, if empty, will be computed + */ + void smart_controller_handle_turn( bool thrusting = false, + cata::optional k_traction_cache = cata::nullopt ); + //deceleration due to ground friction and air resistance int slowdown( int velocity ) const; @@ -1423,8 +1449,8 @@ class vehicle /** * can the helicopter descend/ascend here? */ - bool check_heli_descend( player &p ); - bool check_heli_ascend( player &p ); + bool check_heli_descend( Character &p ); + bool check_heli_ascend( Character &p ); bool check_is_heli_landed(); /** * Player is driving the vehicle @@ -1635,10 +1661,16 @@ class vehicle bool is_part_on( int p ) const; //returns whether the engine uses specified fuel type bool is_engine_type( int e, const itype_id &ft ) const; + //returns whether the engine uses one of specific "combustion" fuel types (gas, diesel and diesel substitutes) + bool is_combustion_engine_type( int e ) const; //returns whether the alternator is operational bool is_alternator_on( int a ) const; - //mark engine as on or off + //turn engine as on or off (note: doesn't perform checks if engine can start) void toggle_specific_engine( int e, bool on ); + // try to turn engine on or off + // (tries to start it and toggles it on if successful, shutdown is always a success) + // returns true if engine status was changed + bool start_engine( int e, bool turn_on ); void toggle_specific_part( int p, bool on ); //true if an engine exists with specified type //If enabled true, this engine must be enabled to return true @@ -1692,7 +1724,7 @@ class vehicle * This should be called only when the vehicle has actually been moved, not when * the map is just shifted (in the later case simply set smx/smy directly). */ - void set_submap_moved( const point &p ); + void set_submap_moved( const tripoint &p ); void use_autoclave( int p ); void use_washing_machine( int p ); void use_dishwasher( int p ); @@ -1744,7 +1776,11 @@ class vehicle void force_erase_part( int part_num ); // Updates the internal precalculated mount offsets after the vehicle has been displaced // used in map::displace_vehicle() - void advance_precalc_mounts( const point &new_pos, int submap_z ); + std::set advance_precalc_mounts( const point &new_pos, const tripoint &src, + const tripoint &dp, int ramp_offset, + bool adjust_pos, std::set parts_to_move ); + // make sure the vehicle is supported across z-levels or on the same z-level + bool level_vehicle(); std::vector omt_path; // route for overmap-scale auto-driving std::vector alternators; // List of alternator indices @@ -1764,6 +1800,8 @@ class vehicle // List of parts that will not be on a vehicle very often, or which only one will be present std::vector speciality; std::vector floating; // List of parts that provide buoyancy to boats + std::vector batteries; // List of batteries + std::vector fuel_containers; // List parts with non-null ammo_type // config values std::string name; // vehicle name @@ -1786,6 +1824,9 @@ class vehicle bool magic = false; // when does the magic vehicle disappear? cata::optional summon_time_limit = cata::nullopt; + // cached values of the factors that determined last chosen engine state + cata::optional smart_controller_state = cata::nullopt; + bool has_enabled_smart_controller = false; private: mutable units::mass mass_cache; @@ -1834,6 +1875,12 @@ class vehicle point pos; // vehicle current velocity, mph * 100 int velocity = 0; + /** + * vehicle continuous moving average velocity + * see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average + * alpha is 0.5: avg_velocity = avg_velocity + 0.5(velocity - avg_velocity) = 0.5 avg_velocity + 0.5 velocity + */ + int avg_velocity = 0; // velocity vehicle's cruise control trying to achieve int cruise_velocity = 0; // Only used for collisions, vehicle falls instantly diff --git a/src/vehicle_display.cpp b/src/vehicle_display.cpp index 3895e85d6f551..6445b7cc234e7 100644 --- a/src/vehicle_display.cpp +++ b/src/vehicle_display.cpp @@ -47,8 +47,9 @@ char vehicle::part_sym( const int p, const bool exact ) const } } -// similar to part_sym(int p) but for use when drawing SDL tiles. Called only by cata_tiles during draw_vpart -// vector returns at least 1 element, max of 2 elements. If 2 elements the second denotes if it is open or damaged +// similar to part_sym(int p) but for use when drawing SDL tiles. Called only by cata_tiles +// during draw_vpart vector returns at least 1 element, max of 2 elements. If 2 elements the +// second denotes if it is open or damaged vpart_id vehicle::part_id_string( const int p, char &part_mod ) const { part_mod = 0; @@ -57,6 +58,11 @@ vpart_id vehicle::part_id_string( const int p, char &part_mod ) const } int displayed_part = part_displayed_at( parts[p].mount ); + if( displayed_part < 0 || displayed_part >= static_cast( parts.size() ) || + parts[ displayed_part ].removed ) { + return vpart_id::NULL_ID(); + } + const vpart_id idinfo = parts[displayed_part].id; if( part_flag( displayed_part, VPFLAG_OPENABLE ) && parts[displayed_part].open ) { diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 282963a234ddd..88b33d2076c29 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -35,6 +35,7 @@ #include "enums.h" #include "int_id.h" #include "monster.h" +#include "vpart_range.h" #define dbg(x) DebugLog((x),D_MAP) << __FILE__ << ":" << __LINE__ << ": " @@ -116,6 +117,263 @@ int vehicle::slowdown( int at_velocity ) const return std::max( 1, slowdown ); } +void vehicle:: smart_controller_handle_turn( bool thrusting, + cata::optional k_traction_cache ) +{ + + if( !engine_on || !has_enabled_smart_controller ) { + smart_controller_state = cata::nullopt; + return; + } + + if( smart_controller_state && smart_controller_state->created == calendar::turn ) { + return; + } + + // controlled engines + // note: contains indices of of elements in `engines` array, not the part ids + std::vector c_engines; + for( int i = 0; i < static_cast( engines.size() ); ++i ) { + if( ( is_engine_type( i, fuel_type_battery ) || is_combustion_engine_type( i ) ) && + ( ( parts[ engines[ i ] ].is_available() && engine_fuel_left( i ) > 0 ) || + is_part_on( engines[ i ] ) ) ) { + c_engines.push_back( i ); + } + } + + bool rotorcraft = is_flying && is_rotorcraft(); + + if( rotorcraft || c_engines.size() <= 1 || c_engines.size() > 5 ) { // bail and shut down + for( const vpart_reference &vp : get_avail_parts( "SMART_ENGINE_CONTROLLER" ) ) { + vp.part().enabled = false; + } + + if( player_in_control( g->u ) ) { + if( rotorcraft ) { + add_msg( _( "Smart controller does not support flying vehicles." ) ); + } else if( c_engines.size() <= 1 ) { + add_msg( _( "Smart controller detects only a single controllable engine." ) ); + add_msg( _( "Smart controller is designed to control more than one engine." ) ); + } else { + add_msg( _( "Smart controller does not support more than five engines." ) ); + } + add_msg( m_bad, _( "Smart controller is shutting down." ) ); + } + has_enabled_smart_controller = false; + smart_controller_state = cata::nullopt; + return; + } + + int cur_battery_level, max_battery_level; + std::tie( cur_battery_level, max_battery_level ) = battery_power_level(); + int battery_level_percent = max_battery_level == 0 ? 0 : cur_battery_level * 100 / + max_battery_level; + + // when battery > 90%, discharge is allowed + // otherwise trying to charge battery to 90% within 30 minutes + bool discharge_forbidden_soft = battery_level_percent <= 90; + bool discharge_forbidden_hard = battery_level_percent <= 25; + int target_charging_rate = ( max_battery_level == 0 || !discharge_forbidden_soft ) ? 0 : + ( 9 * max_battery_level - 10 * cur_battery_level ) / ( 6 * 3 ); + // ( max_battery_level * 0.9 - cur_battery_level ) * (1000 / (60 * 30)) // originally + // ^ 90% bat to W ^ ^ 30 minutes + + int accel_demand = cruise_on + ? // using avg_velocity reduces unnecessary oscillations when traction is low + std::max( std::abs( cruise_velocity - velocity ), std::abs( cruise_velocity - avg_velocity ) ) : + ( thrusting ? 1000 : 0 ); + if( velocity != 0 && accel_demand == 0 ) { + accel_demand = 1; // to prevent zero fuel usage + } + + int velocity_demand = std::max( std::abs( this->velocity ), std::abs( cruise_velocity ) ); + + // for stationary vehicles all velocity and acceleration calculations are skipped + bool is_stationary = avg_velocity == 0 && velocity_demand == 0 && accel_demand == 0; + + bool gas_engine_shutdown_forbidden = smart_controller_state && + ( calendar::turn - smart_controller_state->gas_engine_last_turned_on ) < + 15_seconds; + + + smart_controller_cache cur_state; + + float traction = is_stationary ? 1.0f : + ( k_traction_cache ? *k_traction_cache : k_traction( get_map().vehicle_wheel_traction( *this ) ) ); + + int prev_mask = 0; + // opt_ prefix denotes values for currently found "optimal" engine configuration + int opt_net_echarge_rate = net_battery_charge_rate_w(); + // total engine fuel energy usage (J) + int opt_fuel_usage = 0; + + int opt_accel = is_stationary ? 1 : current_acceleration() * traction; + int opt_safe_vel = is_stationary ? 1 : safe_ground_velocity( true ); + float cur_load_approx = static_cast( std::min( accel_demand, + opt_accel ) ) / std::max( opt_accel, 1 ); + float cur_load_alternator = std::min( 0.01f, static_cast( alternator_load ) / 1000 ); + + for( size_t i = 0; i < c_engines.size(); ++i ) { + if( is_engine_on( c_engines[i] ) ) { + prev_mask |= 1 << i; + bool is_electric = is_engine_type( c_engines[i], fuel_type_battery ); + int fu = engine_fuel_usage( c_engines[i] ) * ( cur_load_approx + ( is_electric ? 0 : + cur_load_alternator ) ); + opt_fuel_usage += fu; + if( is_electric ) { + opt_net_echarge_rate -= fu; + } + } + } + cur_state.created = calendar::turn; + cur_state.battery_percent = battery_level_percent; + cur_state.battery_net_charge_rate = opt_net_echarge_rate; + cur_state.velocity = avg_velocity; + cur_state.load = cur_load_approx + cur_load_alternator; + if( smart_controller_state ) { + cur_state.gas_engine_last_turned_on = smart_controller_state->gas_engine_last_turned_on; + } + cur_state.gas_engine_shutdown_forbidden = gas_engine_shutdown_forbidden; + + int opt_mask = prev_mask; // save current engine state, because it will be temporarily modified + + // if vehicle state has not change, skip actual optimization + if( smart_controller_state && + std::abs( smart_controller_state->velocity - cur_state.velocity ) < 100 && + std::abs( smart_controller_state->battery_percent - cur_state.battery_percent ) <= 2 && + std::abs( smart_controller_state->load - cur_state.load ) < 0.1 && // load diff < 10% + smart_controller_state->battery_net_charge_rate == cur_state.battery_net_charge_rate && + // reevaluate cache if when cache was created, gas engine shutdown was forbidden, but now it's not + !( smart_controller_state->gas_engine_shutdown_forbidden && !gas_engine_shutdown_forbidden ) + ) { + smart_controller_state->created = calendar::turn; + return; + } + + // trying all combinations of engine state (max 31 iterations for 5 engines) + for( int mask = 1; mask < static_cast( 1 << c_engines.size() ); ++mask ) { + if( mask == prev_mask ) { + continue; + } + + bool gas_engine_to_shut_down = false; + for( size_t i = 0; i < c_engines.size(); ++i ) { + bool old_state = ( prev_mask & ( 1 << i ) ) != 0; + bool new_state = ( mask & ( 1 << i ) ) != 0; + // switching enabled flag temporarily to perform calculations below + toggle_specific_engine( c_engines[i], new_state ); + + if( old_state && !new_state && !is_engine_type( c_engines[i], fuel_type_battery ) ) { + gas_engine_to_shut_down = true; + } + } + + if( gas_engine_to_shut_down && gas_engine_shutdown_forbidden ) { + continue; // skip checking this state + } + + int safe_vel = is_stationary ? 1 : safe_ground_velocity( true ); + int accel = is_stationary ? 1 : current_acceleration() * traction; + int fuel_usage = 0; + int net_echarge_rate = net_battery_charge_rate_w(); + float load_approx = static_cast( std::min( accel_demand, accel ) ) / std::max( accel, 1 ); + update_alternator_load(); + float load_approx_alternator = std::min( 0.01f, static_cast( alternator_load ) / 1000 ); + + for( int e : c_engines ) { + bool is_electric = is_engine_type( e, fuel_type_battery ); + int fu = engine_fuel_usage( e ) * ( load_approx + ( is_electric ? 0 : load_approx_alternator ) ); + fuel_usage += fu; + if( is_electric ) { + net_echarge_rate -= fu; + } + } + + if( std::forward_as_tuple( + !discharge_forbidden_hard || ( net_echarge_rate > 0 ), + accel >= accel_demand, + opt_accel < accel_demand ? accel : 0, // opt_accel usage here is intentional + safe_vel >= velocity_demand, + opt_safe_vel < velocity_demand ? -safe_vel : 0, //opt_safe_vel usage here is intentional + !discharge_forbidden_soft || ( net_echarge_rate > target_charging_rate ), + -fuel_usage, + net_echarge_rate + ) >= std::forward_as_tuple( + !discharge_forbidden_hard || ( opt_net_echarge_rate > 0 ), + opt_accel >= accel_demand, + opt_accel < accel_demand ? opt_accel : 0, + opt_safe_vel >= velocity_demand, + opt_safe_vel < velocity_demand ? -opt_safe_vel : 0, + !discharge_forbidden_soft || ( opt_net_echarge_rate > target_charging_rate ), + -opt_fuel_usage, + opt_net_echarge_rate + ) ) { + opt_mask = mask; + opt_fuel_usage = fuel_usage; + opt_net_echarge_rate = net_echarge_rate; + opt_accel = accel; + opt_safe_vel = safe_vel; + + cur_state.battery_net_charge_rate = net_echarge_rate; + cur_state.load = load_approx + load_approx_alternator; + // other `cur_state` fields do not change for different engine state combinations + } + } + + for( size_t i = 0; i < c_engines.size(); ++i ) { // return to prev state + toggle_specific_engine( c_engines[i], static_cast( prev_mask & ( 1 << i ) ) ); + } + + if( opt_mask != prev_mask ) { // we found new configuration + bool failed_to_start = false; + bool turned_on_gas_engine = false; + for( size_t i = 0; i < c_engines.size(); ++i ) { + // ..0.. < ..1.. was off, new state on + if( ( prev_mask & ( 1 << i ) ) < ( opt_mask & ( 1 << i ) ) ) { + if( !start_engine( c_engines[i], true ) ) { + failed_to_start = true; + } + turned_on_gas_engine |= !is_engine_type( c_engines[i], fuel_type_battery ); + } + } + if( failed_to_start ) { + this->smart_controller_state = cata::nullopt; + + for( size_t i = 0; i < c_engines.size(); ++i ) { // return to prev state + toggle_specific_engine( c_engines[i], static_cast( prev_mask & ( 1 << i ) ) ); + } + for( const vpart_reference &vp : get_avail_parts( "SMART_ENGINE_CONTROLLER" ) ) { + vp.part().enabled = false; + } + if( player_in_control( g->u ) ) { + add_msg( m_bad, _( "Smart controller failed to start an engine." ) ); + add_msg( m_bad, _( "Smart controller is shutting down." ) ); + } + has_enabled_smart_controller = false; + + } else { //successfully changed engines state + for( size_t i = 0; i < c_engines.size(); ++i ) { + // was on, needs to be off + if( ( prev_mask & ( 1 << i ) ) > ( opt_mask & ( 1 << i ) ) ) { + start_engine( c_engines[i], false ); + } + } + if( turned_on_gas_engine ) { + cur_state.gas_engine_last_turned_on = calendar::turn; + } + smart_controller_state = cur_state; + + if( player_in_control( g->u ) ) { + add_msg( m_debug, _( "Smart controller optimizes engine state." ) ); + } + } + } else { + // as the optimization was performed (even without state change), cache needs to be updated as well + smart_controller_state = cur_state; + } + update_alternator_load(); +} + void vehicle::thrust( int thd, int z ) { //if vehicle is stopped, set target direction to forward. @@ -124,7 +382,7 @@ void vehicle::thrust( int thd, int z ) turn_dir = face.dir(); stop(); } - bool pl_ctrl = player_in_control( g->u ); + bool pl_ctrl = player_in_control( get_player_character() ); // No need to change velocity if there are no wheels if( ( in_water && can_float() ) || ( is_rotorcraft() && ( z != 0 || is_flying ) ) ) { @@ -150,7 +408,12 @@ void vehicle::thrust( int thd, int z ) } // TODO: Pass this as an argument to avoid recalculating - float traction = k_traction( g->m.vehicle_wheel_traction( *this ) ); + float traction = k_traction( get_map().vehicle_wheel_traction( *this ) ); + + if( thrusting ) { + smart_controller_handle_turn( true, traction ); + } + int accel = current_acceleration() * traction; if( accel < 200 && velocity > 0 && is_towing() ) { if( pl_ctrl ) { @@ -358,8 +621,9 @@ void vehicle::stop( bool update_cache ) if( !update_cache ) { return; } + map &here = get_map(); for( const tripoint &p : get_points() ) { - g->m.set_memory_seen_cache_dirty( p ); + here.set_memory_seen_cache_dirty( p ); } } @@ -407,6 +671,7 @@ bool vehicle::collision( std::vector &colls, int lowest_velocity = coll_velocity; const int sign_before = sgn( velocity_before ); bool empty = true; + map &here = get_map(); for( int p = 0; static_cast( p ) < parts.size(); p++ ) { const vpart_info &info = part_info( p ); if( ( info.location != part_location_structure && info.rotor_diameter() == 0 ) || @@ -420,7 +685,7 @@ bool vehicle::collision( std::vector &colls, veh_collision coll = part_collision( p, dsp, just_detect, bash_floor ); if( coll.type == veh_coll_nothing && info.rotor_diameter() > 0 ) { size_t radius = static_cast( std::round( info.rotor_diameter() / 2.0f ) ); - for( const tripoint &rotor_point : g->m.points_in_radius( dsp, radius ) ) { + for( const tripoint &rotor_point : here.points_in_radius( dsp, radius ) ) { veh_collision rotor_coll = part_collision( p, rotor_point, just_detect, false ); if( rotor_coll.type != veh_coll_nothing ) { coll = rotor_coll; @@ -485,9 +750,10 @@ static void terrain_collision_data( const tripoint &p, bool bash_floor, float &mass, float &density, float &elastic ) { elastic = 0.30; + map &here = get_map(); // Just a rough rescale for now to obtain approximately equal numbers - const int bash_min = g->m.bash_resistance( p, bash_floor ); - const int bash_max = g->m.bash_strength( p, bash_floor ); + const int bash_min = here.bash_resistance( p, bash_floor ); + const int bash_max = here.bash_strength( p, bash_floor ); mass = ( bash_min + bash_max ) / 2.0; density = bash_min; } @@ -498,11 +764,12 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Vertical collisions need to be handled differently // All collisions have to be either fully vertical or fully horizontal for now const bool vert_coll = bash_floor || p.z != sm_pos.z; - const bool pl_ctrl = player_in_control( g->u ); + Character &player_character = get_player_character(); + const bool pl_ctrl = player_in_control( player_character ); Creature *critter = g->critter_at( p, true ); player *ph = dynamic_cast( critter ); - Creature *driver = pl_ctrl ? &g->u : nullptr; + Creature *driver = pl_ctrl ? &player_character : nullptr; // If in a vehicle assume it's this one if( ph != nullptr && ph->in_vehicle ) { @@ -510,7 +777,8 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, ph = nullptr; } - const optional_vpart_position ovp = g->m.veh_at( p ); + map &here = get_map(); + const optional_vpart_position ovp = here.veh_at( p ); // Disable vehicle/critter collisions when bashing floor // TODO: More elegant code const bool is_veh_collision = !bash_floor && ovp && &ovp->vehicle() != this; @@ -547,7 +815,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, return ret; } // we just ran into a fish, so move it out of the way - if( g->m.has_flag( "SWIMMABLE", critter->pos() ) ) { + if( here.has_flag( "SWIMMABLE", critter->pos() ) ) { tripoint end_pos = critter->pos(); tripoint start_pos; const int angle = move.dir() + 45 * ( parts[part].mount.x > pivot_point().x ? -1 : 1 ); @@ -589,31 +857,31 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, part_dens = 15; mass2 = units::to_kilogram( critter->get_weight() ); ret.target_name = critter->disp_name(); - } else if( ( bash_floor && g->m.is_bashable_ter_furn( p, true ) ) || - ( g->m.is_bashable_ter_furn( p, false ) && g->m.move_cost_ter_furn( p ) != 2 && + } else if( ( bash_floor && here.is_bashable_ter_furn( p, true ) ) || + ( here.is_bashable_ter_furn( p, false ) && here.move_cost_ter_furn( p ) != 2 && // Don't collide with tiny things, like flowers, unless we have a wheel in our space. ( part_with_feature( ret.part, VPFLAG_WHEEL, true ) >= 0 || - !g->m.has_flag_ter_or_furn( "TINY", p ) ) && + !here.has_flag_ter_or_furn( "TINY", p ) ) && // Protrusions don't collide with short terrain. // Tiny also doesn't, but it's already excluded unless there's a wheel present. !( part_with_feature( ret.part, "PROTRUSION", true ) >= 0 && - g->m.has_flag_ter_or_furn( "SHORT", p ) ) && + here.has_flag_ter_or_furn( "SHORT", p ) ) && // These are bashable, but don't interact with vehicles. - !g->m.has_flag_ter_or_furn( "NOCOLLIDE", p ) && + !here.has_flag_ter_or_furn( "NOCOLLIDE", p ) && // Do not collide with track tiles if we can use rails - !( g->m.has_flag_ter_or_furn( TFLAG_RAIL, p ) && this->can_use_rails() ) ) ) { + !( here.has_flag_ter_or_furn( TFLAG_RAIL, p ) && this->can_use_rails() ) ) ) { // Movecost 2 indicates flat terrain like a floor, no collision there. ret.type = veh_coll_bashable; terrain_collision_data( p, bash_floor, mass2, part_dens, e ); - ret.target_name = g->m.disp_name( p ); - } else if( g->m.impassable_ter_furn( p ) || - ( bash_floor && !g->m.has_flag( TFLAG_NO_FLOOR, p ) ) ) { + ret.target_name = here.disp_name( p ); + } else if( here.impassable_ter_furn( p ) || + ( bash_floor && !here.has_flag( TFLAG_NO_FLOOR, p ) ) ) { // not destructible ret.type = veh_coll_other; mass2 = 1000; e = 0.10; part_dens = 80; - ret.target_name = g->m.disp_name( p ); + ret.target_name = here.disp_name( p ); } if( ret.type == veh_coll_nothing || just_detect ) { @@ -713,23 +981,23 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Something bashable -- use map::bash to determine outcome // NOTE: Floor bashing disabled for balance reasons // Floor values are still used to set damage dealt to vehicle - smashed = g->m.is_bashable_ter_furn( p, false ) && - g->m.bash_resistance( p, bash_floor ) <= obj_dmg && - g->m.bash( p, obj_dmg, false, false, false, this ).success; + smashed = here.is_bashable_ter_furn( p, false ) && + here.bash_resistance( p, bash_floor ) <= obj_dmg && + here.bash( p, obj_dmg, false, false, false, this ).success; if( smashed ) { - if( g->m.is_bashable_ter_furn( p, bash_floor ) ) { + if( here.is_bashable_ter_furn( p, bash_floor ) ) { // There's new terrain there to smash smashed = false; terrain_collision_data( p, bash_floor, mass2, part_dens, e ); - ret.target_name = g->m.disp_name( p ); - } else if( g->m.impassable_ter_furn( p ) ) { + ret.target_name = here.disp_name( p ); + } else if( here.impassable_ter_furn( p ) ) { // There's new terrain there, but we can't smash it! smashed = false; ret.type = veh_coll_other; mass2 = 1000; e = 0.10; part_dens = 80; - ret.target_name = g->m.disp_name( p ); + ret.target_name = here.disp_name( p ); } } } else if( ret.type == veh_coll_body ) { @@ -870,10 +1138,10 @@ void vehicle::handle_trap( const tripoint &p, int part ) if( pwh < 0 ) { return; } - const trap &tr = g->m.tr_at( p ); - const trap_id t = tr.loadid; + map &here = get_map(); + const trap &tr = here.tr_at( p ); - if( t == tr_null ) { + if( tr.is_null() ) { // If the trap doesn't exist, we can't interact with it, so just return return; } @@ -883,8 +1151,9 @@ void vehicle::handle_trap( const tripoint &p, int part ) return; } - const bool seen = g->u.sees( p ); - const bool known = g->u.knows_trap( p ); + Character &player_character = get_player_character(); + const bool seen = player_character.sees( p ); + const bool known = tr.can_see( p, player_character ); if( seen ) { if( known ) { //~ %1$s: name of the vehicle; %2$s: name of the related vehicle part; %3$s: trap name @@ -907,28 +1176,28 @@ void vehicle::handle_trap( const tripoint &p, int part ) } bool still_has_trap = true; if( veh_data.remove_trap || veh_data.do_explosion ) { - g->m.remove_trap( p ); + here.remove_trap( p ); still_has_trap = false; } for( const auto &it : veh_data.spawn_items ) { int cnt = roll_remainder( it.second ); if( cnt > 0 ) { - g->m.spawn_item( p, it.first, cnt ); + here.spawn_item( p, it.first, cnt ); } } if( veh_data.set_trap ) { - g->m.trap_set( p, veh_data.set_trap.id() ); + here.trap_set( p, veh_data.set_trap.id() ); still_has_trap = true; } if( still_has_trap ) { - const trap &tr = g->m.tr_at( p ); + const trap &tr = here.tr_at( p ); if( seen || known ) { // known status has been reset by map::trap_set() - g->u.add_known_trap( p, tr ); + player_character.add_known_trap( p, tr ); } if( seen && !known ) { // hard to miss! - const std::string direction = direction_name( direction_from( g->u.pos(), p ) ); + const std::string direction = direction_name( direction_from( player_character.pos(), p ) ); add_msg( _( "You've spotted a %1$s to the %2$s!" ), tr.name(), direction ); } } @@ -1005,14 +1274,14 @@ bool vehicle::check_is_heli_landed() { // @TODO - when there are chasms that extend below z-level 0 - perhaps the heli // will be able to descend into them but for now, assume z-level-0 == the ground. - if( global_pos3().z == 0 || !g->m.has_flag_ter_or_furn( TFLAG_NO_FLOOR, global_pos3() ) ) { + if( global_pos3().z == 0 || !get_map().has_flag_ter_or_furn( TFLAG_NO_FLOOR, global_pos3() ) ) { is_flying = false; return true; } return false; } -bool vehicle::check_heli_descend( player &p ) +bool vehicle::check_heli_descend( Character &p ) { if( !is_rotorcraft() ) { debugmsg( "A vehicle is somehow flying without being an aircraft" ); @@ -1020,20 +1289,21 @@ bool vehicle::check_heli_descend( player &p ) } int count = 0; int air_count = 0; + map &here = get_map(); for( const tripoint &pt : get_points( true ) ) { tripoint below( pt.xy(), pt.z - 1 ); - if( g->m.has_zlevels() && ( pt.z < -OVERMAP_DEPTH || - !g->m.has_flag_ter_or_furn( TFLAG_NO_FLOOR, pt ) ) ) { + if( here.has_zlevels() && ( pt.z < -OVERMAP_DEPTH || + !here.has_flag_ter_or_furn( TFLAG_NO_FLOOR, pt ) ) ) { p.add_msg_if_player( _( "You are already landed!" ) ); return false; } - const optional_vpart_position ovp = g->m.veh_at( below ); - if( g->m.impassable_ter_furn( below ) || ovp || g->critter_at( below ) ) { + const optional_vpart_position ovp = here.veh_at( below ); + if( here.impassable_ter_furn( below ) || ovp || g->critter_at( below ) ) { p.add_msg_if_player( m_bad, _( "It would be unsafe to try and land when there are obstacles below you." ) ); return false; } - if( g->m.has_flag_ter_or_furn( TFLAG_NO_FLOOR, below ) ) { + if( here.has_flag_ter_or_furn( TFLAG_NO_FLOOR, below ) ) { air_count++; } count++; @@ -1046,7 +1316,7 @@ bool vehicle::check_heli_descend( player &p ) } -bool vehicle::check_heli_ascend( player &p ) +bool vehicle::check_heli_ascend( Character &p ) { if( !is_rotorcraft() ) { debugmsg( "A vehicle is somehow flying without being an aircraft" ); @@ -1056,10 +1326,11 @@ bool vehicle::check_heli_ascend( player &p ) p.add_msg_if_player( m_bad, _( "It would be unsafe to try and take off while you are moving." ) ); return false; } + map &here = get_map(); for( const tripoint &pt : get_points( true ) ) { tripoint above( pt.xy(), pt.z + 1 ); - const optional_vpart_position ovp = g->m.veh_at( above ); - if( g->m.has_flag_ter_or_furn( TFLAG_INDOORS, pt ) || g->m.impassable_ter_furn( above ) || ovp || + const optional_vpart_position ovp = here.veh_at( above ); + if( here.has_flag_ter_or_furn( TFLAG_INDOORS, pt ) || here.impassable_ter_furn( above ) || ovp || g->critter_at( above ) ) { p.add_msg_if_player( m_bad, _( "It would be unsafe to try and ascend when there are obstacles above you." ) ); @@ -1071,9 +1342,9 @@ bool vehicle::check_heli_ascend( player &p ) void vehicle::pldrive( const point &p, int z ) { - player &u = g->u; + player &player_character = get_avatar(); if( z != 0 && is_rotorcraft() ) { - u.moves = std::min( u.moves, 0 ); + player_character.moves = std::min( player_character.moves, 0 ); thrust( 0, z ); } int turn_delta = 15 * p.x; @@ -1097,15 +1368,15 @@ void vehicle::pldrive( const point &p, int z ) // If you've got more moves than speed, it's most likely time stop // Let's get rid of that - u.moves = std::min( u.moves, u.get_speed() ); + player_character.moves = std::min( player_character.moves, player_character.get_speed() ); ///\EFFECT_DEX reduces chance of losing control of vehicle when turning ///\EFFECT_PER reduces chance of losing control of vehicle when turning ///\EFFECT_DRIVING reduces chance of losing control of vehicle when turning - float skill = std::min( 10.0f, - u.get_skill_level( skill_driving ) + ( u.get_dex() + u.get_per() ) / 10.0f ); + float skill = std::min( 10.0f, player_character.get_skill_level( skill_driving ) + + ( player_character.get_dex() + player_character.get_per() ) / 10.0f ); float penalty = rng_float( 0.0f, handling_diff ) - skill; int cost; if( penalty > 0.0f ) { @@ -1113,7 +1384,7 @@ void vehicle::pldrive( const point &p, int z ) cost = 100 * ( 1.0f + penalty / 2.5f ); } else { // At 10 skill, with a perfect vehicle, we could turn up to 3 times per turn - cost = std::max( u.get_speed(), 100 ) * ( 1.0f - ( -penalty / 10.0f ) * 2 / 3 ); + cost = std::max( player_character.get_speed(), 100 ) * ( 1.0f - ( -penalty / 10.0f ) * 2 / 3 ); } if( penalty > skill || cost > 400 ) { @@ -1121,12 +1392,12 @@ void vehicle::pldrive( const point &p, int z ) // Anything from a wasted attempt to 2 turns in the intended direction turn_delta *= rng( 0, 2 ); // Also wastes next turn - cost = std::max( cost, u.moves + 100 ); + cost = std::max( cost, player_character.moves + 100 ); } else if( one_in( 10 ) ) { // Don't warn all the time or it gets spammy - if( cost >= u.get_speed() * 2 ) { + if( cost >= player_character.get_speed() * 2 ) { add_msg( m_warning, _( "It takes you a very long time to steer that vehicle!" ) ); - } else if( cost >= u.get_speed() * 1.5f ) { + } else if( cost >= player_character.get_speed() * 1.5f ) { add_msg( m_warning, _( "It takes you a long time to steer that vehicle!" ) ); } } @@ -1134,7 +1405,7 @@ void vehicle::pldrive( const point &p, int z ) turn( turn_delta ); // At most 3 turns per turn, because otherwise it looks really weird and jumpy - u.moves -= std::max( cost, u.get_speed() / 3 + 1 ); + player_character.moves -= std::max( cost, player_character.get_speed() / 3 + 1 ); } if( p.y != 0 ) { @@ -1143,7 +1414,7 @@ void vehicle::pldrive( const point &p, int z ) cruise_thrust( -p.y * thr_amount ); } else { thrust( -p.y ); - u.moves = std::min( u.moves, 0 ); + player_character.moves = std::min( player_character.moves, 0 ); } } @@ -1153,9 +1424,10 @@ void vehicle::pldrive( const point &p, int z ) ///\EFFECT_DEX increases chance of regaining control of a vehicle ///\EFFECT_DRIVING increases chance of regaining control of a vehicle - if( handling_diff * rng( 1, 10 ) < u.dex_cur + u.get_skill_level( skill_driving ) * 2 ) { + if( handling_diff * rng( 1, 10 ) < + player_character.dex_cur + player_character.get_skill_level( skill_driving ) * 2 ) { add_msg( _( "You regain control of the %s." ), name ); - u.practice( skill_driving, velocity / 5 ); + player_character.practice( skill_driving, velocity / 5 ); velocity = static_cast( forward_velocity() ); skidding = false; move.init( turn_dir ); @@ -1274,10 +1546,11 @@ void vehicle::precalculate_vehicle_turning( int new_turn_dir, bool check_rail_di */ turning_wheels_that_are_one_axis = 0; + map &here = get_map(); for( int part_index : wheelcache ) { const auto &wheel = parts[ part_index ]; bool rails_ahead = true; - point wheel_point; + tripoint wheel_point; coord_translate( mdir.dir(), this->pivot_point(), wheel.mount, wheel_point ); @@ -1294,7 +1567,7 @@ void vehicle::precalculate_vehicle_turning( int new_turn_dir, bool check_rail_di // advance precalculated wheel position 1 time in direction of moving wheel_tripoint += dp; - if( !g->m.has_flag_ter_or_furn( ter_flag_to_check, wheel_tripoint ) ) { + if( !here.has_flag_ter_or_furn( ter_flag_to_check, wheel_tripoint ) ) { // this tile is not allowed, disallow turn rails_ahead = false; break; @@ -1302,7 +1575,7 @@ void vehicle::precalculate_vehicle_turning( int new_turn_dir, bool check_rail_di // special case for rails if( check_rail_direction ) { - ter_id terrain_at_wheel = g->m.ter( wheel_tripoint ); + ter_id terrain_at_wheel = here.ter( wheel_tripoint ); // check is it correct tile to turn into if( !is_diagonal_movement && ( terrain_at_wheel == t_railroad_track_d || terrain_at_wheel == t_railroad_track_d1 || @@ -1425,7 +1698,8 @@ bool vehicle::is_wheel_state_correct_to_turn_on_rails( int wheels_on_rail, int w vehicle *vehicle::act_on_map() { const tripoint pt = global_pos3(); - if( !g->m.inbounds( pt ) ) { + map &here = get_map(); + if( !here.inbounds( pt ) ) { dbg( D_INFO ) << "stopping out-of-map vehicle. (x,y,z)=(" << pt.x << "," << pt.y << "," << pt.z << ")"; stop( false ); @@ -1436,7 +1710,8 @@ vehicle *vehicle::act_on_map() if( decrement_summon_timer() ) { return nullptr; } - const bool pl_ctrl = player_in_control( g->u ); + Character &player_character = get_player_character(); + const bool pl_ctrl = player_in_control( player_character ); // TODO: Remove this hack, have vehicle sink a z-level if( is_floating && !can_float() ) { add_msg( m_bad, _( "Your %s sank." ), name ); @@ -1447,9 +1722,9 @@ vehicle *vehicle::act_on_map() g->setremoteveh( nullptr ); } - g->m.on_vehicle_moved( sm_pos.z ); + here.on_vehicle_moved( sm_pos.z ); // Destroy vehicle (sank to nowhere) - g->m.destroy_vehicle( this ); + here.destroy_vehicle( this ); return nullptr; } @@ -1483,7 +1758,7 @@ vehicle *vehicle::act_on_map() return this; } - const float wheel_traction_area = g->m.vehicle_wheel_traction( *this ); + const float wheel_traction_area = here.vehicle_wheel_traction( *this ); const float traction = k_traction( wheel_traction_area ); if( traction < 0.001f ) { of_turn = 0; @@ -1592,7 +1867,55 @@ vehicle *vehicle::act_on_map() } } - return g->m.move_vehicle( *this, dp, mdir ); + return here.move_vehicle( *this, dp, mdir ); +} + +bool vehicle::level_vehicle() +{ + map &here = get_map(); + if( !here.has_zlevels() || ( is_flying && is_rotorcraft() ) ) { + return true; + } + // make sure that all parts are either supported across levels or on the same level + std::map no_support; + for( vehicle_part &prt : parts ) { + if( prt.info().location != part_location_structure ) { + continue; + } + const tripoint part_pos = global_part_pos3( prt ); + if( no_support.find( part_pos.z ) == no_support.end() ) { + no_support[part_pos.z] = part_pos.z > -OVERMAP_DEPTH; + } + if( no_support[part_pos.z] ) { + no_support[part_pos.z] = here.has_flag_ter_or_furn( TFLAG_NO_FLOOR, part_pos ) && + !here.supports_above( part_pos + tripoint_below ); + } + } + std::set dropped_parts; + // if it's unsupported but on the same level, just let it fall + bool center_drop = false; + bool adjust_level = false; + if( no_support.size() > 1 ) { + for( int zlevel = -OVERMAP_DEPTH; zlevel <= OVERMAP_DEPTH; zlevel++ ) { + if( no_support.find( zlevel ) == no_support.end() || !no_support[zlevel] ) { + continue; + } + center_drop |= global_pos3().z == zlevel; + adjust_level = true; + // drop unsupported parts 1 zlevel + for( size_t prt = 0; prt < parts.size(); prt++ ) { + if( global_part_pos3( prt ).z == zlevel ) { + dropped_parts.insert( static_cast( prt ) ); + } + } + } + } + if( adjust_level ) { + here.displace_vehicle( *this, tripoint_below, center_drop, dropped_parts ); + return false; + } else { + return true; + } } void vehicle::check_falling_or_floating() @@ -1609,23 +1932,25 @@ void vehicle::check_falling_or_floating() return; } - is_falling = g->m.has_zlevels(); + map &here = get_map(); + is_falling = here.has_zlevels(); if( is_flying && is_rotorcraft() ) { is_falling = false; } else { is_flying = false; } + size_t deep_water_tiles = 0; size_t water_tiles = 0; for( const tripoint &p : pts ) { if( is_falling ) { tripoint below( p.xy(), p.z - 1 ); - is_falling &= g->m.has_flag_ter_or_furn( TFLAG_NO_FLOOR, p ) && ( p.z > -OVERMAP_DEPTH ) && - !g->m.supports_above( below ); + is_falling &= here.has_flag_ter_or_furn( TFLAG_NO_FLOOR, p ) && + ( p.z > -OVERMAP_DEPTH ) && !here.supports_above( below ); } - deep_water_tiles += g->m.has_flag( TFLAG_DEEP_WATER, p ) ? 1 : 0; - water_tiles += g->m.has_flag( TFLAG_SWIMMABLE, p ) ? 1 : 0; + deep_water_tiles += here.has_flag( TFLAG_DEEP_WATER, p ) ? 1 : 0; + water_tiles += here.has_flag( TFLAG_SWIMMABLE, p ) ? 1 : 0; } // floating if 2/3rds of the vehicle is in deep water is_floating = 3 * deep_water_tiles >= 2 * pts.size(); @@ -1779,7 +2104,7 @@ int map::shake_vehicle( vehicle &veh, const int velocity_before, const int direc _( " is hurled from the %s's seat by " "the power of the impact!" ), veh.name ); unboard_vehicle( part_pos ); - } else if( g->u.sees( part_pos ) ) { + } else if( get_player_character().sees( part_pos ) ) { add_msg( m_bad, _( "The %s is hurled from %s's by the power of the impact!" ), pet->disp_name(), veh.name ); } diff --git a/src/vehicle_part.cpp b/src/vehicle_part.cpp index 3cf10e0e41350..ba14b1db9f965 100644 --- a/src/vehicle_part.cpp +++ b/src/vehicle_part.cpp @@ -6,7 +6,7 @@ #include #include -#include "avatar.h" +#include "character.h" #include "color.h" #include "debug.h" #include "enums.h" @@ -233,7 +233,6 @@ int vehicle_part::ammo_remaining() const if( is_tank() ) { return base.contents.empty() ? 0 : base.contents.legacy_front().charges; } - if( is_fuel_store( false ) || is_turret() ) { return base.ammo_remaining(); } @@ -580,7 +579,7 @@ bool vehicle::can_enable( const vehicle_part &pt, bool alert ) const return false; } - if( pt.info().has_flag( "PLANTER" ) && !warm_enough_to_plant( g->u.pos() ) ) { + if( pt.info().has_flag( "PLANTER" ) && !warm_enough_to_plant( get_player_character().pos() ) ) { if( alert ) { add_msg( m_bad, _( "It is too cold to plant anything now." ) ); } diff --git a/src/vehicle_selector.cpp b/src/vehicle_selector.cpp index a1dcc3b14701c..4c6ff142c67e6 100644 --- a/src/vehicle_selector.cpp +++ b/src/vehicle_selector.cpp @@ -12,7 +12,7 @@ vehicle_selector::vehicle_selector( const tripoint &pos, int radius, bool access bool visibility_only ) { map &here = get_map(); - for( const tripoint &e : closest_tripoints_first( pos, radius ) ) { + for( const tripoint &e : closest_points_first( pos, radius ) ) { if( !accessible || ( visibility_only ? here.sees( pos, e, radius ) : here.clear_path( pos, e, radius, 1, 100 ) ) ) { if( const optional_vpart_position vp = here.veh_at( e ) ) { @@ -26,7 +26,7 @@ vehicle_selector::vehicle_selector( const tripoint &pos, int radius, bool access const vehicle &ignore ) { map &here = get_map(); - for( const tripoint &e : closest_tripoints_first( pos, radius ) ) { + for( const tripoint &e : closest_points_first( pos, radius ) ) { if( !accessible || here.clear_path( pos, e, radius, 1, 100 ) ) { if( const optional_vpart_position vp = here.veh_at( e ) ) { if( &vp->vehicle() != &ignore ) { diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index 01ac30d7147c0..18d261cc04d49 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -284,6 +284,8 @@ void vehicle::set_electronics_menu_options( std::vector &options, keybind( "TOGGLE_SCOOP" ), "SCOOP" ); add_toggle( pgettext( "electronics menu option", "water purifier" ), keybind( "TOGGLE_WATER_PURIFIER" ), "WATER_PURIFIER" ); + add_toggle( pgettext( "electronics menu option", "smart controller" ), + keybind( "TOGGLE_SMART_ENGINE_CONTROLLER" ), "SMART_ENGINE_CONTROLLER" ); if( has_part( "DOOR_MOTOR" ) ) { options.emplace_back( _( "Toggle doors" ), keybind( "TOGGLE_DOORS" ) ); @@ -400,7 +402,7 @@ void vehicle::control_engines() if( engines_were_on && !engine_on ) { add_msg( _( "You turn off the %s's engines to change their configurations." ), name ); - } else if( !g->u.controlling_vehicle ) { + } else if( !get_player_character().controlling_vehicle ) { add_msg( _( "You change the %s's engine configuration." ), name ); return; } @@ -437,15 +439,16 @@ bool vehicle::interact_vehicle_locked() return true; } + Character &player_character = get_player_character(); add_msg( _( "You don't find any keys in the %s." ), name ); - const inventory &inv = g->u.crafting_inventory(); + const inventory &inv = player_character.crafting_inventory(); if( inv.has_quality( quality_id( "SCREW" ) ) ) { if( query_yn( _( "You don't find any keys in the %s. Attempt to hotwire vehicle?" ), name ) ) { ///\EFFECT_MECHANICS speeds up vehicle hotwiring - int skill = g->u.get_skill_level( skill_mechanics ); + int skill = player_character.get_skill_level( skill_mechanics ); const int moves = to_moves( 6000_seconds / ( ( skill > 0 ) ? skill : 1 ) ); - tripoint target = g->m.getabs( global_pos3() ) + coord_translate( parts[0].mount ); - g->u.assign_activity( hotwire_car_activity_actor( moves, target ) ); + tripoint target = get_map().getabs( global_pos3() ) + coord_translate( parts[0].mount ); + player_character.assign_activity( hotwire_car_activity_actor( moves, target ) ); } else if( has_security_working() && query_yn( _( "Trigger the %s's Alarm?" ), name ) ) { is_alarm_on = true; } else { @@ -471,10 +474,11 @@ void vehicle::smash_security_system() break; } } + Character &player_character = get_player_character(); //controls and security must both be valid if( c >= 0 && s >= 0 ) { ///\EFFECT_MECHANICS reduces chance of damaging controls when smashing security system - int skill = g->u.get_skill_level( skill_mechanics ); + int skill = player_character.get_skill_level( skill_mechanics ); int percent_controls = 70 / ( 1 + skill ); int percent_alarm = ( skill + 3 ) * 10; int rand = rng( 1, 100 ); @@ -483,7 +487,7 @@ void vehicle::smash_security_system() damage_direct( c, part_info( c ).durability / 4 ); if( parts[ c ].removed || parts[ c ].is_broken() ) { - g->u.controlling_vehicle = false; + player_character.controlling_vehicle = false; is_alarm_on = false; add_msg( _( "You destroy the controls…" ) ); } else { @@ -511,7 +515,7 @@ std::string vehicle::tracking_toggle_string() void vehicle::autopilot_patrol_check() { zone_manager &mgr = zone_manager::get_manager(); - if( mgr.has_near( zone_type_id( "VEHICLE_PATROL" ), g->m.getabs( global_pos3() ), 60 ) ) { + if( mgr.has_near( zone_type_id( "VEHICLE_PATROL" ), get_map().getabs( global_pos3() ), 60 ) ) { enable_patrol(); } else { g->zones_manager(); @@ -581,11 +585,12 @@ void vehicle::use_controls( const tripoint &pos ) bool remote = g->remoteveh() == this; bool has_electronic_controls = false; + avatar &player_character = get_avatar(); if( remote ) { options.emplace_back( _( "Stop controlling" ), keybind( "RELEASE_CONTROLS" ) ); actions.push_back( [&] { - g->u.controlling_vehicle = false; + player_character.controlling_vehicle = false; g->setremoteveh( nullptr ); add_msg( _( "You stop controlling the vehicle." ) ); refresh(); @@ -593,11 +598,11 @@ void vehicle::use_controls( const tripoint &pos ) has_electronic_controls = has_part( "CTRL_ELECTRONIC" ) || has_part( "REMOTE_CONTROLS" ); - } else if( veh_pointer_or_null( g->m.veh_at( pos ) ) == this ) { - if( g->u.controlling_vehicle ) { + } else if( veh_pointer_or_null( get_map().veh_at( pos ) ) == this ) { + if( player_character.controlling_vehicle ) { options.emplace_back( _( "Let go of controls" ), keybind( "RELEASE_CONTROLS" ) ); actions.push_back( [&] { - g->u.controlling_vehicle = false; + player_character.controlling_vehicle = false; add_msg( _( "You let go of the controls." ) ); refresh(); } ); @@ -617,7 +622,7 @@ void vehicle::use_controls( const tripoint &pos ) } if( has_part( "ENGINE" ) ) { - if( g->u.controlling_vehicle || ( remote && engine_on ) ) { + if( player_character.controlling_vehicle || ( remote && engine_on ) ) { options.emplace_back( _( "Stop driving" ), keybind( "TOGGLE_ENGINE" ) ); actions.push_back( [&] { if( engine_on && has_engine_type_not( fuel_type_muscle, true ) ) @@ -653,7 +658,7 @@ void vehicle::use_controls( const tripoint &pos ) } vehicle_noise = 0; engine_on = false; - g->u.controlling_vehicle = false; + player_character.controlling_vehicle = false; g->setremoteveh( nullptr ); sfx::do_vehicle_engine_sfx(); refresh(); @@ -759,7 +764,7 @@ void vehicle::use_controls( const tripoint &pos ) if( menu.ret >= 0 ) { // allow player to turn off engine without triggering another warning if( menu.ret != 0 && menu.ret != 1 && menu.ret != 2 && menu.ret != 3 ) { - if( !handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( !handle_potential_theft( player_character ) ) { return; } } @@ -778,7 +783,8 @@ bool vehicle::fold_up() return false; } - if( g->u.controlling_vehicle ) { + avatar &player_character = get_avatar(); + if( player_character.controlling_vehicle ) { add_msg( m_warning, _( "As the pitiless metal bars close on your nether regions, you reconsider trying to fold the %s while riding it." ), name ); @@ -792,8 +798,8 @@ bool vehicle::fold_up() add_msg( _( "You painstakingly pack the %s into a portable configuration." ), name ); - if( g->u.get_grab_type() != object_type::NONE ) { - g->u.grab( object_type::NONE ); + if( player_character.get_grab_type() != object_type::NONE ) { + player_character.grab( object_type::NONE ); add_msg( _( "You let go of %s as you fold it." ), name ); } @@ -808,11 +814,12 @@ bool vehicle::fold_up() // create a folding [non]bicycle item item bicycle( can_be_folded ? "generic_folded_vehicle" : "folding_bicycle", calendar::turn ); + map &here = get_map(); // Drop stuff in containers on ground for( const vpart_reference &vp : get_any_parts( "CARGO" ) ) { const size_t p = vp.part_index(); for( auto &elem : get_items( p ) ) { - g->m.add_item_or_charges( g->u.pos(), elem ); + here.add_item_or_charges( player_character.pos(), elem ); } while( !get_items( p ).empty() ) { get_items( p ).erase( get_items( p ).begin() ); @@ -844,12 +851,12 @@ bool vehicle::fold_up() bicycle.set_var( "description", string_format( _( "A folded %s." ), name ) ); } - g->m.add_item_or_charges( global_part_pos3( 0 ), bicycle ); - g->m.destroy_vehicle( this ); + here.add_item_or_charges( global_part_pos3( 0 ), bicycle ); + here.destroy_vehicle( this ); // TODO: take longer to fold bigger vehicles // TODO: make this interruptible - g->u.moves -= 500; + player_character.moves -= 500; return true; } @@ -859,7 +866,7 @@ double vehicle::engine_cold_factor( const int e ) const return 0.0; } - int eff_temp = g->weather.get_temperature( g->u.pos() ); + int eff_temp = g->weather.get_temperature( get_player_character().pos() ); if( !parts[ engines[ e ] ].faults().count( fault_engine_glow_plug ) ) { eff_temp = std::min( eff_temp, 20 ); } @@ -906,13 +913,14 @@ bool vehicle::start_engine( const int e ) out_of_fuel = true; } + Character &player_character = get_player_character(); if( out_of_fuel ) { if( einfo.fuel_type == fuel_type_muscle ) { // Muscle engines cannot start with broken limbs - if( einfo.has_flag( "MUSCLE_ARMS" ) && ( g->u.get_working_arm_count() < 2 ) ) { + if( einfo.has_flag( "MUSCLE_ARMS" ) && ( player_character.get_working_arm_count() < 2 ) ) { add_msg( _( "You cannot use %s with a broken arm." ), eng.name() ); return false; - } else if( einfo.has_flag( "MUSCLE_LEGS" ) && ( g->u.get_working_leg_count() < 2 ) ) { + } else if( einfo.has_flag( "MUSCLE_LEGS" ) && ( player_character.get_working_leg_count() < 2 ) ) { add_msg( _( "You cannot use %s with a broken leg." ), eng.name() ); return false; } @@ -1062,14 +1070,15 @@ void vehicle::start_engines( const bool take_control, const bool autodrive ) return; } - if( take_control && !g->u.controlling_vehicle ) { - g->u.controlling_vehicle = true; + Character &player_character = get_player_character(); + if( take_control && !player_character.controlling_vehicle ) { + player_character.controlling_vehicle = true; add_msg( _( "You take control of the %s." ), name ); } if( !autodrive ) { - g->u.assign_activity( ACT_START_ENGINES, start_time ); - g->u.activity.placement = starting_engine_position - g->u.pos(); - g->u.activity.values.push_back( take_control ); + player_character.assign_activity( ACT_START_ENGINES, start_time ); + player_character.activity.placement = starting_engine_position - player_character.pos(); + player_character.activity.values.push_back( take_control ); } } @@ -1122,9 +1131,8 @@ void vehicle::honk_horn() void vehicle::reload_seeds( const tripoint &pos ) { - player &p = g->u; - - std::vector seed_inv = p.items_with( []( const item & itm ) { + Character &player_character = get_player_character(); + std::vector seed_inv = player_character.items_with( []( const item & itm ) { return itm.is_seed(); } ); @@ -1149,13 +1157,13 @@ void vehicle::reload_seeds( const tripoint &pos ) itype_id seed_id = std::get<0>( seed_entries[seed_index] ); std::list used_seed; if( item::count_by_charges( seed_id ) ) { - used_seed = p.use_charges( seed_id, actual_amount ); + used_seed = player_character.use_charges( seed_id, actual_amount ); } else { - used_seed = p.use_amount( seed_id, actual_amount ); + used_seed = player_character.use_amount( seed_id, actual_amount ); } used_seed.front().set_age( 0_turns ); //place seeds into the planter - put_into_vehicle_or_drop( p, item_drop_reason::deliberate, used_seed, pos ); + put_into_vehicle_or_drop( player_character, item_drop_reason::deliberate, used_seed, pos ); } } } @@ -1182,8 +1190,9 @@ void vehicle::beeper_sound() void vehicle::play_music() { + Character &player_character = get_player_character(); for( const vpart_reference &vp : get_enabled_parts( "STEREO" ) ) { - iuse::play_music( g->u, vp.pos(), 15, 30 ); + iuse::play_music( player_character, vp.pos(), 15, 30 ); } } @@ -1204,29 +1213,30 @@ void vehicle::crash_terrain_around() if( total_power_w() <= 0 ) { return; } + map &here = get_map(); for( const vpart_reference &vp : get_enabled_parts( "CRASH_TERRAIN_AROUND" ) ) { tripoint crush_target( 0, 0, -OVERMAP_LAYERS ); const tripoint start_pos = vp.pos(); const transform_terrain_data &ttd = vp.info().transform_terrain; for( size_t i = 0; i < eight_horizontal_neighbors.size() && - !g->m.inbounds_z( crush_target.z ); i++ ) { + !here.inbounds_z( crush_target.z ); i++ ) { tripoint cur_pos = start_pos + eight_horizontal_neighbors.at( i ); bool busy_pos = false; for( const vpart_reference &vp_tmp : get_all_parts() ) { busy_pos |= vp_tmp.pos() == cur_pos; } for( const std::string &flag : ttd.pre_flags ) { - if( g->m.has_flag( flag, cur_pos ) && !busy_pos ) { + if( here.has_flag( flag, cur_pos ) && !busy_pos ) { crush_target = cur_pos; break; } } } //target chosen - if( g->m.inbounds_z( crush_target.z ) ) { + if( here.inbounds_z( crush_target.z ) ) { velocity = 0; cruise_velocity = 0; - g->m.destroy( crush_target ); + here.destroy( crush_target ); sounds::sound( crush_target, 500, sounds::sound_t::combat, _( "Clanggggg!" ), false, "smash_success", "hit_vehicle" ); } @@ -1235,12 +1245,13 @@ void vehicle::crash_terrain_around() void vehicle::transform_terrain() { + map &here = get_map(); for( const vpart_reference &vp : get_enabled_parts( "TRANSFORM_TERRAIN" ) ) { const tripoint start_pos = vp.pos(); const transform_terrain_data &ttd = vp.info().transform_terrain; bool prereq_fulfilled = false; for( const std::string &flag : ttd.pre_flags ) { - if( g->m.has_flag( flag, start_pos ) ) { + if( here.has_flag( flag, start_pos ) ) { prereq_fulfilled = true; break; } @@ -1248,15 +1259,15 @@ void vehicle::transform_terrain() if( prereq_fulfilled ) { const ter_id new_ter = ter_id( ttd.post_terrain ); if( new_ter != t_null ) { - g->m.ter_set( start_pos, new_ter ); + here.ter_set( start_pos, new_ter ); } const furn_id new_furn = furn_id( ttd.post_furniture ); if( new_furn != f_null ) { - g->m.furn_set( start_pos, new_furn ); + here.furn_set( start_pos, new_furn ); } const field_type_id new_field = field_type_id( ttd.post_field ); if( new_field.id() ) { - g->m.add_field( start_pos, new_field, ttd.post_field_intensity, ttd.post_field_age ); + here.add_field( start_pos, new_field, ttd.post_field_intensity, ttd.post_field_age ); } } else { const int speed = std::abs( velocity ); @@ -1270,17 +1281,18 @@ void vehicle::transform_terrain() void vehicle::operate_reaper() { + map &here = get_map(); for( const vpart_reference &vp : get_enabled_parts( "REAPER" ) ) { const size_t reaper_id = vp.part_index(); const tripoint reaper_pos = vp.pos(); const int plant_produced = rng( 1, vp.info().bonus ); const int seed_produced = rng( 1, 3 ); const units::volume max_pickup_volume = vp.info().size / 20; - if( g->m.furn( reaper_pos ) != f_plant_harvest ) { + if( here.furn( reaper_pos ) != f_plant_harvest ) { continue; } // Can't use item_stack::only_item() since there might be fertilizer - map_stack items = g->m.i_at( reaper_pos ); + map_stack items = here.i_at( reaper_pos ); map_stack::iterator seed = std::find_if( items.begin(), items.end(), []( const item & it ) { return it.is_seed(); } ); @@ -1289,13 +1301,13 @@ void vehicle::operate_reaper() // Otherworldly plants, the earth-made reaper can not handle those. continue; } - g->m.furn_set( reaper_pos, f_null ); + here.furn_set( reaper_pos, f_null ); // Secure the seed type before i_clear destroys the item. const itype &seed_type = *seed->type; - g->m.i_clear( reaper_pos ); + here.i_clear( reaper_pos ); for( auto &i : iexamine::get_harvest_items( seed_type, plant_produced, seed_produced, false ) ) { - g->m.add_item_or_charges( reaper_pos, i ); + here.add_item_or_charges( reaper_pos, i ); } sounds::sound( reaper_pos, rng( 10, 25 ), sounds::sound_t::combat, _( "Swish" ), false, "vehicle", "reaper" ); @@ -1314,6 +1326,7 @@ void vehicle::operate_reaper() void vehicle::operate_planter() { + map &here = get_map(); for( const vpart_reference &vp : get_enabled_parts( "PLANTER" ) ) { const size_t planter_id = vp.part_index(); const tripoint loc = vp.pos(); @@ -1321,12 +1334,12 @@ void vehicle::operate_planter() for( auto i = v.begin(); i != v.end(); i++ ) { if( i->is_seed() ) { // If it is an "advanced model" then it will avoid damaging itself or becoming damaged. It's a real feature. - if( g->m.ter( loc ) != t_dirtmound && vp.has_feature( "ADVANCED_PLANTER" ) ) { + if( here.ter( loc ) != t_dirtmound && vp.has_feature( "ADVANCED_PLANTER" ) ) { //then don't put the item there. break; - } else if( g->m.ter( loc ) == t_dirtmound ) { - g->m.set( loc, t_dirt, f_plant_seed ); - } else if( !g->m.has_flag( "PLOWABLE", loc ) ) { + } else if( here.ter( loc ) == t_dirtmound ) { + here.set( loc, t_dirt, f_plant_seed ); + } else if( !here.has_flag( "PLOWABLE", loc ) ) { //If it isn't plowable terrain, then it will most likely be damaged. damage( planter_id, rng( 1, 10 ), DT_BASH, false ); sounds::sound( loc, rng( 10, 20 ), sounds::sound_t::combat, _( "Clink" ), false, "smash_success", @@ -1334,13 +1347,13 @@ void vehicle::operate_planter() } if( !i->count_by_charges() || i->charges == 1 ) { i->set_age( 0_turns ); - g->m.add_item( loc, *i ); + here.add_item( loc, *i ); v.erase( i ); } else { item tmp = *i; tmp.charges = 1; tmp.set_age( 0_turns ); - g->m.add_item( loc, tmp ); + here.add_item( loc, tmp ); i->charges--; } break; @@ -1351,6 +1364,7 @@ void vehicle::operate_planter() void vehicle::operate_scoop() { + map &here = get_map(); for( const vpart_reference &vp : get_enabled_parts( "SCOOP" ) ) { const size_t scoop = vp.part_index(); const int chance_to_damage_item = 9; @@ -1363,17 +1377,17 @@ void vehicle::operate_scoop() random_entry_ref( sound_msgs ), false, "vehicle", "scoop" ); std::vector parts_points; for( const tripoint ¤t : - g->m.points_in_radius( global_part_pos3( scoop ), 1 ) ) { + here.points_in_radius( global_part_pos3( scoop ), 1 ) ) { parts_points.push_back( current ); } for( const tripoint &position : parts_points ) { - g->m.mop_spills( position ); - if( !g->m.has_items( position ) ) { + here.mop_spills( position ); + if( !here.has_items( position ) ) { continue; } item *that_item_there = nullptr; - map_stack items = g->m.i_at( position ); - if( g->m.has_flag( "SEALED", position ) ) { + map_stack items = here.i_at( position ); + if( here.has_flag( "SEALED", position ) ) { // Ignore it. Street sweepers are not known for their ability to harvest crops. continue; } @@ -1396,7 +1410,7 @@ void vehicle::operate_scoop() } //This attempts to add the item to the scoop inventory and if successful, removes it from the map. if( add_item( scoop, *that_item_there ) ) { - g->m.i_rem( position, that_item_there ); + here.i_rem( position, that_item_there ); } else { break; } @@ -1485,8 +1499,9 @@ void vehicle::open_or_close( const int part_index, const bool opening ) //find_lines_of_parts() doesn't return the part_index we passed, so we set it on it's own parts[part_index].open = opening; insides_dirty = true; - g->m.set_transparency_cache_dirty( sm_pos.z ); - const int dist = rl_dist( g->u.pos(), mount_to_tripoint( parts[part_index].mount ) ); + get_map().set_transparency_cache_dirty( sm_pos.z ); + const int dist = rl_dist( get_player_character().pos(), + mount_to_tripoint( parts[part_index].mount ) ); if( dist < 20 ) { sfx::play_variant_sound( opening ? "vehicle_open" : "vehicle_close", parts[ part_index ].info().get_id().str(), 100 - dist * 3 ); @@ -1553,8 +1568,9 @@ void vehicle::use_autoclave( int p ) void vehicle::use_washing_machine( int p ) { + avatar &player_character = get_avatar(); // Get all the items that can be used as detergent - const inventory &inv = g->u.crafting_inventory(); + const inventory &inv = player_character.crafting_inventory(); std::vector detergents = inv.items_with( [inv]( const item & it ) { return it.has_flag( "DETERGENT" ) && inv.has_charges( it.typeId(), 5 ); } ); @@ -1629,7 +1645,7 @@ void vehicle::use_washing_machine( int p ) std::vector detergent; detergent.push_back( item_comp( det_types[chosen_detergent], 5 ) ); - g->u.consume_items( detergent, 1, is_crafting_component ); + player_character.consume_items( detergent, 1, is_crafting_component ); add_msg( m_good, _( "You pour some detergent into the washing machine, close its lid, and turn it on. The washing machine is being filled with water from vehicle tanks." ) ); @@ -1638,7 +1654,8 @@ void vehicle::use_washing_machine( int p ) void vehicle::use_dishwasher( int p ) { - bool detergent_is_enough = g->u.crafting_inventory().has_charges( itype_detergent, 5 ); + avatar &player_character = get_avatar(); + bool detergent_is_enough = player_character.crafting_inventory().has_charges( itype_detergent, 5 ); auto items = get_items( p ); static const std::string filthy( "FILTHY" ); bool filthy_items = std::all_of( items.begin(), items.end(), []( const item & i ) { @@ -1686,7 +1703,7 @@ void vehicle::use_dishwasher( int p ) std::vector detergent; detergent.push_back( item_comp( itype_detergent, 5 ) ); - g->u.consume_items( detergent, 1, is_crafting_component ); + player_character.consume_items( detergent, 1, is_crafting_component ); add_msg( m_good, _( "You pour some detergent into the dishwasher, close its lid, and turn it on. The dishwasher is being filled with water from vehicle tanks." ) ); @@ -1699,7 +1716,7 @@ void vehicle::use_monster_capture( int part, const tripoint &pos ) return; } item base = item( parts[part].get_base() ); - base.type->invoke( g->u, base, pos ); + base.type->invoke( get_avatar(), base, pos ); parts[part].set_base( base ); if( base.has_var( "contained_name" ) ) { parts[part].set_flag( vehicle_part::animal_flag ); @@ -1762,7 +1779,7 @@ void vehicle::use_harness( int part, const tripoint &pos ) add_msg( m_info, _( "You untie your %s." ), m.get_name() ); m.remove_effect( effect_tied ); if( m.tied_item ) { - g->u.i_add( *m.tied_item ); + get_player_character().i_add( *m.tied_item ); m.tied_item.reset(); } } @@ -1860,7 +1877,8 @@ void vehicle::use_bike_rack( int part ) success = try_to_rack_nearby_vehicle( racks_parts ); } if( success ) { - g->m.invalidate_map_cache( g->get_levz() ); + get_map().invalidate_map_cache( g->get_levz() ); + get_map().reset_vehicle_cache( g->get_levz() ); } } @@ -1869,8 +1887,10 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) { std::vector menu_items; std::vector options_message; - const bool has_items_on_ground = g->m.sees_some_items( pos, g->u ); - const bool items_are_sealed = g->m.has_flag( "SEALED", pos ); + map &here = get_map(); + avatar &player_character = get_avatar(); + const bool has_items_on_ground = here.sees_some_items( pos, player_character ); + const bool items_are_sealed = here.has_flag( "SEALED", pos ); auto turret = turret_query( pos ); @@ -2009,7 +2029,7 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) choice = selectmenu.ret; } if( choice != EXAMINE && choice != TRACK && choice != GET_ITEMS_ON_GROUND ) { - if( !handle_potential_theft( dynamic_cast( g->u ) ) ) { + if( !handle_potential_theft( dynamic_cast( player_character ) ) ) { return; } } @@ -2018,10 +2038,18 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) if( fuel_left( itype_battery, true ) < pseudo.ammo_required() ) { return false; } + //Pseudo items don't have a magazine in it, and they don't need it anymore. + //Pseudo magazine in Pseudo item sounds good. + //Somehow the set of available ammos in pocket_data loaded from json is alphabetic, + //so the default ammo is always atomic, haven't checked the relevant codes yet. + item pseudo_magazine( pseudo.magazine_default() ); + //no initial ammo + pseudo_magazine.contents.clear_items(); + pseudo.put_in( pseudo_magazine, item_pocket::pocket_type::MAGAZINE_WELL ); int capacity = pseudo.ammo_capacity( ammotype( "battery" ) ); int qty = capacity - discharge_battery( capacity ); pseudo.ammo_set( itype_battery, qty ); - g->u.invoke_item( &pseudo ); + player_character.invoke_item( &pseudo ); charge_battery( pseudo.ammo_remaining() ); return true; }; @@ -2049,7 +2077,7 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) return; } case USE_TOWEL: { - iuse::towel_common( &g->u, nullptr, false ); + iuse::towel_common( &player_character, nullptr, false ); return; } case USE_AUTOCLAVE: { @@ -2065,13 +2093,13 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) return; } case FILL_CONTAINER: { - g->u.siphon( *this, itype_water_clean ); + player_character.siphon( *this, itype_water_clean ); return; } case DRINK: { item water( "water_clean", 0 ); - if( g->u.can_consume( water ) ) { - g->u.assign_activity( player_activity( consume_activity_actor( water ) ) ); + if( player_character.can_consume( water ) ) { + player_character.assign_activity( player_activity( consume_activity_actor( water ) ) ); drain( itype_water_clean, 1 ); } return; @@ -2079,7 +2107,7 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) case USE_WELDER: { if( veh_tool( itype_welder ) ) { // HACK: Evil hack incoming - auto &act = g->u.activity; + auto &act = player_character.activity; if( act.id() == ACT_REPAIR_ITEM ) { // Magic: first tell activity the item doesn't really exist act.index = INT_MIN; @@ -2121,15 +2149,15 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) } case UNLOAD_TURRET: { item_location loc = turret.base(); - g->unload( loc ); + player_character.unload( loc ); return; } case RELOAD_TURRET: { - item::reload_option opt = g->u.select_ammo( *turret.base(), true ); + item::reload_option opt = player_character.select_ammo( *turret.base(), true ); if( opt ) { - g->u.assign_activity( ACT_RELOAD, opt.moves(), opt.qty() ); - g->u.activity.targets.emplace_back( turret.base() ); - g->u.activity.targets.push_back( std::move( opt.ammo ) ); + player_character.assign_activity( ACT_RELOAD, opt.moves(), opt.qty() ); + player_character.activity.targets.emplace_back( turret.base() ); + player_character.activity.targets.push_back( std::move( opt.ammo ) ); } return; } @@ -2170,7 +2198,7 @@ void vehicle::interact_with( const tripoint &pos, int interact_part ) return; } case WORKBENCH: { - iexamine::workbench_internal( g->u, pos, vpart_reference( *this, workbench_part ) ); + iexamine::workbench_internal( player_character, pos, vpart_reference( *this, workbench_part ) ); return; } } diff --git a/src/vitamin.cpp b/src/vitamin.cpp index c08e002d4a3b2..2cc90260bf8e8 100644 --- a/src/vitamin.cpp +++ b/src/vitamin.cpp @@ -70,10 +70,6 @@ void vitamin::load_vitamin( const JsonObject &jo ) } vit.type_ = jo.get_enum_value( "vit_type" ); - if( vit.rate_ < 0_turns ) { - jo.throw_error( "vitamin consumption rate cannot be negative", "rate" ); - } - for( JsonArray e : jo.get_array( "disease" ) ) { vit.disease_.emplace_back( e.get_int( 0 ), e.get_int( 1 ) ); } diff --git a/src/weather.cpp b/src/weather.cpp index ac1cea97a9864..e4415a2be3fc6 100644 --- a/src/weather.cpp +++ b/src/weather.cpp @@ -7,6 +7,7 @@ #include #include +#include "assign.h" #include "avatar.h" #include "bodypart.h" #include "calendar.h" @@ -20,6 +21,7 @@ #include "item_contents.h" #include "line.h" #include "map.h" +#include "map_iterator.h" #include "math_defines.h" #include "messages.h" #include "options.h" @@ -61,23 +63,36 @@ weather_manager &get_weather() return g->weather; } -static bool is_player_outside() +static bool is_creature_outside( const Creature &target ) { - return g->m.is_outside( point( g->u.posx(), g->u.posy() ) ) && g->get_levz() >= 0; + return get_map().is_outside( point( target.posx(), + target.posy() ) ) && g->get_levz() >= 0; } -static constexpr int THUNDER_CHANCE = 50; -static constexpr int LIGHTNING_CHANCE = 600; +weather_type_id get_bad_weather() +{ + weather_type_id bad_weather = WEATHER_NULL; + const weather_generator &weather_gen = get_weather().get_cur_weather_gen(); + for( const std::string &weather_type : weather_gen.weather_types ) { + weather_type_id current_conditions = weather_type_id( weather_type ); + if( current_conditions->precip == precip_class::heavy ) { + bad_weather = current_conditions; + } + } + return bad_weather; +} /** * Glare. * Causes glare effect to player's eyes if they are not wearing applicable eye protection. * @param intensity Level of sun brighthess */ -void weather_effect::glare( sun_intensity intensity ) +void glare( weather_type_id w ) { + Character &target_character = g->u;//todo npcs, also //General prepequisites for glare - if( !is_player_outside() || !g->is_in_sunlight( g->u.pos() ) || g->u.in_sleep_state() || + if( !is_creature_outside( target_character ) || !g->is_in_sunlight( g->u.pos() ) || + g->u.in_sleep_state() || g->u.worn_with_flag( flag_SUN_GLASSES ) || g->u.has_bionic( bio_sunglasses ) || g->u.is_blind() ) { @@ -90,60 +105,61 @@ void weather_effect::glare( sun_intensity intensity ) if( season == WINTER ) { //Winter snow glare: for both clear & sunny weather effect = &effect_snow_glare; - dur = g->u.has_effect( *effect ) ? 1_turns : 2_turns; - } else if( intensity == sun_intensity::high ) { + dur = target_character.has_effect( *effect ) ? 1_turns : 2_turns; + } else if( w->sun_intensity == sun_intensity_type::high ) { //Sun glare: only for bright sunny weather effect = &effect_glare; - dur = g->u.has_effect( *effect ) ? 1_turns : 2_turns; + dur = target_character.has_effect( *effect ) ? 1_turns : 2_turns; } //apply final glare effect if( dur > 0_turns && effect != nullptr ) { //enhance/reduce by some traits - if( g->u.has_trait( trait_CEPH_VISION ) ) { + if( target_character.has_trait( trait_CEPH_VISION ) ) { dur = dur * 2; } - g->u.add_env_effect( *effect, bp_eyes, 2, dur ); + target_character.add_env_effect( *effect, bp_eyes, 2, dur ); } } ////// food vs weather -int incident_sunlight( weather_type wtype, const time_point &t ) +int incident_sunlight( weather_type_id wtype, const time_point &t ) { - return std::max( 0.0f, sunlight( t, false ) + weather::light_modifier( wtype ) ); + return std::max( 0.0f, sunlight( t, false ) + wtype->light_modifier ); } -inline void proc_weather_sum( const weather_type wtype, weather_sum &data, +inline void proc_weather_sum( const weather_type_id wtype, weather_sum &data, const time_point &t, const time_duration &tick_size ) { - switch( wtype ) { - case WEATHER_LIGHT_DRIZZLE: - data.rain_amount += 1 * to_turns( tick_size ); - break; - case WEATHER_DRIZZLE: - data.rain_amount += 4 * to_turns( tick_size ); - break; - case WEATHER_RAINY: - case WEATHER_THUNDER: - case WEATHER_LIGHTNING: - data.rain_amount += 8 * to_turns( tick_size ); - break; - case WEATHER_ACID_DRIZZLE: - data.acid_amount += 4 * to_turns( tick_size ); - break; - case WEATHER_ACID_RAIN: - data.acid_amount += 8 * to_turns( tick_size ); - break; - default: - break; + int amount = 0; + if( wtype->rains ) { + switch( wtype->precip ) { + case precip_class::very_light: + amount = 1 * to_turns( tick_size ); + break; + case precip_class::light: + amount = 4 * to_turns( tick_size ); + break; + case precip_class::heavy: + amount = 8 * to_turns( tick_size ); + break; + default: + break; + } } + if( wtype->acidic ) { + data.acid_amount += amount; + } else { + data.rain_amount += amount; + } + // TODO: Change this sunlight "sampling" here into a proper interpolation const float tick_sunlight = incident_sunlight( wtype, t ); data.sunlight += tick_sunlight * to_turns( tick_size ); } -weather_type current_weather( const tripoint &location, const time_point &t ) +weather_type_id current_weather( const tripoint &location, const time_point &t ) { const auto wgen = g->weather.get_cur_weather_gen(); if( g->weather.weather_override != WEATHER_NULL ) { @@ -169,7 +185,7 @@ weather_sum sum_conditions( const time_point &start, const time_point &end, tick_size = 1_minutes; } - weather_type wtype = current_weather( location, t ); + weather_type_id wtype = current_weather( location, t ); proc_weather_sum( wtype, data, t, tick_size ); data.wind_amount += get_local_windpower( g->weather.windspeed, overmap_buffer.ter( ms_to_omt_copy( location ) ), @@ -331,8 +347,9 @@ double trap::funnel_turns_per_charge( double rain_depth_mm_per_hour ) const static void fill_funnels( int rain_depth_mm_per_hour, bool acid, const trap &tr ) { const double turns_per_charge = tr.funnel_turns_per_charge( rain_depth_mm_per_hour ); + map &here = get_map(); // Give each funnel on the map a chance to collect the rain. - const std::vector &funnel_locs = g->m.trap_locations( tr.loadid ); + const std::vector &funnel_locs = here.trap_locations( tr.loadid ); for( const tripoint &loc : funnel_locs ) { units::volume maxcontains = 0_ml; if( one_in( turns_per_charge ) ) { @@ -341,7 +358,7 @@ static void fill_funnels( int rain_depth_mm_per_hour, bool acid, const trap &tr // This funnel has collected some rain! Put the rain in the largest // container here which is either empty or contains some mixture of // impure water and acid. - map_stack items = g->m.i_at( loc ); + map_stack items = here.i_at( loc ); auto container = items.end(); for( auto candidate_container = items.begin(); candidate_container != items.end(); ++candidate_container ) { @@ -381,34 +398,53 @@ static void fill_water_collectors( int mmPerHour, bool acid ) * @see map::decay_fields_and_scent * @see player::drench */ -static void wet_player( int amount ) +void wet( Character &target, int amount ) { - if( !is_player_outside() || - g->u.has_trait( trait_FEATHERS ) || - g->u.weapon.has_flag( "RAIN_PROTECT" ) || - ( !one_in( 50 ) && g->u.worn_with_flag( "RAINPROOF" ) ) ) { + if( !is_creature_outside( target ) || + target.has_trait( trait_FEATHERS ) || + target.weapon.has_flag( "RAIN_PROTECT" ) || + ( !one_in( 50 ) && target.worn_with_flag( "RAINPROOF" ) ) ) { return; } // Coarse correction to get us back to previously intended soaking rate. if( !calendar::once_every( 6_seconds ) ) { return; } - const int warmth_delay = g->u.warmth( bodypart_id( "torso" ) ) * 4 / 5 + g->u.warmth( + const int warmth_delay = target.warmth( bodypart_id( "torso" ) ) * 4 / 5 + target.warmth( bodypart_id( "head" ) ) / 5; if( rng( 0, 100 - amount + warmth_delay ) > 10 ) { // Thick clothing slows down (but doesn't cap) soaking return; } - const auto &wet = g->u.body_wetness; - const auto &capacity = g->u.drench_capacity; + const auto &wet = target.body_wetness; + const auto &capacity = target.drench_capacity; body_part_set drenched_parts{ { bodypart_str_id( "torso" ), bodypart_str_id( "arm_l" ), bodypart_str_id( "arm_r" ), bodypart_str_id( "head" ) } }; if( wet[bp_torso] * 100 >= capacity[bp_torso] * 50 ) { // Once upper body is 50%+ drenched, start soaking the legs too drenched_parts.unify_set( { { bodypart_str_id( "leg_l" ), bodypart_str_id( "leg_r" ) } } ); } - g->u.drench( amount, drenched_parts, false ); + target.drench( amount, drenched_parts, false ); +} + +void weather_sound( translation sound_message, std::string sound_effect ) +{ + if( !g->u.has_effect( effect_sleep ) && !g->u.is_deaf() ) { + if( g->get_levz() >= 0 ) { + add_msg( sound_message ); + if( !sound_effect.empty() ) { + sfx::play_variant_sound( "environment", sound_effect, 80, rng( 0, 359 ) ); + } + } else if( one_in( std::max( roll_remainder( 2.0f * g->get_levz() / + g->u.mutation_value( "hearing_modifier" ) ), 1 ) ) ) { + add_msg( sound_message ); + if( !sound_effect.empty() ) { + sfx::play_variant_sound( "environment", sound_effect, + ( 80 * g->u.mutation_value( "hearing_modifier" ) ), rng( 0, 359 ) ); + } + } + } } double precip_mm_per_hour( precip_class const p ) @@ -416,146 +452,155 @@ double precip_mm_per_hour( precip_class const p ) // the precipitation were rain (rather than snow). { return - p == precip_class::VERY_LIGHT ? 0.5 : - p == precip_class::LIGHT ? 1.5 : - p == precip_class::HEAVY ? 3 : + p == precip_class::very_light ? 0.5 : + p == precip_class::light ? 1.5 : + p == precip_class::heavy ? 3 : 0; } -void do_rain( weather_type const w ) +void handle_weather_effects( weather_type_id const w ) { - if( !weather::rains( w ) || weather::precip( w ) == precip_class::NONE ) { - return; - } - fill_water_collectors( precip_mm_per_hour( weather::precip( w ) ), weather::acidic( w ) ); - int wetness = 0; - time_duration decay_time = 60_turns; - if( weather::precip( w ) == precip_class::VERY_LIGHT ) { - wetness = 5; - decay_time = 5_turns; - } else if( weather::precip( w ) == precip_class::LIGHT ) { - wetness = 30; - decay_time = 15_turns; - } else if( weather::precip( w ) == precip_class::HEAVY ) { - decay_time = 45_turns; - wetness = 60; + //Possible TODO, make npc/monsters affected + Character &target_character = get_player_character(); + if( w->rains && w->precip != precip_class::none ) { + fill_water_collectors( precip_mm_per_hour( w->precip ), + w->acidic ); + int wetness = 0; + time_duration decay_time = 60_turns; + if( w->precip == precip_class::very_light ) { + wetness = 5; + decay_time = 5_turns; + } else if( w->precip == precip_class::light ) { + wetness = 30; + decay_time = 15_turns; + } else if( w->precip == precip_class::heavy ) { + decay_time = 45_turns; + wetness = 60; + } + get_map().decay_fields_and_scent( decay_time ); + wet( target_character, wetness ); } - g->m.decay_fields_and_scent( decay_time ); - wet_player( wetness ); -} + glare( w ); + g->weather.lightning_active = false; -void weather_effect::none() -{ - glare( sun_intensity::normal ); -} -void weather_effect::flurry() {} - -void weather_effect::sunny() -{ - glare( sun_intensity::high ); -} -void weather_effect::snow() -{ - wet_player( 10 ); -} - -void weather_effect::snowstorm() -{ - wet_player( 40 ); -} -/** - * Thunder. - * Flavor messages. Very wet. - */ -void weather_effect::thunder() -{ - if( !g->u.has_effect( effect_sleep ) && !g->u.is_deaf() && one_in( THUNDER_CHANCE ) ) { - if( g->get_levz() >= 0 ) { - add_msg( _( "You hear a distant rumble of thunder." ) ); - sfx::play_variant_sound( "environment", "thunder_far", 80, rng( 0, 359 ) ); - } else if( one_in( std::max( roll_remainder( 2.0f * g->get_levz() / - g->u.mutation_value( "hearing_modifier" ) ), 1 ) ) ) { - add_msg( _( "You hear a rumble of thunder from above." ) ); - sfx::play_variant_sound( "environment", "thunder_far", - ( 80 * g->u.mutation_value( "hearing_modifier" ) ), rng( 0, 359 ) ); + for( const weather_effect ¤t_effect : w->effects ) { + if( current_effect.must_be_outside && !is_creature_outside( target_character ) ) { + continue; } - } -} - -/** - * Lightning. - * Chance of lightning illumination for the current turn when aboveground. Thunder. - * - * This used to manifest actual lightning on the map, causing fires and such, but since such effects - * only manifest properly near the player due to the "reality bubble", this was causing undesired metagame tactics - * such as players leaving their shelter for a more "expendable" area during lightning storms. - */ -void weather_effect::lightning() -{ - thunder(); - if( one_in( LIGHTNING_CHANCE ) ) { - if( g->get_levz() >= 0 ) { - add_msg( _( "A flash of lightning illuminates your surroundings!" ) ); - sfx::play_variant_sound( "environment", "thunder_near", 100, rng( 0, 359 ) ); + if( current_effect.time_between > 0_seconds && + !calendar::once_every( current_effect.time_between ) ) { + continue; + } + if( !one_in( current_effect.one_in_chance ) ) { + continue; + } + if( current_effect.lightning && g->get_levz() >= 0 ) { g->weather.lightning_active = true; } - } else { - g->weather.lightning_active = false; - } -} - -/** - * Acid drizzle. - * Causes minor pain only. - */ -void weather_effect::light_acid() -{ - if( calendar::once_every( 1_minutes ) && is_player_outside() ) { - if( g->u.weapon.has_flag( "RAIN_PROTECT" ) && !one_in( 3 ) ) { - add_msg( _( "Your %s protects you from the acidic drizzle." ), g->u.weapon.tname() ); - } else { - if( g->u.worn_with_flag( "RAINPROOF" ) && !one_in( 4 ) ) { - add_msg( _( "Your clothing protects you from the acidic drizzle." ) ); + if( current_effect.rain_proof ) { + int chance = 0; + if( w->precip <= precip_class::light ) { + chance = 2; + } else if( w->precip >= precip_class::heavy ) { + chance = 4; + } + if( target_character.weapon.has_flag( "RAIN_PROTECT" ) && one_in( chance ) ) { + add_msg( _( "Your %s protects you from the weather." ), target_character.weapon.tname() ); + continue; } else { - bool has_helmet = false; - if( g->u.is_wearing_power_armor( &has_helmet ) && ( has_helmet || !one_in( 4 ) ) ) { - add_msg( _( "Your power armor protects you from the acidic drizzle." ) ); + if( target_character.worn_with_flag( "RAINPROOF" ) && one_in( chance * 2 ) ) { + add_msg( _( "Your clothing protects you from the weather." ) ); + continue; } else { - add_msg( m_warning, _( "The acid rain stings, but is mostly harmless for now…" ) ); - if( one_in( 10 ) && ( g->u.get_pain() < 10 ) ) { - g->u.mod_pain( 1 ); + bool has_helmet = false; + if( target_character.is_wearing_power_armor( &has_helmet ) && ( has_helmet || + one_in( chance * 2 ) ) ) { + add_msg( _( "Your power armor protects you from the weather." ) ); + continue; } } } } - } -} + if( target_character.get_pain() >= current_effect.pain_max ) { + continue; + } -/** - * Acid rain. - * Causes major pain. Damages non acid-proof mobs. Very wet (acid). - */ -void weather_effect::acid() -{ - if( calendar::once_every( 2_turns ) && is_player_outside() ) { - if( g->u.weapon.has_flag( "RAIN_PROTECT" ) && one_in( 4 ) ) { - add_msg( _( "Your umbrella protects you from the acid rain." ) ); - } else { - if( g->u.worn_with_flag( "RAINPROOF" ) && one_in( 2 ) ) { - add_msg( _( "Your clothing protects you from the acid rain." ) ); + bool spawned = current_effect.spawns.empty(); + for( const spawn_type &spawn : current_effect.spawns ) { + monster target_monster; + if( spawn.target.is_empty() ) { + //grab a random nearby hostile creature to create a hallucination or copy of + Creature *copy = g->get_creature_if( [&spawn]( const Creature & critter ) -> bool { + bool not_self = get_player_character().pos() != critter.pos(); + bool in_range = std::round( rl_dist_exact( get_player_character().pos(), critter.pos() ) ) <= spawn.target_range; + bool valid_target = get_player_character().attitude_to( critter ) == Creature::Attitude::HOSTILE; + return not_self && in_range && valid_target; + } ); + if( copy == nullptr ) { + continue; + } + target_monster = *dynamic_cast( copy ); } else { - bool has_helmet = false; - if( g->u.is_wearing_power_armor( &has_helmet ) && ( has_helmet || !one_in( 2 ) ) ) { - add_msg( _( "Your power armor protects you from the acid rain." ) ); - } else { - add_msg( m_bad, _( "The acid rain burns!" ) ); - if( one_in( 2 ) && ( g->u.get_pain() < 100 ) ) { - g->u.mod_pain( rng( 1, 5 ) ); - } + target_monster = spawn.target; + } + + for( int i = 0; i < spawn.hallucination_count; i++ ) { + tripoint point; + if( g->find_nearby_spawn_point( target_character, target_monster.type->id, spawn.min_radius, + spawn.max_radius, point ) ) { + g->spawn_hallucination( point, target_monster.type->id ); + spawned = true; + } + } + for( int i = 0; i < spawn.real_count; i++ ) { + tripoint point; + if( g->find_nearby_spawn_point( target_character, target_monster.type->id, spawn.min_radius, + spawn.max_radius, point ) ) { + g->place_critter_at( target_monster.type->id, point ); + spawned = true; + } + } + } + if( !spawned ) { + continue; + } + for( const weather_field &field : current_effect.fields ) { + for( const tripoint &dest : get_map().points_in_radius( target_character.pos(), field.radius ) ) { + if( !field.outdoor_only || get_map().is_outside( dest ) ) { + get_map().add_field( dest, field.type, field.intensity, field.age ); } } } + if( current_effect.effect_id.is_valid() ) { + if( current_effect.target_part.is_valid() ) { + target_character.add_effect( current_effect.effect_id, current_effect.effect_duration, + current_effect.target_part->token ); + } else { + target_character.add_effect( current_effect.effect_id, current_effect.effect_duration ); + } + } + if( current_effect.trait_id_to_add.is_valid() ) { + target_character.set_mutation( current_effect.trait_id_to_add ); + } + if( current_effect.trait_id_to_remove.is_valid() ) { + target_character.unset_mutation( current_effect.trait_id_to_remove ); + } + + if( current_effect.target_part.is_valid() ) { + target_character.deal_damage( nullptr, current_effect.target_part, damage_instance( DT_BASH, + current_effect.damage ) ); + } else { + for( const bodypart_id &bp : target_character.get_all_body_parts() ) { + target_character.deal_damage( nullptr, bp, damage_instance( DT_BASH, current_effect.damage ) ); + } + } + target_character.mod_healthy( current_effect.healthy ); + target_character.mod_rad( current_effect.radiation ); + wet( target_character, current_effect.wet ); + target_character.mod_pain( current_effect.pain ); + weather_sound( current_effect.sound_message, current_effect.sound_effect ); + target_character.add_msg_if_player( current_effect.message ); } } @@ -622,7 +667,7 @@ std::string weather_forecast( const point &abs_sm_pos ) _( "The current time is %1$s Eastern Standard Time. At %2$s in %3$s, it was %4$s. The temperature was %5$s. " ), to_string_time_of_day( calendar::turn ), print_time_just_hour( calendar::turn ), city_name, - weather::name( g->weather.weather ), print_temperature( g->weather.temperature ) + get_weather().weather_id->name, print_temperature( get_weather().temperature ) ); //weather_report += ", the dewpoint ???, and the relative humidity ???. "; @@ -646,7 +691,7 @@ std::string weather_forecast( const point &abs_sm_pos ) const time_point last_hour = calendar::turn - ( calendar::turn - calendar::turn_zero ) % 1_hours; for( int d = 0; d < 6; d++ ) { - weather_type forecast = WEATHER_NULL; + weather_type_id forecast = WEATHER_NULL; const auto wgen = g->weather.get_cur_weather_gen(); for( time_point i = last_hour + d * 12_hours; i < last_hour + ( d + 1 ) * 12_hours; i += 1_hours ) { w_point w = wgen.get_weather( abs_ms_pos, i, g->get_seed() ); @@ -671,7 +716,7 @@ std::string weather_forecast( const point &abs_sm_pos ) } weather_report += string_format( _( "%s… %s. Highs of %s. Lows of %s. " ), - day, weather::name( forecast ), + day, forecast->name, print_temperature( high ), print_temperature( low ) ); } @@ -862,14 +907,14 @@ std::string get_wind_arrow( int dirangle ) return wind_arrow; } -int get_local_humidity( double humidity, weather_type weather, bool sheltered ) +int get_local_humidity( double humidity, weather_type_id weather, bool sheltered ) { int tmphumidity = humidity; if( sheltered ) { // Norm for a house? tmphumidity = humidity * ( 100 - humidity ) / 100 + humidity; - } else if( weather == WEATHER_RAINY || weather == WEATHER_DRIZZLE || weather == WEATHER_THUNDER || - weather == WEATHER_LIGHTNING ) { + } else if( weather->rains && + weather->precip >= precip_class::light ) { tmphumidity = 100; } @@ -905,7 +950,7 @@ double get_local_windpower( double windpower, const oter_id &omter, const tripoi bool is_wind_blocker( const tripoint &location ) { - return g->m.has_flag( "BLOCK_WIND", location ); + return get_map().has_flag( "BLOCK_WIND", location ); } // Description of Wind Speed - https://en.wikipedia.org/wiki/Beaufort_scale @@ -977,7 +1022,7 @@ weather_manager::weather_manager() weather_override = WEATHER_NULL; nextweather = calendar::before_time_starts; temperature = 0; - weather = WEATHER_CLEAR; + weather_id = WEATHER_CLEAR; } const weather_generator &weather_manager::get_cur_weather_gen() const @@ -992,16 +1037,13 @@ void weather_manager::update_weather() w_point &w = *weather_precise; winddirection = wind_direction_override ? *wind_direction_override : w.winddirection; windspeed = windspeed_override ? *windspeed_override : w.windpower; - if( weather == WEATHER_NULL || calendar::turn >= nextweather ) { + if( weather_id == WEATHER_NULL || calendar::turn >= nextweather ) { const weather_generator &weather_gen = get_cur_weather_gen(); w = weather_gen.get_weather( g->u.global_square_location(), calendar::turn, g->get_seed() ); - weather_type old_weather = weather; - weather = weather_override == WEATHER_NULL ? - weather_gen.get_weather_conditions( w ) - : weather_override; - if( weather == WEATHER_SUNNY && is_night( calendar::turn ) ) { - weather = WEATHER_CLEAR; - } + weather_type_id old_weather = weather_id; + weather_id = weather_override == WEATHER_NULL ? + weather_gen.get_weather_conditions( w ) + : weather_override; if( !g->u.has_artifact_with( AEP_BAD_WEATHER ) ) { weather_override = WEATHER_NULL; } @@ -1011,22 +1053,21 @@ void weather_manager::update_weather() // Check weather every few turns, instead of every turn. // TODO: predict when the weather changes and use that time. nextweather = calendar::turn + 5_minutes; - const weather_datum wdata = weather_data( weather ); - if( weather != old_weather && wdata.dangerous && - g->get_levz() >= 0 && g->m.is_outside( g->u.pos() ) + if( weather_id != old_weather && weather_id->dangerous && + g->get_levz() >= 0 && get_map().is_outside( g->u.pos() ) && !g->u.has_activity( ACT_WAIT_WEATHER ) ) { g->cancel_activity_or_ignore_query( distraction_type::weather_change, - string_format( _( "The weather changed to %s!" ), wdata.name ) ); + string_format( _( "The weather changed to %s!" ), weather_id->name ) ); } - if( weather != old_weather && g->u.has_activity( ACT_WAIT_WEATHER ) ) { + if( weather_id != old_weather && g->u.has_activity( ACT_WAIT_WEATHER ) ) { g->u.assign_activity( ACT_WAIT_WEATHER, 0, 0 ); } - if( wdata.sight_penalty != - weather::sight_penalty( old_weather ) ) { + if( weather_id->sight_penalty != + old_weather->sight_penalty ) { for( int i = -OVERMAP_DEPTH; i <= OVERMAP_HEIGHT; i++ ) { - g->m.set_transparency_cache_dirty( i ); + get_map().set_transparency_cache_dirty( i ); } } } @@ -1054,7 +1095,7 @@ int weather_manager::get_temperature( const tripoint &location ) } //underground temperature = average New England temperature = 43F/6C rounded to int const int temp = ( location.z < 0 ? AVERAGE_ANNUAL_TEMPERATURE : temperature ) + - ( g->new_game ? 0 : g->m.get_temperature( location ) + temp_mod ); + ( g->new_game ? 0 : get_map().get_temperature( location ) + temp_mod ); temperature_cache.emplace( std::make_pair( location, temp ) ); return temp; diff --git a/src/weather.h b/src/weather.h index b365cd4273328..dd93db6bfede6 100644 --- a/src/weather.h +++ b/src/weather.h @@ -44,50 +44,8 @@ class item; struct trap; struct rl_vec2d; -/** - * Weather type enum. - */ -enum weather_type : int { - WEATHER_NULL, //!< For data and stuff - WEATHER_CLEAR, //!< No effects - WEATHER_SUNNY, //!< Glare if no eye protection - WEATHER_CLOUDY, //!< No effects - WEATHER_LIGHT_DRIZZLE,//!< very Light rain - WEATHER_DRIZZLE, //!< Light rain - WEATHER_RAINY, //!< Lots of rain, sight penalties - WEATHER_THUNDER, //!< Warns of lightning to come - WEATHER_LIGHTNING, //!< Rare lightning strikes! - WEATHER_ACID_DRIZZLE, //!< No real effects; warning of acid rain - WEATHER_ACID_RAIN, //!< Minor acid damage - WEATHER_FLURRIES, //!< Light snow - WEATHER_SNOW, //!< snow glare effects - WEATHER_SNOWSTORM, //!< sight penalties - NUM_WEATHER_TYPES //!< Sentinel value -}; - -enum class precip_class : int { - NONE, - VERY_LIGHT, - LIGHT, - HEAVY -}; - double precip_mm_per_hour( precip_class p ); -void do_rain( weather_type w ); - -/** - * Weather animation class. - */ -struct weather_animation_t { - float factor; - nc_color color; - char glyph; -}; - -/** - * Weather animation settings for the given type. - */ -weather_animation_t get_weather_animation( weather_type type ); +void handle_weather_effects( weather_type_id w ); /** * Weather drawing tracking. @@ -96,7 +54,7 @@ weather_animation_t get_weather_animation( weather_type type ); */ struct weather_printable { //!< Weather type in use. - weather_type wtype; + weather_type_id wtype; //!< Coordinates targeted for droplets. std::vector > vdrops; //!< Color to draw glyph this animation frame. @@ -105,50 +63,6 @@ struct weather_printable { char cGlyph; }; -/** - * Environmental effects and ramifications of weather. - * Visibility range changes are done elsewhere. - */ -namespace weather_effect -{ - -enum class sun_intensity : int { - normal = 1, - high -}; - -//!< Fallback weather. -void none(); -void glare( sun_intensity ); -void thunder(); -void lightning(); -void light_acid(); -void acid(); -//!< Currently flurries have no additional effects. -void flurry(); -void snow(); -void sunny(); -void snowstorm(); -} //namespace weather_effect - -using weather_effect_fn = void ( * )(); - -struct weather_datum { - std::string name; //!< UI name of weather type. - nc_color color; //!< UI color of weather type. - nc_color map_color; //!< Map color of weather type. - char glyph; //!< Map glyph of weather type. - int ranged_penalty; //!< Penalty to ranged attacks. - float sight_penalty; //!< Penalty to per-square visibility, applied in transparency map. - int light_modifier; //!< Modification to ambient light. - int sound_attn; //!< Sound attenuation of a given weather type. - bool dangerous; //!< If true, our activity gets interrupted. - precip_class precip; //!< Amount of associated precipitation. - bool rains; //!< Whether said precipitation falls as rain. - bool acidic; //!< Whether said precipitation is acidic. - weather_effect_fn effect; //!< Function pointer for weather effects. -}; - struct weather_sum { int rain_amount = 0; int acid_amount = 0; @@ -156,24 +70,7 @@ struct weather_sum { int wind_amount = 0; }; -weather_datum weather_data( weather_type type ); -namespace weather -{ -std::string name( weather_type type ); -nc_color color( weather_type type ); -nc_color map_color( weather_type type ); -char glyph( weather_type type ); -int ranged_penalty( weather_type type ); -float sight_penalty( weather_type type ); -int light_modifier( weather_type type ); -int sound_attn( weather_type type ); -bool dangerous( weather_type type ); -precip_class precip( weather_type type ); -bool rains( weather_type type ); -bool acidic( weather_type type ); -weather_effect_fn effect( weather_type type ); -} // namespace weather - +weather_type_id get_bad_weather(); std::string get_shortdirstring( int angle ); std::string get_dirstring( int angle ); @@ -193,7 +90,7 @@ std::string print_pressure( double pressure, int decimals = 0 ); // Return windchill offset in degrees F, starting from given temperature, humidity and wind int get_local_windchill( double temperature_f, double humidity, double wind_mph ); -int get_local_humidity( double humidity, weather_type weather, bool sheltered = false ); +int get_local_humidity( double humidity, weather_type_id weather, bool sheltered = false ); double get_local_windpower( double windpower, const oter_id &omter, const tripoint &location, const int &winddirection, bool sheltered = false ); @@ -231,16 +128,20 @@ bool warm_enough_to_plant( const tripoint &pos ); bool is_wind_blocker( const tripoint &location ); -weather_type current_weather( const tripoint &location, - const time_point &t = calendar::turn ); +weather_type_id current_weather( const tripoint &location, + const time_point &t = calendar::turn ); +void glare( weather_type_id w ); /** * Amount of sunlight incident at the ground, taking weather and time of day * into account. */ -int incident_sunlight( weather_type wtype, +int incident_sunlight( weather_type_id wtype, const time_point &t = calendar::turn ); +void weather_sound( translation sound_message, std::string sound_effect ); +void wet( Character &target, int amount ); + class weather_manager { public: @@ -252,14 +153,14 @@ class weather_manager int temperature = 0; bool lightning_active = false; // Weather pattern - weather_type weather = weather_type::WEATHER_NULL; + weather_type_id weather_id = WEATHER_NULL; int winddirection = 0; int windspeed = 0; // Cached weather data pimpl weather_precise; cata::optional wind_direction_override; cata::optional windspeed_override; - weather_type weather_override; + weather_type_id weather_override; // not only sets nextweather, but updates weather as well void set_nextweather( time_point t ); // The time at which weather will shift next. diff --git a/src/weather_data.cpp b/src/weather_data.cpp deleted file mode 100644 index 04591a419d955..0000000000000 --- a/src/weather_data.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include "weather.h" // IWYU pragma: associated - -#include -#include -#include -#include - -#include "color.h" -#include "translations.h" - -/** - * @ingroup Weather - * @{ - */ - -weather_animation_t get_weather_animation( weather_type const type ) -{ - static const std::map map { - {WEATHER_ACID_DRIZZLE, weather_animation_t {0.01f, c_light_green, '.'}}, - {WEATHER_ACID_RAIN, weather_animation_t {0.02f, c_light_green, ','}}, - {WEATHER_LIGHT_DRIZZLE, weather_animation_t{0.01f, c_light_blue, ','}}, - {WEATHER_DRIZZLE, weather_animation_t {0.01f, c_light_blue, '.'}}, - {WEATHER_RAINY, weather_animation_t {0.02f, c_light_blue, ','}}, - {WEATHER_THUNDER, weather_animation_t {0.02f, c_light_blue, '.'}}, - {WEATHER_LIGHTNING, weather_animation_t {0.04f, c_light_blue, ','}}, - {WEATHER_FLURRIES, weather_animation_t {0.01f, c_white, '.'}}, - {WEATHER_SNOW, weather_animation_t {0.02f, c_white, ','}}, - {WEATHER_SNOWSTORM, weather_animation_t {0.04f, c_white, '*'}} - }; - - const auto it = map.find( type ); - if( it != std::end( map ) ) { - return it->second; - } - - return {0.0f, c_white, '?'}; -} -struct weather_result { - weather_datum datum; - bool is_valid; -}; -static weather_result weather_data_internal( weather_type const type ) -{ - /** - * Weather types data definition. - * Name, color in UI, color and glyph on map, ranged penalty, sight penalty, - * light modifier, sound attenuation, warn player? - * Note light modifier assumes baseline of default_daylight_level() at 60 - */ - // TODO: but it actually isn't 60, it's 100. Fix this comment or fix the value - static const std::array data {{ - weather_datum { - "NULL Weather - BUG (weather_data.cpp:weather_data)", c_magenta, c_magenta_red, - '0', 0, 0.0f, 0, 0, false, - precip_class::NONE, false, false, &weather_effect::none - }, - weather_datum { - translate_marker( "Clear" ), c_cyan, c_yellow_white, ' ', 0, 1.0f, 0, 0, false, - precip_class::NONE, false, false, &weather_effect::none - }, - weather_datum { - translate_marker( "Sunny" ), c_light_cyan, c_yellow_white, '*', 0, 1.0f, 2, 0, false, - precip_class::NONE, false, false, &weather_effect::sunny - }, - weather_datum { - translate_marker( "Cloudy" ), c_light_gray, c_dark_gray_white, '~', 0, 1.0f, -20, 0, false, - precip_class::NONE, false, false, &weather_effect::none - }, - weather_datum { - translate_marker( "Light Drizzle" ), c_light_blue, h_light_blue, '.', 0, 1.01f, -10, 0, false, - precip_class::VERY_LIGHT, true, false, &weather_effect::none - }, - weather_datum { - translate_marker( "Drizzle" ), c_light_blue, h_light_blue, '.', 1, 1.03f, -20, 1, false, - precip_class::LIGHT, true, false, &weather_effect::none - }, - weather_datum { - translate_marker( "Rain" ), c_blue, h_blue, 'o', 3, 1.1f, -30, 4, false, - precip_class::HEAVY, true, false, &weather_effect::none - }, - weather_datum { - translate_marker( "Thunder Storm" ), c_dark_gray, i_blue, '%', 4, 1.2f, -40, 8, false, - precip_class::HEAVY, true, false, &weather_effect::thunder - }, - weather_datum { - translate_marker( "Lightning Storm" ), c_yellow, h_yellow, '%', 4, 1.25f, -45, 8, false, - precip_class::HEAVY, true, false, &weather_effect::lightning - }, - weather_datum { - translate_marker( "Acidic Drizzle" ), c_light_green, c_yellow_green, '.', 2, 1.03f, -20, 1, true, - precip_class::LIGHT, true, true, &weather_effect::light_acid - }, - weather_datum { - translate_marker( "Acid Rain" ), c_green, c_yellow_green, 'o', 4, 1.1f, -30, 4, true, - precip_class::HEAVY, true, true, &weather_effect::acid - }, - weather_datum { - translate_marker( "Flurries" ), c_white, c_dark_gray_cyan, '.', 2, 1.12f, -15, 2, false, - precip_class::LIGHT, false, false, &weather_effect::flurry - }, - weather_datum { - translate_marker( "Snowing" ), c_white, c_dark_gray_cyan, '*', 4, 1.13f, -20, 4, false, - precip_class::HEAVY, false, false, &weather_effect::snow - }, - weather_datum { - translate_marker( "Snowstorm" ), c_white, c_white_cyan, '%', 6, 1.2f, -30, 6, false, - precip_class::HEAVY, false, false, &weather_effect::snowstorm - } - }}; - - const size_t i = static_cast( type ); - if( i < NUM_WEATHER_TYPES ) { - return { data[i], i > 0 }; - } - - return { data[0], false }; -} - -static weather_datum weather_data_interal_localized( weather_type const type ) -{ - weather_result res = weather_data_internal( type ); - if( res.is_valid ) { - res.datum.name = _( res.datum.name ); - } - return res.datum; -} - -weather_datum weather_data( weather_type const type ) -{ - return weather_data_interal_localized( type ); -} - -namespace weather -{ -std::string name( weather_type const type ) -{ - return weather_data_interal_localized( type ).name; -} -nc_color color( weather_type const type ) -{ - return weather_data_internal( type ).datum.color; -} -nc_color map_color( weather_type const type ) -{ - return weather_data_internal( type ).datum.map_color; -} -char glyph( weather_type const type ) -{ - return weather_data_internal( type ).datum.glyph; -} -int ranged_penalty( weather_type const type ) -{ - return weather_data_internal( type ).datum.ranged_penalty; -} -float sight_penalty( weather_type const type ) -{ - return weather_data_internal( type ).datum.sight_penalty; -} -int light_modifier( weather_type const type ) -{ - return weather_data_internal( type ).datum.light_modifier; -} -int sound_attn( weather_type const type ) -{ - return weather_data_internal( type ).datum.sound_attn; -} -bool dangerous( weather_type const type ) -{ - return weather_data_internal( type ).datum.dangerous; -} -precip_class precip( weather_type const type ) -{ - return weather_data_internal( type ).datum.precip; -} -bool rains( weather_type const type ) -{ - return weather_data_internal( type ).datum.rains; -} -bool acidic( weather_type const type ) -{ - return weather_data_internal( type ).datum.acidic; -} -weather_effect_fn effect( weather_type const type ) -{ - return weather_data_internal( type ).datum.effect; -} -} // namespace weather - -///@} diff --git a/src/weather_gen.cpp b/src/weather_gen.cpp index 2dec277b23ea1..b715a1300627c 100644 --- a/src/weather_gen.cpp +++ b/src/weather_gen.cpp @@ -86,7 +86,7 @@ static double weather_temperature_from_common_data( const weather_generator &wg, const int seasonal_temp_mod[4] = { wg.spring_temp_manual_mod, wg.summer_temp_manual_mod, wg.autumn_temp_manual_mod, wg.winter_temp_manual_mod }; const double baseline( wg.base_temperature + - seasonal_temp_mod[ season ] + + seasonal_temp_mod[season] + dayv * daily_magnitude_K + seasonality * seasonality_magnitude_K ); @@ -146,7 +146,7 @@ w_point weather_generator::get_weather( const tripoint &location, const time_poi 10 * ( -seasonality + 2 ); // Wind power - W = std::max( 0, static_cast( base_wind * rng( 1, 2 ) / std::pow( ( P + W ) / 1014.78, rng( 9, + W = std::max( 0, static_cast( base_wind * rng( 1, 2 ) / std::pow( ( P + W ) / 1014.78, rng( 9, base_wind_distrib_peaks ) ) + -cyf / base_wind_season_variation * rng( 1, 2 ) ) ); // Initial static variable @@ -165,65 +165,60 @@ w_point weather_generator::get_weather( const tripoint &location, const time_poi // Acid rains const double acid_content = base_acid * A; bool acid = acid_content >= 1.0; - return w_point {T, H, P, W, wind_desc, current_winddir, acid}; + return w_point{ T, H, P, W, wind_desc, current_winddir, acid }; } -weather_type weather_generator::get_weather_conditions( const tripoint &location, +weather_type_id weather_generator::get_weather_conditions( const tripoint &location, const time_point &t, unsigned seed ) const { w_point w( get_weather( location, t, seed ) ); - weather_type wt = get_weather_conditions( w ); - // Make sure we don't say it's sunny at night! =P - if( wt == WEATHER_SUNNY && is_night( t ) ) { - return WEATHER_CLEAR; - } + weather_type_id wt = get_weather_conditions( w ); return wt; } -weather_type weather_generator::get_weather_conditions( const w_point &w ) const +weather_type_id weather_generator::get_weather_conditions( const w_point &w ) const { - weather_type r( WEATHER_CLEAR ); - if( w.pressure > 1020 && w.humidity < 70 ) { - r = WEATHER_SUNNY; - } - if( w.pressure < 1010 && w.humidity > 40 ) { - r = WEATHER_CLOUDY; - } - if( r == WEATHER_CLOUDY && ( w.humidity > 96 || w.pressure < 1003 ) ) { - r = WEATHER_LIGHT_DRIZZLE; - } - if( r >= WEATHER_LIGHT_DRIZZLE && ( w.humidity > 97 || w.pressure < 1000 ) ) { - r = WEATHER_DRIZZLE; - } - if( r >= WEATHER_CLOUDY && ( w.humidity > 98 || w.pressure < 993 ) ) { - r = WEATHER_RAINY; - } - if( r == WEATHER_RAINY && w.pressure < 996 ) { - r = WEATHER_THUNDER; - } - if( r == WEATHER_THUNDER && w.pressure < 990 ) { - r = WEATHER_LIGHTNING; - } + weather_type_id current_conditions = WEATHER_CLEAR; + for( const std::string &weather_type : weather_types ) { + weather_type_id type = weather_type_id( weather_type ); + + const weather_requirements &requires = type->requirements; + bool test_pressure = + requires.pressure_max > w.pressure && + requires.pressure_min < w.pressure; + bool test_humidity = + requires.humidity_max > w.humidity && + requires.humidity_min < w.humidity; + if( ( requires.humidity_and_pressure && !( test_pressure && test_humidity ) ) || + ( !requires.humidity_and_pressure && !( test_pressure || test_humidity ) ) ) { + continue; + } + bool test_temperature = + requires.temperature_max > w.temperature && + requires.temperature_min < w.temperature; + bool test_windspeed = + requires.windpower_max > w.windpower && + requires.windpower_min < w.windpower; + bool test_acidic = !requires.acidic || w.acidic; + if( !( test_temperature && test_windspeed && test_acidic ) ) { + continue; + } - if( w.temperature <= 32 ) { - if( r == WEATHER_DRIZZLE ) { - r = WEATHER_FLURRIES; - } else if( r > WEATHER_DRIZZLE ) { - if( r >= WEATHER_THUNDER && w.windpower > 15 ) { - r = WEATHER_SNOWSTORM; - } else { - r = WEATHER_SNOW; + if( !requires.required_weathers.empty() ) { + if( std::find( requires.required_weathers.begin(), requires.required_weathers.end(), + current_conditions ) == requires.required_weathers.end() ) { + continue; } } - } - if( r == WEATHER_DRIZZLE && w.acidic ) { - r = WEATHER_ACID_DRIZZLE; - } - if( r > WEATHER_DRIZZLE && w.acidic ) { - r = WEATHER_ACID_RAIN; + if( !( requires.time == weather_time_requirement_type::both || + ( requires.time == weather_time_requirement_type::day && is_day( calendar::turn ) ) || + ( requires.time == weather_time_requirement_type::night && !is_day( calendar::turn ) ) ) ) { + continue; + } + current_conditions = type; } - return r; + return current_conditions; } int weather_generator::get_wind_direction( const season_type season ) const @@ -298,8 +293,7 @@ void weather_generator::test_weather( unsigned seed = 1000 ) const const time_point end = begin + 2 * calendar::year_length(); for( time_point i = begin; i < end; i += 20_minutes ) { w_point w = get_weather( tripoint_zero, to_turn( i ), seed ); - weather_type c = get_weather_conditions( w ); - weather_datum wd = weather_data( c ); + weather_type_id conditions = get_weather_conditions( w ); int year = to_turns( i - calendar::turn_zero ) / to_turns ( calendar::year_length() ) + 1; @@ -312,9 +306,11 @@ void weather_generator::test_weather( unsigned seed = 1000 ) const day = day_of_season( i ); } testfile << "|;" << year << ";" << season_of_year( i ) << ";" << day << ";" << hour << ";" << minute - << ";" << w.temperature << ";" << w.humidity << ";" << w.pressure << ";" << wd.name << ";" << + << ";" << w.temperature << ";" << w.humidity << ";" << w.pressure << ";" << conditions->name << ";" + << w.windpower << ";" << w.winddirection << std::endl; } + }, "weather test file" ); } @@ -336,5 +332,9 @@ weather_generator weather_generator::load( const JsonObject &jo ) ret.summer_humidity_manual_mod = jo.get_int( "summer_humidity_manual_mod", 0 ); ret.autumn_humidity_manual_mod = jo.get_int( "autumn_humidity_manual_mod", 0 ); ret.winter_humidity_manual_mod = jo.get_int( "winter_humidity_manual_mod", 0 ); + ret.weather_types = jo.get_string_array( "weather_types" ); + if( ret.weather_types.size() < 2 ) { + jo.throw_error( "Need at least 2 weather types per region for null and default." ); + } return ret; } diff --git a/src/weather_gen.h b/src/weather_gen.h index 9b269ec82cced..92f6b4c031711 100644 --- a/src/weather_gen.h +++ b/src/weather_gen.h @@ -3,14 +3,15 @@ #define CATA_SRC_WEATHER_GEN_H #include +#include #include "calendar.h" +#include "color.h" +#include "weather_type.h" struct tripoint; class JsonObject; -enum weather_type : int; - struct w_point { double temperature = 0; double humidity = 0; @@ -46,7 +47,7 @@ class weather_generator //How much the wind folows seasonal variation ( lower means more change ) int base_wind_season_variation = 0; static int current_winddir; - + std::vector weather_types; weather_generator(); /** @@ -55,8 +56,9 @@ class weather_generator * relative position (relative to the map you called getabs on). */ w_point get_weather( const tripoint &, const time_point &, unsigned ) const; - weather_type get_weather_conditions( const tripoint &, const time_point &, unsigned seed ) const; - weather_type get_weather_conditions( const w_point & ) const; + weather_type_id get_weather_conditions( const tripoint &, const time_point &, + unsigned seed ) const; + weather_type_id get_weather_conditions( const w_point & ) const; int get_wind_direction( season_type ) const; int convert_winddir( int ) const; int get_water_temperature() const; diff --git a/src/weather_type.cpp b/src/weather_type.cpp new file mode 100644 index 0000000000000..9bee3b8096247 --- /dev/null +++ b/src/weather_type.cpp @@ -0,0 +1,305 @@ +#include "weather_type.h" +#include "weather.h" +#include "game_constants.h" + +namespace +{ +generic_factory weather_type_factory( "weather_type" ); +} // namespace + + +namespace io +{ +template<> +std::string enum_to_string( precip_class data ) +{ + switch( data ) { + case precip_class::none: + return "none"; + case precip_class::very_light: + return "very_light"; + case precip_class::light: + return "light"; + case precip_class::heavy: + return "heavy"; + case precip_class::last: + break; + } + debugmsg( "Invalid precip_class" ); + abort(); +} + +template<> +std::string enum_to_string( sun_intensity_type data ) +{ + switch( data ) { + case sun_intensity_type::none: + return "none"; + case sun_intensity_type::light: + return "light"; + case sun_intensity_type::normal: + return "normal"; + case sun_intensity_type::high: + return "high"; + case sun_intensity_type::last: + break; + } + debugmsg( "Invalid sun_intensity_type" ); + abort(); +} + +template<> +std::string enum_to_string( weather_time_requirement_type data ) +{ + switch( data ) { + case weather_time_requirement_type::day: + return "day"; + case weather_time_requirement_type::night: + return "night"; + case weather_time_requirement_type::both: + return "both"; + case weather_time_requirement_type::last: + break; + } + debugmsg( "Invalid time_requirement_type" ); + abort(); +} + +template<> +std::string enum_to_string( weather_sound_category data ) +{ + switch( data ) { + case weather_sound_category::drizzle: + return "drizzle"; + case weather_sound_category::flurries: + return "flurries"; + case weather_sound_category::rainy: + return "rainy"; + case weather_sound_category::snow: + return "snow"; + case weather_sound_category::snowstorm: + return "snowstorm"; + case weather_sound_category::thunder: + return "thunder"; + case weather_sound_category::silent: + return "silent"; + case weather_sound_category::last: + break; + } + debugmsg( "Invalid time_requirement_type" ); + abort(); +} + +} // namespace io + +template<> +const weather_type &weather_type_id::obj() const +{ + return weather_type_factory.obj( *this ); +} + +/** @relates string_id */ +template<> +bool string_id::is_valid() const +{ + return weather_type_factory.is_valid( *this ); +} + +void weather_type::finalize() +{ + +} + +void weather_type::check() const +{ + for( const weather_type_id &required : requirements.required_weathers ) { + if( !required.is_valid() ) { + debugmsg( "Required weather type %s does not exist.", required.c_str() ); + abort(); + } + } + for( const weather_effect &effect : effects ) { + if( !effect.effect_id.is_empty() && !effect.effect_id.is_valid() ) { + debugmsg( "Effect type %s does not exist.", effect.effect_id.c_str() ); + abort(); + } + if( !effect.trait_id_to_add.is_empty() && !effect.trait_id_to_add.is_valid() ) { + debugmsg( "Trait %s does not exist.", effect.trait_id_to_add.c_str() ); + abort(); + } + if( !effect.trait_id_to_remove.is_empty() && !effect.trait_id_to_remove.is_valid() ) { + debugmsg( "Trait %s does not exist.", effect.trait_id_to_remove.c_str() ); + abort(); + } + if( !effect.target_part.is_empty() && !effect.target_part.is_valid() ) { + debugmsg( "Target part %s does not exist.", effect.target_part.c_str() ); + abort(); + } + for( const spawn_type &spawn : effect.spawns ) { + if( !spawn.target.is_empty() && !spawn.target.is_valid() ) { + debugmsg( "Spawn target %s does not exist.", spawn.target.c_str() ); + abort(); + } + } + for( const weather_field &field : effect.fields ) { + if( !field.type.is_valid() ) { + debugmsg( "field type %s does not exist.", field.type.c_str() ); + abort(); + } + } + } +} + +void weather_type::load( const JsonObject &jo, const std::string & ) +{ + mandatory( jo, was_loaded, "name", name ); + mandatory( jo, was_loaded, "id", id ); + + assign( jo, "color", color ); + assign( jo, "map_color", map_color ); + + std::string glyph; + mandatory( jo, was_loaded, "glyph", glyph ); + if( glyph.size() != 1 ) { + jo.throw_error( "glyph must be only one character" ); + } else { + glyph = glyph[0]; + } + mandatory( jo, was_loaded, "ranged_penalty", ranged_penalty ); + mandatory( jo, was_loaded, "sight_penalty", sight_penalty ); + mandatory( jo, was_loaded, "light_modifier", light_modifier ); + + mandatory( jo, was_loaded, "sound_attn", sound_attn ); + mandatory( jo, was_loaded, "dangerous", dangerous ); + mandatory( jo, was_loaded, "precip", precip ); + mandatory( jo, was_loaded, "rains", rains ); + optional( jo, was_loaded, "acidic", acidic, false ); + optional( jo, was_loaded, "tiles_animation", tiles_animation, "" ); + optional( jo, was_loaded, "sound_category", sound_category, weather_sound_category::silent ); + mandatory( jo, was_loaded, "sun_intensity", sun_intensity ); + + for( const JsonObject weather_effect_jo : jo.get_array( "effects" ) ) { + + weather_effect effect; + + optional( weather_effect_jo, was_loaded, "message", effect.message ); + optional( weather_effect_jo, was_loaded, "sound_message", effect.sound_message ); + optional( weather_effect_jo, was_loaded, "sound_effect", effect.sound_effect, "" ); + mandatory( weather_effect_jo, was_loaded, "must_be_outside", effect.must_be_outside ); + optional( weather_effect_jo, was_loaded, "one_in_chance", effect.one_in_chance, -1 ); + optional( weather_effect_jo, was_loaded, "time_between", effect.time_between ); + optional( weather_effect_jo, was_loaded, "lightning", effect.lightning, false ); + optional( weather_effect_jo, was_loaded, "rain_proof", effect.rain_proof, false ); + optional( weather_effect_jo, was_loaded, "pain_max", effect.pain_max, INT_MAX ); + optional( weather_effect_jo, was_loaded, "pain", effect.pain, 0 ); + optional( weather_effect_jo, was_loaded, "wet", effect.wet, 0 ); + optional( weather_effect_jo, was_loaded, "radiation", effect.radiation, 0 ); + optional( weather_effect_jo, was_loaded, "healthy", effect.healthy, 0 ); + optional( weather_effect_jo, was_loaded, "effect_id", effect.effect_id ); + optional( weather_effect_jo, was_loaded, "effect_duration", effect.effect_duration ); + optional( weather_effect_jo, was_loaded, "trait_id_to_add", effect.trait_id_to_add ); + optional( weather_effect_jo, was_loaded, "trait_id_to_remove", effect.trait_id_to_remove ); + optional( weather_effect_jo, was_loaded, "target_part", effect.target_part ); + optional( weather_effect_jo, was_loaded, "damage", effect.damage, 0 ); + for( const JsonObject field_jo : weather_effect_jo.get_array( "fields" ) ) { + weather_field new_field; + mandatory( field_jo, was_loaded, "type", new_field.type ); + mandatory( field_jo, was_loaded, "intensity", new_field.intensity ); + mandatory( field_jo, was_loaded, "age", new_field.age ); + optional( field_jo, was_loaded, "outdoor_only", new_field.outdoor_only, true ); + optional( field_jo, was_loaded, "radius", new_field.radius, 10000000 ); + + effect.fields.emplace_back( new_field ); + } + for( const JsonObject spawn_jo : weather_effect_jo.get_array( "spawns" ) ) { + spawn_type spawn; + mandatory( spawn_jo, was_loaded, "max_radius", spawn.max_radius ); + mandatory( spawn_jo, was_loaded, "min_radius", spawn.min_radius ); + optional( spawn_jo, was_loaded, "hallucination_count", spawn.hallucination_count, 0 ); + optional( spawn_jo, was_loaded, "real_count", spawn.real_count, 0 ); + optional( spawn_jo, was_loaded, "target", spawn.target ); + optional( spawn_jo, was_loaded, "target_range", spawn.target_range, 30 ); + + effect.spawns.emplace_back( spawn ); + } + effects.emplace_back( effect ); + } + weather_animation = { 0.0f, c_white, '?' }; + if( jo.has_member( "weather_animation" ) ) { + JsonObject weather_animation_jo = jo.get_object( "weather_animation" ); + weather_animation_t animation; + mandatory( weather_animation_jo, was_loaded, "factor", animation.factor ); + if( !assign( weather_animation_jo, "color", animation.color ) ) { + weather_animation_jo.throw_error( "missing mandatory member \"color\"" ); + } + mandatory( weather_animation_jo, was_loaded, "glyph", glyph ); + if( glyph.size() != 1 ) { + weather_animation_jo.throw_error( "glyph must be only one character" ); + } else { + animation.glyph = glyph[0]; + } + weather_animation = animation; + } + + requirements = {}; + if( jo.has_member( "requirements" ) ) { + JsonObject weather_requires = jo.get_object( "requirements" ); + weather_requirements new_requires; + + optional( weather_requires, was_loaded, "pressure_min", new_requires.pressure_min, INT_MIN ); + optional( weather_requires, was_loaded, "pressure_max", new_requires.pressure_max, INT_MAX ); + optional( weather_requires, was_loaded, "humidity_min", new_requires.humidity_min, INT_MIN ); + optional( weather_requires, was_loaded, "humidity_max", new_requires.humidity_max, INT_MAX ); + optional( weather_requires, was_loaded, "temperature_min", new_requires.temperature_min, INT_MIN ); + optional( weather_requires, was_loaded, "temperature_max", new_requires.temperature_max, INT_MAX ); + optional( weather_requires, was_loaded, "windpower_min", new_requires.windpower_min, INT_MIN ); + optional( weather_requires, was_loaded, "windpower_max", new_requires.windpower_max, INT_MAX ); + optional( weather_requires, was_loaded, "humidity_and_pressure", new_requires.humidity_and_pressure, + true ); + optional( weather_requires, was_loaded, "acidic", new_requires.acidic, false ); + optional( weather_requires, was_loaded, "time", new_requires.time, + weather_time_requirement_type::both ); + for( const std::string &required_weather : + weather_requires.get_string_array( "required_weathers" ) ) { + new_requires.required_weathers.push_back( weather_type_id( required_weather ) ); + } + requirements = new_requires; + } +} + +void weather_types::reset() +{ + weather_type_factory.reset(); +} + +void weather_types::finalize_all() +{ + weather_type_factory.finalize(); + for( const weather_type &wt : weather_type_factory.get_all() ) { + const_cast( wt ).finalize(); + } +} + +const std::vector &weather_types::get_all() +{ + return weather_type_factory.get_all(); +} + +void weather_types::check_consistency() +{ + if( !WEATHER_CLEAR.is_valid() ) { + debugmsg( "Weather type clear is required." ); + abort(); + } + if( !WEATHER_NULL.is_valid() ) { + debugmsg( "Weather type null is required." ); + abort(); + } + weather_type_factory.check(); +} + +void weather_types::load( const JsonObject &jo, const std::string &src ) +{ + weather_type_factory.load( jo, src ); +} + diff --git a/src/weather_type.h b/src/weather_type.h new file mode 100644 index 0000000000000..bc81fedc2668b --- /dev/null +++ b/src/weather_type.h @@ -0,0 +1,175 @@ +#pragma once +#ifndef CATA_SRC_WEATHER_TYPE_H +#define CATA_SRC_WEATHER_TYPE_H + +#include + +#include "bodypart.h" +#include "field.h" +#include "generic_factory.h" +#include "translations.h" +#include "type_id.h" + +const weather_type_id WEATHER_NULL( "null" ); +const weather_type_id WEATHER_CLEAR( "clear" ); + +enum class precip_class : int { + none, + very_light, + light, + heavy, + last +}; +template<> +struct enum_traits { + static constexpr precip_class last = precip_class::last; +}; + +enum class sun_intensity_type : int { + none, + light, + normal, + high, + last +}; +template<> +struct enum_traits { + static constexpr sun_intensity_type last = sun_intensity_type::last; +}; + +enum class weather_time_requirement_type : int { + day, + night, + both, + last +}; +template<> +struct enum_traits { + static constexpr weather_time_requirement_type last = weather_time_requirement_type::last; +}; + + +enum weather_sound_category : int { + silent, + drizzle, + rainy, + thunder, + flurries, + snowstorm, + snow, + last +}; + +template<> +struct enum_traits { + static constexpr weather_sound_category last = weather_sound_category::last; +}; + +/** + * Weather animation class. + */ +struct weather_animation_t { + float factor; + nc_color color; + char glyph; +}; + +struct weather_requirements { + int windpower_min = INT_MIN; + int windpower_max = INT_MAX; + int temperature_min = INT_MIN; + int temperature_max = INT_MAX; + int pressure_min = INT_MIN; + int pressure_max = INT_MAX; + int humidity_min = INT_MIN; + int humidity_max = INT_MAX; + bool humidity_and_pressure = true; + bool acidic = false; + weather_time_requirement_type time; + std::vector required_weathers; +}; + +struct weather_field { + field_type_str_id type; + int intensity; + time_duration age; + int radius; + bool outdoor_only; +}; + +struct spawn_type { + mtype_id target; + int target_range; + int hallucination_count; + int real_count; + int min_radius; + int max_radius; +}; + +struct weather_effect { + int one_in_chance; + time_duration time_between; + translation message; + bool must_be_outside; + translation sound_message; + std::string sound_effect; + bool lightning; + bool rain_proof; + int pain; + int pain_max; + int wet; + int radiation; + int healthy; + efftype_id effect_id; + time_duration effect_duration; + trait_id trait_id_to_add; + trait_id trait_id_to_remove; + bodypart_str_id target_part; + int damage; + std::vector spawns; + std::vector fields; +}; + +struct weather_type { + public: + friend class generic_factory; + bool was_loaded = false; + weather_type_id id; + std::string name; //!< UI name of weather type. + nc_color color; //!< UI color of weather type. + nc_color map_color; //!< Map color of weather type. + char glyph; //!< Map glyph of weather type. + int ranged_penalty; //!< Penalty to ranged attacks. + float sight_penalty; //!< Penalty to per-square visibility, applied in transparency map. + int light_modifier; //!< Modification to ambient light. + int sound_attn; //!< Sound attenuation of a given weather type. + bool dangerous; //!< If true, our activity gets interrupted. + precip_class precip; //!< Amount of associated precipitation. + bool rains; //!< Whether said precipitation falls as rain. + bool acidic; //!< Whether said precipitation is acidic. + std::vector effects; //!< vector for weather effects. + std::string tiles_animation; //!< string for tiles animation + weather_animation_t weather_animation; //!< Information for weather animations + weather_sound_category sound_category; //!< if playing sound effects what to use + sun_intensity_type sun_intensity; //!< strength of the sun + weather_requirements requirements; //!< when this weather should happen + + void load( const JsonObject &jo, const std::string &src ); + void finalize(); + void check() const; + weather_type() = default; +}; +namespace weather_types +{ +/** Get all currently loaded weather types */ +const std::vector &get_all(); +/** Finalize all loaded weather types */ +void finalize_all(); +/** Clear all loaded weather types (invalidating any pointers) */ +void reset(); +/** Load weather type from JSON definition */ +void load( const JsonObject &jo, const std::string &src ); +/** Checks all loaded from JSON are valid */ +void check_consistency(); +} // namespace weather_types +#endif // CATA_SRC_WEATHER_TYPE_H diff --git a/src/wish.cpp b/src/wish.cpp index 1c8691355e6ad..28284f0a2b7d3 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -409,7 +409,7 @@ void debug_menu::wishmonster( const cata::optional &p ) const mtype_id &mon_type = mtypes[ wmenu.ret ]->id; if( cata::optional spawn = p ? p : g->look_around() ) { int num_spawned = 0; - for( const tripoint &destination : closest_tripoints_first( *spawn, cb.group ) ) { + for( const tripoint &destination : closest_points_first( *spawn, cb.group ) ) { monster *const mon = g->place_critter_at( mon_type, destination ); if( !mon ) { continue; @@ -594,16 +594,24 @@ void debug_menu::wishitem( player *p, const tripoint &pos ) if( granted.count_by_charges() ) { if( amount > 0 ) { granted.charges = amount; - p->i_add( granted ); + if( p->can_stash( granted ) ) { + p->i_add( granted ); + } else { + get_map().add_item_or_charges( p->pos(), granted ); + } } } else { for( int i = 0; i < amount; i++ ) { - p->i_add( granted ); + if( p->can_stash( granted ) ) { + p->i_add( granted ); + } else { + get_map().add_item_or_charges( p->pos(), granted ); + } } } p->invalidate_crafting_inventory(); } else if( pos.x >= 0 && pos.y >= 0 ) { - g->m.add_item_or_charges( pos, granted ); + get_map().add_item_or_charges( pos, granted ); wmenu.ret = -1; } if( amount > 0 ) { diff --git a/tests/active_item_cache_test.cpp b/tests/active_item_cache_test.cpp index 7b518b842b571..dcea4669b4912 100644 --- a/tests/active_item_cache_test.cpp +++ b/tests/active_item_cache_test.cpp @@ -3,7 +3,6 @@ #include "calendar.h" #include "catch/catch.hpp" -#include "game.h" #include "game_constants.h" #include "item.h" #include "map.h" @@ -13,14 +12,15 @@ TEST_CASE( "place_active_item_at_various_coordinates", "[item]" ) { clear_map(); + map &here = get_map(); for( int z = -OVERMAP_DEPTH; z < OVERMAP_HEIGHT; ++z ) { for( int x = 0; x < MAPSIZE_X; ++x ) { for( int y = 0; y < MAPSIZE_Y; ++y ) { - g->m.i_clear( { x, y, z } ); + here.i_clear( { x, y, z } ); } } } - REQUIRE( g->m.get_submaps_with_active_items().empty() ); + REQUIRE( here.get_submaps_with_active_items().empty() ); // An arbitrary active item. item active( "firecracker_act", 0, item::default_charges_tag() ); active.activate(); @@ -29,20 +29,20 @@ TEST_CASE( "place_active_item_at_various_coordinates", "[item]" ) int z = 0; for( int x = 0; x < MAPSIZE_X; ++x ) { for( int y = 0; y < MAPSIZE_Y; ++y ) { - REQUIRE( g->m.i_at( { x, y, z } ).empty() ); + REQUIRE( here.i_at( { x, y, z } ).empty() ); CAPTURE( x, y, z ); - tripoint abs_loc = g->m.get_abs_sub() + tripoint( x / SEEX, y / SEEY, z ); + tripoint abs_loc = here.get_abs_sub() + tripoint( x / SEEX, y / SEEY, z ); CAPTURE( abs_loc.x, abs_loc.y, abs_loc.z ); - REQUIRE( g->m.get_submaps_with_active_items().empty() ); - REQUIRE( g->m.get_submaps_with_active_items().find( abs_loc ) == - g->m.get_submaps_with_active_items().end() ); - item &item_ref = g->m.add_item( { x, y, z }, active ); + REQUIRE( here.get_submaps_with_active_items().empty() ); + REQUIRE( here.get_submaps_with_active_items().find( abs_loc ) == + here.get_submaps_with_active_items().end() ); + item &item_ref = here.add_item( { x, y, z }, active ); REQUIRE( item_ref.active ); - REQUIRE_FALSE( g->m.get_submaps_with_active_items().empty() ); - REQUIRE( g->m.get_submaps_with_active_items().find( abs_loc ) != - g->m.get_submaps_with_active_items().end() ); - REQUIRE_FALSE( g->m.i_at( { x, y, z } ).empty() ); - g->m.i_clear( { x, y, z } ); + REQUIRE_FALSE( here.get_submaps_with_active_items().empty() ); + REQUIRE( here.get_submaps_with_active_items().find( abs_loc ) != + here.get_submaps_with_active_items().end() ); + REQUIRE_FALSE( here.i_at( { x, y, z } ).empty() ); + here.i_clear( { x, y, z } ); } } } diff --git a/tests/active_item_test.cpp b/tests/active_item_test.cpp new file mode 100644 index 0000000000000..18fa63411c168 --- /dev/null +++ b/tests/active_item_test.cpp @@ -0,0 +1,43 @@ +#include "avatar.h" +#include "catch/catch.hpp" +#include "item.h" +#include "map.h" +#include "map_helpers.h" +#include "player_helpers.h" +#include "point.h" + +TEST_CASE( "active_items_processed_regularly", "[item]" ) +{ + clear_avatar(); + clear_map(); + avatar &player_character = get_avatar(); + map &here = get_map(); + // An arbitrary active item that ticks every turn. + item active_item( "firecracker_act", 0, 5 ); + active_item.activate(); + const int active_item_ticks = active_item.charges; + item storage( "backpack", 0 ); + cata::optional::iterator> wear_success = player_character.wear_item( storage ); + REQUIRE( wear_success ); + + item *inventory_item = player_character.try_add( active_item ); + REQUIRE( inventory_item != nullptr ); + REQUIRE( inventory_item->charges == active_item_ticks ); + + bool wield_success = player_character.wield( active_item ); + REQUIRE( wield_success ); + REQUIRE( player_character.weapon.charges == active_item_ticks ); + + here.add_item( player_character.pos(), active_item ); + REQUIRE( here.i_at( player_character.pos() ).only_item().charges == active_item_ticks ); + // TODO: spawn a vehicle and stash a firecracker in there too. + + // Call item processing entry points. + here.process_items(); + player_character.process_items(); + + const int expected_ticks = active_item_ticks - 1; + CHECK( inventory_item->charges == expected_ticks ); + CHECK( player_character.weapon.charges == expected_ticks ); + CHECK( here.i_at( player_character.pos() ).only_item().charges == expected_ticks ); +} diff --git a/tests/ammo_test.cpp b/tests/ammo_test.cpp new file mode 100644 index 0000000000000..f0848cf3dc13a --- /dev/null +++ b/tests/ammo_test.cpp @@ -0,0 +1,188 @@ +#include "item.h" +#include "itype.h" + +#include "catch/catch.hpp" + +// Functions: +// - item::ammo_types +// +// TODO: +// - ammo_type +// - common_ammo_default +// - ammo_sort_name + +// item::ammo_types returns the ammo types an item may *contain*, which is distinct from the ammo +// types an item may *use*. +// +// Only magazines have ammo_types(). +// +// Tools, tool mods, and (all other item types?) have empty ammo_types() + + +// Return true if the given item has non-empty ammo_types +static bool has_ammo_types( const item &it ) +{ + return !it.ammo_types().empty(); +} + +TEST_CASE( "ammo types", "[ammo][ammo_types]" ) +{ + // Only a few kinds of item have ammo_types: + // - Items with type=MAGAZINE (including batteries as well as gun magazines) + // - Tools/weapons with magazine_integral (pocket_data has a MAGAZINE rather than MAGAZINE_WELL) + + SECTION( "items with MAGAZINE pockets have ammo_types" ) { + // Batteries are magazines + REQUIRE( item( "light_battery_cell" ).is_magazine() ); + REQUIRE( item( "battery_car" ).is_magazine() ); + + // Tool batteries + CHECK( has_ammo_types( item( "light_battery_cell" ) ) ); + CHECK( has_ammo_types( item( "medium_battery_cell" ) ) ); + CHECK( has_ammo_types( item( "heavy_battery_cell" ) ) ); + CHECK( has_ammo_types( item( "light_disposable_cell" ) ) ); + CHECK( has_ammo_types( item( "medium_disposable_cell" ) ) ); + CHECK( has_ammo_types( item( "heavy_disposable_cell" ) ) ); + // Vehicle batteries + CHECK( has_ammo_types( item( "battery_car" ) ) ); + CHECK( has_ammo_types( item( "battery_motorbike" ) ) ); + CHECK( has_ammo_types( item( "large_storage_battery" ) ) ); + + SECTION( "battery magazines include 'battery' ammo type" ) { + CHECK( item( "light_battery_cell" ).ammo_types().count( ammotype( "battery" ) ) == 1 ); + CHECK( item( "battery_car" ).ammo_types().count( ammotype( "battery" ) ) == 1 ); + } + + // Gun magazines + REQUIRE( item( "belt40mm" ).is_magazine() ); + REQUIRE( item( "akmag10" ).is_magazine() ); + + CHECK( has_ammo_types( item( "belt40mm" ) ) ); + CHECK( has_ammo_types( item( "belt308" ) ) ); + CHECK( has_ammo_types( item( "akmag10" ) ) ); + CHECK( has_ammo_types( item( "akdrum75" ) ) ); + CHECK( has_ammo_types( item( "glockmag" ) ) ); + + SECTION( "gun magazines include ammo type for that magazine" ) { + CHECK( item( "glockmag" ).ammo_types().count( ammotype( "9mm" ) ) == 1 ); + CHECK( item( "akmag10" ).ammo_types().count( ammotype( "762" ) ) == 1 ); + } + } + + SECTION( "GUN items with integral MAGAZINE pockets have ammo_types" ) { + REQUIRE( item( "nailgun" ).magazine_integral() ); + REQUIRE( item( "colt_army" ).magazine_integral() ); + + CHECK( has_ammo_types( item( "nailgun" ) ) ); + CHECK( has_ammo_types( item( "colt_army" ) ) ); + CHECK( has_ammo_types( item( "hand_crossbow" ) ) ); + CHECK( has_ammo_types( item( "compositebow" ) ) ); + CHECK( has_ammo_types( item( "sling" ) ) ); + CHECK( has_ammo_types( item( "slingshot" ) ) ); + } + + SECTION( "TOOL items with integral MAGAZINE pockets have ammo_types" ) { + REQUIRE( item( "sewing_kit" ).magazine_integral() ); + + CHECK( has_ammo_types( item( "needle_bone" ) ) ); + CHECK( has_ammo_types( item( "needle_wood" ) ) ); + CHECK( has_ammo_types( item( "sewing_kit" ) ) ); + CHECK( has_ammo_types( item( "tailors_kit" ) ) ); + } + + SECTION( "TOOL items with NO pockets have ammo_types" ) { + // NOTE: Fish trap is a TOOL with "ammo", but no "pocket_data", so an implicit MAGAZINE + // pocket is added by Item_factory::check_and_create_magazine_pockets on JSON load. + // This item would be considered needing data migration to an explicit MAGAZINE pocket. + REQUIRE( item( "fish_trap" ).magazine_integral() ); + + CHECK( has_ammo_types( item( "fish_trap" ) ) ); + } + + // These items have NO ammo_types: + + SECTION( "GUN items with MAGAZINE_WELL pockets do NOT have ammo_types" ) { + REQUIRE_FALSE( item( "m1911" ).magazine_integral() ); + + CHECK_FALSE( has_ammo_types( item( "m1911" ) ) ); + CHECK_FALSE( has_ammo_types( item( "usp_9mm" ) ) ); + CHECK_FALSE( has_ammo_types( item( "tommygun" ) ) ); + CHECK_FALSE( has_ammo_types( item( "ak74" ) ) ); + CHECK_FALSE( has_ammo_types( item( "ak47" ) ) ); + } + + SECTION( "TOOL items with MAGAZINE_WELL pockets do NOT have ammo_types" ) { + REQUIRE( item( "flashlight" ).is_tool() ); + + CHECK_FALSE( has_ammo_types( item( "flashlight" ) ) ); + CHECK_FALSE( has_ammo_types( item( "hotplate" ) ) ); + CHECK_FALSE( has_ammo_types( item( "vac_sealer" ) ) ); + CHECK_FALSE( has_ammo_types( item( "forge" ) ) ); + CHECK_FALSE( has_ammo_types( item( "cordless_drill" ) ) ); + } + + SECTION( "AMMO items themselves do NOT have ammo_types" ) { + REQUIRE( item( "38_special" ).is_ammo() ); + REQUIRE( item( "sinew" ).is_ammo() ); + + // Ammo for guns + CHECK_FALSE( has_ammo_types( item( "38_special" ) ) ); + CHECK_FALSE( has_ammo_types( item( "reloaded_308" ) ) ); + CHECK_FALSE( has_ammo_types( item( "bp_9mm" ) ) ); + CHECK_FALSE( has_ammo_types( item( "44magnum" ) ) ); + // Not for guns but classified as ammo + CHECK_FALSE( has_ammo_types( item( "sinew" ) ) ); + CHECK_FALSE( has_ammo_types( item( "nail" ) ) ); + CHECK_FALSE( has_ammo_types( item( "rock" ) ) ); + CHECK_FALSE( has_ammo_types( item( "solder_wire" ) ) ); + } + + SECTION( "TOOLMOD items do NOT have ammo_types" ) { + item med_mod( "magazine_battery_medium_mod" ); + REQUIRE( med_mod.is_toolmod() ); + + CHECK_FALSE( has_ammo_types( med_mod ) ); + } +} + +// The same items with no ammo_types, also have no ammo_default. +TEST_CASE( "ammo default", "[ammo][ammo_default]" ) +{ + // TOOLMOD type, and TOOL/GUN type items with MAGAZINE_WELL pockets have no ammo_default + SECTION( "items without ammo_default" ) { + item flashlight( "flashlight" ); + item med_mod( "magazine_battery_medium_mod" ); + item tommygun( "tommygun" ); + + CHECK( flashlight.ammo_default().is_null() ); + CHECK( med_mod.ammo_default().is_null() ); + CHECK( tommygun.ammo_default().is_null() ); + } + + // MAGAZINE type, and TOOL/GUN items with integral MAGAZINE pockets do have ammo_default + SECTION( "items with ammo_default" ) { + // MAGAZINE type items + item battery( "light_battery_cell" ); + item glockmag( "glockmag" ); + CHECK( battery.ammo_default() == itype_id( "battery" ) ); + CHECK( glockmag.ammo_default() == itype_id( "9mm" ) ); + + // TOOL type items with integral magazines + item sewing_kit( "sewing_kit" ); + item needle( "needle_bone" ); + item fishtrap( "fish_trap" ); + CHECK( sewing_kit.ammo_default() == itype_id( "thread" ) ); + CHECK( needle.ammo_default() == itype_id( "thread" ) ); + CHECK( fishtrap.ammo_default() == itype_id( "fish_bait" ) ); + + // GUN type items with integral magazine + item slingshot( "slingshot" ); + item colt( "colt_army" ); + item lemat( "lemat_revolver" ); + CHECK( slingshot.ammo_default() == itype_id( "pebble" ) ); + // Revolver ammo is "44paper" but default ammunition type is "44army" + CHECK( colt.ammo_default() == itype_id( "44army" ) ); + CHECK( lemat.ammo_default() == itype_id( "44army" ) ); + } +} + diff --git a/tests/battery_mod_test.cpp b/tests/battery_mod_test.cpp new file mode 100644 index 0000000000000..4fe26e66fea28 --- /dev/null +++ b/tests/battery_mod_test.cpp @@ -0,0 +1,315 @@ +#include "item.h" +#include "itype.h" + +#include "catch/catch.hpp" + +// Includes functions: +// item::magazine_compatible +// item::magazine_default +// item::magazine_integral +// item::is_reloadable +// item::is_reloadable_with +// item::toolmods +// +// item::ammo_type +// item::ammo_types +// item::ammo_default +// item::ammo_remaining +// item::ammo_capacity +// +// Attributes: +// item.type->mod->acceptable_ammo +// item.type->mod->magazine_adaptor +// item.type->tool->ammo_id +// +// Related JSON fields: +// "ammo_type" +// "acceptable_ammo" +// "ammo_restriction" +// "magazine_adaptor" +// +TEST_CASE( "battery tool mod test", "[battery][mod]" ) +{ + item med_mod( "magazine_battery_medium_mod" ); + + SECTION( "battery mod properties" ) { + // Is a toolmod, and nothing else + CHECK( med_mod.is_toolmod() ); + CHECK_FALSE( med_mod.is_gun() ); + CHECK_FALSE( med_mod.is_tool() ); + CHECK_FALSE( med_mod.is_magazine() ); + + // Mod can be installed on items using battery ammotype + CHECK( med_mod.type->mod->acceptable_ammo.count( ammotype( "battery" ) ) == 1 ); + // The battery mod does not use ammo_modifier (since it gives explicit battery ids) + CHECK( med_mod.type->mod->ammo_modifier.empty() ); + + // And has some magazine adaptors + CHECK_FALSE( med_mod.type->mod->magazine_adaptor.empty() ); + // Mod itself has no ammo types + CHECK( med_mod.ammo_types().empty() ); + + // No tool mods + CHECK( med_mod.toolmods().empty() ); + + // Mods are not directly compatible with magazines, nor reloadable + CHECK( med_mod.magazine_compatible().empty() ); + CHECK_FALSE( med_mod.is_reloadable() ); + CHECK_FALSE( med_mod.is_reloadable_with( itype_id( "battery" ) ) ); + + // Mod magazine is not integral + CHECK_FALSE( med_mod.magazine_integral() ); + } + + GIVEN( "tool compatible with light batteries" ) { + item flashlight( "flashlight" ); + REQUIRE( flashlight.is_reloadable() ); + REQUIRE( flashlight.is_reloadable_with( itype_id( "light_battery_cell" ) ) ); + + // Flashlight must be free of battery or existing mods + REQUIRE_FALSE( flashlight.magazine_current() ); + REQUIRE( flashlight.toolmods().empty() ); + // Needs a MOD pocket to allow modding + REQUIRE( flashlight.contents.has_pocket_type( item_pocket::pocket_type::MOD ) ); + + WHEN( "medium battery mod is installed" ) { + med_mod.item_tags.insert( "IRREMOVABLE" ); + flashlight.put_in( med_mod, item_pocket::pocket_type::MOD ); + + THEN( "tool modification is successful" ) { + CHECK_FALSE( flashlight.toolmods().empty() ); + CHECK_FALSE( flashlight.magazine_compatible().empty() ); + + CHECK( flashlight.tname() == "flashlight (off)+1" ); + } + + + THEN( "medium batteries can be installed" ) { + CHECK( flashlight.is_reloadable() ); + CHECK( flashlight.is_reloadable_with( itype_id( "medium_battery_cell" ) ) ); + const std::set mag_compats = flashlight.magazine_compatible(); + CHECK( mag_compats.count( itype_id( "medium_battery_cell" ) ) == 1 ); + CHECK( mag_compats.count( itype_id( "medium_plus_battery_cell" ) ) == 1 ); + CHECK( mag_compats.count( itype_id( "medium_atomic_battery_cell" ) ) == 1 ); + CHECK( mag_compats.count( itype_id( "medium_disposable_cell" ) ) == 1 ); + CHECK( flashlight.contents.has_pocket_type( item_pocket::pocket_type::MAGAZINE_WELL ) == 1 ); + } + + THEN( "medium battery is now the default" ) { + // FIXME: Required to fix #40948 + itype_id mag_default = flashlight.magazine_default( false ); + CHECK_FALSE( mag_default.is_null() ); + CHECK( mag_default.str() == "medium_atomic_battery_cell" ); + } + + THEN( "light batteries no longer fit" ) { + CHECK_FALSE( flashlight.is_reloadable_with( itype_id( "light_battery_cell" ) ) ); + CHECK_FALSE( flashlight.magazine_compatible().count( itype_id( "light_battery_cell" ) ) ); + } + + AND_WHEN( "a medium battery is installed" ) { + item med_battery( "medium_battery_cell" ); + + THEN( "battery installation succeeds" ) { + ret_val result = flashlight.put_in( med_battery, item_pocket::pocket_type::MAGAZINE_WELL ); + // FIXME: Required to fix #40948 + CHECK( result.success() ); + } + + THEN( "the flashlight has a battery" ) { + flashlight.put_in( med_battery, item_pocket::pocket_type::MAGAZINE_WELL ); + // FIXME: Required to fix #40948 + CHECK( flashlight.magazine_current() ); + } + + AND_WHEN( "the battery is charged" ) { + const int bat_charges = med_battery.ammo_capacity( ammotype( "battery" ) ); + med_battery.ammo_set( med_battery.ammo_default(), bat_charges ); + REQUIRE( med_battery.ammo_remaining() == bat_charges ); + flashlight.put_in( med_battery, item_pocket::pocket_type::MAGAZINE_WELL ); + + THEN( "the flashlight has charges" ) { + // FIXME: Required to fix #40948 + CHECK( flashlight.ammo_remaining() == bat_charges ); + } + } + } + } + } +} + +// This test exercises several item functions related to battery-powered tools. +// +// Tool battery compartments and battery charge use terms derived from firearms, thus: +// +// - Batteries are "magazines" +// - Have "ammo types" compatible with them +// - Can be reloaded with "ammo" (battery charges) +// - Charge left in the battery is "ammo remaining" +// +// - Tools have a "magazine well" (battery compartment) +// - Can be reloaded with a compatible "magazine" (battery) +// - Charge left in the tool's battery is "ammo remaining" +// +TEST_CASE( "battery and tool properties", "[battery][tool][properties]" ) +{ + const item bat_cell( "light_battery_cell" ); + const item flashlight( "flashlight" ); + + // In JSON, "battery" is both an "ammunition_type" (ammo_types.json) and an "AMMO" (ammo.json) + const ammotype bat_ammotype( "battery" ); + const itype_id bat_ammo( "battery" ); + + SECTION( "battery cell" ) { + SECTION( "is a magazine" ) { + CHECK( bat_cell.is_magazine() ); + } + + SECTION( "is not a tool" ) { + CHECK_FALSE( bat_cell.is_tool() ); + } + + SECTION( "is not ammo" ) { + CHECK_FALSE( bat_cell.is_ammo() ); + // Non-ammo itself does not have an ammo type + CHECK( bat_cell.ammo_type() == ammotype::NULL_ID() ); + } + + SECTION( "has compatible ammo types" ) { + const std::set bat_ammos = bat_cell.ammo_types(); + CHECK_FALSE( bat_ammos.empty() ); + CHECK( bat_ammos.count( bat_ammotype ) ); + } + + SECTION( "has capacity to hold battery ammo type" ) { + CHECK( bat_cell.ammo_capacity( bat_ammotype ) > 0 ); + } + + SECTION( "has battery ammo as default" ) { + CHECK( bat_cell.ammo_default() == bat_ammo ); + } + + SECTION( "is reloadable with battery ammo" ) { + CHECK( bat_cell.is_reloadable() ); + CHECK( bat_cell.is_reloadable_with( bat_ammo ) ); + } + + SECTION( "is not counted by charges" ) { + CHECK_FALSE( bat_cell.count_by_charges() ); + } + } + + SECTION( "flashlight" ) { + SECTION( "is a tool" ) { + CHECK( flashlight.is_tool() ); + } + + SECTION( "is not a magazine" ) { + CHECK_FALSE( flashlight.is_magazine() ); + CHECK_FALSE( flashlight.magazine_integral() ); + } + + SECTION( "is not ammo" ) { + CHECK_FALSE( flashlight.is_ammo() ); + // Non-ammo itself does not have an ammo type + CHECK( flashlight.ammo_type() == ammotype::NULL_ID() ); + } + + SECTION( "is reloadable with a magazine" ) { + CHECK( flashlight.is_reloadable() ); + CHECK( flashlight.is_reloadable_with( itype_id( "light_battery_cell" ) ) ); + CHECK( flashlight.is_reloadable_with( itype_id( "light_disposable_cell" ) ) ); + } + + SECTION( "has compatible magazines" ) { + const std::set mag_compats = flashlight.magazine_compatible(); + CHECK_FALSE( mag_compats.empty() ); + CHECK( mag_compats.count( itype_id( "light_battery_cell" ) ) == 1 ); + CHECK( mag_compats.count( itype_id( "light_disposable_cell" ) ) == 1 ); + CHECK( mag_compats.count( itype_id( "light_plus_battery_cell" ) ) == 1 ); + CHECK( mag_compats.count( itype_id( "light_atomic_battery_cell" ) ) == 1 ); + } + + SECTION( "has a default magazine" ) { + itype_id mag_default = flashlight.magazine_default( false ); + CHECK_FALSE( mag_default.is_null() ); + // FIXME: Required to fix #40800 + CHECK( mag_default.str() == "light_atomic_battery_cell" ); + } + + SECTION( "can use battery ammo" ) { + // Since flashlights get their "ammo" from a "magazine", their ammo_types is empty + CHECK( flashlight.ammo_types().empty() ); + CHECK( flashlight.ammo_default().is_null() ); + + // The ammo a flashlight can *use* is given by type->tool->ammo_id + CHECK_FALSE( flashlight.type->tool->ammo_id.empty() ); + CHECK( flashlight.type->tool->ammo_id.count( ammotype( "battery" ) ) == 1 ); + } + + SECTION( "requires some ammo (charge) to use" ) { + CHECK( flashlight.ammo_required() > 0 ); + } + + SECTION( "is not counted by charges" ) { + CHECK_FALSE( flashlight.count_by_charges() ); + } + } +} + +TEST_CASE( "installing battery in tool", "[battery][tool][install]" ) +{ + item bat_cell( "light_battery_cell" ); + item flashlight( "flashlight" ); + + const int bat_charges = bat_cell.ammo_capacity( ammotype( "battery" ) ); + REQUIRE( bat_charges > 0 ); + + SECTION( "flashlight with no battery installed" ) { + REQUIRE( !flashlight.magazine_current() ); + + CHECK( flashlight.ammo_remaining() == 0 ); + CHECK( flashlight.ammo_capacity( ammotype( "battery" ) ) == 0 ); + CHECK( flashlight.remaining_ammo_capacity() == 0 ); + } + + SECTION( "dead battery installed in flashlight" ) { + // Ensure battery is dead + bat_cell.ammo_set( bat_cell.ammo_default(), 0 ); + REQUIRE( bat_cell.ammo_remaining() == 0 ); + + // Put battery in flashlight + REQUIRE( flashlight.contents.has_pocket_type( item_pocket::pocket_type::MAGAZINE_WELL ) ); + ret_val result = flashlight.put_in( bat_cell, item_pocket::pocket_type::MAGAZINE_WELL ); + CHECK( result.success() ); + CHECK( flashlight.magazine_current() ); + + // No remaining ammo + CHECK( flashlight.ammo_remaining() == 0 ); + } + + SECTION( "charged battery installed in flashlight" ) { + // Charge the battery + bat_cell.ammo_set( bat_cell.ammo_default(), bat_charges ); + REQUIRE( bat_cell.ammo_remaining() == bat_charges ); + + // Put battery in flashlight + REQUIRE( flashlight.contents.has_pocket_type( item_pocket::pocket_type::MAGAZINE_WELL ) ); + ret_val result = flashlight.put_in( bat_cell, item_pocket::pocket_type::MAGAZINE_WELL ); + CHECK( result.success() ); + CHECK( flashlight.magazine_current() ); + + // Flashlight has a full charge + CHECK( flashlight.ammo_remaining() == bat_charges ); + } + + SECTION( "wrong size battery for flashlight" ) { + item med_bat_cell( "medium_battery_cell" ); + + // Should fail to install the magazine + REQUIRE( flashlight.contents.has_pocket_type( item_pocket::pocket_type::MAGAZINE_WELL ) ); + ret_val result = flashlight.put_in( med_bat_cell, item_pocket::pocket_type::MAGAZINE_WELL ); + CHECK_FALSE( result.success() ); + CHECK_FALSE( flashlight.magazine_current() ); + } +} diff --git a/tests/cata_generators.cpp b/tests/cata_generators.cpp new file mode 100644 index 0000000000000..ede6a7838c2b6 --- /dev/null +++ b/tests/cata_generators.cpp @@ -0,0 +1,67 @@ +#include "cata_generators.h" + +#include "point.h" +#include "rng.h" + +class RandomPointGenerator final : + public Catch::Generators::IGenerator +{ + public: + RandomPointGenerator( int low, int high ) : + engine( rng_get_engine() ), + dist( low, high ) { + this->next(); + } + + const point &get() const override { + return current_point; + } + + bool next() override { + current_point = point( dist( engine ), dist( engine ) ); + return true; + } + protected: + cata_default_random_engine &engine; + std::uniform_int_distribution<> dist; + point current_point; +}; + +class RandomTripointGenerator final : + public Catch::Generators::IGenerator +{ + public: + RandomTripointGenerator( int low, int high, int zlow, int zhigh ) : + engine( rng_get_engine() ), + xy_dist( low, high ), + z_dist( zlow, zhigh ) { + this->next(); + } + + const tripoint &get() const override { + return current_point; + } + + bool next() override { + current_point = tripoint( xy_dist( engine ), xy_dist( engine ), z_dist( engine ) ); + return true; + } + protected: + cata_default_random_engine &engine; + std::uniform_int_distribution<> xy_dist; + std::uniform_int_distribution<> z_dist; + tripoint current_point; +}; + +Catch::Generators::GeneratorWrapper random_points( int low, int high ) +{ + return Catch::Generators::GeneratorWrapper( + std::make_unique( low, high ) ); +} + +Catch::Generators::GeneratorWrapper random_tripoints( + int low, int high, int zlow, int zhigh ) +{ + return Catch::Generators::GeneratorWrapper( + std::make_unique( low, high, zlow, zhigh ) ); +} diff --git a/tests/cata_generators.h b/tests/cata_generators.h new file mode 100644 index 0000000000000..85dbc1c6a0e9f --- /dev/null +++ b/tests/cata_generators.h @@ -0,0 +1,18 @@ +#pragma once +#ifndef CATA_TESTS_CATA_GENERATORS_H +#define CATA_TESTS_CATA_GENERATORS_H + +// Some Catch2 Generators for generating our data types + +#include "catch/catch.hpp" +#include "game_constants.h" + +struct point; +struct tripoint; + +Catch::Generators::GeneratorWrapper random_points( int low = -1000, int high = 1000 ); + +Catch::Generators::GeneratorWrapper random_tripoints( + int low = -1000, int high = 1000, int zlow = -OVERMAP_DEPTH, int zhigh = OVERMAP_HEIGHT ); + +#endif // CATA_TESTS_CATA_GENERATORS_H diff --git a/tests/catch/catch.hpp b/tests/catch/catch.hpp index e62d863ce0e01..7dba7419f51d6 100644 --- a/tests/catch/catch.hpp +++ b/tests/catch/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.12.0 - * Generated: 2020-04-21 16:27:54.138031 + * Catch v2.13.0 + * Generated: 2020-07-12 20:07:49.015950 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. @@ -15,7 +15,7 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 12 +#define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_PATCH 0 #ifdef __clang__ @@ -164,7 +164,7 @@ namespace Catch { // // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. # if !defined(__ibmxl__) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg) */ +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ # endif # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ @@ -776,7 +776,7 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) @@ -945,13 +945,13 @@ namespace Catch { #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is - // replaced with std::invoke_result here. Also *_t format is preferred over - // typename *::type format. - template - using FunctionReturnType = std::remove_reference_t>>; + // replaced with std::invoke_result here. + template + using FunctionReturnType = std::remove_reference_t>>; #else - template - using FunctionReturnType = typename std::remove_reference::type>::type>::type; + // Keep ::type here because we still support C++11 + template + using FunctionReturnType = typename std::remove_reference::type>::type>::type; #endif } // namespace Catch @@ -1989,20 +1989,27 @@ namespace Catch { #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER namespace Catch { - struct not_this_one {}; // Tag type for detecting which begin/ end are being selected - - // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + // Import begin/ end from std here using std::begin; using std::end; - not_this_one begin( ... ); - not_this_one end( ... ); + namespace detail { + template + struct void_type { + using type = void; + }; + + template + struct is_range_impl : std::false_type { + }; + + template + struct is_range_impl()))>::type> : std::true_type { + }; + } // namespace detail template - struct is_range { - static const bool value = - !std::is_same())), not_this_one>::value && - !std::is_same())), not_this_one>::value; + struct is_range : detail::is_range_impl { }; #if defined(_MANAGED) // Managed types are never ranges @@ -2378,6 +2385,10 @@ namespace Catch { auto operator & (RhsT const& rhs) -> BinaryExpr const { return { static_cast(m_lhs & rhs), m_lhs, "&", rhs }; } + template + auto operator ^ (RhsT const& rhs) -> BinaryExpr const { + return { static_cast(m_lhs ^ rhs), m_lhs, "^", rhs }; + } template auto operator && ( RhsT const& ) -> BinaryExpr const { @@ -2458,7 +2469,7 @@ namespace Catch { virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; + virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) virtual void benchmarkPreparing( std::string const& name ) = 0; @@ -3711,8 +3722,6 @@ namespace Matchers { struct UnorderedEqualsMatcher : MatcherBase> { UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} bool match(std::vector const& vec) const override { - // Note: This is a reimplementation of std::is_permutation, - // because I don't want to include inside the common path if (m_target.size() != vec.size()) { return false; } @@ -3731,7 +3740,7 @@ namespace Matchers { // The following functions create the actual matcher objects. // This allows the types to be inferred - template + template, typename AllocMatch = AllocComp> Vector::ContainsMatcher Contains( std::vector const& comparator ) { return Vector::ContainsMatcher( comparator ); } @@ -3741,17 +3750,17 @@ namespace Matchers { return Vector::ContainsElementMatcher( comparator ); } - template + template, typename AllocMatch = AllocComp> Vector::EqualsMatcher Equals( std::vector const& comparator ) { return Vector::EqualsMatcher( comparator ); } - template + template, typename AllocMatch = AllocComp> Vector::ApproxMatcher Approx( std::vector const& comparator ) { return Vector::ApproxMatcher( comparator ); } - template + template, typename AllocMatch = AllocComp> Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { return Vector::UnorderedEqualsMatcher( target ); } @@ -4072,16 +4081,16 @@ namespace Generators { return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); } - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; template // Note: The type after -> is weird, because VS2015 cannot parse // the expression used in the typedef inside, when it is in // return type. Yeah. - auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { + auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { using UnderlyingType = typename decltype(generatorExpression())::type; - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); + IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); if (!tracker.hasGenerator()) { tracker.setGenerator(pf::make_unique>(generatorExpression())); } @@ -4094,11 +4103,17 @@ namespace Generators { } // namespace Catch #define GENERATE( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) #define GENERATE_COPY( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) #define GENERATE_REF( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) // end catch_generators.hpp // start catch_generators_generic.hpp @@ -4508,6 +4523,7 @@ namespace Catch { virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; + virtual double minDuration() const = 0; virtual TestSpec const& testSpec() const = 0; virtual bool hasTestFilters() const = 0; virtual std::vector const& getTestsOrTags() const = 0; @@ -5280,6 +5296,7 @@ namespace Catch { Verbosity verbosity = Verbosity::Normal; WarnAbout::What warnings = WarnAbout::Nothing; ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + double minDuration = -1; RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; UseColour::YesOrNo useColour = UseColour::Auto; WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; @@ -5330,6 +5347,7 @@ namespace Catch { bool warnAboutMissingAssertions() const override; bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; + double minDuration() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; UseColour::YesOrNo useColour() const override; @@ -5707,6 +5725,9 @@ namespace Catch { // Returns double formatted as %.3f (format expected on output) std::string getFormattedDuration( double duration ); + //! Should the reporter show + bool shouldShowDuration( IConfig const& config, double duration ); + std::string serializeFilters( std::vector const& container ); template @@ -6100,8 +6121,6 @@ namespace Catch { static std::string getDescription(); - ReporterPreferences getPreferences() const override; - void noMatchingTestCases(std::string const& spec) override; void assertionStarting(AssertionInfo const&) override; @@ -6549,20 +6568,18 @@ namespace Catch { return {}; } }; - template - using ResultOf_t = typename std::result_of::type; // invoke and not return void :( template - CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { - return CompleteInvoker>::invoke(std::forward(fun), std::forward(args)...); + CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker>::invoke(std::forward(fun), std::forward(args)...); } const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; } // namespace Detail template - Detail::CompleteType_t> user_code(Fun&& fun) { + Detail::CompleteType_t> user_code(Fun&& fun) { CATCH_TRY{ return Detail::complete_invoke(std::forward(fun)); } CATCH_CATCH_ALL{ @@ -6807,8 +6824,8 @@ namespace Catch { Result result; int iterations; }; - template - using TimingOf = Timing, Detail::CompleteType_t>>; + template + using TimingOf = Timing, Detail::CompleteType_t>>; } // namespace Benchmark } // namespace Catch @@ -6819,7 +6836,7 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure(Fun&& fun, Args&&... args) { + TimingOf measure(Fun&& fun, Args&&... args) { auto start = Clock::now(); auto&& r = Detail::complete_invoke(fun, std::forward(args)...); auto end = Clock::now(); @@ -6838,11 +6855,11 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure_one(Fun&& fun, int iters, std::false_type) { + TimingOf measure_one(Fun&& fun, int iters, std::false_type) { return Detail::measure(fun, iters); } template - TimingOf measure_one(Fun&& fun, int iters, std::true_type) { + TimingOf measure_one(Fun&& fun, int iters, std::true_type) { Detail::ChronometerModel meter; auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); @@ -6859,7 +6876,7 @@ namespace Catch { }; template - TimingOf)> run_for_at_least(ClockDuration how_long, int seed, Fun&& fun) { + TimingOf> run_for_at_least(ClockDuration how_long, int seed, Fun&& fun) { auto iters = seed; while (iters < (1 << 30)) { auto&& Timing = measure_one(fun, iters, is_callable()); @@ -7457,23 +7474,37 @@ namespace TestCaseTracking { SourceLineInfo location; NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { + return lhs.name == rhs.name + && lhs.location == rhs.location; + } }; - struct ITracker; + class ITracker; using ITrackerPtr = std::shared_ptr; - struct ITracker { - virtual ~ITracker(); + class ITracker { + NameAndLocation m_nameAndLocation; + + public: + ITracker(NameAndLocation const& nameAndLoc) : + m_nameAndLocation(nameAndLoc) + {} // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; + NameAndLocation const& nameAndLocation() const { + return m_nameAndLocation; + } + + virtual ~ITracker(); // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; + virtual bool hasStarted() const = 0; virtual ITracker& parent() = 0; @@ -7528,7 +7559,6 @@ namespace TestCaseTracking { }; using Children = std::vector; - NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; @@ -7537,11 +7567,13 @@ namespace TestCaseTracking { public: TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - NameAndLocation const& nameAndLocation() const override; bool isComplete() const override; bool isSuccessfullyCompleted() const override; bool isOpen() const override; bool hasChildren() const override; + bool hasStarted() const override { + return m_runState != NotStarted; + } void addChild( ITrackerPtr const& child ) override; @@ -7904,7 +7936,11 @@ namespace Catch { #ifdef CATCH_PLATFORM_MAC - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #endif #elif defined(CATCH_PLATFORM_IPHONE) @@ -8089,7 +8125,7 @@ namespace Catch { void sectionEnded( SectionEndInfo const& endInfo ) override; void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) void benchmarkPreparing( std::string const& name ) override; @@ -9065,7 +9101,7 @@ namespace detail { } inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( std::tolower(c) ); } ); + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast( std::tolower(c) ); } ); if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") target = true; else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") @@ -9834,6 +9870,9 @@ namespace Catch { | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) ["-d"]["--durations"] ( "show test durations" ) + | Opt( config.minDuration, "seconds" ) + ["-D"]["--min-duration"] + ( "show test durations for tests taking at least the given number of seconds" ) | Opt( loadTestNamesFromFile, "filename" ) ["-f"]["--input-file"] ( "load test names to run from a file" ) @@ -9981,6 +10020,7 @@ namespace Catch { bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + double Config::minDuration() const { return m_data.minDuration; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } @@ -10877,8 +10917,8 @@ namespace Generators { GeneratorUntypedBase::~GeneratorUntypedBase() {} - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { - return getResultCapture().acquireGeneratorTracker( lineInfo ); + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); } } // namespace Generators @@ -11765,10 +11805,10 @@ namespace Catch { Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { auto trimmed = [&] (size_t start, size_t end) { - while (names[start] == ',' || isspace(names[start])) { + while (names[start] == ',' || isspace(static_cast(names[start]))) { ++start; } - while (names[end] == ',' || isspace(names[end])) { + while (names[end] == ',' || isspace(static_cast(names[end]))) { --end; } return names.substr(start, end - start + 1); @@ -12298,11 +12338,13 @@ namespace Catch { namespace Catch { class StartupExceptionRegistry { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) public: void add(std::exception_ptr const& exception) noexcept; std::vector const& getExceptions() const noexcept; private: std::vector m_exceptions; +#endif }; } // end namespace Catch @@ -12385,7 +12427,11 @@ namespace Catch { m_tagAliasRegistry.add( alias, tag, lineInfo ); } void registerStartupException() noexcept override { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) m_exceptionRegistry.add(std::current_exception()); +#else + CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); +#endif } IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { return m_enumValuesRegistry; @@ -12489,17 +12535,32 @@ namespace Catch { std::shared_ptr tracker; ITracker& currentTracker = ctx.currentTracker(); - if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if (currentTracker.nameAndLocation() == nameAndLocation) { + auto thisTracker = currentTracker.parent().findChild(nameAndLocation); + assert(thisTracker); + assert(thisTracker->isGeneratorTracker()); + tracker = std::static_pointer_cast(thisTracker); + } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isGeneratorTracker() ); tracker = std::static_pointer_cast( childTracker ); - } - else { + } else { tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( tracker ); } - if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( !tracker->isComplete() ) { tracker->open(); } @@ -12513,8 +12574,28 @@ namespace Catch { } void close() override { TrackerBase::close(); - // Generator interface only finds out if it has another item on atual move - if (m_runState == CompletedSuccessfully && m_generator->next()) { + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by `SECTION`s. + const bool should_wait_for_child = + !m_children.empty() && + std::find_if( m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr tracker ) { + return tracker->hasStarted(); + } ) == m_children.end(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->next() ) ) { m_children.clear(); m_runState = Executing; } @@ -12650,10 +12731,10 @@ namespace Catch { return true; } - auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); - assert( tracker.isOpen() ); + GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, + TestCaseTracking::NameAndLocation( static_cast(generatorName), lineInfo ) ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } @@ -12696,17 +12777,17 @@ namespace Catch { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) void RunContext::benchmarkPreparing(std::string const& name) { - m_reporter->benchmarkPreparing(name); - } + m_reporter->benchmarkPreparing(name); + } void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { m_reporter->benchmarkStarting( info ); } void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { m_reporter->benchmarkEnded( stats ); } - void RunContext::benchmarkFailed(std::string const & error) { - m_reporter->benchmarkFailed(error); - } + void RunContext::benchmarkFailed(std::string const & error) { + m_reporter->benchmarkFailed(error); + } #endif // CATCH_CONFIG_ENABLE_BENCHMARKING void RunContext::pushScopedMessage(MessageInfo const & message) { @@ -13427,6 +13508,7 @@ namespace Catch { // end catch_singletons.cpp // start catch_startup_exception_registry.cpp +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) namespace Catch { void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { CATCH_TRY { @@ -13442,6 +13524,7 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce } } // end namespace Catch +#endif // end catch_startup_exception_registry.cpp // start catch_stream.cpp @@ -13626,7 +13709,7 @@ namespace Catch { namespace { char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); + return static_cast( std::tolower( static_cast(c) ) ); } } @@ -14209,15 +14292,12 @@ namespace TestCaseTracking { m_currentTracker = tracker; } - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): + ITracker(nameAndLocation), m_ctx( ctx ), m_parent( parent ) {} - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } bool TrackerBase::isComplete() const { return m_runState == CompletedSuccessfully || m_runState == Failed; } @@ -14333,7 +14413,8 @@ namespace TestCaseTracking { bool SectionTracker::isComplete() const { bool complete = true; - if ((m_filters.empty() || m_filters[0] == "") + if (m_filters.empty() + || m_filters[0] == "" || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { complete = TrackerBase::isComplete(); } @@ -15116,7 +15197,9 @@ namespace Catch { namespace Catch { bool uncaught_exceptions() { -#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return false; +#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) return std::uncaught_exceptions() > 0; #else return std::uncaught_exception(); @@ -15156,7 +15239,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 12, 0, "", 0 ); + static Version version( 2, 13, 0, "", 0 ); return version; } @@ -15558,6 +15641,17 @@ namespace Catch { return std::string(buffer); } + bool shouldShowDuration( IConfig const& config, double duration ) { + if ( config.showDurations() == ShowDurations::Always ) { + return true; + } + if ( config.showDurations() == ShowDurations::Never ) { + return false; + } + const double min = config.minDuration(); + return min >= 0 && duration >= min; + } + std::string serializeFilters( std::vector const& container ) { ReusableStringStream oss; bool first = true; @@ -15824,10 +15918,6 @@ class AssertionPrinter { return "Reports test results on a single line, suitable for IDEs"; } - ReporterPreferences CompactReporter::getPreferences() const { - return m_reporterPrefs; - } - void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } @@ -15854,8 +15944,9 @@ class AssertionPrinter { } void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if ( shouldShowDuration( *m_config, dur ) ) { + stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } @@ -16275,8 +16366,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if (shouldShowDuration(*m_config, dur)) { + stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if (m_headerPrinted) { m_headerPrinted = false; @@ -16735,6 +16827,11 @@ namespace Catch { xml.writeAttribute( "name", name ); } xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + // This is not ideal, but it should be enough to mimic gtest's + // junit output. + // Ideally the JUnit reporter would also handle `skipTest` + // events and write those out appropriately. + xml.writeAttribute( "status", "run" ); writeAssertions( sectionNode ); @@ -17169,6 +17266,10 @@ namespace Catch { .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testGroupStats.totals.testCases.passed ) + .writeAttribute( "failures", testGroupStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk ); m_xml.endElement(); } @@ -17178,6 +17279,10 @@ namespace Catch { .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testRunStats.totals.testCases.passed ) + .writeAttribute( "failures", testRunStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk ); m_xml.endElement(); } diff --git a/tests/char_biometrics_test.cpp b/tests/char_biometrics_test.cpp index e233bbc4c6425..b2a376704b75a 100644 --- a/tests/char_biometrics_test.cpp +++ b/tests/char_biometrics_test.cpp @@ -496,6 +496,7 @@ TEST_CASE( "activity level reset, increase and decrease", "[biometrics][activity TEST_CASE( "mutations may affect character metabolic rate", "[biometrics][metabolism]" ) { avatar dummy; + dummy.set_body(); // Metabolic base rate uses PLAYER_HUNGER_RATE from game_balance.json, described as "base hunger // rate per 5 minutes". With no metabolism-affecting mutations, metabolism should be this value. @@ -532,6 +533,7 @@ TEST_CASE( "mutations may affect character metabolic rate", "[biometrics][metabo TEST_CASE( "basal metabolic rate with various size and metabolism", "[biometrics][bmr]" ) { avatar dummy; + dummy.set_body(); // Basal metabolic rate depends on size (height), bodyweight (BMI), and activity level // scaled by metabolic base rate. Assume default metabolic rate. diff --git a/tests/char_edible_rating_test.cpp b/tests/char_edible_rating_test.cpp index 241b349c0e2cc..d5eb07d8a013d 100644 --- a/tests/char_edible_rating_test.cpp +++ b/tests/char_edible_rating_test.cpp @@ -71,6 +71,7 @@ TEST_CASE( "cannot eat dirty food", "[can_eat][edible_rating][dirty]" ) TEST_CASE( "who can eat while underwater", "[can_eat][edible_rating][underwater]" ) { avatar dummy; + dummy.set_body(); item sushi( "sushi_fishroll" ); item water( "water_clean" ); @@ -194,7 +195,7 @@ TEST_CASE( "when frozen food can be eaten", "[can_eat][edible_rating][frozen]" ) TEST_CASE( "who can eat inedible animal food", "[can_eat][edible_rating][inedible][animal]" ) { avatar dummy; - + dummy.set_body(); // Note: There are similar conditions for INEDIBLE food with FELINE or LUPINE flags, but // "birdfood" and "cattlefodder" are the only INEDIBLE items that exist in the game. @@ -246,6 +247,7 @@ TEST_CASE( "who can eat inedible animal food", "[can_eat][edible_rating][inedibl TEST_CASE( "what herbivores can eat", "[can_eat][edible_rating][herbivore]" ) { avatar dummy; + dummy.set_body(); GIVEN( "character is an herbivore" ) { dummy.toggle_trait( trait_id( "HERBIVORE" ) ); @@ -272,6 +274,7 @@ TEST_CASE( "what herbivores can eat", "[can_eat][edible_rating][herbivore]" ) TEST_CASE( "what carnivores can eat", "[can_eat][edible_rating][carnivore]" ) { avatar dummy; + dummy.set_body(); GIVEN( "character is a carnivore" ) { dummy.toggle_trait( trait_id( "CARNIVORE" ) ); @@ -320,6 +323,7 @@ TEST_CASE( "what carnivores can eat", "[can_eat][edible_rating][carnivore]" ) TEST_CASE( "what you can eat with a mycus dependency", "[can_eat][edible_rating][mycus]" ) { avatar dummy; + dummy.set_body(); GIVEN( "character is mycus-dependent" ) { dummy.toggle_trait( trait_id( "M_DEPENDENT" ) ); @@ -344,6 +348,7 @@ TEST_CASE( "what you can eat with a mycus dependency", "[can_eat][edible_rating] TEST_CASE( "what you can drink with a proboscis", "[can_eat][edible_rating][proboscis]" ) { avatar dummy; + dummy.set_body(); GIVEN( "character has a proboscis" ) { dummy.toggle_trait( trait_id( "PROBOSCIS" ) ); @@ -413,6 +418,7 @@ TEST_CASE( "can eat with nausea", "[will_eat][edible_rating][nausea]" ) TEST_CASE( "can eat with allergies", "[will_eat][edible_rating][allergy]" ) { avatar dummy; + dummy.set_body(); item fruit( "apple" ); REQUIRE( fruit.has_flag( "ALLERGEN_FRUIT" ) ); @@ -430,6 +436,7 @@ TEST_CASE( "can eat with allergies", "[will_eat][edible_rating][allergy]" ) TEST_CASE( "who will eat rotten food", "[will_eat][edible_rating][rotten]" ) { avatar dummy; + dummy.set_body(); GIVEN( "food just barely rotten" ) { item toastem_rotten = item( "toastem" ); @@ -480,6 +487,7 @@ TEST_CASE( "who will eat rotten food", "[will_eat][edible_rating][rotten]" ) TEST_CASE( "who will eat cooked human flesh", "[will_eat][edible_rating][cannibal]" ) { avatar dummy; + dummy.set_body(); GIVEN( "some cooked human flesh" ) { item flesh( "human_cooked" ); diff --git a/tests/char_stamina_test.cpp b/tests/char_stamina_test.cpp index 031d154c1629d..1e3c588b2d647 100644 --- a/tests/char_stamina_test.cpp +++ b/tests/char_stamina_test.cpp @@ -428,6 +428,7 @@ TEST_CASE( "stamina regen with mouth encumbrance", "[stamina][update][regen][enc player &dummy = g->u; clear_character( dummy ); catch_breath( dummy ); + dummy.set_body(); int turn_moves = to_moves( 1_turns ); @@ -436,7 +437,7 @@ TEST_CASE( "stamina regen with mouth encumbrance", "[stamina][update][regen][enc GIVEN( "character has mouth encumbrance" ) { dummy.wear_item( item( "scarf_fur" ) ); - REQUIRE( dummy.encumb( bp_mouth ) == 10 ); + REQUIRE( dummy.encumb( bodypart_id( "mouth" ) ) == 10 ); THEN( "stamina regen is reduced" ) { CHECK( actual_regen_rate( dummy, turn_moves ) == ( normal_regen_rate - 2 ) * turn_moves ); @@ -444,7 +445,7 @@ TEST_CASE( "stamina regen with mouth encumbrance", "[stamina][update][regen][enc WHEN( "they have even more mouth encumbrance" ) { // Layering two scarves triples the encumbrance dummy.wear_item( item( "scarf_fur" ) ); - REQUIRE( dummy.encumb( bp_mouth ) == 30 ); + REQUIRE( dummy.encumb( bodypart_id( "mouth" ) ) == 30 ); THEN( "stamina regen is reduced further" ) { CHECK( actual_regen_rate( dummy, turn_moves ) == ( normal_regen_rate - 6 ) * turn_moves ); diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index e982134564347..4ac23050709d9 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -772,7 +772,7 @@ TEST_CASE( "colony sort", "[colony]" ) // Less-than sort test CHECK( sorted ); - test_colony.sort( std::greater() ); + test_colony.sort( std::greater<>() ); prev = 65536; diff --git a/tests/coordinate_test.cpp b/tests/coordinate_test.cpp new file mode 100644 index 0000000000000..f410010cfb00f --- /dev/null +++ b/tests/coordinate_test.cpp @@ -0,0 +1,349 @@ +#include "catch/catch.hpp" + +#include "coordinates.h" +#include "coordinate_conversions.h" +#include "cata_generators.h" +#include "stringmaker.h" + +constexpr int num_trials = 5; + +static_assert( point::dimension == 2, "" ); +static_assert( tripoint::dimension == 3, "" ); +static_assert( point_abs_omt::dimension == 2, "" ); +static_assert( tripoint_abs_omt::dimension == 3, "" ); + +TEST_CASE( "coordinate_strings", "[point][coords]" ) +{ + CHECK( point_abs_omt( point( 3, 4 ) ).to_string() == "(3,4)" ); + + SECTION( "coord_point_matches_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + point_abs_ms cp( p ); + CHECK( p.to_string() == cp.to_string() ); + } +} + +TEST_CASE( "coordinate_operations", "[point][coords]" ) +{ + SECTION( "construct_from_raw_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + point_abs_ms cp( p ); + CHECK( cp.x() == p.x ); + CHECK( cp.y() == p.y ); + } + + SECTION( "construct_from_raw_tripoint" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + tripoint_abs_ms cp( p ); + CHECK( cp.x() == p.x ); + CHECK( cp.y() == p.y ); + CHECK( cp.z() == p.z ); + } + + SECTION( "construct_from_values" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + { + point_abs_ms cp( p.x, p.y ); + CHECK( cp.x() == p.x ); + CHECK( cp.y() == p.y ); + } + { + tripoint_abs_ms cp( p.x, p.y, p.z ); + CHECK( cp.x() == p.x ); + CHECK( cp.y() == p.y ); + CHECK( cp.z() == p.z ); + } + } + + SECTION( "addition" ) { + tripoint t0 = GENERATE( take( num_trials, random_tripoints() ) ); + point p0 = t0.xy(); + point p1 = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p0, p1 ); + tripoint_abs_ms abst0( t0 ); + point_abs_ms abs0( p0 ); + point_rel_ms rel0( p0 ); + point_rel_ms rel1( p1 ); + SECTION( "rel + rel -> rel" ) { + point_rel_ms sum = rel0 + rel1; + CHECK( sum.raw() == p0 + p1 ); + } + SECTION( "abs + rel -> abs" ) { + point_abs_ms sum = abs0 + rel1; + CHECK( sum.raw() == p0 + p1 ); + tripoint_abs_ms sum_t = abst0 + rel1; + CHECK( sum_t.raw() == t0 + p1 ); + } + SECTION( "abs + raw -> abs" ) { + point_abs_ms sum = abs0 + p1; + CHECK( sum.raw() == p0 + p1 ); + } + SECTION( "rel + abs -> abs" ) { + point_abs_ms sum = rel1 + abs0; + CHECK( sum.raw() == p0 + p1 ); + } + SECTION( "rel += rel" ) { + rel0 += rel1; + CHECK( rel0.raw() == p0 + p1 ); + } + SECTION( "abs += rel" ) { + abs0 += rel1; + CHECK( abs0.raw() == p0 + p1 ); + } + SECTION( "abs += raw" ) { + abs0 += p1; + CHECK( abs0.raw() == p0 + p1 ); + } + } + + SECTION( "subtraction" ) { + tripoint t0 = GENERATE( take( num_trials, random_tripoints() ) ); + point p0 = t0.xy(); + point p1 = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p0, p1 ); + tripoint_abs_ms abst0( t0 ); + point_abs_ms abs0( p0 ); + point_abs_ms abs1( p1 ); + point_rel_ms rel0( p0 ); + point_rel_ms rel1( p1 ); + SECTION( "rel - rel -> rel" ) { + point_rel_ms diff = rel0 - rel1; + CHECK( diff.raw() == p0 - p1 ); + } + SECTION( "abs - rel -> abs" ) { + point_abs_ms diff = abs0 - rel1; + CHECK( diff.raw() == p0 - p1 ); + } + SECTION( "abs - raw -> abs" ) { + point_abs_ms diff = abs0 - p1; + CHECK( diff.raw() == p0 - p1 ); + } + SECTION( "abs - abs -> rel" ) { + point_rel_ms diff0 = abs0 - abs1; + CHECK( diff0.raw() == p0 - p1 ); + tripoint_rel_ms diff1 = abst0 - abs1; + CHECK( diff1.raw() == t0 - p1 ); + } + SECTION( "rel -= rel" ) { + rel0 -= rel1; + CHECK( rel0.raw() == p0 - p1 ); + } + SECTION( "abs -= rel" ) { + abs0 -= rel1; + CHECK( abs0.raw() == p0 - p1 ); + } + SECTION( "abs -= raw" ) { + abs0 -= p1; + CHECK( abs0.raw() == p0 - p1 ); + } + } +} + +TEST_CASE( "coordinate_comparison", "[point][coords]" ) +{ + SECTION( "compare_points" ) { + point p0 = GENERATE( take( num_trials, random_points() ) ); + point p1 = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p0, p1 ); + point_rel_ms cp0( p0 ); + point_rel_ms cp1( p1 ); + CAPTURE( cp0, cp1 ); + + CHECK( ( p0 < p1 ) == ( cp0 < cp1 ) ); + CHECK( ( p0 == p1 ) == ( cp0 == cp1 ) ); + CHECK( cp0 == cp0 ); + CHECK( !( cp0 != cp0 ) ); + } + + SECTION( "compare_tripoints" ) { + tripoint p0 = GENERATE( take( num_trials, random_tripoints() ) ); + tripoint p1 = GENERATE( take( num_trials, random_tripoints() ) ); + CAPTURE( p0, p1 ); + tripoint_rel_ms cp0( p0 ); + tripoint_rel_ms cp1( p1 ); + CAPTURE( cp0, cp1 ); + + CHECK( ( p0 < p1 ) == ( cp0 < cp1 ) ); + CHECK( ( p0 == p1 ) == ( cp0 == cp1 ) ); + CHECK( cp0 == cp0 ); + CHECK( !( cp0 != cp0 ) ); + } +} + +TEST_CASE( "coordinate_hash", "[point][coords]" ) +{ + SECTION( "point_hash" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + point_abs_ms cp( p ); + CHECK( std::hash()( cp ) == std::hash()( p ) ); + } + + SECTION( "tripoint_hash" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + tripoint_abs_ms cp( p ); + CHECK( std::hash()( cp ) == std::hash()( p ) ); + } +} + +TEST_CASE( "coordinate_conversion_consistency", "[point][coords]" ) +{ + // Verifies that the new coord_point-based conversions yield the same + // results as the legacy conversion functions. + SECTION( "omt_to_om_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_om new_conversion = project_to( point_abs_omt( p ) ); + point old_conversion = omt_to_om_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "omt_to_om_tripoint" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + CAPTURE( p ); + tripoint_abs_om new_conversion = project_to( tripoint_abs_omt( p ) ); + tripoint old_conversion = omt_to_om_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "omt_to_om_remain_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_om new_conversion; + point_om_omt remainder; + std::tie( new_conversion, remainder ) = project_remain( point_abs_omt( p ) ); + point old_conversion = omt_to_om_remain( p ); + CHECK( old_conversion == new_conversion.raw() ); + CHECK( p == remainder.raw() ); + } + + SECTION( "sm_to_omt_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_omt new_conversion = project_to( point_abs_sm( p ) ); + point old_conversion = sm_to_omt_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "sm_to_omt_remain_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_omt new_conversion; + point_omt_sm remainder; + std::tie( new_conversion, remainder ) = project_remain( point_abs_sm( p ) ); + point old_conversion = sm_to_omt_remain( p ); + CHECK( old_conversion == new_conversion.raw() ); + CHECK( p == remainder.raw() ); + } + + SECTION( "sm_to_om_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_om new_conversion = project_to( point_abs_sm( p ) ); + point old_conversion = sm_to_om_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "sm_to_om_remain_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_om new_conversion; + point_om_sm remainder; + std::tie( new_conversion, remainder ) = project_remain( point_abs_sm( p ) ); + point old_conversion = sm_to_om_remain( p ); + CHECK( old_conversion == new_conversion.raw() ); + CHECK( p == remainder.raw() ); + } + + SECTION( "omt_to_sm_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_sm new_conversion = project_to( point_abs_omt( p ) ); + point old_conversion = omt_to_sm_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "om_to_sm_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_sm new_conversion = project_to( point_abs_om( p ) ); + point old_conversion = om_to_sm_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "ms_to_sm_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_sm new_conversion = project_to( point_abs_ms( p ) ); + point old_conversion = ms_to_sm_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "sm_to_ms_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_ms new_conversion = project_to( point_abs_sm( p ) ); + point old_conversion = sm_to_ms_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "ms_to_omt_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_omt new_conversion = project_to( point_abs_ms( p ) ); + point old_conversion = ms_to_omt_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } + + SECTION( "ms_to_omt_remain_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_omt new_conversion; + point_omt_ms remainder; + std::tie( new_conversion, remainder ) = project_remain( point_abs_ms( p ) ); + point old_conversion = ms_to_omt_remain( p ); + CHECK( old_conversion == new_conversion.raw() ); + CHECK( p == remainder.raw() ); + } + + SECTION( "omt_to_seg_tripoint" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + CAPTURE( p ); + tripoint_abs_seg new_conversion = project_to( tripoint_abs_omt( p ) ); + tripoint old_conversion = omt_to_seg_copy( p ); + CHECK( old_conversion == new_conversion.raw() ); + } +} + +TEST_CASE( "combine_is_opposite_of_remain", "[point][coords]" ) +{ + SECTION( "point_point" ) { + point p = GENERATE( take( num_trials, random_points() ) ); + CAPTURE( p ); + point_abs_sm orig( p ); + point_abs_om quotient; + point_om_sm remainder; + std::tie( quotient, remainder ) = project_remain( orig ); + point_abs_sm recombined = project_combine( quotient, remainder ); + CHECK( recombined == orig ); + } + SECTION( "tripoint_point" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + CAPTURE( p ); + tripoint_abs_sm orig( p ); + tripoint_abs_om quotient; + point_om_sm remainder; + std::tie( quotient, remainder ) = project_remain( orig ); + tripoint_abs_sm recombined = project_combine( quotient, remainder ); + CHECK( recombined == orig ); + } + SECTION( "point_tripoint" ) { + tripoint p = GENERATE( take( num_trials, random_tripoints() ) ); + CAPTURE( p ); + tripoint_abs_sm orig( p ); + point_abs_om quotient; + tripoint_om_sm remainder; + std::tie( quotient, remainder ) = project_remain( orig ); + tripoint_abs_sm recombined = project_combine( quotient, remainder ); + CHECK( recombined == orig ); + } +} diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index a7037d38c13c2..c5fa16be1ed2e 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -295,25 +295,26 @@ static void prep_craft( const recipe_id &rid, const std::vector &tools, clear_map(); const tripoint test_origin( 60, 60, 0 ); - g->u.setpos( test_origin ); + Character &player_character = get_player_character(); + player_character.setpos( test_origin ); const item backpack( "backpack" ); - g->u.worn.push_back( backpack ); - g->u.worn.push_back( backpack ); + player_character.worn.push_back( backpack ); + player_character.worn.push_back( backpack ); for( const item &gear : tools ) { - g->u.i_add( gear ); + player_character.i_add( gear ); } const recipe &r = rid.obj(); // Ensure adequate skill for all "required" skills for( const std::pair &skl : r.required_skills ) { - g->u.set_skill_level( skl.first, skl.second ); + player_character.set_skill_level( skl.first, skl.second ); } // and just in case "used" skill difficulty is higher, set that too - g->u.set_skill_level( r.skill_used, std::max( r.difficulty, - g->u.get_skill_level( r.skill_used ) ) ); - g->u.moves--; - const inventory &crafting_inv = g->u.crafting_inventory(); + player_character.set_skill_level( r.skill_used, std::max( r.difficulty, + player_character.get_skill_level( r.skill_used ) ) ); + player_character.moves--; + const inventory &crafting_inv = player_character.crafting_inventory(); bool can_craft = r.deduped_requirements().can_make_with_inventory( crafting_inv, r.get_component_filter() ); REQUIRE( can_craft == expect_craftable ); @@ -326,7 +327,7 @@ static void set_time( const time_point &time ) { calendar::turn = time; g->reset_light_level(); - int z = g->u.posz(); + int z = get_player_character().posz(); map &here = get_map(); here.update_visibility_cache( z ); here.invalidate_map_cache( z ); @@ -340,27 +341,29 @@ static int actually_test_craft( const recipe_id &rid, const std::vector &t { prep_craft( rid, tools, true ); set_time( midday ); // Ensure light for crafting + avatar &player_character = get_avatar(); const recipe &rec = rid.obj(); - REQUIRE( g->u.morale_crafting_speed_multiplier( rec ) == 1.0 ); - REQUIRE( g->u.lighting_craft_speed_multiplier( rec ) == 1.0 ); - REQUIRE( !g->u.activity ); + REQUIRE( player_character.morale_crafting_speed_multiplier( rec ) == 1.0 ); + REQUIRE( player_character.lighting_craft_speed_multiplier( rec ) == 1.0 ); + REQUIRE( !player_character.activity ); // This really shouldn't be needed, but for some reason the tests fail for mingw builds without it - g->u.learn_recipe( &rec ); - REQUIRE( g->u.has_recipe( &rec, g->u.crafting_inventory(), g->u.get_crafting_helpers() ) != -1 ); - g->u.remove_weapon(); - REQUIRE( !g->u.is_armed() ); - g->u.make_craft( rid, 1 ); - REQUIRE( g->u.activity ); - REQUIRE( g->u.activity.id() == activity_id( "ACT_CRAFT" ) ); + player_character.learn_recipe( &rec ); + REQUIRE( player_character.has_recipe( &rec, player_character.crafting_inventory(), + player_character.get_crafting_helpers() ) != -1 ); + player_character.remove_weapon(); + REQUIRE( !player_character.is_armed() ); + player_character.make_craft( rid, 1 ); + REQUIRE( player_character.activity ); + REQUIRE( player_character.activity.id() == activity_id( "ACT_CRAFT" ) ); int turns = 0; - while( g->u.activity.id() == activity_id( "ACT_CRAFT" ) ) { + while( player_character.activity.id() == activity_id( "ACT_CRAFT" ) ) { if( turns >= interrupt_after_turns ) { set_time( midnight ); // Kill light to interrupt crafting } ++turns; - g->u.moves = 100; - g->u.activity.do_turn( g->u ); + player_character.moves = 100; + player_character.activity.do_turn( player_character ); } return turns; } @@ -502,22 +505,23 @@ TEST_CASE( "tool_use", "[crafting][tool]" ) // Resume the first in progress craft found in the player's inventory static int resume_craft() { - std::vector crafts = g->u.items_with( []( const item & itm ) { + avatar &player_character = get_avatar(); + std::vector crafts = player_character.items_with( []( const item & itm ) { return itm.is_craft(); } ); REQUIRE( crafts.size() == 1 ); item *craft = crafts.front(); set_time( midday ); // Ensure light for crafting - REQUIRE( g->u.crafting_speed_multiplier( *craft, tripoint_zero ) == 1.0 ); - REQUIRE( !g->u.activity ); - g->u.use( g->u.get_item_position( craft ) ); - REQUIRE( g->u.activity ); - REQUIRE( g->u.activity.id() == activity_id( "ACT_CRAFT" ) ); + REQUIRE( player_character.crafting_speed_multiplier( *craft, tripoint_zero ) == 1.0 ); + REQUIRE( !player_character.activity ); + player_character.use( player_character.get_item_position( craft ) ); + REQUIRE( player_character.activity ); + REQUIRE( player_character.activity.id() == activity_id( "ACT_CRAFT" ) ); int turns = 0; - while( g->u.activity.id() == activity_id( "ACT_CRAFT" ) ) { + while( player_character.activity.id() == activity_id( "ACT_CRAFT" ) ) { ++turns; - g->u.moves = 100; - g->u.activity.do_turn( g->u ); + player_character.moves = 100; + player_character.activity.do_turn( player_character ); } return turns; } @@ -527,21 +531,22 @@ static void verify_inventory( const std::vector &has, { std::ostringstream os; os << "Inventory:\n"; - for( const item *i : g->u.inv_dump() ) { + Character &player_character = get_player_character(); + for( const item *i : player_character.inv_dump() ) { os << " " << i->typeId().str() << " (" << i->charges << ")\n"; } - os << "Wielded:\n" << g->u.weapon.tname() << "\n"; + os << "Wielded:\n" << player_character.weapon.tname() << "\n"; INFO( os.str() ); for( const std::string &i : has ) { INFO( "expecting " << i ); const bool has_item = - player_has_item_of_type( i ) || g->u.weapon.type->get_id() == itype_id( i ); + player_has_item_of_type( i ) || player_character.weapon.type->get_id() == itype_id( i ); REQUIRE( has_item ); } for( const std::string &i : hasnt ) { INFO( "not expecting " << i ); const bool hasnt_item = - !player_has_item_of_type( i ) && !( g->u.weapon.type->get_id() == itype_id( i ) ); + !player_has_item_of_type( i ) && !( player_character.weapon.type->get_id() == itype_id( i ) ); REQUIRE( hasnt_item ); } } @@ -550,7 +555,7 @@ TEST_CASE( "total crafting time with or without interruption", "[crafting][time] { GIVEN( "a recipe and all the required tools and materials to craft it" ) { recipe_id test_recipe( "crude_picklock" ); - int expected_time_taken = test_recipe->batch_time( 1, 1, 0 ); + int expected_time_taken = test_recipe->batch_time( get_player_character(), 1, 1, 0 ); int expected_turns_taken = divide_round_up( expected_time_taken, 100 ); std::vector tools; diff --git a/tests/creature_effect_test.cpp b/tests/creature_effect_test.cpp index 02b2e893f5fc4..ad82e8e5e0d0f 100644 --- a/tests/creature_effect_test.cpp +++ b/tests/creature_effect_test.cpp @@ -33,6 +33,7 @@ TEST_CASE( "character add_effect", "[creature][character][effect][add]" ) { avatar dummy; + dummy.set_body(); const efftype_id effect_bleed( "bleed" ); const efftype_id effect_grabbed( "grabbed" ); const body_part left_arm = bodypart_id( "arm_l" )->token; @@ -416,6 +417,7 @@ TEST_CASE( "monster is_immune_effect", "[creature][monster][effect][immune]" ) TEST_CASE( "character is_immune_effect", "[creature][character][effect][immune]" ) { avatar dummy; + dummy.set_body(); dummy.clear_mutations(); // TODO: Character may be immune to: diff --git a/tests/effective_dps_test.cpp b/tests/effective_dps_test.cpp index 00761c3e18c1f..daca6debc51fc 100644 --- a/tests/effective_dps_test.cpp +++ b/tests/effective_dps_test.cpp @@ -4,7 +4,6 @@ #include "avatar.h" #include "calendar.h" #include "creature.h" -#include "game.h" #include "item.h" #include "melee.h" #include "player.h" @@ -96,7 +95,7 @@ static void check_accuracy_dps( avatar &attacker, monster &defender, item &wpn1, } TEST_CASE( "effective damage per second", "[effective][dps]" ) { - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); item clumsy_sword( "test_clumsy_sword" ); @@ -159,7 +158,7 @@ TEST_CASE( "effective damage per second", "[effective][dps]" ) TEST_CASE( "effective vs actual damage per second", "[actual][dps][!mayfail]" ) { - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); monster soldier( mtype_id( "mon_zombie_soldier" ) ); @@ -191,7 +190,7 @@ TEST_CASE( "effective vs actual damage per second", "[actual][dps][!mayfail]" ) TEST_CASE( "accuracy increases success", "[accuracy][dps]" ) { - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); monster soldier( mtype_id( "mon_zombie_soldier" ) ); @@ -250,8 +249,8 @@ static void make_experienced_tester( avatar &test_guy ) static void calc_expected_dps( avatar &test_guy, const std::string &weapon_id, double target ) { item weapon( weapon_id ); - CHECK( test_guy.melee_value( weapon ) == Approx( target ).margin( 0.75 ) ); - if( test_guy.melee_value( weapon ) != Approx( target ).margin( 0.75 ) ) { + CHECK( test_guy.melee_value( weapon ) == Approx( target ).margin( 0.5 ) ); + if( test_guy.melee_value( weapon ) != Approx( target ).margin( 0.5 ) ) { std::cout << weapon_id << " out of range, expected: " << target; std::cout << " got " << test_guy.melee_value( weapon ) << std::endl; } @@ -263,21 +262,21 @@ static void calc_expected_dps( avatar &test_guy, const std::string &weapon_id, d */ TEST_CASE( "expected weapon dps", "[expected][dps]" ) { - avatar &test_guy = g->u; + avatar &test_guy = get_avatar(); make_experienced_tester( test_guy ); SECTION( "staves" ) { // typical value around 18 calc_expected_dps( test_guy, "i_staff", 18.0 ); calc_expected_dps( test_guy, "q_staff", 17.0 ); - calc_expected_dps( test_guy, "l-stick_on", 18.0 ); - calc_expected_dps( test_guy, "l-stick", 18.0 ); + calc_expected_dps( test_guy, "l-stick_on", 17.5 ); + calc_expected_dps( test_guy, "l-stick", 17.5 ); calc_expected_dps( test_guy, "shock_staff", 17.0 ); - calc_expected_dps( test_guy, "hockey_stick", 13.0 ); + calc_expected_dps( test_guy, "hockey_stick", 13.75 ); calc_expected_dps( test_guy, "pool_cue", 10.0 ); - calc_expected_dps( test_guy, "broom", 4.0 ); + calc_expected_dps( test_guy, "broom", 3.25 ); } SECTION( "spear" ) { // typical value around 24 - calc_expected_dps( test_guy, "spear_steel", 24.0 ); + calc_expected_dps( test_guy, "spear_steel", 24.5 ); calc_expected_dps( test_guy, "pike", 23.0 ); calc_expected_dps( test_guy, "qiang", 23.0 ); calc_expected_dps( test_guy, "spear_dory", 23 ); @@ -297,9 +296,9 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "halberd", 36.0 ); calc_expected_dps( test_guy, "halberd_fake", 15.0 ); calc_expected_dps( test_guy, "ji", 35.0 ); - calc_expected_dps( test_guy, "glaive", 35.0 ); + calc_expected_dps( test_guy, "glaive", 34.5 ); calc_expected_dps( test_guy, "naginata", 35.0 ); - calc_expected_dps( test_guy, "naginata_inferior", 21.0 ); + calc_expected_dps( test_guy, "naginata_inferior", 21.5 ); calc_expected_dps( test_guy, "naginata_fake", 10.0 ); calc_expected_dps( test_guy, "lucern_hammer", 36.0 ); calc_expected_dps( test_guy, "lucern_hammerfake", 14.0 ); @@ -309,10 +308,10 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) SECTION( "two-handed axe" ) { // typical value around 29 calc_expected_dps( test_guy, "battleaxe", 29.0 ); calc_expected_dps( test_guy, "battleaxe_fake", 11.0 ); - calc_expected_dps( test_guy, "battleaxe_inferior", 20.0 ); + calc_expected_dps( test_guy, "battleaxe_inferior", 19.25 ); calc_expected_dps( test_guy, "fire_ax", 25.0 ); calc_expected_dps( test_guy, "lobotomizer", 24.0 ); - calc_expected_dps( test_guy, "ax", 21.0 ); + calc_expected_dps( test_guy, "ax", 20.25 ); calc_expected_dps( test_guy, "copper_ax", 12.0 ); calc_expected_dps( test_guy, "e_combatsaw_on", 28.0 ); calc_expected_dps( test_guy, "combatsaw_on", 28.0 ); @@ -325,12 +324,12 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "combatsaw_off", 3.0 ); calc_expected_dps( test_guy, "chainsaw_off", 2.0 ); calc_expected_dps( test_guy, "cs_lajatang_off", 2.5 ); - calc_expected_dps( test_guy, "circsaw_off", 2.0 ); + calc_expected_dps( test_guy, "circsaw_off", 1.25 ); } SECTION( "two-handed club/hammer" ) { // expected value ideally around 28 calc_expected_dps( test_guy, "warhammer", 28.0 ); calc_expected_dps( test_guy, "hammer_sledge", 20.0 ); - calc_expected_dps( test_guy, "halligan", 17.0 ); + calc_expected_dps( test_guy, "halligan", 15.25 ); calc_expected_dps( test_guy, "stick_long", 6.0 ); } SECTION( "two-handed flails" ) { // expected value ideally around 28 @@ -339,7 +338,7 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "homewrecker", 13.0 ); } SECTION( "fist weapons" ) { // expected value around 10 but wide variation - calc_expected_dps( test_guy, "bio_claws_weapon", 18.0 ); // basically a knife + calc_expected_dps( test_guy, "bio_claws_weapon", 17.25 ); // basically a knife calc_expected_dps( test_guy, "bagh_nakha", 14.5 ); calc_expected_dps( test_guy, "punch_dagger", 11.0 ); calc_expected_dps( test_guy, "knuckle_katar", 10.5 ); @@ -383,7 +382,7 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "golf_club", 14.0 ); calc_expected_dps( test_guy, "mace_fake", 13.0 ); calc_expected_dps( test_guy, "claw_bar", 11.0 ); - calc_expected_dps( test_guy, "shovel", 11.0 ); + calc_expected_dps( test_guy, "shovel", 10.25 ); calc_expected_dps( test_guy, "e_tool", 11.0 ); calc_expected_dps( test_guy, "sword_nail", 11.0 ); calc_expected_dps( test_guy, "sword_wood", 10.5 ); @@ -401,15 +400,15 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "rock", 6.0 ); } SECTION( "two-handed sword" ) { // expected value around 27, 25 for long swords - calc_expected_dps( test_guy, "nodachi", 27.0 ); + calc_expected_dps( test_guy, "nodachi", 26.5 ); calc_expected_dps( test_guy, "zweihander", 27.0 ); calc_expected_dps( test_guy, "estoc", 27.0 ); - calc_expected_dps( test_guy, "longsword", 25.0 ); + calc_expected_dps( test_guy, "longsword", 24.25 ); calc_expected_dps( test_guy, "katana", 25.0 ); calc_expected_dps( test_guy, "longsword_inferior", 18.5 ); calc_expected_dps( test_guy, "zweihander_inferior", 16.5 ); - calc_expected_dps( test_guy, "katana_inferior", 16.0 ); - calc_expected_dps( test_guy, "nodachi_inferior", 17.0 ); + calc_expected_dps( test_guy, "katana_inferior", 14.0 ); + calc_expected_dps( test_guy, "nodachi_inferior", 16.25 ); calc_expected_dps( test_guy, "estoc_inferior", 16.0 ); calc_expected_dps( test_guy, "estoc_fake", 11.0 ); calc_expected_dps( test_guy, "zweihander_fake", 10.0 ); @@ -428,16 +427,16 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "broadsword_fake", 10.0 ); calc_expected_dps( test_guy, "rapier_fake", 8.0 ); calc_expected_dps( test_guy, "arming_sword_fake", 13.0 ); - calc_expected_dps( test_guy, "jian_fake", 8.0 ); + calc_expected_dps( test_guy, "jian_fake", 8.25 ); calc_expected_dps( test_guy, "glass_macuahuitl", 11.0 ); - calc_expected_dps( test_guy, "blade_scythe", 6.0 ); + calc_expected_dps( test_guy, "blade_scythe", 5.25 ); } SECTION( "shortsword" ) { // expected value 22 calc_expected_dps( test_guy, "scimitar", 22.0 ); calc_expected_dps( test_guy, "butterfly_swords", 22.0 ); calc_expected_dps( test_guy, "cutlass", 22.0 ); - calc_expected_dps( test_guy, "sword_bayonet", 22.0 ); - calc_expected_dps( test_guy, "kukri", 22.0 ); + calc_expected_dps( test_guy, "sword_bayonet", 22.75 ); + calc_expected_dps( test_guy, "kukri", 22.75 ); calc_expected_dps( test_guy, "wakizashi", 22.0 ); calc_expected_dps( test_guy, "sword_xiphos", 22.0 ); calc_expected_dps( test_guy, "khopesh", 21.0 ); @@ -452,7 +451,7 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "wakizashi_inferior", 13.0 ); calc_expected_dps( test_guy, "makeshift_machete", 11.0 ); calc_expected_dps( test_guy, "cavalry_sabre_fake", 8.0 ); - calc_expected_dps( test_guy, "cutlass_fake", 7.0 ); + calc_expected_dps( test_guy, "cutlass_fake", 7.75 ); calc_expected_dps( test_guy, "scimitar_fake", 7.0 ); calc_expected_dps( test_guy, "wakizashi_fake", 7.0 ); calc_expected_dps( test_guy, "blade", 7.0 ); @@ -477,7 +476,7 @@ TEST_CASE( "expected weapon dps", "[expected][dps]" ) calc_expected_dps( test_guy, "copper_knife", 8.0 ); calc_expected_dps( test_guy, "knife_butcher", 7.5 ); calc_expected_dps( test_guy, "throwing_knife", 7.0 ); - calc_expected_dps( test_guy, "tanto_fake", 7.0 ); + calc_expected_dps( test_guy, "tanto_fake", 7.75 ); calc_expected_dps( test_guy, "pockknife", 4.5 ); calc_expected_dps( test_guy, "spike", 4.0 ); calc_expected_dps( test_guy, "kris_fake", 2.5 ); diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index 27ae8fe12a3ff..4d84777ad1664 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -5,23 +5,21 @@ #include #include -#include "avatar.h" #include "catch/catch.hpp" -#include "npc.h" -#include "player.h" #include "bodypart.h" #include "character.h" +#include "debug.h" #include "item.h" #include "material.h" +#include "npc.h" #include "type_id.h" -#include "debug.h" static void test_encumbrance_on( - player &p, + Character &p, const std::vector &clothing, const std::string &body_part, int expected_encumbrance, - const std::function &tweak_player = {} + const std::function &tweak_player = {} ) { CAPTURE( body_part ); @@ -34,8 +32,8 @@ static void test_encumbrance_on( for( const item &i : clothing ) { p.worn.push_back( i ); } - p.reset_encumbrance(); - encumbrance_data enc = p.get_encumbrance()[ get_body_part_token( body_part ) ]; + p.calc_encumbrance(); + encumbrance_data enc = p.get_part_encumbrance_data( bodypart_id( body_part ) ); CHECK( enc.encumbrance == expected_encumbrance ); } @@ -43,7 +41,7 @@ static void test_encumbrance_items( const std::vector &clothing, const std::string &body_part, const int expected_encumbrance, - const std::function &tweak_player = {} + const std::function &tweak_player = {} ) { // Test NPC first because NPC code can accidentally end up using properties @@ -53,7 +51,8 @@ static void test_encumbrance_items( test_encumbrance_on( example_npc, clothing, body_part, expected_encumbrance, tweak_player ); } SECTION( "testing on player" ) { - test_encumbrance_on( get_avatar(), clothing, body_part, expected_encumbrance, tweak_player ); + test_encumbrance_on( get_player_character(), clothing, body_part, expected_encumbrance, + tweak_player ); } } @@ -75,7 +74,7 @@ struct add_trait { add_trait( const std::string &t ) : trait( t ) {} add_trait( const trait_id &t ) : trait( t ) {} - void operator()( player &p ) { + void operator()( Character &p ) { p.toggle_trait( trait ); } @@ -88,47 +87,47 @@ static constexpr int jacket_jean_e = 9; TEST_CASE( "regular_clothing_encumbrance", "[encumbrance]" ) { - test_encumbrance( { "postman_shirt" }, "TORSO", postman_shirt_e ); - test_encumbrance( { "longshirt" }, "TORSO", longshirt_e ); - test_encumbrance( { "jacket_jean" }, "TORSO", jacket_jean_e ); + test_encumbrance( { "postman_shirt" }, "torso", postman_shirt_e ); + test_encumbrance( { "longshirt" }, "torso", longshirt_e ); + test_encumbrance( { "jacket_jean" }, "torso", jacket_jean_e ); } TEST_CASE( "separate_layer_encumbrance", "[encumbrance]" ) { - test_encumbrance( { "longshirt", "jacket_jean" }, "TORSO", longshirt_e + jacket_jean_e ); + test_encumbrance( { "longshirt", "jacket_jean" }, "torso", longshirt_e + jacket_jean_e ); } TEST_CASE( "out_of_order_encumbrance", "[encumbrance]" ) { - test_encumbrance( { "jacket_jean", "longshirt" }, "TORSO", longshirt_e * 2 + jacket_jean_e ); + test_encumbrance( { "jacket_jean", "longshirt" }, "torso", longshirt_e * 2 + jacket_jean_e ); } TEST_CASE( "same_layer_encumbrance", "[encumbrance]" ) { // When stacking within a layer, encumbrance for additional items is // counted twice - test_encumbrance( { "longshirt", "longshirt" }, "TORSO", longshirt_e * 2 + longshirt_e ); + test_encumbrance( { "longshirt", "longshirt" }, "torso", longshirt_e * 2 + longshirt_e ); // ... with a minimum of 2 - test_encumbrance( { "postman_shirt", "postman_shirt" }, "TORSO", postman_shirt_e * 2 + 2 ); + test_encumbrance( { "postman_shirt", "postman_shirt" }, "torso", postman_shirt_e * 2 + 2 ); // ... and a maximum of 10 - test_encumbrance( { "jacket_jean", "jacket_jean" }, "TORSO", jacket_jean_e * 2 + 10 ); + test_encumbrance( { "jacket_jean", "jacket_jean" }, "torso", jacket_jean_e * 2 + 10 ); } TEST_CASE( "tiny_clothing", "[encumbrance]" ) { item i( "longshirt" ); i.set_flag( "UNDERSIZE" ); - test_encumbrance_items( { i }, "TORSO", longshirt_e * 3 ); + test_encumbrance_items( { i }, "torso", longshirt_e * 3 ); } TEST_CASE( "tiny_character", "[encumbrance]" ) { item i( "longshirt" ); SECTION( "regular shirt" ) { - test_encumbrance_items( { i }, "TORSO", longshirt_e * 2, add_trait( "SMALL2" ) ); + test_encumbrance_items( { i }, "torso", longshirt_e * 2, add_trait( "SMALL2" ) ); } SECTION( "undersize shrt" ) { i.set_flag( "UNDERSIZE" ); - test_encumbrance_items( { i }, "TORSO", longshirt_e, add_trait( "SMALL2" ) ); + test_encumbrance_items( { i }, "torso", longshirt_e, add_trait( "SMALL2" ) ); } } diff --git a/tests/explosion_balance_test.cpp b/tests/explosion_balance_test.cpp index 12aade2b89328..c1869945fdccc 100644 --- a/tests/explosion_balance_test.cpp +++ b/tests/explosion_balance_test.cpp @@ -48,7 +48,7 @@ static void check_lethality( const std::string &explosive_id, const int range, f // Spawn some monsters in a circle. tripoint origin( 30, 30, 0 ); int num_subjects_this_time = 0; - for( const tripoint &monster_position : closest_tripoints_first( origin, range ) ) { + for( const tripoint &monster_position : closest_points_first( origin, range ) ) { if( rl_dist( monster_position, origin ) != range ) { continue; } diff --git a/tests/flat_set_test.cpp b/tests/flat_set_test.cpp index f5262888daaeb..b2aea60f0ec5f 100644 --- a/tests/flat_set_test.cpp +++ b/tests/flat_set_test.cpp @@ -74,7 +74,7 @@ TEST_CASE( "flat_set_ranged_operations", "[flat_set]" ) TEST_CASE( "reversed_flat_set_insertion", "[flat_set]" ) { - cata::flat_set> s; + cata::flat_set> s; s.insert( 2 ); s.insert( 1 ); s.insert( 4 ); diff --git a/tests/food_fun_for_test.cpp b/tests/food_fun_for_test.cpp index 6bcd7ac95679a..e862d037325b1 100644 --- a/tests/food_fun_for_test.cpp +++ b/tests/food_fun_for_test.cpp @@ -74,6 +74,7 @@ TEST_CASE( "fun for food eaten while sick", "[fun_for][food][sick]" ) TEST_CASE( "fun for rotten food", "[fun_for][food][rotten]" ) { avatar dummy; + dummy.set_body(); std::pair actual_fun; GIVEN( "some rotten food" ) { @@ -240,6 +241,7 @@ TEST_CASE( "fun for melted food", "[fun_for][food][melted]" ) TEST_CASE( "fun for cat food", "[fun_for][food][cat][feline]" ) { avatar dummy; + dummy.set_body(); std::pair actual_fun; GIVEN( "cat food" ) { @@ -270,6 +272,7 @@ TEST_CASE( "fun for cat food", "[fun_for][food][cat][feline]" ) TEST_CASE( "fun for dog food", "[fun_for][food][dog][lupine]" ) { avatar dummy; + dummy.set_body(); std::pair actual_fun; GIVEN( "dog food" ) { @@ -301,6 +304,7 @@ TEST_CASE( "fun for dog food", "[fun_for][food][dog][lupine]" ) TEST_CASE( "fun for gourmand", "[fun_for][food][gourmand]" ) { avatar dummy; + dummy.set_body(); std::pair actual_fun; GIVEN( "food that tastes good" ) { @@ -404,6 +408,7 @@ TEST_CASE( "fun for food eaten too often", "[fun_for][food][monotony]" ) TEST_CASE( "fun for bionic bio taste blocker", "[fun_for][food][bionic]" ) { avatar dummy; + dummy.set_body(); std::pair actual_fun; GIVEN( "food that tastes bad" ) { diff --git a/tests/ground_destroy_test.cpp b/tests/ground_destroy_test.cpp index 85cbda89f8c5b..48ecba6ca4af9 100644 --- a/tests/ground_destroy_test.cpp +++ b/tests/ground_destroy_test.cpp @@ -4,7 +4,6 @@ #include "avatar.h" #include "catch/catch.hpp" -#include "game.h" #include "int_id.h" #include "item.h" #include "itype.h" @@ -19,21 +18,19 @@ // Destroying pavement with a pickaxe should not leave t_flat_roof. // See issue #24707: // https://github.com/CleverRaven/Cataclysm-DDA/issues/24707 -// Behavior may depend on ZLEVELS being set. TEST_CASE( "pavement_destroy", "[.]" ) { const ter_id flat_roof_id = ter_id( "t_flat_roof" ); REQUIRE( flat_roof_id != t_null ); - const bool zlevels_set = get_option( "ZLEVELS" ); - INFO( "ZLEVELS is " << zlevels_set ); clear_map_and_put_player_underground(); + map &here = get_map(); // Populate the map with pavement. - g->m.ter_set( tripoint_zero, ter_id( "t_pavement" ) ); + here.ter_set( tripoint_zero, ter_id( "t_pavement" ) ); // Destroy it - g->m.destroy( tripoint_zero, true ); - ter_id after_destroy = g->m.ter( tripoint_zero ); + here.destroy( tripoint_zero, true ); + ter_id after_destroy = here.ter( tripoint_zero ); if( after_destroy == flat_roof_id ) { FAIL( flat_roof_id.obj().name() << " found after destroying pavement" ); } else { @@ -44,25 +41,22 @@ TEST_CASE( "pavement_destroy", "[.]" ) // Ground-destroying explosions on dirt or grass shouldn't leave t_flat_roof. // See issue #23250: // https://github.com/CleverRaven/Cataclysm-DDA/issues/23250 -// Behavior may depend on ZLEVELS being set. TEST_CASE( "explosion_on_ground", "[.]" ) { ter_id flat_roof_id = ter_id( "t_flat_roof" ); REQUIRE( flat_roof_id != t_null ); - const bool zlevels_set = get_option( "ZLEVELS" ); - INFO( "ZLEVELS is " << zlevels_set ); - clear_map_and_put_player_underground(); std::vector test_terrain_id = { ter_id( "t_dirt" ), ter_id( "t_grass" ) }; + map &here = get_map(); int idx = 0; const int area_dim = 16; // Populate map with various test terrain. for( int x = 0; x < area_dim; x++ ) { for( int y = 0; y < area_dim; y++ ) { - g->m.ter_set( tripoint( x, y, 0 ), test_terrain_id[idx] ); + here.ter_set( tripoint( x, y, 0 ), test_terrain_id[idx] ); idx = ( idx + 1 ) % test_terrain_id.size(); } } @@ -73,13 +67,13 @@ TEST_CASE( "explosion_on_ground", "[.]" ) const tripoint area_center( area_dim / 2, area_dim / 2, 0 ); item rdx_keg( rdx_keg_typeid ); rdx_keg.charges = 0; - rdx_keg.type->invoke( g->u, rdx_keg, area_center ); + rdx_keg.type->invoke( get_avatar(), rdx_keg, area_center ); // Check area to see if any t_flat_roof is present. for( int x = 0; x < area_dim; x++ ) { for( int y = 0; y < area_dim; y++ ) { tripoint pt( x, y, 0 ); - ter_id t_id = g->m.ter( pt ); + ter_id t_id = here.ter( pt ); if( t_id == flat_roof_id ) { FAIL( "After explosion, " << t_id.obj().name() << " found at " << x << "," << y ); } @@ -90,7 +84,6 @@ TEST_CASE( "explosion_on_ground", "[.]" ) // Ground-destroying explosions on t_floor with a t_rock_floor basement // below should create some t_open_air, not just t_flat_roof (which is // the defined roof of a t_rock-floor). -// Behavior depends on ZLEVELS being set. TEST_CASE( "explosion_on_floor_with_rock_floor_basement", "[.]" ) { ter_id flat_roof_id = ter_id( "t_flat_roof" ); @@ -103,16 +96,14 @@ TEST_CASE( "explosion_on_floor_with_rock_floor_basement", "[.]" ) REQUIRE( rock_floor_id != t_null ); REQUIRE( open_air_id != t_null ); - const bool zlevels_set = get_option( "ZLEVELS" ); - INFO( "ZLEVELS is " << zlevels_set ); - clear_map_and_put_player_underground(); + map &here = get_map(); const int area_dim = 24; for( int x = 0; x < area_dim; x++ ) { for( int y = 0; y < area_dim; y++ ) { - g->m.ter_set( tripoint( x, y, 0 ), floor_id ); - g->m.ter_set( tripoint( x, y, -1 ), rock_floor_id ); + here.ter_set( tripoint( x, y, 0 ), floor_id ); + here.ter_set( tripoint( x, y, -1 ), rock_floor_id ); } } // Detonate an RDX keg item in the middle of the populated map space @@ -122,14 +113,14 @@ TEST_CASE( "explosion_on_floor_with_rock_floor_basement", "[.]" ) const tripoint area_center( area_dim / 2, area_dim / 2, 0 ); item rdx_keg( rdx_keg_typeid ); rdx_keg.charges = 0; - rdx_keg.type->invoke( g->u, rdx_keg, area_center ); + rdx_keg.type->invoke( get_avatar(), rdx_keg, area_center ); // Check z0 for open air bool found_open_air = false; for( int x = 0; x < area_dim; x++ ) { for( int y = 0; y < area_dim; y++ ) { tripoint pt( x, y, 0 ); - ter_id t_id = g->m.ter( pt ); + ter_id t_id = here.ter( pt ); INFO( "t " << t_id.obj().name() << " at " << x << "," << y ); if( t_id == open_air_id ) { found_open_air = true; @@ -148,7 +139,6 @@ TEST_CASE( "explosion_on_floor_with_rock_floor_basement", "[.]" ) // Destroying interior floors shouldn't cause the roofs above to collapse. // Destroying supporting walls should cause the roofs above to collapse. -// Behavior may depend on ZLEVELS being set. TEST_CASE( "collapse_checks", "[.]" ) { constexpr int wall_size = 5; @@ -163,14 +153,13 @@ TEST_CASE( "collapse_checks", "[.]" ) REQUIRE( wall_id != t_null ); REQUIRE( open_air_id != t_null ); - const bool zlevels_set = get_option( "ZLEVELS" ); - INFO( "ZLEVELS is " << zlevels_set ); clear_map_and_put_player_underground(); + map &here = get_map(); // build a structure const tripoint &midair = tripoint( tripoint_zero.xy(), tripoint_zero.z + 1 ); - for( const tripoint &pt : g->m.points_in_radius( midair, wall_size, 1 ) ) { - g->m.ter_set( pt, floor_id ); + for( const tripoint &pt : here.points_in_radius( midair, wall_size, 1 ) ) { + here.ter_set( pt, floor_id ); } std::set corners; for( int delta_z = 0; delta_z < 3; delta_z++ ) { @@ -178,31 +167,31 @@ TEST_CASE( "collapse_checks", "[.]" ) for( int delta_y = 0; delta_y <= 1; delta_y++ ) { const tripoint pt( delta_x * wall_size, delta_y * wall_size, delta_z ); corners.insert( pt ); - g->m.ter_set( pt, wall_id ); + here.ter_set( pt, wall_id ); } } } // make sure it's a valid structure - for( const tripoint &pt : g->m.points_in_radius( midair, wall_size, 1 ) ) { + for( const tripoint &pt : here.points_in_radius( midair, wall_size, 1 ) ) { if( corners.find( pt ) != corners.end() ) { - REQUIRE( g->m.ter( pt ) == wall_id ); + REQUIRE( here.ter( pt ) == wall_id ); } else { - REQUIRE( g->m.ter( pt ) == floor_id ); + REQUIRE( here.ter( pt ) == floor_id ); } } // destroy the floor on the first floor; floor above should not collapse - for( const tripoint &pt : g->m.points_in_radius( tripoint_zero, wall_size ) ) { + for( const tripoint &pt : here.points_in_radius( tripoint_zero, wall_size ) ) { if( corners.find( pt ) == corners.end() ) { - g->m.destroy( pt, true ); + here.destroy( pt, true ); } } - for( const tripoint &pt : g->m.points_in_radius( midair, wall_size ) ) { + for( const tripoint &pt : here.points_in_radius( midair, wall_size ) ) { if( corners.find( pt ) != corners.end() ) { - CHECK( g->m.ter( pt ) == wall_id ); + CHECK( here.ter( pt ) == wall_id ); } else { - CHECK( g->m.ter( pt ) == floor_id ); + CHECK( here.ter( pt ) == floor_id ); } } @@ -210,17 +199,17 @@ TEST_CASE( "collapse_checks", "[.]" ) for( int delta_x = 0; delta_x <= 1; delta_x++ ) { for( int delta_y = 0; delta_y <= 1; delta_y++ ) { const tripoint pt( delta_x * wall_size, delta_y * wall_size, 0 ); - g->m.destroy( pt, true ); + here.destroy( pt, true ); } } int open_air_count = 0; int tile_count = 0; int no_wall_count = 0; - for( const tripoint &pt : g->m.points_in_radius( midair, wall_size, 1 ) ) { + for( const tripoint &pt : here.points_in_radius( midair, wall_size, 1 ) ) { if( pt.z == 0 ) { continue; } - const ter_id t_id = g->m.ter( pt ); + const ter_id t_id = here.ter( pt ); tile_count += 1; if( t_id == t_open_air ) { open_air_count += 1; diff --git a/tests/item_contents_test.cpp b/tests/item_contents_test.cpp index 6c74b339cfb14..ce13bfd485f82 100644 --- a/tests/item_contents_test.cpp +++ b/tests/item_contents_test.cpp @@ -17,10 +17,27 @@ TEST_CASE( "item_contents" ) item wrench( "wrench" ); item crowbar( "crowbar" ); - tool_belt.put_in( hammer, item_pocket::pocket_type::CONTAINER ); - tool_belt.put_in( tongs, item_pocket::pocket_type::CONTAINER ); - tool_belt.put_in( wrench, item_pocket::pocket_type::CONTAINER ); - tool_belt.put_in( crowbar, item_pocket::pocket_type::CONTAINER ); + ret_val i1 = tool_belt.put_in( hammer, item_pocket::pocket_type::CONTAINER ); + ret_val i2 = tool_belt.put_in( tongs, item_pocket::pocket_type::CONTAINER ); + ret_val i3 = tool_belt.put_in( wrench, item_pocket::pocket_type::CONTAINER ); + ret_val i4 = tool_belt.put_in( crowbar, item_pocket::pocket_type::CONTAINER ); + + { + CAPTURE( i1.str() ); + CHECK( i1.success() ); + } + { + CAPTURE( i2.str() ); + CHECK( i2.success() ); + } + { + CAPTURE( i3.str() ); + CHECK( i3.success() ); + } + { + CAPTURE( i4.str() ); + CHECK( i4.success() ); + } // check the items actually got added to the tool belt REQUIRE( tool_belt.contents.num_item_stacks() == 4 ); diff --git a/tests/item_location_test.cpp b/tests/item_location_test.cpp index 03a94bbab44c9..ea95b1e1990ce 100644 --- a/tests/item_location_test.cpp +++ b/tests/item_location_test.cpp @@ -2,8 +2,8 @@ #include #include -#include "avatar.h" #include "catch/catch.hpp" +#include "character.h" #include "item.h" #include "map_helpers.h" #include "rng.h" @@ -68,7 +68,7 @@ TEST_CASE( "item_location_doesnt_return_stale_map_item", "[item][item_location]" TEST_CASE( "item_in_container", "[item][item_location]" ) { - avatar &dummy = get_avatar(); + Character &dummy = get_player_character(); clear_avatar(); item &backpack = dummy.i_add( item( "backpack" ) ); item jeans( "jeans" ); @@ -77,7 +77,7 @@ TEST_CASE( "item_in_container", "[item][item_location]" ) backpack.put_in( jeans, item_pocket::pocket_type::CONTAINER ); - item_location backpack_loc( dummy, & **dummy.wear( backpack ) ); + item_location backpack_loc( dummy, & **dummy.wear_item( backpack ) ); REQUIRE( dummy.has_item( *backpack_loc ) ); diff --git a/tests/item_tname_test.cpp b/tests/item_tname_test.cpp index f97b39c9e68ef..f3d13560e9c28 100644 --- a/tests/item_tname_test.cpp +++ b/tests/item_tname_test.cpp @@ -386,7 +386,7 @@ TEST_CASE( "weapon fouling", "[item][tname][fouling][dirt]" ) // Ensure the player and gun are normal size to prevent "too big" or "too small" suffix in tname g->u.clear_mutations(); - REQUIRE( gun.get_sizing( g-> u, true ) == item::sizing::human_sized_human_char ); + REQUIRE( gun.get_sizing( g-> u ) == item::sizing::ignore ); REQUIRE_FALSE( gun.has_flag( "OVERSIZE" ) ); REQUIRE_FALSE( gun.has_flag( "UNDERSIZE" ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 0d2ea0397f26f..013a4cfb0777f 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -64,7 +64,7 @@ static std::string item_info_str( const item &it, const std::vectoru, true ) ); + //CAPTURE( i.get_sizing( get_avatar(), true ) ); std::vector info_v; const iteminfo_query query_v( part_flags ); @@ -187,7 +187,7 @@ TEST_CASE( "item owner", "[iteminfo][owner]" ) SECTION( "item owned by player" ) { item my_rock( "test_rock" ); - my_rock.set_owner( g->u ); + my_rock.set_owner( get_player_character() ); REQUIRE_FALSE( my_rock.get_owner().is_null() ); CHECK( item_info_str( my_rock, { iteminfo_parts::BASE_OWNER } ) == "Owner: Your Followers\n" ); } @@ -359,6 +359,7 @@ TEST_CASE( "item price and barter value", "[iteminfo][price]" ) // "encumbrance" // "max_encumbrance" // "pocket_data" +// "coverage" // - "rigid" // - "max_contains_volume" // @@ -377,7 +378,19 @@ TEST_CASE( "item rigidity", "[iteminfo][rigidity]" ) REQUIRE( briefcase.contents.all_pockets_rigid() ); CHECK( item_info_str( briefcase, encumbrance ) == "--\n" - "Encumbrance: 30\n" ); + "Encumbrance:\n" + "L. Arm: 30 " + "When Full: 30 " + "Coverage: 10\n" + "R. Arm: 30 " + "When Full: 30 " + "Coverage: 10\n" + "L. Hand: 30 " + "When Full: 30 " + "Coverage: 10\n" + "R. Hand: 30 " + "When Full: 30 " + "Coverage: 10\n" ); } SECTION( "non-rigid items indicate their flexible volume/encumbrance" ) { @@ -412,20 +425,32 @@ TEST_CASE( "item rigidity", "[iteminfo][rigidity]" ) // based on the pocket "max_contains_volume" (1 encumbrance per 250 ml). CHECK( item_info_str( waterskin, encumbrance ) == "--\n" - "Encumbrance: 0" - " Encumbrance when full: 6\n" ); + "Encumbrance:\n" + "L. Leg: 0 " + "When Full: 6 " + "Coverage: 5\n" + "R. Leg: 0 " + "When Full: 6 " + "Coverage: 5\n" ); // test_backpack has an explicit "encumbrance" and "max_encumbrance" CHECK( item_info_str( backpack, encumbrance ) == "--\n" - "Encumbrance: 2" - " Encumbrance when full: 15\n" ); + "Encumbrance:\n" + "Torso: 2 " + "When Full: 15 " + "Coverage: 30\n" ); // quiver has no volume, only an implicit volume via ammo CHECK( item_info_str( quiver, encumbrance ) == "--\n" - "Encumbrance: 3" - " Encumbrance when full: 11\n" ); + "Encumbrance:\n" + "L. Leg: 3 " + "When Full: 11 " + "Coverage: 10\n" + "R. Leg: 3 " + "When Full: 11 " + "Coverage: 10\n" ); } } } @@ -440,9 +465,10 @@ TEST_CASE( "item rigidity", "[iteminfo][rigidity]" ) TEST_CASE( "weapon attack ratings and moves", "[iteminfo][weapon]" ) { clear_avatar(); + Character &player_character = get_player_character(); // new DPS calculations depend on the avatar's stats, so make sure they're consistent - REQUIRE( g->u.get_str() == 8 ); - REQUIRE( g->u.get_dex() == 8 ); + REQUIRE( player_character.get_str() == 8 ); + REQUIRE( player_character.get_dex() == 8 ); item rag( "test_rag" ); item rock( "test_rock" ); @@ -625,6 +651,17 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag // Long-sleeved shirt covering torso and arms item longshirt( "test_longshirt" ); REQUIRE( longshirt.get_covered_body_parts().any() ); + REQUIRE( longshirt.get_coverage( bodypart_id( "torso" ) ) == 90 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "arm_l" ) ) == 90 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "arm_r" ) ) == 90 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "leg_l" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "leg_r" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "head" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( longshirt.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); CHECK( item_info_str( longshirt, { iteminfo_parts::ARMOR_BODYPARTS } ) == "--\n" @@ -637,20 +674,324 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Layer: Normal. \n" ); // NOLINT(cata-text-style) // Coverage and warmth are displayed together on a single line - std::vector cov_warm = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; - REQUIRE( longshirt.get_coverage() == 90 ); + std::vector cov_warm_shirt = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + REQUIRE( longshirt.get_avg_coverage() == 90 ); REQUIRE( longshirt.get_warmth() == 5 ); - CHECK( item_info_str( longshirt, cov_warm ) + CHECK( item_info_str( longshirt, cov_warm_shirt ) == "--\n" - "Coverage: 90% Warmth: 5\n" ); + "Average Coverage: 90% Warmth: 5\n" ); + + REQUIRE( longshirt.get_avg_encumber( get_player_character() ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); + + REQUIRE( longshirt.get_avg_encumber( get_player_character(), + item::encumber_flags::assume_full ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "torso" ), + item::encumber_flags::assume_full ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_l" ), + item::encumber_flags::assume_full ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_r" ), + item::encumber_flags::assume_full ) == 3 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_r" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_r" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "head" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "mouth" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_r" ), + item::encumber_flags::assume_full ) == 0 ); + - REQUIRE( longshirt.get_encumber( g->u ) == 3 ); CHECK( item_info_str( longshirt, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" - "Encumbrance:" - " 3" - " (poor fit)\n" ); + "Encumbrance: (poor fit)\n" + "Arms: 3 " + "When Full: 3 " + "Coverage: 90\n" + "Torso: 3 " + "When Full: 3 " + "Coverage: 90\n" ); + + item swat_armor( "test_swat_armor" ); + REQUIRE( swat_armor.get_covered_body_parts().any() ); + + CHECK( item_info_str( swat_armor, { iteminfo_parts::ARMOR_BODYPARTS } ) == + "--\n" + "Covers:" + " The torso." + " The arms." + " The legs. \n" ); + + CHECK( item_info_str( swat_armor, { iteminfo_parts::ARMOR_LAYER } ) == + "--\n" + "Layer: Normal. \n" ); + + std::vector cov_warm_swat = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + REQUIRE( swat_armor.get_avg_coverage() == 95 ); + REQUIRE( swat_armor.get_warmth() == 35 ); + CHECK( item_info_str( swat_armor, cov_warm_swat ) + == + "--\n" + "Average Coverage: 95% Warmth: 35\n" ); + + REQUIRE( swat_armor.get_coverage( bodypart_id( "torso" ) ) == 95 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "leg_l" ) ) == 95 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "leg_r" ) ) == 95 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "arm_l" ) ) == 95 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "arm_r" ) ) == 95 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "head" ) ) == 0 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "eyes" ) ) == 0 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); + REQUIRE( swat_armor.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); + + REQUIRE( swat_armor.get_avg_encumber( get_player_character() ) == 12 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 12 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 12 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 12 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 12 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 12 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); + + + REQUIRE( swat_armor.get_avg_encumber( get_player_character(), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "torso" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_l" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_r" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_l" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_r" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_r" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "head" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "eyes" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "mouth" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_r" ), + item::encumber_flags::assume_full ) == 0 ); + + CHECK( item_info_str( swat_armor, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == + "--\n" + "Encumbrance:\n" + "Arms: 12 " + "When Full: 25 " + "Coverage: 95\n" + "Legs: 12 " + "When Full: 25 " + "Coverage: 95\n" + "Torso: 12 " + "When Full: 25 " + "Coverage: 95\n" ); + + // Test copy-from + item faux_fur_pants( "test_pants_faux_fur" ); + REQUIRE( faux_fur_pants.get_covered_body_parts().any() ); + + CHECK( item_info_str( faux_fur_pants, { iteminfo_parts::ARMOR_BODYPARTS } ) == + "--\n" + "Covers:" + " The legs. \n" ); + + CHECK( item_info_str( faux_fur_pants, { iteminfo_parts::ARMOR_LAYER } ) == + "--\n" + "Layer: Normal. \n" ); + + std::vector cov_warm_pants = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + REQUIRE( faux_fur_pants.get_avg_coverage() == 95 ); + REQUIRE( faux_fur_pants.get_warmth() == 70 ); + CHECK( item_info_str( faux_fur_pants, cov_warm_pants ) + == + "--\n" + "Average Coverage: 95% Warmth: 70\n" ); + + REQUIRE( faux_fur_pants.get_avg_coverage() == 95 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "leg_l" ) ) == 95 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "leg_r" ) ) == 95 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "arm_l" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "arm_r" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "head" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "eyes" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); + + REQUIRE( faux_fur_pants.get_avg_encumber( get_player_character() ) == 16 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 16 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 16 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); + + REQUIRE( faux_fur_pants.get_avg_encumber( get_player_character(), + item::encumber_flags::assume_full ) == 20 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_l" ), + item::encumber_flags::assume_full ) == 20 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_r" ), + item::encumber_flags::assume_full ) == 20 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_r" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_r" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "head" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "eyes" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "mouth" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_r" ), + item::encumber_flags::assume_full ) == 0 ); + + item faux_fur_suit( "test_portion_faux_fur_pants_suit" ); + REQUIRE( faux_fur_suit.get_covered_body_parts().any() ); + + CHECK( item_info_str( faux_fur_suit, { iteminfo_parts::ARMOR_BODYPARTS } ) == + "--\n" + "Covers:" + " The head." + " The torso." + " The arms." + " The legs. \n" ); + + CHECK( item_info_str( faux_fur_suit, { iteminfo_parts::ARMOR_LAYER } ) == + "--\n" + "Layer: Normal. \n" ); + + std::vector cov_warm_suit = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + REQUIRE( faux_fur_suit.get_avg_coverage() == 75 ); + REQUIRE( faux_fur_suit.get_warmth() == 5 ); + CHECK( item_info_str( faux_fur_suit, cov_warm_suit ) + == + "--\n" + "Average Coverage: 75% Warmth: 5\n" ); + + REQUIRE( faux_fur_suit.get_avg_coverage() == 75 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "torso" ) ) == 100 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "leg_l" ) ) == 50 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "leg_r" ) ) == 100 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "arm_l" ) ) == 50 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "arm_r" ) ) == 100 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "head" ) ) == 50 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "eyes" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); + + REQUIRE( faux_fur_suit.get_avg_encumber( get_player_character() ) == 7 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 10 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 5 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 10 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 5 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 10 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 5 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); + + REQUIRE( faux_fur_suit.get_avg_encumber( get_player_character(), + item::encumber_flags::assume_full ) == 17 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "torso" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_l" ), + item::encumber_flags::assume_full ) == 9 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_r" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_l" ), + item::encumber_flags::assume_full ) == 9 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_r" ), + item::encumber_flags::assume_full ) == 25 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "head" ), + item::encumber_flags::assume_full ) == 9 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "eyes" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "mouth" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_l" ), + item::encumber_flags::assume_full ) == 0 ); + REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_r" ), + item::encumber_flags::assume_full ) == 0 ); + + CHECK( item_info_str( faux_fur_suit, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == + "--\n" + "Encumbrance: (poor fit)\n" + "L. Arm: 5 " + "When Full: 9 " + "Coverage: 50\n" + "R. Arm: 10 " + "When Full: 25 " + "Coverage: 100\n" + "Head: 5 " + "When Full: 9 " + "Coverage: 50\n" + "L. Leg: 5 " + "When Full: 9 " + "Coverage: 50\n" + "R. Leg: 10 " + "When Full: 25 " + "Coverage: 100\n" + "Torso: 10 " + "When Full: 25 " + "Coverage: 100\n" ); } SECTION( "armor with no coverage omits irrelevant info" ) { @@ -860,8 +1201,9 @@ TEST_CASE( "book info", "[iteminfo][book]" ) } WHEN( "book has been identified" ) { - g->u.do_read( cmdline ); - g->u.do_read( dragon ); + avatar &player_character = get_avatar(); + player_character.do_read( cmdline ); + player_character.do_read( dragon ); THEN( "some basic book info is shown" ) { CHECK( item_info_str( cmdline, summary ) == @@ -1358,9 +1700,10 @@ TEST_CASE( "food freshness and lifetime", "[iteminfo][food]" ) { clear_avatar(); + Character &player_character = get_player_character(); // Ensure test character has no skill estimating spoilage - g->u.empty_skills(); - REQUIRE_FALSE( g->u.can_estimate_rot() ); + player_character.empty_skills(); + REQUIRE_FALSE( player_character.can_estimate_rot() ); item nuts( "test_pine_nuts" ); REQUIRE( nuts.goes_bad() ); @@ -1446,12 +1789,13 @@ TEST_CASE( "basic food info", "[iteminfo][food]" ) TEST_CASE( "food character is allergic to", "[iteminfo][food][allergy]" ) { clear_avatar(); + Character &player_character = get_player_character(); std::vector allergen = { iteminfo_parts::FOOD_ALLERGEN }; GIVEN( "character allergic to fruit" ) { - g->u.toggle_trait( trait_id( "ANTIFRUIT" ) ); - REQUIRE( g->u.has_trait( trait_id( "ANTIFRUIT" ) ) ); + player_character.toggle_trait( trait_id( "ANTIFRUIT" ) ); + REQUIRE( player_character.has_trait( trait_id( "ANTIFRUIT" ) ) ); THEN( "fruit indicates an allergic reaction" ) { item apple( "test_apple" ); @@ -1494,11 +1838,12 @@ TEST_CASE( "food with hidden poison or hallucinogen", "[iteminfo][food][poison][ std::vector poison = { iteminfo_parts::FOOD_POISON }; std::vector hallu = { iteminfo_parts::FOOD_HALLUCINOGENIC }; + Character &player_character = get_player_character(); // Seeing hidden poison or hallucinogen depends on character survival skill // At low level, no info is shown GIVEN( "survival 2" ) { - g->u.set_skill_level( skill_id( "survival" ), 2 ); - REQUIRE( g->u.get_skill_level( skill_id( "survival" ) ) == 2 ); + player_character.set_skill_level( skill_id( "survival" ), 2 ); + REQUIRE( player_character.get_skill_level( skill_id( "survival" ) ) == 2 ); THEN( "cannot see hidden poison or hallucinogen" ) { CHECK( item_info_str( almond, poison ).empty() ); @@ -1508,8 +1853,8 @@ TEST_CASE( "food with hidden poison or hallucinogen", "[iteminfo][food][poison][ // Hidden poison is visible at survival level 3 GIVEN( "survival 3" ) { - g->u.set_skill_level( skill_id( "survival" ), 3 ); - REQUIRE( g->u.get_skill_level( skill_id( "survival" ) ) == 3 ); + player_character.set_skill_level( skill_id( "survival" ), 3 ); + REQUIRE( player_character.get_skill_level( skill_id( "survival" ) ) == 3 ); THEN( "can see hidden poison" ) { CHECK( item_info_str( almond, poison ) == @@ -1525,8 +1870,8 @@ TEST_CASE( "food with hidden poison or hallucinogen", "[iteminfo][food][poison][ // Hidden hallucinogen is not visible until survival level 5 GIVEN( "survival 4" ) { - g->u.set_skill_level( skill_id( "survival" ), 4 ); - REQUIRE( g->u.get_skill_level( skill_id( "survival" ) ) == 4 ); + player_character.set_skill_level( skill_id( "survival" ), 4 ); + REQUIRE( player_character.get_skill_level( skill_id( "survival" ) ) == 4 ); THEN( "still cannot see hidden hallucinogen" ) { CHECK( item_info_str( nutmeg, hallu ).empty() ); @@ -1534,8 +1879,8 @@ TEST_CASE( "food with hidden poison or hallucinogen", "[iteminfo][food][poison][ } GIVEN( "survival 5" ) { - g->u.set_skill_level( skill_id( "survival" ), 5 ); - REQUIRE( g->u.get_skill_level( skill_id( "survival" ) ) == 5 ); + player_character.set_skill_level( skill_id( "survival" ), 5 ); + REQUIRE( player_character.get_skill_level( skill_id( "survival" ) ) == 5 ); THEN( "can see hidden hallucinogen" ) { CHECK( item_info_str( nutmeg, hallu ) == @@ -1556,6 +1901,7 @@ TEST_CASE( "food that is made of human flesh", "[iteminfo][food][cannibal]" ) // TODO: Test food that is_tainted(): "This food is *tainted* and will poison you" clear_avatar(); + Character &player_character = get_player_character(); std::vector cannibal = { iteminfo_parts::FOOD_CANNIBALISM }; @@ -1563,7 +1909,7 @@ TEST_CASE( "food that is made of human flesh", "[iteminfo][food][cannibal]" ) REQUIRE( thumb.has_flag( "CANNIBALISM" ) ); GIVEN( "character is not a cannibal" ) { - REQUIRE_FALSE( g->u.has_trait( trait_id( "CANNIBAL" ) ) ); + REQUIRE_FALSE( player_character.has_trait( trait_id( "CANNIBAL" ) ) ); THEN( "human flesh is indicated as bad" ) { // red highlight CHECK( item_info_str( thumb, cannibal ) == @@ -1573,8 +1919,8 @@ TEST_CASE( "food that is made of human flesh", "[iteminfo][food][cannibal]" ) } GIVEN( "character is a cannibal" ) { - g->u.toggle_trait( trait_id( "CANNIBAL" ) ); - REQUIRE( g->u.has_trait( trait_id( "CANNIBAL" ) ) ); + player_character.toggle_trait( trait_id( "CANNIBAL" ) ); + REQUIRE( player_character.has_trait( trait_id( "CANNIBAL" ) ) ); THEN( "human flesh is indicated as good" ) { // green highlight @@ -1948,19 +2294,21 @@ TEST_CASE( "item description flags", "[iteminfo][flags]" ) TEST_CASE( "show available recipes with item as an ingredient", "[iteminfo][recipes]" ) { clear_avatar(); + avatar &player_character = get_avatar(); const recipe *purtab = &recipe_id( "pur_tablets" ).obj(); - recipe_subset &known_recipes = const_cast( g->u.get_learned_recipes() ); + recipe_subset &known_recipes = const_cast + ( player_character.get_learned_recipes() ); known_recipes.clear(); // FIXME: Factor out of final_info std::vector crafting = { iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES }; GIVEN( "character has a potassium iodide tablet and no skill" ) { - g->u.worn.push_back( item( "backpack" ) ); - item &iodine = g->u.i_add( item( "iodine" ) ); - g->u.empty_skills(); - REQUIRE( !g->u.knows_recipe( purtab ) ); + player_character.worn.push_back( item( "backpack" ) ); + item &iodine = player_character.i_add( item( "iodine" ) ); + player_character.empty_skills(); + REQUIRE( !player_character.knows_recipe( purtab ) ); THEN( "nothing is craftable from it" ) { CHECK( item_info_str( iodine, crafting ) == @@ -1968,8 +2316,8 @@ TEST_CASE( "show available recipes with item as an ingredient", "[iteminfo][reci } WHEN( "they acquire the needed skills" ) { - g->u.set_skill_level( purtab->skill_used, purtab->difficulty ); - REQUIRE( g->u.get_skill_level( purtab->skill_used ) == purtab->difficulty ); + player_character.set_skill_level( purtab->skill_used, purtab->difficulty ); + REQUIRE( player_character.get_skill_level( purtab->skill_used ) == purtab->difficulty ); THEN( "still nothing is craftable from it" ) { CHECK( item_info_str( iodine, crafting ) == @@ -1977,8 +2325,8 @@ TEST_CASE( "show available recipes with item as an ingredient", "[iteminfo][reci } WHEN( "they have no book, but have the recipe memorized" ) { - g->u.learn_recipe( purtab ); - REQUIRE( g->u.knows_recipe( purtab ) ); + player_character.learn_recipe( purtab ); + REQUIRE( player_character.knows_recipe( purtab ) ); THEN( "they can use potassium iodide tablets to craft it" ) { CHECK( item_info_str( iodine, crafting ) == @@ -1989,11 +2337,11 @@ TEST_CASE( "show available recipes with item as an ingredient", "[iteminfo][reci } WHEN( "they have the recipe in a book, but not memorized" ) { - item &textbook = g->u.i_add( item( "textbook_chemistry" ) ); - g->u.do_read( textbook ); - REQUIRE( g->u.has_identified( itype_id( "textbook_chemistry" ) ) ); + item &textbook = player_character.i_add( item( "textbook_chemistry" ) ); + player_character.do_read( textbook ); + REQUIRE( player_character.has_identified( itype_id( "textbook_chemistry" ) ) ); // update the crafting inventory cache - g->u.moves++; + player_character.moves++; THEN( "they can use potassium iodide tablets to craft it" ) { CHECK( item_info_str( iodine, crafting ) == @@ -2117,7 +2465,7 @@ TEST_CASE( "pocket info for a multi-pocket item", "[iteminfo][pocket][multiple]" "--\n" "4 Pockets with capacity:\n" "Volume: 1.50 L Weight: 1.00 kg\n" - "Maximum item length: 155 mm\n" + "Maximum item length: 60 cm\n" "Minimum item volume: 0.050 L\n" "Base moves to remove item: 50\n" ); } @@ -2221,14 +2569,15 @@ TEST_CASE( "weight_to_info", "[iteminfo][weight]" ) TEST_CASE( "final info", "[iteminfo][final]" ) { clear_avatar(); + Character &player_character = get_player_character(); SECTION( "material allergy" ) { item socks( "test_socks" ); REQUIRE( socks.made_of( material_id( "wool" ) ) ); WHEN( "avatar has a wool allergy" ) { - g->u.toggle_trait( trait_id( "WOOLALLERGY" ) ); - REQUIRE( g->u.has_trait( trait_id( "WOOLALLERGY" ) ) ); + player_character.toggle_trait( trait_id( "WOOLALLERGY" ) ); + REQUIRE( player_character.has_trait( trait_id( "WOOLALLERGY" ) ) ); CHECK( item_info_str( socks, { iteminfo_parts::DESCRIPTION_ALLERGEN } ) == "--\n" @@ -2322,4 +2671,3 @@ TEST_CASE( "item debug info", "[iteminfo][debug][!mayfail][.]" ) "Freeze point: 32\n" ); } } - diff --git a/tests/itemname_test.cpp b/tests/itemname_test.cpp index f5c79dbe8540d..728c5fdd5bb86 100644 --- a/tests/itemname_test.cpp +++ b/tests/itemname_test.cpp @@ -35,7 +35,7 @@ TEST_CASE( "item sizing display", "[item][iteminfo][display_name][sizing]" ) std::string name = i.display_name(); THEN( "we have the correct sizing" ) { - const item::sizing sizing_level = i.get_sizing( g->u, true ); + const item::sizing sizing_level = i.get_sizing( g->u ); CHECK( sizing_level == item::sizing::small_sized_human_char ); } @@ -71,7 +71,7 @@ TEST_CASE( "item sizing display", "[item][iteminfo][display_name][sizing]" ) std::string name = i.display_name(); THEN( "we have the correct sizing" ) { - const item::sizing sizing_level = i.get_sizing( g->u, true ); + const item::sizing sizing_level = i.get_sizing( g->u ); CHECK( sizing_level == item::sizing::small_sized_big_char ); } @@ -107,7 +107,7 @@ TEST_CASE( "item sizing display", "[item][iteminfo][display_name][sizing]" ) std::string name = i.display_name(); THEN( "we have the correct sizing" ) { - const item::sizing sizing_level = i.get_sizing( g->u, true ); + const item::sizing sizing_level = i.get_sizing( g->u ); CHECK( sizing_level == item::sizing::small_sized_small_char ); } diff --git a/tests/iuse_actor_test.cpp b/tests/iuse_actor_test.cpp index 91cadb681680c..ca9c7e54ee01f 100644 --- a/tests/iuse_actor_test.cpp +++ b/tests/iuse_actor_test.cpp @@ -16,15 +16,14 @@ static player &get_sanitized_player( ) { - player &dummy = g->u; - + avatar &player_character = get_avatar(); // Remove first worn item until there are none left. std::list temp; - while( dummy.takeoff( dummy.i_at( -2 ), &temp ) ) {} - dummy.inv.clear(); - dummy.remove_weapon(); + while( player_character.takeoff( player_character.i_at( -2 ), &temp ) ) {} + player_character.inv.clear(); + player_character.remove_weapon(); - return dummy; + return player_character; } static monster *find_adjacent_monster( const tripoint &pos ) @@ -45,23 +44,23 @@ static monster *find_adjacent_monster( const tripoint &pos ) TEST_CASE( "manhack", "[iuse_actor][manhack]" ) { - player &dummy = get_sanitized_player(); + player &player_character = get_sanitized_player(); g->clear_zombies(); - item &test_item = dummy.i_add( item( "bot_manhack", 0, item::default_charges_tag{} ) ); + item &test_item = player_character.i_add( item( "bot_manhack", 0, item::default_charges_tag{} ) ); - REQUIRE( dummy.has_item( test_item ) ); + REQUIRE( player_character.has_item( test_item ) ); - monster *new_manhack = find_adjacent_monster( dummy.pos() ); + monster *new_manhack = find_adjacent_monster( player_character.pos() ); REQUIRE( new_manhack == nullptr ); - dummy.invoke_item( &test_item ); + player_character.invoke_item( &test_item ); - REQUIRE( !dummy.has_item_with( []( const item & it ) { + REQUIRE( !player_character.has_item_with( []( const item & it ) { return it.typeId() == itype_id( "bot_manhack" ); } ) ); - new_manhack = find_adjacent_monster( dummy.pos() ); + new_manhack = find_adjacent_monster( player_character.pos() ); REQUIRE( new_manhack != nullptr ); REQUIRE( new_manhack->type->id == mtype_id( "mon_manhack" ) ); g->clear_zombies(); diff --git a/tests/list_test.cpp b/tests/list_test.cpp index e6f28f4e5683e..1aa6122d580e3 100644 --- a/tests/list_test.cpp +++ b/tests/list_test.cpp @@ -583,7 +583,7 @@ TEST_CASE( "list sort and reverse", "[list]" ) } SECTION( "greater than (predicate)" ) { - test_list.sort( std::greater() ); + test_list.sort( std::greater<>() ); bool passed = true; int previous = 65535; diff --git a/tests/magic_spell_test.cpp b/tests/magic_spell_test.cpp index b7af678a8a473..a00c622408c52 100644 --- a/tests/magic_spell_test.cpp +++ b/tests/magic_spell_test.cpp @@ -465,7 +465,7 @@ TEST_CASE( "spell effect - target_attack", "[magic][spell][effect][target_attack int after_hp = 0; // Avatar/spellcaster - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); dummy.setpos( dummy_loc ); REQUIRE( dummy.pos() == dummy_loc ); @@ -514,7 +514,7 @@ TEST_CASE( "spell effect - summon", "[magic][spell][effect][summon]" ) const tripoint dummy_loc = { 60, 60, 0 }; const tripoint mummy_loc = { 61, 60, 0 }; - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); dummy.setpos( dummy_loc ); REQUIRE( dummy.pos() == dummy_loc ); @@ -553,7 +553,7 @@ TEST_CASE( "spell effect - recover_energy", "[magic][spell][effect][recover_ener // For that, "target_attack" with a negative damage is used. // Yer a wizard, ya dummy - player &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); clear_map(); diff --git a/tests/map_extra_test.cpp b/tests/map_extra_test.cpp index 01f690463e9a8..283d94e9a8d25 100644 --- a/tests/map_extra_test.cpp +++ b/tests/map_extra_test.cpp @@ -11,9 +11,9 @@ TEST_CASE( "mx_minefield real spawn", "[map_extra][overmap]" ) // many overmaps when searching. const tripoint origin = tripoint( 90, 90, 0 ); - // Find all of the bridges within a 180 OMT radius of this location. + // Find all of the bridgeheads within a 180 OMT radius of this location. omt_find_params find_params; - find_params.types = {{"bridge", ot_match_type::type}}; + find_params.types = {{"bridgehead_ground", ot_match_type::type}}; find_params.search_range = 180; const std::vector bridges = overmap_buffer.find_all( origin, find_params ); @@ -46,15 +46,16 @@ TEST_CASE( "mx_minefield theoretical spawn", "[map_extra][overmap]" ) overmap &om = overmap_buffer.get( point_zero ); const oter_id road( "road_ns" ); + const oter_id bridgehead( "bridgehead_ground_north" ); const oter_id bridge( "bridge_north" ); // The mx_minefield map extra expects to have a particular configuration with - // three OMTs--a road, then a bridge, then a bridge once again. + // three OMTs--a bridgehead, then a road, then a road once again. // It does this for four rotations, with the road on the north, south, east, // and west of the target point. const auto setup_terrain_and_generate = [&]( const tripoint & center, om_direction::type bridge_direction ) { - om.ter_set( center, bridge ); + om.ter_set( center, bridgehead ); om.ter_set( center + om_direction::displace( bridge_direction, 1 ), bridge ); om.ter_set( center + om_direction::displace( om_direction::opposite( bridge_direction ), 1 ), road ); diff --git a/tests/map_helpers.cpp b/tests/map_helpers.cpp index 70c5741ab0952..2e5eae6a79cf6 100644 --- a/tests/map_helpers.cpp +++ b/tests/map_helpers.cpp @@ -6,7 +6,7 @@ #include #include -#include "avatar.h" +#include "character.h" #include "field.h" #include "game.h" #include "game_constants.h" @@ -22,25 +22,27 @@ class vehicle; // Remove all vehicles from the map void clear_vehicles() { - for( wrapped_vehicle &veh : g->m.get_vehicles() ) { - g->m.destroy_vehicle( veh.v ); + map &here = get_map(); + for( wrapped_vehicle &veh : here.get_vehicles() ) { + here.destroy_vehicle( veh.v ); } } void wipe_map_terrain() { - const int mapsize = g->m.getmapsize() * SEEX; + map &here = get_map(); + const int mapsize = here.getmapsize() * SEEX; for( int z = 0; z <= OVERMAP_HEIGHT; ++z ) { ter_id terrain = z == 0 ? t_grass : t_open_air; for( int x = 0; x < mapsize; ++x ) { for( int y = 0; y < mapsize; ++y ) { - g->m.set( { x, y, z}, terrain, f_null ); + here.set( { x, y, z}, terrain, f_null ); } } } clear_vehicles(); - g->m.invalidate_map_cache( 0 ); - g->m.build_map_cache( 0, true ); + here.invalidate_map_cache( 0 ); + here.build_map_cache( 0, true ); } void clear_creatures() @@ -61,16 +63,17 @@ void clear_npcs() void clear_fields( const int zlevel ) { - const int mapsize = g->m.getmapsize() * SEEX; + map &here = get_map(); + const int mapsize = here.getmapsize() * SEEX; for( int x = 0; x < mapsize; ++x ) { for( int y = 0; y < mapsize; ++y ) { const tripoint p( x, y, zlevel ); std::vector fields; - for( auto &pr : g->m.field_at( p ) ) { + for( auto &pr : here.field_at( p ) ) { fields.push_back( pr.second.get_field_type() ); } for( field_type_id f : fields ) { - g->m.remove_field( p, f ); + here.remove_field( p, f ); } } } @@ -78,10 +81,11 @@ void clear_fields( const int zlevel ) void clear_items( const int zlevel ) { - const int mapsize = g->m.getmapsize() * SEEX; + map &here = get_map(); + const int mapsize = here.getmapsize() * SEEX; for( int x = 0; x < mapsize; ++x ) { for( int y = 0; y < mapsize; ++y ) { - g->m.i_clear( { x, y, zlevel } ); + here.i_clear( { x, y, zlevel } ); } } } @@ -96,7 +100,7 @@ void clear_map() wipe_map_terrain(); clear_npcs(); clear_creatures(); - g->m.clear_traps(); + get_map().clear_traps(); for( int z = -2; z <= 0; ++z ) { clear_items( z ); } @@ -106,7 +110,7 @@ void clear_map_and_put_player_underground() { clear_map(); // Make sure the player doesn't block the path of the monster being tested. - g->u.setpos( { 0, 0, -2 } ); + get_player_character().setpos( { 0, 0, -2 } ); } monster &spawn_test_monster( const std::string &monster_type, const tripoint &start ) @@ -120,14 +124,15 @@ monster &spawn_test_monster( const std::string &monster_type, const tripoint &st // terrain, and no furniture, traps, or items. void build_test_map( const ter_id &terrain ) { - for( const tripoint &p : g->m.points_in_rectangle( tripoint_zero, + map &here = get_map(); + for( const tripoint &p : here.points_in_rectangle( tripoint_zero, tripoint( MAPSIZE * SEEX, MAPSIZE * SEEY, 0 ) ) ) { - g->m.furn_set( p, furn_id( "f_null" ) ); - g->m.ter_set( p, terrain ); - g->m.trap_set( p, trap_id( "tr_null" ) ); - g->m.i_clear( p ); + here.furn_set( p, furn_id( "f_null" ) ); + here.ter_set( p, terrain ); + here.trap_set( p, trap_id( "tr_null" ) ); + here.i_clear( p ); } - g->m.invalidate_map_cache( 0 ); - g->m.build_map_cache( 0, true ); + here.invalidate_map_cache( 0 ); + here.build_map_cache( 0, true ); } diff --git a/tests/map_iterator_test.cpp b/tests/map_iterator_test.cpp index 61772ac263bbf..f8654c9cadc46 100644 --- a/tests/map_iterator_test.cpp +++ b/tests/map_iterator_test.cpp @@ -2,6 +2,7 @@ #include #include "catch/catch.hpp" +#include "coordinates.h" #include "map_iterator.h" #include "point.h" @@ -14,7 +15,8 @@ std::array range_1_2d_centered = { TEST_CASE( "Radius one 2D square centered at origin." ) { - for( const tripoint &candidate : tripoint_range( tripoint_north_west, tripoint_south_east ) ) { + for( const tripoint &candidate : + tripoint_range( tripoint_north_west, tripoint_south_east ) ) { REQUIRE( std::find( range_1_2d_centered.begin(), range_1_2d_centered.end(), candidate ) != range_1_2d_centered.end() ); } @@ -29,12 +31,21 @@ std::array range_1_2d_offset = { TEST_CASE( "Radius one 2D square centered at -4/-4/0." ) { - for( const tripoint &candidate : tripoint_range( {-5, -5, 0}, {-3, -3, 0} ) ) { + for( const tripoint &candidate : tripoint_range( {-5, -5, 0}, {-3, -3, 0} ) ) { REQUIRE( std::find( range_1_2d_offset.begin(), range_1_2d_offset.end(), candidate ) != range_1_2d_offset.end() ); } } +TEST_CASE( "Radius one 2D square centered at -4/-4/0 in abs_omt coords." ) +{ + for( const tripoint_abs_omt &candidate : + tripoint_range( {-5, -5, 0}, {-3, -3, 0} ) ) { + REQUIRE( std::find( range_1_2d_offset.begin(), range_1_2d_offset.end(), candidate.raw() ) != + range_1_2d_offset.end() ); + } +} + std::array range_3_3d_offset = { { { 5, 5, -2}, { 6, 5, -2}, { 7, 5, -2}, { 8, 5, -2}, { 9, 5, -2}, {10, 5, -2}, {11, 5, -2}, { 5, 6, -2}, { 6, 6, -2}, { 7, 6, -2}, { 8, 6, -2}, { 9, 6, -2}, {10, 6, -2}, {11, 6, -2}, @@ -96,7 +107,7 @@ std::array range_3_3d_offset = { TEST_CASE( "Radius three 3D square centered at 8/8/1." ) { - for( const tripoint &candidate : tripoint_range( {5, 5, -2}, {11, 11, 4} ) ) { + for( const tripoint &candidate : tripoint_range( {5, 5, -2}, {11, 11, 4} ) ) { REQUIRE( std::find( range_3_3d_offset.begin(), range_3_3d_offset.end(), candidate ) != range_3_3d_offset.end() ); } diff --git a/tests/map_test.cpp b/tests/map_test.cpp index cb3a919d8975e..6bf8ca312b7e9 100644 --- a/tests/map_test.cpp +++ b/tests/map_test.cpp @@ -14,18 +14,19 @@ TEST_CASE( "destroy_grabbed_furniture" ) { clear_map(); + avatar &player_character = get_avatar(); GIVEN( "Furniture grabbed by the player" ) { const tripoint test_origin( 60, 60, 0 ); map &here = get_map(); - g->u.setpos( test_origin ); + player_character.setpos( test_origin ); const tripoint grab_point = test_origin + tripoint_east; here.furn_set( grab_point, furn_id( "f_chair" ) ); - g->u.grab( object_type::FURNITURE, grab_point ); + player_character.grab( object_type::FURNITURE, grab_point ); WHEN( "The furniture grabbed by the player is destroyed" ) { here.destroy( grab_point ); THEN( "The player's grab is released" ) { - CHECK( g->u.get_grab_type() == object_type::NONE ); - CHECK( g->u.grab_point == tripoint_zero ); + CHECK( player_character.get_grab_type() == object_type::NONE ); + CHECK( player_character.grab_point == tripoint_zero ); } } } diff --git a/tests/melee_dodge_hit_test.cpp b/tests/melee_dodge_hit_test.cpp index 0146ca8a643aa..4f16a8ae3ad60 100644 --- a/tests/melee_dodge_hit_test.cpp +++ b/tests/melee_dodge_hit_test.cpp @@ -68,7 +68,7 @@ TEST_CASE( "Character::get_hit_base", "[character][melee][hit][dex]" ) { clear_map(); - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); SECTION( "character get_hit_base increases by 1/4 for each point of DEX" ) { @@ -96,7 +96,7 @@ TEST_CASE( "Character::get_dodge_base", "[character][melee][dodge][dex][skill]" { clear_map(); - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); // Character::get_dodge_base is simply DEXTERITY / 2 + DODGE_SKILL @@ -188,7 +188,7 @@ TEST_CASE( "player::get_dodge", "[player][melee][dodge]" ) { clear_map(); - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); const float base_dodge = dummy.get_dodge_base(); @@ -222,7 +222,7 @@ TEST_CASE( "player::get_dodge with effects", "[player][melee][dodge][effect]" ) { clear_map(); - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); // Compare all effects against base dodge ability @@ -281,7 +281,7 @@ TEST_CASE( "player::get_dodge while grabbed", "[player][melee][dodge][grab]" ) { clear_map(); - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); // Base dodge rate when not grabbed @@ -354,7 +354,7 @@ TEST_CASE( "player::get_dodge while grabbed", "[player][melee][dodge][grab]" ) TEST_CASE( "player::get_dodge stamina effects", "[player][melee][dodge][stamina]" ) { - avatar &dummy = g->u; + avatar &dummy = get_avatar(); clear_character( dummy ); SECTION( "8/8/8/8, no skills, unencumbered" ) { diff --git a/tests/memorial_test.cpp b/tests/memorial_test.cpp index 105451d3eb82d..17d291fb4f330 100644 --- a/tests/memorial_test.cpp +++ b/tests/memorial_test.cpp @@ -50,7 +50,7 @@ void check_memorial( memorial_logger &m, event_bus &b, const std::string &ref, A } } -TEST_CASE( "memorials" ) +TEST_CASE( "memorials", "[memorial]" ) { memorial_logger &m = g->memorial(); m.clear(); @@ -58,9 +58,10 @@ TEST_CASE( "memorials" ) event_bus &b = g->events(); - g->u.male = false; - character_id ch = g->u.getID(); - std::string u_name = g->u.name; + avatar &player_character = get_avatar(); + player_character.male = false; + character_id ch = player_character.getID(); + std::string u_name = player_character.name; character_id ch2 = character_id( ch.get_value() + 1 ); mutagen_technique mutagen = mutagen_technique::injected_purifier; mtype_id mon( "mon_zombie_kevlar_2" ); @@ -88,6 +89,10 @@ TEST_CASE( "memorials" ) check_memorial( m, b, "Became wanted by the police!", ch ); + // To insure we don't trigger losing the Structural Integrity conduct during the test, + // Break the subject's leg first. + b.send( ch, bp_leg_l ); + check_memorial( m, b, "Broke her right arm.", ch, bp_arm_r ); @@ -143,6 +148,15 @@ TEST_CASE( "memorials" ) check_memorial( m, b, "Died of a drug overdose.", ch, eff ); + check_memorial( + m, b, "Bled to death.", ch ); + + check_memorial( + m, b, "Died of hypovolemic shock.", ch ); + + check_memorial( + m, b, "Died from loss of red blood cells.", ch ); + check_memorial( m, b, "Succumbed to the infection.", ch ); @@ -193,8 +207,8 @@ TEST_CASE( "memorials" ) std::chrono::seconds( 100 ) ); check_memorial( - m, b, u_name + " began their journey into the Cataclysm.", ch, u_name, g->u.male, - g->u.prof->ident(), g->u.custom_profession, "VERSION_STRING" ); + m, b, u_name + " began their journey into the Cataclysm.", ch, u_name, player_character.male, + player_character.prof->ident(), player_character.custom_profession, "VERSION_STRING" ); // Invokes achievement, so send another to clear the log for the test b.send( ch, cbm ); @@ -270,3 +284,49 @@ TEST_CASE( "memorials" ) check_memorial( m, b, "Used the debug menu (WISH).", debug_menu::debug_menu_index::WISH ); } + +TEST_CASE( "convert_legacy_memorial_log", "[memorial]" ) +{ + // Verify that the old format can be transformed into the new format + const std::string input = + "| Year 1, Spring, day 0 0800.00 | prison | Hubert 'Daffy' Mullin began their journey into the Cataclysm.\n" + "| Year 1, Spring, day 0 0800.05 | prison | Gained the mutation 'Debug Invincibility'.\n"; + const std::string json_value = + R"([{"preformatted":"| Year 1, Spring, day 0 0800.00 | prison | Hubert 'Daffy' Mullin began their journey into the Cataclysm."},{"preformatted":"| Year 1, Spring, day 0 0800.05 | prison | Gained the mutation 'Debug Invincibility'."}])"; + + memorial_logger logger; + { + std::istringstream is( input ); + logger.load( is ); + std::ostringstream os; + logger.save( os ); + CHECK( os.str() == json_value ); + } + + // Then verify that the new format is unchanged + { + std::istringstream is( json_value ); + logger.load( is ); + std::ostringstream os; + logger.save( os ); + CHECK( os.str() == json_value ); + } + + // Finally, verify that dump matches legacy input + CHECK( logger.dump() == input ); +} + +TEST_CASE( "memorial_log_dumping", "[memorial]" ) +{ + // An example log file with one legacy and one "modern" entry + const std::string json_value = + R"([{"preformatted":"| Year 1, Spring, day 0 0800.00 | refugee center | Apolonia Trout began their journey into the Cataclysm."},{"time":15614,"oter_id":"cabin_isherwood","oter_name":"forest","message":"Used the debug menu (ENABLE_ACHIEVEMENTS)."}])"; + const std::string expected_output = + "| Year 1, Spring, day 0 0800.00 | refugee center | Apolonia Trout began their journey into the Cataclysm.\n" + "| Year 1, Spring, day 1 4:20:14 AM | forest | Used the debug menu (ENABLE_ACHIEVEMENTS).\n"; + + memorial_logger logger; + std::istringstream is( json_value ); + logger.load( is ); + CHECK( logger.dump() == expected_output ); +} diff --git a/tests/modify_morale_test.cpp b/tests/modify_morale_test.cpp index b05bf6b887fdc..ccf8c29a35b2f 100644 --- a/tests/modify_morale_test.cpp +++ b/tests/modify_morale_test.cpp @@ -80,6 +80,7 @@ TEST_CASE( "dining with table and chair", "[food][modify_morale][table][chair]" clear_map(); map &here = get_map(); avatar dummy; + dummy.set_body(); const tripoint avatar_pos( 60, 60, 0 ); dummy.setpos( avatar_pos ); dummy.worn.push_back( item( "backpack" ) ); @@ -269,6 +270,7 @@ TEST_CASE( "drugs", "[food][modify_morale][drug]" ) TEST_CASE( "cannibalism", "[food][modify_morale][cannibal]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); item &human = dummy.i_add( item( "bone_human" ) ); @@ -344,6 +346,7 @@ TEST_CASE( "cannibalism", "[food][modify_morale][cannibal]" ) TEST_CASE( "sweet junk food", "[food][modify_morale][junk][sweet]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); GIVEN( "some sweet junk food" ) { @@ -397,6 +400,7 @@ TEST_CASE( "sweet junk food", "[food][modify_morale][junk][sweet]" ) TEST_CASE( "junk food that is not ingested", "[modify_morale][junk][no_ingest]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); item &caff_gum = dummy.i_add( item( "caff_gum" ) ); @@ -462,6 +466,7 @@ TEST_CASE( "junk food that is not ingested", "[modify_morale][junk][no_ingest]" TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); int penalty = -75; @@ -548,6 +553,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) TEST_CASE( "saprophage character", "[food][modify_morale][saprophage]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); GIVEN( "character is a saprophage, preferring rotted food" ) { @@ -584,6 +590,7 @@ TEST_CASE( "saprophage character", "[food][modify_morale][saprophage]" ) TEST_CASE( "ursine honey", "[food][modify_morale][ursine][honey]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); item &honeycomb = dummy.i_add( item( "honeycomb" ) ); diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index dddceab3914d1..1343278ff84b7 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -8,20 +8,19 @@ #include #include -#include "avatar.h" #include "catch/catch.hpp" +#include "character.h" #include "game.h" +#include "game_constants.h" +#include "item.h" +#include "line.h" #include "map.h" #include "map_helpers.h" #include "monster.h" #include "options_helpers.h" #include "options.h" -#include "player.h" -#include "test_statistics.h" -#include "game_constants.h" -#include "item.h" -#include "line.h" #include "point.h" +#include "test_statistics.h" using move_statistics = statistics; @@ -86,10 +85,11 @@ static int can_catch_player( const std::string &monster_type, const tripoint &di { clear_map(); REQUIRE( g->num_creatures() == 1 ); // the player - player &test_player = get_avatar(); + Character &test_player = get_player_character(); // Strip off any potentially encumbering clothing. - std::list temp; - while( test_player.takeoff( test_player.i_at( -2 ), &temp ) ) {} + test_player.remove_worn_items_with( []( item & ) { + return true; + } ); const tripoint center{ 65, 65, 0 }; test_player.setpos( center ); diff --git a/tests/monster_vision_test.cpp b/tests/monster_vision_test.cpp index cef8bd52fa32d..b35d863942ea2 100644 --- a/tests/monster_vision_test.cpp +++ b/tests/monster_vision_test.cpp @@ -23,8 +23,7 @@ static const time_point midday = calendar::turn_zero + 12_hours; TEST_CASE( "monsters shouldn't see through floors", "[vision]" ) { - override_option opt( "ZLEVELS", "true" ); - override_option opt2( "FOV_3D", "true" ); + override_option opt( "FOV_3D", "true" ); bool old_fov_3d = fov_3d; fov_3d = true; calendar::turn = midday; diff --git a/tests/mutation_test.cpp b/tests/mutation_test.cpp index 654dae132bfd1..5cd4cec7efebe 100644 --- a/tests/mutation_test.cpp +++ b/tests/mutation_test.cpp @@ -18,6 +18,7 @@ std::string get_mutations_as_string( const player &p ); static void give_all_mutations( player &p, const mutation_category_trait &category, const bool include_postthresh ) { + p.set_body(); const std::vector category_mutations = mutations_category[category.id]; // Add the threshold mutation first diff --git a/tests/new_character_test.cpp b/tests/new_character_test.cpp index 9184eb3a9afe3..9223612a2d63a 100644 --- a/tests/new_character_test.cpp +++ b/tests/new_character_test.cpp @@ -147,7 +147,7 @@ TEST_CASE( "starting_items", "[slow]" ) g->u.worn.clear(); g->u.remove_weapon(); g->u.inv.clear(); - g->u.reset_encumbrance(); + g->u.calc_encumbrance(); g->u.male = i == 0; g->u.add_profession_items(); diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index f05b2e4f1f9e9..3318b0bdf545b 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -29,6 +29,7 @@ #include "point.h" #include "string_id.h" #include "stringmaker.h" +#include "talker.h" #include "type_id.h" static const efftype_id effect_gave_quest_item( "gave_quest_item" ); @@ -42,7 +43,7 @@ static const trait_id trait_PROF_SWAT( "PROF_SWAT" ); static npc &create_test_talker() { const string_id test_talker( "test_talker" ); - const character_id model_id = get_map().place_npc( point( 25, 25 ), test_talker, true ); + const character_id model_id = get_map().place_npc( point( 25, 25 ), test_talker ); g->load_npcs(); npc *model_npc = g->find_npc( model_id ); @@ -51,6 +52,7 @@ static npc &create_test_talker() for( const trait_id &tr : model_npc->get_mutations() ) { model_npc->unset_mutation( tr ); } + model_npc->name = "Beta NPC"; model_npc->set_hunger( 0 ); model_npc->set_thirst( 0 ); model_npc->set_fatigue( 0 ); @@ -85,7 +87,7 @@ static std::string gen_dynamic_line( dialogue &d ) static void change_om_type( const std::string &new_type ) { - const tripoint omt_pos = ms_to_omt_copy( get_map().getabs( get_avatar().pos() ) ); + const tripoint omt_pos = ms_to_omt_copy( get_map().getabs( get_player_character().pos() ) ); overmap_buffer.ter_set( omt_pos, oter_id( new_type ) ); } @@ -94,6 +96,7 @@ static npc &prep_test( dialogue &d ) clear_avatar(); clear_vehicles(); avatar &player_character = get_avatar(); + player_character.name = "Alpha Avatar"; REQUIRE_FALSE( player_character.in_vehicle ); const tripoint test_origin( 15, 15, 0 ); @@ -101,12 +104,12 @@ static npc &prep_test( dialogue &d ) g->faction_manager_ptr->create_if_needed(); - npc &talker_npc = create_test_talker(); + npc &beta = create_test_talker(); - d.alpha = &player_character; - d.beta = &talker_npc; + d.alpha = get_talker_for( player_character ); + d.beta = get_talker_for( beta ); - return talker_npc; + return beta; } TEST_CASE( "npc_talk_start", "[npc_talk]" ) @@ -134,7 +137,7 @@ TEST_CASE( "npc_talk_stats", "[npc_talk]" ) dialogue d; prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); player_character.str_cur = 8; player_character.dex_cur = 8; player_character.int_cur = 8; @@ -170,7 +173,7 @@ TEST_CASE( "npc_talk_skills", "[npc_talk]" ) const skill_id skill( "driving" ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); player_character.set_skill_level( skill, 8 ); d.add_topic( "TALK_TEST_SIMPLE_SKILLS" ); @@ -193,7 +196,7 @@ TEST_CASE( "npc_talk_wearing_and_trait", "[npc_talk]" ) dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); for( const trait_id &tr : player_character.get_mutations() ) { player_character.unset_mutation( tr ); } @@ -238,7 +241,7 @@ TEST_CASE( "npc_talk_effect", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); d.add_topic( "TALK_TEST_EFFECT" ); gen_response_lines( d, 1 ); @@ -259,7 +262,7 @@ TEST_CASE( "npc_talk_service", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); d.add_topic( "TALK_TEST_SERVICE" ); player_character.cash = 0; @@ -466,7 +469,7 @@ TEST_CASE( "npc_talk_switch", "[npc_talk]" ) { dialogue d; prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); d.add_topic( "TALK_TEST_SWITCH" ); player_character.cash = 1000; @@ -496,7 +499,7 @@ TEST_CASE( "npc_talk_or", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); d.add_topic( "TALK_TEST_OR" ); player_character.cash = 0; @@ -513,7 +516,7 @@ TEST_CASE( "npc_talk_and", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); player_character.toggle_trait( trait_id( "ELFA_EARS" ) ); d.add_topic( "TALK_TEST_AND" ); @@ -530,7 +533,7 @@ TEST_CASE( "npc_talk_nested", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); d.add_topic( "TALK_TEST_NESTED" ); talker_npc.add_effect( effect_currently_busy, 9999_turns ); @@ -547,7 +550,7 @@ TEST_CASE( "npc_talk_nested", "[npc_talk]" ) TEST_CASE( "npc_talk_conditionals", "[npc_talk]" ) { dialogue d; - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); prep_test( d ); player_character.cash = 800; @@ -577,7 +580,7 @@ TEST_CASE( "npc_talk_items", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); player_character.remove_items_with( []( const item & it ) { return it.get_category().get_id() == item_category_id( "books" ) || @@ -856,19 +859,44 @@ TEST_CASE( "npc_talk_adjust_vars", "[npc_talk]" ) CHECK( d.responses[10].text == "This is a npc_compare_var test response for < 0." ); } +TEST_CASE( "npc_talk_vars_time", "[npc_talk]" ) +{ + dialogue d; + prep_test( d ); + + time_point start_turn = calendar::turn; + calendar::turn = calendar::turn + time_duration( 1_hours ); + d.add_topic( "TALK_TEST_VARS_TIME" ); + gen_response_lines( d, 3 ); + CHECK( d.responses[0].text == "This is a basic test response." ); + CHECK( d.responses[1].text == "This is a u_add_var time test response." ); + CHECK( d.responses[2].text == "This is a npc_add_var time test response." ); + talk_effect_t &effects = d.responses[1].success; + effects.apply( d ); + gen_response_lines( d, 1 ); + CHECK( d.responses[0].text == "This is a basic test response." ); + time_point then = calendar::turn; + calendar::turn = calendar::turn + time_duration( 4_days ); + REQUIRE( then < calendar::turn ); + gen_response_lines( d, 2 ); + CHECK( d.responses[0].text == "This is a basic test response." ); + CHECK( d.responses[1].text == "This is a u_compare_var time test response for > 3_days." ); + calendar::turn = start_turn; +} + TEST_CASE( "npc_talk_bionics", "[npc_talk]" ) { dialogue d; - npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + npc &beta = prep_test( d ); + player &player_character = get_avatar(); player_character.clear_bionics(); - talker_npc.clear_bionics(); + beta.clear_bionics(); d.add_topic( "TALK_TEST_BIONICS" ); gen_response_lines( d, 1 ); CHECK( d.responses[0].text == "This is a basic test response." ); player_character.add_bionic( bionic_id( "bio_ads" ) ); - talker_npc.add_bionic( bionic_id( "bio_power_storage" ) ); + beta.add_bionic( bionic_id( "bio_power_storage" ) ); gen_response_lines( d, 3 ); CHECK( d.responses[0].text == "This is a basic test response." ); CHECK( d.responses[1].text == "This is a u_has_bionics bio_ads test response." ); @@ -879,7 +907,7 @@ TEST_CASE( "npc_talk_effects", "[npc_talk]" ) { dialogue d; npc &talker_npc = prep_test( d ); - avatar &player_character = get_avatar(); + player &player_character = get_avatar(); // speaker effects just use are owed because I don't want to do anything complicated player_character.cash = 1000; diff --git a/tests/npc_test.cpp b/tests/npc_test.cpp index 8f2253af2dfb2..900b448326870 100644 --- a/tests/npc_test.cpp +++ b/tests/npc_test.cpp @@ -5,7 +5,6 @@ #include #include -#include "avatar.h" #include "calendar.h" #include "catch/catch.hpp" #include "common_types.h" @@ -313,40 +312,42 @@ TEST_CASE( "npc-movement" ) clear_map(); + Character &player_character = get_player_character(); + map &here = get_map(); for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { const char type = setup[y][x]; - const tripoint p = g->u.pos() + point( x, y ); + const tripoint p = player_character.pos() + point( x, y ); // create walls if( type == '#' ) { - g->m.ter_set( p, t_reinforced_glass ); + here.ter_set( p, t_reinforced_glass ); } else { - g->m.ter_set( p, t_floor ); + here.ter_set( p, t_floor ); } // spawn acid // a copy is needed because we will remove elements from it - const field fs = g->m.field_at( p ); + const field fs = here.field_at( p ); for( const auto &f : fs ) { - g->m.remove_field( p, f.first ); + here.remove_field( p, f.first ); } if( type == 'A' || type == 'R' || type == 'W' || type == 'M' || type == 'B' || type == 'C' ) { - g->m.add_field( p, fd_acid, 3 ); + here.add_field( p, fd_acid, 3 ); } // spawn rubbles if( type == 'R' ) { - g->m.furn_set( p, f_rubble ); + here.furn_set( p, f_rubble ); } else { - g->m.furn_set( p, f_null ); + here.furn_set( p, f_null ); } // create vehicles if( type == 'V' || type == 'W' || type == 'M' ) { - vehicle *veh = g->m.add_vehicle( vproto_id( "none" ), p, 270, 0, 0 ); + vehicle *veh = here.add_vehicle( vproto_id( "none" ), p, 270, 0, 0 ); REQUIRE( veh != nullptr ); veh->install_part( point_zero, vpart_frame_vertical ); veh->install_part( point_zero, vpart_seat ); - g->m.add_vehicle_to_cache( veh ); + here.add_vehicle_to_cache( veh ); } // spawn npcs if( type == 'A' || type == 'R' || type == 'W' || type == 'M' @@ -374,28 +375,28 @@ TEST_CASE( "npc-movement" ) for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { const char type = setup[y][x]; - const tripoint p = g->u.pos() + point( x, y ); + const tripoint p = player_character.pos() + point( x, y ); if( type == '#' ) { - REQUIRE( !g->m.passable( p ) ); + REQUIRE( !here.passable( p ) ); } else { - REQUIRE( g->m.passable( p ) ); + REQUIRE( here.passable( p ) ); } if( type == 'R' ) { - REQUIRE( g->m.has_flag( "UNSTABLE", p ) ); + REQUIRE( here.has_flag( "UNSTABLE", p ) ); } else { - REQUIRE( !g->m.has_flag( "UNSTABLE", p ) ); + REQUIRE( !here.has_flag( "UNSTABLE", p ) ); } if( type == 'V' || type == 'W' || type == 'M' ) { - REQUIRE( g->m.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ).has_value() ); + REQUIRE( here.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ).has_value() ); } else { - REQUIRE( !g->m.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ).has_value() ); + REQUIRE( !here.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ).has_value() ); } npc *guy = g->critter_at( p ); if( type == 'A' || type == 'R' || type == 'W' || type == 'M' || type == 'B' || type == 'C' ) { REQUIRE( guy != nullptr ); - REQUIRE( guy->is_dangerous_fields( g->m.field_at( p ) ) ); + REQUIRE( guy->is_dangerous_fields( here.field_at( p ) ) ); } else { REQUIRE( guy == nullptr ); } @@ -403,16 +404,16 @@ TEST_CASE( "npc-movement" ) } SECTION( "NPCs escape dangerous terrain by pushing other NPCs" ) { - check_npc_movement( g->u.pos() ); + check_npc_movement( player_character.pos() ); } SECTION( "Player in vehicle & NPCs escaping dangerous terrain" ) { - const tripoint origin = g->u.pos(); + const tripoint origin = player_character.pos(); for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { if( setup[y][x] == 'V' ) { - g->place_player( g->u.pos() + point( x, y ) ); + g->place_player( player_character.pos() + point( x, y ) ); break; } } @@ -434,8 +435,9 @@ TEST_CASE( "npc_can_target_player" ) clear_npcs(); clear_creatures(); - npc &hostile = spawn_npc( g->u.pos().xy() + point_south, "thug" ); - REQUIRE( rl_dist( g->u.pos(), hostile.pos() ) <= 1 ); + Character &player_character = get_player_character(); + npc &hostile = spawn_npc( player_character.pos().xy() + point_south, "thug" ); + REQUIRE( rl_dist( player_character.pos(), hostile.pos() ) <= 1 ); hostile.set_attitude( NPCATT_KILL ); hostile.name = "Enemy NPC"; @@ -443,5 +445,5 @@ TEST_CASE( "npc_can_target_player" ) hostile.regen_ai_cache(); REQUIRE( hostile.current_target() != nullptr ); - CHECK( hostile.current_target() == static_cast( &g->u ) ); + CHECK( hostile.current_target() == static_cast( &player_character ) ); } diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index df42e38bedb94..7619904eb3585 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -26,7 +26,7 @@ int get_remaining_charges( const std::string &tool_id ) { - const inventory crafting_inv = g->u.crafting_inventory(); + const inventory crafting_inv = get_player_character().crafting_inventory(); std::vector items = crafting_inv.items_with( [tool_id]( const item & i ) { return i.typeId() == itype_id( tool_id ); @@ -40,7 +40,7 @@ int get_remaining_charges( const std::string &tool_id ) bool player_has_item_of_type( const std::string &type ) { - std::vector matching_items = g->u.inv.items_with( + std::vector matching_items = get_player_character().inv.items_with( [&]( const item & i ) { return i.type->get_id() == itype_id( type ); } ); @@ -55,7 +55,7 @@ void clear_character( player &dummy, bool debug_storage ) // delete all worn items. dummy.worn.clear(); - dummy.reset_encumbrance(); + dummy.calc_encumbrance(); dummy.inv.clear(); dummy.remove_weapon(); dummy.clear_mutations(); @@ -113,7 +113,7 @@ void clear_character( player &dummy, bool debug_storage ) void clear_avatar() { - clear_character( g->u ); + clear_character( get_avatar() ); } void process_activity( player &dummy ) @@ -129,7 +129,7 @@ void process_activity( player &dummy ) npc &spawn_npc( const point &p, const std::string &npc_class ) { const string_id test_guy( npc_class ); - const character_id model_id = g->m.place_npc( p, test_guy, true ); + const character_id model_id = get_map().place_npc( p, test_guy ); g->load_npcs(); npc *guy = g->find_npc( model_id ); diff --git a/tests/player_test.cpp b/tests/player_test.cpp index d3ffb68878053..15e64c69d73a2 100644 --- a/tests/player_test.cpp +++ b/tests/player_test.cpp @@ -3,9 +3,8 @@ #include #include -#include "avatar.h" #include "catch/catch.hpp" -#include "player.h" +#include "character.h" #include "weather.h" #include "bodypart.h" #include "calendar.h" @@ -13,7 +12,7 @@ // Set the stage for a particular ambient and target temperature and run update_bodytemp() until // core body temperature settles. -static void temperature_check( player *p, const int ambient_temp, const int target_temp ) +static void temperature_check( Character *p, const int ambient_temp, const int target_temp ) { get_weather().temperature = ambient_temp; for( int i = 0 ; i < num_bp; i++ ) { @@ -40,7 +39,7 @@ static void temperature_check( player *p, const int ambient_temp, const int targ CHECK( high > p->temp_cur[0] ); } -static void equip_clothing( player *p, const std::string &clothing ) +static void equip_clothing( Character *p, const std::string &clothing ) { const item article( clothing, 0 ); p->wear_item( article ); @@ -48,7 +47,7 @@ static void equip_clothing( player *p, const std::string &clothing ) // Run the tests for each of the temperature setpoints. // ambient_temps MUST have 7 values or we'll segfault. -static void test_temperature_spread( player *p, const std::array &ambient_temps ) +static void test_temperature_spread( Character *p, const std::array &ambient_temps ) { temperature_check( p, ambient_temps[0], BODYTEMP_FREEZING ); temperature_check( p, ambient_temps[1], BODYTEMP_VERY_COLD ); @@ -59,14 +58,15 @@ static void test_temperature_spread( player *p, const std::array &ambien temperature_check( p, ambient_temps[6], BODYTEMP_SCORCHING ); } -TEST_CASE( "Player body temperatures converge on expected values.", "[.bodytemp]" ) +TEST_CASE( "player body temperatures converge on expected values.", "[.bodytemp]" ) { - player &dummy = get_avatar(); + Character &dummy = get_player_character(); - // Remove first worn item until there are none left. - std::list temp; - while( dummy.takeoff( dummy.i_at( -2 ), &temp ) ) {} + // Strip off any potentially encumbering clothing. + dummy.remove_worn_items_with( []( item & ) { + return true; + } ); // See http://personal.cityu.edu.hk/~bsapplec/heat.htm for temperature basis. // As we aren't modeling metabolic rate, assume 2 METS when not sleeping. diff --git a/tests/point_test.cpp b/tests/point_test.cpp index 596d9c6d103bd..64449971fa390 100644 --- a/tests/point_test.cpp +++ b/tests/point_test.cpp @@ -2,6 +2,7 @@ #include #include "catch/catch.hpp" +#include "coordinates.h" #include "point.h" TEST_CASE( "rectangle_containment", "[point]" ) @@ -65,27 +66,27 @@ TEST_CASE( "tripoint_xy", "[point]" ) CHECK( p.xy() == point( 1, 2 ) ); } -TEST_CASE( "closest_tripoints_first", "[point]" ) +TEST_CASE( "closest_points_first_tripoint", "[point]" ) { const tripoint center = { 1, -1, 2 }; GIVEN( "min_dist > max_dist" ) { - const std::vector result = closest_tripoints_first( center, 1, 0 ); + const std::vector result = closest_points_first( center, 1, 0 ); CHECK( result.empty() ); } GIVEN( "min_dist = max_dist = 0" ) { - const std::vector result = closest_tripoints_first( center, 0, 0 ); + const std::vector result = closest_points_first( center, 0, 0 ); - CHECK( result.size() == 1 ); + REQUIRE( result.size() == 1 ); CHECK( result[0] == tripoint{ 1, -1, 2 } ); } GIVEN( "min_dist = 0, max_dist = 1" ) { - const std::vector result = closest_tripoints_first( center, 0, 1 ); + const std::vector result = closest_points_first( center, 0, 1 ); - CHECK( result.size() == 9 ); + REQUIRE( result.size() == 9 ); CHECK( result[0] == tripoint{ 1, -1, 2 } ); CHECK( result[1] == tripoint{ 2, -1, 2 } ); CHECK( result[2] == tripoint{ 2, 0, 2 } ); @@ -98,9 +99,9 @@ TEST_CASE( "closest_tripoints_first", "[point]" ) } GIVEN( "min_dist = 2, max_dist = 2" ) { - const std::vector result = closest_tripoints_first( center, 2, 2 ); + const std::vector result = closest_points_first( center, 2, 2 ); - CHECK( result.size() == 16 ); + REQUIRE( result.size() == 16 ); CHECK( result[0] == tripoint{ 3, -2, 2 } ); CHECK( result[1] == tripoint{ 3, -1, 2 } ); @@ -120,3 +121,36 @@ TEST_CASE( "closest_tripoints_first", "[point]" ) CHECK( result[15] == tripoint{ 3, -3, 2 } ); } } + +TEST_CASE( "closest_points_first_point_abs_omt", "[point]" ) +{ + const point_abs_omt center( 1, 3 ); + + GIVEN( "min_dist > max_dist" ) { + const std::vector result = closest_points_first( center, 1, 0 ); + + CHECK( result.empty() ); + } + + GIVEN( "min_dist = max_dist = 0" ) { + const std::vector result = closest_points_first( center, 0, 0 ); + + REQUIRE( result.size() == 1 ); + CHECK( result[0].raw() == point{ 1, 3 } ); + } + + GIVEN( "min_dist = 0, max_dist = 1" ) { + const std::vector result = closest_points_first( center, 0, 1 ); + + REQUIRE( result.size() == 9 ); + CHECK( result[0].raw() == point{ 1, 3 } ); + CHECK( result[1].raw() == point{ 2, 3 } ); + CHECK( result[2].raw() == point{ 2, 4 } ); + CHECK( result[3].raw() == point{ 1, 4 } ); + CHECK( result[4].raw() == point{ 0, 4 } ); + CHECK( result[5].raw() == point{ 0, 3 } ); + CHECK( result[6].raw() == point{ 0, 2 } ); + CHECK( result[7].raw() == point{ 1, 2 } ); + CHECK( result[8].raw() == point{ 2, 2 } ); + } +} diff --git a/tests/projectile_test.cpp b/tests/projectile_test.cpp index c1bfb3aff4303..2c4f4dc318ade 100644 --- a/tests/projectile_test.cpp +++ b/tests/projectile_test.cpp @@ -1,7 +1,7 @@ #include "catch/catch.hpp" -#include "avatar.h" #include "ballistics.h" +#include "character.h" #include "dispersion.h" #include "game.h" #include "itype.h" @@ -21,7 +21,8 @@ static tripoint projectile_end_point( const std::vector &range, const dealt_projectile_attack attack; - attack = projectile_attack( test_proj, range[0], range[2], dispersion_sources(), &get_avatar(), + attack = projectile_attack( test_proj, range[0], range[2], dispersion_sources(), + &get_player_character(), nullptr ); return attack.end_point; @@ -33,7 +34,7 @@ TEST_CASE( "projectiles_through_obstacles", "[projectile]" ) map &here = get_map(); // Move the player out of the way of the test area - get_avatar().setpos( { 2, 2, 0 } ); + get_player_character().setpos( { 2, 2, 0 } ); // Ensure that a projectile fired from a gun can pass through a chain link fence // First, set up a test area - three tiles in a row diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index fae734b679735..7c3e00c9dd189 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -258,7 +258,7 @@ static void assert_encumbrance( npc &shooter, int encumbrance ) { for( const bodypart_id &bp : shooter.get_all_body_parts() ) { INFO( "Body Part: " << body_part_name( bp ) ); - REQUIRE( shooter.encumb( bp->token ) == encumbrance ); + REQUIRE( shooter.encumb( bp ) == encumbrance ); } } @@ -268,6 +268,7 @@ TEST_CASE( "unskilled_shooter_accuracy", "[ranged] [balance] [slow]" ) { clear_map(); standard_npc shooter( "Shooter", shooter_pos, {}, 0, 8, 8, 8, 7 ); + shooter.set_body(); shooter.worn.push_back( item( "backpack" ) ); equip_shooter( shooter, { "bastsandals", "armguard_chitin", "armor_chitin", "beekeeping_gloves", "fencing_mask" } ); assert_encumbrance( shooter, 10 ); @@ -308,6 +309,7 @@ TEST_CASE( "competent_shooter_accuracy", "[ranged] [balance]" ) { clear_map(); standard_npc shooter( "Shooter", shooter_pos, {}, 5, 10, 10, 10, 10 ); + shooter.set_body(); equip_shooter( shooter, { "cloak_wool", "footrags_wool", "gloves_wraps_fur", "glasses_safety", "balclava" } ); assert_encumbrance( shooter, 5 ); @@ -347,6 +349,7 @@ TEST_CASE( "expert_shooter_accuracy", "[ranged] [balance]" ) { clear_map(); standard_npc shooter( "Shooter", shooter_pos, {}, 10, 20, 20, 20, 20 ); + shooter.set_body(); equip_shooter( shooter, { } ); assert_encumbrance( shooter, 0 ); diff --git a/tests/reading_test.cpp b/tests/reading_test.cpp index e13bb96ad78f3..a1ba79073aef1 100644 --- a/tests/reading_test.cpp +++ b/tests/reading_test.cpp @@ -48,6 +48,7 @@ TEST_CASE( "identifying unread books", "[reading][book][identify]" ) TEST_CASE( "reading a book for fun", "[reading][book][fun]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); GIVEN( "a fun book" ) { @@ -250,6 +251,7 @@ TEST_CASE( "estimated reading time for a book", "[reading][book][time]" ) TEST_CASE( "reasons for not being able to read", "[reading][reasons]" ) { avatar dummy; + dummy.set_body(); dummy.worn.push_back( item( "backpack" ) ); std::vector reasons; std::vector expect_reasons; diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index 2121acd958e12..94051b246b116 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -20,7 +20,7 @@ TEST_CASE( "reload_gun_with_integral_magazine", "[reload],[gun]" ) { - player &dummy = g->u; + player &dummy = get_avatar(); clear_avatar(); // Make sure the player doesn't drop anything :P @@ -41,7 +41,7 @@ TEST_CASE( "reload_gun_with_integral_magazine", "[reload],[gun]" ) TEST_CASE( "reload_gun_with_integral_magazine_using_speedloader", "[reload],[gun]" ) { - player &dummy = g->u; + player &dummy = get_avatar(); clear_avatar(); // Make sure the player doesn't drop anything :P @@ -74,7 +74,7 @@ TEST_CASE( "reload_gun_with_integral_magazine_using_speedloader", "[reload],[gun TEST_CASE( "reload_gun_with_swappable_magazine", "[reload],[gun]" ) { - player &dummy = g->u; + player &dummy = get_avatar(); clear_avatar(); // Make sure the player doesn't drop anything :P @@ -103,7 +103,7 @@ TEST_CASE( "reload_gun_with_swappable_magazine", "[reload],[gun]" ) REQUIRE( glock.magazine_current() != nullptr ); // We're expecting the magazine to end up in the inventory. item_location glock_loc( dummy, &glock ); - REQUIRE( g->unload( glock_loc ) ); + REQUIRE( dummy.unload( glock_loc ) ); const std::vector glock_mags = dummy.items_with( []( const item & it ) { return it.typeId() == itype_id( "glockmag" ); } ); @@ -150,7 +150,7 @@ static void reload_a_revolver( player &dummy, item &gun, item &ammo ) TEST_CASE( "automatic_reloading_action", "[reload],[gun]" ) { - player &dummy = g->u; + player &dummy = get_avatar(); clear_avatar(); // Make sure the player doesn't drop anything :P diff --git a/tests/simple_pathfinding_test.cpp b/tests/simple_pathfinding_test.cpp new file mode 100644 index 0000000000000..bf028575985dc --- /dev/null +++ b/tests/simple_pathfinding_test.cpp @@ -0,0 +1,31 @@ +#include "catch/catch.hpp" +#include "simple_pathfinding.h" + +#include "coordinates.h" + +template +static void test_path() +{ + Point start; + Point finish( point( 3, 0 ) ); + Point max( point( 10, 10 ) ); + + const auto estimate = + [&]( const pf::node &, const pf::node * ) { + return 1; + }; + + pf::path pth = pf::find_path( start, finish, max, estimate ); + REQUIRE( pth.nodes.size() == 4 ); + CHECK( pth.nodes[3].pos == Point() ); + // NOLINTNEXTLINE(cata-use-named-point-constants) + CHECK( pth.nodes[2].pos == Point( point( 1, 0 ) ) ); + CHECK( pth.nodes[1].pos == Point( point( 2, 0 ) ) ); + CHECK( pth.nodes[0].pos == Point( point( 3, 0 ) ) ); +} + +TEST_CASE( "simple_line_path" ) +{ + test_path(); + test_path(); +} diff --git a/tests/stomach_contents_test.cpp b/tests/stomach_contents_test.cpp index 6f5a81094a27c..05f0da0ced676 100644 --- a/tests/stomach_contents_test.cpp +++ b/tests/stomach_contents_test.cpp @@ -4,7 +4,6 @@ #include "avatar.h" #include "catch/catch.hpp" #include "calendar.h" -#include "game.h" #include "player.h" #include "player_helpers.h" #include "item.h" @@ -15,13 +14,13 @@ static void reset_time() { calendar::turn = calendar::start_of_cataclysm; - player &p = g->u; - p.set_stored_kcal( p.get_healthy_kcal() ); - p.set_hunger( 0 ); + Character &player_character = get_player_character(); + player_character.set_stored_kcal( player_character.get_healthy_kcal() ); + player_character.set_hunger( 0 ); clear_avatar(); } -static void pass_time( player &p, time_duration amt ) +static void pass_time( Character &p, time_duration amt ) { for( auto turns = 1_turns; turns < amt; turns += 1_turns ) { calendar::turn += 1_turns; @@ -29,13 +28,13 @@ static void pass_time( player &p, time_duration amt ) } } -static void clear_stomach( player &p ) +static void clear_stomach( Character &p ) { p.stomach.empty(); p.guts.empty(); } -static void set_all_vitamins( int target, player &p ) +static void set_all_vitamins( int target, Character &p ) { p.vitamin_set( vitamin_id( "vitA" ), target ); p.vitamin_set( vitamin_id( "vitB" ), target ); @@ -46,7 +45,7 @@ static void set_all_vitamins( int target, player &p ) // time (in minutes) it takes for the player to feel hungry // passes time on the calendar -static time_duration time_until_hungry( player &p ) +static time_duration time_until_hungry( Character &p ) { unsigned int thirty_minutes = 0; do { @@ -58,7 +57,7 @@ static time_duration time_until_hungry( player &p ) return thirty_minutes * 30_minutes; } -static void print_stomach_contents( player &p, const bool print ) +static void print_stomach_contents( Character &p, const bool print ) { if( !print ) { return; @@ -87,7 +86,7 @@ static void eat_all_nutrients( player &p ) // player does not thirst or tire or require vitamins TEST_CASE( "starve_test", "[starve][slow]" ) { - player &dummy = g->u; + Character &dummy = get_player_character(); reset_time(); clear_stomach( dummy ); @@ -125,7 +124,7 @@ TEST_CASE( "starve_test", "[starve][slow]" ) // player does not thirst or tire or require vitamins TEST_CASE( "starve_test_hunger3", "[starve][slow]" ) { - player &dummy = g->u; + Character &dummy = get_player_character(); reset_time(); clear_stomach( dummy ); while( !( dummy.has_trait( trait_id( "HUNGER3" ) ) ) ) { @@ -164,7 +163,7 @@ TEST_CASE( "all_nutrition_starve_test", "[starve][slow]" ) { // change this bool when editing the test const bool print_tests = false; - player &dummy = g->u; + avatar &dummy = get_avatar(); reset_time(); clear_stomach( dummy ); eat_all_nutrients( dummy ); @@ -205,7 +204,7 @@ TEST_CASE( "tape_worm_halves_nutrients" ) { const efftype_id effect_tapeworm( "tapeworm" ); const bool print_tests = false; - player &dummy = g->u; + avatar &dummy = get_avatar(); reset_time(); clear_stomach( dummy ); eat_all_nutrients( dummy ); @@ -225,7 +224,7 @@ TEST_CASE( "hunger" ) { // change this bool when editing the test const bool print_tests = false; - player &dummy = g->u; + avatar &dummy = get_avatar(); reset_time(); clear_stomach( dummy ); dummy.initialize_stomach_contents(); @@ -268,8 +267,8 @@ TEST_CASE( "hunger" ) if( print_tests ) { printf( "%d minutes til hunger sets in\n", hunger_time ); } - CHECK( hunger_time <= 375 ); - CHECK( hunger_time >= 345 ); + CHECK( hunger_time <= 285 ); + CHECK( hunger_time >= 255 ); if( print_tests ) { print_stomach_contents( dummy, print_tests ); printf( "eat 16 veggy\n" ); diff --git a/tests/string_formatter_test.cpp b/tests/string_formatter_test.cpp index 001a83c06e95d..3ddf328dc156e 100644 --- a/tests/string_formatter_test.cpp +++ b/tests/string_formatter_test.cpp @@ -100,7 +100,10 @@ void mingw_test( const char *const old_pattern, const char *const new_pattern, c CHECK( original_result == new_result ); } -TEST_CASE( "string_formatter" ) +// Marking mayfail due to failure in Appveyor. Looks like a bug in the Visual +// Studio runtime libraries. Once that failure stops showing up on Appveyor, +// this can cease to be marked thus. +TEST_CASE( "string_formatter", "[!mayfail]" ) { test_typed_printf( "%hhi", "%i" ); test_typed_printf( "%hhu", "%u" ); @@ -144,19 +147,8 @@ TEST_CASE( "string_formatter" ) #pragma GCC diagnostic pop test_new_old_pattern( "%6$-*5$.*4$f%3$s%2$s%1$s", "%6$-*5$.*4$f", "", "", "", 7, 4, 100.44 ); } - CHECK_THROWS( test_for_error( "%6$-*5$.*4$f", 1, 2, 3 ) ); - CHECK_THROWS( test_for_error( "%6$-*5$.*4$f", 1, 2, 3, 4 ) ); - CHECK_THROWS( test_for_error( "%6$-*5$.*4$f", 1, 2, 3, 4, 5 ) ); - - // invalid format specifier - CHECK_THROWS( test_for_error( "%k" ) ); - // can't print a void pointer - CHECK_THROWS( test_for_error( "%s", static_cast( nullptr ) ) ); - CHECK_THROWS( test_for_error( "%d", static_cast( nullptr ) ) ); - CHECK_THROWS( test_for_error( "%d", "some string" ) ); test_for_expected( "", "", "whatever", 5, 0.4 ); - CHECK_THROWS( test_for_error( "%d %d %d %d %d", 1, 2, 3, 4 ) ); test_for_expected( "1 2 3 4 5", "%d %d %d %d %d", 1, 2, 3, 4, 5 ); // test automatic type conversion @@ -570,3 +562,19 @@ TEST_CASE( "string_formatter" ) importet_test( 414, "1234ABCD ", "% -+0*.*X", 20, 5, 305441741 ); importet_test( 415, "00EDCB5433 ", "% -+0*.*X", 20, 10, 3989525555U ); } + +TEST_CASE( "string_formatter_errors" ) +{ + CHECK_THROWS( test_for_error( "%6$-*5$.*4$f", 1, 2, 3 ) ); + CHECK_THROWS( test_for_error( "%6$-*5$.*4$f", 1, 2, 3, 4 ) ); + CHECK_THROWS( test_for_error( "%6$-*5$.*4$f", 1, 2, 3, 4, 5 ) ); + + // invalid format specifier + CHECK_THROWS( test_for_error( "%k" ) ); + // can't print a void pointer + CHECK_THROWS( test_for_error( "%s", static_cast( nullptr ) ) ); + CHECK_THROWS( test_for_error( "%d", static_cast( nullptr ) ) ); + CHECK_THROWS( test_for_error( "%d", "some string" ) ); + + CHECK_THROWS( test_for_error( "%d %d %d %d %d", 1, 2, 3, 4 ) ); +} diff --git a/tests/stringmaker.h b/tests/stringmaker.h index f65d7fc3c2450..bf8cf7521a5dd 100644 --- a/tests/stringmaker.h +++ b/tests/stringmaker.h @@ -26,6 +26,13 @@ struct StringMaker { } }; +template<> +struct StringMaker { + static std::string convert( const point &p ) { + return string_format( "point( %d, %d )", p.x, p.y ); + } +}; + template<> struct StringMaker { static std::string convert( const rectangle &r ) { diff --git a/tests/test_main.cpp b/tests/test_main.cpp index f0ff30227e652..758a99316668b 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -141,17 +141,17 @@ static void init_global_game_state( const std::vector &mods, g->load_core_data( ui ); g->load_world_modfiles( ui ); - g->u = avatar(); - g->u.create( character_type::NOW ); + get_avatar() = avatar(); + get_avatar().create( character_type::NOW ); - g->m = map( get_option( "ZLEVELS" ) ); + get_map() = map(); overmap_special_batch empty_specials( point_zero ); overmap_buffer.create_custom_overmap( point_zero, empty_specials ); - g->m.load( tripoint( g->get_levx(), g->get_levy(), g->get_levz() ), false ); + get_map().load( tripoint( g->get_levx(), g->get_levy(), g->get_levz() ), false ); - g->weather.update_weather(); + get_weather().update_weather(); } // Checks if any of the flags are in container, removes them all diff --git a/tests/throwing_test.cpp b/tests/throwing_test.cpp index 15eca333b61e8..9fe7ba95fd063 100644 --- a/tests/throwing_test.cpp +++ b/tests/throwing_test.cpp @@ -55,7 +55,7 @@ static std::ostream &operator<<( std::ostream &stream, const throw_test_pstats & static const skill_id skill_throw = skill_id( "throw" ); -static void reset_player( player &p, const throw_test_pstats &pstats, const tripoint &pos ) +static void reset_player( Character &p, const throw_test_pstats &pstats, const tripoint &pos ) { p.reset(); p.set_stamina( p.get_stamina_max() ); @@ -129,7 +129,7 @@ static void test_throwing_player_versus( } } g->remove_zombie( mon ); - p.i_rem( -1 ); + p.remove_weapon(); // only need to check dmg_thresh_met because it can only be true if // hit_thresh_met first } while( !dmg_thresh_met && data.hits.n() < max_throws ); @@ -171,7 +171,7 @@ constexpr throw_test_pstats hi_skill_athlete_stats = { MAX_SKILL, 12, 12, 12 }; TEST_CASE( "basic_throwing_sanity_tests", "[throwing],[balance]" ) { - player &p = g->u; + avatar &p = get_avatar(); clear_map(); SECTION( "test_player_vs_zombie_rock_basestats" ) { @@ -216,7 +216,7 @@ TEST_CASE( "basic_throwing_sanity_tests", "[throwing],[balance]" ) TEST_CASE( "throwing_skill_impact_test", "[throwing],[balance]" ) { - player &p = g->u; + avatar &p = get_avatar(); clear_map(); // we already cover low stats in the sanity tests and we only cover a few @@ -279,7 +279,7 @@ static void test_player_kills_monster( while( p.get_moves() > 0 ) { p.wield( it ); p.throw_item( mon.pos(), it ); - p.i_rem( -1 ); + p.remove_weapon(); ++num_items; } mon_is_dead = mon.is_dead(); @@ -304,7 +304,7 @@ static void test_player_kills_monster( TEST_CASE( "player_kills_zombie_before_reach", "[throwing],[balance][scenario]" ) { - player &p = g->u; + avatar &p = get_avatar(); clear_map(); SECTION( "test_player_kills_zombie_with_rock_basestats" ) { @@ -315,7 +315,7 @@ TEST_CASE( "player_kills_zombie_before_reach", "[throwing],[balance][scenario]" int throw_cost( const player &c, const item &to_throw ); TEST_CASE( "time_to_throw_independent_of_number_of_projectiles", "[throwing],[balance]" ) { - player &p = g->u; + player &p = get_avatar(); clear_avatar(); item thrown( "throwing_stick", calendar::turn, 10 ); diff --git a/tests/vehicle_drag_test.cpp b/tests/vehicle_drag_test.cpp index 499b2eafc1ddb..a7268479d814e 100644 --- a/tests/vehicle_drag_test.cpp +++ b/tests/vehicle_drag_test.cpp @@ -3,10 +3,10 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" #include "catch/catch.hpp" +#include "character.h" #include "map.h" #include "map_helpers.h" #include "point.h" @@ -27,7 +27,7 @@ static void clear_game_drag( const ter_id &terrain ) clear_creatures(); clear_npcs(); - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); // Move player somewhere safe CHECK( !player_character.in_vehicle ); player_character.setpos( tripoint_zero ); diff --git a/tests/vehicle_efficiency_test.cpp b/tests/vehicle_efficiency_test.cpp index 87ceb1d9257bd..f3256deb70031 100644 --- a/tests/vehicle_efficiency_test.cpp +++ b/tests/vehicle_efficiency_test.cpp @@ -10,10 +10,10 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" #include "catch/catch.hpp" +#include "character.h" #include "enums.h" #include "game.h" #include "item.h" @@ -42,11 +42,12 @@ static void clear_game( const ter_id &terrain ) clear_npcs(); clear_vehicles(); + Character &player_character = get_player_character(); // Move player somewhere safe - REQUIRE_FALSE( g->u.in_vehicle ); - g->u.setpos( tripoint_zero ); + REQUIRE_FALSE( player_character.in_vehicle ); + player_character.setpos( tripoint_zero ); // Blind the player to avoid needless drawing-related overhead - g->u.add_effect( effect_blind, 1_turns, num_bp, true ); + player_character.add_effect( effect_blind, 1_turns, num_bp, true ); build_test_map( terrain ); } @@ -431,7 +432,7 @@ TEST_CASE( "vehicle_efficiency", "[vehicle] [engine]" ) test_vehicle( "truck_swat", 5959334, 483800, 322700, 29610, 7604 ); test_vehicle( "tractor_plow", 723658, 482400, 482400, 113900, 113900 ); test_vehicle( "apc", 5801619, 1069000, 922400, 130800, 85590 ); - test_vehicle( "humvee", 5503245, 574300, 325900, 25620, 9171 ); + test_vehicle( "humvee", 5503345, 574300, 325900, 25620, 9171 ); test_vehicle( "road_roller", 8829220, 357200, 380200, 22760, 6925 ); test_vehicle( "golf_cart", 444630, 52460, 105500, 27250, 14200 ); } diff --git a/tests/vehicle_interact_test.cpp b/tests/vehicle_interact_test.cpp index 4caaaeb294134..93add711f3688 100644 --- a/tests/vehicle_interact_test.cpp +++ b/tests/vehicle_interact_test.cpp @@ -2,10 +2,9 @@ #include #include -#include "avatar.h" #include "calendar.h" #include "catch/catch.hpp" -#include "game.h" +#include "character.h" #include "inventory.h" #include "item.h" #include "map.h" @@ -23,15 +22,16 @@ static void test_repair( const std::vector &tools, bool expect_craftable ) clear_map(); const tripoint test_origin( 60, 60, 0 ); - g->u.setpos( test_origin ); + Character &player_character = get_player_character(); + player_character.setpos( test_origin ); const item backpack( "backpack" ); - g->u.wear( g->u.i_add( backpack ), false ); + player_character.wear_item( backpack ); for( const item &gear : tools ) { - g->u.i_add( gear ); + player_character.i_add( gear ); } const tripoint vehicle_origin = test_origin + tripoint_south_east; - vehicle *veh_ptr = g->m.add_vehicle( vproto_id( "bicycle" ), vehicle_origin, -90, 0, 0 ); + vehicle *veh_ptr = get_map().add_vehicle( vproto_id( "bicycle" ), vehicle_origin, -90, 0, 0 ); REQUIRE( veh_ptr != nullptr ); // Find the frame at the origin. vehicle_part *origin_frame = nullptr; @@ -51,10 +51,11 @@ static void test_repair( const std::vector &tools, bool expect_craftable ) requirement_data reqs = vp.repair_requirements(); // Bust cache on crafting_inventory() - g->u.mod_moves( 1 ); - inventory crafting_inv = g->u.crafting_inventory(); - bool can_repair = vp.repair_requirements().can_make_with_inventory( g->u.crafting_inventory(), - is_crafting_component ); + player_character.mod_moves( 1 ); + inventory crafting_inv = player_character.crafting_inventory(); + bool can_repair = vp.repair_requirements().can_make_with_inventory( + player_character.crafting_inventory(), + is_crafting_component ); CHECK( can_repair == expect_craftable ); } diff --git a/tests/vehicle_power_test.cpp b/tests/vehicle_power_test.cpp index 74b0fbb5fb372..f069d3ba1a01f 100644 --- a/tests/vehicle_power_test.cpp +++ b/tests/vehicle_power_test.cpp @@ -2,10 +2,10 @@ #include #include -#include "avatar.h" #include "bodypart.h" #include "calendar.h" #include "catch/catch.hpp" +#include "character.h" #include "map.h" #include "map_helpers.h" #include "point.h" @@ -17,9 +17,10 @@ static const itype_id fuel_type_battery( "battery" ); static const itype_id fuel_type_plut_cell( "plut_cell" ); static const efftype_id effect_blind( "blind" ); +// TODO: Move this into player_helpers to avoid character include. static void reset_player() { - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); // Move player somewhere safe REQUIRE( !player_character.in_vehicle ); player_character.setpos( tripoint_zero ); @@ -71,7 +72,7 @@ TEST_CASE( "vehicle power with reactor and solar panels", "[vehicle][power]" ) calendar::turn = calendar::turn_zero + calendar::season_length() + 1_days; const time_point start_time = sunrise( calendar::turn ) + 3_hours; veh_ptr->update_time( start_time ); - get_weather().weather_override = WEATHER_SUNNY; + get_weather().weather_override = weather_type_id( "sunny" ); AND_GIVEN( "the battery has no charge" ) { veh_ptr->discharge_battery( veh_ptr->fuel_left( fuel_type_battery ) ); diff --git a/tests/vehicle_ramp_test.cpp b/tests/vehicle_ramp_test.cpp new file mode 100644 index 0000000000000..7c44124012c66 --- /dev/null +++ b/tests/vehicle_ramp_test.cpp @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avatar.h" +#include "catch/catch.hpp" +#include "itype.h" +#include "map.h" +#include "map_helpers.h" +#include "map_iterator.h" +#include "veh_type.h" +#include "vehicle.h" +#include "vpart_range.h" +#include "bodypart.h" +#include "calendar.h" +#include "enums.h" +#include "game.h" +#include "game_constants.h" +#include "item.h" +#include "line.h" +#include "mapdata.h" +#include "map_helpers.h" +#include "monster.h" +#include "mtype.h" +#include "units.h" +#include "type_id.h" +#include "point.h" +#include "vpart_position.h" +#include "player_helpers.h" +#include "map_helpers.h" + +static const efftype_id effect_blind( "blind" ); + +static void clear_game_and_set_ramp( const int transit_x, bool use_ramp, bool up ) +{ + // Set to turn 0 to prevent solars from producing power + calendar::turn = 0; + clear_creatures(); + clear_npcs(); + clear_vehicles(); + + Character &player_character = get_player_character(); + // Move player somewhere safe + REQUIRE_FALSE( player_character.in_vehicle ); + player_character.setpos( tripoint_zero ); + // Blind the player to avoid needless drawing-related overhead + //player_character.add_effect( effect_blind, 1_turns, num_bp, true ); + + map &here = get_map(); + wipe_map_terrain(); + build_test_map( ter_id( "t_pavement" ) ); + if( use_ramp ) { + const int upper_zlevel = up ? 1 : 0; + const int lower_zlevel = up - 1; + const int highx = transit_x + ( up ? 0 : 1 ); + const int lowx = transit_x + ( up ? 1 : 0 ); + + // up z1 ...... rdh rDl + // z0 rUh rul ................. + // down z0 rDl rdh ................. + // z-1 ...... rdl rUh + // 60 61 + for( int y = 0; y < SEEY * MAPSIZE; y++ ) { + for( int x = 0; x < transit_x; x++ ) { + const int mid = up ? upper_zlevel : lower_zlevel; + here.ter_set( tripoint( x, y, mid - 2 ), ter_id( "t_rock" ) ); + here.ter_set( tripoint( x, y, mid - 1 ), ter_id( "t_rock" ) ); + here.ter_set( tripoint( x, y, mid ), ter_id( "t_pavement" ) ); + here.ter_set( tripoint( x, y, mid + 1 ), ter_id( "t_open_air" ) ); + here.ter_set( tripoint( x, y, mid + 2 ), ter_id( "t_open_air" ) ); + } + const tripoint ramp_up_low = tripoint( lowx, y, lower_zlevel ); + const tripoint ramp_up_high = tripoint( highx, y, lower_zlevel ); + const tripoint ramp_down_low = tripoint( lowx, y, upper_zlevel ); + const tripoint ramp_down_high = tripoint( highx, y, upper_zlevel ); + here.ter_set( ramp_up_low, ter_id( "t_ramp_up_low" ) ); + here.ter_set( ramp_up_high, ter_id( "t_ramp_up_high" ) ); + here.ter_set( ramp_down_low, ter_id( "t_ramp_down_low" ) ); + here.ter_set( ramp_down_high, ter_id( "t_ramp_down_high" ) ); + for( int x = transit_x + 2; x < SEEX * MAPSIZE; x++ ) { + here.ter_set( tripoint( x, y, 1 ), ter_id( "t_open_air" ) ); + here.ter_set( tripoint( x, y, 0 ), ter_id( "t_pavement" ) ); + here.ter_set( tripoint( x, y, -1 ), ter_id( "t_rock" ) ); + } + } + } + here.invalidate_map_cache( 0 ); + here.build_map_cache( 0, true ); +} + +// Algorithm goes as follows: +// Clear map and create a ramp +// Spawn a vehicle +// Drive it over the ramp, and confirm that the vehicle changes z-levels +static void ramp_transition_angled( const vproto_id &veh_id, const int angle, + const int transition_x, bool use_ramp, bool up ) +{ + map &here = get_map(); + clear_game_and_set_ramp( transition_x, use_ramp, up ); + + const tripoint map_starting_point( transition_x + 4, 60, 0 ); + REQUIRE( here.ter( map_starting_point ) == ter_id( "t_pavement" ) ); + if( here.ter( map_starting_point ) != ter_id( "t_pavement" ) ) { + return; + } + vehicle *veh_ptr = here.add_vehicle( veh_id, map_starting_point, angle, 1, 0 ); + + REQUIRE( veh_ptr != nullptr ); + if( veh_ptr == nullptr ) { + return; + } + + vehicle &veh = *veh_ptr; + veh.check_falling_or_floating(); + + REQUIRE( !veh.is_in_water() ); + + veh.tags.insert( "IN_CONTROL_OVERRIDE" ); + veh.engine_on = true; + Character &player_character = get_player_character(); + player_character.setpos( map_starting_point ); + + REQUIRE( player_character.pos() == map_starting_point ); + if( player_character.pos() != map_starting_point ) { + return; + } + get_map().board_vehicle( map_starting_point, &player_character ); + REQUIRE( player_character.pos() == map_starting_point ); + if( player_character.pos() != map_starting_point ) { + return; + } + const int transition_cycle = 3; + veh.cruise_velocity = 0; + veh.velocity = 0; + here.vehmove(); + + const int target_velocity = 400; + veh.cruise_velocity = target_velocity; + veh.velocity = target_velocity; + CHECK( veh.safe_velocity() > 0 ); + int cycles = 0; + const int target_z = use_ramp ? ( up ? 1 : -1 ) : 0; + + std::set vpts = veh.get_points(); + while( veh.engine_on && veh.safe_velocity() > 0 && cycles < 10 ) { + for( const tripoint &checkpt : vpts ) { + int partnum = 0; + vehicle *check_veh = here.veh_at_internal( checkpt, partnum ); + CHECK( check_veh == veh_ptr ); + } + vpts.clear(); + here.vehmove(); + // If the vehicle starts skidding, the effects become random and test is RUINED + REQUIRE( !veh.skidding ); + for( const tripoint &pos : veh.get_points() ) { + REQUIRE( here.ter( pos ) ); + } + for( const vpart_reference &vp : veh.get_all_parts() ) { + if( vp.info().location != "structure" ) { + continue; + } + const point &pmount = vp.mount(); + const tripoint &ppos = vp.pos(); + if( cycles > ( transition_cycle - pmount.x ) ) { + CHECK( ppos.z == target_z ); + } else { + CHECK( ppos.z == 0 ); + } + if( pmount.x == 0 && pmount.y == 0 ) { + CHECK( player_character.pos() == ppos ); + } + } + vpts = veh.get_points(); + cycles++; + } + const cata::optional vp = here.veh_at( player_character.pos() ).part_with_feature( + VPFLAG_BOARDABLE, true ); + REQUIRE( vp ); + if( vp ) { + const int z_change = map_starting_point.z - player_character.pos().z; + here.unboard_vehicle( *vp, &player_character, false ); + here.ter_set( map_starting_point, ter_id( "t_pavement" ) ); + player_character.setpos( map_starting_point ); + if( z_change ) { + g->vertical_move( z_change, true ); + } + } +} + +static void test_ramp( std::string type, const int transition_x ) +{ + SECTION( type + " no ramp" ) { + ramp_transition_angled( vproto_id( type ), 180, transition_x, false, false ); + } + SECTION( type + " ramp up" ) { + ramp_transition_angled( vproto_id( type ), 180, transition_x, true, true ); + } + SECTION( type + " ramp down" ) { + ramp_transition_angled( vproto_id( type ), 180, transition_x, true, false ); + } + SECTION( type + " angled no ramp" ) { + ramp_transition_angled( vproto_id( type ), 225, transition_x, false, false ); + } + SECTION( type + " angled ramp down" ) { + ramp_transition_angled( vproto_id( type ), 225, transition_x, true, false ); + } + SECTION( type + " angled ramp up" ) { + ramp_transition_angled( vproto_id( type ), 225, transition_x, true, true ); + } +} + +static std::vector ramp_vehs_to_test = {{ + "motorcycle", + } +}; + +// I'd like to do this in a single loop, but that doesn't work for some reason +TEST_CASE( "vehicle_ramp_test_59", "[vehicle][ramp]" ) +{ + for( const std::string &veh : ramp_vehs_to_test ) { + test_ramp( veh, 59 ); + } +} +TEST_CASE( "vehicle_ramp_test_60", "[vehicle][ramp]" ) +{ + for( const std::string &veh : ramp_vehs_to_test ) { + test_ramp( veh, 60 ); + } +} +TEST_CASE( "vehicle_ramp_test_61", "[vehicle][ramp]" ) +{ + for( const std::string &veh : ramp_vehs_to_test ) { + test_ramp( veh, 61 ); + } +} + +static void level_out( const vproto_id &veh_id, const bool drop_pos ) +{ + map &here = get_map(); + clear_game_and_set_ramp( 75, drop_pos, false ); + const int start_z = drop_pos ? 1 : 0; + + const tripoint map_starting_point( 60, 60, start_z ); + vehicle *veh_ptr = here.add_vehicle( veh_id, map_starting_point, 180, 1, 0 ); + + REQUIRE( veh_ptr != nullptr ); + if( veh_ptr == nullptr ) { + return; + } + vehicle &veh = *veh_ptr; + veh.check_falling_or_floating(); + + REQUIRE( !veh.is_in_water() ); + + veh.tags.insert( "IN_CONTROL_OVERRIDE" ); + veh.engine_on = true; + + const int target_velocity = 800; + veh.cruise_velocity = target_velocity; + veh.velocity = target_velocity; + CHECK( veh.safe_velocity() > 0 ); + + std::vector all_parts; + for( const tripoint &pos : veh.get_points() ) { + for( vehicle_part *prt : veh.get_parts_at( pos, "", part_status_flag::any ) ) { + all_parts.push_back( prt ); + if( drop_pos && prt->mount.x < 0 ) { + prt->precalc[0].z = -1; + prt->precalc[1].z = -1; + } else if( !drop_pos && prt->mount.x > 1 ) { + prt->precalc[0].z = 1; + prt->precalc[1].z = 1; + } + } + } + std::set z_span; + for( vehicle_part *prt : all_parts ) { + z_span.insert( veh.global_part_pos3( *prt ).z ); + } + REQUIRE( z_span.size() > 1 ); + + monster *dmon_p = g->place_critter_at( mtype_id( "debug_mon" ), map_starting_point ); + monster &dmon = *dmon_p; + + for( int y = 0; y < SEEY * MAPSIZE; y++ ) { + for( int x = 0; x < SEEX * MAPSIZE; x++ ) { + here.ter_set( tripoint( x, y, 1 ), ter_id( "t_open_air" ) ); + here.ter_set( tripoint( x, y, 0 ), ter_id( "t_pavement" ) ); + } + } + + here.vehmove(); + for( vehicle_part *prt : all_parts ) { + CHECK( veh.global_part_pos3( *prt ).z == 0 ); + } + CHECK( dmon.posz() == 0 ); + CHECK( veh.global_pos3().z == 0 ); +} + +static void test_leveling( std::string type ) +{ + SECTION( type + " body drop" ) { + level_out( vproto_id( type ), true ); + } + SECTION( type + " edge drop" ) { + level_out( vproto_id( type ), false ); + } +} + +static std::vector level_vehs_to_test = {{ + "beetle", + } +}; + +TEST_CASE( "vehicle_level_test", "[vehicle][ramp]" ) +{ + for( const std::string &veh : level_vehs_to_test ) { + test_leveling( veh ); + } +} diff --git a/tests/vehicle_split_test.cpp b/tests/vehicle_split_test.cpp index 3a615b43603c2..de96ec8412166 100644 --- a/tests/vehicle_split_test.cpp +++ b/tests/vehicle_split_test.cpp @@ -2,9 +2,8 @@ #include #include -#include "avatar.h" #include "catch/catch.hpp" -#include "game.h" +#include "character.h" #include "map.h" #include "vehicle.h" #include "type_id.h" @@ -12,26 +11,28 @@ TEST_CASE( "vehicle_split_section" ) { + map &here = get_map(); + Character &player_character = get_player_character(); for( int dir = 0; dir < 360; dir += 15 ) { - CHECK( !g->u.in_vehicle ); + CHECK( !player_character.in_vehicle ); const tripoint test_origin( 15, 15, 0 ); - g->u.setpos( test_origin ); + player_character.setpos( test_origin ); tripoint vehicle_origin = tripoint( 10, 10, 0 ); - VehicleList vehs = g->m.get_vehicles(); + VehicleList vehs = here.get_vehicles(); vehicle *veh_ptr; for( auto &vehs_v : vehs ) { veh_ptr = vehs_v.v; - g->m.destroy_vehicle( veh_ptr ); + here.destroy_vehicle( veh_ptr ); } - REQUIRE( g->m.get_vehicles().empty() ); - veh_ptr = g->m.add_vehicle( vproto_id( "cross_split_test" ), vehicle_origin, dir, 0, 0 ); + REQUIRE( here.get_vehicles().empty() ); + veh_ptr = here.add_vehicle( vproto_id( "cross_split_test" ), vehicle_origin, dir, 0, 0 ); REQUIRE( veh_ptr != nullptr ); std::set original_points = veh_ptr->get_points( true ); - g->m.destroy( vehicle_origin ); + here.destroy( vehicle_origin ); veh_ptr->part_removal_cleanup(); REQUIRE( veh_ptr->get_parts_at( vehicle_origin, "", part_status_flag::available ).empty() ); - vehs = g->m.get_vehicles(); + vehs = here.get_vehicles(); // destroying the center frame results in 4 new vehicles CHECK( vehs.size() == 4 ); if( vehs.size() == 4 ) { @@ -59,19 +60,19 @@ TEST_CASE( "vehicle_split_section" ) } } } - g->m.destroy_vehicle( vehs[ 3 ].v ); - g->m.destroy_vehicle( vehs[ 2 ].v ); - g->m.destroy_vehicle( vehs[ 1 ].v ); - g->m.destroy_vehicle( vehs[ 0 ].v ); + here.destroy_vehicle( vehs[ 3 ].v ); + here.destroy_vehicle( vehs[ 2 ].v ); + here.destroy_vehicle( vehs[ 1 ].v ); + here.destroy_vehicle( vehs[ 0 ].v ); } - REQUIRE( g->m.get_vehicles().empty() ); + REQUIRE( here.get_vehicles().empty() ); vehicle_origin = tripoint( 20, 20, 0 ); - veh_ptr = g->m.add_vehicle( vproto_id( "circle_split_test" ), vehicle_origin, dir, 0, 0 ); + veh_ptr = here.add_vehicle( vproto_id( "circle_split_test" ), vehicle_origin, dir, 0, 0 ); REQUIRE( veh_ptr != nullptr ); - g->m.destroy( vehicle_origin ); + here.destroy( vehicle_origin ); veh_ptr->part_removal_cleanup(); REQUIRE( veh_ptr->get_parts_at( vehicle_origin, "", part_status_flag::available ).empty() ); - vehs = g->m.get_vehicles(); + vehs = here.get_vehicles(); CHECK( vehs.size() == 1 ); if( vehs.size() == 1 ) { CHECK( vehs[ 0 ].v->part_count() == 38 ); diff --git a/tests/vehicle_test.cpp b/tests/vehicle_test.cpp index 82cbe00928294..c6c5b63e0d31f 100644 --- a/tests/vehicle_test.cpp +++ b/tests/vehicle_test.cpp @@ -19,7 +19,7 @@ TEST_CASE( "detaching_vehicle_unboards_passengers" ) const tripoint test_origin( 60, 60, 0 ); const tripoint vehicle_origin = test_origin; map &here = get_map(); - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); vehicle *veh_ptr = here.add_vehicle( vproto_id( "bicycle" ), vehicle_origin, -90, 0, 0 ); here.board_vehicle( test_origin, &player_character ); REQUIRE( player_character.in_vehicle ); diff --git a/tests/vehicle_turrets_test.cpp b/tests/vehicle_turrets_test.cpp index 6c319c9adf96d..a1416f8983660 100644 --- a/tests/vehicle_turrets_test.cpp +++ b/tests/vehicle_turrets_test.cpp @@ -5,8 +5,8 @@ #include #include "ammo.h" -#include "avatar.h" #include "catch/catch.hpp" +#include "character.h" #include "item.h" #include "item_location.h" #include "itype.h" @@ -61,7 +61,7 @@ static const vpart_info *biggest_tank( const ammotype &ammo ) TEST_CASE( "vehicle_turret", "[vehicle] [gun] [magazine] [.]" ) { map &here = get_map(); - avatar &player_character = get_avatar(); + Character &player_character = get_player_character(); for( auto e : turret_types() ) { SECTION( e->name() ) { vehicle *veh = here.add_vehicle( vproto_id( "none" ), point( 65, 65 ), 270, 0, 0 ); diff --git a/tests/vision_test.cpp b/tests/vision_test.cpp index a9d218973675b..e711727bd13b3 100644 --- a/tests/vision_test.cpp +++ b/tests/vision_test.cpp @@ -8,7 +8,6 @@ #include #include -#include "avatar.h" #include "calendar.h" #include "catch/catch.hpp" #include "character.h" @@ -56,23 +55,24 @@ static void full_map_test( const std::vector &setup, const efftype_id effect_narcosis( "narcosis" ); const ter_id t_flat_roof( "t_flat_roof" ); + Character &player_character = get_player_character(); g->place_player( tripoint( 60, 60, 0 ) ); - g->u.worn.clear(); // Remove any light-emitting clothing - g->u.clear_effects(); + player_character.worn.clear(); // Remove any light-emitting clothing + player_character.clear_effects(); clear_map(); g->reset_light_level(); if( !!( flags & vision_test_flags::crouching ) ) { - g->u.set_movement_mode( move_mode_crouch ); + player_character.set_movement_mode( move_mode_crouch ); } else { - g->u.set_movement_mode( move_mode_walk ); + player_character.set_movement_mode( move_mode_walk ); } - REQUIRE( !g->u.is_blind() ); - REQUIRE( !g->u.in_sleep_state() ); - REQUIRE( !g->u.has_effect( effect_narcosis ) ); + REQUIRE( !player_character.is_blind() ); + REQUIRE( !player_character.in_sleep_state() ); + REQUIRE( !player_character.has_effect( effect_narcosis ) ); - g->u.recalc_sight_limits(); + player_character.recalc_sight_limits(); calendar::turn = time; @@ -96,13 +96,13 @@ static void full_map_test( const std::vector &setup, case 'V': case 'U': case 'u': - origin = g->u.pos() - point( x, y ); + origin = player_character.pos() - point( x, y ); if( setup[y][x] == 'V' ) { item headlamp( "wearable_light_on" ); item battery( "light_battery_cell" ); battery.ammo_set( battery.ammo_default(), -1 ); headlamp.put_in( battery, item_pocket::pocket_type::MAGAZINE_WELL ); - g->u.worn.push_back( headlamp ); + player_character.worn.push_back( headlamp ); } break; } @@ -112,7 +112,7 @@ static void full_map_test( const std::vector &setup, { // Sanity check on player placement REQUIRE( origin.z < OVERMAP_HEIGHT ); - tripoint player_offset = g->u.pos() - origin; + tripoint player_offset = player_character.pos() - origin; REQUIRE( player_offset.y >= 0 ); REQUIRE( player_offset.y < height ); REQUIRE( player_offset.x >= 0 ); @@ -121,6 +121,7 @@ static void full_map_test( const std::vector &setup, REQUIRE( ( player_char == 'U' || player_char == 'u' || player_char == 'V' ) ); } + map &here = get_map(); for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { const tripoint p = origin + point( x, y ); @@ -129,21 +130,21 @@ static void full_map_test( const std::vector &setup, case ' ': break; case 'L': - g->m.ter_set( p, t_utility_light ); - g->m.ter_set( above, t_flat_roof ); + here.ter_set( p, t_utility_light ); + here.ter_set( above, t_flat_roof ); break; case '#': - g->m.ter_set( p, t_brick_wall ); - g->m.ter_set( above, t_flat_roof ); + here.ter_set( p, t_brick_wall ); + here.ter_set( above, t_flat_roof ); break; case '=': - g->m.ter_set( p, t_window_frame ); - g->m.ter_set( above, t_flat_roof ); + here.ter_set( p, t_window_frame ); + here.ter_set( above, t_flat_roof ); break; case '-': case 'u': - g->m.ter_set( p, t_floor ); - g->m.ter_set( above, t_flat_roof ); + here.ter_set( p, t_floor ); + here.ter_set( above, t_flat_roof ); break; case 'U': case 'V': @@ -159,17 +160,17 @@ static void full_map_test( const std::vector &setup, // player's vision_threshold is based on the previous lighting level (so // they might, for example, have poor nightvision due to having just been // in daylight) - g->m.update_visibility_cache( origin.z ); - g->m.invalidate_map_cache( origin.z ); - g->m.build_map_cache( origin.z ); - g->m.update_visibility_cache( origin.z ); - g->m.invalidate_map_cache( origin.z ); - g->m.build_map_cache( origin.z ); - - const level_cache &cache = g->m.access_cache( origin.z ); - const level_cache &above_cache = g->m.access_cache( origin.z + 1 ); + here.update_visibility_cache( origin.z ); + here.invalidate_map_cache( origin.z ); + here.build_map_cache( origin.z ); + here.update_visibility_cache( origin.z ); + here.invalidate_map_cache( origin.z ); + here.build_map_cache( origin.z ); + + const level_cache &cache = here.access_cache( origin.z ); + const level_cache &above_cache = here.access_cache( origin.z + 1 ); const visibility_variables &vvcache = - g->m.get_visibility_variables_cache(); + here.get_visibility_variables_cache(); std::ostringstream fields; std::ostringstream transparency; @@ -186,7 +187,7 @@ static void full_map_test( const std::vector &setup, for( int x = 0; x < width; ++x ) { const tripoint p = origin + point( x, y ); const map::apparent_light_info al = map::apparent_light_helper( cache, p ); - for( auto &pr : g->m.field_at( p ) ) { + for( auto &pr : here.field_at( p ) ) { fields << pr.second.name() << ','; } fields << ' '; @@ -208,10 +209,10 @@ static void full_map_test( const std::vector &setup, floor_above << '\n'; } - INFO( "zlevels: " << g->m.has_zlevels() ); + INFO( "zlevels: " << here.has_zlevels() ); INFO( "origin: " << origin ); - INFO( "player: " << g->u.pos() ); - INFO( "unimpaired_range: " << g->u.unimpaired_range() ); + INFO( "player: " << player_character.pos() ); + INFO( "unimpaired_range: " << player_character.unimpaired_range() ); INFO( "vision_threshold: " << vvcache.vision_threshold ); INFO( "fields:\n" << fields.str() ); INFO( "transparency:\n" << transparency.str() ); @@ -228,7 +229,7 @@ static void full_map_test( const std::vector &setup, for( int y = 0; y < height; ++y ) { for( int x = 0; x < width; ++x ) { const tripoint p = origin + point( x, y ); - const lit_level level = g->m.apparent_light_at( p, vvcache ); + const lit_level level = here.apparent_light_at( p, vvcache ); const char exp_char = expected_results[y][x]; if( exp_char < '0' || exp_char > '9' ) { FAIL( "unexpected result char '" << diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index 696208e169996..3dbd44a810414 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -4,11 +4,9 @@ #include #include -#include "avatar.h" #include "calendar.h" #include "cata_utility.h" #include "catch/catch.hpp" -#include "game.h" #include "inventory.h" #include "item.h" #include "item_contents.h" @@ -16,7 +14,7 @@ #include "map.h" #include "map_selector.h" #include "optional.h" -#include "player.h" +#include "character.h" #include "point.h" #include "rng.h" #include "type_id.h" @@ -46,25 +44,26 @@ TEST_CASE( "visitable_remove", "[visitable]" ) REQUIRE( item( container_id ).is_container() ); REQUIRE( item( worn_id ).is_container() ); - player &p = g->u; + Character &p = get_player_character(); p.worn.clear(); p.worn.push_back( item( "backpack" ) ); p.inv.clear(); p.remove_weapon(); p.wear_item( item( "backpack" ) ); // so we don't drop anything + map &here = get_map(); // check if all tiles within radius are loaded within current submap and passable - const auto suitable = []( const tripoint & pos, const int radius ) { - std::vector tiles = closest_tripoints_first( pos, radius ); - return std::all_of( tiles.begin(), tiles.end(), []( const tripoint & e ) { - if( !g->m.inbounds( e ) ) { + const auto suitable = [&here]( const tripoint & pos, const int radius ) { + std::vector tiles = closest_points_first( pos, radius ); + return std::all_of( tiles.begin(), tiles.end(), [&here]( const tripoint & e ) { + if( !here.inbounds( e ) ) { return false; } - if( const optional_vpart_position vp = g->m.veh_at( e ) ) { - g->m.destroy_vehicle( &vp->vehicle() ); + if( const optional_vpart_position vp = here.veh_at( e ) ) { + here.destroy_vehicle( &vp->vehicle() ); } - g->m.i_clear( e ); - return g->m.passable( e ); + here.i_clear( e ); + return here.passable( e ); } ); }; @@ -73,7 +72,7 @@ TEST_CASE( "visitable_remove", "[visitable]" ) // move player randomly until we find a suitable position while( !suitable( p.pos(), 1 ) ) { CHECK( !p.in_vehicle ); - p.setpos( random_entry( closest_tripoints_first( p.pos(), 1 ) ) ); + p.setpos( random_entry( closest_points_first( p.pos(), 1 ) ) ); } item temp_liquid( liquid_id ); @@ -296,7 +295,7 @@ TEST_CASE( "visitable_remove", "[visitable]" ) } GIVEN( "A player surrounded by several bottles of water" ) { - std::vector tiles = closest_tripoints_first( p.pos(), 1 ); + std::vector tiles = closest_points_first( p.pos(), 1 ); tiles.erase( tiles.begin() ); // player tile int our = 0; // bottles placed on player tile @@ -306,11 +305,11 @@ TEST_CASE( "visitable_remove", "[visitable]" ) if( i == 0 || tiles.empty() ) { // always place at least one bottle on player tile our++; - g->m.add_item( p.pos(), obj ); + here.add_item( p.pos(), obj ); } else { // randomly place bottles on adjacent tiles adj++; - g->m.add_item( random_entry( tiles ), obj ); + here.add_item( random_entry( tiles ), obj ); } } REQUIRE( our + adj == count ); @@ -413,16 +412,16 @@ TEST_CASE( "visitable_remove", "[visitable]" ) } GIVEN( "An adjacent vehicle contains several bottles of water" ) { - std::vector tiles = closest_tripoints_first( p.pos(), 1 ); + std::vector tiles = closest_points_first( p.pos(), 1 ); tiles.erase( tiles.begin() ); // player tile tripoint veh = random_entry( tiles ); - REQUIRE( g->m.add_vehicle( vproto_id( "shopping_cart" ), veh, 0, 0, 0 ) ); + REQUIRE( here.add_vehicle( vproto_id( "shopping_cart" ), veh, 0, 0, 0 ) ); - REQUIRE( std::count_if( tiles.begin(), tiles.end(), []( const tripoint & e ) { - return static_cast( g->m.veh_at( e ) ); + REQUIRE( std::count_if( tiles.begin(), tiles.end(), [&here]( const tripoint & e ) { + return static_cast( here.veh_at( e ) ); } ) == 1 ); - const cata::optional vp = g->m.veh_at( veh ).part_with_feature( "CARGO", true ); + const cata::optional vp = here.veh_at( veh ).part_with_feature( "CARGO", true ); REQUIRE( vp ); vehicle *const v = &vp->vehicle(); const int part = vp->part_index(); diff --git a/tests/weather_test.cpp b/tests/weather_test.cpp index 29b95858e1232..1e2befc78f779 100644 --- a/tests/weather_test.cpp +++ b/tests/weather_test.cpp @@ -70,7 +70,7 @@ TEST_CASE( "weather realism" ) int hour = to_hours( time_past_new_year( i ) ); hourly_precip[hour] += precip_mm_per_hour( - weather::precip( wgen.get_weather_conditions( w ) ) ) + wgen.get_weather_conditions( w )->precip ) / 60; } diff --git a/tests/wield_times_test.cpp b/tests/wield_times_test.cpp index 0d6c790a49cad..9cd37fb745a8c 100644 --- a/tests/wield_times_test.cpp +++ b/tests/wield_times_test.cpp @@ -59,6 +59,7 @@ TEST_CASE( "Wield time test", "[wield]" ) item knife( "knife_hunting" ); avatar guy; + guy.set_body(); guy.worn.push_back( backpack ); item_location backpack_loc( guy, &guy.worn.back() ); backpack_loc->put_in( plastic_bag, item_pocket::pocket_type::CONTAINER ); diff --git a/tools/clang-tidy-plugin/UsePointApisCheck.cpp b/tools/clang-tidy-plugin/UsePointApisCheck.cpp index 61c82088a8916..7f71e9994431a 100644 --- a/tools/clang-tidy-plugin/UsePointApisCheck.cpp +++ b/tools/clang-tidy-plugin/UsePointApisCheck.cpp @@ -54,7 +54,9 @@ void UsePointApisCheck::registerMatchers( MatchFinder *Finder ) isXParam() ).bind( "xparam" ) ), - hasDeclaration( cxxMethodDecl( unless( ofClass( isPointType() ) ) ).bind( "callee" ) ) + hasDeclaration( + cxxMethodDecl( unless( ofClass( isPointOrCoordPointType() ) ) ).bind( "callee" ) + ) ).bind( "constructorCall" ), this ); diff --git a/tools/clang-tidy-plugin/Utils.h b/tools/clang-tidy-plugin/Utils.h index f3f51afb4d6ea..13dd8d4c15462 100644 --- a/tools/clang-tidy-plugin/Utils.h +++ b/tools/clang-tidy-plugin/Utils.h @@ -95,6 +95,14 @@ inline auto isPointType() return cxxRecordDecl( anyOf( hasName( "point" ), hasName( "tripoint" ) ) ); } +inline auto isPointOrCoordPointType() +{ + using namespace clang::ast_matchers; + return cxxRecordDecl( + anyOf( hasName( "point" ), hasName( "tripoint" ), hasName( "coord_point" ) ) + ); +} + inline auto isPointConstructor() { using namespace clang::ast_matchers;