From 7223232e50295fd314da7090b54fcd52dbba169a Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 15 Sep 2019 22:51:25 -0400 Subject: [PATCH 001/219] adding more tabs to bionics menu --- data/json/bionics.json | 78 ++-- data/json/bionicsDisplayType.json | 37 ++ data/raw/keybindings.json | 14 +- src/bionics.cpp | 65 ++- src/bionics.h | 25 ++ src/bionics_ui.cpp | 711 ++++++++++++++---------------- src/init.cpp | 1 + src/string_id_null_ids.cpp | 1 + src/type_id.h | 3 + 9 files changed, 530 insertions(+), 405 deletions(-) create mode 100644 data/json/bionicsDisplayType.json diff --git a/data/json/bionics.json b/data/json/bionics.json index 252d043c7eeec..9b0dab4fbadfd 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -5,7 +5,8 @@ "name": "Adrenaline Pump", "description": "A stimulator system has been surgically implanted alongside your adrenal glands, allowing you to trigger your body's adrenaline response at the cost of some bionic power.", "occupied_bodyparts": [ [ "TORSO", 6 ] ], - "act_cost": 50 + "act_cost": 50, + "display_type": "display_internal" }, { "id": "bio_ads", @@ -114,7 +115,8 @@ "name": "Optical Dampers", "description": "The lenses surgically installed over your eyes can be tinted to block out incoming light.", "included": true, - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_sensory" }, { "id": "bio_blood_anal", @@ -122,7 +124,8 @@ "name": "Blood Analysis", "description": "Small sensors have been surgically implanted in your heart, allowing you to analyze your blood. This will detect many illnesses, drugs, and other conditions.", "occupied_bodyparts": [ [ "TORSO", 5 ] ], - "act_cost": 25 + "act_cost": 25, + "display_type": "display_internal" }, { "id": "bio_blood_filter", @@ -130,7 +133,8 @@ "name": "Blood Filter", "description": "A filtration system in your heart allows you to actively filter out chemical impurities, primarily drugs. It will have limited impact on viruses. Note that it is not a targeted filter; ALL drugs in your system will be affected.", "occupied_bodyparts": [ [ "TORSO", 10 ] ], - "act_cost": 75 + "act_cost": 75, + "display_type": "display_internal" }, { "id": "bio_cable", @@ -200,7 +204,8 @@ "act_cost": 1, "react_cost": 1, "time": 24, - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_internal" }, { "id": "bio_cloak", @@ -289,7 +294,8 @@ "name": "Sound Dampeners", "description": "When this bionic is active, you can block hearing completely (with Enhanced Hearing deactivated) or dampen sound slightly (with Enhanced Hearing activated).", "included": true, - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_sensory" }, { "id": "bio_ears", @@ -298,7 +304,8 @@ "description": "When this bionic is active, your hearing will be drastically improved, allowing you to hear ten times better than the average person. Additionally, high-intensity sounds will be automatically dampened before they can damage your hearing.", "occupied_bodyparts": [ [ "HEAD", 3 ] ], "flags": [ "BIONIC_TOGGLED" ], - "included_bionics": [ "bio_earplugs" ] + "included_bionics": [ "bio_earplugs" ], + "display_type": "display_sensory" }, { "id": "bio_emp", @@ -306,7 +313,8 @@ "name": "Directional EMP", "description": "Surgically mounted in the palm of your hand are small parabolic EMP field generators. You may use power to fire a wide, but short-ranged blast which will disable electronics and robots.", "occupied_bodyparts": [ [ "ARM_R", 1 ], [ "HAND_R", 2 ] ], - "act_cost": 100 + "act_cost": 100, + "display_type": "display_weapon" }, { "type": "bionic", @@ -403,7 +411,8 @@ "act_cost": 1, "react_cost": 1, "time": 150, - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_sensory" }, { "id": "bio_tattoo_led", @@ -436,7 +445,8 @@ "name": "Respirator", "description": "A complex respiration augmentation system. Improves respiration ability in air and allows breathing water. Will automatically turn on when drowning. Turn on to recharge stamina faster, at moderate power cost. Asthmatics may also use it to stop asthma attacks.", "occupied_bodyparts": [ [ "TORSO", 8 ], [ "HEAD", 2 ], [ "MOUTH", 2 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_internal" }, { "id": "bio_ground_sonar", @@ -447,7 +457,8 @@ "flags": [ "BIONIC_TOGGLED" ], "act_cost": 5, "react_cost": 1, - "time": 1 + "time": 1, + "display_type": "display_sensory" }, { "id": "bio_heat_absorb", @@ -466,7 +477,8 @@ [ "FOOT_L", 2 ], [ "FOOT_R", 2 ] ], - "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ] + "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "display_type": "display_weapon" }, { "id": "bio_heatsink", @@ -488,7 +500,8 @@ "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], "act_cost": 4, "react_cost": 4, - "time": 1 + "time": 1, + "display_type": "display_internal" }, { "id": "bio_hydraulics", @@ -499,7 +512,8 @@ "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], "act_cost": 17, "react_cost": 17, - "time": 1 + "time": 1, + "display_type": "display_internal" }, { "id": "bio_infrared", @@ -510,7 +524,8 @@ "flags": [ "BIONIC_TOGGLED" ], "act_cost": 5, "react_cost": 1, - "time": 1 + "time": 1, + "display_type": "display_sensory" }, { "id": "bio_int_enhancer", @@ -555,7 +570,8 @@ "flags": [ "BIONIC_TOGGLED", "BIONIC_SLEEP_FRIENDLY", "BIONIC_NPC_USABLE" ], "act_cost": 10, "react_cost": 1, - "time": 3600 + "time": 3600, + "display_type": "display_internal" }, { "id": "bio_lighter", @@ -599,7 +615,8 @@ "flags": [ "BIONIC_TOGGLED", "BIONIC_SLEEP_FRIENDLY" ], "act_cost": 10, "react_cost": 1, - "time": 600 + "time": 600, + "display_type": "display_internal" }, { "id": "bio_metabolics", @@ -623,7 +640,8 @@ "name": "Repair Nanobots", "description": "Inside your body is a fleet of tiny dormant robots. While activated they will flit about your body, repairing damage at 1 HP/s and stopping bleeding at the cost of power.", "occupied_bodyparts": [ [ "TORSO", 10 ] ], - "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ] + "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "display_type": "display_internal" }, { "id": "bio_night", @@ -645,7 +663,8 @@ "flags": [ "BIONIC_TOGGLED" ], "act_cost": 1, "react_cost": 1, - "time": 10000 + "time": 10000, + "display_type": "display_sensory" }, { "id": "bio_noise", @@ -681,7 +700,8 @@ "name": "Sensory Dulling", "description": "Your nervous system is wired to allow you to inhibit the signals of pain, allowing you to dull your senses at will. However, the use of this system may cause delayed reaction time and drowsiness.", "occupied_bodyparts": [ [ "HEAD", 2 ] ], - "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ] + "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "display_type": "display_sensory" }, { "id": "bio_pokedeye", @@ -774,7 +794,8 @@ "flags": [ "BIONIC_TOGGLED" ], "act_cost": 1, "react_cost": 1, - "time": 1 + "time": 1, + "display_type": "display_weapon" }, { "id": "bio_razors", @@ -831,7 +852,8 @@ "flags": [ "BIONIC_TOGGLED" ], "act_cost": 1, "react_cost": 1, - "time": 6 + "time": 6, + "display_type": "display_sensory" }, { "id": "bio_shakes", @@ -847,7 +869,8 @@ "name": "Electroshock Unit", "description": "While fighting unarmed, or with a weapon that conducts electricity, there is a chance that a successful hit will shock your opponent, inflicting extra damage and disabling them temporarily at the cost of some energy.", "occupied_bodyparts": [ [ "TORSO", 8 ], [ "ARM_L", 3 ], [ "ARM_R", 3 ], [ "HAND_L", 1 ], [ "HAND_R", 1 ] ], - "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ] + "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "display_type": "display_weapon" }, { "id": "bio_shockwave", @@ -1020,7 +1043,8 @@ "name": "Joint Servo", "description": "Your leg joints have been equipped with servomotors that provide power-assisted movement. They are optimized for running, but walking also requires less effort when this bionic is online. However, when it's offline it will hamper your movement, as you struggle against its moving parts.", "occupied_bodyparts": [ [ "LEG_L", 12 ], [ "LEG_R", 12 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_internal" }, { "id": "bio_trip", @@ -1115,7 +1139,8 @@ "name": "Taste Modifier", "description": "A set of highly sensitive sensors is installed in your mouth, and a small yet sophisticated analyzer is installed in the cavity of your skull. The active bionic will nullify the taste of all comestibles with negative enjoyment value at the cost of draining bionic power.", "occupied_bodyparts": [ [ "HEAD", 1 ], [ "MOUTH", 1 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_sensory" }, { "id": "bio_soporific", @@ -1123,6 +1148,7 @@ "name": "Soporific Induction", "description": "An electrode has been implanted into your brain's ventrolateral preoptic nucleus. It turns on whenever you're trying to fall asleep, creating an artificial but effective sensation of fatigue.", "occupied_bodyparts": [ [ "HEAD", 1 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "display_type": "display_internal" } ] diff --git a/data/json/bionicsDisplayType.json b/data/json/bionicsDisplayType.json new file mode 100644 index 0000000000000..c9bf58ca7efc4 --- /dev/null +++ b/data/json/bionicsDisplayType.json @@ -0,0 +1,37 @@ +[ + { + "type": "bionics_display_type", + "ident": "display_weapon", + "display_string": "Weapons" + }, + { + "type": "bionics_display_type", + "ident": "display_power", + "display_string": "Power" + }, + { + "type": "bionics_display_type", + "ident": "display_sensory", + "display_string": "Sensory" + }, + { + "type": "bionics_display_type", + "ident": "display_internal", + "display_string": "Internal" + }, + { + "type": "bionics_display_type", + "ident": "display_other", + "display_string": "Other" + }, + { + "type": "bionics_display_type", + "ident": "display_passive", + "display_string": "Passive" + }, + { + "type": "bionics_display_type", + "ident": "display_faulty", + "display_string": "Faulty" + } +] diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 84a163f74a39c..2821f6a0bfe8c 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -1396,13 +1396,6 @@ "name": "Toggle item as favorite", "bindings": [ { "input_method": "keyboard", "key": "*" } ] }, - { - "type": "keybinding", - "id": "TOGGLE_EXAMINE", - "category": "BIONICS", - "name": "Toggle activate/examine", - "bindings": [ { "input_method": "keyboard", "key": "!" } ] - }, { "type": "keybinding", "id": "TOGGLE_EXAMINE", @@ -2263,6 +2256,13 @@ { "input_method": "gamepad", "key": "JOY_DOWN" } ] }, + { + "type": "keybinding", + "id": "TOGGLE_EXAMINE", + "category": "BIONICS", + "name": "Display Columns Info", + "bindings": [ { "input_method": "keyboard", "key": "F1" } ] + }, { "type": "keybinding", "id": "REASSIGN", diff --git a/src/bionics.cpp b/src/bionics.cpp index 3faa1db2a1ec3..d593233b90455 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2051,7 +2051,6 @@ static bool get_bool_or_flag( JsonObject &jsobj, const std::string &name, const void load_bionic( JsonObject &jsobj ) { - bionic_data new_bionic; const bionic_id id( jsobj.get_string( "id" ) ); @@ -2131,6 +2130,10 @@ void load_bionic( JsonObject &jsobj ) new_bionic.power_activate > 0 || new_bionic.charge_time > 0; + if( !jsobj.read( "display_type", new_bionic.display_type ) ) { + new_bionic.display_type = BionicsDisplayType::infer_type( new_bionic ); + } + const auto result = bionics.insert( std::make_pair( id, new_bionic ) ); if( !result.second ) { @@ -2287,3 +2290,63 @@ void player::introduce_into_anesthesia( const time_duration &duration, player &i fall_asleep( duration ); } } + +std::vector BionicsDisplayType::displayTypes; +static const BionicsDisplayType invalid_bionics_display_type; + +BionicsDisplayType::BionicsDisplayType() : BionicsDisplayType( bionics_displayType_id::NULL_ID(), + to_translation( "invalid" ) ) +{ +} + +BionicsDisplayType::BionicsDisplayType( const bionics_displayType_id &ident, + const translation &display_string ) + : _ident( ident ), _display_string( display_string ) +{ +} + +void BionicsDisplayType::load( JsonObject &jsobj ) +{ + bionics_displayType_id ident = bionics_displayType_id( jsobj.get_string( "ident" ) ); + displayTypes.erase( std::remove_if( begin( displayTypes ), + end( displayTypes ), [&]( const BionicsDisplayType & s ) { + return s._ident == ident; + } ), end( displayTypes ) ); + + translation display_string; + jsobj.read( "display_string", display_string ); + const BionicsDisplayType sk( ident, display_string ); + displayTypes.push_back( sk ); +} + +const BionicsDisplayType &BionicsDisplayType::get_display_type( bionics_displayType_id id ) +{ + for( auto &i : displayTypes ) { + if( i._ident == id ) { + return i; + } + } + return invalid_bionics_display_type; +} + + +bionics_displayType_id BionicsDisplayType::infer_type( const bionic_data &b ) +{ + std::string type_string; + if( b.activated ) { //if value is not set manually, try to infer from other parameters + if( b.weapon_bionic || b.gun_bionic ) { + type_string = "display_weapon"; + } else if( b.power_source ) { + type_string = "display_power"; + } else { + type_string = "display_other"; + } + } else { + if( b.faulty ) { + type_string = "display_faulty"; + } else { + type_string = "display_passive"; + } + } + return bionics_displayType_id( type_string ); +} diff --git a/src/bionics.h b/src/bionics.h index 400fef1eba812..ed8651ee0c569 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -27,6 +27,8 @@ struct bionic_data { translation name; translation description; + /** Used to determine tab in the bionics menu */ + bionics_displayType_id display_type; /** Power cost on activation */ int power_activate = 0; /** Power cost on deactivation */ @@ -156,6 +158,29 @@ struct bionic { void deserialize( JsonIn &jsin ); }; +class BionicsDisplayType +{ + friend class string_id; + bionics_displayType_id _ident; + translation _display_string; + public: + static std::vector displayTypes; + static void load( JsonObject &jsobj ); + static bionics_displayType_id infer_type( const bionic_data &b ); + + static const BionicsDisplayType &get_display_type( bionics_displayType_id ); + + BionicsDisplayType(); + BionicsDisplayType( const bionics_displayType_id &ident, const translation &display_string ); + + const bionics_displayType_id &ident() const { + return _ident; + } + std::string display_string() const { + return _display_string.translated(); + } +}; + // A simpler wrapper to allow forward declarations of it. std::vector can not // be forward declared without a *definition* of bionic, but this wrapper can. class bionic_collection : public std::vector diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 5b2e2de357658..c9cb3b7d1e1f0 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -20,15 +20,118 @@ bionic_chars( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"#&()*+./:;@ namespace { -enum bionic_tab_mode { - TAB_ACTIVE, - TAB_PASSIVE +using bvector = std::vector ; + +enum bionic_columns : int { + column_status, + column_act_cost, + column_turn_cost, + column_num_entries }; -enum bionic_menu_mode { - ACTIVATING, - EXAMINING, - REASSIGNING +struct bionic_col_data { + private: + int width; + std::string name; + std::string description; + public: + bionic_col_data( int width, std::string name, std::string description ) : + width( width ), name( name ), description( description ) { + } + int get_width() { + return std::max( utf8_width( _( name ) ) + 1, width ); + } + std::string get_name() { + return _( name ); + } + std::string get_description() { + return _( description ); + } }; +bionic_col_data get_col_data( int col_idx ) +{ + static std::array< bionic_col_data, column_num_entries> col_data = { { + { + 3, translate_marker( "Status" ), + string_format( translate_marker( "CBM Status:\n\t+ - activated\n\tx - incapacitated. This CBM cannot be used for some time." ), + string_from_color( c_green ), string_from_color( c_red ) ) + }, + {8, translate_marker( "Activation" ), translate_marker( "Amount of Bionic Power required to activeate this CBM." )}, + {8, translate_marker( "Turn Cost" ), translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) } + } + }; + return col_data[col_idx]; +} + +void print_columnns( bionic *bio, bool is_selected, const catacurses::window &w, int right_bound, + int cur_print_y ) +{ + const bionic_data &bio_data = bio->id.obj(); + nc_color print_col; + + if( is_selected ) { + print_col = h_white; + } else if( bio->powered ) { + print_col = c_light_cyan; + } else { + if( bio_data.gun_bionic ) { + print_col = c_light_green; + } else { + print_col = c_dark_gray; + } + } + + + for( size_t col_idx = column_num_entries; col_idx-- > 0; ) { + std::string print_str; + switch( col_idx ) { + case column_status: { + int col_w = get_col_data( col_idx ).get_width(); + if( is_selected ) { //fill whole line with color + mvwprintz( w, point( right_bound - col_w, cur_print_y ), print_col, "%*s", col_w, "" ); + } + int pos_x = right_bound - 1; + if( bio_data.toggled && bio->powered ) { + nc_color print_col2 = is_selected ? h_green : c_green; + mvwprintz( w, point( pos_x, cur_print_y ), print_col2, "+" ); + } + --pos_x; + if( bio->incapacitated_time > 0_turns ) { + nc_color print_col2 = is_selected ? h_red : c_red; + mvwprintz( w, point( pos_x, cur_print_y ), print_col2, "x" ); + } + --pos_x; + + right_bound -= col_w; + continue; //special printing case; skip generic handling + } + break; + case column_act_cost: + if( bio_data.power_activate > 0 ) { + print_str = string_format( "%d", bio_data.power_activate ); + } + break; + case column_turn_cost: + if( bio_data.charge_time > 0 && bio_data.power_over_time > 0 ) { + print_str = bio_data.charge_time == 1 + ? string_format( _( "%d" ), bio_data.power_over_time ) + : string_format( _( "%d /%d" ), bio_data.power_over_time, + bio_data.charge_time ); + } + break; + default: + break; + } + int col_w = get_col_data( col_idx ).get_width(); + right_bound -= col_w; + mvwprintz( w, point( right_bound, cur_print_y ), print_col, "%*s", col_w, print_str ); + } + + if( is_selected ) { //fill whole line with color + mvwprintz( w, point( 0, cur_print_y ), print_col, "%*s", right_bound, "" ); + } + trim_and_print( w, point( 1, cur_print_y ), right_bound, print_col, "%c %s", bio->invlet, + bio_data.name ); +} } // namespace bionic *player::bionic_by_invlet( const int ch ) @@ -55,8 +158,7 @@ char get_free_invlet( player &p ) return ' '; } -static void draw_bionics_titlebar( const catacurses::window &window, player *p, - bionic_menu_mode mode ) +static void draw_bionics_titlebar( const catacurses::window &window, player *p ) { werase( window ); std::ostringstream fuel_stream; @@ -67,101 +169,29 @@ static void draw_bionics_titlebar( const catacurses::window &window, player *p, fuel ) << "" << "/" << p->get_total_fuel_capacity( fuel ) << " "; } } - const int pwr_str_pos = right_print( window, 0, 1, c_white, - string_format( _( "Bionic Power: %i/%i" ), - p->power_level, p->max_power_level ) ); - std::string desc; - if( mode == REASSIGNING ) { - desc = _( "Reassigning.\nSelect a bionic to reassign or press SPACE to cancel." ); - } else if( mode == ACTIVATING ) { - desc = _( "Activating ! to examine, = to reassign, TAB to switch tabs." ); - } else if( mode == EXAMINING ) { - desc = _( "Examining ! to activate, = to reassign, TAB to switch tabs." ); - } - int n_pt_y = 0; - fold_and_print( window, point( 1, n_pt_y++ ), pwr_str_pos, c_white, desc ); - fold_and_print( window, point( 1, n_pt_y++ ), pwr_str_pos, c_white, fuel_stream.str() ); + fold_and_print( window, point( 1, 0 ), getmaxx( window ), c_white, fuel_stream.str() ); wrefresh( window ); } -//builds the power usage string of a given bionic -static std::string build_bionic_poweronly_string( const bionic &bio ) -{ - const bionic_data &bio_data = bio.id.obj(); - std::vector properties; - - if( bio_data.power_activate > 0 ) { - properties.push_back( string_format( _( "%d PU act" ), bio_data.power_activate ) ); - } - if( bio_data.power_deactivate > 0 ) { - properties.push_back( string_format( _( "%d PU deact" ), bio_data.power_deactivate ) ); - } - if( bio_data.charge_time > 0 && bio_data.power_over_time > 0 ) { - properties.push_back( bio_data.charge_time == 1 - ? string_format( _( "%d PU/turn" ), bio_data.power_over_time ) - : string_format( _( "%d PU/%d turns" ), bio_data.power_over_time, - bio_data.charge_time ) ); - } - if( bio_data.toggled ) { - properties.push_back( bio.powered ? _( "ON" ) : _( "OFF" ) ); - } - if( bio.incapacitated_time > 0_turns ) { - properties.push_back( _( "(incapacitated)" ) ); - } - - return enumerate_as_string( properties, enumeration_conjunction::none ); -} - -//generates the string that show how much power a bionic uses -static std::string build_bionic_powerdesc_string( const bionic &bio ) -{ - std::ostringstream power_desc; - const std::string power_string = build_bionic_poweronly_string( bio ); - power_desc << bio.id->name; - if( !power_string.empty() ) { - power_desc << ", " << power_string; - } - return power_desc.str(); -} - -static void draw_bionics_tabs( const catacurses::window &win, const size_t active_num, - const size_t passive_num, const bionic_tab_mode current_mode ) +static void draw_bionics_tabs( const catacurses::window &win, std::vector bionics, + int current_mode ) { werase( win ); const int width = getmaxx( win ); mvwhline( win, point( 0, 2 ), LINE_OXOX, width ); - - const std::string active_tab_name = string_format( _( "ACTIVE (%i)" ), active_num ); - const std::string passive_tab_name = string_format( _( "PASSIVE (%i)" ), passive_num ); const int tab_step = 3; + std::string tab_name; int tab_x = 1; - draw_tab( win, tab_x, active_tab_name, current_mode == TAB_ACTIVE ); - tab_x += tab_step + utf8_width( active_tab_name ); - draw_tab( win, tab_x, passive_tab_name, current_mode == TAB_PASSIVE ); - - wrefresh( win ); -} - -static void draw_description( const catacurses::window &win, const bionic &bio ) -{ - werase( win ); - const int width = getmaxx( win ); - const std::string poweronly_string = build_bionic_poweronly_string( bio ); - int ypos = fold_and_print( win, point_zero, width, c_white, "%s", bio.id->name ); - if( !poweronly_string.empty() ) { - ypos += fold_and_print( win, point( 0, ypos ), width, c_light_gray, - _( "Power usage: %s" ), poweronly_string ); - } - ypos += 1 + fold_and_print( win, point( 0, ypos ), width, c_light_blue, "%s", bio.id->description ); - - // TODO: Unhide when enforcing limits - if( get_option < bool >( "CBM_SLOTS_ENABLED" ) ) { - const bool each_bp_on_new_line = ypos + static_cast( num_bp ) + 1 < getmaxy( win ); - // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores) - ypos += fold_and_print( win, point( 0, ypos ), width, c_light_gray, - list_occupied_bps( bio.id, _( "This bionic occupies the following body parts:" ), - each_bp_on_new_line ) ); + bionics_displayType_id cur_type_id = BionicsDisplayType::displayTypes[current_mode].ident(); + for( size_t i = 0; i < BionicsDisplayType::displayTypes.size(); i++ ) { + if( bionics[i].empty() ) { + continue; + } + BionicsDisplayType type = BionicsDisplayType::displayTypes[i]; + tab_name = type.display_string(); + draw_tab( win, tab_x, tab_name, cur_type_id == type.ident() ); + tab_x += tab_step + utf8_width( tab_name ); } wrefresh( win ); } @@ -169,18 +199,19 @@ static void draw_description( const catacurses::window &win, const bionic &bio ) static void draw_connectors( const catacurses::window &win, const int start_y, const int start_x, const int last_x, const bionic_id &bio_id ) { - const int LIST_START_Y = 6; + const int LIST_START_Y = 5; // first: pos_y, second: occupied slots std::vector> pos_and_num; for( const auto &elem : bio_id->occupied_bodyparts ) { pos_and_num.emplace_back( static_cast( elem.first ) + LIST_START_Y, elem.second ); } - if( pos_and_num.empty() || !get_option < bool >( "CBM_SLOTS_ENABLED" ) ) { + if( pos_and_num.empty() ) { return; } // draw horizontal line from selected bionic - const int turn_x = start_x + ( last_x - start_x ) * 2 / 3; + const int width = last_x - start_x; + const int turn_x = start_x + ( width > 20 ? width * 2 / 3 : width / 3 ); mvwputch( win, point( start_x, start_y ), BORDER_COLOR, '>' ); mvwhline( win, point( start_x + 1, start_y ), LINE_OXOX, turn_x - start_x - 1 ); @@ -246,144 +277,113 @@ static void draw_connectors( const catacurses::window &win, const int start_y, c mvwputch( win, point( turn_x, start_y ), BORDER_COLOR, bionic_chr ); } -//get a text color depending on the power/powering state of the bionic -static nc_color get_bionic_text_color( const bionic &bio, const bool isHighlightedBionic ) +void player::power_bionics() { - nc_color type = c_white; - if( bio.id->activated ) { - if( isHighlightedBionic ) { - if( bio.powered && !bio.id->power_source ) { - type = h_red; - } else if( bio.id->power_source && !bio.powered ) { - type = h_light_cyan; - } else if( bio.id->power_source && bio.powered ) { - type = h_light_green; - } else { - type = h_light_red; - } - } else { - if( bio.powered && !bio.id->power_source ) { - type = c_red; - } else if( bio.id->power_source && !bio.powered ) { - type = c_light_cyan; - } else if( bio.id->power_source && bio.powered ) { - type = c_light_green; - } else { - type = c_light_red; - } + bool with_slots = get_option < bool >( "CBM_SLOTS_ENABLED" ); + std::vector bionics_by_type( BionicsDisplayType::displayTypes.size() ); + size_t max_list_size = with_slots ? num_bp : 4; //start with min list size + int max_name_length = 0; + for( auto &b : *my_bionics ) { + int name_w = utf8_width( b.id->name.translated() ); + if( name_w > max_name_length ) { + max_name_length = name_w; } - } else { - if( isHighlightedBionic ) { - if( bio.id->power_source ) { - type = h_light_cyan; - } else { - type = h_cyan; - } - } else { - if( bio.id->power_source ) { - type = c_light_cyan; - } else { - type = c_cyan; + bionics_displayType_id dType = b.id->display_type; + for( size_t i = 0; i < BionicsDisplayType::displayTypes.size(); i++ ) { + if( BionicsDisplayType::displayTypes[i].ident() == dType ) { + bionics_by_type[i].emplace_back( &b ); + if( bionics_by_type[i].size() > max_list_size ) { + max_list_size = bionics_by_type[i].size(); + } + break; } } } - return type; -} + const int SLOTS_WIDTH = 29; -static std::vector filtered_bionics( bionic_collection &all_bionics, - bionic_tab_mode mode ) -{ - std::vector< bionic *>filtered_entries; - for( auto &elem : all_bionics ) { - if( ( mode == TAB_ACTIVE ) == elem.id->activated ) { - filtered_entries.push_back( &elem ); - } + max_name_length += 2; //invlet + size_t col_width = with_slots ? SLOTS_WIDTH : 0; + for( size_t i = 0; i < column_num_entries; i++ ) { + col_width += get_col_data( i ).get_width(); } - return filtered_entries; -} -void player::power_bionics() -{ - std::vector passive = filtered_bionics( *my_bionics, TAB_PASSIVE ); - std::vector active = filtered_bionics( *my_bionics, TAB_ACTIVE ); - bionic *bio_last = nullptr; - bionic_tab_mode tab_mode = TAB_ACTIVE; + size_t tabs_width = 1; + for( size_t i = 0; i < bionics_by_type.size(); i++ ) { + if( !bionics_by_type.empty() ) { + tabs_width += utf8_width( BionicsDisplayType::displayTypes[i].display_string() ) + 3; + } + } //added title_tab_height for the tabbed bionic display - int TITLE_HEIGHT = 2; - int TITLE_TAB_HEIGHT = 3; + const int TITLE_HEIGHT = 1; + const int TITLE_TAB_HEIGHT = 3; + const int FOOTER_HEIGHT = 5; // Main window - /** Total required height is: - * top frame line: + 1 - * height of title window: + TITLE_HEIGHT - * height of tabs: + TITLE_TAB_HEIGHT - * height of the biggest list of active/passive bionics: + bionic_count - * bottom frame line: + 1 - * TOTAL: TITLE_HEIGHT + TITLE_TAB_HEIGHT + bionic_count + 2 - */ - const int HEIGHT = std::min( TERMY, - std::max( FULL_SCREEN_HEIGHT, - TITLE_HEIGHT + TITLE_TAB_HEIGHT + - static_cast( my_bionics->size() ) + 2 ) ); - const int WIDTH = FULL_SCREEN_WIDTH + ( TERMX - FULL_SCREEN_WIDTH ) / 2; - const int START_X = ( TERMX - WIDTH ) / 2; - const int START_Y = ( TERMY - HEIGHT ) / 2; - //wBio is the entire bionic window - catacurses::window wBio = catacurses::newwin( HEIGHT, WIDTH, point( START_X, START_Y ) ); + // +3 = top + bottom + footer line + const int requested_height = TITLE_HEIGHT + TITLE_TAB_HEIGHT + FOOTER_HEIGHT + max_list_size + 3; + const int HEIGHT = std::min( TERMY, requested_height ); - const int LIST_HEIGHT = HEIGHT - TITLE_HEIGHT - TITLE_TAB_HEIGHT - 2; + int requested_width = std::max( max_name_length + col_width + 3, tabs_width ); + requested_width = std::max( requested_width, 80 ); - const int DESCRIPTION_WIDTH = WIDTH - 2 - 40; - const int DESCRIPTION_START_Y = START_Y + TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; - const int DESCRIPTION_START_X = START_X + 1 + 40; - //w_description is the description panel that is controlled with ! key - catacurses::window w_description = catacurses::newwin( LIST_HEIGHT, DESCRIPTION_WIDTH, - point( DESCRIPTION_START_X, DESCRIPTION_START_Y ) ); + const int WIDTH = std::min( requested_width, TERMX ); + const int MAIN_WINDOW_X = ( TERMX - WIDTH ) / 2; + const int MAIN_WINDOW_Y = ( TERMY - HEIGHT ) / 2; + + //wBio is the entire bionic window + catacurses::window wBio = catacurses::newwin( HEIGHT, WIDTH, point( MAIN_WINDOW_X, + MAIN_WINDOW_Y ) ); // Title window - const int TITLE_START_Y = START_Y + 1; - const int HEADER_LINE_Y = TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; - catacurses::window w_title = catacurses::newwin( TITLE_HEIGHT, WIDTH - 2, point( START_X + 1, - TITLE_START_Y ) ); + const int TITLE_WINDOW_Y = MAIN_WINDOW_Y + 1; + catacurses::window w_title = catacurses::newwin( TITLE_HEIGHT, WIDTH - 2, point( MAIN_WINDOW_X + 1, + TITLE_WINDOW_Y ) ); + + //Tabs bar + const int TAB_WINDOW_Y = TITLE_WINDOW_Y + TITLE_HEIGHT; + catacurses::window w_tabs = catacurses::newwin( TITLE_TAB_HEIGHT, WIDTH - 2, + point( MAIN_WINDOW_X + 1, + TAB_WINDOW_Y ) ); - const int TAB_START_Y = TITLE_START_Y + 2; - //w_tabs is the tab bar for passive and active bionic groups - catacurses::window w_tabs = catacurses::newwin( TITLE_TAB_HEIGHT, WIDTH - 2, point( START_X + 1, - TAB_START_Y ) ); + const int header_line_y = TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; + const int footer_start_y = HEIGHT - FOOTER_HEIGHT - 1; + + const int col_right_bound = WIDTH - ( with_slots ? SLOTS_WIDTH : 3 ); int scroll_position = 0; int cursor = 0; + int cur_tab_idx = 0; - //generate the tab title string and a count of the bionics owned - bionic_menu_mode menu_mode = ACTIVATING; - // offset for display: bionic with index i is drawn at y=list_start_y+i - // drawing the bionics starts with bionic[scroll_position] - // scroll_position; - const int list_start_y = HEADER_LINE_Y; + const int list_start_y = header_line_y + 1; + const int LIST_HEIGHT = footer_start_y - list_start_y - 1; //-1 is footer separator int half_list_view_location = LIST_HEIGHT / 2; - int max_scroll_position = std::max( 0, static_cast( active.size() ) ); + int max_scroll_position = std::max( 0, static_cast( bionics_by_type[0].size() ) ); input_context ctxt( "BIONICS" ); ctxt.register_updown(); ctxt.register_action( "ANY_INPUT" ); - ctxt.register_action( "TOGGLE_EXAMINE" ); ctxt.register_action( "REASSIGN" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "HELP_KEYBINDINGS" ); + ctxt.register_action( "USAGE_HELP" ); bool recalc = false; bool redraw = true; for( ;; ) { if( recalc ) { - passive = filtered_bionics( *my_bionics, TAB_PASSIVE ); - active = filtered_bionics( *my_bionics, TAB_ACTIVE ); - - if( active.empty() && !passive.empty() ) { - tab_mode = TAB_PASSIVE; + bionics_by_type.clear(); + for( auto b : *my_bionics ) { + bionics_displayType_id dType = b.id->display_type; + for( size_t i = 0; i < BionicsDisplayType::displayTypes.size(); i++ ) { + if( BionicsDisplayType::displayTypes[i].ident() == dType ) { + bionics_by_type[i].emplace_back( &b ); + break; + } + } } if( --cursor < 0 ) { @@ -400,17 +400,39 @@ void player::power_bionics() } //track which list we are looking at - std::vector *current_bionic_list = ( tab_mode == TAB_ACTIVE ? &active : &passive ); - max_scroll_position = std::max( 0, static_cast( current_bionic_list->size() ) - LIST_HEIGHT ); + const bvector ¤t_bionic_list = bionics_by_type[cur_tab_idx]; + max_scroll_position = std::max( 0, static_cast( current_bionic_list.size() ) - LIST_HEIGHT ); if( redraw ) { redraw = false; werase( wBio ); - draw_border( wBio, BORDER_COLOR, _( " BIONICS " ) ); + draw_border( wBio, BORDER_COLOR ); + nc_color col = c_white; + print_colored_text( wBio, point( 1, 0 ), col, col, + string_format( _( "< Bionic Power: %i/%i >" ), + power_level, max_power_level ) ); + std::string help_str = string_format( _( "< [%s] Columns Info >" ), ctxt.get_desc( "USAGE_HELP" ) ); + mvwprintz( wBio, point( WIDTH - 1 - utf8_width( help_str ), 0 ), c_white, help_str ); + // Draw symbols to connect additional lines to border - mvwputch( wBio, point( 0, HEADER_LINE_Y - 1 ), BORDER_COLOR, LINE_XXXO ); // |- - mvwputch( wBio, point( WIDTH - 1, HEADER_LINE_Y - 1 ), BORDER_COLOR, LINE_XOXX ); // -| + mvwputch( wBio, point( 0, header_line_y - 1 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( wBio, point( WIDTH - 1, header_line_y - 1 ), BORDER_COLOR, LINE_XOXX ); // -| + + mvwputch( wBio, point( 0, footer_start_y - 1 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( wBio, point( WIDTH - 1, footer_start_y - 1 ), BORDER_COLOR, LINE_XOXX ); // -| + mvwhline( wBio, point( 1, footer_start_y - 1 ), LINE_OXOX, WIDTH - 2 ); + help_str = string_format( _( "" ), + ctxt.get_desc( "REASSIGN" ) ); + mvwprintz( wBio, point( 2, footer_start_y - 1 ), c_white, help_str ); + + for( size_t col_idx = column_num_entries, right_bound = col_right_bound; col_idx-- > 0; ) { + bionic_col_data col_data = get_col_data( col_idx ); + int col_w = col_data.get_width(); + right_bound -= col_w; + mvwprintz( wBio, point( right_bound, header_line_y ), c_light_gray, "%*s", col_w, + col_data.get_name() ); + } int max_width = 0; std::vectorbps; @@ -423,77 +445,68 @@ void player::power_bionics() max_width = std::max( max_width, utf8_width( s ) ); } const int pos_x = WIDTH - 2 - max_width; - if( get_option < bool >( "CBM_SLOTS_ENABLED" ) ) { + if( with_slots ) { for( size_t i = 0; i < bps.size(); ++i ) { - mvwprintz( wBio, point( pos_x, i + list_start_y ), c_light_gray, bps[i] ); + mvwprintz( wBio, point( pos_x, i + list_start_y - 1 ), c_light_gray, bps[i] ); } } - if( current_bionic_list->empty() ) { - std::string msg; - switch( tab_mode ) { - case TAB_ACTIVE: - msg = _( "No activatable bionics installed." ); - break; - case TAB_PASSIVE: - msg = _( "No passive bionics installed." ); - break; - } - fold_and_print( wBio, point( 2, list_start_y ), pos_x - 1, c_light_gray, msg ); + if( current_bionic_list.empty() ) { + fold_and_print( wBio, point( 2, list_start_y ), pos_x - 1, c_light_gray, + _( "No bionics installed." ) ); } else { - for( size_t i = scroll_position; i < current_bionic_list->size(); i++ ) { - if( list_start_y + static_cast( i ) - scroll_position == HEIGHT - 1 ) { + for( size_t i = scroll_position; i < current_bionic_list.size(); i++ ) { + if( static_cast( i ) - scroll_position == LIST_HEIGHT ) { break; } const bool is_highlighted = cursor == static_cast( i ); - const nc_color col = get_bionic_text_color( *( *current_bionic_list )[i], - is_highlighted ); - const std::string desc = string_format( "%c %s", ( *current_bionic_list )[i]->invlet, - build_bionic_powerdesc_string( - *( *current_bionic_list )[i] ).c_str() ); - trim_and_print( wBio, point( 2, list_start_y + i - scroll_position ), WIDTH - 3, col, - desc ); - if( is_highlighted && menu_mode != EXAMINING && get_option < bool >( "CBM_SLOTS_ENABLED" ) ) { - const bionic_id bio_id = ( *current_bionic_list )[i]->id; - draw_connectors( wBio, list_start_y + i - scroll_position, utf8_width( desc ) + 3, + int y_pos = list_start_y + i - scroll_position; + print_columnns( current_bionic_list[i], is_highlighted, wBio, col_right_bound, y_pos ); + if( is_highlighted && with_slots ) { + const bionic_id bio_id = current_bionic_list[i]->id; + draw_connectors( wBio, y_pos, col_right_bound, pos_x - 2, bio_id ); + add_msg_if_player( "++ %d %d", col_right_bound, pos_x - 2 ); + // redraw highlighted (occupied) body parts for( auto &elem : bio_id->occupied_bodyparts ) { const int i = static_cast( elem.first ); - mvwprintz( wBio, point( pos_x, i + list_start_y ), c_yellow, bps[i] ); + mvwprintz( wBio, point( pos_x, i + list_start_y - 1 ), c_yellow, bps[i] ); } } } } - draw_scrollbar( wBio, cursor, LIST_HEIGHT, current_bionic_list->size(), point( 0, list_start_y ) ); + draw_scrollbar( wBio, cursor, LIST_HEIGHT, current_bionic_list.size(), point( 0, list_start_y ) ); + + if( current_bionic_list[cursor] != nullptr ) { + fold_and_print( wBio, point( 1, footer_start_y ), WIDTH - 2, c_light_blue, "%s", + current_bionic_list[cursor]->id->description ); + } #if defined(__ANDROID__) ctxt.get_registered_manual_keys().clear(); - for( size_t i = 0; i < current_bionic_list->size(); i++ ) { - ctxt.register_manual_key( ( *current_bionic_list )[i]->invlet, - build_bionic_powerdesc_string( *( *current_bionic_list )[i] ).c_str() ); + for( size_t i = 0; i < current_bionic_list.size(); i++ ) { + ctxt.register_manual_key( current_bionic_list[i]->invlet, + build_bionic_powerdesc_string( *current_bionic_list[i] ).c_str() ); } #endif } wrefresh( wBio ); - draw_bionics_tabs( w_tabs, active.size(), passive.size(), tab_mode ); - draw_bionics_titlebar( w_title, this, menu_mode ); - if( menu_mode == EXAMINING && !current_bionic_list->empty() ) { - draw_description( w_description, *( *current_bionic_list )[cursor] ); - } + draw_bionics_tabs( w_tabs, bionics_by_type, cur_tab_idx ); + draw_bionics_titlebar( w_title, this ); const std::string action = ctxt.handle_input(); const int ch = ctxt.get_raw_input().get_first_input(); bionic *tmp = nullptr; - bool confirmCheck = false; + bool need_activate = false; if( action == "DOWN" ) { redraw = true; - if( static_cast( cursor ) < current_bionic_list->size() - 1 ) { + if( static_cast( cursor ) < current_bionic_list.size() - 1 ) { cursor++; } else { cursor = 0; @@ -510,7 +523,7 @@ void player::power_bionics() if( cursor > 0 ) { cursor--; } else { - cursor = current_bionic_list->size() - 1; + cursor = current_bionic_list.size() - 1; } if( scroll_position > 0 && cursor - scroll_position < half_list_view_location ) { scroll_position--; @@ -518,167 +531,123 @@ void player::power_bionics() if( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position = - std::max( std::min( current_bionic_list->size() - LIST_HEIGHT, + std::max( std::min( current_bionic_list.size() - LIST_HEIGHT, cursor - half_list_view_location ), 0 ); } - } else if( menu_mode == REASSIGNING ) { - menu_mode = ACTIVATING; - - if( action == "CONFIRM" && !current_bionic_list->empty() ) { - auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; - tmp = bio_list[cursor]; - } else { - tmp = bionic_by_invlet( ch ); - } - - if( tmp == nullptr ) { - // Selected an non-existing bionic (or Escape, or ...) - continue; + } else if( action == "REASSIGN" ) { + tmp = current_bionic_list[cursor]; + while( true ) { + const int invlet = popup_getkey( + _( "%s\n\nEnter new letter. Press SPACE to clear a manually assigned letter, ESCAPE to cancel." ), + bionic_chars.get_allowed_chars() ); + + if( invlet == KEY_ESCAPE ) { + break; + } else if( invlet == ' ' ) { + tmp->invlet = invlet; + break; + } else if( bionic_chars.valid( invlet ) ) { + bionic *otmp = bionic_by_invlet( invlet ); + std::swap( tmp->invlet, otmp->invlet ); + break; + } } redraw = true; - const int newch = popup_getkey( _( "%s; enter new letter. Space to clear. Esc to cancel." ), - tmp->id->name ); - wrefresh( wBio ); - if( newch == ch || newch == KEY_ESCAPE ) { - continue; - } - if( newch == ' ' ) { - tmp->invlet = ' '; - continue; - } - if( !bionic_chars.valid( newch ) ) { - popup( _( "Invalid bionic letter. Only those characters are valid:\n\n%s" ), - bionic_chars.get_allowed_chars() ); - continue; - } - bionic *otmp = bionic_by_invlet( newch ); - if( otmp != nullptr ) { - std::swap( tmp->invlet, otmp->invlet ); - } else { - tmp->invlet = newch; - } - // TODO: show a message like when reassigning a key to an item? } else if( action == "NEXT_TAB" ) { redraw = true; scroll_position = 0; cursor = 0; - if( tab_mode == TAB_ACTIVE ) { - tab_mode = TAB_PASSIVE; - } else { - tab_mode = TAB_ACTIVE; + if( !current_bionic_list.empty() ) { + do { + cur_tab_idx = ( cur_tab_idx + 1 ) % BionicsDisplayType::displayTypes.size(); + } while( bionics_by_type[cur_tab_idx].empty() ); } } else if( action == "PREV_TAB" ) { redraw = true; scroll_position = 0; cursor = 0; - if( tab_mode == TAB_PASSIVE ) { - tab_mode = TAB_ACTIVE; - } else { - tab_mode = TAB_PASSIVE; + if( !current_bionic_list.empty() ) { + do { + if( --cur_tab_idx < 0 ) { + cur_tab_idx = BionicsDisplayType::displayTypes.size() - 1; + } + } while( bionics_by_type[cur_tab_idx].empty() ); } - } else if( action == "REASSIGN" ) { - menu_mode = REASSIGNING; - } else if( action == "TOGGLE_EXAMINE" ) { // switches between activation and examination - menu_mode = menu_mode == ACTIVATING ? EXAMINING : ACTIVATING; - redraw = true; } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; } else if( action == "CONFIRM" ) { - confirmCheck = true; + tmp = current_bionic_list[cursor]; + need_activate = true; + } else if( action == "USAGE_HELP" ) { + std::string help_str; + for( size_t i = 0; i < column_num_entries; i++ ) { + bionic_col_data col_data = get_col_data( i ); + help_str += colorize( col_data.get_name(), c_white ); + help_str += " - "; + help_str += colorize( col_data.get_description(), c_light_gray ); + help_str += "\n"; + } + popup( help_str ); + redraw = true; } else { - confirmCheck = true; - } - //confirmation either occurred by pressing enter where the bionic cursor is, or the hotkey was selected - if( confirmCheck ) { - auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; - if( action == "CONFIRM" && !current_bionic_list->empty() ) { - tmp = bio_list[cursor]; - } else { - tmp = bionic_by_invlet( ch ); - if( tmp && tmp != bio_last ) { - // new bionic selected, update cursor and scroll position - int temp_cursor = 0; - for( temp_cursor = 0; temp_cursor < static_cast( bio_list.size() ); temp_cursor++ ) { - if( bio_list[temp_cursor] == tmp ) { + if( ch == ' ' || ch == KEY_ESCAPE ) { + break; + } + tmp = bionic_by_invlet( ch ); + + //jump to bionic + if( tmp != nullptr ) { + bool is_found = false; + for( size_t i = 0; i < bionics_by_type.size(); i++ ) { + const bvector &cur_list = bionics_by_type[i]; + cur_tab_idx = i; + for( size_t j = 0; j < cur_list.size(); j++ ) { + if( cur_list[j] == tmp ) { + cursor = j; + scroll_position = 0; + while( scroll_position < max_scroll_position && + cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { + scroll_position++; + } + is_found = true; break; } } - // if bionic is not found in current list, ignore the attempt to view/activate - if( temp_cursor >= static_cast( bio_list.size() ) ) { - continue; - } - //relocate cursor to the bionic that was found - cursor = temp_cursor; - scroll_position = 0; - while( scroll_position < max_scroll_position && - cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { - scroll_position++; + if( is_found ) { + break; } } } - if( !tmp ) { - // entered a key that is not mapped to any bionic, - // -> leave screen - break; - } - bio_last = tmp; + need_activate = true; + redraw = true; + } + if( tmp == nullptr ) { + //Do nothing + } else if( need_activate ) { const bionic_id &bio_id = tmp->id; const bionic_data &bio_data = bio_id.obj(); - if( menu_mode == ACTIVATING ) { - if( bio_data.activated ) { - int b = tmp - &( *my_bionics )[0]; - if( tmp->powered ) { - deactivate_bionic( b ); - } else { - activate_bionic( b ); - // Clear the menu if we are firing a bionic gun - if( tmp->info().gun_bionic || tmp->ammo_count > 0 ) { - break; - } + if( bio_data.activated ) { + int bionic_idx = tmp - &( *my_bionics )[0]; + if( tmp->powered ) { + deactivate_bionic( bionic_idx ); + } else { + activate_bionic( bionic_idx ); + if( !bio_data.toggled ) { + popup( "You activate your %s.", bio_data.name ); } - // update message log and the menu - g->refresh_all(); - redraw = true; - if( moves < 0 ) { - return; + // Clear the menu if we are firing a bionic gun + if( tmp->info().gun_bionic || tmp->ammo_count > 0 ) { + break; } - continue; - } else { - popup( _( "You can not activate %s!\n" - "To read a description of %s, press '!', then '%c'." ), bio_data.name, - bio_data.name, tmp->invlet ); - redraw = true; } - } else if( menu_mode == EXAMINING ) { // Describing bionics, allow user to jump to description key + // update message log and the menu + g->refresh_all(); redraw = true; - if( action != "CONFIRM" ) { - for( size_t i = 0; i < active.size(); i++ ) { - if( active[i] == tmp ) { - tab_mode = TAB_ACTIVE; - cursor = static_cast( i ); - int max_scroll_check = std::max( 0, static_cast( active.size() ) - LIST_HEIGHT ); - if( static_cast( i ) > max_scroll_check ) { - scroll_position = max_scroll_check; - } else { - scroll_position = i; - } - break; - } - } - for( size_t i = 0; i < passive.size(); i++ ) { - if( passive[i] == tmp ) { - tab_mode = TAB_PASSIVE; - cursor = static_cast( i ); - int max_scroll_check = std::max( 0, static_cast( passive.size() ) - LIST_HEIGHT ); - if( static_cast( i ) > max_scroll_check ) { - scroll_position = max_scroll_check; - } else { - scroll_position = i; - } - break; - } - } + if( moves < 0 ) { + return; } + } else { + popup( _( "You can not activate %s." ), bio_data.name ); } } } diff --git a/src/init.cpp b/src/init.cpp index 5736edd91993e..b33d7ac57bac4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -195,6 +195,7 @@ void DynamicDataLoader::initialize() add( "profession_item_substitutions", &profession::load_item_substitutions ); add( "skill", &Skill::load_skill ); add( "skill_display_type", &SkillDisplayType::load ); + add( "bionics_display_type", &BionicsDisplayType::load ); add( "dream", &dream::load ); add( "mutation_category", &mutation_category_trait::load ); add( "mutation_type", &load_mutation_type ); diff --git a/src/string_id_null_ids.cpp b/src/string_id_null_ids.cpp index e81d2ccd79687..aca47c528ef80 100644 --- a/src/string_id_null_ids.cpp +++ b/src/string_id_null_ids.cpp @@ -21,6 +21,7 @@ MAKE_NULL_ID( overmap_connection, "", 0 ) MAKE_NULL_ID( map_extra, "", 0 ) MAKE_NULL_ID( Skill, "none" ) MAKE_NULL_ID( SkillDisplayType, "none" ) +MAKE_NULL_ID( BionicsDisplayType, "none" ) MAKE_NULL_ID( npc_class, "NC_NONE" ) MAKE_NULL_ID( ammunition_type, "NULL" ) MAKE_NULL_ID( vpart_info, "null" ) diff --git a/src/type_id.h b/src/type_id.h index 8f7faab63eb60..ef4a7649ea1dc 100644 --- a/src/type_id.h +++ b/src/type_id.h @@ -93,6 +93,9 @@ using skill_id = string_id; class SkillDisplayType; using skill_displayType_id = string_id; +class BionicsDisplayType; +using bionics_displayType_id = string_id; + struct species_type; using species_id = string_id; From 3996f384290cefb5154d67e58aae85c1719e0337 Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 16 Sep 2019 00:43:06 -0400 Subject: [PATCH 002/219] fixing crash when no bionics installed --- src/bionics_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index c9cb3b7d1e1f0..f9f8be52b3a28 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -481,7 +481,7 @@ void player::power_bionics() draw_scrollbar( wBio, cursor, LIST_HEIGHT, current_bionic_list.size(), point( 0, list_start_y ) ); - if( current_bionic_list[cursor] != nullptr ) { + if( !current_bionic_list.empty() && current_bionic_list[cursor] != nullptr ) { fold_and_print( wBio, point( 1, footer_start_y ), WIDTH - 2, c_light_blue, "%s", current_bionic_list[cursor]->id->description ); } From 1fa9730773c93e972bb2e9a6449c4e5540712076 Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 16 Sep 2019 01:51:17 -0400 Subject: [PATCH 003/219] removing androind bindings travis --- src/bionics_ui.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index f9f8be52b3a28..4d47ecd6fb09f 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -169,7 +169,7 @@ static void draw_bionics_titlebar( const catacurses::window &window, player *p ) fuel ) << "" << "/" << p->get_total_fuel_capacity( fuel ) << " "; } } - fold_and_print( window, point( 1, 0 ), getmaxx( window ), c_white, fuel_stream.str() ); + fold_and_print( window, point_east, getmaxx( window ), c_white, fuel_stream.str() ); wrefresh( window ); } @@ -409,7 +409,7 @@ void player::power_bionics() werase( wBio ); draw_border( wBio, BORDER_COLOR ); nc_color col = c_white; - print_colored_text( wBio, point( 1, 0 ), col, col, + print_colored_text( wBio, point_east, col, col, string_format( _( "< Bionic Power: %i/%i >" ), power_level, max_power_level ) ); std::string help_str = string_format( _( "< [%s] Columns Info >" ), ctxt.get_desc( "USAGE_HELP" ) ); @@ -485,15 +485,6 @@ void player::power_bionics() fold_and_print( wBio, point( 1, footer_start_y ), WIDTH - 2, c_light_blue, "%s", current_bionic_list[cursor]->id->description ); } - -#if defined(__ANDROID__) - ctxt.get_registered_manual_keys().clear(); - for( size_t i = 0; i < current_bionic_list.size(); i++ ) { - ctxt.register_manual_key( current_bionic_list[i]->invlet, - build_bionic_powerdesc_string( *current_bionic_list[i] ).c_str() ); - } -#endif - } wrefresh( wBio ); draw_bionics_tabs( w_tabs, bionics_by_type, cur_tab_idx ); From b0b7d2493d8708a3c4e6e3fce0b013888d331ac6 Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 16 Sep 2019 20:45:14 -0400 Subject: [PATCH 004/219] fixes from BevapDin Also added reset for SkillDisplayType --- src/bionics.cpp | 7 +++++-- src/bionics.h | 1 + src/bionics_ui.cpp | 17 +++++++++-------- src/init.cpp | 2 ++ src/skill.cpp | 7 +++++-- src/skill.h | 1 + 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/bionics.cpp b/src/bionics.cpp index d593233b90455..9acaebfb2879e 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2315,8 +2315,11 @@ void BionicsDisplayType::load( JsonObject &jsobj ) translation display_string; jsobj.read( "display_string", display_string ); - const BionicsDisplayType sk( ident, display_string ); - displayTypes.push_back( sk ); + displayTypes.emplace_back( ident, display_string ); +} +void BionicsDisplayType::reset() +{ + displayTypes.clear(); } const BionicsDisplayType &BionicsDisplayType::get_display_type( bionics_displayType_id id ) diff --git a/src/bionics.h b/src/bionics.h index ed8651ee0c569..ff6392a896b3a 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -166,6 +166,7 @@ class BionicsDisplayType public: static std::vector displayTypes; static void load( JsonObject &jsobj ); + static void reset(); static bionics_displayType_id infer_type( const bionic_data &b ); static const BionicsDisplayType &get_display_type( bionics_displayType_id ); diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 4d47ecd6fb09f..63a7bddefce1d 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -52,8 +52,7 @@ bionic_col_data get_col_data( int col_idx ) static std::array< bionic_col_data, column_num_entries> col_data = { { { 3, translate_marker( "Status" ), - string_format( translate_marker( "CBM Status:\n\t+ - activated\n\tx - incapacitated. This CBM cannot be used for some time." ), - string_from_color( c_green ), string_from_color( c_red ) ) + string_format( translate_marker( "CBM Status:\n\t+ - activated\n\tx - incapacitated. This CBM cannot be used for some time." ) ) }, {8, translate_marker( "Activation" ), translate_marker( "Amount of Bionic Power required to activeate this CBM." )}, {8, translate_marker( "Turn Cost" ), translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) } @@ -376,7 +375,7 @@ void player::power_bionics() for( ;; ) { if( recalc ) { bionics_by_type.clear(); - for( auto b : *my_bionics ) { + for( auto &b : *my_bionics ) { bionics_displayType_id dType = b.id->display_type; for( size_t i = 0; i < BionicsDisplayType::displayTypes.size(); i++ ) { if( BionicsDisplayType::displayTypes[i].ident() == dType ) { @@ -467,8 +466,6 @@ void player::power_bionics() draw_connectors( wBio, y_pos, col_right_bound, pos_x - 2, bio_id ); - add_msg_if_player( "++ %d %d", col_right_bound, pos_x - 2 ); - // redraw highlighted (occupied) body parts for( auto &elem : bio_id->occupied_bodyparts ) { const int i = static_cast( elem.first ); @@ -539,7 +536,11 @@ void player::power_bionics() break; } else if( bionic_chars.valid( invlet ) ) { bionic *otmp = bionic_by_invlet( invlet ); - std::swap( tmp->invlet, otmp->invlet ); + if( otmp ) { + std::swap( tmp->invlet, otmp->invlet ); + } else { + tmp->invlet = invlet; + } break; } } @@ -623,8 +624,8 @@ void player::power_bionics() deactivate_bionic( bionic_idx ); } else { activate_bionic( bionic_idx ); - if( !bio_data.toggled ) { - popup( "You activate your %s.", bio_data.name ); + if( !bio_data.toggled && !bio_data.gun_bionic ) { + popup( _( "You activate your %s." ), bio_data.name ); } // Clear the menu if we are firing a bionic gun if( tmp->info().gun_bionic || tmp->ammo_count > 0 ) { diff --git a/src/init.cpp b/src/init.cpp index b33d7ac57bac4..bf7ee5ddaeb17 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -468,6 +468,8 @@ void DynamicDataLoader::unload_data() materials::reset(); profession::reset(); Skill::reset(); + SkillDisplayType::reset(); + BionicsDisplayType::reset(); dreams.clear(); // clear techniques, martial arts, and ma buffs clear_techniques_and_martial_arts(); diff --git a/src/skill.cpp b/src/skill.cpp index 2370f4cb56d22..90dc622c8a911 100644 --- a/src/skill.cpp +++ b/src/skill.cpp @@ -127,10 +127,13 @@ void SkillDisplayType::load( JsonObject &jsobj ) translation display_string; jsobj.read( "display_string", display_string ); - const SkillDisplayType sk( ident, display_string ); - skillTypes.push_back( sk ); + skillTypes.emplace_back( ident, display_string ); } +void SkillDisplayType::reset() +{ + skillTypes.clear(); +} const SkillDisplayType &SkillDisplayType::get_skill_type( skill_displayType_id id ) { diff --git a/src/skill.h b/src/skill.h index 71a6771034ae2..b014d8ae7a166 100644 --- a/src/skill.h +++ b/src/skill.h @@ -202,6 +202,7 @@ class SkillDisplayType public: static std::vector skillTypes; static void load( JsonObject &jsobj ); + static void reset( ); static const SkillDisplayType &get_skill_type( skill_displayType_id ); From e54612f600a35d9016c9697e71886629199bfa5d Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 17 Sep 2019 23:21:50 -0400 Subject: [PATCH 005/219] fixes from AMurkin --- data/json/bionicsDisplayType.json | 6 +- src/bionics.cpp | 20 ++---- src/bionics.h | 9 ++- src/bionics_ui.cpp | 109 ++++++++++++++++-------------- 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/data/json/bionicsDisplayType.json b/data/json/bionicsDisplayType.json index c9bf58ca7efc4..98e43cf3bb6d1 100644 --- a/data/json/bionicsDisplayType.json +++ b/data/json/bionicsDisplayType.json @@ -27,11 +27,13 @@ { "type": "bionics_display_type", "ident": "display_passive", - "display_string": "Passive" + "display_string": "Passive", + "hide_columns": true }, { "type": "bionics_display_type", "ident": "display_faulty", - "display_string": "Faulty" + "display_string": "Faulty", + "hide_columns": true } ] diff --git a/src/bionics.cpp b/src/bionics.cpp index 9acaebfb2879e..87ca68243945a 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2295,13 +2295,13 @@ std::vector BionicsDisplayType::displayTypes; static const BionicsDisplayType invalid_bionics_display_type; BionicsDisplayType::BionicsDisplayType() : BionicsDisplayType( bionics_displayType_id::NULL_ID(), - to_translation( "invalid" ) ) + to_translation( "invalid" ), false ) { } BionicsDisplayType::BionicsDisplayType( const bionics_displayType_id &ident, - const translation &display_string ) - : _ident( ident ), _display_string( display_string ) + const translation &display_string, bool hide_columns ) + : _ident( ident ), _display_string( display_string ), _hide_columns( hide_columns ) { } @@ -2315,24 +2315,14 @@ void BionicsDisplayType::load( JsonObject &jsobj ) translation display_string; jsobj.read( "display_string", display_string ); - displayTypes.emplace_back( ident, display_string ); + bool hide_col = jsobj.get_bool( "hide_columns", false ); + displayTypes.emplace_back( ident, display_string, hide_col ); } void BionicsDisplayType::reset() { displayTypes.clear(); } -const BionicsDisplayType &BionicsDisplayType::get_display_type( bionics_displayType_id id ) -{ - for( auto &i : displayTypes ) { - if( i._ident == id ) { - return i; - } - } - return invalid_bionics_display_type; -} - - bionics_displayType_id BionicsDisplayType::infer_type( const bionic_data &b ) { std::string type_string; diff --git a/src/bionics.h b/src/bionics.h index ff6392a896b3a..37b5af5be7ece 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -163,16 +163,16 @@ class BionicsDisplayType friend class string_id; bionics_displayType_id _ident; translation _display_string; + bool _hide_columns; public: static std::vector displayTypes; static void load( JsonObject &jsobj ); static void reset(); static bionics_displayType_id infer_type( const bionic_data &b ); - static const BionicsDisplayType &get_display_type( bionics_displayType_id ); - BionicsDisplayType(); - BionicsDisplayType( const bionics_displayType_id &ident, const translation &display_string ); + BionicsDisplayType( const bionics_displayType_id &ident, const translation &display_string, + bool hide_columns ); const bionics_displayType_id &ident() const { return _ident; @@ -180,6 +180,9 @@ class BionicsDisplayType std::string display_string() const { return _display_string.translated(); } + bool is_hide_columns() { + return _hide_columns; + } }; // 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 63a7bddefce1d..d0dabad0cc498 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -52,16 +52,17 @@ bionic_col_data get_col_data( int col_idx ) static std::array< bionic_col_data, column_num_entries> col_data = { { { 3, translate_marker( "Status" ), - string_format( translate_marker( "CBM Status:\n\t+ - activated\n\tx - incapacitated. This CBM cannot be used for some time." ) ) + translate_marker( "CBM Status:\n\t+ - activated\n\tx - incapacitated. This CBM cannot be used for some time." ) }, {8, translate_marker( "Activation" ), translate_marker( "Amount of Bionic Power required to activeate this CBM." )}, - {8, translate_marker( "Turn Cost" ), translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) } + {8, translate_marker( "Turn Cost" ), translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) } } }; return col_data[col_idx]; } -void print_columnns( bionic *bio, bool is_selected, const catacurses::window &w, int right_bound, +void print_columnns( bionic *bio, bool is_selected, bool name_only, const catacurses::window &w, + int right_bound, int cur_print_y ) { const bionic_data &bio_data = bio->id.obj(); @@ -79,50 +80,51 @@ void print_columnns( bionic *bio, bool is_selected, const catacurses::window &w, } } + if( !name_only ) { + for( size_t col_idx = column_num_entries; col_idx-- > 0; ) { + std::string print_str; + switch( col_idx ) { + case column_status: { + int col_w = get_col_data( col_idx ).get_width(); + if( is_selected ) { //fill whole line with color + mvwprintz( w, point( right_bound - col_w, cur_print_y ), print_col, "%*s", col_w, "" ); + } + int pos_x = right_bound - 1; + if( bio_data.toggled && bio->powered ) { + nc_color print_col2 = is_selected ? h_green : c_green; + mvwprintz( w, point( pos_x, cur_print_y ), print_col2, "+" ); + } + --pos_x; + if( bio->incapacitated_time > 0_turns ) { + nc_color print_col2 = is_selected ? h_red : c_red; + mvwprintz( w, point( pos_x, cur_print_y ), print_col2, "x" ); + } + --pos_x; - for( size_t col_idx = column_num_entries; col_idx-- > 0; ) { - std::string print_str; - switch( col_idx ) { - case column_status: { - int col_w = get_col_data( col_idx ).get_width(); - if( is_selected ) { //fill whole line with color - mvwprintz( w, point( right_bound - col_w, cur_print_y ), print_col, "%*s", col_w, "" ); - } - int pos_x = right_bound - 1; - if( bio_data.toggled && bio->powered ) { - nc_color print_col2 = is_selected ? h_green : c_green; - mvwprintz( w, point( pos_x, cur_print_y ), print_col2, "+" ); - } - --pos_x; - if( bio->incapacitated_time > 0_turns ) { - nc_color print_col2 = is_selected ? h_red : c_red; - mvwprintz( w, point( pos_x, cur_print_y ), print_col2, "x" ); - } - --pos_x; - - right_bound -= col_w; - continue; //special printing case; skip generic handling - } - break; - case column_act_cost: - if( bio_data.power_activate > 0 ) { - print_str = string_format( "%d", bio_data.power_activate ); - } - break; - case column_turn_cost: - if( bio_data.charge_time > 0 && bio_data.power_over_time > 0 ) { - print_str = bio_data.charge_time == 1 - ? string_format( _( "%d" ), bio_data.power_over_time ) - : string_format( _( "%d /%d" ), bio_data.power_over_time, - bio_data.charge_time ); + right_bound -= col_w; + continue; //special printing case; skip generic handling } break; - default: - break; + case column_act_cost: + if( bio_data.power_activate > 0 ) { + print_str = string_format( "%d", bio_data.power_activate ); + } + break; + case column_turn_cost: + if( bio_data.charge_time > 0 && bio_data.power_over_time > 0 ) { + print_str = bio_data.charge_time == 1 + ? string_format( "%d", bio_data.power_over_time ) + : string_format( "%d /%d", bio_data.power_over_time, + bio_data.charge_time ); + } + break; + default: + break; + } + int col_w = get_col_data( col_idx ).get_width(); + right_bound -= col_w; + mvwprintz( w, point( right_bound, cur_print_y ), print_col, "%*s", col_w, print_str ); } - int col_w = get_col_data( col_idx ).get_width(); - right_bound -= col_w; - mvwprintz( w, point( right_bound, cur_print_y ), print_col, "%*s", col_w, print_str ); } if( is_selected ) { //fill whole line with color @@ -421,16 +423,19 @@ void player::power_bionics() mvwputch( wBio, point( 0, footer_start_y - 1 ), BORDER_COLOR, LINE_XXXO ); // |- mvwputch( wBio, point( WIDTH - 1, footer_start_y - 1 ), BORDER_COLOR, LINE_XOXX ); // -| mvwhline( wBio, point( 1, footer_start_y - 1 ), LINE_OXOX, WIDTH - 2 ); - help_str = string_format( _( "" ), + help_str = string_format( _( "" ), ctxt.get_desc( "REASSIGN" ) ); mvwprintz( wBio, point( 2, footer_start_y - 1 ), c_white, help_str ); - for( size_t col_idx = column_num_entries, right_bound = col_right_bound; col_idx-- > 0; ) { - bionic_col_data col_data = get_col_data( col_idx ); - int col_w = col_data.get_width(); - right_bound -= col_w; - mvwprintz( wBio, point( right_bound, header_line_y ), c_light_gray, "%*s", col_w, - col_data.get_name() ); + const bool name_only = BionicsDisplayType::displayTypes[cur_tab_idx].is_hide_columns(); + if( !name_only ) { + for( size_t col_idx = column_num_entries, right_bound = col_right_bound; col_idx-- > 0; ) { + bionic_col_data col_data = get_col_data( col_idx ); + int col_w = col_data.get_width(); + right_bound -= col_w; + mvwprintz( wBio, point( right_bound, header_line_y ), c_light_gray, "%*s", col_w, + col_data.get_name() ); + } } int max_width = 0; @@ -460,7 +465,7 @@ void player::power_bionics() } const bool is_highlighted = cursor == static_cast( i ); int y_pos = list_start_y + i - scroll_position; - print_columnns( current_bionic_list[i], is_highlighted, wBio, col_right_bound, y_pos ); + print_columnns( current_bionic_list[i], is_highlighted, name_only, wBio, col_right_bound, y_pos ); if( is_highlighted && with_slots ) { const bionic_id bio_id = current_bionic_list[i]->id; draw_connectors( wBio, y_pos, col_right_bound, @@ -526,7 +531,7 @@ void player::power_bionics() tmp = current_bionic_list[cursor]; while( true ) { const int invlet = popup_getkey( - _( "%s\n\nEnter new letter. Press SPACE to clear a manually assigned letter, ESCAPE to cancel." ), + _( "%s\n\nEnter new letter. Press SPACE to clear a manually assigned letter, ESCAPE to cancel." ), bionic_chars.get_allowed_chars() ); if( invlet == KEY_ESCAPE ) { From a872196c5151734c36568e4fed1da41358028ae8 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 18 Sep 2019 16:04:35 -0400 Subject: [PATCH 006/219] fixes from AMurkin 2 cleaning up code a little fixing help keybinding --- data/raw/keybindings.json | 2 +- src/bionics_ui.cpp | 42 ++++++++++----------------------------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index 2821f6a0bfe8c..d3c6cd5df1ef3 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2258,7 +2258,7 @@ }, { "type": "keybinding", - "id": "TOGGLE_EXAMINE", + "id": "USAGE_HELP", "category": "BIONICS", "name": "Display Columns Info", "bindings": [ { "input_method": "keyboard", "key": "F1" } ] diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index d0dabad0cc498..ec7d706641992 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -321,8 +321,8 @@ void player::power_bionics() const int FOOTER_HEIGHT = 5; // Main window - // +3 = top + bottom + footer line - const int requested_height = TITLE_HEIGHT + TITLE_TAB_HEIGHT + FOOTER_HEIGHT + max_list_size + 3; + // +4 = top + bottom + footer line + column names + const int requested_height = TITLE_HEIGHT + TITLE_TAB_HEIGHT + FOOTER_HEIGHT + max_list_size + 4; const int HEIGHT = std::min( TERMY, requested_height ); int requested_width = std::max( max_name_length + col_width + 3, tabs_width ); @@ -354,7 +354,6 @@ void player::power_bionics() int scroll_position = 0; int cursor = 0; - int cur_tab_idx = 0; const int list_start_y = header_line_y + 1; const int LIST_HEIGHT = footer_start_y - list_start_y - 1; //-1 is footer separator @@ -371,35 +370,15 @@ void player::power_bionics() ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "USAGE_HELP" ); - bool recalc = false; - bool redraw = true; + int cur_tab_idx = 0; + for( ; static_cast( cur_tab_idx ) < bionics_by_type.size() && + bionics_by_type[cur_tab_idx].empty(); cur_tab_idx++ ); //try to find non-empty list + if( static_cast( cur_tab_idx ) >= bionics_by_type.size() ) { //if all lists are empty + cur_tab_idx = 0; + } + bool redraw = true; for( ;; ) { - if( recalc ) { - bionics_by_type.clear(); - for( auto &b : *my_bionics ) { - bionics_displayType_id dType = b.id->display_type; - for( size_t i = 0; i < BionicsDisplayType::displayTypes.size(); i++ ) { - if( BionicsDisplayType::displayTypes[i].ident() == dType ) { - bionics_by_type[i].emplace_back( &b ); - break; - } - } - } - - if( --cursor < 0 ) { - cursor = 0; - } - if( scroll_position > max_scroll_position && - cursor - scroll_position < LIST_HEIGHT - half_list_view_location ) { - scroll_position--; - } - - recalc = false; - // bionics were modified, so it's necessary to redraw the screen - redraw = true; - } - //track which list we are looking at const bvector ¤t_bionic_list = bionics_by_type[cur_tab_idx]; max_scroll_position = std::max( 0, static_cast( current_bionic_list.size() ) - LIST_HEIGHT ); @@ -427,7 +406,8 @@ void player::power_bionics() ctxt.get_desc( "REASSIGN" ) ); mvwprintz( wBio, point( 2, footer_start_y - 1 ), c_white, help_str ); - const bool name_only = BionicsDisplayType::displayTypes[cur_tab_idx].is_hide_columns(); + const bool name_only = current_bionic_list.empty() || + BionicsDisplayType::displayTypes[cur_tab_idx].is_hide_columns(); if( !name_only ) { for( size_t col_idx = column_num_entries, right_bound = col_right_bound; col_idx-- > 0; ) { bionic_col_data col_data = get_col_data( col_idx ); From fff2621cb64222177dad68304fdfbd83d4e547e1 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 18 Sep 2019 19:00:41 -0400 Subject: [PATCH 007/219] changing how tabs are drawn to new style fixing Return crashing with empty list --- src/bionics_ui.cpp | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index ec7d706641992..e926b34d24b66 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -179,21 +179,27 @@ static void draw_bionics_tabs( const catacurses::window &win, std::vector> tabs; for( size_t i = 0; i < BionicsDisplayType::displayTypes.size(); i++ ) { if( bionics[i].empty() ) { continue; } BionicsDisplayType type = BionicsDisplayType::displayTypes[i]; - tab_name = type.display_string(); - draw_tab( win, tab_x, tab_name, cur_type_id == type.ident() ); - tab_x += tab_step + utf8_width( tab_name ); + tabs.emplace_back( type.ident(), type.display_string() ); + } + bionics_displayType_id cur_type_id = BionicsDisplayType::displayTypes[current_mode].ident(); + draw_tabs( win, tabs, cur_type_id ); + + // Draw symbols to connect additional lines to border + int width = getmaxx( win ); + int height = getmaxy( win ); + for( int i = 0; i < height - 1; ++i ) { + mvwputch( win, point( 0, i ), BORDER_COLOR, LINE_XOXO ); // | + mvwputch( win, point( width - 1, i ), BORDER_COLOR, LINE_XOXO ); // | } + mvwputch( win, point( 0, height - 1 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( win, point( width - 1, height - 1 ), BORDER_COLOR, LINE_XOXX ); // -| + wrefresh( win ); } @@ -343,8 +349,8 @@ void player::power_bionics() //Tabs bar const int TAB_WINDOW_Y = TITLE_WINDOW_Y + TITLE_HEIGHT; - catacurses::window w_tabs = catacurses::newwin( TITLE_TAB_HEIGHT, WIDTH - 2, - point( MAIN_WINDOW_X + 1, + catacurses::window w_tabs = catacurses::newwin( TITLE_TAB_HEIGHT, WIDTH, + point( MAIN_WINDOW_X, TAB_WINDOW_Y ) ); const int header_line_y = TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; @@ -395,10 +401,6 @@ void player::power_bionics() std::string help_str = string_format( _( "< [%s] Columns Info >" ), ctxt.get_desc( "USAGE_HELP" ) ); mvwprintz( wBio, point( WIDTH - 1 - utf8_width( help_str ), 0 ), c_white, help_str ); - // Draw symbols to connect additional lines to border - mvwputch( wBio, point( 0, header_line_y - 1 ), BORDER_COLOR, LINE_XXXO ); // |- - mvwputch( wBio, point( WIDTH - 1, header_line_y - 1 ), BORDER_COLOR, LINE_XOXX ); // -| - mvwputch( wBio, point( 0, footer_start_y - 1 ), BORDER_COLOR, LINE_XXXO ); // |- mvwputch( wBio, point( WIDTH - 1, footer_start_y - 1 ), BORDER_COLOR, LINE_XOXX ); // -| mvwhline( wBio, point( 1, footer_start_y - 1 ), LINE_OXOX, WIDTH - 2 ); @@ -553,7 +555,9 @@ void player::power_bionics() } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; } else if( action == "CONFIRM" ) { - tmp = current_bionic_list[cursor]; + if( !current_bionic_list.empty() ) { + tmp = current_bionic_list[cursor]; + } need_activate = true; } else if( action == "USAGE_HELP" ) { std::string help_str; From 3b044422662b1688dddbb05c1b20f7c87a8af080 Mon Sep 17 00:00:00 2001 From: Alexey Date: Fri, 20 Sep 2019 03:09:11 -0400 Subject: [PATCH 008/219] travis --- src/bionics_ui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index e926b34d24b66..a180633febddc 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -363,8 +363,7 @@ void player::power_bionics() const int list_start_y = header_line_y + 1; const int LIST_HEIGHT = footer_start_y - list_start_y - 1; //-1 is footer separator - int half_list_view_location = LIST_HEIGHT / 2; - int max_scroll_position = std::max( 0, static_cast( bionics_by_type[0].size() ) ); + const int half_list_view_location = LIST_HEIGHT / 2; input_context ctxt( "BIONICS" ); ctxt.register_updown(); @@ -387,7 +386,8 @@ void player::power_bionics() for( ;; ) { //track which list we are looking at const bvector ¤t_bionic_list = bionics_by_type[cur_tab_idx]; - max_scroll_position = std::max( 0, static_cast( current_bionic_list.size() ) - LIST_HEIGHT ); + const int max_scroll_position = std::max( 0, + static_cast( current_bionic_list.size() ) - LIST_HEIGHT ); if( redraw ) { redraw = false; From 2b58665261554ec2bfa0431c4dc435b59ea39524 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 16 Oct 2019 13:59:19 -0400 Subject: [PATCH 009/219] add some documentation to BionicsDisplayType --- src/bionics.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bionics.h b/src/bionics.h index f4b0229495479..95fe1f84a0293 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -165,16 +165,21 @@ struct bionic { void deserialize( JsonIn &jsin ); }; +// represents a tab in the Bionics menu class BionicsDisplayType { friend class string_id; + // internal id bionics_displayType_id _ident; + // string displayed to user translation _display_string; + // will only disply name if set to true. Useful for passive bionics. bool _hide_columns; public: static std::vector displayTypes; static void load( JsonObject &jsobj ); static void reset(); + //if bionic doesn't have "display_type" filed in .json, use this to infer it from other parameters static bionics_displayType_id infer_type( const bionic_data &b ); BionicsDisplayType(); From bbfd42c27a8d3c94f94e3eefb4fc74f18dfe1b35 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 16 Oct 2019 14:39:00 -0400 Subject: [PATCH 010/219] adding documentation to JSON_INFO.md --- doc/JSON_INFO.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 51e419500e34f..6fc5056a330b2 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -380,6 +380,7 @@ This section describes each json file and their contents. Each json has their ow | exothermic_power_gen | (_optional_) If true this bionic emits heat when producing power. (default: `false`) | power_gen_emission | (_optional_) `emit_id` of the field emitted by this bionic when it produces energy. Emit_ids are defined in `emit.json`. | stat_bonus | (_optional_) List of passive stat bonus. Stat are designated as follow: "DEX", "INT", "STR", "PER". +| display_type | (_optional_) Determines the tab in the Bionics menu. Must be equal to one of `"ident"` in bionicsDisplayType.json. If not set, the code will try to infer the tab from other parameters. ```C++ { @@ -397,7 +398,8 @@ This section describes each json file and their contents. Each json has their ow "encumbrance" : [ [ "TORSO", 10 ], [ "ARM_L", 10 ], [ "ARM_R", 10 ], [ "LEG_L", 10 ], [ "LEG_R", 10 ], [ "FOOT_L", 10 ], [ "FOOT_R", 10 ] ], "description" : "You have a battery draining attachment, and thus can make use of the energy contained in normal, everyday batteries. Use 'E' to consume batteries.", "canceled_mutations": ["HYPEROPIC"], - "included_bionics": ["bio_blindfold"] + "included_bionics": ["bio_blindfold"], + "display_type": "display_internal" }, { "id": "bio_purifier", @@ -413,6 +415,22 @@ This section describes each json file and their contents. Each json has their ow Bionics effects are defined in the code and new effects cannot be created through JSON alone. When adding a new bionic, if it's not included with another one, you must also add the corresponding CBM item in `data/json/items/bionics.json`. Even for a faulty bionic. +### bionicsDisplayType + +Represents a tab in the Bionics menu + +| Identifier | Description +|--- |--- +| ident | Unique ID. +| display_string| User will see this as a tab name. +| hide_columns | (_optional_) only display the name column and hide all others. (default: `false`) + +```JSON +"type": "bionics_display_type", +"ident": "display_weapon", +"display_string": "Weapons", +"hide_columns": true + ### Dreams | Identifier | Description From 2a0d05d5af009fe6b6fb370fa98b0c59f0726c44 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 16 Oct 2019 22:16:59 -0400 Subject: [PATCH 011/219] revert accidental astyle for src/Android.mk and src/CMakeLists.txt --- src/Android.mk | 20 +- src/CMakeLists.txt | 524 ++++++++++++++++++++++----------------------- 2 files changed, 269 insertions(+), 275 deletions(-) diff --git a/src/Android.mk b/src/Android.mk index 17e6a861a01d0..ade6ef40127a2 100644 --- a/src/Android.mk +++ b/src/Android.mk @@ -1,23 +1,17 @@ -LOCAL_PATH : - = $( call my - dir ) +LOCAL_PATH := $(call my-dir) - include $( CLEAR_VARS ) +include $(CLEAR_VARS) - LOCAL_MODULE : - = main +LOCAL_MODULE := main - SDL_PATH : - = .. / SDL2 +SDL_PATH := ../SDL2 - LOCAL_C_INCLUDES : - = $( LOCAL_PATH ) / $( SDL_PATH ) / include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include - LOCAL_CPP_FEATURES : - = exceptions rtti +LOCAL_CPP_FEATURES := exceptions rtti # Add your application source files here... - FILE_LIST : - = $( wildcard $( LOCAL_PATH )/*.cpp) +FILE_LIST := $(wildcard $(LOCAL_PATH)/*.cpp) LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) LOCAL_SHARED_LIBRARIES := libhidapi SDL2 SDL2_mixer SDL2_image SDL2_ttf libintl-lite mpg123 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 391413be2360f..81c3622f0e3b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,11 +1,11 @@ # Cataclysm DDA client -cmake_minimum_required( VERSION 3.0.0 ) +cmake_minimum_required(VERSION 3.0.0) -SET( MAIN_CPP $ {CMAKE_SOURCE_DIR} / src / main.cpp ) -SET( RESOURCE_RC $ {CMAKE_SOURCE_DIR} / src / resource.rc ) +SET(MAIN_CPP ${CMAKE_SOURCE_DIR}/src/main.cpp) +SET(RESOURCE_RC ${CMAKE_SOURCE_DIR}/src/resource.rc) -FILE( GLOB CATACLYSM_DDA_SOURCES - $ {CMAKE_SOURCE_DIR} / src/*.cpp) +FILE(GLOB CATACLYSM_DDA_SOURCES + ${CMAKE_SOURCE_DIR}/src/*.cpp) LIST(REMOVE_ITEM CATACLYSM_DDA_SOURCES ${MAIN_CPP}) @@ -14,278 +14,278 @@ FILE(GLOB CATACLYSM_DDA_HEADERS # Get GIT version strings ADD_CUSTOM_TARGET( - get_version - DEPENDS ${CMAKE_SOURCE_DIR}/src/version.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + get_version + DEPENDS ${CMAKE_SOURCE_DIR}/src/version.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) ADD_CUSTOM_COMMAND ( - OUTPUT ${CMAKE_SOURCE_DIR}/src/version.h - COMMAND ${CMAKE_COMMAND} - -D SRC=${CMAKE_SOURCE_DIR}/src/version.h.in - -D DST=${CMAKE_SOURCE_DIR}/src/version.h - -D GIT_EXECUTABLE=${GIT_EXECUTABLE} - -P ${CMAKE_SOURCE_DIR}/src/version.cmake - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT ${CMAKE_SOURCE_DIR}/src/version.h + COMMAND ${CMAKE_COMMAND} + -D SRC=${CMAKE_SOURCE_DIR}/src/version.h.in + -D DST=${CMAKE_SOURCE_DIR}/src/version.h + -D GIT_EXECUTABLE=${GIT_EXECUTABLE} + -P ${CMAKE_SOURCE_DIR}/src/version.cmake + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) # Build tiles version if requested IF(TILES) - add_library(libcataclysm-tiles STATIC - ${CATACLYSM_DDA_SOURCES} - ${CATACLYSM_DDA_HEADERS} - ) - - target_include_directories(libcataclysm-tiles INTERFACE ${CMAKE_SOURCE_DIR}/src) - - IF(WIN32) - ADD_DEFINITIONS(-DUSE_WINMAIN) - ADD_EXECUTABLE(cataclysm-tiles WIN32 - ${MAIN_CPP} - ${RESOURCE_RC} - ) - ELSE(WIN32) - ADD_EXECUTABLE(cataclysm-tiles - ${MAIN_CPP} - ) - ENDIF(WIN32) - - ADD_DEPENDENCIES(libcataclysm-tiles get_version) - - target_link_libraries(cataclysm-tiles libcataclysm-tiles) - target_compile_definitions(libcataclysm-tiles PUBLIC TILES ) - - IF (LOCALIZE) - target_include_directories(libcataclysm-tiles PUBLIC - ${LIBINTL_INCLUDE_DIR} - ${ICONV_INCLUDE_DIR} - ) - target_link_libraries(libcataclysm-tiles - ${LIBINTL_LIBRARIES} - ${ICONV_LIBRARIES} - ) - ENDIF (LOCALIZE) - - IF(CMAKE_USE_PTHREADS_INIT) - target_compile_options(libcataclysm-tiles PUBLIC "-pthread") - ENDIF(CMAKE_USE_PTHREADS_INIT) - - IF(CMAKE_THREAD_LIBS_INIT) - target_link_libraries(libcataclysm-tiles ${CMAKE_THREAD_LIBS_INIT}) - ENDIF(CMAKE_THREAD_LIBS_INIT) - - IF (NOT DYNAMIC_LINKING) - # SDL, SDL_Image, SDL_ttf deps are required for static build - target_include_directories(libcataclysm-tiles PUBLIC - ${FREETYPE_INCLUDE_DIRS} - ${PNG_INCLUDE_DIRS} - ${JPEG_INCLUDE_DIR} - ${ZLIB_INCLUDE_DIRS} - ${BZIP2_INCLUDE_DIR} - ) - target_link_libraries(libcataclysm-tiles - ${FREETYPE_LIBRARIES} - ${PNG_LIBRARIES} - ${JPEG_LIBRARIES} - ${ZLIB_LIBRARIES} - ${BZIP2_LIBRARIES} - ) - ENDIF (NOT DYNAMIC_LINKING) - - target_include_directories(libcataclysm-tiles PUBLIC - ${SDL2_INCLUDE_DIR} - ${SDL2_IMAGE_INCLUDE_DIRS} - ${SDL2_TTF_INCLUDE_DIRS} - ) - target_link_libraries(libcataclysm-tiles - ${SDL2_LIBRARY} - ${SDL2_IMAGE_LIBRARIES} - ${SDL2_TTF_LIBRARIES} - ) - - IF(SOUND) - target_compile_definitions(libcataclysm-tiles PUBLIC SDL_SOUND ) - - target_include_directories(libcataclysm-tiles PUBLIC ${OGGVORBIS_INCLUDE_DIR}) - target_link_libraries(libcataclysm-tiles ${OGG_LIBRARY}) - target_link_libraries(libcataclysm-tiles ${VORBIS_LIBRARY}) - target_link_libraries(libcataclysm-tiles ${VORBISFILE_LIBRARY}) - - target_include_directories(libcataclysm-tiles PUBLIC ${SDL2_MIXER_INCLUDE_DIRS}) - target_link_libraries(libcataclysm-tiles ${SDL2_MIXER_LIBRARIES}) - ENDIF(SOUND) - - IF(WIN32) - # Global settings for Windows targets (at end) - target_link_libraries(libcataclysm-tiles gdi32.lib) - target_link_libraries(libcataclysm-tiles winmm.lib) - target_link_libraries(libcataclysm-tiles imm32.lib) - target_link_libraries(libcataclysm-tiles ole32.lib) - target_link_libraries(libcataclysm-tiles oleaut32.lib) - target_link_libraries(libcataclysm-tiles version.lib) - IF (BACKTRACE) - target_link_libraries(libcataclysm-tiles dbghelp.lib) - ENDIF(BACKTRACE) - ENDIF(WIN32) - - IF(RELEASE) - install(TARGETS cataclysm-tiles DESTINATION ${BIN_PREFIX}) - ENDIF(RELEASE) + add_library(libcataclysm-tiles STATIC + ${CATACLYSM_DDA_SOURCES} + ${CATACLYSM_DDA_HEADERS} + ) + + target_include_directories(libcataclysm-tiles INTERFACE ${CMAKE_SOURCE_DIR}/src) + + IF(WIN32) + ADD_DEFINITIONS(-DUSE_WINMAIN) + ADD_EXECUTABLE(cataclysm-tiles WIN32 + ${MAIN_CPP} + ${RESOURCE_RC} + ) + ELSE(WIN32) + ADD_EXECUTABLE(cataclysm-tiles + ${MAIN_CPP} + ) + ENDIF(WIN32) + + ADD_DEPENDENCIES(libcataclysm-tiles get_version) + + target_link_libraries(cataclysm-tiles libcataclysm-tiles) + target_compile_definitions(libcataclysm-tiles PUBLIC TILES ) + + IF (LOCALIZE) + target_include_directories(libcataclysm-tiles PUBLIC + ${LIBINTL_INCLUDE_DIR} + ${ICONV_INCLUDE_DIR} + ) + target_link_libraries(libcataclysm-tiles + ${LIBINTL_LIBRARIES} + ${ICONV_LIBRARIES} + ) + ENDIF (LOCALIZE) + + IF(CMAKE_USE_PTHREADS_INIT) + target_compile_options(libcataclysm-tiles PUBLIC "-pthread") + ENDIF(CMAKE_USE_PTHREADS_INIT) + + IF(CMAKE_THREAD_LIBS_INIT) + target_link_libraries(libcataclysm-tiles ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(CMAKE_THREAD_LIBS_INIT) + + IF (NOT DYNAMIC_LINKING) + # SDL, SDL_Image, SDL_ttf deps are required for static build + target_include_directories(libcataclysm-tiles PUBLIC + ${FREETYPE_INCLUDE_DIRS} + ${PNG_INCLUDE_DIRS} + ${JPEG_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIRS} + ${BZIP2_INCLUDE_DIR} + ) + target_link_libraries(libcataclysm-tiles + ${FREETYPE_LIBRARIES} + ${PNG_LIBRARIES} + ${JPEG_LIBRARIES} + ${ZLIB_LIBRARIES} + ${BZIP2_LIBRARIES} + ) + ENDIF (NOT DYNAMIC_LINKING) + + target_include_directories(libcataclysm-tiles PUBLIC + ${SDL2_INCLUDE_DIR} + ${SDL2_IMAGE_INCLUDE_DIRS} + ${SDL2_TTF_INCLUDE_DIRS} + ) + target_link_libraries(libcataclysm-tiles + ${SDL2_LIBRARY} + ${SDL2_IMAGE_LIBRARIES} + ${SDL2_TTF_LIBRARIES} + ) + + IF(SOUND) + target_compile_definitions(libcataclysm-tiles PUBLIC SDL_SOUND ) + + target_include_directories(libcataclysm-tiles PUBLIC ${OGGVORBIS_INCLUDE_DIR}) + target_link_libraries(libcataclysm-tiles ${OGG_LIBRARY}) + target_link_libraries(libcataclysm-tiles ${VORBIS_LIBRARY}) + target_link_libraries(libcataclysm-tiles ${VORBISFILE_LIBRARY}) + + target_include_directories(libcataclysm-tiles PUBLIC ${SDL2_MIXER_INCLUDE_DIRS}) + target_link_libraries(libcataclysm-tiles ${SDL2_MIXER_LIBRARIES}) + ENDIF(SOUND) + + IF(WIN32) + # Global settings for Windows targets (at end) + target_link_libraries(libcataclysm-tiles gdi32.lib) + target_link_libraries(libcataclysm-tiles winmm.lib) + target_link_libraries(libcataclysm-tiles imm32.lib) + target_link_libraries(libcataclysm-tiles ole32.lib) + target_link_libraries(libcataclysm-tiles oleaut32.lib) + target_link_libraries(libcataclysm-tiles version.lib) + IF (BACKTRACE) + target_link_libraries(libcataclysm-tiles dbghelp.lib) + ENDIF(BACKTRACE) + ENDIF(WIN32) + + IF(RELEASE) + install(TARGETS cataclysm-tiles DESTINATION ${BIN_PREFIX}) + ENDIF(RELEASE) ENDIF(TILES) # Build curses version if requested IF(CURSES) - add_library(libcataclysm STATIC - ${CATACLYSM_DDA_SOURCES} - ${CATACLYSM_DDA_HEADERS} - ) - - target_include_directories(libcataclysm INTERFACE ${CMAKE_SOURCE_DIR}/src) - - IF(WIN32) - ADD_EXECUTABLE(cataclysm - ${MAIN_CPP} - ${RESOURCE_RC} - ) - ELSE(WIN32) - ADD_EXECUTABLE(cataclysm - ${MAIN_CPP} - ) - ENDIF(WIN32) - - ADD_DEPENDENCIES(libcataclysm get_version) - - target_link_libraries(cataclysm libcataclysm) - - IF (LOCALIZE) - target_include_directories(libcataclysm PUBLIC - ${LIBINTL_INCLUDE_DIR} - ${ICONV_INCLUDE_DIR} - ) - target_link_libraries(libcataclysm - ${LIBINTL_LIBRARIES} - ${ICONV_LIBRARIES} - ) - ENDIF (LOCALIZE) - - target_include_directories(libcataclysm PUBLIC ${CURSES_INCLUDE_DIR}) - target_link_libraries(libcataclysm ${CURSES_LIBRARIES}) - - IF(CMAKE_USE_PTHREADS_INIT) - target_compile_options(libcataclysm PUBLIC "-pthread") - ENDIF(CMAKE_USE_PTHREADS_INIT) - - IF(CMAKE_THREAD_LIBS_INIT) - target_link_libraries(libcataclysm ${CMAKE_THREAD_LIBS_INIT}) - ENDIF(CMAKE_THREAD_LIBS_INIT) - - IF(WIN32) - # Global settings for Windows targets (at end) - target_link_libraries(libcataclysm gdi32.lib) - target_link_libraries(libcataclysm winmm.lib) - target_link_libraries(libcataclysm imm32.lib) - target_link_libraries(libcataclysm ole32.lib) - target_link_libraries(libcataclysm oleaut32.lib) - target_link_libraries(libcataclysm version.lib) - IF (BACKTRACE) - target_link_libraries(libcataclysm dbghelp.lib) - ENDIF(BACKTRACE) - ENDIF(WIN32) - - IF(RELEASE) - install(TARGETS cataclysm DESTINATION ${BIN_PREFIX}) - ENDIF(RELEASE) + add_library(libcataclysm STATIC + ${CATACLYSM_DDA_SOURCES} + ${CATACLYSM_DDA_HEADERS} + ) + + target_include_directories(libcataclysm INTERFACE ${CMAKE_SOURCE_DIR}/src) + + IF(WIN32) + ADD_EXECUTABLE(cataclysm + ${MAIN_CPP} + ${RESOURCE_RC} + ) + ELSE(WIN32) + ADD_EXECUTABLE(cataclysm + ${MAIN_CPP} + ) + ENDIF(WIN32) + + ADD_DEPENDENCIES(libcataclysm get_version) + + target_link_libraries(cataclysm libcataclysm) + + IF (LOCALIZE) + target_include_directories(libcataclysm PUBLIC + ${LIBINTL_INCLUDE_DIR} + ${ICONV_INCLUDE_DIR} + ) + target_link_libraries(libcataclysm + ${LIBINTL_LIBRARIES} + ${ICONV_LIBRARIES} + ) + ENDIF (LOCALIZE) + + target_include_directories(libcataclysm PUBLIC ${CURSES_INCLUDE_DIR}) + target_link_libraries(libcataclysm ${CURSES_LIBRARIES}) + + IF(CMAKE_USE_PTHREADS_INIT) + target_compile_options(libcataclysm PUBLIC "-pthread") + ENDIF(CMAKE_USE_PTHREADS_INIT) + + IF(CMAKE_THREAD_LIBS_INIT) + target_link_libraries(libcataclysm ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(CMAKE_THREAD_LIBS_INIT) + + IF(WIN32) + # Global settings for Windows targets (at end) + target_link_libraries(libcataclysm gdi32.lib) + target_link_libraries(libcataclysm winmm.lib) + target_link_libraries(libcataclysm imm32.lib) + target_link_libraries(libcataclysm ole32.lib) + target_link_libraries(libcataclysm oleaut32.lib) + target_link_libraries(libcataclysm version.lib) + IF (BACKTRACE) + target_link_libraries(libcataclysm dbghelp.lib) + ENDIF(BACKTRACE) + ENDIF(WIN32) + + IF(RELEASE) + install(TARGETS cataclysm DESTINATION ${BIN_PREFIX}) + ENDIF(RELEASE) ENDIF(CURSES) IF(MINGW AND NOT RELEASE) - # Try to Install shared libraries for dev builds - # - # Note: It is specific to MSYS2 and uses hardcoded versions so - # probly it will fail if you run it :) - - # GCC-specific libraries - find_library(RuntimeLib_GCC_S_DW2_1 "gcc_s_dw2-1") - find_library(RuntimeLib_STDC_PP_6 "stdc++-6") - find_library(RuntimeLib_WINPTHREAD_1 "winpthread-1") - SET(RuntimeLib_GCC_ALL - ${RuntimeLib_GCC_S_DW2_1} - ${RuntimeLib_STDC_PP_6} - ${RuntimeLib_WINPTHREAD_1} - ) - IF (LOCALIZE) - find_library(RuntimeLib_iconv "libiconv-2") - find_library(RuntimeLib_intl "libintl-8") - SET(RuntimeLib_LOCALIZE - ${RuntimeLib_iconv} - ${RuntimeLib_intl} - ) - ENDIF (LOCALIZE) - IF (TILES) - # SDL2 can have a varoius deps. Here you are the MSYS2 ones... - find_library(RuntimeLib_SDL2 "SDL2") - find_library(RuntimeLib_SDL2_IMG "SDL2_image") - find_library(RuntimeLib_png "libpng16-16") - find_library(RuntimeLib_jpeg "libjpeg-8") - find_library(RuntimeLib_jbig "libjbig-0") - find_library(RuntimeLib_tiff "libtiff-5") - find_library(RuntimeLib_webp "libwebp-5") - find_library(RuntimeLib_lzma "liblzma-5") - find_library(RuntimeLib_bz2 "libbz2-1") - find_library(RuntimeLib_zlib "zlib1") - find_library(RuntimeLib_hb "libharfbuzz-0") - find_library(RuntimeLib_SDL2_TTF "SDL2_ttf") - find_library(RuntimeLib_ft "libfreetype-6") - find_library(RuntimeLib_glib "libglib-2.0-0") - SET(RuntimeLib_SDL - ${RuntimeLib_SDL2} - ${RuntimeLib_SDL2_IMG} - ${RuntimeLib_png} - ${RuntimeLib_jpeg} - ${RuntimeLib_jbig} - ${RuntimeLib_tiff} - ${RuntimeLib_webp} - ${RuntimeLib_lzma} - ${RuntimeLib_bz2} - ${RuntimeLib_zlib} - ${RuntimeLib_hb} - ${RuntimeLib_SDL2_TTF} - ${RuntimeLib_ft} - ${RuntimeLib_glib} - ) - IF(SOUND) - find_library(RuntimeLib_SDL_SND "SDL2_mixer") - find_library(RuntimeLib_flak "libFLAC-8") - find_library(RuntimeLib_ogg "libogg-0") - find_library(RuntimeLib_flu "libfluidsynth-1") - find_library(RuntimeLib_port "libportaudio-2") - find_library(RuntimeLib_snd "libsndfile-1") - find_library(RuntimeLib_vorb "libvorbis-0") - find_library(RuntimeLib_vorb_enc "libvorbisenc-2") - find_library(RuntimeLib_vorb_f "libvorbisfile-3") - find_library(RuntimeLib_mod "libmodplug-1") - find_library(RuntimeLib_mpeg "smpeg2") - SET(RuntimeLib_SDL_SOUND - ${RuntimeLib_SDL_SND} - ${RuntimeLib_flak} - ${RuntimeLib_ogg} - ${RuntimeLib_flu} - ${RuntimeLib_port} - ${RuntimeLib_snd} - ${RuntimeLib_vorb} - ${RuntimeLib_vorb_enc} - ${RuntimeLib_vorb_f} - ${RuntimeLib_mod} - ${RuntimeLib_mpeg} - ) - ENDIF(SOUND) - ENDIF (TILES) - install(FILES ${RuntimeLib_GCC_ALL} - ${RuntimeLib_LOCALIZE} - ${RuntimeLib_SDL} - ${RuntimeLib_SDL_SOUND} - DESTINATION ${BIN_PREFIX} - ) + # Try to Install shared libraries for dev builds + # + # Note: It is specific to MSYS2 and uses hardcoded versions so + # probly it will fail if you run it :) + + # GCC-specific libraries + find_library(RuntimeLib_GCC_S_DW2_1 "gcc_s_dw2-1") + find_library(RuntimeLib_STDC_PP_6 "stdc++-6") + find_library(RuntimeLib_WINPTHREAD_1 "winpthread-1") + SET(RuntimeLib_GCC_ALL + ${RuntimeLib_GCC_S_DW2_1} + ${RuntimeLib_STDC_PP_6} + ${RuntimeLib_WINPTHREAD_1} + ) + IF (LOCALIZE) + find_library(RuntimeLib_iconv "libiconv-2") + find_library(RuntimeLib_intl "libintl-8") + SET(RuntimeLib_LOCALIZE + ${RuntimeLib_iconv} + ${RuntimeLib_intl} + ) + ENDIF (LOCALIZE) + IF (TILES) + # SDL2 can have a varoius deps. Here you are the MSYS2 ones... + find_library(RuntimeLib_SDL2 "SDL2") + find_library(RuntimeLib_SDL2_IMG "SDL2_image") + find_library(RuntimeLib_png "libpng16-16") + find_library(RuntimeLib_jpeg "libjpeg-8") + find_library(RuntimeLib_jbig "libjbig-0") + find_library(RuntimeLib_tiff "libtiff-5") + find_library(RuntimeLib_webp "libwebp-5") + find_library(RuntimeLib_lzma "liblzma-5") + find_library(RuntimeLib_bz2 "libbz2-1") + find_library(RuntimeLib_zlib "zlib1") + find_library(RuntimeLib_hb "libharfbuzz-0") + find_library(RuntimeLib_SDL2_TTF "SDL2_ttf") + find_library(RuntimeLib_ft "libfreetype-6") + find_library(RuntimeLib_glib "libglib-2.0-0") + SET(RuntimeLib_SDL + ${RuntimeLib_SDL2} + ${RuntimeLib_SDL2_IMG} + ${RuntimeLib_png} + ${RuntimeLib_jpeg} + ${RuntimeLib_jbig} + ${RuntimeLib_tiff} + ${RuntimeLib_webp} + ${RuntimeLib_lzma} + ${RuntimeLib_bz2} + ${RuntimeLib_zlib} + ${RuntimeLib_hb} + ${RuntimeLib_SDL2_TTF} + ${RuntimeLib_ft} + ${RuntimeLib_glib} + ) + IF(SOUND) + find_library(RuntimeLib_SDL_SND "SDL2_mixer") + find_library(RuntimeLib_flak "libFLAC-8") + find_library(RuntimeLib_ogg "libogg-0") + find_library(RuntimeLib_flu "libfluidsynth-1") + find_library(RuntimeLib_port "libportaudio-2") + find_library(RuntimeLib_snd "libsndfile-1") + find_library(RuntimeLib_vorb "libvorbis-0") + find_library(RuntimeLib_vorb_enc "libvorbisenc-2") + find_library(RuntimeLib_vorb_f "libvorbisfile-3") + find_library(RuntimeLib_mod "libmodplug-1") + find_library(RuntimeLib_mpeg "smpeg2") + SET(RuntimeLib_SDL_SOUND + ${RuntimeLib_SDL_SND} + ${RuntimeLib_flak} + ${RuntimeLib_ogg} + ${RuntimeLib_flu} + ${RuntimeLib_port} + ${RuntimeLib_snd} + ${RuntimeLib_vorb} + ${RuntimeLib_vorb_enc} + ${RuntimeLib_vorb_f} + ${RuntimeLib_mod} + ${RuntimeLib_mpeg} + ) + ENDIF(SOUND) + ENDIF (TILES) + install(FILES ${RuntimeLib_GCC_ALL} + ${RuntimeLib_LOCALIZE} + ${RuntimeLib_SDL} + ${RuntimeLib_SDL_SOUND} + DESTINATION ${BIN_PREFIX} + ) ENDIF(MINGW AND NOT RELEASE) # vim:noet From 7eef8860e6b54bb899135746937b01dfc720a85e Mon Sep 17 00:00:00 2001 From: akozhevn Date: Sat, 26 Oct 2019 09:38:42 -0400 Subject: [PATCH 012/219] missing comma --- data/json/bionics.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index dfb765ad52e51..1ed978783a131 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -646,7 +646,7 @@ "react_cost": "4 J", "time": 1, "display_type": "display_internal" - } + }, { "id": "bio_night", "type": "bionic", From d44706cb01d9b5f91b1ce599570020c38e252e13 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 26 Oct 2019 22:23:58 -0400 Subject: [PATCH 013/219] travis --- src/bionics_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 91a72dfc12b01..6b78d1f5bff33 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -52,7 +52,7 @@ bionic_col_data get_col_data( int col_idx ) static std::array< bionic_col_data, column_num_entries> col_data = { { { 3, translate_marker( "Status" ), - translate_marker( "CBM Status:\n\t+ - activated\n\tx - incapacitated. This CBM cannot be used for some time." ) + translate_marker( "CBM Status:\n + - activated\n x - incapacitated. This CBM cannot be used for some time." ) }, {8, translate_marker( "Activation" ), translate_marker( "Amount of Bionic Power required to activeate this CBM." )}, {8, translate_marker( "Turn Cost" ), translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) } From 152389bf79322f2acc6d2ff945494d7d195e5680 Mon Sep 17 00:00:00 2001 From: LyleSY Date: Fri, 6 Mar 2020 05:09:42 -0500 Subject: [PATCH 014/219] DinoModv3: DinoDNA (#26525) --- data/mods/DinoMod/dinosaur.json | 440 ++++++++++++------ data/mods/DinoMod/egg.json | 108 +++++ data/mods/DinoMod/forage.json | 14 + data/mods/DinoMod/lab_notes.json | 10 + data/mods/DinoMod/monstergroups_egg.json | 23 + .../mods/DinoMod/recipe_medsandchemicals.json | 20 + 6 files changed, 475 insertions(+), 140 deletions(-) create mode 100644 data/mods/DinoMod/egg.json create mode 100644 data/mods/DinoMod/forage.json create mode 100644 data/mods/DinoMod/lab_notes.json create mode 100644 data/mods/DinoMod/monstergroups_egg.json create mode 100644 data/mods/DinoMod/recipe_medsandchemicals.json diff --git a/data/mods/DinoMod/dinosaur.json b/data/mods/DinoMod/dinosaur.json index 18fda81786c73..a26fc5b2278bf 100644 --- a/data/mods/DinoMod/dinosaur.json +++ b/data/mods/DinoMod/dinosaur.json @@ -13,25 +13,41 @@ "default_faction": "compsognathus", "symbol": "D", "color": "green_yellow", - "volume": "30000 ml", - "weight": "40750 g", + "volume": "5500 ml", + "weight": 5500, "material": "flesh", - "aggression": -80, - "morale": -8, + "aggression": 3, + "morale": 20, "speed": 140, - "melee_skill": 4, + "melee_skill": 5, "melee_dice": 1, - "melee_dice_sides": 1, - "melee_cut": 0, + "melee_dice_sides": 2, + "melee_cut": 1, "dodge": 4, "vision_day": 50, "armor_bash": 1, "armor_cut": 0, - "luminance": 0, "hp": 20, "death_function": [ "NORMAL" ], "description": "A bipedal dinosaur about the size of a turkey. Its teeth and claws are small but sharp.", - "flags": [ "SEES", "SMELLS", "HEARS", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "BLEED", "WARM" ], + "reproduction": { "baby_egg": "egg_compsognathus", "baby_count": 3, "baby_timer": 12 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "HIT_AND_RUN", + "ANIMAL", + "PATH_AVOID_DANGER_1", + "BLEED", + "WARM", + "SWIMS", + "CATFOOD", + "SWARMS", + "ATTACKMON", + "GROUP_MORALE" + ], "harvest": "mammal_leather", "anger_triggers": [ "PLAYER_WEAK", "HURT" ], "fear_triggers": [ "PLAYER_CLOSE", "FIRE", "FRIEND_DIED" ], @@ -46,8 +62,8 @@ "default_faction": "gallimimus", "symbol": "D", "color": "light_green_yellow", - "volume": "62500 ml", - "weight": "81500 g", + "volume": "440000 ml", + "weight": 440000, "material": "flesh", "aggression": -60, "morale": -20, @@ -59,45 +75,26 @@ "dodge": 3, "armor_bash": 1, "armor_cut": 1, - "luminance": 0, "hp": 40, "death_function": [ "NORMAL" ], "description": "A feathered bipedal dinosaur, standing as tall as a human. It looks somewhat like a reptilian ostrich.", - "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM" ], - "harvest": "dino_feather_leather", - "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "FIRE" ], - "categories": [ "DINOSAUR" ] - }, - { - "type": "MONSTER", - "id": "mon_titanis", - "name": { "str": "Titanis", "str_pl": "Titanis" }, - "species": "DINOSAUR", - "default_faction": "titanis", - "symbol": "D", - "color": "blue_green", - "volume": "92500 ml", - "weight": "120 kg", - "material": "flesh", - "aggression": -20, - "morale": 60, - "speed": 150, - "melee_skill": 8, - "melee_dice": 1, - "melee_dice_sides": 8, - "melee_cut": 2, - "dodge": 1, - "armor_bash": 1, - "armor_cut": 1, - "luminance": 0, - "hp": 60, - "death_function": [ "NORMAL" ], - "description": "It looks like a dodo, only much bigger, with longer, muscular legs and a predatory gleam in its eyes.", - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "GRABS", "KEENNOSE", "BLEED", "WARM" ], + "reproduction": { "baby_egg": "egg_gallimimus", "baby_count": 3, "baby_timer": 12 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "GOODHEARING", + "ANIMAL", + "PATH_AVOID_DANGER_1", + "PET_MOUNTABLE", + "CATTLEFODDER", + "PET_WONT_FOLLOW", + "WARM" + ], "harvest": "dino_feather_leather", - "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], - "fear_triggers": [ "SOUND", "FIRE" ], - "placate_triggers": [ "MEAT" ], + "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "HURT", "FIRE" ], "categories": [ "DINOSAUR" ] }, { @@ -108,8 +105,8 @@ "default_faction": "spinosaurus", "symbol": "D", "color": "red_white", - "volume": "875000 ml", - "weight": "200 kg", + "volume": "16000000 ml", + "weight": 16000000, "material": "flesh", "aggression": 100, "morale": 100, @@ -121,11 +118,25 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 2, - "luminance": 0, "hp": 400, "death_function": [ "NORMAL" ], "description": "A huge dinosaur about the size of a small house, with a ferocious crocodile-like head and a sail on its back.", - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "DESTROYS", "BLEED", "ATTACKMON", "WARM" ], + "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" + ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], "fear_triggers": [ "SOUND", "FIRE" ], @@ -140,8 +151,8 @@ "default_faction": "t-rex", "symbol": "D", "color": "light_red_white", - "volume": "875000 ml", - "weight": "200 kg", + "volume": "5500000 ml", + "weight": 5500000, "material": "flesh", "aggression": 100, "morale": 100, @@ -153,10 +164,12 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 2, - "luminance": 0, "hp": 300, "death_function": [ "NORMAL" ], - "description": "Look at those TEETH!", + "description": "Look at those teeth! Tiny little claws though.", + "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" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], @@ -172,9 +185,10 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "light_green_magenta", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "6000000 ml", + "weight": 6000000, "material": "flesh", + "diff": 30, "aggression": -50, "morale": 50, "speed": 80, @@ -185,10 +199,12 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 2, - "luminance": 0, "hp": 150, "death_function": [ "NORMAL" ], "description": "A massive rhino-like dinosaur with a bony crest from which three large horns emerge.", + "reproduction": { "baby_egg": "egg_triceratops", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], @@ -203,8 +219,8 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "green_magenta", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "3000000 ml", + "weight": 3000000, "material": "flesh", "aggression": -50, "morale": -20, @@ -216,10 +232,12 @@ "dodge": 1, "armor_bash": 3, "armor_cut": 1, - "luminance": 0, "hp": 150, "death_function": [ "NORMAL" ], "description": "A large quadruped dinosaur with plates on its back, and a spiked tail.", + "reproduction": { "baby_egg": "egg_stegosaurus", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], @@ -234,8 +252,8 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "brown_magenta", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "6000000 ml", + "weight": 6000000, "material": "flesh", "aggression": -50, "morale": 30, @@ -247,10 +265,12 @@ "dodge": 1, "armor_bash": 6, "armor_cut": 4, - "luminance": 0, "hp": 120, "death_function": [ "NORMAL" ], "description": "This dinosaur looks like a giant prehistoric armadillo. Its tail ends in a massive spiked club of bone.", + "reproduction": { "baby_egg": "egg_ankylosaurus", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], @@ -265,8 +285,8 @@ "default_faction": "allosaurus", "symbol": "D", "color": "brown_white", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "1000000 ml", + "weight": 1000000, "material": "flesh", "aggression": 80, "morale": 80, @@ -278,10 +298,12 @@ "dodge": 1, "armor_bash": 3, "armor_cut": 1, - "luminance": 0, "hp": 120, "death_function": [ "NORMAL" ], "description": "A large predatory bipedal dinosaur, with tiger-like stripes on its broad back.", + "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" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], @@ -297,8 +319,8 @@ "default_faction": "eoraptor", "symbol": "D", "color": "dark_gray_yellow", - "volume": "750 ml", - "weight": "1 kg", + "volume": "15000 ml", + "weight": 15000, "material": "flesh", "aggression": -60, "morale": -60, @@ -310,10 +332,12 @@ "dodge": 4, "armor_bash": 1, "armor_cut": 0, - "luminance": 0, "hp": 10, "death_function": [ "NORMAL" ], "description": "A bipedal dinosaur about the size of a chicken. It roots around the undergrowth, scavenging on small animals and plants.", + "reproduction": { "baby_egg": "egg_eoraptor", "baby_count": 3, "baby_timer": 12 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM" ], "harvest": "mammal_tiny", "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "FIRE" ], @@ -327,8 +351,8 @@ "default_faction": "velociraptor", "symbol": "D", "color": "light_red_green", - "volume": "30000 ml", - "weight": "40750 g", + "volume": "15000 ml", + "weight": 15000, "material": "flesh", "aggression": 0, "morale": 20, @@ -340,11 +364,13 @@ "dodge": 3, "armor_bash": 1, "armor_cut": 1, - "luminance": 0, "hp": 30, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], "description": "A small bipedal dinosaur covered with feathers. Small, hooked claws emerge from its feet and hands.", + "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" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], @@ -357,11 +383,11 @@ "id": "mon_deinonychus", "name": { "str": "Deinonychus", "str_pl": "Deinonychus" }, "species": "DINOSAUR", - "default_faction": "deinoychus", + "default_faction": "deinonychus", "symbol": "D", "color": "red_green", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "75000 ml", + "weight": 75000, "material": "flesh", "aggression": 1, "morale": 50, @@ -373,11 +399,13 @@ "dodge": 2, "armor_bash": 1, "armor_cut": 1, - "luminance": 0, "hp": 60, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], "description": "A medium-sized bipedal dinosaur covered with feathers. At the end of each foot is a large sickle-like claw.", + "reproduction": { "baby_egg": "egg_deinonychus", "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" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], @@ -393,8 +421,8 @@ "default_faction": "utahraptor", "symbol": "D", "color": "dark_gray_white", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "500000 ml", + "weight": 500000, "material": "flesh", "aggression": 30, "morale": 80, @@ -406,11 +434,13 @@ "dodge": 1, "armor_bash": 2, "armor_cut": 1, - "luminance": 0, "hp": 100, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], "description": "A large bipedal dinosaur with feathered arms, a long tail, and scythe-like claws.", + "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" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], @@ -426,8 +456,8 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "dark_gray_magenta", - "volume": "875000 ml", - "weight": "200 kg", + "volume": "3500000 ml", + "weight": 3500000, "material": "flesh", "aggression": -40, "morale": -10, @@ -439,48 +469,18 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 4, - "luminance": 0, "hp": 300, "death_function": [ "NORMAL" ], "description": "A huge mottled dinosaur with a blunt head crest. It contentedly strips leaves from a nearby shrub.", + "reproduction": { "baby_egg": "egg_parasaurolophus", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "FIRE" ], "categories": [ "DINOSAUR" ] }, - { - "type": "MONSTER", - "id": "mon_dimorphodon", - "name": "Dimorphodon", - "species": "DINOSAUR", - "default_faction": "dimorphodon", - "symbol": "D", - "color": "light_gray_yellow", - "volume": "30000 ml", - "weight": "40750 g", - "material": "flesh", - "aggression": -80, - "morale": -8, - "speed": 110, - "melee_skill": 5, - "melee_dice": 2, - "melee_dice_sides": 6, - "melee_cut": 0, - "dodge": 3, - "armor_bash": 3, - "armor_cut": 1, - "luminance": 0, - "vision_day": 50, - "hp": 30, - "death_function": [ "NORMAL" ], - "description": "A small flying reptile, circling overhead looking for prey.", - "flags": [ "SEES", "SMELLS", "HEARS", "FLIES", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "BLEED" ], - "harvest": "animal_noskin", - "fear_triggers": [ "PLAYER_CLOSE", "FIRE", "FRIEND_DIED" ], - "placate_triggers": [ "MEAT" ], - "categories": [ "DINOSAUR" ] - }, { "type": "MONSTER", "id": "mon_dilophosaurus", @@ -489,8 +489,8 @@ "default_faction": "dilophosaurus", "symbol": "D", "color": "magenta_green", - "volume": "62500 ml", - "weight": "81500 g", + "volume": "400000 ml", + "weight": 400000, "material": "flesh", "aggression": 10, "morale": 30, @@ -502,11 +502,13 @@ "dodge": 1, "armor_bash": 3, "armor_cut": 1, - "luminance": 0, "hp": 120, "death_function": [ "NORMAL" ], "special_attacks": [ [ "BOOMER", 20 ] ], "description": "A medium dinosaur with a sticky green bile dripping from its teeth.", + "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" ], "harvest": "mammal_leather", "anger_triggers": [ "PLAYER_WEAK", "HURT" ], @@ -514,6 +516,126 @@ "placate_triggers": [ "MEAT" ], "categories": [ "DINOSAUR" ] }, + { + "id": "mon_compsognathus_hatchling", + "type": "MONSTER", + "name": "greenish yellow hatchling", + "description": "A tiny dinosaur hatchling with huge shiny eyes, it could be from a number of different species.", + "default_faction": "compsognathus", + "categories": [ "DINOSAUR" ], + "species": [ "DINOSAUR" ], + "diff": 10, + "volume": "2000 ml", + "weight": 2000, + "hp": 2, + "speed": 60, + "material": [ "flesh" ], + "symbol": "v", + "color": "green_yellow", + "looks_like": "mon_compsognathus", + "aggression": -99, + "morale": -8, + "melee_skill": 1, + "melee_dice": 1, + "melee_dice_sides": 1, + "melee_cut": 1, + "dodge": 1, + "death_function": [ "NORMAL" ], + "upgrades": { "age_grow": 14, "into": "mon_compsognathus" }, + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "CATFOOD" ], + "harvest": "mammal_tiny" + }, + { + "id": "mon_gallimimus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "light green and yellow hatchling", + "upgrades": { "age_grow": 20, "into": "mon_gallimimus" } + }, + { + "id": "mon_spinosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "red and white hatchling", + "upgrades": { "age_grow": 30, "into": "mon_spinosaurus" } + }, + { + "id": "mon_tyrannosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "light red and white hatchling", + "upgrades": { "age_grow": 30, "into": "mon_tyrannosaurus" } + }, + { + "id": "mon_triceratops_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "light green and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_triceratops" } + }, + { + "id": "mon_stegosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "green and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_stegosaurus" } + }, + { + "id": "mon_ankylosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "brown and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_ankylosaurus" } + }, + { + "id": "mon_allosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "brown and white hatchling", + "upgrades": { "age_grow": 30, "into": "mon_allosaurus" } + }, + { + "id": "mon_eoraptor_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and yellow hatchling", + "upgrades": { "age_grow": 10, "into": "mon_eoraptor" } + }, + { + "id": "mon_velociraptor_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and yellow hatchling", + "upgrades": { "age_grow": 20, "into": "mon_velociraptor" } + }, + { + "id": "mon_deinonychus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "red and green hatchling", + "upgrades": { "age_grow": 20, "into": "mon_deinonychus" } + }, + { + "id": "mon_utahraptor_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and white hatchling", + "upgrades": { "age_grow": 20, "into": "mon_utahraptor" } + }, + { + "id": "mon_parasaurolophus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_parasaurolophus" } + }, + { + "id": "mon_dilophosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "magenta and green hatchling", + "upgrades": { "age_grow": 20, "into": "mon_dilophosaurus" } + }, { "type": "monstergroup", "name": "GROUP_DINOSAUR", @@ -521,7 +643,6 @@ "monsters": [ { "monster": "mon_compsognathus", "freq": 100, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_gallimimus", "freq": 50, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, - { "monster": "mon_titanis", "freq": 10, "cost_multiplier": 10 }, { "monster": "mon_spinosaurus", "freq": 1, "cost_multiplier": 50 }, { "monster": "mon_tyrannosaurus", "freq": 1, "cost_multiplier": 40 }, { "monster": "mon_triceratops", "freq": 3, "cost_multiplier": 30, "pack_size": [ 1, 2 ] }, @@ -533,7 +654,6 @@ { "monster": "mon_deinonychus", "freq": 10, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, { "monster": "mon_utahraptor", "freq": 5, "cost_multiplier": 30 }, { "monster": "mon_parasaurolophus", "freq": 3, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_dimorphodon", "freq": 50, "cost_multiplier": 0, "pack_size": [ 2, 4 ] }, { "monster": "mon_dilophosaurus", "freq": 15, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] }, @@ -542,7 +662,6 @@ "name": "GROUP_DINOSAUR_HARMLESS", "default": "mon_null", "monsters": [ - { "monster": "mon_compsognathus", "freq": 100, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_gallimimus", "freq": 50, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, { "monster": "mon_eoraptor", "freq": 20, "cost_multiplier": 0, "pack_size": [ 4, 12 ] } ] @@ -552,7 +671,7 @@ "name": "GROUP_DINOSAUR_DANGEROUS", "default": "mon_null", "monsters": [ - { "monster": "mon_titanis", "freq": 10, "cost_multiplier": 10 }, + { "monster": "mon_compsognathus", "freq": 100, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_allosaurus", "freq": 2, "cost_multiplier": 30 }, { "monster": "mon_velociraptor", "freq": 15, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, { "monster": "mon_deinonychus", "freq": 10, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, @@ -560,12 +679,6 @@ { "monster": "mon_dilophosaurus", "freq": 15, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] }, - { - "type": "monstergroup", - "name": "GROUP_DINOSAUR_FLY", - "default": "mon_null", - "monsters": [ { "monster": "mon_dimorphodon", "freq": 50, "cost_multiplier": 0, "pack_size": [ 2, 4 ] } ] - }, { "type": "monstergroup", "name": "GROUP_DINOSAUR_MEGA_HERBIVORE", @@ -587,11 +700,64 @@ { "monster": "mon_allosaurus", "freq": 2, "cost_multiplier": 30 } ] }, + { + "type": "monstergroup", + "name": "GROUP_FOREST", + "default": "mon_null", + "is_animal": true, + "monsters": [ + { + "monster": "mon_gallimimus", + "freq": 20, + "cost_multiplier": 0, + "pack_size": [ 4, 8 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_stegosaurus", + "freq": 10, + "cost_multiplier": 20, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_ankylosaurus", + "freq": 3, + "cost_multiplier": 20, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_triceratops", + "freq": 10, + "cost_multiplier": 30, + "pack_size": [ 1, 2 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_dilophosaurus", + "freq": 5, + "cost_multiplier": 10, + "pack_size": [ 1, 2 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { "monster": "mon_utahraptor", "freq": 3, "cost_multiplier": 30 }, + { + "monster": "mon_eoraptor", + "freq": 3, + "cost_multiplier": 0, + "pack_size": [ 4, 12 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + } + ] + }, { "type": "monstergroup", "name": "GROUP_SWAMP", "default": "mon_null", + "is_animal": true, "monsters": [ + { "monster": "mon_parasaurolophus", "freq": 30, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, + { "monster": "mon_deinonychus", "freq": 10, "cost_multiplier": 15, "pack_size": [ 2, 3 ] }, { "monster": "mon_spinosaurus", "freq": 1, "cost_multiplier": 50 }, { "monster": "mon_tyrannosaurus", "freq": 1, "cost_multiplier": 40 }, { "monster": "mon_allosaurus", "freq": 2, "cost_multiplier": 30 } @@ -601,17 +767,13 @@ "type": "monstergroup", "name": "GROUP_SEWER", "default": "mon_sewer_rat", + "is_animal": true, "monsters": [ - { "monster": "mon_compsognathus", "freq": 600, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, - { "monster": "mon_gallimimus", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, - { "monster": "mon_titanis", "freq": 150, "cost_multiplier": 10 }, - { "monster": "mon_spinosaurus", "freq": 50, "cost_multiplier": 50 }, - { "monster": "mon_ankylosaurus", "freq": 80, "cost_multiplier": 20 }, + { "monster": "mon_compsognathus", "freq": 300, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_eoraptor", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_velociraptor", "freq": 150, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 2, 3 ] }, { "monster": "mon_utahraptor", "freq": 100, "cost_multiplier": 30 }, - { "monster": "mon_parasaurolophus", "freq": 80, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, { "monster": "mon_dilophosaurus", "freq": 150, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] }, @@ -621,19 +783,18 @@ "is_safe": true, "default": "mon_null", "monsters": [ - { "monster": "mon_compsognathus", "freq": 1, "cost_multiplier": 1, "pack_size": [ 4, 12 ] }, - { "monster": "mon_gallimimus", "freq": 1, "cost_multiplier": 1, "pack_size": [ 4, 8 ] }, - { "monster": "mon_eoraptor", "freq": 1, "cost_multiplier": 1, "pack_size": [ 4, 12 ] } + { "monster": "mon_gallimimus", "freq": 50, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, + { "monster": "mon_eoraptor", "freq": 20, "cost_multiplier": 0, "pack_size": [ 4, 12 ] } ] }, { "type": "monstergroup", "name": "GROUP_CAVE", "default": "mon_null", + "is_animal": true, "monsters": [ { "monster": "mon_compsognathus", "freq": 600, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_gallimimus", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, - { "monster": "mon_titanis", "freq": 150, "cost_multiplier": 10 }, { "monster": "mon_spinosaurus", "freq": 50, "cost_multiplier": 50 }, { "monster": "mon_tyrannosaurus", "freq": 50, "cost_multiplier": 40 }, { "monster": "mon_triceratops", "freq": 80, "cost_multiplier": 30, "pack_size": [ 1, 2 ] }, @@ -642,10 +803,9 @@ { "monster": "mon_allosaurus", "freq": 100, "cost_multiplier": 30 }, { "monster": "mon_eoraptor", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_velociraptor", "freq": 150, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 2, 3 ] }, { "monster": "mon_utahraptor", "freq": 100, "cost_multiplier": 30 }, { "monster": "mon_parasaurolophus", "freq": 80, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_dimorphodon", "freq": 500, "cost_multiplier": 0, "pack_size": [ 2, 4 ] }, { "monster": "mon_dilophosaurus", "freq": 150, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] } diff --git a/data/mods/DinoMod/egg.json b/data/mods/DinoMod/egg.json new file mode 100644 index 0000000000000..e92131e9cd3cf --- /dev/null +++ b/data/mods/DinoMod/egg.json @@ -0,0 +1,108 @@ +[ + { + "type": "COMESTIBLE", + "id": "egg_dino", + "name": "dinosaur egg", + "weight": 75, + "color": "green", + "spoils_in": "14 days", + "comestible_type": "FOOD", + "symbol": "o", + "quench": 4, + "healthy": 1, + "calories": 113, + "description": "Pale, football-shaped egg laid by a dinosaur.", + "price": 500, + "material": "egg", + "volume": 1, + "stack_size": 4, + "fun": -6, + "flags": [ "FREEZERBURN" ], + "rot_spawn": "GROUP_EGG_DINO", + "rot_spawn_chance": 70 + }, + { + "type": "COMESTIBLE", + "id": "egg_compsognathus", + "name": "compsognathus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_gallimimus", + "name": "gallimimus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_spinosaurus", + "name": "spinosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_tyrannosaurus", + "name": "tyrannosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_triceratops", + "name": "triceratops egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_stegosaurus", + "name": "stegosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_ankylosaurus", + "name": "ankylosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_allosaurus", + "name": "allosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_eoraptor", + "name": "eoraptor egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_velociraptor", + "name": "velociraptor egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_deinonychus", + "name": "deinonychus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_utahraptor", + "name": "utahraptor egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_parasaurolophus", + "name": "parasaurolophus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_dilophosaurus", + "name": "dilophosaurus egg", + "copy-from": "egg_dino" + } +] diff --git a/data/mods/DinoMod/forage.json b/data/mods/DinoMod/forage.json new file mode 100644 index 0000000000000..a9f60cbefe80d --- /dev/null +++ b/data/mods/DinoMod/forage.json @@ -0,0 +1,14 @@ +[ + { + "id": "forage_spring", + "type": "item_group", + "subtype": "distribution", + "entries": [ { "item": "egg_dino", "prob": 3, "count-min": 2, "count-max": 5 } ] + }, + { + "id": "forage_summer", + "type": "item_group", + "subtype": "distribution", + "entries": [ { "item": "egg_dino", "prob": 3, "count-min": 2, "count-max": 5 } ] + } +] diff --git a/data/mods/DinoMod/lab_notes.json b/data/mods/DinoMod/lab_notes.json new file mode 100644 index 0000000000000..ae03e7703214b --- /dev/null +++ b/data/mods/DinoMod/lab_notes.json @@ -0,0 +1,10 @@ +{ + "type": "snippet", + "category": "lab_notes", + "text": [ + "Research on our visitors is proceeding nicely. The raptor DNA is of special interest, with some novel protein chains that may lead to medical breakthroughs.", + "Dr. Yoshimi has been reprimanded for unauthorized contact with the procompsignathids. Disgusting behavior, and a terrible example to the junior researchers.", + "Dr. Yoshimi has escaped, along with an unknown number of dinosaurs. Unfortunately, we have bigger problems with XE037.", + "Strange sounds have been reported from the swamp nearby. An enhanced security team was dispatched, but has not returned in 48 hours. The facility is on lockdown. We can’t let them get back in." + ] +} diff --git a/data/mods/DinoMod/monstergroups_egg.json b/data/mods/DinoMod/monstergroups_egg.json new file mode 100644 index 0000000000000..b44b015cc31af --- /dev/null +++ b/data/mods/DinoMod/monstergroups_egg.json @@ -0,0 +1,23 @@ +[ + { + "name": "GROUP_EGG_DINO", + "type": "monstergroup", + "default": "mon_compsognathus_hatchling", + "monsters": [ + { "monster": "mon_compsognathus_hatchling", "freq": 100, "cost_multiplier": 1 }, + { "monster": "mon_gallimimus_hatchling", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_spinosaurus_hatchling", "freq": 1, "cost_multiplier": 1 }, + { "monster": "mon_tyrannosaurus_hatchling", "freq": 1, "cost_multiplier": 1 }, + { "monster": "mon_triceratops_hatchling", "freq": 3, "cost_multiplier": 1 }, + { "monster": "mon_stegosaurus_hatchling", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_ankylosaurus_hatchling", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_allosaurus_hatchling", "freq": 2, "cost_multiplier": 1 }, + { "monster": "mon_eoraptor_hatchling", "freq": 20, "cost_multiplier": 1 }, + { "monster": "mon_velociraptor_hatchling", "freq": 15, "cost_multiplier": 1 }, + { "monster": "mon_deinonychus_hatchling", "freq": 10, "cost_multiplier": 1 }, + { "monster": "mon_utahraptor_hatchling", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_parasaurolophus_hatchling", "freq": 3, "cost_multiplier": 1 }, + { "monster": "mon_dilophosaurus_hatchling", "freq": 15, "cost_multiplier": 1 } + ] + } +] diff --git a/data/mods/DinoMod/recipe_medsandchemicals.json b/data/mods/DinoMod/recipe_medsandchemicals.json new file mode 100644 index 0000000000000..05fe942030cff --- /dev/null +++ b/data/mods/DinoMod/recipe_medsandchemicals.json @@ -0,0 +1,20 @@ +[ + { + "type": "recipe", + "result": "mutagen_raptor", + "category": "CC_CHEM", + "subcategory": "CSC_CHEM_MUTAGEN", + "skill_used": "cooking", + "skills_required": [ "firstaid", 1 ], + "difficulty": 9, + "time": 10000, + "book_learn": [ [ "recipe_raptor", 9 ] ], + "qualities": [ { "id": "CHEM", "level": 3 } ], + "tools": [ [ [ "surface_heat", 25, "LIST" ] ] ], + "components": [ + [ [ "mutagen", 1 ] ], + [ [ "egg_dino", 1 ], [ "egg_velociraptor", 1 ], [ "egg_deinonychus", 1 ], [ "egg_utahraptor", 1 ] ], + [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] + ] + } +] From ae4d3a044d489e8c20e97f2030c398ca92118b5a Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 6 Mar 2020 05:09:21 -0500 Subject: [PATCH 015/219] [Aftershock] Millyficent whately and the migo (#36908) --- data/mods/Aftershock/effects.json | 58 +++ data/mods/Aftershock/items/mutagen.json | 22 ++ .../maps/mapgen/millyficent_lab.json | 335 ++++++++++++++++++ .../Aftershock/maps/overmap_specials.json | 16 + .../mods/Aftershock/maps/overmap_terrain.json | 33 ++ .../mods/Aftershock/mobs/monster_faction.json | 7 + data/mods/Aftershock/mutations/dreams.json | 35 ++ data/mods/Aftershock/mutations/mutations.json | 264 ++++++++++++++ data/mods/Aftershock/npcs/classes.json | 37 ++ data/mods/Aftershock/npcs/factions.json | 70 ++++ .../Aftershock/npcs/whately_dialogue.json | 193 ++++++++++ 11 files changed, 1070 insertions(+) create mode 100644 data/mods/Aftershock/effects.json create mode 100644 data/mods/Aftershock/items/mutagen.json create mode 100644 data/mods/Aftershock/maps/mapgen/millyficent_lab.json create mode 100644 data/mods/Aftershock/mutations/dreams.json create mode 100644 data/mods/Aftershock/npcs/whately_dialogue.json diff --git a/data/mods/Aftershock/effects.json b/data/mods/Aftershock/effects.json new file mode 100644 index 0000000000000..f0a14dc006566 --- /dev/null +++ b/data/mods/Aftershock/effects.json @@ -0,0 +1,58 @@ +[ + { + "id": "fd_migo_atmosphere", + "type": "field_type", + "intensity_levels": [ + { + "name": "foul-smelling air", + "sym": "8", + "dangerous": true, + "effects": [ + { + "effect_id": "migo_atmosphere", + "body_part": "MOUTH", + "intensity": 1, + "min_duration": "5 seconds", + "max_duration": "10 seconds", + "immune_inside_vehicle": true + } + ] + }, + { + "name": "foul-smelling air", + "translucency": 1, + "effects": [ + { + "effect_id": "migo_atmosphere", + "body_part": "MOUTH", + "intensity": 2, + "min_duration": "10 seconds", + "max_duration": "25 seconds" + } + ] + }, + { + "name": "foul-smelling air", + "effects": [ + { + "effect_id": "migo_atmosphere", + "body_part": "MOUTH", + "intensity": 4, + "min_duration": "15 seconds", + "max_duration": "25 seconds" + } + ] + } + ], + "decay_amount_factor": 5, + "gas_absorption_factor": 15, + "percent_spread": 30, + "outdoor_age_speedup": "3 minutes", + "dirty_transparency_cache": true, + "has_fume": true, + "immunity_data": { "body_part_env_resistance": [ [ "MOUTH", 15 ] ], "traits": [ "MIGO_BREATHE" ] }, + "priority": 8, + "half_life": "10 minutes", + "phase": "gas" + } +] diff --git a/data/mods/Aftershock/items/mutagen.json b/data/mods/Aftershock/items/mutagen.json new file mode 100644 index 0000000000000..b17547f34c6cd --- /dev/null +++ b/data/mods/Aftershock/items/mutagen.json @@ -0,0 +1,22 @@ +[ + { + "id": "iv_mutagen_migo", + "copy-from": "iv_mutagen_flavor", + "type": "COMESTIBLE", + "name": "mi-go serum", + "description": "A super-concentrated mutagen strongly resembling a lava lamp. You need a syringe to inject it… if you really want to?", + "price": 1000000, + "color": "red", + "healthy": -4, + "use_action": { "type": "mutagen_iv", "mutation_category": "MIGO" } + }, + { + "id": "mutagen_migo", + "copy-from": "mutagen_flavor", + "type": "COMESTIBLE", + "name": "mi-go mutagen", + "description": "An extremely rare mutagen cocktail, it smells of sulphur and glows orange.", + "price": 500000, + "use_action": { "type": "mutagen", "mutation_category": "MIGO" } + } +] diff --git a/data/mods/Aftershock/maps/mapgen/millyficent_lab.json b/data/mods/Aftershock/maps/mapgen/millyficent_lab.json new file mode 100644 index 0000000000000..820ffad36f229 --- /dev/null +++ b/data/mods/Aftershock/maps/mapgen/millyficent_lab.json @@ -0,0 +1,335 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "mortuary_2story" ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + "..,,,,,...uuuu...,,,,,..", + "..,,,,,..uaaaau..,,,,,..", + "..,,,,,.uaffffau.,,,,,..", + "..,,,,,..uuuuuu..,,,,,..", + "..,,,,,..........,,,,,..", + "..,,,,,,........,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "...,,,,,,,,,,,,,,,,,,...", + "....uuuu.|o++o|.uuuu....", + "..|-oooo-|P P|-oooo-|u.", + "..oP cc P|H H| |fu", + "|-|c c|H H| H H ofu", + "|&|c c| | H H |fu", + "| + + DD + H H P|u.", + "|i|D ll P|P hP| H H C|..", + "--|------|-++-| H H P|u.", + ".4|dT~T~i|C O| |fu", + "..|------|-++-|-o--o-|u.", + ".........u.,,.u........." + ], + "terrain": { + " ": "t_floor", + "*": "t_door_locked_interior", + "+": "t_door_c", + ",": "t_pavement", + "-": "t_wall_w", + ".": "t_grass", + "L": "t_linoleum_white", + "T": "t_linoleum_white", + "a": "t_dirt", + "d": "t_linoleum_white", + "f": "t_dirt", + "i": "t_linoleum_white", + "o": "t_window_bars_curtains", + "u": "t_shrub", + "|": "t_wall_w", + "~": "t_linoleum_white", + "4": "t_gutter_downspout", + ">": "t_wood_stairs_down", + "<": "t_wood_stairs_up" + }, + "toilets": { "&": { "amount": [ 0, 50 ] } }, + "furniture": { + "C": "f_coffin_c", + "D": "f_desk", + "H": "f_bench", + "h": "f_chair", + "L": "f_locker", + "O": "f_coffin_o", + "P": [ "f_indoor_plant_y", "f_indoor_plant" ], + "T": "f_table", + "a": "f_dahlia", + "c": "f_sofa", + "d": "f_rack", + "f": [ "f_datura", "f_bluebell", "f_mutpoppy", "f_dahlia", "f_flower_tulip", "f_chamomile", "f_flower_spurge", "f_lily" ], + "i": "f_sink", + "l": "f_bookcase" + }, + "place_signs": [ { "signage": "Whately Family Mortuary Services. Serving New England for three hundred years.'", "x": 15, "y": 11 } ], + "place_items": [ + { "item": "cleaning", "x": 3, "y": [ 19, 20 ], "chance": 50 }, + { "item": "dissection", "x": 3, "y": 21, "chance": 70 }, + { "item": "church", "x": [ 16, 18 ], "y": [ 14, 20 ], "chance": 50 }, + { "item": "lab_torso", "x": 8, "y": 19, "chance": 50 }, + { "item": "bionics_common", "x": 8, "y": 19, "chance": 30 }, + { "item": "homebooks", "x": [ 5, 6 ], "y": 17, "chance": 50 }, + { "item": "magazines", "x": 3, "y": 17, "chance": 50 } + ], + "place_loot": [ + { "group": "corpse_male_mortuary", "x": 4, "y": 19, "chance": 40 }, + { "group": "corpse_female_mortuary", "x": 6, "y": 19, "chance": 40 }, + { "group": "corpse_female_mortuary", "x": 6, "y": 21, "chance": 40 }, + { "group": "corpse_viewing", "x": 20, "y": 17, "chance": 50 } + ], + "place_vehicles": [ { "vehicle": "hearse", "x": 12, "y": 7, "chance": 90 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "mortuary_basement" ], + "weight": 200, + "object": { + "rotation": [ 0, 3 ], + "fill_ter": "t_rock", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " |||||||||||| ", + " |T8T5CfHH??| ", + " |,h,,,,,,,?| ", + " |n,,,*,,???| ", + " ||||,,,,|||| ", + " |ffG,,,,ACA| ", + " ||||,,,,,,,,,,||||| ", + " |&_+*,,,,,*,TTT|EWU| ", + " |i_|,,TT,,,,,,+_*_| ", + " |||||+||,,||+|||||| ", + " |i,A,F|++|U__XU| ", + " |D,*,T|..|U_*_c| ", + " |b,,hT|<<|U___c| ", + " |b,n,T||||U_U_U| ", + " ||||||| ||||||| ", + " ", + " ", + " " + ], + "terrain": { + "|": "t_wall", + "<": "t_stairs_up", + "+": "t_door_c", + ".": "t_floor", + "_": "t_linoleum_gray", + "c": "t_linoleum_gray", + "U": "t_linoleum_gray", + "X": "t_linoleum_gray", + "E": "t_linoleum_gray", + "i": "t_linoleum_gray", + "&": "t_linoleum_gray", + ",": "t_linoleum_white", + "C": "t_linoleum_white", + "?": "t_linoleum_white", + "A": "t_linoleum_white", + "h": "t_linoleum_white", + "D": "t_linoleum_white", + "5": "t_linoleum_white", + "F": "t_linoleum_white", + "f": "t_linoleum_white", + "G": "t_linoleum_white", + "b": "t_linoleum_white", + "n": "t_linoleum_white", + "H": "t_linoleum_white", + "T": "t_linoleum_white", + "8": "t_console_broken", + "W": "t_water_dispenser", + "*": "t_utility_light" + }, + "liquids": { "E": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, + "furniture": { + "T": "f_workbench", + "G": "f_glass_cabinet", + "c": "f_counter", + "h": "f_chair", + "A": "f_air_filter", + "C": "f_air_conditioner", + "E": "f_water_heater", + "X": [ "f_crate_c", "f_crate_o", "f_cardboard_box" ], + "U": "f_utility_shelf", + "H": "f_bookcase", + "F": "f_glass_fridge", + "i": "f_sink", + "?": "f_sofa", + "n": "f_trashcan", + "f": "f_filing_cabinet", + "5": "f_server", + "b": "f_lab_bench", + "D": "f_fume_hood" + }, + "items": { + "U": [ + { "item": "cleaning", "chance": 30 }, + { "item": "supplies_reagents_lab", "chance": 10 }, + { "item": "home_hw", "chance": 50 }, + { "item": "supplies_electronics", "chance": 50 } + ], + "c": [ { "item": "home_hw", "chance": 70 } ], + "X": [ { "item": "electronics", "chance": 70 } ], + "b": [ { "item": "chem_home", "chance": 30 } ], + "D": [ { "item": "chem_home", "chance": 60 } ], + "i": [ { "item": "trash", "chance": 60 } ], + "F": [ { "item": "chem_home", "chance": 50 }, { "item": "supplies_reagents_lab", "chance": 20 } ], + "T": [ { "item": "chem_home", "chance": 30 }, { "item": "electronics", "chance": 50 } ], + "f": [ { "item": "file_room", "chance": 70, "repeat": [ 1, 5 ] } ], + "G": [ { "item": "office_paper", "chance": 30 } ], + "H": [ { "item": "magazines", "chance": 40, "repeat": [ 1, 2 ] }, { "item": "lab_bookshelves", "chance": 20 } ] + }, + "toilets": { "&": { "amount": [ 0, 50 ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "mortuary_2story_second" ], + "object": { + "fill_ter": "t_open_air", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________|w||w|_________", + "__||wwww||%%%%||wwww||__", + "__wZZil.b|%%%%|8....1|__", + "|||ZZ..cb|%%%%|F.....w__", + "|&|A....b|%%%%|e.....|__", + "|%+......+%%%%m.....1|__", + "|S|D ll P|%%%%|E.....|__", + "||||||||||:++:|h.....|__", + "__|BB>CoC|1..t|a....1|__", + "__|B..*..+.*st|o.....w__", + "__|TBBfiB|1..t|......|__", + "__||||||||||||||w||w||__", + "________________________" + ], + "toilets": { "&": { } }, + "terrain": { + ".": "t_floor", + "#": "t_brick_wall", + "|": "t_strconc_wall", + " ": "t_strconc_floor", + "%": "t_linoleum_white", + "+": "t_door_c", + "-": "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", + "*": "t_utility_light", + "w": "t_window_bars_curtains", + ">": "t_wood_stairs_down" + }, + "furniture": { + "T": "f_trashcan", + "1": [ "f_indoor_plant", "f_indoor_plant_y" ], + "5": "f_server", + "8": "f_sample_freezer", + "a": "f_autoclave", + "A": "f_air_filter", + "b": "f_lab_bench", + "B": "f_bookcase", + "C": "f_counter", + "c": "f_chair", + "d": "f_desk", + "D": "f_dishwasher", + "e": "f_eyewash", + "E": "f_electron_microscope", + "F": "f_fume_hood", + "f": "f_fridge", + "G": "f_GC", + "h": "f_shaker", + "H": "f_HPLC", + "i": "f_filing_cabinet", + "I": "f_scan_bed", + "l": "f_locker", + "M": "f_MS", + "N": "f_NMR", + "O": "f_MRI", + "0": "f_CTscan", + "r": "f_rack", + "s": "f_stool", + "S": "f_sink", + "t": "f_table", + "U": "f_utility_shelf", + "v": "f_ventilator", + "Z": "f_bed" + }, + "place_npcs": [ { "class": "millyficent_whately", "x": 17, "y": 14 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "mortuary_2story_roof", + "object": { + "fill_ter": "t_flat_roof", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |22223 ", + " |222222|....|2222223 ", + " |..................3 ", + "|2|..................3 ", + "|....................3 ", + "|.U..................3 ", + "|....................3 ", + "--5..................3 ", + " |..................3 ", + " |..................3 ", + " |..................3 ", + " |------------------3 ", + " " + ], + "palettes": [ "roof_palette" ], + "nested": { "U": { "chunks": [ "roof_2x2_infrastructure" ] } }, + "place_nested": [ + { + "chunks": [ + [ "null", 20 ], + [ "roof_2x2_utilities_b", 15 ], + [ "roof_2x2_utilities_c", 5 ], + [ "roof_2x2_utilities_d", 40 ], + [ "roof_2x2_utilities", 50 ] + ], + "x": [ 4, 17 ], + "y": [ 14, 19 ] + } + ] + } + } +] diff --git a/data/mods/Aftershock/maps/overmap_specials.json b/data/mods/Aftershock/maps/overmap_specials.json index 4925449cd2642..71cb777cac0dd 100644 --- a/data/mods/Aftershock/maps/overmap_specials.json +++ b/data/mods/Aftershock/maps/overmap_specials.json @@ -45,5 +45,21 @@ "flags": [ "FUNGAL" ], "rotate": false, "spawns": { "group": "GROUP_FUNGI_TOWER", "population": [ 125, 175 ], "radius": [ 2, 2 ] } + }, + { + "type": "overmap_special", + "id": "mortuary_2story", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "mortuary_2story_north" }, + { "point": [ 0, 0, 1 ], "overmap": "mortuary_2story_second_north" }, + { "point": [ 0, 0, -1 ], "overmap": "mortuary_basement_north" }, + { "point": [ 0, 0, 2 ], "overmap": "mortuary_roof_north" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road" } ], + "locations": [ "land" ], + "city_distance": [ 5, -1 ], + "city_sizes": [ 2, -1 ], + "occurrences": [ 0, 1 ], + "flags": [ "CLASSIC" ] } ] diff --git a/data/mods/Aftershock/maps/overmap_terrain.json b/data/mods/Aftershock/maps/overmap_terrain.json index 0fb0e584e5349..0361a3988aee4 100644 --- a/data/mods/Aftershock/maps/overmap_terrain.json +++ b/data/mods/Aftershock/maps/overmap_terrain.json @@ -73,5 +73,38 @@ "see_cost": 3, "extras": "marloss", "flags": [ "NO_ROTATE", "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "mortuary_2story", + "name": "county mortuary", + "sym": "M", + "color": "light_green", + "see_cost": 3, + "flags": [ "SIDEWALK" ] + }, + { + "type": "overmap_terrain", + "id": "mortuary_basement", + "name": "county mortuary basement", + "sym": "M", + "color": "white", + "see_cost": 3 + }, + { + "type": "overmap_terrain", + "id": "mortuary_2story_second", + "name": "county mortuary second floor", + "sym": "M", + "color": "light_green", + "see_cost": 3 + }, + { + "type": "overmap_terrain", + "id": "mortuary_2story_roof", + "name": "county mortuary roof", + "sym": "M", + "color": "light_green", + "see_cost": 3 } ] diff --git a/data/mods/Aftershock/mobs/monster_faction.json b/data/mods/Aftershock/mobs/monster_faction.json index 1c23ef23ed06d..91b25239f299d 100644 --- a/data/mods/Aftershock/mobs/monster_faction.json +++ b/data/mods/Aftershock/mobs/monster_faction.json @@ -5,5 +5,12 @@ "friendly": [ "Prepnet_Phyle", "human", "PrepNet", "player" ], "neutral": "herbivore", "by_mood": [ "insect", "small_animal" ] + }, + { + "type": "MONSTER_FACTION", + "name": "whately", + "friendly": [ "human", "player" ], + "neutral": "herbivore", + "by_mood": [ "insect", "small_animal" ] } ] diff --git a/data/mods/Aftershock/mutations/dreams.json b/data/mods/Aftershock/mutations/dreams.json new file mode 100644 index 0000000000000..8d9c5a3928e8c --- /dev/null +++ b/data/mods/Aftershock/mutations/dreams.json @@ -0,0 +1,35 @@ +[ + { + "type": "dream", + "messages": [ "You dream of warm, alien winds.", "You dream of landscapes lit by the light of alien moons." ], + "category": "MIGO", + "strength": 1 + }, + { + "type": "dream", + "messages": [ + "You stand at the edge of a fissure into strange earth. Mustard brown gasses caress and lift your fronds", + "You dream of being vivsected by humans. One asks if the other thinks you can feel pain." + ], + "category": "MIGO", + "strength": 2 + }, + { + "type": "dream", + "messages": [ + "Trapped in a cage, you mimic the sounds of your guard's spawn. He threatens you and enters the cage. He screams, you recall.", + "It's your birthday. But everyone has given you these hideous metal and plastic objects." + ], + "category": "MIGO", + "strength": 3 + }, + { + "type": "dream", + "messages": [ + "The stars await you, your chariot of fire is ready. The holds are full of slaves.", + "You have transitioned from a dying race to a glorious future." + ], + "category": "MIGO", + "strength": 4 + } +] diff --git a/data/mods/Aftershock/mutations/mutations.json b/data/mods/Aftershock/mutations/mutations.json index f20602050727b..79c6da950a6d4 100644 --- a/data/mods/Aftershock/mutations/mutations.json +++ b/data/mods/Aftershock/mutations/mutations.json @@ -8,5 +8,269 @@ "description": "NPC trait that makes monsters see it as a Prepnet. It is a bug if you have it.", "player_display": false, "threshold": true + }, + { + "type": "mutation_category", + "id": "MIGO", + "name": "YUGGOTH", + "threshold_mut": "THRESH_YUGGOTH", + "mutagen_message": "Strange memories of another world overwhelm you…", + "iv_message": "You look into your own cells and change them.", + "iv_pain": 10, + "iv_morale": 25, + "iv_morale_max": 100, + "iv_sleep": true, + "//": "Should be out for two minutes. Nightmare realm becomes home", + "iv_sleep_dur": 20, + "iv_sleep_message": "You gaze inside, past your fear, past good and evil, into the future.", + "memorial_message": "Prepared the way into the galaxy." + }, + { + "type": "mutation", + "id": "MIGO_HEAT_RESIST", + "name": "Mi-go acclimatization", + "points": 4, + "bodytemp_modifiers": [ -2500, -6500 ], + "description": "Fleshy fronds grown from your scalp function like organic heat sinks. They allow you to live comfortably within the mi-go atmosphere.", + "player_display": true, + "threshreq": [ "THRESH_YUGGOTH" ], + "starting_trait": false, + "types": [ "METABOLISM" ], + "active": true, + "category": [ "MIGO" ], + "prereqs": [ "WARM_NATURED" ] + }, + { + "type": "mutation", + "id": "FACIAL_TENTACLES", + "name": "Facial Tentacles", + "points": 1, + "visibility": 8, + "ugliness": 5, + "description": "A set of tentacles surrounds your mouth. They allow you to eat twice as fast. Slightly decreases wet penalties.", + "prereqs": [ "MOUTH_TENDRILS" ], + "cancels": [ "MANDIBLES" ], + "category": [ "MIGO" ], + "wet_protection": [ { "part": "MOUTH", "neutral": 4 } ] + }, + { + "type": "mutation", + "id": "MOUTH_TENDRILS", + "name": "Mouth Tendrils", + "points": -1, + "visibility": 7, + "ugliness": 6, + "description": "Skin tabs and odd flaps of skin surround your mouth. They don't affect your eating, but are unpleasant to look at.", + "category": [ "MIGO" ], + "leads_to": [ "FACIAL_TENTACLES" ] + }, + { + "type": "mutation", + "id": "WARM_NATURED", + "name": "Warm Natured", + "points": 2, + "description": "Your body becomes much more efficient at distributing heat from itself.", + "category": [ "MIGO" ], + "leads_to": [ "MIGO_HEAT_RESIST" ], + "bodytemp_modifiers": [ -500, -1250 ] + }, + { + "type": "mutation", + "id": "NEURAL_IMPROVEMENT", + "name": "Neural Improvement", + "points": 1, + "description": "You see the world a little differently today. Intelligence + 1", + "changes_to": [ "EXPANDED_CONSCIOUSNESS" ], + "category": [ "MIGO" ], + "passive_mods": { "int_mod": 1 } + }, + { + "type": "mutation", + "id": "EXPANDED_CONSCIOUSNESS", + "name": "Expanded Consciousness", + "points": 2, + "description": "You are beginning to see a way off this planet. Intelligence + 2", + "prereqs": [ "NEURAL_IMPROVEMENT" ], + "changes_to": [ "UPLIFTED" ], + "category": [ "MIGO" ], + "passive_mods": { "int_mod": 2 } + }, + { + "type": "mutation", + "id": "UPLIFTED", + "name": "Extremely Smart", + "points": 3, + "visibility": 1, + "ugliness": 1, + "description": "As humans uplifted our pets in the final years this process is lifting you to a new level of intelligence. Intelligence + 4", + "prereqs": [ "EXPANDED_CONSCIOUSNESS" ], + "changes_to": [ "ALIEN_INT" ], + "category": [ "MIGO" ], + "passive_mods": { "int_mod": 4 } + }, + { + "type": "mutation", + "id": "ALIEN_INT", + "name": "Alien Intelligence", + "points": 3, + "visibility": 3, + "ugliness": 6, + "description": "You can see the connections from A to B to C to D. You look at fellow survivors like you are imagining taking them apart. Intelligence + 5", + "prereqs": [ "UPLIFTED" ], + "category": [ "MIGO" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "starting_trait": false, + "passive_mods": { "int_mod": 5 } + }, + { + "type": "mutation", + "id": "ENHANCED_REACTIONS", + "name": "Enhanced Reactions", + "points": 1, + "description": "Today is the day to start juggling. Dexterity + 1", + "changes_to": [ "QUICKENING" ], + "category": [ "MIGO" ], + "passive_mods": { "dex_mod": 1 } + }, + { + "type": "mutation", + "id": "QUICKENING", + "name": "Quickening", + "points": 2, + "description": "You are starting to move like they do. Dexterity + 2", + "prereqs": [ "ENHANCED_REACTIONS" ], + "changes_to": [ "OTHERWORLDLY_GRACE" ], + "category": [ "MIGO" ], + "passive_mods": { "dex_mod": 2 } + }, + { + "type": "mutation", + "id": "OTHERWORLDLY_GRACE", + "name": "Otherworldly Grace", + "points": 3, + "description": "You no longer move like a human, others find it disconcerting. Dexterity + 4", + "prereqs": [ "ENHANCED_REACTIONS" ], + "category": [ "MIGO" ], + "passive_mods": { "dex_mod": 4 } + }, + { + "type": "mutation", + "id": "NEW_MUSCLES", + "name": "New Muscles", + "points": 1, + "description": "You see some new muscles that you aren't sure you've seen on humans before. Strength + 1", + "changes_to": [ "MUSCLE_FIBER" ], + "category": [ "MIGO" ], + "passive_mods": { "str_mod": 1 } + }, + { + "type": "mutation", + "id": "MUSCLE_FIBER", + "name": "Muscle Fiber", + "points": 2, + "description": "Fibrous tissue seems to be spreading through your body. Strength + 2", + "prereqs": [ "STR_UP" ], + "category": [ "MIGO" ], + "passive_mods": { "str_mod": 2 } + }, + { + "type": "mutation", + "id": "MIGO_EARS", + "name": "Mi-go Ears", + "points": 1, + "visibility": 4, + "description": "Your ears have split into a series of tuberous projections. They waggle towards far away sounds.", + "types": [ "EARS" ], + "category": [ "MIGO" ], + "hearing_modifier": 1.4 + }, + { + "type": "mutation", + "id": "DETACHMENT", + "name": "Detachment", + "points": 2, + "flags": [ "PRED1" ], + "description": "When were you ever like these creatures, helpless before the changes ravaging this world. ", + "purifiable": false, + "changes_to": [ "PRED2" ], + "prereqs": [ "THRESH_YUGGOTH" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "cancels": [ "PACIFIST" ], + "category": [ "MIGO" ] + }, + { + "type": "mutation", + "id": "ELDRITCH", + "name": "Eldritch", + "points": 3, + "description": "You have a sinister aspect to your demeanor, no longer part of this world. You feel no sorrow at the deaths of humans and your brain now processes combat skills more efficiently as you mentally dissect your opponents.", + "social_modifiers": { "intimidate": 3 }, + "purifiable": false, + "flags": [ "PRED1" ], + "prereqs": [ "THRESH_YUGGOTH" ], + "prereqs2": [ "DETACHMENT" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "cancels": [ "PACIFIST" ], + "category": [ "MIGO" ] + }, + { + "type": "mutation", + "id": "THRESH_YUGGOTH", + "name": "YUGGOTH", + "points": 1, + "description": "This death throes of this world are the birthing pangs of yours.", + "valid": false, + "purifiable": false, + "threshold": true + }, + { + "type": "mutation", + "id": "MIGO_SCENT", + "name": "Fetid scent", + "points": 6, + "description": "Your sweat now smells otherworldly, and not in a good way. The mi-go still hate you but at least they aren't offended by your smell. ", + "valid": false, + "purifiable": false, + "types": [ "LEGS" ], + "prereqs": [ "SMELLY", "SMELLY2" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "category": [ "MIGO" ], + "scent_type": "sc_fetid" + }, + { + "type": "mutation", + "id": "EERIE", + "name": "Eerie", + "points": 1, + "description": "You are offputting to others. You're mannerisms have changed as if human interaction is becoming foreign.", + "category": [ "MIGO" ], + "social_modifiers": { "intimidate": 15 } + }, + { + "type": "mutation", + "id": "WINGS_migo", + "name": "Mi-go Wings", + "points": 1, + "visibility": 4, + "ugliness": 8, + "description": "You have a pair of large, veiny wings. They don't appear to be made for this atmosphere but they grant a powerful buffeting attack.", + "types": [ "WINGS" ], + "prereqs": [ "WINGS_STUB" ], + "category": [ "MIGO" ], + "attacks": { + "attack_text_u": "You buffet %s with your wings", + "attack_text_npc": "%1$s buffets %2$s with their wings", + "chance": 20, + "base_damage": { "damage_type": "bash", "amount": 26 } + } + }, + { + "type": "mutation", + "id": "MIGO_BREATHE", + "name": "Mi-go breathe", + "points": 4, + "description": "You can now breathe the gasses the mi-go thrive in.", + "starting_trait": false, + "category": [ "MIGO" ] } ] diff --git a/data/mods/Aftershock/npcs/classes.json b/data/mods/Aftershock/npcs/classes.json index b1c8d915a4610..53ea486f9e5a5 100644 --- a/data/mods/Aftershock/npcs/classes.json +++ b/data/mods/Aftershock/npcs/classes.json @@ -41,5 +41,42 @@ { "id": "bio_tools", "chance": 100 }, { "id": "bio_torsionratchet", "chance": 100 } ] + }, + { + "type": "npc", + "id": "millyficent_whately", + "name_unique": "Millyficen Whately", + "name_suffix": "Xenobiologist, madwoman", + "class": "afs_xenobiologist_madwoman", + "attitude": 0, + "mission": 7, + "chat": "TALK_Millyficent_1", + "mission_offered": "MISSION_migo_biology_1", + "faction": "whately_family" + }, + { + "type": "npc_class", + "id": "afs_xenobiologist_madwoman", + "name": "mi-go enthusiast", + "job_description": "I've been studying the mi-go for years…", + "common": false, + "traits": [ + [ "hair_red_long", 100 ], + [ "SKIN_LIGHT", 100 ], + [ "WARM_NATURED", 100 ], + [ "INT_UP_3", 100 ], + [ "DEX_UP_2", 100 ], + [ "STR_UP", 100 ], + { "group": "Appearance_demographics", "prob": 100 } + ], + "bonus_dex": { "rng": [ -1, 0 ] }, + "bonus_int": { "rng": [ 2, 5 ] }, + "skills": [ + { "skill": "ALL", "level": { "mul": [ { "one_in": 3 }, { "sum": [ { "dice": [ 2, 2 ] }, { "constant": -4 } ] } ] } }, + { "skill": "computer", "bonus": { "rng": [ 1, 5 ] } }, + { "skill": "electronics", "bonus": { "rng": [ 1, 5 ] } }, + { "skill": "firstaid", "bonus": { "rng": [ 1, 4 ] } }, + { "skill": "cooking", "bonus": { "rng": [ 6, 8 ] } } + ] } ] diff --git a/data/mods/Aftershock/npcs/factions.json b/data/mods/Aftershock/npcs/factions.json index 4df287e763e82..82862cff9bdda 100644 --- a/data/mods/Aftershock/npcs/factions.json +++ b/data/mods/Aftershock/npcs/factions.json @@ -69,5 +69,75 @@ "marloss": { "kill on sight": true } }, "description": "A group of bionic preppers who had expected the collapse of the economy and global chaos, instead they were slightly more ready than others for the Cataclysm." + }, + { + "type": "faction", + "id": "whately_family", + "name": "Whately Family", + "mon_faction": "whately", + "likes_u": 0, + "respects_u": 0, + "known_by_u": false, + "size": 15, + "power": 20, + "food_supply": 1200, + "wealth": 7500, + "relations": { + "free_merchants": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": true, + "defends your space": false, + "knows your voice": true + }, + "old_guard": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": false, + "defends your space": false, + "knows your voice": false + }, + "tacoma_commune": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": true, + "defends your space": false + }, + "lobby_beggars": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": true, + "lets you in": false, + "defends your space": false + }, + "no_faction": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": false, + "defends your space": false, + "knows your voice": true + }, + "wasteland_scavengers": { + "kill on sight": false, + "watch your back": true, + "share my stuff": false, + "guard your stuff": true, + "lets you in": false, + "defends your space": false, + "knows your voice": true + }, + "hells_raiders": { "kill on sight": true }, + "marloss": { "kill on sight": true } + }, + "description": "The Whately's are an old New England family of eccentrics. Eccentrics being the kind words used about them." } ] diff --git a/data/mods/Aftershock/npcs/whately_dialogue.json b/data/mods/Aftershock/npcs/whately_dialogue.json new file mode 100644 index 0000000000000..cb9a3470e2877 --- /dev/null +++ b/data/mods/Aftershock/npcs/whately_dialogue.json @@ -0,0 +1,193 @@ +[ + { + "type": "effect_type", + "id": "u_met_millyficent" + }, + { + "type": "talk_topic", + "id": "TALK_Millyficent_1", + "dynamic_line": { + "u_has_var": "u_met_millyficent", + "type": "general", + "context": "meeting", + "value": "yes", + "yes": [ "What did you bring me?", "Hello.", "How are you?", "Welcome!", "Do you smell something?" ], + "no": "New test subjects! I'm so glad you showed up!" + }, + "responses": [ + { + "text": "Who are you?", + "effect": { "u_add_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "condition": { "not": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" } }, + "topic": "TALK_millyficent_firstmeet" + }, + { + "text": "What is this place?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_millyficent_place" + }, + { + "text": "How did you get here?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_millyficent_ask_past" + }, + { + "text": "How are things here?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_millyficent_ask_mood" + }, + { + "text": "Can I do anything for you? Do I want to?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_MISSION_LIST" + }, + { "text": "I'm going on my way now.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_firstmeet", + "dynamic_line": "Millyficent Whately. I'm so glad you finally arrived. It's been a while since I last received new lab partners.", + "responses": [ + { "text": "I'm so hungry, can you help me?", "topic": "TALK_millyficent_food" }, + { "text": "You are aware of the Cataclysm?", "topic": "TALK_millyficent_cataclysm" }, + { "text": "I am your new lab partner.", "topic": "TALK_Millyficent_1" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_place", + "dynamic_line": "Welcome to my lab! Here we explore the boundaries of the possible beyond the reach of small minds.", + "responses": [ + { "text": "Can you give me something to eat then?", "topic": "TALK_millyficent_food" }, + { "text": "Oh, okay.", "topic": "TALK_Millyficent_1" }, + { "text": "I think there's been a mistake.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_food", + "dynamic_line": "No, no, no! No food without succesfully completed experiments. We mustn't break the contract!", + "responses": [ + { "text": "What do I have to do?", "topic": "TALK_MISSION_LIST" }, + { "text": "I don't think you are well.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_ask_past", + "dynamic_line": "Well after I did my graduate thesis on theoretical xenobiology the government hired me to join the most interesting program. Yes there were deaths but we learned so much.", + "responses": [ { "text": "Let's talk about something else.", "topic": "TALK_Millyficent_1" } ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_cataclysm", + "dynamic_line": "What I know is that I pay well for test subjects and I deliver results and at this rate we will not be releasing on time!", + "responses": [ { "text": "Let's talk about something else.", "topic": "TALK_Millyficent_1" } ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_ask_mood", + "dynamic_line": "Ever since they moved me to my own lab my research has progressed so much faster.", + "responses": [ { "text": "This is not reassuring.", "topic": "TALK_Millyficent_1" } ] + }, + { + "id": "MISSION_migo_biology_1", + "type": "mission_definition", + "name": "Migo biology", + "description": "Find fetid goop.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 5, + "value": 0, + "item": "fetid_goop", + "count": 14, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_migo_biology_2", + "dialogue": { + "describe": "I need 14 fetid goops from mi-go locations.", + "offer": "My experiments are at a critical point. Could you find about… 14 fetid goops for me?", + "accepted": "Don't forget to tell me when you have them.", + "rejected": "Then why are you even here? Just let me know if you reconsider.", + "advice": "Find a mi-go base, find a way inside, smash things until you find what I need.", + "inquire": "Why aren't you done yet?", + "success": "Taste this.", + "success_lie": "Thanks for trying… I guess.", + "failure": "You are holding back the evolution of the human race." + }, + "end": { "effect": [ { "u_buy_item": "mutagen_migo", "container": "flask_glass", "count": 1 } ] } + }, + { + "id": "MISSION_migo_biology_2", + "type": "mission_definition", + "name": "Migo Resin", + "description": "Find 56 chunks of mi-go resin.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 6, + "value": 0, + "item": "resin_chunk", + "count": 50, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_migo_biology_3", + "dialogue": { + "describe": "I need 56 chunks of mi-go resin.", + "offer": "I need to understand more about their environment and how they create it. This research wasn't even possible previously. Bring me fifty six chunks of mi-go resin.", + "accepted": "My notes suggest that their building materials are alive. I need you to help me confirm that.", + "rejected": "You can't just walk away from this. We're changing the world!", + "advice": "Find their buildings, jackhammer them. What did you do before the world changed for the better, cold call salesman?", + "inquire": "Have you found my resin?", + "success": "Drink this.", + "success_lie": "Did you act on Broadway? Because I bet that skill isn't useful anymore.", + "failure": "I wonder if I could trade you to them for what I need?" + }, + "end": { "effect": [ { "u_buy_item": "mutagen_migo", "container": "flask_glass", "count": 1 } ] } + }, + { + "id": "MISSION_migo_biology_3", + "type": "mission_definition", + "name": "Mutagen", + "description": "Bring me 3 mutagen.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 3, + "value": 0, + "item": "mutagen", + "count": 3, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_migo_biology_4", + "dialogue": { + "describe": "I need three mutagen.", + "offer": "I need some mutagen and I don't want to spend the time making it myself. Bring me three doses, if you would be so kind.", + "accepted": "Mutagen makes the world go round, it's definitely more valuable than love.", + "rejected": "Are you scared of where I'm taking you?", + "advice": "If you can't make it yourself go hit up a government lab. Be prepared for anything in there.", + "inquire": "Mutagen? Why are you in front of me if not?", + "success": "I've got something more potent for you this time.", + "success_lie": "Lies and the lying liars who tell them.", + "failure": "You are keeping me from my experiments. Would you like to become one?" + }, + "end": { "effect": [ { "u_buy_item": "iv_mutagen_migo", "container": "flask_glass", "count": 1 } ] } + }, + { + "id": "MISSION_migo_biology_4", + "type": "mission_definition", + "name": "Humming Hearts", + "description": "Find 2 humming hearts.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 8, + "value": 0, + "item": "humming_heart", + "count": 2, + "origins": [ "ORIGIN_SECONDARY" ], + "dialogue": { + "describe": "Parts, parts, parts. Bring me some hearts. ", + "offer": "The Whately's are known in these parts for gathering body parts. Ha! That's just rumors and hearsay. But I do need two humming hearts.", + "accepted": "I have some relatives you should meet, if you don't mind hard work for the advancement of science.", + "rejected": "Even I understand this is dangerous.", + "advice": "Brain blasters, that's what I call them. Some kind of automated weapon system the mi-go use.", + "inquire": "They speak sometimes. I wonder if they still think.", + "success": "Let's see what improvements we can divine from these beauties.", + "success_lie": "Thanks for trying… I guess.", + "failure": "I can't be Dr Frankenstein unless you get me these." + }, + "end": { "effect": [ { "u_buy_item": "mutagen_migo", "container": "flask_glass", "count": 2 } ] } + } +] From e794245a1c627b630db60a9e9d29498b68335dd9 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 6 Mar 2020 05:29:40 -0500 Subject: [PATCH 016/219] [Aftershock] Mutant npcs to aftershock (#37530) --- .../npcs/mutant_npcs/npc_classes_mutant.json | 385 ++++++++ .../npcs/mutant_npcs/trait_groups.json | 924 ++++++++++++++++++ 2 files changed, 1309 insertions(+) create mode 100644 data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json create mode 100644 data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json diff --git a/data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json b/data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json new file mode 100644 index 0000000000000..ab0677b3ac616 --- /dev/null +++ b/data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json @@ -0,0 +1,385 @@ +[ + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_LIZARD", + "name": "Lizard Mutant", + "job_description": "I'm looking for lizard mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 4, + "bonus_dex": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_lizard" }, + { "distribution": [ { "group": "trait_group_lizard_nonthres" }, { "group": "trait_group_lizard_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_MEDICAL", + "name": "Medical Mutant", + "job_description": "I'm looking for medical mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_medical" }, + { + "distribution": [ { "group": "trait_group_medical_nonthres" }, { "group": "trait_group_medical_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_BIRD", + "name": "Bird Mutant", + "job_description": "I'm looking for bird mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 4, + "bonus_per": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_bird" }, + { "distribution": [ { "group": "trait_group_bird_nonthres" }, { "group": "trait_group_bird_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_FISH", + "name": "Fish Mutant", + "job_description": "I'm looking for fish mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "swimming", "bonus": { "rng": [ 5, 15 ] } } + ], + "bonus_dex": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_fish" }, + { "distribution": [ { "group": "trait_group_fish_nonthres" }, { "group": "trait_group_fish_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_BEAST", + "name": "Beast Mutant", + "job_description": "I'm looking for beast mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 4, 8 ] } } + ], + "bonus_str": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_beast" }, + { "distribution": [ { "group": "trait_group_beast_nonthres" }, { "group": "trait_group_beast_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_URSINE", + "name": "Ursine Mutant", + "job_description": "I'm looking for ursine mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 11, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_ursine" }, + { "distribution": [ { "group": "trait_group_ursine_nonthres" }, { "group": "trait_group_ursine_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_FELINE", + "name": "Feline Mutant", + "job_description": "I'm looking for feline mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_feline" }, + { "distribution": [ { "group": "trait_group_feline_nonthres" }, { "group": "trait_group_feline_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_LUPINE", + "name": "Lupine Mutant", + "job_description": "I'm looking for lupine mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_lupine" }, + { "distribution": [ { "group": "trait_group_lupine_nonthres" }, { "group": "trait_group_lupine_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_CATTLE", + "name": "Cattle Mutant", + "job_description": "I'm looking for cattle mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 6, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_cattle" }, + { "distribution": [ { "group": "trait_group_cattle_nonthres" }, { "group": "trait_group_cattle_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_INSECT", + "name": "Insect Mutant", + "job_description": "I'm looking for insect mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 1, + "bonus_dex": 1, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_insect" }, + { "distribution": [ { "group": "trait_group_insect_nonthres" }, { "group": "trait_group_insect_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_PLANT", + "name": "Plant Mutant", + "job_description": "I'm looking for plant mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_plant" }, + { "distribution": [ { "group": "trait_group_plant_nonthres" }, { "group": "trait_group_plant_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_SLIME", + "name": "Slime Mutant", + "job_description": "I'm looking for slime mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 4 ] } } + ], + "bonus_str": -4, + "bonus_dex": 5, + "bonus_int": 10, + "bonus_per": 5, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_slime" }, + { "distribution": [ { "group": "trait_group_slime_nonthres" }, { "group": "trait_group_slime_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_TROGLOBITE", + "name": "Troglobite Mutant", + "job_description": "I'm looking for troglobite mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 4, 8 ] } } + ], + "bonus_str": 6, + "bonus_dex": -2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_troglobite" }, + { + "distribution": [ { "group": "trait_group_troglobite_nonthres" }, { "group": "trait_group_troglobite_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_CEPHALOPOD", + "name": "Cephalopod Mutant", + "job_description": "I'm looking for cephalopod mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "swimming", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 7, + "bonus_int": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_cephalopod" }, + { + "distribution": [ { "group": "trait_group_cephalopod_nonthres" }, { "group": "trait_group_cephalopod_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_SPIDER", + "name": "Spider Mutant", + "job_description": "I'm looking for spider mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_spider" }, + { "distribution": [ { "group": "trait_group_spider_nonthres" }, { "group": "trait_group_spider_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_RAT", + "name": "Rat Mutant", + "job_description": "I'm looking for rat mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_rat" }, + { "distribution": [ { "group": "trait_group_rat_nonthres" }, { "group": "trait_group_rat_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_MOUSE", + "name": "Mouse Mutant", + "job_description": "I'm looking for mouse mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 7 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 5 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 5 ] } } + ], + "bonus_dex": 6, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_mouse" }, + { "distribution": [ { "group": "trait_group_mouse_nonthres" }, { "group": "trait_group_mouse_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_ALPHA", + "name": "Alpha Mutant", + "job_description": "I'm looking for alpha mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 5, + "bonus_dex": 5, + "bonus_int": 5, + "bonus_per": 5, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_alpha" }, + { "distribution": [ { "group": "trait_group_alpha_nonthres" }, { "group": "trait_group_alpha_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_ELFA", + "name": "Elfa Mutant", + "job_description": "I'm looking for elfa mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 4 ] } } + ], + "bonus_str": 1, + "bonus_dex": 5, + "bonus_int": 4, + "bonus_per": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_elfa" }, + { "distribution": [ { "group": "trait_group_elfa_nonthres" }, { "group": "trait_group_elfa_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_CHIMERA", + "name": "Chimera Mutant", + "job_description": "I'm looking for chimera mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 4, 8 ] } } + ], + "bonus_str": 4, + "bonus_dex": 2, + "bonus_per": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_chimera" }, + { + "distribution": [ { "group": "trait_group_chimera_nonthres" }, { "group": "trait_group_chimera_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_RAPTOR", + "name": "Raptor Mutant", + "job_description": "I'm looking for raptor mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 6, 10 ] } }, + { "skill": "melee", "bonus": { "rng": [ 6, 10 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 6, 10 ] } } + ], + "bonus_str": 1, + "bonus_dex": 2, + "bonus_per": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_raptor" }, + { "distribution": [ { "group": "trait_group_raptor_nonthres" }, { "group": "trait_group_raptor_postthres" } ] } + ] + } +] diff --git a/data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json b/data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json new file mode 100644 index 0000000000000..c8b08a0792f54 --- /dev/null +++ b/data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json @@ -0,0 +1,924 @@ +[ + { + "type": "trait_group", + "id": "trait_group_spider", + "subtype": "collection", + "traits": [ + { "trait": "FLEET", "prob": 50 }, + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "NIGHTVISION3", "prob": 50 }, + { "trait": "INFRARED", "prob": 50 }, + { "trait": "WEB_WALKER", "prob": 50 }, + { "trait": "DEX_UP_2" }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "COLDBLOOD", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_spider_nonthres", + "subtype": "collection", + "traits": [ + { "trait": "POISONOUS", "prob": 50 }, + { "trait": "MANDIBLES", "prob": 50 }, + { "distribution": [ { "trait": "CHITIN3" }, { "trait": "CHITIN_FUR2" } ] } + ] + }, + { + "type": "trait_group", + "id": "trait_group_spider_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_SPIDER" }, + { "distribution": [ { "trait": "ARACHNID_ARMS" }, { "trait": "ARACHNID_ARMS_OK" } ] }, + { "trait": "CHITIN_FUR3" }, + { "trait": "CF_HAIR", "prob": 50 }, + { "trait": "POISONOUS2", "prob": 50 }, + { "trait": "PRED3", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "FANGS_SPIDER", "prob": 50 }, + { + "distribution": [ + { "trait": "WEB_SPINNER" }, + { "collection": [ { "trait": "WEB_WEAVER" }, { "trait": "WEB_RAPPEL" }, { "trait": "WEB_ROPE" } ] } + ] + } + ] + }, + { + "type": "trait_group", + "id": "trait_group_alpha", + "subtype": "collection", + "traits": [ + { "trait": "GOODHEARING", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "PRETTY", "prob": 50 }, + { "trait": "ANTIJUNK", "prob": 50 }, + { "trait": "NAUSEA", "prob": 50 }, + { "trait": "HUNGER", "prob": 50 }, + { "trait": "ROT3", "prob": 50 }, + { "trait": "STR_ALPHA" }, + { "trait": "DEX_ALPHA" }, + { "trait": "INT_ALPHA" }, + { "trait": "PER_ALPHA" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_alpha_nonthres", + "subtype": "collection", + "traits": [ { "trait": "WAKEFUL", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_alpha_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_ALPHA" }, { "trait": "WAKEFUL2", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_fish", + "subtype": "collection", + "traits": [ + { "trait": "GOODCARDIO", "prob": 50 }, + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "NIGHTVISION3", "prob": 50 }, + { "trait": "FANGS", "prob": 50 }, + { "trait": "MEMBRANE", "prob": 50 }, + { "trait": "GILLS", "prob": 50 }, + { "trait": "SLEEK_SCALES", "prob": 50 }, + { "trait": "TAIL_FIN", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "THIRST2", "prob": 50 }, + { "trait": "WEBBED", "prob": 50 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "COLDBLOOD", "prob": 50 }, + { "trait": "DEX_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_fish_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_fish_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_FISH" } ] + }, + { + "type": "trait_group", + "id": "trait_group_lupine", + "subtype": "collection", + "traits": [ + { "trait": "GOODCARDIO", "prob": 50 }, + { "trait": "SMELLY", "prob": 50 }, + { "distribution": [ { "trait": "UGLY" }, { "trait": "DEFORMED" }, { "trait": "PRETTY" } ] }, + { "trait": "ANIMALDISCORD", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "FANGS", "prob": 50 }, + { "trait": "LUPINE_FUR", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "TAIL_FLUFFY", "prob": 50 }, + { "trait": "LUPINE_EARS", "prob": 50 }, + { "trait": "STR_UP_3" }, + { "trait": "MUZZLE", "prob": 50 }, + { "trait": "HEAVYSLEEPER2", "prob": 50 }, + { "trait": "PAWS", "prob": 50 }, + { "trait": "GROWL", "prob": 50 }, + { "trait": "SHOUT3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lupine_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_lupine_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_LUPINE" }, { "trait": "PRED3", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_bird", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "NIGHTVISION", "prob": 50 }, + { "trait": "DEFT", "prob": 50 }, + { "trait": "LIGHTSTEP", "prob": 50 }, + { "trait": "BADBACK", "prob": 50 }, + { "trait": "GLASSJAW", "prob": 50 }, + { "trait": "BIRD_EYE", "prob": 50 }, + { "trait": "FEATHERS", "prob": 50 }, + { "trait": "WINGS_BIRD", "prob": 50 }, + { "trait": "DEX_UP_3" }, + { "trait": "HOLLOW_BONES", "prob": 50 }, + { "trait": "PER_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_bird_nonthres", + "subtype": "collection", + "traits": [ { "trait": "BEAK", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_bird_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_BIRD" }, + { "trait": "DOWN", "prob": 50 }, + { "trait": "TALONS", "prob": 50 }, + { "trait": "GIZZARD", "prob": 50 }, + { "trait": "FLEET2", "prob": 50 }, + { "distribution": [ { "trait": "BEAK_PECK", "prob": 50 }, { "trait": "BEAK_HUM", "prob": 50 } ] } + ] + }, + { + "type": "trait_group", + "id": "trait_group_insect", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "NIGHTVISION", "prob": 50 }, + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "TERRIFYING", "prob": 50 }, + { "trait": "HEAVYSLEEPER", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "INFRARED", "prob": 50 }, + { "trait": "CHITIN2", "prob": 50 }, + { "trait": "PHEROMONE_INSECT", "prob": 50 }, + { "trait": "COMPOUND_EYES", "prob": 50 }, + { "trait": "ANTENNAE", "prob": 50 }, + { "trait": "TAIL_STING", "prob": 50 }, + { "trait": "MANDIBLES", "prob": 50 }, + { "trait": "STR_UP", "prob": 50 }, + { "trait": "DEX_UP" }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "COLDBLOOD3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_insect_nonthres", + "subtype": "collection", + "traits": [ { "trait": "WINGS_INSECT", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_insect_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_INSECT" }, + { "distribution": [ { "trait": "WINGS_BUTTERFLY", "prob": 50 }, { "trait": "WINGS_INSECT", "prob": 50 } ] }, + { "trait": "PROBOSCIS", "prob": 50 }, + { "distribution": [ { "trait": "INSECT_ARMS", "prob": 50 }, { "trait": "INSECT_ARMS_OK", "prob": 50 } ] } + ] + }, + { + "type": "trait_group", + "id": "trait_group_troglobite", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "MYOPIC", "prob": 50 }, + { "trait": "NIGHTVISION3", "prob": 50 }, + { "trait": "INFRARED", "prob": 50 }, + { "trait": "REGEN", "prob": 50 }, + { "trait": "DISIMMUNE", "prob": 50 }, + { "trait": "INFRESIST", "prob": 50 }, + { "trait": "POISONOUS", "prob": 50 }, + { "trait": "ALCMET", "prob": 50 }, + { "trait": "SAPROVORE", "prob": 50 }, + { "trait": "STR_UP_3" }, + { "trait": "SUNBURN", "prob": 50 }, + { "trait": "TROGLO3", "prob": 50 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "STOCKY_TROGLO" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_troglobite_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_troglobite_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_TROGLOBITE" }, { "trait": "PAINRESIST_TROGLO", "prob": 50 }, { "trait": "EATPOISON", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_chimera", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "TERRIFYING", "prob": 50 }, + { "trait": "ADRENALINE", "prob": 50 }, + { "trait": "SLEEPY", "prob": 50 }, + { "trait": "BADTEMPER", "prob": 50 }, + { "trait": "FORGETFUL", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "SCALES", "prob": 50 }, + { "trait": "LIGHTFUR", "prob": 50 }, + { "trait": "TALONS", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "HOOVES", "prob": 50 }, + { "trait": "SAPROVORE", "prob": 50 }, + { "trait": "HORNS_CURLED", "prob": 50 }, + { "trait": "TAIL_CLUB", "prob": 50 }, + { "trait": "CANINE_EARS", "prob": 50 }, + { "trait": "STR_UP_3" }, + { "trait": "DEX_UP_2" }, + { "trait": "PER_UP_2" }, + { "trait": "MOUTH_FLAPS", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED3", "prob": 50 }, + { "trait": "HUNGER3", "prob": 50 }, + { "trait": "THIRST", "prob": 50 }, + { "trait": "ROT2", "prob": 50 }, + { "distribution": [ { "trait": "UNSTABLE", "prob": 10 }, { "trait": "CHAOTIC", "prob": 10 } ] }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "SNARL", "prob": 50 }, + { "trait": "SHOUT3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_chimera_nonthres", + "subtype": "collection", + "traits": [ { "trait": "FANGS", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_chimera_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_CHIMERA" }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "MUT_JUNKIE", "prob": 50 }, + { "trait": "MUT_TOUGH2", "prob": 50 }, + { "trait": "EATPOISON", "prob": 50 }, + { "trait": "EATDEAD", "prob": 50 }, + { "trait": "SABER_TEETH", "prob": 50 }, + { "trait": "EATHEALTH", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_raptor", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "DEFT", "prob": 50 }, + { "trait": "ANTIJUNK", "prob": 50 }, + { "trait": "GLASSJAW", "prob": 50 }, + { "trait": "ANIMALDISCORD", "prob": 50 }, + { "trait": "UGLY", "prob": 50 }, + { "trait": "LIZ_EYE", "prob": 50 }, + { "trait": "SCALES", "prob": 50 }, + { "trait": "NAILS", "prob": 50 }, + { "trait": "RAP_TALONS", "prob": 50 }, + { "trait": "TAIL_RAPTOR", "prob": 50 }, + { "trait": "STR_UP" }, + { "trait": "DEX_UP_2" }, + { "trait": "PER_UP_3" }, + { "trait": "SLIT_NOSTRILS", "prob": 50 }, + { "trait": "FORKED_TONGUE", "prob": 50 }, + { "trait": "HUNGER2", "prob": 50 }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "COLDBLOOD2", "prob": 50 }, + { "trait": "HISS", "prob": 50 }, + { "trait": "SHOUT1", "prob": 50 }, + { "trait": "ARM_FEATHERS", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_raptor_nonthres", + "subtype": "collection", + "traits": [ { "trait": "FANGS", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_raptor_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_RAPTOR" }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "EATPOISON", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_medical", + "subtype": "collection", + "traits": [ + { "trait": "FASTHEALER", "prob": 50 }, + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "SELFAWARE", "prob": 50 }, + { "trait": "MASOCHIST", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "HEAVYSLEEPER", "prob": 50 }, + { "trait": "INSOMNIA", "prob": 50 }, + { "trait": "FORGETFUL", "prob": 50 }, + { "trait": "LIGHTWEIGHT", "prob": 50 }, + { "trait": "ADDICTIVE", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "SCHIZOPHRENIC", "prob": 50 }, + { "trait": "JITTERY", "prob": 50 }, + { "trait": "MOODSWINGS", "prob": 50 }, + { "trait": "RADIOGENIC", "prob": 50 }, + { "trait": "INFIMMUNE", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "PAINREC3", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "HUNGER", "prob": 50 }, + { "trait": "UNSTABLE", "prob": 10 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_medical_nonthres", + "subtype": "collection", + "traits": [ { "trait": "PAINRESIST", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_medical_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_MEDICAL", "prob": 50 }, + { "trait": "MUT_TOUGH2", "prob": 50 }, + { "trait": "CENOBITE", "prob": 50 }, + { "trait": "NOPAIN", "prob": 50 }, + { "trait": "MUT_JUNKIE", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cattle", + "subtype": "collection", + "traits": [ + { "trait": "NIGHTVISION", "prob": 50 }, + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "FUR", "prob": 50 }, + { "trait": "HOOVES", "prob": 50 }, + { "trait": "HORNS", "prob": 50 }, + { "trait": "TAIL_CATTLE", "prob": 50 }, + { "trait": "CANINE_EARS", "prob": 50 }, + { "trait": "STR_UP_2" }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "MINOTAUR", "prob": 50 }, + { "trait": "PONDEROUS2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cattle_nonthres", + "subtype": "collection", + "traits": [ { "trait": "RUMINANT", "prob": 50 }, { "trait": "HUGE" } ] + }, + { + "type": "trait_group", + "id": "trait_group_cattle_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_CATTLE" }, + { "trait": "GRAZER", "prob": 50 }, + { "trait": "HUGE_OK" }, + { "trait": "MUT_TOUGH3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_slime", + "subtype": "collection", + "traits": [ + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "REGEN", "prob": 50 }, + { "trait": "RADIOGENIC", "prob": 50 }, + { "trait": "DISIMMUNE", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "POISONOUS", "prob": 50 }, + { "trait": "SLIME_HANDS", "prob": 50 }, + { "trait": "DEX_UP" }, + { "trait": "DEFORMED3", "prob": 50 }, + { "trait": "HOLLOW_BONES", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "HUNGER2", "prob": 50 }, + { "trait": "THIRST2", "prob": 50 }, + { "trait": "SORES", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "WEBBED", "prob": 50 }, + { "trait": "UNSTABLE", "prob": 10 }, + { "trait": "RADIOACTIVE1", "prob": 0 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "INT_SLIME" }, + { "trait": "BENDY3" }, + { "trait": "PER_SLIME_OK" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_slime_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_slime_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_SLIME" }, + { "trait": "VISCOUS", "prob": 50 }, + { "trait": "AMORPHOUS", "prob": 50 }, + { "trait": "SLIMESPAWNER", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lizard", + "subtype": "collection", + "traits": [ + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "BADTEMPER", "prob": 50 }, + { "trait": "LIZ_EYE", "prob": 50 }, + { "trait": "REGEN_LIZ", "prob": 50 }, + { "trait": "FANGS", "prob": 50 }, + { "trait": "MEMBRANE", "prob": 50 }, + { "trait": "TAIL_THICK", "prob": 50 }, + { "trait": "STR_UP_2" }, + { "trait": "DEX_UP_2" }, + { "trait": "SLIT_NOSTRILS", "prob": 50 }, + { "trait": "FORKED_TONGUE", "prob": 50 }, + { "trait": "MUZZLE_LONG", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "WEBBED", "prob": 50 }, + { "trait": "HISS", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lizard_nonthres", + "subtype": "collection", + "traits": [ + { "trait": "SCALES", "prob": 50 }, + { "trait": "LARGE" }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "COLDBLOOD3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lizard_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_LIZARD" }, + { "trait": "THICK_SCALES", "prob": 50 }, + { "trait": "TALONS", "prob": 50 }, + { "trait": "MUT_TOUGH", "prob": 50 }, + { "trait": "PRED3", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "LARGE_OK" }, + { "trait": "COLDBLOOD4", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_beast", + "subtype": "collection", + "traits": [ + { "trait": "DEFT", "prob": 50 }, + { "trait": "ANIMALEMPATH", "prob": 50 }, + { "trait": "TERRIFYING", "prob": 50 }, + { "trait": "ADRENALINE", "prob": 50 }, + { "trait": "MYOPIC", "prob": 50 }, + { "trait": "SLEEPY", "prob": 50 }, + { "trait": "ANTIJUNK", "prob": 50 }, + { "trait": "FORGETFUL", "prob": 50 }, + { "trait": "ANIMALDISCORD", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "FUR", "prob": 50 }, + { "trait": "CLAWS", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "TAIL_FLUFFY", "prob": 50 }, + { "trait": "CANINE_EARS", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED2", "prob": 50 }, + { "trait": "MUZZLE", "prob": 50 }, + { "trait": "HUNGER2", "prob": 50 }, + { "trait": "HEAVYSLEEPER2", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "PAWS_LARGE", "prob": 50 }, + { "trait": "SNARL", "prob": 50 }, + { "trait": "SHOUT2", "prob": 50 }, + { "trait": "STR_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_beast_nonthres", + "subtype": "collection", + "traits": [ { "trait": "CARNIVORE", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_beast_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_BEAST" }, + { "trait": "MUT_TOUGH", "prob": 50 }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_rat", + "subtype": "collection", + "traits": [ + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "INCISORS", "prob": 50 }, + { "trait": "FUR", "prob": 50 }, + { "trait": "TAIL_RAT", "prob": 50 }, + { "trait": "WHISKERS_RAT", "prob": 50 }, + { "trait": "DEFORMED3", "prob": 50 }, + { "trait": "MUZZLE_RAT", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "MET_RAT", "prob": 50 }, + { "trait": "PAWS", "prob": 50 }, + { "trait": "GROWL", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_rat_nonthres", + "subtype": "collection", + "traits": [ { "trait": "CLAWS_RAT", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_rat_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_RAT" }, + { "trait": "CLAWS_ST", "prob": 50 }, + { "trait": "BURROW", "prob": 50 }, + { "trait": "INFRESIST", "prob": 50 }, + { "trait": "EATDEAD", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_mouse", + "subtype": "collection", + "traits": [ + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "FELINE_FUR", "prob": 50 }, + { "trait": "TAIL_RAT", "prob": 50 }, + { "trait": "MET_RAT", "prob": 50 }, + { "trait": "ANIMALDISCORD2", "prob": 50 }, + { "trait": "WHISKERS_RAT", "prob": 50 }, + { "trait": "PROJUNK", "prob": 50 }, + { "trait": "SMALL2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_mouse_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_mouse_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_MOUSE" }, + { "trait": "GOODCARDIO2", "prob": 50 }, + { "trait": "SMALL_OK", "prob": 50 }, + { "trait": "INFRESIST", "prob": 50 }, + { "trait": "PROJUNK2", "prob": 50 }, + { "trait": "EASYSLEEPER2", "prob": 50 }, + { "trait": "CRAFTY", "prob": 50 }, + { "trait": "EATDEAD", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_elfa", + "subtype": "collection", + "traits": [ + { "trait": "LIGHTSTEP", "prob": 50 }, + { "trait": "WEAKSCENT", "prob": 50 }, + { "trait": "BADBACK", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "ELFAEYES", "prob": 50 }, + { "trait": "ELFA_FNV", "prob": 50 }, + { "trait": "PLANTSKIN", "prob": 50 }, + { "trait": "LEAVES", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "ELFA_EARS", "prob": 50 }, + { "trait": "STR_UP" }, + { "trait": "DEX_UP_3" }, + { "trait": "INT_UP_3" }, + { "trait": "PER_UP_3" }, + { "trait": "BEAUTIFUL3", "prob": 50 }, + { "trait": "HOLLOW_BONES", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "HUNGER", "prob": 50 }, + { "trait": "THIRST", "prob": 50 }, + { "trait": "ROT1", "prob": 50 }, + { "trait": "RADIOACTIVE2", "prob": 0 }, + { "trait": "BENDY1" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_elfa_nonthres", + "subtype": "collection", + "traits": [ { "trait": "WAKEFUL", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_elfa_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_ELFA" }, { "trait": "WAKEFUL3", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_feline", + "subtype": "collection", + "traits": [ + { "trait": "LIGHTSTEP", "prob": 50 }, + { "trait": "SMELLY", "prob": 50 }, + { "distribution": [ { "trait": "PRETTY" }, { "trait": "DEFORMED" }, { "trait": "UGLY" } ] }, + { "trait": "FEL_EYE", "prob": 50 }, + { "trait": "FEL_NV", "prob": 50 }, + { "trait": "FELINE_FUR", "prob": 50 }, + { "trait": "LYNX_FUR", "prob": 50 }, + { "trait": "CLAWS_RETRACT", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "FELINE_EARS", "prob": 50 }, + { "trait": "WHISKERS", "prob": 50 }, + { "trait": "DEX_UP_3" }, + { "trait": "SNOUT", "prob": 50 }, + { "trait": "SLEEPY2", "prob": 50 }, + { "trait": "PAWS", "prob": 50 }, + { "trait": "SNARL", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_feline_nonthres", + "subtype": "collection", + "traits": [ { "trait": "FANGS", "prob": 50 }, { "trait": "CARNIVORE", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_feline_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_FELINE" }, + { "trait": "PRED3", "prob": 50 }, + { "trait": "SABER_TEETH", "prob": 50 }, + { "trait": "TAIL_LONG", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_plant", + "subtype": "collection", + "traits": [ + { "trait": "HEAVYSLEEPER", "prob": 50 }, + { "trait": "BADHEARING", "prob": 50 }, + { "trait": "FASTHEALER2", "prob": 50 }, + { "trait": "BARK", "prob": 50 }, + { "trait": "THORNS", "prob": 50 }, + { "trait": "LEAVES", "prob": 50 }, + { "trait": "STR_UP_2" }, + { "trait": "DEFORMED2", "prob": 50 }, + { "trait": "PONDEROUS3", "prob": 50 }, + { "trait": "SUNLIGHT_DEPENDENT", "prob": 50 }, + { "trait": "VINES3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_plant_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_plant_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_PLANT" }, + { "trait": "FLOWERS", "prob": 50 }, + { "trait": "DISIMMUNE", "prob": 50 }, + { "trait": "SAPROPHAGE", "prob": 50 }, + { "trait": "ROOTS3", "prob": 50 }, + { "trait": "CHLOROMORPH", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_ursine", + "subtype": "collection", + "traits": [ + { "trait": "BADTEMPER", "prob": 50 }, + { "trait": "URSINE_EYE", "prob": 50 }, + { "trait": "URSINE_FUR", "prob": 50 }, + { "trait": "CLAWS", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "TAIL_STUB", "prob": 50 }, + { "trait": "HIBERNATE", "prob": 50 }, + { "trait": "URSINE_EARS", "prob": 50 }, + { "trait": "FAT", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED2", "prob": 50 }, + { "trait": "MUZZLE_BEAR", "prob": 50 }, + { "trait": "PAWS_LARGE", "prob": 50 }, + { "trait": "PONDEROUS1", "prob": 50 }, + { "trait": "GROWL", "prob": 50 }, + { "trait": "STR_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_ursine_nonthres", + "subtype": "collection", + "traits": [ { "trait": "HUGE" } ] + }, + { + "type": "trait_group", + "id": "trait_group_ursine_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_URSINE" }, + { "trait": "MUT_TOUGH3", "prob": 50 }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "HUGE_OK" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cephalopod", + "subtype": "collection", + "traits": [ + { "trait": "CEPH_EYES", "prob": 50 }, + { "trait": "CEPH_VISION", "prob": 50 }, + { "trait": "GILLS_CEPH", "prob": 50 }, + { "trait": "SLIT_NOSTRILS", "prob": 50 }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "THIRST2", "prob": 50 }, + { "trait": "BEAK", "prob": 50 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "COLDBLOOD", "prob": 50 }, + { "trait": "DEX_UP_4" }, + { "trait": "INT_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cephalopod_nonthres", + "subtype": "collection", + "traits": [ + { "trait": "LEG_TENTACLES", "prob": 50 }, + { "distribution": [ { "trait": "ARM_TENTACLES" }, { "trait": "ARM_TENTACLES_4" } ], "prob": 50 }, + { "trait": "SHELL", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cephalopod_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_CEPHALOPOD" }, + { "trait": "MOUTH_TENTACLES", "prob": 50 }, + { + "distribution": [ { "trait": "ARM_TENTACLES" }, { "trait": "ARM_TENTACLES_4" }, { "trait": "ARM_TENTACLES_8" } ] + }, + { "trait": "CLAWS_TENTACLE", "prob": 50 }, + { "trait": "LEG_TENTACLES" }, + { "trait": "LEG_TENT_BRACE", "prob": 50 }, + { "trait": "SHELL2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_mutant_npc_common", + "subtype": "collection", + "traits": [ + { "distribution": [ { "trait": "FASTLEARNER" }, { "trait": "SLOWLEARNER" } ], "prob": 10 }, + { + "distribution": [ { "trait": "FASTREADER" }, { "trait": "SLOWREADER" }, { "trait": "ILLITERATE", "prob": 5 } ], + "prob": 10 + }, + { "distribution": [ { "trait": "PARKOUR" }, { "trait": "BADKNEES" } ], "prob": 10 }, + { "distribution": [ { "trait": "LIAR" }, { "trait": "TRUTHTELLER" } ], "prob": 10 }, + { + "distribution": [ + { "trait": "MARTIAL_ARTS" }, + { "trait": "MARTIAL_ARTS2" }, + { "trait": "MARTIAL_ARTS3" }, + { "trait": "MARTIAL_ARTS4" }, + { "trait": "MARTIAL_ARTS5" } + ], + "prob": 10 + }, + { "trait": "DEFT", "prob": 10 }, + { "trait": "ADRENALINE", "prob": 10 }, + { "trait": "OUTDOORSMAN", "prob": 10 }, + { "trait": "PAINRESIST", "prob": 10 }, + { "trait": "QUICK", "prob": 10 }, + { "trait": "ROBUST", "prob": 10 }, + { "trait": "SELFAWARE", "prob": 10 }, + { "trait": "SPIRITUAL", "prob": 10 }, + { "trait": "STYLISH", "prob": 10 }, + { "trait": "ALBINO", "prob": 5 }, + { "trait": "ASTHMA", "prob": 5 }, + { "trait": "CHEMIMBALANCE", "prob": 10 }, + { "trait": "HOARDER", "prob": 10 }, + { "trait": "JITTERY", "prob": 10 }, + { "trait": "MOODSWINGS", "prob": 10 }, + { "trait": "SAVANT", "prob": 10 }, + { "trait": "SCHIZOPHRENIC", "prob": 10 }, + { "trait": "SQUEAMISH", "prob": 10 }, + { "trait": "TRIGGERHAPPY", "prob": 10 }, + { "group": "Appearance_demographics", "prob": 100 } + ] + } +] From c2a85262b3c06834f6fe38681a3af59a1e39904e Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 6 Mar 2020 04:29:57 -0600 Subject: [PATCH 017/219] Aftershock Crafting System (#37707) --- data/mods/Aftershock/crafting_system.md | 67 ++++++++++++++++ .../items/crafting_scrap/abstract_scrap.json | 49 ++++++++++++ .../items/crafting_scrap/circuity_scrap.json | 42 ++++++++++ .../crafting_scrap/energy_storage_scrap.json | 42 ++++++++++ .../items/crafting_scrap/magnet_scrap.json | 26 ++++++ .../items/crafting_scrap/material_scrap.json | 42 ++++++++++ .../items/crafting_scrap/neural_io_scrap.json | 42 ++++++++++ data/mods/Aftershock/items/grenades.json | 24 ++++++ data/mods/Aftershock/items/item_groups.json | 18 +++++ data/mods/Aftershock/items/items.json | 2 +- data/mods/Aftershock/items/tool_quality.json | 5 ++ data/mods/Aftershock/items/tools.json | 8 ++ .../Aftershock/recipes/bionic_recipes.json | 80 ++++++++++--------- .../deconstruction/bionic_deconstruction.json | 18 +++++ data/mods/Aftershock/recipes/grenades.json | 15 ++++ 15 files changed, 441 insertions(+), 39 deletions(-) create mode 100644 data/mods/Aftershock/crafting_system.md create mode 100644 data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/material_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json create mode 100644 data/mods/Aftershock/items/grenades.json create mode 100644 data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json create mode 100644 data/mods/Aftershock/recipes/grenades.json diff --git a/data/mods/Aftershock/crafting_system.md b/data/mods/Aftershock/crafting_system.md new file mode 100644 index 0000000000000..84a2d111fb110 --- /dev/null +++ b/data/mods/Aftershock/crafting_system.md @@ -0,0 +1,67 @@ +# Scrap Crafting System + +## Overview + +As one of its main goals, Aftershock allows the crafting of miscellaneous, highly technological devices that have no actual basis in reality. To make the crafting of these devices more balanced an intuitive, and to make adding more recipes and items easier, aftershock utilizes a crafting a system in which abstracted pieces of increasingly rare scrap are used to craft increasingly useful tools. + + +### Current Scrap Categories + +The following table lists the currently planned/implemented scrap categories and their tiers. + +| Category | Tier 1 | Tier 2 | Tier 3 | Tier 4 | Tier 5 | +| ----------------- | -------------------- | ------------------------ | -------------------------- | ------------------------- | ------------------------------------ | +| `Circuitry` | scrap photonics | photonic circuitry | photonic computation core | hypergeometric photonics | acausal logic permutator | +| `Energy Storage` | Nanowire battery | ultracapacitor | Ultracapacitor array | Superconductive Coil | zero-point energy extractor | +| `Material` | Composite Superalloy | vacuum cast Carbide | Nanoprinted Alloys | crystal forged neutrite | phase-uneven matter | +| `Cloth` | E-textile | monofilament silk | graphene weave | woven metamaterial | | +| `Magnet` | Emag | cryo electromagnet | super conductive emag | ferrofluid dynamo | | +| `Optics ` | | Laser Optics | Phased Array Optics | Nano-optics | | +| `Neural I/O` | peripheral electrode | neural electrode | Brain implant prod | Synthetic Neural Tissue | neurosynaptic interface matrix | +| `Biomaterial` | monomeric slurry | micellular growth medium | artificial muscle fibers | self healing polymers | autologous totipotent tissue culture | + +Note that more categories can be added, and that it inst necessary for a category to encompass the five tiers, although its better if they do. + +## Scrap Tiers Briefly Explained + +### Tier 1 + +Tier 1 scrap is plentiful, and can be easily found even when you aren't specifically looking for it. It might be dropped by defeating common enemies, or by disassembling common household objects. Ideally Tier 1 scrap is mostly used as a filler component in more advanced recipes. Things that might be crafted using only this tier of scrap must be single-use and not very effective, and should see little use outside of the early game.For example + +- Makeshift ammunition of all kinds, that might risk damaging your gun. +- Weak grenades with very limited range. + +### Tier 2 + +Tier 2 scrap remains common, but requires some measure of effort to acquire. Perhaps it spawns only in certain locations or requires specialized tools and skills to extract. This scrap might be used to craft disposable tools and weapons or to make decent quality ammunition and explosives. For example: + +- Bulky, makeshift version of an UPS with very limited charge capacity. +- A rail gun/laser that works only for a limited number of shots before melting. +- A grenade that emits a low range electric field. + +### Tier 3 + +Much like tier 2 above, this type of scrap is common, but is only meant to spawn in locations that might prove dangerous to a mid-game characters. Additionally, it should always need tools and skills to extract. Tier 3 scrap might be used to craft basic rechargeable tools, mid-quality weapons and exotic ammunition and grenades. For example: + +- UPS +- Non relaodable charge packs for Laser Weapons +- Shoddy laser Rifle + +### Tier 4 + +This tier of scrap is properly uncommon, it spawns should be limited to the 'boss rooms' of mid-game and to end-game dungeons, and should prove challenging to acquire. It might be used to craft tools that provide great convenience in the non combat aspects of the game, single use items that grant very powerful abilities and good quality weapons. For Example + +- Most utility bionics. +- Laser Weapons. +- Atomic tools. +- Singe use invisibility cloak. + +### Tier 5 + +Very rare loot occasionally dropped by endgame threats and dungeons, extracting it requires very high skills and specialized tools. Thematically linked to the dimensional technology that caused the cataclysm. Might be used to craft items that severely and permanently alter the combat aspects of gameplay. For example: + +- Hologram Cloak Mk. II +- Rechargeable Spell Casters +- CBMs that interact with space-time +- Most combat bionics. + diff --git a/data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json b/data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json new file mode 100644 index 0000000000000..b529cda9d6512 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json @@ -0,0 +1,49 @@ +[ + { + "abstract": "afs_scrap_1", + "type": "GENERIC", + "category": "spare_parts", + "name": "ur-scrap", + "description": "A small techno doodad.", + "looks_like": "e_scrap", + "price": 500, + "price_postapoc": 1000, + "weight": "250 g", + "volume": "50 ml", + "to_hit": -3, + "symbol": "*", + "color": "light_gray" + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_2", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 5000, + "price_postapoc": 10000 + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_3", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 5000, + "price_postapoc": 50000 + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_4", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 50000, + "price_postapoc": 100000 + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_5", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 500000, + "price_postapoc": 1000000 + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json b/data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json new file mode 100644 index 0000000000000..648f8deda18f1 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_circuitry_1", + "copy-from": "afs_scrap_1", + "name": "scrap photonics", + "description": "Small circuits blue and gold, transmitting signals through light.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_2", + "copy-from": "afs_scrap_2", + "name": "photonic circuitry", + "description": "A resplendent golden grid inlaid on dark blue substrate.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_3", + "copy-from": "afs_scrap_3", + "name": "photonic computation core", + "description": "A monolithic circuit shaped as a glowing cube of crystal.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_4", + "copy-from": "afs_scrap_4", + "name": "hypergeometric photonics", + "description": "In your hands lies a self-contained digital universe. Its programs glowing like stars fixed on computational shells infinitely layered.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_5", + "copy-from": "afs_scrap_5", + "name": "acausal logic permutator", + "description": "It has given you an answer, but you are yet to ask anything.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json b/data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json new file mode 100644 index 0000000000000..110562c24db93 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_energy_storage_1", + "copy-from": "afs_scrap_1", + "name": "nanowire battery", + "description": "A small battery component with a very high energy density.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_2", + "copy-from": "afs_scrap_2", + "name": "ultracapacitor", + "description": "A capacitor made from exotic compounds, capable of storing a high amount of electric charge.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_3", + "copy-from": "afs_scrap_3", + "name": "ultracapacitor array", + "description": "Ultracapacitors assembled into a finely tunned energy storage array.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_4", + "copy-from": "afs_scrap_4", + "name": "superconductive coil", + "description": "Superconductive wire warped upon itself manipulates the electromagnetic spectrum to store vast amounts of power.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_5", + "copy-from": "afs_scrap_5", + "name": "zero-point energy extractor", + "description": "A complex grid pins space-time to the surface of the multiversal hyper-torus, allowing the energies within to leak into our sliver of existence.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json b/data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json new file mode 100644 index 0000000000000..64fa59e99bcf3 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json @@ -0,0 +1,26 @@ +[ + { + "type": "GENERIC", + "id": "afs_magnet_1", + "copy-from": "afs_scrap_1", + "name": "high quality electromagnet", + "description": "A sturdy, industrially crafted electromagnet.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_magnet_2", + "copy-from": "afs_scrap_2", + "name": "cryo electromagnet", + "description": "A powerful super conductive electromagnet, that must be kept at very low temperatures to operate.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_magnet_3", + "copy-from": "afs_scrap_3", + "name": "super conductive electromagnet", + "description": "A powerful electromagnet made from a room temperature superconductor .", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/material_scrap.json b/data/mods/Aftershock/items/crafting_scrap/material_scrap.json new file mode 100644 index 0000000000000..ef49f59636b74 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/material_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_material_1", + "copy-from": "afs_scrap_1", + "name": "composite alloy", + "description": "Miscellaneous scrap pieces made from a composite alloy.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_2", + "copy-from": "afs_scrap_2", + "name": "vacuum cast carbide", + "description": "Malleable carbide cast by forges on high earth orbit.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_3", + "copy-from": "afs_scrap_1", + "name": "nanoprinted alloy", + "description": "A meta material fabricated by precisely layering different elements at an atomic scale.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_4", + "copy-from": "afs_scrap_4", + "name": "crystal forged neutrite", + "description": "Great forges within the Earth's core wrought hydrogen into flaming metal and poured it within lattices of super conductive lanthanum. Locked in magnetic equilibrium, it was left to cool into a dark unbreakable metal", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_5", + "copy-from": "afs_scrap_5", + "name": "phase uneven matter", + "description": "Matter condensed from the liminal spaces between dimmensions.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json b/data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json new file mode 100644 index 0000000000000..538390ee5dec5 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_neural_io_1", + "copy-from": "afs_scrap_1", + "name": "peripheral electrode", + "description": "A thin strand of wire and a clamp, meant to be spliced into the smaller nerves of the human body.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_2", + "copy-from": "afs_scrap_2", + "name": "neural electrode", + "description": "A small array of metallic needles allows complex communication between machine and human mind.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_3", + "copy-from": "afs_scrap_3", + "name": "brain implant prod", + "description": "A complexly etched rod of metal interfaces with the corpus callosum of the patient, granting increased control of bionic functions.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_4", + "copy-from": "afs_scrap_4", + "name": "artificial neural tissue", + "description": "Photonic axons process thought at speeds far surpassing primitive, chemical-driven communication.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_5", + "copy-from": "afs_scrap_5", + "name": "neurosynaptic interface matrix", + "description": "A membrane of artificial neurons envelops the cerebral cortex, melding machine and human intellect into a gestalt much greater than its individual parts.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/grenades.json b/data/mods/Aftershock/items/grenades.json new file mode 100644 index 0000000000000..b69bbb3af2764 --- /dev/null +++ b/data/mods/Aftershock/items/grenades.json @@ -0,0 +1,24 @@ +[ + { + "id": "afs_electroshock_grenade_1", + "type": "TOOL", + "copy-from": "grenade_canister", + "category": "weapons", + "looks_like": "grenade_emp", + "name": "electroshock grenade", + "description": "This is an electronic weapon that will emit a short ranged electric field. When activated, you'll have five turns before it starts doing so; throwing it before that would be a good idea.", + "countdown_action": { "menu_text": "Pull pin", "type": "transform", "target": "afs_electroshock_grenade_1_act" } + }, + { + "id": "afs_electroshock_grenade_1_act", + "type": "TOOL", + "copy-from": "afs_electroshock_grenade_1", + "looks_like": "grenade_emp_act", + "name": "armed electroshock grenade", + "description": "This electroshock grenade is currently creating a dangerous electric field.", + "emits": [ "emit_shock_cloud" ], + "countdown_interval": 20, + "countdown_action": { "type": "transform", "target": "null" }, + "flags": [ "TRADER_AVOID" ] + } +] diff --git a/data/mods/Aftershock/items/item_groups.json b/data/mods/Aftershock/items/item_groups.json index b18fd6cd6119d..74f51f2e177a3 100644 --- a/data/mods/Aftershock/items/item_groups.json +++ b/data/mods/Aftershock/items/item_groups.json @@ -78,6 +78,24 @@ [ "schematics_searchlight", 50 ] ] }, + { + "id": "science", + "//": "extension of vanilla itemgroup", + "type": "item_group", + "items": [ [ "bionic_maintenance_toolkit", 20 ] ] + }, + { + "id": "tools_medical", + "//": "extension of vanilla itemgroup", + "type": "item_group", + "items": [ [ "bionic_maintenance_toolkit", 20 ] ] + }, + { + "id": "surgery", + "//": "extension of vanilla itemgroup", + "type": "item_group", + "items": [ [ "bionic_maintenance_toolkit", 20 ] ] + }, { "id": "jewelry_accessories", "type": "item_group", diff --git a/data/mods/Aftershock/items/items.json b/data/mods/Aftershock/items/items.json index b91d911a94384..9f64907df8795 100644 --- a/data/mods/Aftershock/items/items.json +++ b/data/mods/Aftershock/items/items.json @@ -5,7 +5,7 @@ "type": "TOOL", "name": { "str": "precision solderers", "str_pl": "precision solderers" }, "flags": "TRADER_AVOID", - "qualities": [ [ "SAW_M_FINE", 1 ], [ "SCREW_FINE", 1 ], [ "CUT_FINE", 2 ] ] + "qualities": [ [ "SAW_M_FINE", 1 ], [ "SCREW_FINE", 1 ], [ "CUT_FINE", 2 ], [ "BIONIC_ASSEMBLY", 2 ] ] }, { "type": "GENERIC", diff --git a/data/mods/Aftershock/items/tool_quality.json b/data/mods/Aftershock/items/tool_quality.json index 646e2f5df34d6..2ed36b8777d4d 100644 --- a/data/mods/Aftershock/items/tool_quality.json +++ b/data/mods/Aftershock/items/tool_quality.json @@ -4,5 +4,10 @@ "id": "CHURN", "name": "churn", "//": "Delete this when you mainline Dairy products existing PR" + }, + { + "type": "tool_quality", + "id": "BIONIC_ASSEMBLY", + "name": "bionic assembly" } ] diff --git a/data/mods/Aftershock/items/tools.json b/data/mods/Aftershock/items/tools.json index 5ab24368437ab..8a85a2c4885ad 100644 --- a/data/mods/Aftershock/items/tools.json +++ b/data/mods/Aftershock/items/tools.json @@ -250,6 +250,14 @@ "covers": [ "LEG_EITHER" ], "flags": [ "WAIST", "FRAGILE", "OVERSIZE", "IS_UPS" ] }, + { + "id": "bionic_maintenance_toolkit", + "copy-from": "screwdriver_set", + "type": "TOOL", + "name": { "str": "bionic maintenance toolkit", "str_pl": "bionic maintenance toolkits" }, + "description": "A set of very small tools and encrypted digital keys normally used to repair bionic modules in clinical settings. They will allow you to disassemble simple bionics, but anything more complex would require even more specialized tools.", + "qualities": [ [ "BIONIC_ASSEMBLY", 1 ], [ "SAW_M_FINE", 1 ] ] + }, { "id": "afs_bionic_power_mod", "copy-from": "mod_battery", diff --git a/data/mods/Aftershock/recipes/bionic_recipes.json b/data/mods/Aftershock/recipes/bionic_recipes.json index e4ba280ffe77e..d684f316cd313 100644 --- a/data/mods/Aftershock/recipes/bionic_recipes.json +++ b/data/mods/Aftershock/recipes/bionic_recipes.json @@ -12,8 +12,7 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_augs", 5 ], [ "recipe_lab_elec", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 6 ], [ "UPS_off", 1 ] ], [ [ "amplifier", 4 ] ], @@ -33,9 +32,8 @@ "reversible": true, "decomp_learn": 8, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], - "using": [ [ "soldering_standard", 32 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "using": [ [ "soldering_standard", 20 ] ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 10 ], [ "UPS_off", 2 ], [ "adv_UPS_off", 1 ] ], [ [ "amplifier", 6 ] ], @@ -56,8 +54,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 4 ] ], [ [ "amplifier", 2 ] ], [ [ "solar_cell", 4 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -73,8 +70,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "amplifier", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -106,8 +102,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "hose", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -123,8 +118,7 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 1 ] ], [ [ "amplifier", 1 ] ], [ [ "lens", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -140,8 +134,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "element", 1 ] ], [ [ "hose", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -155,10 +148,8 @@ "time": 50000, "reversible": true, "decomp_learn": 8, - "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "element", 4 ] ], @@ -180,8 +171,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "amplifier", 3 ] ], @@ -203,8 +193,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "mold_plastic", -1 ] ], [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "syringe", 1 ] ], [ [ "plastic_chunk", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -220,8 +209,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "spring", 4 ] ], [ [ "plastic_chunk", 3 ] ], @@ -243,8 +231,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "spring", 4 ] ], [ [ "afs_scrap_titanium", 4 ] ], [ [ "wire", 4 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -260,8 +247,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "glass_tinted", 4 ] ], [ [ "cable", 7 ] ], [ [ "wire", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -277,8 +263,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "glass_tinted", 4 ] ], [ [ "cable", 7 ] ], [ [ "wire", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -293,9 +278,8 @@ "reversible": true, "decomp_learn": 9, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 6 ] ], - "using": [ [ "soldering_standard", 20 ], [ "welding_standard", 5 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ], + "using": [ [ "soldering_standard", 20 ] ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "pipe", 1 ] ], [ [ "spring", 1 ] ], [ [ "plastic_chunk", 2 ] ], [ [ "nail", 1 ] ] ] }, { @@ -311,7 +295,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -327,7 +316,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -343,7 +337,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -359,7 +358,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 6 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -375,7 +379,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 4 ], [ "recipe_augs", 4 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 1 } ], "components": [ [ [ "scrap", 4 ] ], [ [ "element", 3 ] ], [ [ "cable", 10 ] ], [ [ "burnt_out_bionic", 1 ] ] ] } ] diff --git a/data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json b/data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json new file mode 100644 index 0000000000000..9b2cc4e0c1d3b --- /dev/null +++ b/data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json @@ -0,0 +1,18 @@ +[ + { + "result": "burnt_out_bionic", + "type": "uncraft", + "skill_used": "electronics", + "difficulty": 7, + "time": "10 m", + "using": [ [ "soldering_standard", 10 ], [ "welding_standard", 10 ] ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 1 } ], + "components": [ + [ [ "afs_circuitry_2", 1 ] ], + [ [ "afs_magnet_1", 2 ] ], + [ [ "afs_energy_storage_2", 1 ] ], + [ [ "afs_neural_io_1", 2 ] ], + [ [ "afs_material_1", 1 ] ] + ] + } +] diff --git a/data/mods/Aftershock/recipes/grenades.json b/data/mods/Aftershock/recipes/grenades.json new file mode 100644 index 0000000000000..c0004dd60a86e --- /dev/null +++ b/data/mods/Aftershock/recipes/grenades.json @@ -0,0 +1,15 @@ +[ + { + "result": "afs_electroshock_grenade_1", + "type": "recipe", + "category": "CC_ELECTRONIC", + "subcategory": "CSC_WEAPON_EXPLOSIVE", + "skill_used": "electronics", + "difficulty": 3, + "autolearn": true, + "time": "5 m", + "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "using": [ [ "soldering_standard", 10 ] ], + "components": [ [ [ "afs_energy_storage_2", 1 ] ], [ [ "afs_material_1", 2 ] ] ] + } +] From 4424ccf7c2bc708c5cb66f964fa55b9ee3608b81 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 1 Mar 2020 15:08:18 -0500 Subject: [PATCH 018/219] Dark Skies Part 2: Blacklists (#38501) --- .../blacklists/item_blacklist.json | 264 ++++++++++++++++++ .../blacklists/location_blacklist.json | 89 ++++++ .../blacklists/mon_blacklist.json | 8 + .../blacklists/scenario_blacklist.json | 19 ++ .../blacklists/trait_blacklist.json | 7 + 5 files changed, 387 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/blacklists/item_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/location_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json diff --git a/data/mods/Dark-Skies-Above/blacklists/item_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/item_blacklist.json new file mode 100644 index 0000000000000..544b4ae9376d9 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/item_blacklist.json @@ -0,0 +1,264 @@ +[ + { + "//": "blacklists sci-fi items native to cata's default setting, as they don't fit C:DSA's lore at the moment", + "type": "ITEM_BLACKLIST", + "items": [ + "12mm", + "20x66_10_mag", + "20x66_20_mag", + "20x66_40_mag", + "20x66_beanbag", + "20x66_bootleg_flechette", + "20x66_bootleg_shot", + "20x66_bootleg_slug", + "20x66_exp", + "20x66_flare", + "20x66_flechette", + "20x66_frag", + "20x66_inc", + "20x66_shot", + "20x66_slug", + "360_200_mag", + "360_400_mag", + "5x50_100_mag", + "5x50_50_mag", + "5x50_hull", + "5x50dart", + "5x50heavy", + "8mm_bootleg", + "8mm_caseless", + "8mm_civilian", + "8mm_fmj", + "8mm_inc", + "8mm_jhp", + "8x40_10_mag", + "8x40_100_mag", + "8x40_25_mag", + "8x40_250_mag", + "8x40_50_mag", + "8x40_500_mag", + "alien_pod_resin", + "arm", + "atomic_coffee", + "atomic_coffeepot", + "atomic_lamp", + "atomic_light", + "bio_adrenaline", + "bio_ads", + "bio_alarm", + "bio_armor_arms", + "bio_armor_eyes", + "bio_armor_head", + "bio_armor_legs", + "bio_armor_torso", + "bio_batteries", + "bio_blade", + "bio_blood_anal", + "bio_blood_filter", + "bio_cable", + "bio_carbon", + "bio_chain_lightning", + "bio_claws", + "bio_climate", + "bio_cloak", + "bio_dex_enhancer", + "bio_digestion", + "bio_ears", + "bio_emp", + "bio_emp_armgun", + "bio_ethanol", + "bio_evap", + "bio_eye_enhancer", + "bio_eye_optic", + "bio_face_mask", + "bio_faraday", + "bio_fingerhack", + "bio_flashbang", + "bio_flashlight", + "bio_fuel_cell_gasoline", + "bio_geiger", + "bio_gills", + "bio_ground_sonar", + "bio_heat_absorb", + "bio_heatsink", + "bio_hydraulics", + "bio_infrared", + "bio_int_enhancer", + "bio_jointservo", + "bio_laser", + "bio_leukocyte", + "bio_lighter", + "bio_lockpick", + "bio_magnet", + "bio_membrane", + "bio_memory", + "bio_metabolics", + "bio_nanobots", + "bio_night", + "bio_night_vision", + "bio_ods", + "bio_painkiller", + "bio_power_armor_interface", + "bio_power_armor_interface_mkII", + "bio_power_storage", + "bio_probability_travel", + "bio_purifier", + "bio_radscrubber", + "bio_railgun", + "bio_razors", + "bio_recycler", + "bio_remote", + "bio_resonator", + "bio_scent_mask", + "bio_scent_vision", + "bio_shock", + "bio_shock_absorber", + "bio_shockwave", + "bio_shotgun", + "bio_soporific", + "bio_speed", + "bio_str_enhancer", + "bio_sunglasses", + "bio_surgical_razor", + "bio_syringe", + "bio_targeting", + "bio_taste_blocker", + "bio_tattoo_led", + "bio_teleport", + "bio_time_freeze", + "bio_tools", + "bio_torsionratchet", + "bio_uncanny_dodge", + "bio_ups", + "bio_watch", + "bio_water_extractor", + "bio_weight", + "bot_rifleturret", + "bot_crows_m240", + "bot_turret_riot", + "cerberus_laser", + "coilgun", + "depowered_armor", + "depowered_helmet", + "emp_gun", + "fetus", + "ftk93", + "heavy_atomic_battery_cell", + "hk_g80", + "huge_atomic_battery_cell", + "iv_mutagen", + "iv_mutagen_alpha", + "iv_mutagen_beast", + "iv_mutagen_bird", + "iv_mutagen_cattle", + "iv_mutagen_cephalopod", + "iv_mutagen_chimera", + "iv_mutagen_elfa", + "iv_mutagen_feline", + "iv_mutagen_fish", + "iv_mutagen_insect", + "iv_mutagen_lizard", + "iv_mutagen_lupine", + "iv_mutagen_medical", + "iv_mutagen_plant", + "iv_mutagen_raptor", + "iv_mutagen_rat", + "iv_mutagen_slime", + "iv_mutagen_spider", + "iv_mutagen_troglobite", + "iv_mutagen_ursine", + "iv_purifier", + "l_bak_223", + "l_base_223", + "l_car_223", + "l_dsr_223", + "l_enforcer_45", + "l_HFPack", + "l_lmg_223", + "l_long_45", + "l_lookout_9mm", + "l_mbr_223", + "l_mp_45", + "l_mp_9mm", + "l_sp_45", + "l_sp_9mm", + "laser_pack", + "laser_rifle", + "leg", + "light_atomic_battery_cell", + "light_minus_atomic_battery_cell", + "lw12mag", + "lw21mag", + "lwfeed", + "marloss_berry", + "marloss_gel", + "marloss_scarf", + "marloss_seed", + "medium_atomic_battery_cell", + "mutagen", + "mutagen_alpha", + "mutagen_beast", + "mutagen_bird", + "mutagen_cattle", + "mutagen_cephalopod", + "mutagen_chimera", + "mutagen_elfa", + "mutagen_feline", + "mutagen_fish", + "mutagen_insect", + "mutagen_lizard", + "mutagen_lupine", + "mutagen_medical", + "mutagen_plant", + "mutagen_raptor", + "mutagen_rat", + "mutagen_slime", + "mutagen_spider", + "mutagen_troglobite", + "mutagen_ursine", + "mycus_fruit", + "needlegun", + "needlepistol", + "pheromone", + "plasma_gun", + "plasma_rifle", + "plut_cell", + "power_armor_basic", + "power_armor_frame", + "power_armor_heavy", + "power_armor_helmet_basic", + "power_armor_helmet_heavy", + "power_armor_helmet_light", + "power_armor_light", + "purifier", + "razorclaw_roe", + "rebar_rail", + "rebar_rifle", + "recipe_caseless", + "reloaded_5x50dart", + "resin_chunk", + "rm103a_pistol", + "rm120c", + "rm121aux", + "rm13_armor", + "rm13_armor_on", + "rm20", + "rm2000_smg", + "rm228", + "rm298", + "rm360_carbine", + "rm451_flamethrower", + "rm51_assault_rifle", + "rm614_lmg", + "rm802", + "rm88_battle_rifle", + "rm99_pistol", + "steel_rail", + "taint_tornado", + "unbio_blaster_gun", + "v29", + "v29_cheap", + "wine_mycus" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json new file mode 100644 index 0000000000000..80201b69af785 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json @@ -0,0 +1,89 @@ +[ + { + "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be readded with time", + "type": "overmap_special", + "id": "Necropolis", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "St_Johns_farm", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Strangle Temple", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "evac_center", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "hub_01", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Hazardous Waste Sarcophagus", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Isherwood Farms", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "//": "sorry Mr. Lapin ;w;. temporary until I work on NPCs", + "type": "overmap_special", + "id": "Cabin_Lapin", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Strange Cabin", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "//": "there will be 'FEMA camps' in the future, but almost even more sinister", + "type": "overmap_special", + "id": "FEMA Camp", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "FEMA_camp", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "lab_surface_big", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Mass Grave", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Mine Entrance", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json new file mode 100644 index 0000000000000..ed0d7c07cf6ad --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json @@ -0,0 +1,8 @@ +[ + { + "//": "edited from no_wildlife", + "type": "MONSTER_WHITELIST", + "mode": "EXCLUSIVE", + "categories": [ "ALIEN", "WILDLIFE" ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json new file mode 100644 index 0000000000000..eb53b77bf1bc2 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json @@ -0,0 +1,19 @@ +[ + { + "type": "SCENARIO_BLACKLIST", + "subtype": "whitelist", + "scenarios": [ + "evacuee", + "missed", + "largebuilding", + "surrounded", + "isolationist", + "infected", + "fire", + "bad_day", + "patient", + "wilderness", + "heli_crash" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json new file mode 100644 index 0000000000000..3074ac0086318 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json @@ -0,0 +1,7 @@ +[ + { + "//": "no need for robust genetics atm", + "type": "ITEM_BLACKLIST", + "traits": [ "ROBUST" ] + } +] From dfe31edf1ef35514f63f5e81dc4e7a9193a697c9 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 1 Mar 2020 16:33:03 -0500 Subject: [PATCH 019/219] Dark Skies Part 3: Effects and Items (#38520) --- data/mods/Dark-Skies-Above/ammo_effect.json | 27 ++++++++ data/mods/Dark-Skies-Above/effects.json | 14 ++++ .../items/clothing+armor.json | 68 +++++++++++++++++++ .../Dark-Skies-Above/items/electronics.json | 44 ++++++++++++ data/mods/Dark-Skies-Above/items/weapons.json | 43 ++++++++++++ .../Dark-Skies-Above/mutations/traits.json | 33 +++++++++ .../speech/neworder_speech.json | 68 +++++++++++++++++++ 7 files changed, 297 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/ammo_effect.json create mode 100644 data/mods/Dark-Skies-Above/effects.json create mode 100644 data/mods/Dark-Skies-Above/items/clothing+armor.json create mode 100644 data/mods/Dark-Skies-Above/items/electronics.json create mode 100644 data/mods/Dark-Skies-Above/items/weapons.json create mode 100644 data/mods/Dark-Skies-Above/mutations/traits.json create mode 100644 data/mods/Dark-Skies-Above/speech/neworder_speech.json diff --git a/data/mods/Dark-Skies-Above/ammo_effect.json b/data/mods/Dark-Skies-Above/ammo_effect.json new file mode 100644 index 0000000000000..62ba6a77ad085 --- /dev/null +++ b/data/mods/Dark-Skies-Above/ammo_effect.json @@ -0,0 +1,27 @@ +[ + { + "id": "DKS_NUKEGAS", + "type": "ammo_effect", + "aoe": { "field_type": "fd_nuke_gas", "intensity_min": 0, "intensity_max": 3 } + }, + { + "id": "DKS_RELAXGAS", + "type": "ammo_effect", + "aoe": { "field_type": "fd_relax_gas", "intensity_min": 0, "intensity_max": 3, "radius": 2 } + }, + { + "id": "DKS_RELAXTRAIL", + "type": "ammo_effect", + "trail": { "field_type": "fd_relax_gas", "intensity_min": 1, "intensity_max": 2, "chance": 75 } + }, + { + "id": "DKS_TOXTRAIL", + "type": "ammo_effect", + "aoe": { "field_type": "fd_toxic_gas", "intensity_min": 0, "intensity_max": 3 } + }, + { + "id": "DKS_TOXGAS_BIG", + "type": "ammo_effect", + "aoe": { "field_type": "fd_toxic_gas", "intensity_min": 3, "intensity_max": 3, "radius": 3 } + } +] diff --git a/data/mods/Dark-Skies-Above/effects.json b/data/mods/Dark-Skies-Above/effects.json new file mode 100644 index 0000000000000..deda33e111896 --- /dev/null +++ b/data/mods/Dark-Skies-Above/effects.json @@ -0,0 +1,14 @@ +[ + { + "type": "effect_type", + "id": "panic", + "name": [ "Panicking" ], + "desc": [ "You just can't stop shaking and are overwhelmed by fear." ], + "apply_message": "An all consuming dread overwhelms your mind and you begin to shake uncontrollably!", + "rating": "bad", + "remove_message": "Your heartrate slows back to normal!", + "miss_messages": [ [ "You shake uncontrollably", 4 ] ], + "base_mods": { "dex_mod": [ -2 ], "int_mod": [ -1 ], "per_mod": [ -3 ] }, + "show_in_info": true + } +] diff --git a/data/mods/Dark-Skies-Above/items/clothing+armor.json b/data/mods/Dark-Skies-Above/items/clothing+armor.json new file mode 100644 index 0000000000000..c7489ff632ae3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/items/clothing+armor.json @@ -0,0 +1,68 @@ +[ + { + "//": "a bit of a placeholder until I work on this more in-depth", + "id": "dks_neworder_armor_salvaged", + "type": "ARMOR", + "category": "armor", + "name": "salvaged new order armor", + "description": "A suit of armor belonging to a human-sized soldier of the New Order. Its terribly damaged from some combination of the combat its seen, the process needed to pry it off its wearer, and some sort of dead man's switch on the elements that actually power the thing and make it easy to wear.", + "weight": "12214 g", + "volume": "25 L", + "price": 70000, + "price_postapoc": 70000, + "to_hit": 1, + "bashing": 1, + "material": [ "steel", "nomex" ], + "symbol": "[", + "looks_like": "power_armor", + "color": "light_gray", + "covers": [ "TORSO", "ARMS", "HANDS", "LEGS", "FEET", "HEAD" ], + "coverage": 95, + "encumbrance": 40, + "storage": "2500 ml", + "warmth": 50, + "material_thickness": 4, + "environmental_protection": 6, + "flags": [ "WATERPROOF", "STURDY" ] + }, + { + "id": "dks_riotshield", + "type": "ARMOR", + "name": "new order shield", + "category": "armor", + "description": "A simple shield made of some sort of polycarbonates, used extensively by the Vigilants, the gendarmerie of the New Order. Alongside their infamous shock batons, this is an essential tool in 'keeping the peace'.", + "weight": "3400 g", + "volume": "4 L", + "price": 110000, + "bashing": 8, + "material": [ "plastic" ], + "symbol": "[", + "color": "dark_gray", + "covers": [ "ARM_EITHER", "HAND_EITHER" ], + "coverage": 85, + "encumbrance": 16, + "material_thickness": 3, + "techniques": [ "WBLOCK_2" ], + "flags": [ "OVERSIZE", "BELTED", "RESTRICT_HANDS", "BLOCK_WHILE_WORN" ] + }, + { + "id": "dks_battleshield", + "type": "ARMOR", + "name": "new order battle shield", + "category": "armor", + "description": "A well forged shield made of steel, emblazed with what appears to be a highly stylized depiction of a sword piercing a star.", + "weight": "3300 g", + "volume": "5 L", + "price": 110000, + "bashing": 8, + "material": [ "steel" ], + "symbol": "[", + "color": "dark_gray", + "covers": [ "ARM_EITHER", "HAND_EITHER" ], + "coverage": 90, + "encumbrance": 20, + "material_thickness": 3, + "techniques": [ "WBLOCK_3" ], + "flags": [ "OVERSIZE", "BELTED", "RESTRICT_HANDS", "BLOCK_WHILE_WORN" ] + } +] diff --git a/data/mods/Dark-Skies-Above/items/electronics.json b/data/mods/Dark-Skies-Above/items/electronics.json new file mode 100644 index 0000000000000..477d94a92abc4 --- /dev/null +++ b/data/mods/Dark-Skies-Above/items/electronics.json @@ -0,0 +1,44 @@ +[ + { + "type": "GENERIC", + "id": "broken_dks_emissary", + "symbol": ",", + "color": "green", + "name": "broken emissary", + "category": "other", + "description": "The massive body of a collapsed emissary. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts.", + "price": 1000, + "material": [ "superalloy" ], + "volume": "875000 ml", + "weight": "200 kg", + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] + }, + { + "type": "GENERIC", + "id": "broken_dks_emissary_war", + "symbol": ",", + "color": "green", + "name": "broken emissary of war", + "category": "other", + "description": "The massive body of a collapsed emissary of war. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts.", + "price": 1000, + "material": [ "superalloy" ], + "volume": "875000 ml", + "weight": "200 kg", + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] + }, + { + "type": "GENERIC", + "id": "broken_dks_emissary_flame", + "symbol": ",", + "color": "green", + "name": "broken emissary of flame", + "category": "other", + "description": "The massive body of a collapsed emissary of flame. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts.", + "price": 1000, + "material": [ "superalloy" ], + "volume": "875000 ml", + "weight": "200 kg", + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] + } +] diff --git a/data/mods/Dark-Skies-Above/items/weapons.json b/data/mods/Dark-Skies-Above/items/weapons.json new file mode 100644 index 0000000000000..cb8eee3ac4ef9 --- /dev/null +++ b/data/mods/Dark-Skies-Above/items/weapons.json @@ -0,0 +1,43 @@ +[ + { + "id": "dks_flamesword_salvaged", + "type": "TOOL", + "category": "weapons", + "looks_like": "zweihander", + "name": { "str": "salvaged consecrator's sword" }, + "description": "A well built and decorated sword forged from dense alien metal. Its ability to conjure fireballs does not seem to respond to your will, but the cutting edge is perfectly servicable.", + "weight": "5400 g", + "volume": "3750 ml", + "price": 310000, + "bashing": 17, + "cutting": 40, + "material": "superalloy", + "symbol": "/", + "color": "light_gray", + "charges_per_use": 1, + "max_charges": 50, + "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 1 ] ], + "flags": [ "DURABLE_MELEE", "SHEATH_SWORD", "ALWAYS_TWOHAND" ] + }, + { + "id": "dks_knightsword_salvaged", + "type": "TOOL", + "symbol": "/", + "color": "light_gray", + "looks_like": "arming_sword", + "name": { "str": "salvaged knight's sword" }, + "description": "A well built sword made from dense alien metal, in service of the knights of the New Order. The runes that adorn it no longer glow, but its cutting edge is perfectly servicable.", + "price": 100000, + "material": "superalloy", + "techniques": [ "WBLOCK_2" ], + "weight": "3360 g", + "volume": "2 L", + "bashing": 14, + "cutting": 31, + "to_hit": 1, + "category": "weapons", + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 8 ] ], + "flags": [ "DURABLE_MELEE", "SHEATH_SWORD" ] + } +] diff --git a/data/mods/Dark-Skies-Above/mutations/traits.json b/data/mods/Dark-Skies-Above/mutations/traits.json new file mode 100644 index 0000000000000..578d13a0df98b --- /dev/null +++ b/data/mods/Dark-Skies-Above/mutations/traits.json @@ -0,0 +1,33 @@ +[ + { + "//": "RP traits that help define your character in the world. allows you to indicate your character's background, affecting some NPC interactions. somewhat experimental", + "type": "mutation", + "id": "DKS_COMBAT", + "name": "RP: Combatant", + "points": 0, + "description": "You've seen your fair share of scruffs and scrapes, and when the Cataclysm hit, you fought the Occupiers and managed to survive to tell the tale. Has no direct skill benefit, but allows you to present yourself as a fighter to certain NPCs. Some might even recognize you.", + "valid": false, + "starting_trait": true, + "purifiable": false + }, + { + "type": "mutation", + "id": "DKS_MED", + "name": "RP: Medic", + "points": 0, + "description": "Your job or experiences had you seeing all sorts of trauma, both physical and mental, and you were trusted during the Cataclysm to provide life-saving care. Has no direct skill benefit, but allows you to present yourself as a healer to certain NPCs. Some might even recognize you.", + "valid": false, + "starting_trait": true, + "purifiable": false + }, + { + "type": "mutation", + "id": "DKS_LEADER", + "name": "RP: Leader", + "points": 0, + "description": "Whether or not you like it, you've always had a knack for managing people and have some hard-won skill in doing so. During the arrival and the ensuing chaos, you helped lead people around you to safety. Has no direct skill benefit, but allows you to present yourself as a leader to certain NPCs. Some might even recognize you.", + "valid": false, + "starting_trait": true, + "purifiable": false + } +] diff --git a/data/mods/Dark-Skies-Above/speech/neworder_speech.json b/data/mods/Dark-Skies-Above/speech/neworder_speech.json new file mode 100644 index 0000000000000..09bfd1ac33562 --- /dev/null +++ b/data/mods/Dark-Skies-Above/speech/neworder_speech.json @@ -0,0 +1,68 @@ +[ + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter.", + "volume": 20 + }, + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter.", + "volume": 20 + }, + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter, followed by a response.", + "volume": 25 + }, + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter.", + "volume": 20 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war" ], + "sound": "a haunting mechanical humming.", + "volume": 60 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary_flame" ], + "sound": "a semi-musical chirping that echos across the landscape.", + "volume": 60 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + } +] From 237ed9969e90148edc0ba369f09f447fe7207bd7 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Fri, 6 Mar 2020 05:26:11 -0500 Subject: [PATCH 020/219] Dark Skies Part 4: Overrides (#38526) --- .../furniture_terrain/indoor_furniture.json | 31 ++++ .../furniture_terrain/outdoor-furniture.json | 9 ++ .../overrides/items/armor.json | 16 ++ .../overrides/items/books.json | 30 ++++ .../overrides/items/carnivore.json | 139 ++++++++++++++++++ .../overrides/items/electronic.json | 24 +++ .../overrides/items/generics.json | 16 ++ .../overrides/items/newspaper.json | 74 ++++++++++ .../overrides/items/ranged.json | 18 +++ .../overrides/items/tools.json | 51 +++++++ .../overrides/items/vehicle.json | 16 ++ .../overrides/items/weapons.json | 16 ++ .../overrides/locations/cemetery.json | 93 ++++++++++++ .../overrides/locations/overmap_special.json | 12 ++ .../Dark-Skies-Above/overrides/monsters.json | 56 +++++++ 15 files changed, 601 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json create mode 100644 data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/armor.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/books.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/carnivore.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/electronic.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/generics.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/newspaper.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/ranged.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/tools.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/vehicle.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/weapons.json create mode 100644 data/mods/Dark-Skies-Above/overrides/locations/cemetery.json create mode 100644 data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json create mode 100644 data/mods/Dark-Skies-Above/overrides/monsters.json diff --git a/data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json new file mode 100644 index 0000000000000..691ad164b9879 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json @@ -0,0 +1,31 @@ +[ + { + "//": "todo: add more tech junk to salvage from these things", + "type": "terrain", + "id": "t_plut_generator", + "copy-from": "t_plut_generator", + "name": "Edison generator", + "description": "This imposing apparatus harnesses 'atmospheric charges', or at least thats what the news said when these things came out. Pioneered by Elton Moosek and his Bluebox team, these were immediately snapped up by the government due to their potential to generate near limitless power. It's not doing much good here though. Perhaps it could be salvaged for other purposes.", + "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": "scrap", "count": [ 8, 16 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_dresser", + "copy-from": "f_dresser", + "name": "dresser", + "description": "Dress yourself!" + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json new file mode 100644 index 0000000000000..646f31a041806 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json @@ -0,0 +1,9 @@ +[ + { + "type": "furniture", + "id": "f_mutpoppy", + "copy-from": "f_mutpoppy", + "name": "poppy bush", + "description": "An invasive species brought to Earth by the invaders and found it quite to its liking. It spiny, writhing fronds make it look more like a jungle bush than a conventional poppy except for its red petals, but is named after such due to its similar medicinal properties. It exudes a potent, sleep inducing aroma." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/armor.json b/data/mods/Dark-Skies-Above/overrides/items/armor.json new file mode 100644 index 0000000000000..af4aa91b453be --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/armor.json @@ -0,0 +1,16 @@ +[ + { + "id": "quiver_large", + "copy-from": "quiver_large", + "type": "ARMOR", + "name": { "str": "large quiver" }, + "description": "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 sometimes horses are a little hard to come by in this day and age. Activate to store arrows." + }, + { + "id": "bra", + "copy-from": "bra", + "type": "ARMOR", + "name": { "str": "bra" }, + "description": "A simple bra. For protecting those bits you don't want creatures to look at." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/books.json b/data/mods/Dark-Skies-Above/overrides/items/books.json new file mode 100644 index 0000000000000..ca0ca3f5f373a --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/books.json @@ -0,0 +1,30 @@ +[ + { + "id": "child_book", + "copy-from": "child_book", + "type": "BOOK", + "name": { "str": "children's book" }, + "description": "A little book for little readers. The colorful cartoon characters and sweet stories contained herein belong to a different time, before the sky grew dark and the aliens arrived." + }, + { + "id": "mag_news", + "copy-from": "mag_news", + "type": "BOOK", + "name": { "str": "TIME magazine" }, + "description": "Current events concerning a bunch of people who're all dead now - or working for them." + }, + { + "id": "ZSG", + "copy-from": "ZSG", + "type": "BOOK", + "name": { "str": "Zombie Survival Guide", "str_pl": "copies of Zombie Survival Guide" }, + "description": "While this seems like it would be at least partially useful in this situation, the sheer amount of speculative fiction present makes it practically useless. What the hell is a mi-go? Aren't triffids from some ancient movie?" + }, + { + "id": "mag_tv", + "copy-from": "mag_tv", + "type": "BOOK", + "name": { "str": "US Weekly", "str_pl": "US Weeklies" }, + "description": "Current events concerning a bunch of people who're all dead now - or working for them." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/carnivore.json b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json new file mode 100644 index 0000000000000..07ccc2b00fac3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json @@ -0,0 +1,139 @@ +[ + { + "id": "brain_cooked", + "type": "COMESTIBLE", + "copy-from": "brain_cooked", + "looks_like": "offal_cooked", + "name": { "str": "cooked brains", "str_pl": "cooked brains" }, + "description": "Now you can emulate a zombie! Preparing brain for eating is challenging, and this doesn't seem to be the best way to do it." + }, + { + "//": "tainted meat is meat that has been heavily genetically poisoned or is completely alien in nature", + "type": "COMESTIBLE", + "id": "meat_tainted", + "copy-from": "meat_tainted", + "name": { "str": "chunk of alien meat", "str_pl": "chunks of alien meat" }, + "description": "This dense, stringy substance smells strongly like burnt oil, or some sort of industrial chemical. For all intents and purposes, it seems like the 'meat' of the creature, but its bizarre texture and faintly red-purple tint is unlike anything you've ever experienced before. You could eat it, but no doubt it would not only taste henious but also make you sick, being made of material your body was never supposed to injest." + }, + { + "type": "COMESTIBLE", + "id": "dry_meat_tainted", + "name": "dehydrated alien meat", + "copy-from": "dry_meat_tainted", + "description": "Pieces of alien meat that have been dried to prevent them from rotting away. It will still poison you if you eat this." + }, + { + "type": "COMESTIBLE", + "id": "bone_tainted", + "category": "other", + "copy-from": "bone_tainted", + "name": "alien bone", + "description": "A piece of a hard material with many crests and protrusions, made of a hard material that occasionally leaves a bit of moisture on your hand when you touch it. It seems basically like a bone, though not one you'd see in any anatomy textbook. You could eat it, but no doubt it would not only taste henious but also make you sick, being made of material your body was never supposed to injest. It might at least be able to be used for something, if not as well as the earthly variant due to its fiddly size and shape." + }, + { + "type": "COMESTIBLE", + "id": "fat_tainted", + "category": "other", + "copy-from": "fat_tainted", + "name": "alien fat", + "description": "A chunk of dense fat that is tough and rubbery. It smells simply henious, like open sewer and pungent chemicals, and is doubtless full of strange material that your body was never supposed to injest. It might at least be able to be used for something, if not quite as well as its earthly variant due to its relative impurities." + }, + { + "type": "COMESTIBLE", + "id": "tallow_tainted", + "copy-from": "tallow_tainted", + "name": "alien tallow", + "description": "A smooth grayish block of cleaned and rendered alien fat. Processing it seems to have at least removed some of the smell. It won't spoil for a very long time, and can be used as an ingredient in many projects. It is no safer than its source material to consume." + }, + { + "//": "mutant meat is meat that comes from a creature that is spliced with earthly genes or originally came from earth before being modded", + "id": "mutant_meat", + "copy-from": "mutant_meat", + "type": "COMESTIBLE", + "name": { "str": "chunk of unusual meat", "str_pl": "chunks of unusual meat" }, + "description": "Meat from the aliens is typically quite foul, full of toxins and substances not meant to be digested by humans, however this piece almost looks edible - if not for a few sections that still have strange hues and disgusting, spongey texture. Still, with a bit of preperation, it might even be somewhat palatable." + }, + { + "id": "mutant_meat_scrap", + "type": "COMESTIBLE", + "copy-from": "mutant_meat_scrap", + "name": { "str": "scrap of unusual meat", "str_pl": "scraps of unusual meat" }, + "description": "A tiny scrap of meat from an unusual creature. It smells a bit odd and has a variety of discolorations that indicate that it is still going to be rough on your digestive system. Still, seems digestible at least, if you cook it and remove the worst parts." + }, + { + "id": "mutant_human_flesh", + "copy-from": "mutant_human_flesh", + "type": "COMESTIBLE", + "name": "unusual humanoid meat", + "description": "Freshly butchered from the body of an alien creature that was unsettlingly humanoid in appearance. It smells faintly of chemicals and is colored odd hues that indicate that it is still going to be rough on your digestive system. You'd have to be crazy or starving to eat this." + }, + { + "id": "mutant_human_cooked", + "copy-from": "mutant_human_cooked", + "type": "COMESTIBLE", + "name": "cooked cretin", + "description": "Cooked meat from an alien humanoid. Now that the worst bits have been processed, it's probably digestible, if not very appetizing." + }, + { + "id": "mutant_meat_cooked", + "type": "COMESTIBLE", + "copy-from": "mutant_meat_cooked", + "name": "cooked unusual meat", + "description": "This is a cooked chunk of meat from an unusual critter. It has strange colors, smells a bit funny, and has a mushy texture but it tastes… mostly normal. Hopefully you cut away the worst bits well enough." + }, + { + "id": "mutant_meat_scrap_cooked", + "type": "COMESTIBLE", + "copy-from": "mutant_meat_scrap_cooked", + "name": { "str": "cooked scrap of unusual meat", "str_pl": "cooked scraps of unusual meat" } + }, + { + "id": "mutant_tallow", + "type": "COMESTIBLE", + "copy-from": "mutant_tallow", + "name": "unusual tallow", + "description": "A smooth white block of cleaned and rendered fat sourced from an unusual creature. It will remain edible for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "id": "mutant_lard", + "type": "COMESTIBLE", + "copy-from": "mutant_lard", + "name": "unusual lard", + "description": "A smooth white block of dry-rendered fat sourced from an alien. It will remain edible for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "id": "mutant_human_fat", + "type": "COMESTIBLE", + "copy-from": "mutant_human_fat", + "name": { "str": "chunk of mutant humanoid fat", "str_pl": "chunks of mutant humanoid fat" }, + "description": "Freshly butchered fat from an alien humanoid." + }, + { + "type": "COMESTIBLE", + "id": "mutant_human_tallow", + "name": "unusual humanoid tallow", + "copy-from": "mutant_human_tallow", + "description": "A smooth white block of cleaned and rendered fat sourced from an alien humanoid. It won't rot for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "type": "COMESTIBLE", + "id": "mutant_human_lard", + "name": "unusual humanoid lard", + "copy-from": "mutant_human_lard", + "description": "A smooth white block of dry-rendered fat sourced from an alien humanoid. It won't rot for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "type": "COMESTIBLE", + "id": "raw_hleather", + "copy-from": "raw_hleather", + "name": "raw human skin", + "description": "A carefully folded raw skin harvested from a humanoid. You can cure it for storage and tanning, or eat it if you're desperate enough." + }, + { + "type": "COMESTIBLE", + "id": "raw_hfur", + "copy-from": "raw_hfur", + "name": "raw humanoid pelt", + "description": "A carefully folded raw skin harvested from a fur-bearing creature that was disturbingly humanoid. It still has the fur attached. You can cure it for storage and tanning, or eat it if you're desperate enough." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/electronic.json b/data/mods/Dark-Skies-Above/overrides/items/electronic.json new file mode 100644 index 0000000000000..9ac5410d1c44b --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/electronic.json @@ -0,0 +1,24 @@ +[ + { + "id": "smart_phone", + "type": "TOOL", + "name": { "str": "smartphone" }, + "copy-from": "smart_phone", + "description": "A popular, fancy smartphone. Capable of making photos due to integrated camera and illuminating an area as per its flashlight app, assuming it has enough charge. The smartphone also has a clock app that includes an alarm. Runs on a small, proprietary power cell that needs a specialized charger. That is to say, is quite difficult to recharge post-Cataclysm.", + "delete": { "flags": [ "USE_UPS" ] } + }, + { + "id": "smartphone_music", + "copy-from": "smartphone_music", + "type": "TOOL", + "name": { "str": "smartphone - music", "str_pl": "smartphones - music" }, + "delete": { "flags": [ "USE_UPS" ] } + }, + { + "id": "smart_phone_flashlight", + "copy-from": "smart_phone_flashlight", + "type": "TOOL", + "name": { "str": "smartphone - Flashlight", "str_pl": "smartphones - Flashlight" }, + "delete": { "flags": [ "USE_UPS" ] } + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/generics.json b/data/mods/Dark-Skies-Above/overrides/items/generics.json new file mode 100644 index 0000000000000..1d1f3c3e745b5 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/generics.json @@ -0,0 +1,16 @@ +[ + { + "id": "brush_toilet", + "name": { "str": "toilet brush", "str_pl": "toilet brushes" }, + "copy-from": "brush_toilet", + "type": "GENERIC", + "description": "The aliens that have invaded Earth cannot be intimidated or humiliated - at least not meaningfully - so this stiff brush is only useful for scouring toilet bowls." + }, + { + "type": "GENERIC", + "id": "basketball", + "copy-from": "basketball", + "name": "basketball", + "description": "A high-quality indoor basketball. You could throw it at your enemies." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/newspaper.json b/data/mods/Dark-Skies-Above/overrides/items/newspaper.json new file mode 100644 index 0000000000000..99e9e0a635d6a --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/newspaper.json @@ -0,0 +1,74 @@ +[ + { + "type": "GENERIC", + "id": "newest_newspaper", + "category": "books", + "copy-from": "newest_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_newest_news", + "description": "A single sheet of newspaper broadsheet. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly - some things from before the Cataclysm, and some even after." + }, + { + "type": "GENERIC", + "id": "many_years_old_newspaper", + "category": "books", + "copy-from": "many_years_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_many_years_old_news", + "description": "A single sheet of newspaper broadsheet. It seems to date from several years ago, and you've NO idea how it lasted this long. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "years_old_newspaper", + "category": "books", + "copy-from": "years_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_years_old_news", + "description": "A single sheet of newspaper broadsheet. It seems to date from a few years ago--amazing it has lasted this long. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "one_year_old_newspaper", + "copy-from": "one_year_old_newspaper", + "category": "books", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_one_year_old_news", + "description": "A single sheet of newspaper broadsheet. It was printed more than a year ago. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "months_old_newspaper", + "category": "books", + "copy-from": "months_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_months_old_news", + "description": "A single sheet of newspaper broadsheet. It was printed in the months leading up to the Cataclysm. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "weeks_old_newspaper", + "category": "books", + "copy-from": "weeks_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_weeks_old_news", + "description": "A single sheet of newspaper broadsheet. It was printed in the weeks leading up to the Cataclysm. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "survnote", + "category": "books", + "copy-from": "survnote", + "name": { "str": "survivor's note" }, + "snippet_category": "dks_note", + "description": "A scrap of paper. Something's written on it, scrawled in bad handwriting." + }, + { + "type": "GENERIC", + "id": "flyer", + "category": "books", + "copy-from": "flyer", + "name": { "str": "flyer" }, + "snippet_category": "dks_flier", + "description": "A scrap of paper." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/ranged.json b/data/mods/Dark-Skies-Above/overrides/items/ranged.json new file mode 100644 index 0000000000000..153563f1688ae --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/ranged.json @@ -0,0 +1,18 @@ +[ + { + "id": "longbow", + "//": "Tileset whitelist for bows", + "type": "GUN", + "copy-from": "longbow", + "name": { "str": "longbow" }, + "description": "A six-foot wooden bow that takes a fair amount of strength to draw. It can be used effectively by those of somewhat above-average strength. Used mainly in medieval England in wartime, but pierces hide just as well as chainmail." + }, + { + "id": "rifle_flintlock", + "looks_like": "ar15", + "type": "GUN", + "copy-from": "rifle_flintlock", + "name": { "str": "flintlock rifle" }, + "description": "This ancient firearm lacks the fire-rate of modern weapons, but packs as much punch as the best of 'em and rewards the skilled shooter with easily-crafted ammunition." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/tools.json b/data/mods/Dark-Skies-Above/overrides/items/tools.json new file mode 100644 index 0000000000000..71861f76a60c4 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/tools.json @@ -0,0 +1,51 @@ +[ + { + "id": "carver_off", + "copy-from": "carver_off", + "type": "TOOL", + "name": { "str": "electric carver (off)", "str_pl": "electric carvers (off)" }, + "description": "An electric meat carver powered by batteries. Two serrated blades that vibrate together to slice just about anything from turkey to ham… even your enemies!" + }, + { + "id": "noise_emitter", + "copy-from": "noise_emitter", + "type": "TOOL", + "name": { "str": "noise emitter (off)", "str_pl": "noise emitters (off)" }, + "description": "This device was constructed by 'enhancing' a speaker ripped off from some electronic device with some amplifier circuits. It has now no other use beside emitting loud crackling static noise, that could distract an enemy." + }, + { + "id": "noise_emitter_on", + "copy-from": "noise_emitter_on", + "type": "TOOL", + "name": { "str": "noise emitter (on)", "str_pl": "noise emitters (on)" }, + "description": "This device has been turned on and is emitting horrible crackles, pops and other static sounds. Quick, get away from it before it draws enemies to you!" + }, + { + "id": "e_handcuffs", + "copy-from": "e_handcuffs", + "type": "TOOL", + "name": { "str": "electronic handcuffs", "str_pl": "electronic handcuffs" }, + "description": "A pair of electronic handcuffs, used by automated New Order units to detain captives. Their continuous siren clearly identifies the wearer as a person of interet and alerts nearby 'safety teams' to their presence. Wait for their arrival, don't try to escape or to remove the cuffs - they will administer an electric shock.\nHowever, since capture is out of the question, you're probably in for a painful time, unless you get creative…" + }, + { + "id": "trimmer_off", + "copy-from": "trimmer_off", + "type": "TOOL", + "name": { "str": "hedge trimmer (off)", "str_pl": "hedge trimmers (off)" }, + "description": "A cordless, double-sided, gasoline-powered hedge trimmer. A long line of sharp-edged teeth extends from the engine; turning the trimmer on will make them rapidly vibrate. The poor man's chainsaw as far as your enemies are concerned." + }, + { + "id": "trimmer_on", + "copy-from": "trimmer_on", + "type": "TOOL", + "name": { "str": "hedge trimmer (on)", "str_pl": "hedge trimmers (on)" }, + "description": "A cordless, double-sided, gasoline-powered hedge trimmer. It is currently on, ready to do some alien topiary; use this item to turn it off." + }, + { + "id": "circsaw_off", + "copy-from": "circsaw_off", + "type": "TOOL", + "name": { "str": "circular saw (off)", "str_pl": "circular saws (off)" }, + "description": "A lightweight handheld cordless circular saw. Spins a circular blade fast enough to cut wood, aliens, or in an emergency, pizza. The blade, while effective in combat, is hard to hit with due to its small size." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/vehicle.json b/data/mods/Dark-Skies-Above/overrides/items/vehicle.json new file mode 100644 index 0000000000000..c95307fd9f6b3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/vehicle.json @@ -0,0 +1,16 @@ +[ + { + "type": "GENERIC", + "id": "reinforced_solar_panel", + "copy-from": "reinforced_solar_panel", + "name": { "str": "reinforced solar panel" }, + "description": "A solar panel that has been covered with a pane of reinforced glass to protect the delicate solar cells from aliens or errant baseballs. The glass causes this panel to produce slightly less power than a normal panel. Useful for a vehicle." + }, + { + "type": "GENERIC", + "id": "reinforced_solar_panel_v2", + "copy-from": "reinforced_solar_panel_v2", + "name": { "str": "upgraded reinforced solar panel" }, + "description": "An upgraded solar panel that has been covered with a pane of reinforced glass to protect the delicate solar cells from aliens or errant baseballs. The glass causes this panel to produce slightly less power than a normal upgraded panel. Useful for a vehicle." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/weapons.json b/data/mods/Dark-Skies-Above/overrides/items/weapons.json new file mode 100644 index 0000000000000..34426f495152d --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/weapons.json @@ -0,0 +1,16 @@ +[ + { + "id": "lobotomizer", + "copy-from": "lobotomizer", + "type": "TOOL", + "name": { "str": "lobotomizer" }, + "description": "This is a hand-forged collapsible tool that has two axe heads and sharp shovel-like tip on one end. It can be used as a shovel, or you could chop an enemy up with it instead." + }, + { + "id": "spear_spike", + "copy-from": "spear_spike", + "type": "TOOL", + "name": { "str": "spike on a stick" }, + "description": "A flimsy pole made of wood with a basic metal spike tied to it. It's barely sharp, and crudely constructed, but it will keep an enemy out of arm's reach until you can find something better." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/locations/cemetery.json b/data/mods/Dark-Skies-Above/overrides/locations/cemetery.json new file mode 100644 index 0000000000000..35e88053a7208 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/locations/cemetery.json @@ -0,0 +1,93 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "cemetery_4square_11" ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + " 1=", + "]]]]]]]] 11111111 7$=", + "]]]]]]]] 1=", + " SMS ]] 1$$$$$$1$$$$ 7=", + " ] ]] 1--0---G---$ 7=", + "]]]]]]]] 1-TT_,,n,,-$ $=", + " ]] $G,,_,,,,,G$ 7=", + " ]] $G_+_,,T,,G$ $=", + " 7 ]] S-,,,,,,,,-$ $=", + " ]]]]+,,,,bbb,G$ $=", + " ]]]]+,,,,,,,,G$ 7=", + " ]] S-,,S,bbb,-$ 7=", + " 7 ]] $G,,,,,,,,G$ 1=", + " ]] $G,,_,bbb,G$ 1=", + " ]] 1-,f_,,,,,-$ 7=", + " ]] 1--GG--GG--$ 7=", + " 7 ]] 1$$$$$$$$$$$ $=", + " ]]] $=", + " ]]]] 777 777 7=", + " ]]] ] $=", + " ]]]7iSi7 777 777 1=", + "]]]] 7---7 1=", + "$$11 11711 $$177$117$77=", + "========================" + ], + "terrain": { + " ": [ "t_dirt", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass" ], + "$": [ "t_shrub", "t_shrub", "t_shrub", "t_underbrush", "t_underbrush", "t_tree_young" ], + "+": [ "t_door_locked", "t_door_locked", "t_door_locked", "t_door_locked", "t_door_locked", "t_door_c" ], + ",": "t_floor", + "-": "t_rock_smooth", + ".": "t_pavement", + "0": "t_window_domestic", + "1": [ "t_tree_young", "t_tree_young", "t_tree_young", "t_tree_young", "t_tree", "t_shrub" ], + "7": [ "t_tree", "t_tree", "t_tree_willow" ], + ":": "t_pavement_y", + "<": "t_stairs_up", + "=": "t_rock_wall_half", + ">": "t_stairs_down", + "G": [ "t_window_stained_green", "t_window_stained_green", "t_window_stained_red", "t_window_stained_blue" ], + "O": "t_chainfence_posts", + "]": "t_sidewalk", + "_": "t_wall", + "a": "t_wall_glass_alarm", + "d": "t_door_glass_c", + "i": "t_column", + "o": "t_fencegate_o" + }, + "furniture": { + "8": "f_shackle", + "M": "f_grave_monument", + "P": "f_sign", + "S": "f_statue", + "T": "f_table", + "^": "f_grave_stone", + "a": "f_sink", + "b": "f_bench", + "c": "f_counter", + "f": "f_rack", + "g": [ + "f_grave_head", + "f_grave_head", + "f_grave_head", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone_old", + "f_statue" + ], + "h": "f_grave_head", + "n": "f_slab", + "r": "f_rubble_rock", + "x": "f_grave_stone_old" + }, + "place_items": [ + { "item": "church", "x": [ 14, 18 ], "y": [ 5, 14 ], "chance": 65 }, + { "item": "church", "x": [ 11, 12 ], "y": [ 5, 6 ], "chance": 65 }, + { "item": "jackets", "x": [ 12 ], "y": [ 14 ], "chance": 50 } + ] + } + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json b/data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json new file mode 100644 index 0000000000000..82f49bd99d5b1 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json @@ -0,0 +1,12 @@ +[ + { + "type": "overmap_special", + "id": "Toxic Waste Dump", + "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "toxic_dump_north" } ], + "locations": [ "land" ], + "city_distance": [ 15, -1 ], + "city_sizes": [ 0, 12 ], + "occurrences": [ 0, 1 ], + "flags": [ "CLASSIC" ] + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/monsters.json b/data/mods/Dark-Skies-Above/overrides/monsters.json new file mode 100644 index 0000000000000..ea7a618811662 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/monsters.json @@ -0,0 +1,56 @@ +[ + { + "id": "mon_c4_hack", + "copy-from": "mon_c4_hack", + "type": "MONSTER", + "name": { "str": "C-4 hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have some C-4 inside." + }, + { + "id": "mon_flashbang_hack", + "copy-from": "mon_flashbang_hack", + "type": "MONSTER", + "name": { "str": "flashbang hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have a flashbang inside." + }, + { + "id": "mon_gasbomb_hack", + "copy-from": "mon_gasbomb_hack", + "type": "MONSTER", + "name": { "str": "tear gas hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have a tear gas canister inside." + }, + { + "id": "mon_grenade_hack", + "copy-from": "mon_grenade_hack", + "type": "MONSTER", + "name": { "str": "grenade hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have a grenade inside." + }, + { + "id": "mon_manhack", + "copy-from": "mon_manhack", + "type": "MONSTER", + "name": { "str": "manhack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated anti-personnel drone, a small flying robot surrounded by whirring blades." + }, + { + "id": "mon_rattlesnake_giant", + "copy-from": "mon_rattlesnake_giant", + "type": "MONSTER", + "name": "giant rattlesnake", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_nakedmolerat_giant", + "copy-from": "mon_nakedmolerat_giant", + "type": "MONSTER", + "name": "gigantic naked mole-rat", + "delete": { "categories": [ "WILDLIFE" ] } + } +] From 1ce00298aa8995542863f9d4fbfb13cafd98732f Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Tue, 3 Mar 2020 20:51:24 -0500 Subject: [PATCH 021/219] Dark Skies 5: Override Scraps (#38550) --- .../overrides/locations/evac_center.json | 589 ++++++++++++++++++ .../Dark-Skies-Above/overrides/scenarios.json | 297 +++++++++ 2 files changed, 886 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/overrides/locations/evac_center.json create mode 100644 data/mods/Dark-Skies-Above/overrides/scenarios.json diff --git a/data/mods/Dark-Skies-Above/overrides/locations/evac_center.json b/data/mods/Dark-Skies-Above/overrides/locations/evac_center.json new file mode 100644 index 0000000000000..f070b29e88f95 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/locations/evac_center.json @@ -0,0 +1,589 @@ +[ + { + "type": "mapgen", + "method": "json", + "weight": 100, + "om_terrain": [ "shelter" ], + "object": { + "fill_ter": "t_floor", + "rows": [ + " !!!!!!!!!!!!!!!! ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " &&&&&&&&&&&&&&&& ", + " |----:-++-:----| ", + " |.............6| ", + " |..............| ", + " |..............| ", + " |..............| ", + " :..............: ", + " |..............| ", + " |......>>......| ", + " |......>>......| ", + " |..............| ", + " :..............: ", + " |..............| ", + " |..............| ", + " |||............| ", + " |*=...........6| ", + " |----:--+-:----|4 " + ], + "palettes": [ "shelter" ], + "place_nested": [ + { + "chunks": [ [ "dks_shelter_nest_base", 25 ], [ "dks_shelter_nest_used", 45 ], [ "dks_shelter_nest_vandalized", 30 ] ], + "x": 0, + "y": 0 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "weight": 100, + "om_terrain": [ "shelter_1" ], + "object": { + "fill_ter": "t_floor", + "rows": [ + " !!!!!!!!!!!!!!!! ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " &&&|---++---|&&& ", + " |........| ", + " |-:|........| ", + " |...........|:-| ", + " |.............6| ", + " |..............| ", + " :..............: ", + " |..............| ", + " |..............| ", + " |........|||...| ", + " |.-----..|*=...| ", + " :........|||...: ", + " |..........|-+-| ", + " |..........|...| ", + " |..........|>..| ", + " |..........|>..|4 ", + " |----:--+-:----| " + ], + "palettes": [ "shelter" ], + "place_nested": [ + { + "chunks": [ [ "dks_shelter_1_nest_base", 25 ], [ "dks_shelter_1_nest_used", 45 ], [ "dks_shelter_1_nest_vandalized", 30 ] ], + "x": 0, + "y": 0 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "weight": 100, + "om_terrain": [ "shelter_2" ], + "object": { + "fill_ter": "t_floor", + "rows": [ + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " &&&&&&&&&&&&&&&& ", + " |-:-++-:-| ", + " ||------|........| ", + " |*|..............| ", + " |.=..............| ", + " |--|.............--| ", + " |..................| ", + " :..................: ", + " |..................| ", + " |.......|--|.......| ", + " |........>>........| ", + " |........>>........| ", + " :.......|--|.......: ", + " |..................| ", + " |..................| ", + " |--..............--| ", + " |................|4 ", + " |--------|.......| ", + " |-:-+-:-| " + ], + "palettes": [ "shelter" ], + "place_nested": [ + { + "chunks": [ [ "dks_shelter_2_nest_base", 25 ], [ "dks_shelter_2_nest_used", 45 ], [ "dks_shelter_2_nest_vandalized", 30 ] ], + "x": 0, + "y": 0 + } + ], + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_nest_base", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " llll c 6 ", + " b b b c ", + " b b b c ", + " b b b c ", + " b b b ", + " ", + " ", + " ", + " ", + " b b b ", + " b b b c ", + " b b b c ", + " b b c ", + " c 6 ", + " " + ], + "terrain": { " ": "t_null" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 75 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_nest_used", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |||||:|++|:||||| ", + " |llll......c..6| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " :.b.b.b........: ", + " |..............| ", + " |..............| ", + " |..............| ", + " |..............| ", + " :.b.b.b........: ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |||.b.b....c...| ", + " | =........c..x| ", + " |||||:||+|:||||| " + ], + "terrain": { "x": "t_console_broken" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { + "l": { "item": "SUS_evac_shelter_locker_used", "chance": 75 }, + "c": { "item": "SUS_evac_shelter_cabinet_used", "chance": 50 }, + "b": [ { "item": "shelter_supplies", "chance": 2 }, { "item": "trash", "chance": 2 } ], + ".": [ + { "item": "shelter_supplies", "chance": 1 }, + { "item": "trash", "chance": 1 }, + { "item": "trash_forest", "chance": 1 } + ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 10 ], [ "null", 90 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_nest_vandalized", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |||||:|++|:||||| ", + " |llll......c..6| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " :.b.b.b........: ", + " |..............| ", + " |..............| ", + " |..............| ", + " |..............| ", + " :.b.b.b........: ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |||.b.b....c...| ", + " | =........c..6| ", + " |||||:||+|:||||| " + ], + "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" + }, + "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 } ], + "b": [ { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ], + ".": [ { "item": "trash", "chance": 1 }, { "item": "trash_forest", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 5 ], [ "dks_general_graffiti", 20 ], [ "null", 75 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_1_nest_base", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " bbbbb c 6 ", + " c ", + " bbbbb c ", + " cc ", + " bbbbb ", + " l ", + " l ", + " l ", + " b b b c ", + " b b b c l ", + " b b b c l ", + " l ", + " " + ], + "terrain": { " ": "t_null" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 70 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_1_nest_used", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ||||++|||| ", + " |........| ", + " ||:|........| ", + " |...........|:|| ", + " |.bbbbb.....c.6| ", + " |...........c..| ", + " :.bbbbb.....c..: ", + " |...........cc.| ", + " |.bbbbb........| ", + " |.......l|||...| ", + " |.-----.l| =...| ", + " :.......l|||...: ", + " |.b.b.b...c|-+-| ", + " |.b.b.b...c|..l| ", + " |.b.b.b...c|..l| ", + " |..........|..l| ", + " |||||:||+|:||||| " + ], + "terrain": { "x": "t_console_broken" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { + "l": { "item": "SUS_evac_shelter_locker_used", "chance": 70 }, + "c": { "item": "SUS_evac_shelter_cabinet_used", "chance": 50 }, + "b": [ { "item": "shelter_supplies", "chance": 2 }, { "item": "trash", "chance": 2 } ], + ".": [ { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 10 ], [ "null", 90 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_1_nest_vandalized", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ||||++|||| ", + " |........| ", + " ||:|........| ", + " |...........|:|| ", + " |.bbbbb.....c.6| ", + " |...........c..| ", + " :.bbbbb.....c..: ", + " |...........cc.| ", + " |.bbbbb........| ", + " |.......l|||...| ", + " |.-----.l| =...| ", + " :.......l|||...: ", + " |.b.b.b...c|-+-| ", + " |.b.b.b...c|..l| ", + " |.b.b.b...c|..l| ", + " |..........|..l| ", + " |||||:||+|:||||| " + ], + "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" + }, + "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 } ], + "b": [ { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ], + ".": [ { "item": "trash", "chance": 1 }, { "item": "trash_forest", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 5 ], [ "dks_general_graffiti", 20 ], [ "null", 75 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_2_nest_base", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " % l ", + " cccc6 l ", + " l ", + " ", + " b bbbbb b b ", + " b b b b ", + " b b llll b b ", + " b b b b ", + " b b b b ", + " b b b b ", + " b b b b ", + " b b llll b b ", + " b b b b ", + " bbbb ", + " 6 ", + " c ", + " " + ], + "terrain": { " ": "t_null" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 70 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_2_nest_used", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ||:|++|:|| ", + " |||||||||%......l| ", + " |*|cccc6........l| ", + " |.=.............l| ", + " |--|.............||| ", + " |b.....bbbbb...b..b| ", + " :b..b..........b..b: ", + " |b..b...llll...b..b| ", + " |b..b...|--|...b..b| ", + " |b..b..........b..b| ", + " |b..b..........b..b| ", + " :b..b...|--|...b..b: ", + " |b..b...llll...b..b| ", + " |b..b..........b..b| ", + " |--.....bbbb.....||| ", + " |l..............x| ", + " ||||||||||......c| ", + " ||:|+|:|| " + ], + "terrain": { "x": "t_console_broken" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { + "l": { "item": "SUS_evac_shelter_locker_used", "chance": 70 }, + "c": { "item": "SUS_evac_shelter_cabinet_used", "chance": 50 }, + "%": [ + { "item": "shelter_supplies", "chance": 15, "repeat": [ 1, 2 ] }, + { "item": "trash", "chance": 25, "repeat": [ 1, 3 ] } + ], + "b": [ { "item": "shelter_supplies", "chance": 2 }, { "item": "trash", "chance": 2 } ], + ".": [ { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 10 ], [ "null", 90 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_2_nest_vandalized", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ||:|++|:|| ", + " |||||||||%......l| ", + " |*|cccc6........l| ", + " |.=.............l| ", + " |--|.............||| ", + " |b.....bbbbb...b..b| ", + " :b..b..........b..b: ", + " |b..b...llll...b..b| ", + " |b..b...|--|...b..b| ", + " |b..b..........b..b| ", + " |b..b..........b..b| ", + " :b..b...|--|...b..b: ", + " |b..b..........b..b| ", + " |b..b..........b..b| ", + " |--.....bbbb.....||| ", + " |l..............x| ", + " ||||||||||......c| ", + " ||:|+|:|| " + ], + "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", "t_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 } ], + "b": [ { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ], + ".": [ { "item": "trash", "chance": 1 }, { "item": "trash_forest", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 5 ], [ "dks_general_graffiti", 20 ], [ "null", 75 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_graffiti", + "object": { "mapgensize": [ 1, 1 ], "place_graffiti": [ { "x": 0, "y": 0, "snippet": "dks_shelter_graffiti_snippets" } ] } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_general_graffiti", + "object": { "mapgensize": [ 1, 1 ], "place_graffiti": [ { "x": 0, "y": 0, "snippet": "dks_general_graffiti_snippets" } ] } + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/scenarios.json b/data/mods/Dark-Skies-Above/overrides/scenarios.json new file mode 100644 index 0000000000000..f3df83c067b77 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/scenarios.json @@ -0,0 +1,297 @@ +[ + { + "type": "scenario", + "ident": "evacuee", + "copy-from": "evacuee", + "name": "Evacuee", + "description": "You have survived the initial wave of panic and managed to avoid being taken to the Designated Living Zones. You begin in the (relative) safety in one of the many government evac shelters.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "missed", + "copy-from": "missed", + "name": "Missed", + "description": "Whether due to stubbornness, ignorance, or just plain bad luck, you missed the evacuation and managed to avoid being turned into one of those things outside. You are now left in a city full of the hateful revenants of your neighbors.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "largebuilding", + "copy-from": "largebuilding", + "name": "Large Building", + "description": "Whether due to stubbornness, ignorance, or just plain bad luck, you missed the evacuation and managed to avoid being turned into one of those things outside. You are now left in a city full of the hateful revenants of your neighbors.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "surrounded", + "copy-from": "surrounded", + "name": "Surrounded", + "description": "You've attracted the attention of a pack of mutants in some way, now they're all around and you'll likely have to fight thorough them if you want to escape.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "isolationist", + "copy-from": "isolationist", + "name": "Safe Place", + "description": "You've found some distant safe place that seems to have gone unnoticed by the invasion force. Looks like you're on your own…", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "infected", + "copy-from": "infected", + "name": "Infected", + "description": "In the chaos and panic of the invasion, you got a horrible wound! You didn't get proper medical care, and now it has started turning green.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "fire", + "copy-from": "fire", + "name": "Burning Building", + "description": "The building you had chosen to reside in has suddenly caught fire! You might want to leave.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "patient", + "copy-from": "patient", + "name": "Challenge - Abandoned", + "professions": [ "unemployed", "patient" ] + }, + { + "type": "scenario", + "ident": "wilderness", + "copy-from": "wilderness", + "name": "Wilderness", + "description": "You find yourself amongst trees. The screaming and the explosions are fainter this far from civilization, but you'd better know what you're doing out here.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "heli_crash", + "copy-from": "heli_crash", + "name": "Helicopter Crash", + "description": "While being evacuated from a hot zone, the pilot lost control of the helicopter and crashed in the middle of nowhere. Hopefully some of the soldiers that were with you also survived the accident.", + "professions": [ "soldier", "specops", "national_guard", "politician" ] + } +] From 9e1900121038884fc85f87e61e8e3c9772fc3ce9 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Tue, 3 Mar 2020 21:09:50 -0500 Subject: [PATCH 022/219] Dark Skies 6: Snippets (#38551) --- .../Dark-Skies-Above/snippets/fliers.json | 299 +++++++++++ .../Dark-Skies-Above/snippets/graffiti.json | 117 +++++ .../Dark-Skies-Above/snippets/newspaper.json | 178 +++++++ .../mods/Dark-Skies-Above/snippets/radio.json | 15 + .../Dark-Skies-Above/snippets/survnotes.json | 495 ++++++++++++++++++ 5 files changed, 1104 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/snippets/fliers.json create mode 100644 data/mods/Dark-Skies-Above/snippets/graffiti.json create mode 100644 data/mods/Dark-Skies-Above/snippets/newspaper.json create mode 100644 data/mods/Dark-Skies-Above/snippets/radio.json create mode 100644 data/mods/Dark-Skies-Above/snippets/survnotes.json diff --git a/data/mods/Dark-Skies-Above/snippets/fliers.json b/data/mods/Dark-Skies-Above/snippets/fliers.json new file mode 100644 index 0000000000000..1a4ad838bc332 --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/fliers.json @@ -0,0 +1,299 @@ +[ + { + "type": "snippet", + "category": "dks_flier", + "text": [ + { + "id": "dks_flier_1", + "text": "This is an advertisement for Aunt Janice's Pickled Meat. \"When times get tough, the tough get pickling. Aunt Janice's Pickled Meat: more than 30% real beef!\"" + }, + { "id": "dks_flier_2", "text": "This is an advertisement for a quality-of-life medicine." }, + { "id": "dks_flier_3", "text": "This is an advertisement promoting enlisting in the US armed forces." }, + { + "id": "dks_flier_4", + "text": "This is a somewhat weather-worn advertisement for the 'new' FEMA evacuation shelters. Beneath the colorful photo it reads, \"Familiarize yourself with your nearest emergency shelter. It could save your life.\"" + }, + { + "id": "dks_flier_5", + "text": "This is an advertisement for a FEMA evacuation shelter. Beneath a picture of a shelter it reads, \"Contact your local FEMA office to arrange a tour of your nearest evacuation shelter. Be prepared!\"" + }, + { + "id": "dks_flier_6", + "text": "This is an advertisement for a pre-manufactured emergency supply kit. It is made of a very flashy tactical fabric and looks very impractical based on your experience. \"Be ready for anything with the Tactica Supreme GO-30 kit.\"00" + }, + { + "id": "dks_flier_7", + "text": "This is an ad for a complicated survival knife with an enormous serrated back edge and far too many tools included in the handle. \"Come down to the Knife Shack at Cumberton Mall! We've got it all.\"" + }, + { + "id": "dks_flier_8", + "text": "This is an advertisement for a local church. The picture looks surprisingly mundane, but the text is not: \"Revelations services offered round the clock. The end times are here, make your peace.\"" + }, + { + "id": "dks_flier_9", + "text": "This is an advertisement for a local church. It looks like it was put together at the last minute. \"Visit St Mary's on the River while it's not too late. Repent, while you still can!\"" + }, + { + "id": "dks_flier_10", + "text": "This is a hand-drawn flier that has been photocopied for wide distribution. It reads, in what looks like sharpie-bolded letters, \"THEY DON'T WANT YOU TO KNOW. They KNEW this would happen. They were watching everything. They struck a deal even before they landed.\" There used to be tear-away phone numbers at the bottom, but they're all gone now." + }, + { + "id": "dks_flier_11", + "text": "This is a government-issued, air-dropped alert. \"EVACUTE IMMEDIATELY. Proceed to your closest FEMA operated community shelter to await police and military escort to safety.\"" + }, + { + "id": "dks_flier_12", + "text": "This is a government-issued, air-dropped alert. \"EVACUATE IMMEDIATELY. Police and military forces have been dispatched to your area and will help escort you to safety.\"" + }, + { + "id": "dks_flier_13", + "text": "This is a government-issued, air-dropped alert. \"EVACUATION ALERT. Please make your way to the nearest FEMA evacuation shelter. Seek protection from police and military forces if traveling in groups.\"" + }, + { + "id": "dks_flier_14", + "text": "This is a government-issued, air-dropped alert. \"EVACUATION ALERT. Please make your way to the nearest FEMA evacuation shelter. Travel in groups and avoid crowds. Avoid hostile forces at all costs.\"" + }, + { + "id": "dks_flier_15", + "text": "This is a glossy, high quality flier. \"What they don't want you to know! Reading this may save your life.\" Inside is a series of warnings recommending people avoid the evacuation shelters, state roads, and worse, contact with any police or military forces as they might be rogue. A picture of uniformed humans apparently in league with the invaders is included, as well as several shots of civilians being lead off a FEMA bus and towards an alien spaceship." + }, + { + "id": "dks_flier_16", + "text": "This is a glossy advertisement from FEMA asking that people donate their canned goods in return for tax writeoffs. From the date on the flier, it doesn't look like the initative ever had time to get off the ground." + }, + { + "id": "dks_flier_17", + "text": "This is a grocery store coupon flier, dated three days before the evacuation orders went out. \"At Marigold Market, we still have canned food and bottled water! Come on in and stock up!\" The front image shows a grocery store, the entrance flanked by a pair of smiling guards armed with assault rifles." + }, + { + "id": "dks_flier_18", + "text": "This is an advertisement for a local electronics store, dated a few weeks before the evacuation order. \"Sale on smartphones and refurbished laptops at DigiMart, three days only!\"" + }, + { + "id": "dks_flier_19", + "text": "This very recent looking air-dropped alert. \"THE WAR IS OVER. Do not continue to fight. Fugitives will be charged with malcompliant destabilizaion if they do not surrender to their nearest safety office at once. Join our New Order. Do not live in squalor. Witness what we can do *together*.\" Pictured is one of the Designated Living Zones, a city and its surrounding areas set aside specifically for humans. Underneath is listed some of the many qualities of the DLZs: safety, cleanliness, opprotunity, and so on." + }, + { + "id": "dks_flier_20", + "text": "This very recent looking air-dropped alert. \"THE WAR IS OVER. Do not continue to fight. Surrender to your nearest surveillance drone for immediate evacuation to a designated civilian zone. Join our New Order. Witness what we can do *together*.\" Pictured is the president, along with several other 'smiling' world leaders, standing next to multiple cloaked creatures." + }, + { + "id": "dks_flier_21", + "text": "This very recent looking air-dropped alert. \"THE WAR IS OVER. Resistance will be met with lethal deterrence. Do not throw away your potential. Join our New Order. Witness what we can do *together*.\" Pictured is a smiling family of humans standing in front of an alien soldier." + }, + { + "id": "dks_flier_22", + "text": "This is an advertisement for a local funk-polka band, the \"Chilly Winters\". Apparently they were playing in the Wonky Donkey Pub." + }, + { + "id": "dks_flier_23", + "text": "This is a flier with the tour appearance dates of a small, niche-successful drum-and-bass/yodelling fusion band, the \"Ol' Yellers\". The dates continue well past the end of the world; most likely, the tour was cut short." + }, + { + "id": "dks_flier_24", + "text": "This is an advertisement for a death metal band, \"Roxanne and the Soul-Crushing Ennui\", known for mixing their ear-blasting riffs with chipper interludes of classic fifties doo-wop. The art depicts a zombified version of a Betty Crocker-esque housewife, slamming on a spike-encrusted electric guitar." + }, + { + "id": "dks_flier_25", + "text": "This is an advertisement for a local gun shop. In huge red letters, it reads: \"This is it. Arm yourselves and protect your freedom. Come on down while supplies last.\"" + }, + { "id": "dks_flier_26", "text": "This is a flier for pet food, with a cute animal performing a silly trick." }, + { + "id": "dks_flier_27", + "text": "This is an advertisement for a portable generator, the kind that was becoming popular in the face of increasing natural disasters before the end of the world as you knew it." + }, + { + "id": "dks_flier_28", + "text": "This is very recent looking air-dropped alert. \"HERE FOR YOU\" is written in somewhat imposing text at the bottom of a depiction of several smiling humans wearing Occupation uniforms." + }, + { + "id": "dks_flier_29", + "text": "This is very recent looking air-dropped alert. \"HERE FOR YOU\" is written in somewhat imposing text at the bottom of a depiction of several smiling humans wearing Occupation uniforms. Someone has scrawled \"TRAITORS\" in marker across the front." + }, + { + "id": "dks_flier_30", + "text": "This is very recent looking air-dropped alert. \"HERE FOR YOU\" is written in somewhat imposing text at the bottom of a depiction of several smiling humans wearing Occupation uniforms. Someone has scrawled \"FAIR WEATHER SOLDIERS\" across the front." + }, + { + "id": "dks_flier_31", + "text": "This is a public notice from a local police department encouraging citizens to pack their supplies before their designated evacuation date to ensure faster transit." + }, + { + "id": "dks_flier_32", + "text": "This is a public alert from the Centers for Disease Control. Its message, repeated in several languages, reads: PUBLIC HEALTH ALERT: Due to recent events, the CDC is issuing a warning to avoid public areas and spaces. An unknown biological contaminant is suspected to be affecting citizens. The CDC would like to remind the public to cover your nose and mouth when sneezing, wash your hands frequently, and receive an up-to-date flu shot if possible. Boiling water is recommended until further notice." + }, + { + "id": "dks_flier_33", + "text": "This is a public alert from the Federal Emergency Management Agency. Its message, repeated in several languages, reads: STAY IN YOUR HOMES! All residents of the New England Disaster Area are advised to shelter in place wherever possible. The United States Armed Forces are working to secure the area. If there is a nearby evacuation shelter you can get to safely, you are recommended to do so. Otherwise, stay in your homes until authorized personnel evacuate you to a secured facility. Thank you for your compliance." + }, + { + "id": "dks_flier_34", + "text": "This is a public alert from the Federal Emergency Management Agency. Its message, repeated in several languages, consists of a list of towns serving as major evacuation points from the hot zones. Someone has scribbled off most of the town names, and scrawled \"OVERRUN\" next to each one." + }, + { + "id": "dks_flier_35", + "text": "This is a public warning from an unnamed source. Its rambling message, poorly-photocopied onto both sides of the page, reads: Don't believe the lies! The Army cannot stop them, FEMA is in league with them. They want us alive but have no quams about killing anyone who RESISTS. Secure supplies and escape while there is still time." + }, + { + "id": "dks_flier_36", + "text": "This is a public message from an unnamed source. Its message, photocopied from a scrawled handwritten copy, reads: REPENT YOUR SINS O BABYLON FOR THE TIME OF HIS JUDGEMENT IS NIGH! LOOK UPON YOUR DESTRUCTION AND KNOW THAT IT IS JUST! YOU WILL BE DIVIDED FATHER AGAINST SON AND MOTHER AGAINST CHILD UNTO THE VERY LAST SINNER!" + }, + { + "id": "dks_flier_37", + "text": "This is a public warning from the Federal Government. Its brief message, repeated in several languages, reads: The President of the United States has declared unilateral martial law to be in effect in response to the ongoing national crisis. Continue to shelter in place until evacuated to an appropriate emergency management camp by authorized military personnel. A 24-hour curfew has been established. This curfew will remain in effect until further notice. Stay indoors to avoid friendly fire." + }, + { + "id": "dks_flier_38", + "text": "This is an advertisement for Galaxybux coffee. The smiling, feminine alien mascot seems a little inappropriate now." + }, + { + "id": "dks_flier_39", + "text": "This is a soda advertisement. On the front is a picture of a happy couple on a beach watching the sun set. Between them are bottles of soda. The poster reads, \"Cascade Cola, for those special moments\" in bold white letters." + }, + { + "id": "dks_flier_40", + "text": "This is a flier for a fast food chain. In it, a man is placing an order with an attractive woman wearing a bright green shirt in the window with two happy children sitting in the back seat. The flier reads \"Burgers, fries, and a Smile.\" Down in one corner is a company logo." + }, + { + "id": "dks_flier_41", + "text": "This is an advertisement for soda. It shows a dark brown can of soda on a black background. The label reads \"Spin\"." + }, + { + "id": "dks_flier_42", + "text": "This is a flyer for a local pizza chain. On it is a picture of a cartoon Italian holding a pizza, with the words \"It's a goooood pizza\" written above his head." + }, + { + "id": "dks_flier_43", + "text": "This is a poster advertising contact lenses. On it is a picture of a blood shot eye with a rather long block of information beneath it making some fairly exaggerated claims about the product." + }, + { + "id": "dks_flier_44", + "text": "This is a public alert from the Federal Emergency Management Agency. Its message, repeated in several languages, consists of a list of towns serving as major evacuation points from the hot zones." + }, + { + "id": "dks_flier_45", + "text": "This is a large movie poster for \"Action Packstone 6, Revenge of the Catgirls\". It shows a fit man in a leather jacket with a revolver and a claymore walking towards the viewer. At his side is his trusty cyberdog companion and in the background is an explosion." + }, + { + "id": "dks_flier_46", + "text": "This is an illustrated poster for a brand of solar car. The vehicle is driving through a lush country side as small animals look on. The slogan \"Improving the world, one tank at a time.\" is written across the top in small letters." + }, + { + "id": "dks_flier_47", + "text": "This is a soda advertisement. On the front is a picture of a happy couple on a beach watching the sun set. Between them are bottles of soda. The poster reads, \"Cascade Cola, for those special moments\" in bold white letters. Someone has colored in the sun with a black marker. The words \"oh Discordia\" are scrawled across the top." + }, + { + "id": "dks_flier_48", + "text": "This is a flier for a fast food chain. In it, a man is placing an order with an attractive woman wearing a bright green shirt in the window with two happy children in the back seat. The flier reads \"Burgers, fries, and a Smile.\" down in one corner is a company logo. Someone has gone to town on this one with a permanent marker. It is now covered in rude images and racial epithets." + }, + { + "id": "dks_flier_49", + "text": "This is a flier for a local pizza chain. On it is a picture of a cartoon Italian holding a pizza, with the words \"It's a goooood pizza\" written above his head. Someone has drawn an exaggerated mustache on the cartoon Italian, along with a pair of crude, oversized breasts." + }, + { + "id": "dks_flier_50", + "text": "This is a poster advertising contact lenses. On it is a picture of a blood shot eye. Someone has defaced this one. The informative part has been torn off, and written in jagged letters across the top in red crayon are the words \"ALL HAIL THE CRIMSON KING!\"." + }, + { + "id": "dks_flier_51", + "text": "This is an illustrated poster for a brand of solar car. The vehicle is driving through a lush country side as small animals look on. The slogan \"Improving the world, one tank at a time.\" is written across the top. Someone used a blue pen to write \"who gives a shit\" across the slogan and put X's over the eyes of all the animals." + }, + { + "id": "dks_flier_52", + "text": "This is a poster advertising a underground bunker. The poster shows a nuclear bomb wiping out a city while a family huddles safely underground. There a slogan \"Concerned about enemy attack? Want to protect your family? Join the VAULT program today.\" which is written in the middle. However, there seems to be no information about *how* one might do so." + }, + { + "id": "dks_flier_53", + "text": "This is a flier for Red Ryder BBGuns. On it a child is pulling a shining red wagon with a cooked pheasant on it and a wooden rifle over one shoulder. The child has a dog trailing beside him and a satisfied look on his face. The caption reads \"When you chose Red Ryder, you invested in the American Dream. You invested in our Independence.\"" + }, + { + "id": "dks_flier_54", + "text": "This is an old flier for a movie from the 30s. A tan man with slick black hair and muscles bulging through his offwhite suit is clasping a woman to his hip with one hand, and the woman is wearing a black leather dress. With her hips splayed, she is holding a pistol in one hand and starring directly out of the advert. The caption reads \"Witness the rebirth of New Noir with 'Jersey Shore Blues'. Starring Jenifer Languiz as 'Snookie'!\"" + }, + { + "id": "dks_flier_55", + "text": "\"Joe's Diner; 1/2 pound of meat, 3 toppings, 'your choice', all with a side of freedom fries and a BIG Gulp size pop.\"" + }, + { + "id": "dks_flier_56", + "text": "This is an advertisement for the popular fast food chain, Foodplace. On an unadorned blue-and-magenta background it shows clear, unmistakable depictions of their products and plainly stated prices. The foodburger looks particularly nice." + }, + { + "id": "dks_flier_57", + "text": "This is a leaflet about autoclaving procedure. One sentence catches your attention \"/!\\Always place your tools into an autoclave pouch before autoclaving./!\\\"" + }, + { + "id": "dks_flier_58", + "text": "This is a propaganda poster from only a few weeks before the evacuation orders. A parent dressed in military fatigues hugs their partner goodbye as their smiling children look on. \"Enlist today. Take you freedom in your own hands.\"" + }, + { + "id": "dks_flier_59", + "text": "This is a propaganda poster from only a few weeks before the evacuation orders. A handsome looking person dressed in military fatigues exercises along with several other people. \"Enlist today.\"" + }, + { + "id": "dks_flier_60", + "text": "This is a propaganda poster from only a few weeks before the evacuation orders. Someone in military fatigues is helping someonestand up. \"Enlist today and become a community leader.\"" + }, + { + "id": "dks_flier_61", + "text": "This advertisement reads \"Sick of FUEL PRICES? Bus stop too far? Get your driving fix from THE SUN! Solar powered electric cars by Edison: Silent, Cheap, Powerful.\"" + }, + { + "id": "dks_flier_62", + "text": "This is an advertisement that looks like it came right out of Silicon Valley. 'Space age aesthetic' is written in cursive scipt underneath a picture of some sleek but terribly useless home gadget." + }, + { + "id": "dks_flier_63", + "text": "PICKLED MEAT IN A JAR! Just like your grandma used to make! It will last for months or longer, and when you've eaten it, you can refill and seal the jar! Stock your emergency supply TODAY!" + }, + { + "id": "dks_flier_64", + "text": "BAGS, BAGS, BAGS! They're very useful things! If we didn't have BAGS, what-would-we-use… to PUT a lot of things in!? (Ad by the \"Play SchoolClothing Co.\")" + }, + { + "id": "dks_flier_65", + "text": "GLAMOPOLITAN! We've got ALL the latest tips! Whether you want to know what the elite are eating, wearing or discussing, Glamopolitan is YOUR magazine! So pick up a copy today and \"Sizzle Like A Star\"!" + }, + { + "id": "dks_flier_66", + "text": "POPULAR MECHANICS: People say mechanics is boring? We say, Prove them Wrong! We've got all the articles that make it interesting to talk about, so you can \"Make Mechanics Popular\"!" + }, + { + "id": "dks_flier_67", + "text": "BIRDHOUSE MONTHLY… Which wood would a woodpecker prefer? This month we discuss hardwood versus soft woods, whether to lacquer, oil or paint, and which type of nails you should use!" + }, + { + "id": "dks_flier_68", + "text": "FEELING BLUE? Try \"Greens\" for Magazines! Your local Supermarket! Nothing cheers you up like a good magazine… Unless it's JUNK FOOD! Or why not buy an MP3 PLAYER or a GAME CONSOLE? Chase those Blues away at GREENS Supermarket" + }, + { + "id": "dks_flier_69", + "text": "…What do you know about surviving in the Wilderness? If you can't make a snare you don't know TRAP! Hunt down a copy of TRAPPERS' LIFE and learn about wildlife!… And how to kill it. Classic BEAR TRAP returns in this issue!" + }, + { + "id": "dks_flier_70", + "text": "HUNTING GOODS! Food prices getting you down? Why not get a crossbow or compound bow and Hunt Your Own!? Our arrows and bolts are completely reusable, so why not hunt animals like Mother Nature intended?" + }, + { + "id": "dks_flier_71", + "text": "FEELING BLUE? Try \"Greens\" for Magazines! Your local Supermarket! Nothing cheers you up like a good magazine… Unless it's JUNK FOOD! Or why not buy an MP3 PLAYER or a GAME CONSOLE? Chase those blues away at GREENS Supermarket" + }, + { + "id": "dks_flier_72", + "text": "…What do you know about surviving in the Wilderness? If you can't make a snare you don't know TRAP! Hunt down a copy of TRAPPERS' LIFE and learn about wildlife!… And how to kill it. This week, a CROSSBOW TRAP!" + }, + { + "id": "dks_flier_73", + "text": "BIRDHOUSE MONTHLY… This month we look at some Dutch innovations in birdhouse design, and compare with the often confused Scandinavian Birdhouse design. Our article on sheet metal birdhouses will have you riveted!" + }, + { + "id": "dks_flier_74", + "text": "CRAFTY CRAFTERS QUARTERLY: Macaroni isn't just for eating anymore! Learn how to make jewelry and art from it as well! We also discuss the correct way to use superglue without gluing your hands together!" + }, + { + "id": "dks_flier_75", + "text": "\"The Nintendy Flip! Play your games anywhere!\" Following is an illustration of several people playing their games in unlikely places, using the titular gaming device." + } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/graffiti.json b/data/mods/Dark-Skies-Above/snippets/graffiti.json new file mode 100644 index 0000000000000..33b24ad7965b1 --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/graffiti.json @@ -0,0 +1,117 @@ +[ + { + "type": "snippet", + "category": "dks_general_graffiti_snippets", + "//": "This graffiti is generally assumed to come from before the Cataclysm", + "text": [ + { "id": "dks_general_graffiti_1", "text": " is the biggest slut in , and I'm damn proud of it!" }, + { "id": "dks_general_graffiti_2", "text": "There is a beautifully drawn graffiti tag on the wall here." }, + { "id": "dks_general_graffiti_3", "text": " is a heteronormative bully!" }, + { "id": "dks_general_graffiti_4", "text": " + " }, + { "id": "dks_general_graffiti_5", "text": "Hell in " }, + { "id": "dks_general_graffiti_6", "text": "were all gonna die" }, + { "id": "dks_general_graffiti_7", "text": "MOM" }, + { "id": "dks_general_graffiti_8", "text": "FUCK YOU" }, + { "id": "dks_general_graffiti_9", "text": "This is a cartoon rendition of an alien." }, + { "id": "dks_general_graffiti_10", "text": "This is a crudely spraypainted tag adorned with skulls." }, + { + "id": "dks_general_graffiti_11", + "text": "I have a secure and loving relationship with your mom and you're going to need to come to terms with that.\n\nDo you want to talk about it? You know where to find me. Love you sweety." + }, + { "id": "dks_general_graffiti_12", "text": " you fuckin gave me ADES you SHIT." }, + { "id": "dks_general_graffiti_13", "text": "I <3 ." }, + { "id": "dks_general_graffiti_14", "text": " fucked ." }, + { + "id": "dks_general_graffiti_15", + "text": "This is a spraypainted drawing of an angel with wings made of vines." + }, + { "id": "dks_general_graffiti_16", "text": "Mr. is a vampire!" }, + { "id": "dks_general_graffiti_17", "text": "Their hiding the truth" }, + { "id": "dks_general_graffiti_18", "text": "FOLLOW THE CHEMTRAILS" }, + { + "id": "dks_general_graffiti_19", + "text": "This is a curious drawing of a roll of toilet paper dissolving into a rainbow." + }, + { "id": "dks_general_graffiti_20", "text": "This is a cartoon rendition of a zombie." }, + { "id": "dks_general_graffiti_21", "text": "" }, + { "id": "dks_general_graffiti_22", "text": "don't drink the water" }, + { + "id": "dks_general_graffiti_23", + "text": "And they walked upon His Earth, and there was a RECKONING, and only the worthy survived" + }, + { "id": "dks_general_graffiti_24", "text": "This is a drawing of a zombie with a bullethole in its head." }, + { "id": "dks_general_graffiti_25", "text": "This is a surprisingly artistic drawing of a penis." }, + { "id": "dks_general_graffiti_26", "text": "This is a simple spraypainted graphic of a forest made of bones." }, + { "id": "dks_general_graffiti_27", "text": "This is a drawing of an alien with a bullethole in its head." }, + { "id": "dks_general_graffiti_28", "text": "we can never go back" }, + { "id": "dks_general_graffiti_29", "text": "dont by meth from " }, + { "id": "dks_general_graffiti_30", "text": " you owe me fifty bucks" }, + { "id": "dks_general_graffiti_31", "text": "Im gonna kill u " }, + { "id": "dks_general_graffiti_32", "text": "eyes to the skies" }, + { + "id": "dks_general_graffiti_33", + "text": "This is a spraypainting of an anatomically unlikely woman wearing very little." + } + ] + }, + { + "type": "snippet", + "category": "dks_shelter_graffiti_snippets", + "text": [ + { "id": "dks_shelter_graffiti_1", "text": "BIGGEST WASTE OF TAX MONEY FUCK YOU GOVERMINT" }, + { "id": "dks_shelter_graffiti_2", "text": "Dont eat the proten bars" }, + { "id": "dks_shelter_graffiti_3", "text": "FEMA: FUCKIN EAT MY ASSHOLE" }, + { + "id": "dks_shelter_graffiti_4", + "text": "This is a simple drawing of a skinny figure wearing an emergency evac jacket and a gas mask. Scrawled beneath, it says \"thanks for the outfit\"." + }, + { "id": "dks_shelter_graffiti_5", "text": "Abandon hope, all ye who enter here." }, + { "id": "dks_shelter_graffiti_6", "text": "NO ONE IS COMING FOR US" }, + { "id": "dks_shelter_graffiti_7", "text": "THAT'S NO RESCUE BUS" }, + { "id": "dks_shelter_graffiti_8", "text": "THEY LET US DOWN" }, + { "id": "dks_shelter_graffiti_9", "text": "Don't dead open inside" }, + { "id": "dks_shelter_graffiti_10", "text": "SANCTUARY" }, + { "id": "dks_shelter_graffiti_11", "text": "'s cosplay supply all welcome" }, + { "id": "dks_shelter_graffiti_12", "text": "LAST STOP" }, + { "id": "dks_shelter_graffiti_13", "text": "They aren't coming to help, they're coming to clean up" }, + { + "id": "dks_shelter_graffiti_14", + "text": "This is a far-too-detailed drawing the inside of an alien craft, in all its biomechanical horror." + }, + { + "id": "dks_shelter_graffiti_15", + "text": "This is a quick rendition in permanent marker of an alien craft with war machines spilling out of it. Underneath, it reads \"What did we do to deserve this?\"" + }, + { "id": "dks_shelter_graffiti_16", "text": "RIP humanity" }, + { "id": "dks_shelter_graffiti_17", "text": "NEW GODS" }, + { "id": "dks_shelter_graffiti_18", "text": "WE'RE ALL FINE HERE HOW R U" }, + { + "id": "dks_shelter_graffiti_19", + "text": " I couldn't wait any longer, went to cabin. Meet me there. Love ." + }, + { "id": "dks_shelter_graffiti_20", "text": " I am still looking for you." }, + { "id": "dks_shelter_graffiti_21", "text": " was here and still alive" }, + { "id": "dks_shelter_graffiti_22", "text": "Blue 52" }, + { "id": "dks_shelter_graffiti_23", "text": " I no I said Id wait for u but I gotta run, find me" }, + { + "id": "dks_shelter_graffiti_24", + "text": "In memoriam:\n\n\n\n\n\nI would not be alive without all of you. I will not forget." + }, + { + "id": "dks_shelter_graffiti_25", + "text": "\"keep moving their looking for us\" is written here in a hasty scrawl." + }, + { "id": "dks_shelter_graffiti_26", "text": "EARTH WASN'T THE FIRST" }, + { "id": "dks_shelter_graffiti_27", "text": "stay out of " }, + { "id": "dks_shelter_graffiti_28", "text": " has fallen" }, + { "id": "dks_shelter_graffiti_29", "text": "NO ONE LEFT HERE MOVE ON" }, + { "id": "dks_shelter_graffiti_30", "text": "deth trap" }, + { "id": "dks_shelter_graffiti_31", "text": "seven hour war" }, + { "id": "dks_shelter_graffiti_32", "text": "ARMY WORKING WITH THEM" }, + { "id": "dks_shelter_graffiti_33", "text": "FUCK CHINA" }, + { "id": "dks_shelter_graffiti_34", "text": "gray dawn" }, + { "id": "dks_shelter_graffiti_35", "text": "Remember " }, + { "id": "dks_shelter_graffiti_36", "text": "they can't read english communicate below:" } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/newspaper.json b/data/mods/Dark-Skies-Above/snippets/newspaper.json new file mode 100644 index 0000000000000..83e266e36345a --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/newspaper.json @@ -0,0 +1,178 @@ +[ + { + "type": "snippet", + "category": "dks_many_years_old_news", + "text": [ + { + "id": "dks_many_years_old_news_1", + "text": "DISASTER IN THE SARITANIA MINES! A copper mine west of Saritania, a small town in Vermont, collapsed Wednesday, killing an estimated thirty miners in the disaster. Local officials could not be reached for comment, despite the mine being Saritania's primary industry. An anonymous but credible source did contact our offices, claiming that the Saritania Mine was in fact an underground military facility, and that the disaster was a cover-up for a failed experiment. These allegations were not addressed by officials." + }, + { + "id": "dks_many_years_old_news_2", + "text": "ALIENS AMONG US! Janine Galfrizowich, of Martha's Vineyard, wrote in to our Paranormal Investigation Staff with this cryptic gem. \"They're always watching, always watching from the shadows. Stealing my avocados and watching! They took my neighbor and made him into one of them!\" Our journalists are trying to track Mrs Galfrizowich down, but it is clear enough that this ties into the well known Avocado Conspiracy (see issue 24, volume 7)." + }, + { + "id": "dks_many_years_old_news_3", + "text": "EDITORIAL: ALIENS ARE BACK IN A BIG WAY. We've all seen that autopsy video that's making the rounds. I'm not going to say if I believe it's real or not (I will say \"I want to believe\" though!) but regardless of the truth, one thing is clear: the public mind is completely addicted to aliens in the biggest way I've seen since ET was popular. What's brought little green men back into the public eye? It's anyone's guess, but personally I think it's a concerning sign that we're culturally digging in to a second Cold War." + } + ] + }, + { + "type": "snippet", + "category": "dks_years_old_news", + "text": [ + { + "id": "dks_years_old_news_1", + "text": "DRIVING ON A WING AND A PRAYER: A New England man has proven it is possible to create a new car from scrap parts using almost nothing but duct tape. When asked why he had done it, his answer was \"Well, I didn't have a welder.\"" + }, + { + "id": "dks_years_old_news_2", + "text": "STUDENT MISSING: A high school student vanished yesterday evening in the forest near Wayland. The 17-year-old international student from China (who adopted the anglicized nickname \"Brett\" due to his classmates' difficulty pronouncing his given name) was last seen with his friends in the camp. \"Brett said that he was gonna get some firewood but he never came back,\" said his classmate, Jianxiang Wang. The search is underway." + }, + { + "id": "dks_years_old_news_3", + "text": "STILL SEARCHING: The search for Brett, the high school student who went missing three days ago, is still ongoing. \"He could have played in the soccer game against Weston High School yesterday,\" Brett's sorrowful teammate said, \"[..] we've never stopped praying.\" Despite the best efforts of the County Search & Rescue, Brett had still not been located at the time of this report." + }, + { + "id": "dks_years_old_news_4", + "text": "POPULAR 'ALIEN AUTOPSY' DEBUNKED. A widely circulated video, making the rounds everywhere from FriendFace to television news, has been debunked as a fake. This extremely realistic and graphic alien autopsy shows an insect-like creature being dismantled by Japanese researchers, who comment on its anatomy in Japanese throughout the video. Yesterday, on the popular social media website Eddit, a 'making of' video was posted, clearly exposing the work as the final film project of a small group of students at UCLA." + }, + { + "id": "dks_years_old_news_5", + "text": "BIG BREAK. At the pressure of tech moguls like Elton Moosek, a new bipartisan bill has set aside a big boost for long underfunded NASA. \"It's time we started looking at opportunities beyond our own atmosphere,\" says a spokesperson for Edison Automotives. This space fad is no doubt tied to a new collaborative in the tech industry, secretively nicknamed \"Project Bluebox.\"" + } + ] + }, + { + "type": "snippet", + "category": "dks_one_year_old_news", + "text": [ + { + "id": "dks_one_year_old_news_1", + "text": "READY FOR THE WORST. In response to growing public concern about a potential attack from China, the president announced a major funding initiative for the construction of FEMA-supported community shelters near major population sites. \"These shelters will provide a much-needed near safety points in an emergency,\" said a spokesperson for FEMA. \"They're to be equipped with a secure basement that can resist heavy bombardment, able to fit hundreds of people, and equipped to survive gas and biological attacks. They have self-contained water and power, protective gear, and communications equipment. In short, they are public survivalist bunkers. We've very excited about this initiative.\"" + }, + { + "id": "dks_one_year_old_news_2", + "text": "TURNING UP THE HEAT: New statistics suggest the average temperature in New England has climbed several degrees in the last two years. \"No doubt crops are going to start suffering unless something is done,\" said an expert." + }, + { + "id": "dks_one_year_old_news_3", + "text": "EDITORIAL: SOCIAL MEDIA HAS GOTTEN OUT OF HAND, AND GONE OUT OF COUNTRY. We can no longer trust what we read, and it's all because of social media. Although our newspaper takes painstaking efforts to source our data, our colleagues have forgotten what it means to be a journalist, and widespread falsehoods are repeated even by reputable publications as fact. What is the ultimate source of all this misinformation? It's anyone's guess, but I think we need look no further than our largest international trade partner and rival, China." + }, + { + "id": "dks_one_year_old_news_5", + "text": "EDITORIAL: THIS IS WHERE 'ME TOO' ENDS UP. It's been a while now since 'Me Too' swept the message boards of our nation, but its repercussions are felt every day. Disconnected from our identities and our heritage by the overwhelming urge to suppress the white male and hide his every achievement, American citizens are turning to violence to find a place of belonging. Mark my words: within a year, there will be a reckoning, and it won't be caused by the trade war, it will be from the broken heart of America." + }, + { + "id": "dks_one_year_old_news_6", + "text": "EDITORIAL: THE RISE OF THE RIGHT HAS BROUGHT US HERE. As the wounded white male ego becomes more and more of a self-stereotype, we see the cost of allowing right-wing sentiment echoed all around us. A stricter stance on gun control, workplace discrimination, and domestic terrorist groups must be taken if our most marginalized populations are to survive the next year. Everyone is affected by these sorts of issues." + }, + { + "id": "dks_one_year_old_news_7", + "text": "NEW LAB OPENS: The Messier Research Facility has been officially opened by NASA right here in New England. According to Deputy Administer Sophie Perla, \"This state of the art facility will catapult us back onto the world stage. With the opening of the Messier research complex, New England has a starry future ahead of it.\"" + }, + { + "id": "dks_one_year_old_news_8", + "text": "'SPACE AGE AESTHETIC'. After much buzz in the tech world about \"Project Bluebox\", a new line of what is being termed as 'space-age aesthetic' products have been demoed to a select group of potential investors, particularly NASA administrators. \"The public can look forward to new cutting edge devices hitting the shelves within a year. Prepare to have your horizons broadened.\" a spokesperson said mysteriously this Monday, standing in front of a display case with heavily tinted glass." + }, + { + "id": "dks_one_year_old_news_9", + "text": "WHEN I DID MY TIME. We spoke to Dan Huang, the Chinese-American author of the New York Times bestselling exposé \"When I Did my Time\", the story of his three years living with his extended family in China, immersed in what he describes as \"The ever-escalating anti-American propaganda of the East.\"\n\n\"It's a real threat,\" said Huang. \"They are being taught to hate our freedom, and our technology. Mark my words: there is going to be a reckoning, and we need to be ready.\"" + }, + { + "id": "dks_one_year_old_news_10", + "text": "IT CAME FROM BEYOND. [Pictured: Margaret Antwerp holds the fragment of alien satellite that landed in her rose garden.] It was a normal day for Margaret. Normal, that is, until a thundering crash in her front yard nearly knocked her house over. \"This damn thing fell right out of space, I tell you,\" she told investigative journalists from our Paranormal Investigations department. \"It was glowing red hot, and it had burnt my prize-winning roses to a crisp.\" The US government and air force have declined to comment, as usual." + } + ] + }, + { + "type": "snippet", + "category": "dks_months_old_news", + "text": [ + { + "id": "dks_months_old_news_1", + "text": "SUPPORT THE COUNTRIES THAT SUPPORT YOURS: Washington has announced the deployment of additional soldiers to key locations in East Asia following Chinese joint military exercises with North Korea. \"We pledge our support to our allies, no matter where they are,\" the president said today in a press statement. Our survey results show that the public is more than 56% in favor of a war with China, up 2% from where it was last month." + }, + { + "id": "dks_months_old_news_2", + "text": "EVACS UNDER STRESS. Following recent a recent string of devastating weather-related natural disasters, FEMA sponsered community shelters are under significant stress to stay in stock as the public flocks to their safety. \"We're going to have to start finding new, cost efficient ways to fill those lockers with filling food and warm clothes,\" said FEMA spokesperson Quinn Wright. \"There's no way that we can keep this up with what we have right now.\"" + }, + { + "id": "dks_months_old_news_3", + "text": "INCREASE IN \"MONSTER\" SIGHTINGS HAS EXPERTS BAFFLED. A tenfold spike in sightings of unexplained phenomena, particularly fantastic beasts and monsters, has experts confused. \"This could be related to the recent rise in hallucinations,\" said Dr. Barb Coulson in an interview on web-based debate show ContraPoints on Friday. \"It's probably drugs,\" replied debate partner Leanne Jefferson, a spokesperson from MADD. \"You're both idiots,\" moderator Natalie Wynn interjected. \"The obvious answer is that it's monsters walking the Earth, preparing to kill us all.\"" + }, + { + "id": "dks_months_old_news_4", + "text": "EDITORIAL: HOME CANNING NEEDS TO MAKE A COMEBACK. With food security in question after severe drought this year, I think it's clear we all need to get out Grandma's old books, and learn how to can again. Grocery stores could be a bit empty this winter, and now is the time to make pickles and preserves while the pickling's good. In this issue, three of our editors share their uplifting stories of rediscovering the joys of home canning." + }, + { + "id": "dks_months_old_news_5", + "text": "SUNNY FUTURES. Edison Automotives released a new line of solar-powered vehicles today, as part of their 'space age aesthetic' initative. \"This is big news for everybody, no less those concerned with global warming as it stands. We could see massive cutbacks in atmospheric carbon dioxide,\" said a spokesperson during the meeting." + }, + { + "id": "dks_months_old_news_6", + "text": "ASTRONOMERS SHOCKED. \"We don't know how this could've happened. We've never had a nebula simply disappear on us,\" said a renowned astronomer after the big news was leaked to the Associated Press last week. When attempting to set up a follow up interview, we could could reach her for further comment." + } + ] + }, + { + "type": "snippet", + "category": "dks_weeks_old_news", + "text": [ + { + "id": "dks_weeks_old_news_1", + "text": "CHINESE AGGRESSION: China took the offensive last week on the country’s disputed border with India, seizing a local village along an important highway. While there was no violence, the UN is scrambling to ease tensions, calling the move \"Hostile for hostility's sake.\" China claims that British land treaties support their actions, saying that they were merely taking back what was rightfully theirs. This has done nothing to assuage national fears of open military conflict as the trade war begins to cut deep." + }, + { + "id": "dks_weeks_old_news_2", + "text": "WILD WEATHER. Meteorologists are reported to be \"concerned\" by recent weather patterns, new survey says. Our own weatherman, Farhan Kishor, has this to say: \"Stock up on batteries and food and prepare to stay indoors for a while due to flooding and strong winds. Stay tuned to your local weather station for updates. We're in store for a big one, folks.\"" + }, + { + "id": "dks_weeks_old_news_3", + "text": "GIVING BACK: PUTTING THE \"COMMUNITY\" IN COMMUNITY SHELTERS. A FEMA spokesperson is unveiling a new community-lead effort today: tax deductions in return for donations of canned goods. \"This will be a great way for local communities to get excited about what we're doing here and invest in their own safety.\"" + }, + { + "id": "dks_weeks_old_news_4", + "text": "COMET OVERHEAD. Keep your eyes peeled for the sudden appearance of a previously untracked comet tonight, visible around noon in the night sky. Local stargazers are saying that this is a surprise, but a welcome one. \"It's not often that you get to see this sort of thing with your own eyes quite so clearly,\" says sky watcher Paul O'Ryan." + }, + { + "id": "dks_weeks_old_news_5", + "text": "\"TAKE YOUR FREEDOM IN YOUR OWN HANDS.\" In a surprise press conference today, the president and senior military figures revealed shocking information on an impending terrorist attack by an organization codenamed 'Vanguard'. \"It's time to take freedom into your own hands,\" President Loft said when addressing the crowd, urging them to enlist in the armed forces immediately. \"We don't know when or where they will strike, but they mean to do as much harm as possible to our sovereignty as a nation, and as citizens of the United States.\" Washington has refused to comment further." + }, + { + "id": "dks_weeks_old_news_6", + "text": "WAR CONFIRMED. Chinese-backed armed forces are on their way across the ocean as part of a strike force codenamed 'Vanguard' by government officials. Washington warns that citizens on the West Coast, and on a lesser scale, nationwide, should immediately begin packing for impending evacuation orders. The president is urging enlistment, and no doubt a draft is to follow to combat this new threat that seems to have DC scared to death." + } + ] + }, + { + "type": "snippet", + "category": "dks_newest_news", + "text": [ + { + "id": "dks_newest_news_1", + "text": "EVACUATION ALERT: FEMA officials said today \"Do not try to defend your property. Please retreat to your nearest evacuation center and await extraction to a safe facility. Military officials require all civilians to be removed from hot sites for potential hostile strikes. When the evacuation order is over, you will be able to return to your homes.\"" + }, + { + "id": "dks_newest_news_2", + "text": "BLOOD IN THE STREETS. [Pictured: A grainy image of a terrifying war machine prowling a body-strewn street, taken from between a set of curtains.] The police didn't stand a chance, neither did the National Guard, and neither will you. Stay hidden. Stay alert. Do not go with them when they come to your shelter. This will be our last issue." + }, + { + "id": "dks_newest_news_3", + "text": "A BRIDGE TOO FAR. In a statement Monday, the Department of Defense detailed its plans to deploy strategic minefields on key bridge crossings, in order to slow down invading ground forces. \"Military personnel will be on-site to assist any refugees fleeing the hot zones. We urge citizens to comply with all military directives and proceed directly to evacuation centers for relocation.\"" + }, + { + "id": "dks_newest_news_4", + "text": "SURRENDER. [Pictured: An idle alien war machine surrounded by smiling humans wearing armbands.] The tyranny of the unworthy is over. You are now free, no longer choked by those who have long grown fat and contented on their wealth and your suffering. Surrender to us, and we will show you what we have been building. You can be part of our new order." + }, + { + "id": "dks_newest_news_5", + "text": "GOVERNMENT FACILITIES BOMBED: In an apparent foreign attack (contradicting earlier Department of Defense denials of that the Vanguard terrorists can make strikes against the continental US) a coordinated bombing strike hit a wide number of US governmental facilities simultaneously yesterday, as well as numerous locations in isolated parts of the coastal United States. A statement from the Pentagon has been issued, stating that Vanguard was responsible for the attacks, and assured that action would be taken in kind against the aggressors. Allegations that terrorist operators have been spotted on the ground, a week early from previous statements, have been vehemently denied." + }, + { + "id": "dks_newest_news_6", + "text": "HAPPINESS SKYROCKETS. [Pictured: The street of what can only be one of the Designated Living Zones, appearing clean and well kept, with many smiling people.] Life in the Designated Living Zones has never been better, a new study shows. Over 99.9% of the world population reports an overwhelming since of gratitude and contentedness with their new living conditions. This author can't help but wonder why some people continue to reject these gifts." + } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/radio.json b/data/mods/Dark-Skies-Above/snippets/radio.json new file mode 100644 index 0000000000000..8a271e79ecc9b --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/radio.json @@ -0,0 +1,15 @@ +[ + { + "type": "snippet", + "category": "radio_archive", + "text": [ + "kssht. Dark Horse, this is Blue Jay, what's your status, over. kssht. Blue Jay, this is Black Horse, still holding, but not for long. kssht. Dark Horse, you've got to hold position for 3 hours. We're almost black on ammo, but resupply is on the way, over. kssht. Not possible Blue Jay, too many tangos. 30 minutes max, and if you don't order us to retreat we're gone, over. kssht.", + "kssht. Blue Jay, this is Black Rose, got your resupply, going in on vector 36, what's the status of the LZ? kssht. Black Rose, this is Blue Jay, what took you so long? LZ hot and unsecured, ammo black, bayonets in action, land on your own discretion, over. kssht. Roger that, hold on, Black Rose out. kssht.", + "To whomever is listening, this may be our last broadcast. Wish you luck. Can't stay in the studio any longer, station is being rewired to military frequencies for automatic broadcast. Stay safe, and bless you, people.", + "This is …kssht… we're holding the line so that …kssht… it's been a pleasure to serve, but there's too many of them …kssht… God bless America…", + "Attention. Attention. Do not fight. Do not resist. Become one with the family. Surrender. Recieve care. Be loved. Live. Do not throw your life away. Do not fight. Do not resist. Attention. Attention.", + "This is an emergency broadcast from the National Emergency Alert System. This is not a test. Unknown military forces have been spotted nationwide. They are confirmed by law enforcement officials to be hostile. Please proceed to your local community shelter. If you are not in an evacuation zone, officials highly recommend you pack gear for evacuation. Make sure to include clean clothes, a blanket, and enough food and water to last a few days. More information will be released as it becomes available.", + "This is an emergency broadcast from the National Emergency Alert System. This is not a test. Seek immediate shelter. Multiple missile launches have been confirmed to be target designated military targets, including in urban areas. Seek immediate shelter. If a community shelter is not available, alternative shelter locations are basements, beneath stairwells, or central rooms with no windows. Ensure that you have sufficient protection from falling debris. Ensure that you have food and water for at least one week. Repeat. Seek immediate shelter." + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/survnotes.json b/data/mods/Dark-Skies-Above/snippets/survnotes.json new file mode 100644 index 0000000000000..a60fdb02c35f6 --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/survnotes.json @@ -0,0 +1,495 @@ +[ + { + "type": "snippet", + "category": "dks_note", + "text": [ + { "id": "dks_note_1", "text": "\"WE WERE RIGHT THE GOVERNMENT DID IT\"" }, + { "id": "dks_note_2", "text": "\"watch those wrist rockets\"" }, + { "id": "dks_note_3", "text": "\"I shot the sheriff; but I couldn't find the deputy\"" }, + { + "id": "dks_note_4", + "text": "\"Some plant vines started chasin after me, so I took a gas mask and some teargas and I ran through them.\"" + }, + { "id": "dks_note_5", "text": "\"Slingshot right through the windshield k?\"" }, + { + "id": "dks_note_6", + "text": "\"When I was a kid I used to slingshot at bugs and birds. Its really playing off nowadays, Ill tell you what\"" + }, + { + "id": "dks_note_7", + "text": "\"ALL YOU STONERS WITH YOUR VIDEYA GAMES - I BET YOU WISH YOU TOOK THE TIME TO LEARN A SKILL NOW DONTYA\"" + }, + { "id": "dks_note_8", "text": "\"I tried to be a bard, but the rats didn't like my piping.\"" }, + { + "id": "dks_note_9", + "text": "\"I found a chocolate bar on my pillow when I got home last night. I left and don't wanna go back.\"" + }, + { + "id": "dks_note_10", + "text": "\"this spider thing came after me it got me good i shot it but i dont know if ill make it\"" + }, + { + "id": "dks_note_11", + "text": "\"DANNY IF YOU READ THIS THIS IS CLARA WE'RE ALL OKAY AND WE'RE HEADING TO THE RIVER. A BOAT SAID THEY WERE DOCKED NEARBY.\"" + }, + { + "id": "dks_note_12", + "text": "\"When I think of the aliens I get mad, because I was supposed to be the next big leader. WHERES MY CHANCE!??\"" + }, + { "id": "dks_note_13", "text": "\"They stopped me at the edge of town, said they wanted to make a deal…\"" }, + { "id": "dks_note_14", "text": "\"robots cant smell. youll thank me later\"" }, + { + "id": "dks_note_15", + "text": "\"Hey. Everyone reading this. Life isn't so bad with them. People just need to read up on their capitals if you catch my drift.\"" + }, + { "id": "dks_note_16", "text": "\"goddamn piece of shit gun doesnt fucking work\"" }, + { + "id": "dks_note_17", + "text": "\"Gotta slow down, man. I don't think we spend more than 20% of our time fightin', Put some Marley on and take off that racketus tripcore nonsense, man.\"" + }, + { "id": "dks_note_18", "text": "\"I kept shooting with my handgun, but I never got any better!\"" }, + { + "id": "dks_note_19", + "text": "\"ITS OKEY GUYS! I BARRYED A TIME CAPSUL IN MY BACKYARD! I PUT IN SOME HOEHOES.\"" + }, + { + "id": "dks_note_20", + "text": "\"I got my tinfoil hat on. Good thing too, cause this alien was starrin at me kinda funny, trying to freeze my mind in place.\"" + }, + { "id": "dks_note_21", "text": "\"You want my advice? Smoke crack, it gets shit done.\"" }, + { + "id": "dks_note_22", + "text": "\"ALWAYS WITH THE EFFICIENCY GUYS; YOURE ALWAYS WORKING TO GO HOME TO PAY RENT TO SLEEP TO WAKE UP TO WORK AGAIN. STOP\"" + }, + { "id": "dks_note_23", "text": "\"IM OFF TO THUNDERDOME, BYE SUCKERS.\"" }, + { + "id": "dks_note_24", + "text": "\"If you get a parasite, take some sand and some vodka. Rub the sand into the afflicted area, real good too; like you're washing your hair. Then rinse with vodka.\"" + }, + { + "id": "dks_note_25", + "text": "\"I put my toilet water into a gastank. Then I poured it into a glass cup. Then I drank it without vomiting my insides back into the toilet.\"" + }, + { "id": "dks_note_26", "text": "\"This isn't real this is a test to turn you into a Manchurian Candidate!\"" }, + { + "id": "dks_note_27", + "text": "\"they sold us all down the river real fast huh? they're on the radio near washington.\"" + }, + { + "id": "dks_note_28", + "text": "\"Some of 'em are big. Real big. Don't stick around, I saw my mate get fucking torn in half!\"" + }, + { "id": "dks_note_29", "text": "\"po p y fl ow er s don t ea at them\"" }, + { "id": "dks_note_30", "text": "\"saw some of ours with them. traitor traitor traitor\"" }, + { "id": "dks_note_31", "text": "\"did they break all the fucking lawnmowers?!\"" }, + { + "id": "dks_note_32", + "text": "\"Some of the bridges, they're right next to each other, right? If you see something up ahead one of those, just careen through to the other side. My van was long enough to bridge right across!\"" + }, + { "id": "dks_note_33", "text": "\"BURN BURN BURN BURN BURN ALL BURN ALL BURN ALL BURN\"" }, + { + "id": "dks_note_34", + "text": "\"I took all the supplies. Don't follow me. I'm sorry, man. I have to look out for myself now.\"" + }, + { "id": "dks_note_35", "text": "\"My next-door neighbor had a katana in his basement!\"" }, + { "id": "dks_note_36", "text": "\"Am I the last one free?\"" }, + { + "id": "dks_note_37", + "text": "\"Boyfriend stole my pistol while I was asleep. I locked him in the bathroom and set the house on fire. At least he attracted their attention.\"" + }, + { "id": "dks_note_38", "text": "\"who fucking popped all the tires you assholes\"" }, + { + "id": "dks_note_39", + "text": "\"ambushed a couple and they weren't too tough. just watch out for the reinforcements.\"" + }, + { + "id": "dks_note_40", + "text": "\"Why would you hide in a farm? Sure, it's isolated, but if they know where you are, you don't exactly have cover on all sides.\"" + }, + { "id": "dks_note_41", "text": "\"earth wasn't the first\"" }, + { "id": "dks_note_42", "text": "\"bullet holes and plasma burns all over the car. piece of shit hardly runs\"" }, + { "id": "dks_note_43", "text": "\"one day this will all be over.\"" }, + { + "id": "dks_note_44", + "text": "\"Got a picture of one of those walkers. You should see it in the news soon: remember me by it.\"" + }, + { "id": "dks_note_45", "text": "\"Gas mask is nice and all, but I can hardly run with it on.\"" }, + { "id": "dks_note_46", "text": "\"why would you set up fucking mines they don't do anything to them\"" }, + { + "id": "dks_note_47", + "text": "\"The evac shelters are a death trap. They took everyone else away but something in the driver's eyes told me not to go. Now it's just me.\"" + }, + { "id": "dks_note_48", "text": "\"plugged some alient techn ignto me idkont know if i feel so gowod\"" }, + { "id": "dks_note_49", "text": "\"i've heard they know how to bring you back if you die\"" }, + { "id": "dks_note_50", "text": "\"you motherfucker\"" }, + { "id": "dks_note_51", "text": "\"Don't keep your goddamn casings! They'll just weigh you down.\"" }, + { + "id": "dks_note_52", + "text": "\"seen them around a lot of military installations. i think they know some of us didn't surrender like they said to\"" + }, + { "id": "dks_note_53", "text": "\"hahahahahaha die you flammable bastards\"" }, + { + "id": "dks_note_54", + "text": "\"If you're reading this: they're looking for you. Join us by Boston, we've set up a camp in the woods\"" + }, + { + "id": "dks_note_55", + "text": "\"I thought bigmouth carp were bad. The things they brought with them? Talk about invasive species.\"" + }, + { + "id": "dks_note_56", + "text": "\"please let this all be a dream. i had to bury her last night. i don't even know what to do anymore.\"" + }, + { "id": "dks_note_57", "text": "\"TALL ONES RUN RUN RUN RUN RUN\"" }, + { "id": "dks_note_58", "text": "\"Are they still human inside that armor?\"" }, + { "id": "dks_note_59", "text": "\"got close to one of their ships and i feel crawly inside\"" }, + { + "id": "dks_note_60", + "text": "\"Remember history class with the invaders and their disesases? yeah… my gut doesn't feel right… like it's moving…\"" + }, + { + "id": "dks_note_61", + "text": "\"They build modern bullets fuckin crazy. Set some on fire and they all goes like a lil grenade. Need kindling first.\"" + }, + { "id": "dks_note_62", "text": "\"GOD CAN'T SAVE US\"" }, + { "id": "dks_note_63", "text": "\"SHOOT YOURSELF, LET IT END QUICKLY\"" }, + { + "id": "dks_note_64", + "text": "\"There are five basic rules to survival. One, stay prepared and watchful. Two, keep your iron sights lined up or succumb. Three, stay FAR WAY from all\"" + }, + { + "id": "dks_note_65", + "text": "\"The bricks of this bathroom look like a face. Haha… it's all I can focus on. At least let me shit before you kick down the door. Please…\"" + }, + { "id": "dks_note_66", "text": "\"What the hell are they mining for in these shafts?\"" }, + { + "id": "dks_note_67", + "text": "\"fucking idiots with their medieval getups like that's gonna help against LASER RIFLES\"" + }, + { "id": "dks_note_68", "text": "\"Broadsword! Yeah!\"" }, + { + "id": "dks_note_69", + "text": "\"If you see a trail of dirt getting displaced in your direction… run. Run for your life.\"" + }, + { + "id": "dks_note_70", + "text": "\"wish the rain kept up after they arrived. made my funnel collection feel more useful\"" + }, + { "id": "dks_note_71", "text": "\"Libraries are useless after the apocalypse. Can't read away the drones.\"" }, + { + "id": "dks_note_72", + "text": "\"I swear to God I've seen these aliens before! In a game, or something! I swear…\"" + }, + { + "id": "dks_note_73", + "text": "\"Think it's worth it to crack a bank now that all the guards were killed or sent off?\"" + }, + { "id": "dks_note_74", "text": "\"Make sure your car is REALLY stopped before you get out.\"" }, + { + "id": "dks_note_75", + "text": "\"They're setting up in camps and cities all over. Looks like some shit out of a sci-fi movie… goes without saying huh\"" + }, + { + "id": "dks_note_76", + "text": "\"Why would you ever hide in a damn gun store? The owner… he was a moron alright.\"" + }, + { "id": "dks_note_77", "text": "\"THEY DON'T feel ANYTHING\"" }, + { "id": "dks_note_78", "text": "\"What was the government doing, anyway?\"" }, + { + "id": "dks_note_79", + "text": "\"i've seen what they've done to dissidents in those camps of theirs. I don't know if I'll be able to sleep right again…\"" + }, + { "id": "dks_note_80", "text": "\"THE MARLEY WAS RIGHT\"" }, + { + "id": "dks_note_81", + "text": "\"We surrendered to them and they're treating us well. I don't know why I was hiding all that time. \"" + }, + { "id": "dks_note_82", "text": "\"how long were they watching us?\"" }, + { + "id": "dks_note_83", + "text": "\"couldn't even dent one with the .45. all the noise just made me a bigger target.\"" + }, + { "id": "dks_note_84", "text": "\"Don't let the ember go out please don't go out I need you precious fire.\"" }, + { + "id": "dks_note_85", + "text": "\"Everyone used their gas to get to another town… but it's the same story everywhere.\"" + }, + { "id": "dks_note_86", "text": "\"There's still an evacuation point at Concord, spread the word.\"" }, + { "id": "dks_note_87", "text": "\"STAY AWAY FROM CONCORD\"" }, + { + "id": "dks_note_88", + "text": "\"Most things can be taken out with a shotgun. More things can be taken out with a grenade. Imagine what a mini-nuke does.\"" + }, + { "id": "dks_note_89", "text": "\"Come to the bar if you see this, let's re-enact an alien movie, friends.\"" }, + { + "id": "dks_note_90", + "text": "\"here I was hoping for zombies hahahaha, feel like I was born into the wrong apocalypse\"" + }, + { + "id": "dks_note_91", + "text": "\"have you seen some of the plants they drug in on their boots? best you don't.\"" + }, + { + "id": "dks_note_92", + "text": "\"Your backpack's gonna weigh you down in the water. Hell, feel free to get naked. Nobody's going to judge your modesty.\"" + }, + { "id": "dks_note_93", "text": "\"Guns too loud. Crossbow too long. Running is best.\"" }, + { + "id": "dks_note_94", + "text": "\"I don't think they can read English. Write down where you are down here so we can share supplies:\"" + }, + { + "id": "dks_note_95", + "text": "\"Crawled in through the vents. Whole office building is a wreck. Saved some, turned their guns on others.\"" + }, + { + "id": "dks_note_96", + "text": "\"god help you if you get caught by one of those nasty blade things that have been carving up wood. my arm…\"" + }, + { + "id": "dks_note_96a", + "text": "\"Occupants are everywhere. Do NOT let those fucking drones see you. They'll alert the others with sirens and lights\"" + }, + { + "id": "dks_note_97", + "text": "\"New order, occupiers, invaders, grays, aliens, new gods, vanguard. Did I miss any?\"" + }, + { + "id": "dks_note_98", + "text": "\"All I've got is this keg of beer and an appetite. Come at me, apocalypse!\"" + }, + { "id": "dks_note_99", "text": "\"remember lambda\"" }, + { + "id": "dks_note_100", + "text": "\"do NOT surrender. if you're so lucky as to find any that won't rip you up or shoot you on sight at this point, they do NOT have anything good in mind for us\"" + }, + { + "id": "dks_note_101", + "text": "\"we were the finest army in the world. problem is, they're the finest army off-world.\"" + }, + { + "id": "dks_note_102", + "text": "\"River water around these parts is extremely safe. Probably more safe than the damn tap water at this point.\"" + }, + { "id": "dks_note_103", "text": "\"watch your six. some of them can cloak.\"" }, + { "id": "dks_note_104", "text": "\"ALL HAIL THE NEW GODS\"" }, + { "id": "dks_note_105", "text": "\"I just realized how damn demented those fliers are.\"" }, + { "id": "dks_note_106", "text": "\"I propose a new currency: 9mm.\"" }, + { "id": "dks_note_107", "text": "\"My skin is crawling and I teleport every few minutes… what is going o\"" }, + { + "id": "dks_note_108", + "text": "\"Occupiers crawling all over the place. Have reinforcement points all over. Could take them out. Might buy us some time in some places.\"" + }, + { + "id": "dks_note_109", + "text": "\"they can fucking read english you moron - or at least they have collaborators that CAN\"" + }, + { "id": "dks_note_110", "text": "\"watch what you write. they're paying attention.\"" }, + { "id": "dks_note_111", "text": "\"STAY AWAY FROM THE BIG ONES IN THE FOREST\"" }, + { + "id": "dks_note_112", + "text": "\"got into a prison with a halligan bar. makes me wonder how they kept prisoners inside\"" + }, + { + "id": "dks_note_113", + "text": "\"This thing isn't a car any more. It's just a fucking mountain of metal on wheels, which I live in.\"" + }, + { "id": "dks_note_114", "text": "\"if you hear tires: run\"" }, + { "id": "dks_note_115", "text": "\"get on the roofs. they might see you but they can't climb.\"" }, + { "id": "dks_note_116", "text": "\"i'm running out of ink but listen you need to\"" }, + { + "id": "dks_note_117", + "text": "\"Make sure you strip the house for all available resources-- tubes, pipes, ceramics, sheets, strings, and more\"" + }, + { "id": "dks_note_118", "text": "\"mmm mmm delsihous alien drink\"" }, + { + "id": "dks_note_119", + "text": "\"they have their own line of fucking fast food. do NOT eat the Ascendant Burgers DO NOT DO NOT\"" + }, + { "id": "dks_note_120", "text": "\"tried one of the ascendant burgs. Feeling fine. They're safe, guys.\"" }, + { "id": "dks_note_121", "text": "\"CHINA DID THIS\"" }, + { "id": "dks_note_122", "text": "\"RUSSIA DID THIS\"" }, + { "id": "dks_note_123", "text": "\"ELTON MOOSEK DID THIS\"" }, + { "id": "dks_note_124", "text": "\"did you know? alien wildlife is friendly to other aliens. whoda thunk.\"" }, + { "id": "dks_note_125", "text": "\"dont try to leave they will shoot you\"" }, + { + "id": "dks_note_126", + "text": "\"I'd like to thank my high-school culinary arts class for teaching me how to make RDX.\"" + }, + { + "id": "dks_note_127", + "text": "\"in my dreams i saw hordes of the walking dead and a guy named kevin standing above it all, speaking in tongues. glad it wasn't real\"" + }, + { "id": "dks_note_128", "text": "\"he calls himself the 'man with the hands', don't approach\"" }, + { "id": "dks_note_129", "text": "\"sometimes… I dream about cheese\"" }, + { "id": "dks_note_130", "text": "\"mushy fucking pickles\"" }, + { "id": "dks_note_131", "text": "\"I've never been very confident, is that why my shots keep missing?\"" }, + { "id": "dks_note_132", "text": "\"FIRE BAD. NOW NAKED. PLEASE HELP.\"" }, + { "id": "dks_note_133", "text": "\"war of the god damn worlds looking ass\"" }, + { "id": "dks_note_134", "text": "\"KASHWAK: NO-FO\"" }, + { + "id": "dks_note_135", + "text": "\"The whispering fog is taking me in like a blanket. I'm warm now. I'm finally\"" + }, + { + "id": "dks_note_136", + "text": "\"made a movie out of some footage of the war. two days cut down into seven hours.\"" + }, + { + "id": "dks_note_137", + "text": "\"Got split from my squad. If you're reading this and you're still loyal, meet me at the nearby bunker. If not: I've got a bullet with your fucking name on it.\"" + }, + { + "id": "dks_note_138", + "text": "\"if anyones reading this, please tell my mom i was right about robots being superior\"" + }, + { "id": "dks_note_139", "text": "\"heard a kid whispering to me from inside a garage. i fucking bolted\"" }, + { "id": "dks_note_140", "text": "\"waded through 14 miles of sewage for playboy magazine, wasnt worth it\"" }, + { + "id": "dks_note_141", + "text": "\"I'm coming back for this note in twelve hours. If I don't, take all my shit!\"" + }, + { + "id": "dks_note_142", + "text": "\"all my friends died when they came near me. there's nothing funny about that\"" + }, + { "id": "dks_note_143", "text": "\"DOG NOT REAL DOG\"" }, + { + "id": "dks_note_144", + "text": "\"This is all just a dream, right??! I'M GOING TO WAKE UP, HE'S GOING TO BE OK\"" + }, + { "id": "dks_note_145", "text": "\"wek ik spak\"" }, + { "id": "dks_note_146", "text": "\"I figured it out.\"" }, + { + "id": "dks_note_147", + "text": "\"If I had a dollar for every cash card I've found, I'd have more money than is on these stupid things!\"" + }, + { + "id": "dks_note_148", + "text": "\"can never have enough kevlar. basically just live in a kevlar turtle shell.\"" + }, + { "id": "dks_note_149", "text": "\"Glad you found this finally. I've been watching you for a while.\"" }, + { "id": "dks_note_150", "text": "\"chin up brian\"" }, + { "id": "dks_note_151", "text": "\"all they had to do was look at me WHAT THE FUCK DID THEY DO TO ME\"" }, + { + "id": "dks_note_152", + "text": "\"a ctulaly don t mi nd t he cold it s f i ne in h ere nn o problem\"" + }, + { "id": "dks_note_153", "text": "\"i think i've been here before\"" }, + { + "id": "dks_note_154", + "text": "\"Tried wearing one of their uniforms and they shot at me anyway. It's like they're a hivemind, man.\"" + }, + { "id": "dks_note_155", "text": "\"knock knock? check the back window.\"" }, + { + "id": "dks_note_156", + "text": "\"For anyone that's reading this, I just want to confirm (FROM AN UNBIASED SOURCE) that it was NOT the scientists' fault.\"" + }, + { "id": "dks_note_157", "text": "\"for anyone reading: no SETI had nothing-to-fuck do with this\"" }, + { "id": "dks_note_158", "text": "\"WE'RE GOING TO SAIL TO CANADA, BITCHES!\"" }, + { + "id": "dks_note_159", + "text": "\"Anyone hear about that guy who tried to sail his family to Canada? What a moron, right?\"" + }, + { "id": "dks_note_160", "text": "\"recently canadian border has gotten more dangerous don't go there\"" }, + { "id": "dks_note_161", "text": "\"Hey, what happened to my dad's airboat?!\"" }, + { "id": "dks_note_162", "text": "\"Reading is good! Never stop reading. Read EVERYTHING.\"" }, + { + "id": "dks_note_163", + "text": "\"I'm gonna be honest here, I'm really gonna die soon so I dont want to gt forgnottedn ples dont forntget me y nrmmy name is h@@hbhbh\"" + }, + { "id": "dks_note_164", "text": "\"all it takes to seal a wound is a sawblade and a match! trust me\"" }, + { + "id": "dks_note_165", + "text": "\"is it just me or are we healing faster? i think they put something in the water...\"" + }, + { "id": "dks_note_166", "text": "\"the 50cal is strong with this one\"" }, + { + "id": "dks_note_167", + "text": "\"WBLF 970 went off-air three days ago. There's nothing left on the radio but the propaganda. Might as well throw this thing away…\"" + }, + { + "id": "dks_note_168", + "text": "\"I've heard it's safer across the Mississippi. Going to start driving today. If you're reading this, pray for me\"" + }, + { "id": "dks_note_169", "text": "\"remember to bleach those bandages\"" }, + { "id": "dks_note_170", "text": "\"We have Landed our Comet. The Sky is Ablaze.\"" }, + { + "id": "dks_note_171", + "text": "\"Last one standing. It's good feeling. I win. I win I win I win I win I win\"" + }, + { "id": "dks_note_172", "text": "\"Adderall cures weakness, tramadol cures death\"" }, + { "id": "dks_note_173", "text": "\"parry this you casuals\"" }, + { "id": "dks_note_174", "text": "\"Best way to train is by throwing pebbles at birds. You'll be a legend.\"" }, + { "id": "dks_note_175", "text": "\"new bedford is overrun. i'm sorry. we tried.\"" }, + { + "id": "dks_note_176", + "text": "\"I've seen what they do with the bodies. Their medical prowess is staggering…\"" + }, + { "id": "dks_note_177", "text": "\"You're next.\"" }, + { "id": "dks_note_178", "text": "\"anyone else want to go down in a blaze of glory? join me at the park.\"" }, + { + "id": "dks_note_179", + "text": "\"Lots of new easy ways to burn calories now. Fighting the Occupiers, managing the fields, outrunning the new 'wildlife', and more.\"" + }, + { "id": "dks_note_180", "text": "\"FLAMING SWORD HUMANE. CAUTERIZES WOUNDS. SURGICAL.\"" }, + { "id": "dks_note_181", "text": "\"knife screams it screams i cant breathe so scared help me please help\"" }, + { "id": "dks_note_182", "text": "\"when it started, we could still hope The Man was gonna save us…\"" }, + { "id": "dks_note_183", "text": "\"it wasn't even a person anymore im sorry god\"" }, + { + "id": "dks_note_184", + "text": "\"i say we call the material from melting down cars and dead robots 'massachusetite' or 'vermontsteel' or 'connecticut composite'\"" + }, + { + "id": "dks_note_185", + "text": "\"Sometimes what you need when you're infected, bleeding, sick and hungover is a J and some chips.\"" + }, + { + "id": "dks_note_186", + "text": "\"This has to be China's fault. Seriously, why is nobody suspecting the people we're having a cold war with! This is an invasion! These aren't aliens, it's just camouflage! WAKE UP, SHEEPLE!\"" + }, + { + "id": "dks_note_187", + "text": "\"Hahahahaa stupid fuck in his mansion, with his plate armor and big axe. Guy never swung the thing in his life. Can't block bullets, dipshit\"" + }, + { "id": "dks_note_188", "text": "\"Two words: Truman Show.\"" }, + { + "id": "dks_note_189", + "text": "\"poor guy. watched him from afar with my binocs for months and months. today he died fighting. feels like i knew him even though i never approached.\"" + }, + { "id": "dks_note_190", "text": "\"ENGLAND DID THIS\"" }, + { + "id": "dks_note_191", + "text": "\"That little fakkin rat din say anythin till we whacked him with a steel chain! Then 'e just wanted to know if he could buy the chain!\"" + }, + { + "id": "dks_note_192", + "text": "\"tom, adorned with fluid sacs three layers deep, crawls to safety like a slug\"" + }, + { + "id": "dks_note_193", + "text": "\"my friend turned fuckin insane and ate his arms and then his sister's arms! he looked rather cross\"" + }, + { "id": "dks_note_194", "text": "\"Starting today, the hallucinations are my only friends.\"" }, + { "id": "dks_note_195", "text": "\"For sale: baby shoes, unused\"" }, + { + "id": "dks_note_196", + "text": "\"Started my own brewery recently. I just need some glass bottles, now! Several thousand! I'm planning way ahead.\"" + }, + { + "id": "dks_note_197", + "text": "\"Heard recently of some radio op who lives in a skyscraper, announcing where the grays are going. I think I saw the explosion a mile away after they caught wind.\"" + }, + { "id": "dks_note_198", "text": "\"Woah, bud! Not all cannibals eat meat!\"" }, + { "id": "dks_note_199", "text": "\"ay why aint my bullets fuckin explodin\"" }, + { "id": "dks_note_200", "text": "\"Those Fiktok clan people picked this place clean… no food…\"" }, + { + "id": "dks_note_201", + "text": "\"The fewer 'resistance members' in New England, the stronger we'll become out here in the wilds. Let them have the cities.\"" + }, + { "id": "dks_note_202", "text": "\"It all boils down to the Apex Predator.\"" }, + { "id": "dks_note_203", "text": "\"It's been a while, hasn't it? Glad I found you again.\"" }, + { "id": "dks_note_204", "text": "\"Got my mortar and pestle. Now if I could just find some avocados…\"" } + ] + } +] From 2061f331935b3797587923be27229609be5048a4 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Tue, 3 Mar 2020 22:01:19 -0500 Subject: [PATCH 023/219] Dark Skies 7: Monsters (#38552) --- .../mon_groups/alienanimal_spawns.json | 9 + .../monsters/mon_groups/neworder_spawns.json | 82 +++++++ .../monsters/mon_groups/upgrades.json | 12 + .../Dark-Skies-Above/monsters/monattack.json | 109 ++++++++++ .../Dark-Skies-Above/monsters/mondrops.json | 90 ++++++++ .../Dark-Skies-Above/monsters/mongun.json | 54 +++++ .../Dark-Skies-Above/monsters/monspell.json | 89 ++++++++ .../new_order/neworder_highorder.json | 71 ++++++ .../monsters/new_order/neworder_loworder.json | 139 ++++++++++++ .../monsters/new_order/neworder_misc.json | 205 ++++++++++++++++++ 10 files changed, 860 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json create mode 100644 data/mods/Dark-Skies-Above/monsters/monattack.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mondrops.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mongun.json create mode 100644 data/mods/Dark-Skies-Above/monsters/monspell.json create mode 100644 data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json create mode 100644 data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json create mode 100644 data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json new file mode 100644 index 0000000000000..c5702e8e73fd3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json @@ -0,0 +1,9 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_SEWER", + "default": "mon_sewer_rat", + "is_animal": true, + "monsters": [ { "monster": "dks_mon_lurker_sewer", "freq": 10, "cost_multiplier": 2, "pack_size": [ 1, 2 ] } ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json new file mode 100644 index 0000000000000..4fbeffa7346aa --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json @@ -0,0 +1,82 @@ +[ + { + "name": "GROUP_PARK_SCENIC", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 50, "cost_multiplier": 5, "pack_size": [ 2, 5 ] }, + { "monster": "dks_neworder_pyro", "freq": 25, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_neworder_cop", "freq": 5, "cost_multiplier": 10, "pack_size": [ 1, 2 ] }, + { "monster": "mon_dks_emissary", "freq": 1, "starts": 24, "cost_multiplier": 20 }, + { "monster": "mon_dks_emissary_plague", "freq": 1, "starts": 36, "cost_multiplier": 25 }, + { "monster": "mon_dks_emissary_flame", "freq": 1, "starts": 48, "cost_multiplier": 30 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_POLICE", + "default": "mon_null", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 40, "cost_multiplier": 10, "pack_size": [ 2, 5 ] }, + { "monster": "dks_neworder_cop", "freq": 10, "cost_multiplier": 10, "pack_size": [ 1, 2 ] }, + { "monster": "mon_dks_emissary", "freq": 1, "cost_multiplier": 40 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_FOREST", + "default": "mon_null", + "is_animal": true, + "monsters": [ + { "monster": "dks_neworder_scout", "freq": 1, "cost_multiplier": 10, "pack_size": [ 1, 3 ] }, + { "monster": "mon_dks_emissary", "freq": 1, "starts": 24, "cost_multiplier": 20 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_MAYBE_MIL", + "//": "50% chance military zombie or robot", + "default": "mon_null", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 35, "cost_multiplier": 1 }, + { "monster": "dks_neworder_cop", "freq": 10, "cost_multiplier": 50 }, + { "monster": "mon_dks_emissary", "freq": 5, "cost_multiplier": 50 }, + { "monster": "mon_dks_emissary_plague", "freq": 5, "cost_multiplier": 50 } + ] + }, + { + "name": "GROUP_MIL_WEAK", + "type": "monstergroup", + "default": "dks_neworder_knight", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 150, "cost_multiplier": 2, "pack_size": [ 1, 4 ] }, + { "monster": "dks_neworder_cop", "freq": 200, "cost_multiplier": 30 }, + { "monster": "mon_dks_emissary", "freq": 5, "cost_multiplier": 20 } + ] + }, + { + "name": "GROUP_MIL_STRONG", + "type": "monstergroup", + "default": "dks_neworder_knight", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 100, "cost_multiplier": 2, "pack_size": [ 1, 4 ] }, + { "monster": "dks_neworder_knight", "freq": 150, "cost_multiplier": 2, "pack_size": [ 2, 6 ] }, + { "monster": "dks_neworder_cop", "freq": 100, "cost_multiplier": 30 }, + { "monster": "mon_dks_emissary", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_dks_emissary_plague", "freq": 5, "cost_multiplier": 5 }, + { "monster": "mon_dks_emissary_flame", "freq": 5, "cost_multiplier": 20 } + ] + }, + { + "name": "GROUP_MIL_BASE", + "type": "monstergroup", + "default": "dks_neworder_knight", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_neworder_cop", "freq": 15, "cost_multiplier": 5 }, + { "monster": "mon_dks_emissary", "freq": 1, "cost_multiplier": 1 }, + { "monster": "mon_dks_emissary_plague", "freq": 1, "cost_multiplier": 5 }, + { "monster": "mon_dks_emissary_flame", "freq": 1, "cost_multiplier": 20 } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json new file mode 100644 index 0000000000000..d45b325f02381 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json @@ -0,0 +1,12 @@ +[ + { + "type": "monstergroup", + "name": "DKS_GROUP_STRAY_UPGRADE", + "default": "dks_mon_stray_fast", + "monsters": [ + { "monster": "dks_mon_stray_fast", "freq": 200, "cost_multiplier": 10 }, + { "monster": "dks_mon_stray_heavy", "freq": 100, "cost_multiplier": 10 }, + { "monster": "dks_mon_stray_eater", "freq": 50, "cost_multiplier": 10 } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/monattack.json b/data/mods/Dark-Skies-Above/monsters/monattack.json new file mode 100644 index 0000000000000..425507a90641b --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/monattack.json @@ -0,0 +1,109 @@ +[ + { + "id": "pneumatic_bite", + "type": "monster_attack", + "attack_type": "bite", + "cooldown": 40, + "accuracy": 6, + "effects": [ { "id": "grabbed", "duration": 1000, "bp": "TORSO" } ], + "body_parts": [ [ "ARM_L", 3 ], [ "ARM_R", 3 ] ], + "no_infection_chance": 100, + "damage_max_instance": [ + { "damage_type": "stab", "amount": 9, "armor_multiplier": 0.5 }, + { "damage_type": "bash", "amount": 15, "armor_multiplier": 0.5 } + ], + "hit_dmg_u": "The %1$s grabs your arm and bites down hard!!", + "hit_dmg_npc": "The %1$s grabs and bites down hard!!", + "no_dmg_msg_u": "The %1$s grabs your arm in its mouth, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s grabs , but fails to penetrate the armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "slash", + "cooldown": 20, + "move_cost": 150, + "damage_max_instance": [ { "damage_type": "cut", "amount": 8 } ], + "body_parts": [ + [ "FOOT_L", 2 ], + [ "FOOT_R", 2 ], + [ "LEG_L", 3 ], + [ "LEG_R", 3 ], + [ "HAND_L", 2 ], + [ "HAND_R", 2 ], + [ "HEAD", 3 ], + [ "EYES", 2 ], + [ "MOUTH", 1 ], + [ "ARM_L", 3 ], + [ "ARM_R", 3 ], + [ "TORSO", 4 ] + ], + "hit_dmg_u": "The %1$s slashes you!", + "hit_dmg_npc": "The %1$s slashes !", + "no_dmg_msg_u": "The %1$s attempts to cut you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to cut , but fails to penetrate your armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "heavyslash", + "cooldown": 20, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "cut", "amount": 15, "armor_multiplier": 0.2 } ], + "body_parts": [ + [ "FOOT_L", 2 ], + [ "FOOT_R", 2 ], + [ "LEG_L", 3 ], + [ "LEG_R", 3 ], + [ "HAND_L", 2 ], + [ "HAND_R", 2 ], + [ "HEAD", 3 ], + [ "EYES", 2 ], + [ "MOUTH", 1 ], + [ "ARM_L", 3 ], + [ "ARM_R", 3 ], + [ "TORSO", 4 ] + ], + "hit_dmg_u": "The %1$s hits you with a heavy sword-slash!!", + "hit_dmg_npc": "The %1$s heavily slashes !!", + "no_dmg_msg_u": "The %1$s attempts to cut you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to cut , but fails to penetrate your armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "knockdown", + "effects": [ { "id": "downed", "duration": 3 } ], + "cooldown": 20, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "bash", "amount": 4 } ], + "body_parts": [ [ "LEG_L", 3 ], [ "LEG_R", 3 ] ], + "hit_dmg_u": "The %1$s sweeps your legs from under you!", + "hit_dmg_npc": "The %1$s knocks to the ground!", + "no_dmg_msg_u": "The %1$s tries to sweep out your leg, but can't get through the armor.", + "no_dmg_msg_npc": "The %1$s tries to sweep to the ground, but can't get through the armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "shieldbash", + "effects": [ { "id": "stunned", "duration": 3 } ], + "cooldown": 35, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "bash", "amount": 6 } ], + "body_parts": [ + [ "LEG_L", 3 ], + [ "LEG_R", 3 ], + [ "HEAD", 3 ], + [ "EYES", 2 ], + [ "MOUTH", 1 ], + [ "ARM_L", 3 ], + [ "ARM_R", 3 ], + [ "TORSO", 4 ] + ], + "hit_dmg_u": "The %1$s suddenly slams you with their shield, stunning you!", + "hit_dmg_npc": "The %1$s stuns with a shield bash!", + "no_dmg_msg_u": "The %1$s tries to shield bash you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries bash , but fails to penetrate the armor." + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mondrops.json b/data/mods/Dark-Skies-Above/monsters/mondrops.json new file mode 100644 index 0000000000000..e80965398cbfb --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mondrops.json @@ -0,0 +1,90 @@ +[ + { + "id": "dks_mon_neworder_scout", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "item": "machete" }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "knife_combat", "container-item": "sheath", "prob": 40 }, + { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, + { "group": "dks_scout_extras", "prob": 60 } + ] + }, + { + "id": "dks_mon_neworder_cop", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "item": "shocktonfa_off", "charges-min": 10, "charges-max": 1198 }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "dks_riotshield" }, + { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, + { "group": "dks_cop_extras", "prob": 60, "count": [ 0, 2 ] } + ] + }, + { + "id": "dks_mon_neworder_pyro", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "dks_flamesword_salvaged" }, + { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, + { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } + ] + }, + { + "id": "dks_mon_neworder_knight", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "dks_knightsword_salvaged" }, + { "item": "dks_battleshield" }, + { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, + { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } + ] + }, + { + "id": "dks_cop_extras", + "type": "item_group", + "items": [ + { "item": "1st_aid", "prob": 25 }, + { "item": "legrig", "prob": 10 }, + { "item": "dump_pouch", "prob": 10 }, + { "item": "medium_disposable_cell", "prob": 30 } + ] + }, + { + "id": "dks_scout_extras", + "type": "item_group", + "items": [ + { "item": "1st_aid", "prob": 25 }, + { "item": "legrig", "prob": 10 }, + { "item": "dump_pouch", "prob": 10 }, + { "item": "binoculars", "prob": 30 } + ] + }, + { + "id": "dks_knight_extras", + "type": "item_group", + "items": [ { "item": "1st_aid", "prob": 25 }, { "item": "legrig", "prob": 10 }, { "item": "dump_pouch", "prob": 10 } ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mongun.json b/data/mods/Dark-Skies-Above/monsters/mongun.json new file mode 100644 index 0000000000000..be2019c0b8734 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mongun.json @@ -0,0 +1,54 @@ +[ + { + "id": "dks_mon_flamesword", + "copy-from": "v29", + "type": "GUN", + "name": "fake flamesword", + "description": "a fake gun used by the consecrator. it's a bug if you find this in the wild", + "ranged_damage": { "damage_type": "heat", "amount": 10 }, + "pierce": 30, + "range": 9, + "loudness": 1, + "ammo_effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + }, + { + "id": "dks_mon_devastator", + "copy-from": "v29", + "type": "GUN", + "symbol": "/", + "color": "red", + "name": { "str": "fake firecannon" }, + "description": "Fires an explosive bolt of firey energy. If you're seeing this, it's a bug.", + "skill": "launcher", + "range": 15, + "ranged_damage": 5, + "flags": [ "NEVER_JAMS" ], + "ammo_effects": [ "NAPALM", "PLASMA", "STREAM_BIG", "INCENDIARY" ] + }, + { + "id": "dks_mon_radgun", + "copy-from": "v29", + "type": "GUN", + "symbol": "/", + "color": "red", + "name": { "str": "fake smokegun" }, + "description": "Shoots dangerous radioactive gas. If you're seeing this, it's a bug.", + "skill": "launcher", + "range": 10, + "flags": [ "NEVER_JAMS" ], + "ammo_effects": [ "DKS_NUKEGAS", "DKS_TOXGAS_BIG", "SMOKE", "DKS_TOXTRAIL" ] + }, + { + "id": "dks_mon_gasgun", + "copy-from": "v29", + "type": "GUN", + "symbol": "/", + "color": "red", + "name": { "str": "fake riotgun" }, + "description": "Shoots pacification gas. If you're seeing this, it's a bug.", + "skill": "launcher", + "range": 25, + "flags": [ "NEVER_JAMS" ], + "ammo_effects": [ "DKS_RELAXGAS", "DKS_RELAXTRAIL" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/monspell.json b/data/mods/Dark-Skies-Above/monsters/monspell.json new file mode 100644 index 0000000000000..8921f36f6d776 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/monspell.json @@ -0,0 +1,89 @@ +[ + { + "type": "SPELL", + "id": "dks_monspell_stun", + "name": "psi stun", + "description": "an attack that stuns the target for a few turns", + "valid_targets": [ "hostile" ], + "effect": "target_attack", + "effect_str": "stunned", + "message": "%1$s gesticulates at %3$s and a pulse of disorienting psionic energy ripples through the air!", + "min_range": 1, + "max_range": 10, + "min_duration": 225, + "max_duration": 225, + "flags": [ "SILENT" ] + }, + { + "type": "SPELL", + "id": "dks_monspell_panic", + "name": "psi panic", + "description": "an attack that panics the target for a few turns", + "valid_targets": [ "hostile" ], + "effect": "target_attack", + "effect_str": "panic", + "message": "The %1$s gesticulates at %3$s and a pulse of fear-inducing psionic energy ripples through the air!", + "min_range": 1, + "max_range": 10, + "min_duration": 425, + "max_duration": 425, + "flags": [ "SILENT" ] + }, + { + "type": "SPELL", + "id": "dks_monspell_halluc", + "name": "psi hallucinate", + "description": "an attack that causes the target to hallucinate for a few turns", + "valid_targets": [ "hostile" ], + "effect": "target_attack", + "effect_str": "visuals", + "message": "%1$s gesticulates at %3$s and a pulse of mind-bending psionic energy ripples through the air!", + "min_range": 1, + "max_range": 10, + "min_duration": 225, + "max_duration": 225, + "flags": [ "SILENT" ] + }, + { + "type": "SPELL", + "id": "dks_monspell_psighost", + "name": "psi ghost", + "description": "an attack that summons a temporary monster", + "valid_targets": [ "ground" ], + "effect": "summon", + "effect_str": "dks_mon_psighost", + "message": "%1$s gesticulates, and a soldier made of a mysterious energy appears!", + "min_damage": 1, + "max_damage": 1, + "min_range": 1, + "max_range": 10, + "min_aoe": 3, + "max_aoe": 3, + "min_duration": 1800, + "max_duration": 3600, + "flags": [ "SILENT", "HOSTILE_SUMMON" ] + }, + { + "type": "SPELL", + "id": "dks_spell_mindblast", + "name": "psi mindblast", + "description": "blasts a target with a wave of disorienting psionic energy. has random effects", + "valid_targets": [ "hostile" ], + "message": "", + "effect": "none", + "min_damage": 1, + "max_damage": 1, + "min_range": 10, + "max_range": 10, + "base_casting_time": 250, + "extra_effects": [ + { "id": "dks_monspell_stun" }, + { "id": "dks_monspell_panic" }, + { "id": "dks_monspell_panic" }, + { "id": "dks_monspell_halluc" }, + { "id": "dks_monspell_halluc" }, + { "id": "dks_monspell_psighost" } + ], + "flags": [ "SILENT", "WONDER" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json new file mode 100644 index 0000000000000..74e743f43a808 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json @@ -0,0 +1,71 @@ +[ + { + "//": "'high order' refers particularly to alien-derived units", + "id": "dks_neworder_pyro", + "type": "MONSTER", + "name": { "str": "new order consecrator" }, + "description": "Dressed from head to toe in stylized heavy armor, this holy warrior of the New Order wields an ornate greatsword. With chanted incantation, it can conjure bolts of flame from the hilt, scorching enemies before it. It has a strangely musical voice, marking it as something more than human.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN" ], + "diff": 10, + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 80, + "material": [ "flesh" ], + "symbol": "@", + "color": "red", + "aggression": 15, + "morale": 100, + "vision_day": 30, + "melee_skill": 5, + "melee_dice": 3, + "melee_dice_sides": 6, + "melee_cut": 6, + "armor_bash": 16, + "armor_cut": 16, + "harvest": "zombie_leather", + "special_attacks": [ + { + "type": "gun", + "cooldown": 1, + "move_cost": 400, + "gun_type": "dks_mon_flamesword", + "ammo_type": "generic_no_ammo", + "fake_skills": [ [ "gun", 5 ], [ "pistol", 4 ] ], + "fake_dex": 9, + "ranges": [ [ 0, 10, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 400, + "targeting_sound": "a sharp hymn in a strange language.", + "description": "The consecrator gestures with its sword, and all before it erupts in flame!!", + "targeting_volume": 20, + "no_ammo_sound": "a battlecry!" + }, + [ "PARROT", 20 ], + { "id": "heavyslash" } + ], + "death_drops": "dks_mon_neworder_pyro", + "path_settings": { "max_dist": 10 }, + "death_function": [ "FIREBALL", "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "PACIFIST", + "SWARMS", + "BASHES", + "GROUP_BASH", + "FIREPROOF", + "ACIDPROOF", + "PATH_AVOID_DANGER_2", + "PRIORITIZE_TARGETS", + "CAN_OPEN_DOORS" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json new file mode 100644 index 0000000000000..774050870c4fa --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json @@ -0,0 +1,139 @@ +[ + { + "//": "'low order' refers particularly to human-derived, humanoid units", + "id": "dks_neworder_scout", + "type": "MONSTER", + "name": { "str": "new order scout" }, + "description": "A soldier dressed in extremely light armor and a cloak that shifts subtly to camoflauge them against their surroundings. Armed with a fine blade and quite quick on their feet, they are often found in uncivilized locations, keeping tabs on the ever shifting Frontier.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 120, + "material": [ "flesh" ], + "symbol": "@", + "color": "green", + "aggression": 5, + "morale": 100, + "melee_skill": 6, + "melee_dice": 3, + "melee_dice_sides": 4, + "melee_cut": 5, + "dodge": 3, + "armor_bash": 6, + "armor_cut": 6, + "harvest": "dks_mhuman_chipped", + "special_attacks": [ [ "PARROT", 20 ], { "id": "knockdown" }, { "id": "slash" } ], + "death_drops": "dks_mon_neworder_scout", + "path_settings": { "max_dist": 20 }, + "anger_triggers": [ "PLAYER_CLOSE", "PLAYER_WEAK", "STALK" ], + "death_function": [ "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "BASHES", + "GROUP_BASH", + "BLEED", + "HUMAN", + "PATH_AVOID_DANGER_2", + "PRIORITIZE_TARGETS", + "CLIMBS" + ] + }, + { + "id": "dks_neworder_cop", + "type": "MONSTER", + "name": { "str": "new order vigilant" }, + "description": "A low ranking warpriest, a gendarmerie by any other name, assigned to the Frontier to supplement more conventional forces. They are in light armor to preserve both their agility and ability to channel psionics, which they use in conjunction with a small shield and shock baton.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 90, + "speed": 110, + "material": [ "flesh" ], + "symbol": "@", + "color": "blue", + "aggression": 15, + "morale": 100, + "vision_day": 30, + "melee_skill": 5, + "melee_dice": 2, + "melee_dice_sides": 5, + "melee_damage": [ { "damage_type": "electric", "amount": 4 } ], + "melee_cut": 0, + "dodge": 2, + "armor_bash": 8, + "armor_cut": 8, + "harvest": "dks_mhuman_chipped", + "special_attacks": [ [ "PARROT", 20 ], { "type": "spell", "spell_id": "dks_monspell_panic", "cooldown": 10 } ], + "death_drops": "dks_mon_neworder_cop", + "path_settings": { "max_dist": 5 }, + "death_function": [ "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "SWARMS", + "BASHES", + "GROUP_BASH", + "FIREPROOF", + "HUMAN", + "PATH_AVOID_DANGER_1", + "PRIORITIZE_TARGETS", + "CLIMBS" + ] + }, + { + "id": "dks_neworder_knight", + "type": "MONSTER", + "name": { "str": "new order knight" }, + "description": "A human clad in strange plate armor at that pulses with laser etched runes, mixed with more 'modern' looking combat gear. Armed with a runed sword that can cut through many materials with ease, a shield emblazed with the symbol of a sun being pierced by a sword, and unshakable faith in whatever otherworldy god they venerate, they stride forward to put down enemies of the Order wherever they may be.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 90, + "speed": 90, + "material": [ "flesh" ], + "symbol": "@", + "color": "light_gray", + "aggression": 15, + "morale": 100, + "vision_day": 30, + "melee_skill": 6, + "melee_dice": 3, + "melee_dice_sides": 4, + "melee_cut": 4, + "armor_bash": 16, + "armor_cut": 16, + "harvest": "dks_mhuman_chipped", + "special_attacks": [ [ "PARROT", 20 ], { "id": "slash" } ], + "death_drops": "dks_mon_neworder_knight", + "path_settings": { "max_dist": 10 }, + "death_function": [ "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "SWARMS", + "BASHES", + "GROUP_BASH", + "FIREPROOF", + "ACIDPROOF", + "PATH_AVOID_DANGER_1", + "PRIORITIZE_TARGETS" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json new file mode 100644 index 0000000000000..704a1f09fc71d --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json @@ -0,0 +1,205 @@ +[ + { + "id": "mon_dks_emissary", + "type": "MONSTER", + "name": { "str": "emissary", "str_pl": "emissaries" }, + "description": "A towering, metallic creature with a stunningly beautiful design and brilliantly shining etchings, standing atop three segmented legs. The tentacles that drift off of its central chassis are tipped with strange looking devices as it strides slowly across the shatterd landscape. This one seems less aggressive than those seen on the frontlines of the Arrival, studying its surroundings and probing things in the environment with a variety of internal tools. A sickeningly sweet gas hangs around it.", + "default_faction": "neworder", + "species": [ "ROBOT", "ALIEN" ], + "categories": [ "ALIEN" ], + "diff": 20, + "volume": "875000 ml", + "weight": "200 kg", + "hp": 250, + "speed": 75, + "material": [ "superalloy" ], + "symbol": "W", + "luminance": 60, + "color": "white", + "aggression": 40, + "morale": 10, + "melee_skill": 6, + "melee_dice": 5, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 90, + "armor_cut": 90, + "path_settings": { "max_dist": 30 }, + "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, + "fear_triggers": [ "HURT" ], + "special_attacks": [ + [ "PARROT", 20 ], + [ "TAZER", 20 ], + [ "RANGED_PULL", 20 ], + [ "GRAB_DRAG", 10 ], + { + "type": "gun", + "cooldown": 2, + "move_cost": 700, + "gun_type": "dks_mon_gasgun", + "max_ammo": 1000, + "ranges": [ [ 0, 30, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 500, + "targeting_sound": "the sound of pressurized gas hissing loudly.", + "targeting_volume": 40, + "description": "The emissary emits a stream of sedative gas!", + "no_ammo_sound": "a roar!" + } + ], + "death_function": [ "BROKEN" ], + "flags": [ + "SEES", + "HEARS", + "FIREPROOF", + "ACIDPROOF", + "GOODHEARING", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "ELECTRONIC", + "CLIMBS", + "GROUP_MORALE", + "PUSH_MON", + "PUSH_VEH", + "PRIORITIZE_TARGETS" + ] + }, + { + "id": "mon_dks_emissary_plague", + "type": "MONSTER", + "name": { "str": "emissary of pestilence", "str_pl": "emissaries of pestilence" }, + "description": "A towering, stories-tall metallic creature standing atop three long legs connected to a central chassis. It would be stunningly beautiful with its glowing golden inlays and celestial design, were it not for the gas that pours from its tentacle-mounted guns that despoils the landscape and makes your skin prickle just looking at its toxic, likely radioactive, glory. Its hums hauntingly as it moves and booming footsteps often heralded trouble to come during the Arrival, now is no different.", + "default_faction": "neworder", + "species": [ "ROBOT", "ALIEN" ], + "categories": [ "ALIEN" ], + "diff": 20, + "volume": "875000 ml", + "weight": "200 kg", + "hp": 250, + "speed": 75, + "material": [ "superalloy" ], + "symbol": "W", + "luminance": 60, + "color": "green", + "aggression": 40, + "morale": 10, + "melee_skill": 6, + "melee_dice": 5, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 90, + "armor_cut": 90, + "path_settings": { "max_dist": 30 }, + "emit_fields": [ { "emit_id": "emit_toxic_leak", "delay": "1 s" } ], + "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, + "fear_triggers": [ "HURT" ], + "special_attacks": [ + [ "PARROT", 20 ], + [ "SMASH", 30 ], + [ "LONGSWIPE", 20 ], + { + "type": "gun", + "cooldown": 2, + "move_cost": 700, + "gun_type": "dks_mon_radgun", + "max_ammo": 1000, + "ranges": [ [ 0, 20, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 500, + "targeting_sound": "an ominous rumble and hiss of gas.", + "targeting_volume": 40, + "description": "Putrid gas rolls across the landscape!", + "no_ammo_sound": "a roar!" + } + ], + "death_function": [ "BROKEN" ], + "flags": [ + "SEES", + "HEARS", + "FIREPROOF", + "ACIDPROOF", + "GOODHEARING", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "ELECTRONIC", + "CLIMBS", + "GROUP_MORALE", + "PUSH_MON", + "PUSH_VEH", + "PRIORITIZE_TARGETS" + ] + }, + { + "id": "mon_dks_emissary_flame", + "type": "MONSTER", + "name": { "str": "emissary of flame", "str_pl": "emissaries of flame" }, + "description": "Like all emissaries, this breathtaking metallic creature stands atop three long legs, with many more segmented tentacles eminating from its central chassis and a glowing halo about its head. This one is far more terrifying though, its claim to fame being some sort of high-intensity energy cannon, capable of rending whatever it touches asunder in an explosive burst of plasma and flame. Its unique chirping and booming footsteps often heralded trouble to come during the Arrival, and now is no different.", + "default_faction": "neworder", + "species": [ "ROBOT", "ALIEN" ], + "categories": [ "ALIEN" ], + "diff": 30, + "volume": "875000 ml", + "weight": "200 kg", + "hp": 250, + "speed": 75, + "material": [ "superalloy" ], + "symbol": "W", + "luminance": 60, + "color": "dark_gray", + "aggression": 40, + "morale": 10, + "melee_skill": 6, + "melee_dice": 5, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 90, + "armor_cut": 90, + "path_settings": { "max_dist": 30 }, + "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, + "fear_triggers": [ "HURT" ], + "special_attacks": [ + [ "PARROT", 20 ], + [ "SMASH", 30 ], + [ "LONGSWIPE", 20 ], + { + "type": "gun", + "cooldown": 2, + "move_cost": 700, + "gun_type": "dks_mon_devastator", + "max_ammo": 1000, + "ranges": [ [ 0, 30, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 600, + "targeting_sound": "the air pressure suddenly drop as the emissary charges its cannon!", + "targeting_volume": 40, + "description": "Sound returns as the emissary's cannon roars to life!!", + "no_ammo_sound": "a roar!" + } + ], + "death_function": [ "BROKEN" ], + "flags": [ + "SEES", + "HEARS", + "FIREPROOF", + "ACIDPROOF", + "GOODHEARING", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "ELECTRONIC", + "CLIMBS", + "GROUP_MORALE", + "PUSH_MON", + "PUSH_VEH", + "PRIORITIZE_TARGETS" + ] + } +] From 1f6b018971d935e7300984ccada217dd203ea21c Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Fri, 6 Mar 2020 14:16:02 -0500 Subject: [PATCH 024/219] Dark Skies 8: Adds strays, lurker, enemies; updates modinfo (#38596) --- data/mods/Dark-Skies-Above/modinfo.json | 11 + .../monsters/mon_groups/stray_spawns.json | 349 ++++++++++++++++++ .../monsters/wild_aliens/lurker.json | 33 ++ .../monsters/wild_aliens/strays.json | 345 +++++++++++++++++ 4 files changed, 738 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/modinfo.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json create mode 100644 data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json create mode 100644 data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json diff --git a/data/mods/Dark-Skies-Above/modinfo.json b/data/mods/Dark-Skies-Above/modinfo.json new file mode 100644 index 0000000000000..6c86d0ba5a4ed --- /dev/null +++ b/data/mods/Dark-Skies-Above/modinfo.json @@ -0,0 +1,11 @@ +[ + { + "type": "MOD_INFO", + "ident": "darkskies", + "name": "Dark Skies Above", + "authors": [ "ephemeral_storyteller" ], + "description": "A total conversion that shifts the Cataclysm towards an XCOM 2 style alien occupation. Use other mods at your own risk!", + "category": "content", + "dependencies": [ "dda" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json new file mode 100644 index 0000000000000..ed6a010724e27 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json @@ -0,0 +1,349 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 7, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 15, "pack_size": [ 25, 45 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 20, "pack_size": [ 35, 55 ] }, + { "monster": "dks_mon_stray", "freq": 65, "cost_multiplier": 0, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 75, "cost_multiplier": 0, "pack_size": [ 15, 30 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 5, "cost_multiplier": 10, "pack_size": [ 2, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 5, "cost_multiplier": 5, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 10 ] }, + { "monster": "dks_mon_stray_fast", "freq": 20, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_fast", "freq": 5, "cost_multiplier": 10, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 5, "pack_size": [ 1, 6 ] }, + { "monster": "dks_mon_stray_child", "freq": 40, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_eater", "freq": 5, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 15, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 10 } + ] + }, + { + "name": "GROUP_PARK_PLAYGROUND", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 295, "cost_multiplier": 1, "pack_size": [ 5, 12 ] }, + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 75, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_wretch", "freq": 50, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_burnt", "freq": 50, "cost_multiplier": 2 } + ] + }, + { + "name": "GROUP_PARK_DOG", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 125, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 125, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_eater", "freq": 5, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 20, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 2 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_HOUSE", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 70, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 65, "cost_multiplier": 2, "pack_size": [ 1, 4 ] }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_wretch", "freq": 15, "cost_multiplier": 2, "pack_size": [ 1, 3 ] } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_VANILLA", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_burnt", "freq": 60, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_wretch", "freq": 50, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 30, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_eater", "freq": 20, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_PHARM", + "//": "+13% fast", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_eater", "freq": 130, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_wretch", "freq": 130, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_burnt", "freq": 40, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 130, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ELECTRO", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_wretch", "freq": 130, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_burnt", "freq": 40, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 130, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_GROCERY", + "//": "+15% eater", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_eater", "freq": 280, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_wretch", "freq": 40, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_PUBLICWORKERS", + "default": "dks_mon_stray_fast", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 5 }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_wretch", "freq": 4, "cost_multiplier": 5 }, + { "monster": "dks_mon_stray_heavy", "freq": 200, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_MAYBE_ZOMBIE", + "//": "10% chance of a zombie", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 40, "cost_multiplier": 0, "pack_size": [ 1, 5 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 6, "cost_multiplier": 2, "pack_size": [ 1, 5 ] }, + { "monster": "dks_mon_stray_fast", "freq": 5, "cost_multiplier": 2, "pack_size": [ 1, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_child", "freq": 11, "cost_multiplier": 0 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_FAT_BASE", + "default": "mon_null", + "monsters": [ { "monster": "dks_mon_stray_eater", "freq": 40, "cost_multiplier": 2 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_FAT", + "default": "mon_null", + "monsters": [ { "monster": "dks_mon_stray_eater", "freq": 480, "cost_multiplier": 2 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_SCHOOL", + "default": "mon_null", + "//": "School monster spawns.", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 650, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray", "freq": 150, "cost_multiplier": 1 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_SMALL_STATION", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 55, "cost_multiplier": 4, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_fast", "freq": 50, "cost_multiplier": 5, "pack_size": [ 2, 4 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 25, "cost_multiplier": 0 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_LARGE_STATION", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 55, "cost_multiplier": 4, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_fast", "freq": 50, "cost_multiplier": 5, "pack_size": [ 2, 4 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 40, "cost_multiplier": 10 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_CHURCH_ZOMBIE", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 1, "cost_multiplier": 7, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 1, "cost_multiplier": 13, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 1, "cost_multiplier": 20, "pack_size": [ 35, 40 ] }, + { "monster": "dks_mon_stray_eater", "freq": 75, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray", "freq": 3, "cost_multiplier": 7, "pack_size": [ 3, 5 ] }, + { "monster": "dks_mon_stray_fast", "freq": 75, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_child", "freq": 75, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_burnt", "freq": 50, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 25, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_PRISON", + "default": "dks_mon_stray", + "monsters": [ { "monster": "dks_mon_stray", "freq": 350, "cost_multiplier": 0 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_COP", + "default": "dks_mon_stray_fast", + "monsters": [ + { "monster": "dks_mon_stray_fast", "freq": 100, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_heavy", "freq": 40, "cost_multiplier": 10 } + ] + }, + { + "name": "GROUP_MANSION", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 2, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 30, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child", "freq": 10, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 4 }, + { "monster": "dks_mon_stray_fast", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 2 ] } + ] + }, + { + "name": "GROUP_PANICROOM", + "type": "monstergroup", + "default": "dks_mon_stray_child", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray", "freq": 20, "cost_multiplier": 1 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_HOSPITAL", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 7, "pack_size": [ 5, 10 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 15, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 20, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 75, "cost_multiplier": 0, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 5, "pack_size": [ 2, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 5, "cost_multiplier": 10, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 10 ] }, + { "monster": "dks_mon_stray_fast", "freq": 65, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_fast", "freq": 1, "cost_multiplier": 5, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 70, "cost_multiplier": 5, "pack_size": [ 1, 6 ] }, + { "monster": "dks_mon_stray_child", "freq": 40, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_eater", "freq": 5, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 15, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 10 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_STEEL_MILL", + "default": "mon_null", + "//": "Steel mill monster spawns.", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 7, "pack_size": [ 5, 10 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 15, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 20, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 75, "cost_multiplier": 0, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 5, "pack_size": [ 2, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 5, "cost_multiplier": 10, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 10 ] }, + { "monster": "dks_mon_stray_fast", "freq": 65, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_fast", "freq": 1, "cost_multiplier": 5, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 20, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 10, "cost_multiplier": 15, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 10, "cost_multiplier": 10 } + ] + }, + { + "name": "GROUP_MALL", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_eater", "freq": 40, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 10, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 20, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 1 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_SEXSHOP_A", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 150, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 100, "cost_multiplier": 2 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_SEXSHOP_B", + "default": "mon_null", + "monsters": [ { "monster": "dks_mon_stray", "freq": 500, "cost_multiplier": 2 } ] + }, + { + "name": "GROUP_FIRE", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_fast", "freq": 100, "cost_multiplier": 2, "pack_size": [ 3, 5 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 40, "cost_multiplier": 1 } + ] + }, + { + "name": "GROUP_PLAIN", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ { "monster": "dks_mon_stray", "freq": 40, "cost_multiplier": 1 } ] + }, + { + "name": "GROUP_HOTEL_POOL", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray", "freq": 50, "cost_multiplier": 10, "pack_size": [ 3, 8 ] }, + { "monster": "dks_mon_stray_child", "freq": 35, "cost_multiplier": 1 } + ] + }, + { + "name": "GROUP_HOTEL_GYM", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 30, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 15, "cost_multiplier": 8, "pack_size": [ 2, 6 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 8, "cost_multiplier": 3 } + ] + }, + { + "name": "GROUP_POOL_NOKIDS", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray", "freq": 50, "cost_multiplier": 10, "pack_size": [ 3, 8 ] } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json b/data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json new file mode 100644 index 0000000000000..4c084d345e584 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json @@ -0,0 +1,33 @@ +[ + { + "id": "dks_mon_lurker_sewer", + "type": "MONSTER", + "name": { "str": "sewer lurker" }, + "description": "A dripping creature, a writhing mass of tentacles attached to a gnashing maw, this thing seems to have found its home among trash and sewage. It is an ambush predator, prefering to lurk just beneath the cloudy water before something comes close enough to snag.", + "default_faction": "lurker", + "bodytype": "spider", + "categories": [ "ALIEN" ], + "species": [ "WILDALIEN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 150, + "speed": 120, + "material": [ "flesh" ], + "symbol": "&", + "color": "green_white", + "aggression": -5, + "morale": 100, + "melee_skill": 7, + "melee_dice": 4, + "melee_dice_sides": 6, + "melee_cut": 0, + "dodge": 5, + "armor_bash": 6, + "armor_cut": 2, + "harvest": "zombie_leather", + "special_attacks": [ [ "GRAB", 7 ], [ "TENTACLE", 5 ] ], + "anger_triggers": [ "PLAYER_CLOSE", "PLAYER_WEAK" ], + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "SWIMS", "AQUATIC", "POISON", "HARDTOSHOOT" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json b/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json new file mode 100644 index 0000000000000..3287f540948f4 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json @@ -0,0 +1,345 @@ +[ + { + "id": "dks_mon_stray", + "type": "MONSTER", + "name": "stray", + "description": "The pitifully thin body of what once was a human, ruined beyond recognition by whatever foul weapons were used on them during the Arrival. Now suspended somewhere between life and death at the hands of its own rogue biology, this creature wanders the ruins of its former hometown, its hollow eyes glowing with pinpricks of hateful energy.", + "looks_like": "mon_skeleton", + "default_faction": "stray", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 50, + "speed": 65, + "material": [ "flesh" ], + "symbol": "S", + "color": "white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 2, + "melee_dice_sides": 3, + "melee_cut": 1, + "vision_night": 3, + "harvest": "mutant_human", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ { "type": "bite", "cooldown": 5 }, [ "GRAB", 7 ], [ "scratch", 20 ] ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 10, "into": "DKS_GROUP_STRAY_UPGRADE" }, + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "STUMBLES", + "POISON", + "BLEED", + "HUMAN", + "FILTHY", + "BASHES", + "REVIVES", + "GROUP_BASH", + "PUSH_MON" + ] + }, + { + "id": "dks_mon_stray_eater", + "type": "MONSTER", + "name": "hungy stray", + "description": "A hunger-bloated body with a distended jaw, a pitiful figure but no less hateful than its friends. It lets out bloodcurdling howls of want and constantly regurgitates the contents of its stomach, only to seek another meal in some sort of mockery of human eating patterns.", + "looks_like": "mon_boomer", + "default_faction": "stray", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 50, + "speed": 55, + "material": [ "flesh" ], + "symbol": "S", + "color": "pink_white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 2, + "melee_dice_sides": 3, + "melee_cut": 1, + "armor_bash": 5, + "armor_cut": 3, + "vision_night": 3, + "harvest": "zombie", + "path_settings": { "max_dist": 2 }, + "regenerates": 10, + "special_attacks": [ [ "BOOMER", 20 ], { "type": "bite", "cooldown": 2, "accuracy": 3, "no_infection_chance": 10 }, [ "SHRIEK", 10 ] ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "BOOMER" ], + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "STUMBLES", + "POISON", + "BILE_BLOOD", + "KEENNOSE", + "FILTHY", + "REVIVES", + "BASHES", + "GROUP_BASH", + "PUSH_MON" + ] + }, + { + "id": "dks_mon_stray_fast", + "type": "MONSTER", + "name": "stray sprinter", + "description": "This once-shambling human body has become subtly toned, and though its still appears caught between putrefying on the spot and living, it now moves with a hint of animal cunning. A tightened mouth surrounds gnashing teeth as it hunts for fresh meat with more intensity than those around it.", + "default_faction": "stray", + "looks_like": "mon_zombie_runner", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 60, + "speed": 105, + "material": [ "flesh" ], + "symbol": "S", + "color": "light_gray", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 4, + "melee_dice_sides": 3, + "melee_cut": 3, + "dodge": 1, + "vision_night": 3, + "harvest": "mutant_human", + "path_settings": { "max_dist": 5 }, + "regenerates": 1, + "special_attacks": [ + [ "scratch", 10 ], + { + "type": "bite", + "cooldown": 5, + "damage_max_instance": [ { "damage_type": "stab", "amount": 10, "armor_multiplier": 0.7 } ] + } + ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "NORMAL" ], + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "WARM", + "HUMAN", + "BASHES", + "POISON", + "PUSH_MON", + "REVIVES", + "PATH_AVOID_FALL", + "FILTHY", + "BLEED" + ] + }, + { + "id": "dks_mon_stray_heavy", + "type": "MONSTER", + "name": "stray bruiser", + "description": "Swollen with muscle beyond what the human form would have normally allowed, this festering mass of raw power pulverizes whatever it comes across with the thick cudgels that were once its hands. Its evolved regenative capacity seems to have granted it an outer shell now a protective layer of scar tissue, like a cocoon. Tiny eyes peer out from behind the thick layers of callused flesh on its face, but its ears are now large holes in the sides of its head, suggesting it now has other ways of finding you.", + "default_faction": "stray", + "looks_like": "mon_skeleton_brute", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 2, + "volume": "62500 ml", + "weight": "81500 g", + "hp": 100, + "speed": 90, + "material": [ "flesh" ], + "symbol": "S", + "color": "red_white", + "aggression": 100, + "morale": 100, + "melee_skill": 5, + "melee_dice": 3, + "melee_dice_sides": 8, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "vision_day": 15, + "vision_night": 1, + "harvest": "zombie", + "path_settings": { "max_dist": 2 }, + "regenerates": 5, + "special_attacks": [ [ "SMASH", 30 ], [ "GRAB", 7 ] ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "NORMAL" ], + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "GOODHEARING", + "SMELLS", + "STUMBLES", + "WARM", + "BASHES", + "GROUP_BASH", + "REVIVES", + "POISON", + "PUSH_MON", + "PUSH_VEH", + "ATTACKMON", + "FILTHY" + ] + }, + { + "id": "dks_mon_stray_burnt", + "type": "MONSTER", + "name": "stray husk", + "description": "The charred body of a human, burned beyond recognition. Though its skin is slowly regenerating back to its base state, the charcoal-like shell that has formed around its skin and its spikes make for decent armor and weaponry. If killed now, it likely won't be coming back, its regenative properties overwhelmed.", + "default_faction": "stray", + "looks_like": "mon_zombie_scorched", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 40, + "speed": 60, + "material": [ "flesh" ], + "symbol": "S", + "color": "i_white", + "aggression": 100, + "morale": 100, + "melee_skill": 2, + "melee_dice": 2, + "melee_dice_sides": 2, + "melee_cut": 4, + "armor_bash": 2, + "armor_cut": 9, + "armor_acid": 3, + "armor_fire": 15, + "vision_day": 10, + "vision_night": 3, + "harvest": "mutant_human", + "emit_fields": [ "emit_smaller_smoke_plume" ], + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ [ "GRAB", 7 ] ], + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 9, "into": "dks_mon_stray" }, + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "POISON", "BLEED", "FILTHY" ] + }, + { + "id": "dks_mon_stray_child", + "type": "MONSTER", + "name": "stray waif", + "description": "If not for the painfully pale skin and heavily sunken eyes, it would be easy to mistake this little figure for a normal child. Unfortunately, whatever terrible weapon that the aliens used on much of the population has been no kinder to them, and the same hateful malice lurks deep within the dark of their eye-sockets. Still, the idea of putting it down twists your gut in some sort of primal way.", + "default_faction": "stray", + "looks_like": "mon_zombie_waif", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 35, + "speed": 65, + "material": [ "flesh" ], + "symbol": "s", + "color": "white", + "aggression": 80, + "morale": 100, + "melee_skill": 2, + "melee_dice": 2, + "melee_dice_sides": 2, + "melee_cut": 1, + "dodge": 2, + "armor_cut": 5, + "vision_day": 30, + "vision_night": 5, + "harvest": "mutant_human", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ [ "scratch", 10 ] ], + "death_drops": { "subtype": "collection", "groups": [ [ "mon_zombie_hulk_death_drops", 100 ], [ "child_items", 65 ] ] }, + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 12, "into": "dks_mon_stray_wretch" }, + "burn_into": "dks_mon_stray_child_burnt", + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "HUMAN", "WARM", "BLEED", "GUILT", "POISON", "REVIVES", "FILTHY" ] + }, + { + "id": "dks_mon_stray_child_burnt", + "type": "MONSTER", + "name": "stray tinder", + "description": "What remains of a thoroughly charred child, grimacing features just intact enough to make your gut churn. Even now, its regenative properties work to repair its body back to its former self - given enough time. If killed like this, it probably won't be coming back - its regentative properties are greatly weakened now.", + "default_faction": "stray", + "looks_like": "mon_zombie_child_scorched", + "bodytype": "human", + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 15, + "speed": 60, + "material": [ "flesh" ], + "symbol": "s", + "color": "i_white", + "aggression": 100, + "morale": 100, + "melee_skill": 2, + "melee_dice": 1, + "melee_dice_sides": 3, + "melee_cut": 5, + "armor_bash": 4, + "armor_cut": 5, + "armor_acid": 3, + "armor_fire": 15, + "vision_day": 10, + "vision_night": 3, + "harvest": "mutant_human", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "emit_fields": [ "emit_smaller_smoke_plume" ], + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 9, "into": "dks_mon_stray_child" }, + "flags": [ "SEES", "HEARS", "STUMBLES", "POISON", "GUILT", "FILTHY" ] + }, + { + "id": "dks_mon_stray_wretch", + "type": "MONSTER", + "name": "stray wretch", + "description": "This blur of jagged limbs and hair might have been a housepet at some point - or, forbid, perhaps even a child. Regardless of its origin, this creature has been thoroughly twisted into something you'd expect to see in an episode of sleep paralysis.", + "default_faction": "stray", + "looks_like": "mon_dog_skeleton", + "bodytype": "dog", + "species": [ "ZOMBIE" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 25, + "speed": 110, + "material": [ "flesh" ], + "symbol": "s", + "color": "white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 1, + "melee_dice_sides": 6, + "melee_cut": 2, + "dodge": 3, + "vision_night": 4, + "harvest": "zombie_fur", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ { "type": "bite", "cooldown": 5 }, { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "BLEED", "HARDTOSHOOT", "REVIVES", "POISON", "CLIMBS", "FILTHY" ] + } +] From d09413b71a63a335f57488e8af9001fd1483a7e3 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 8 Mar 2020 12:13:51 -0400 Subject: [PATCH 025/219] Dark Skies: Spell Fixes (#38643) --- .../Dark-Skies-Above/monsters/new_order/neworder_loworder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json index 774050870c4fa..ecc4636791d99 100644 --- a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json @@ -73,7 +73,7 @@ "armor_bash": 8, "armor_cut": 8, "harvest": "dks_mhuman_chipped", - "special_attacks": [ [ "PARROT", 20 ], { "type": "spell", "spell_id": "dks_monspell_panic", "cooldown": 10 } ], + "special_attacks": [ [ "PARROT", 20 ], { "type": "spell", "spell_data": { "id": "dks_monspell_panic" }, "cooldown": 10 } ], "death_drops": "dks_mon_neworder_cop", "path_settings": { "max_dist": 5 }, "death_function": [ "NORMAL" ], From 554cb14cb23803eff1808a34f573996a6ed56df6 Mon Sep 17 00:00:00 2001 From: curstwist <39442864+curstwist@users.noreply.github.com> Date: Sun, 8 Mar 2020 12:25:41 -0400 Subject: [PATCH 026/219] [Magiclysm] Add Magiclysm academy (#38511) --- .../mods/Magiclysm/itemgroups/itemgroups.json | 465 ++++++++++++- data/mods/Magiclysm/items/books_lore.json | 50 ++ data/mods/Magiclysm/items/spell_scrolls.json | 94 +++ data/mods/Magiclysm/items/spellbooks.json | 23 + .../Magiclysm/worldgen/magic_academy.json | 617 ++++++++++++++++++ .../Magiclysm/worldgen/magic_basement.json | 2 +- .../worldgen/multitile_city_buildings.json | 17 + .../Magiclysm/worldgen/overmap_terrain.json | 89 +++ .../Magiclysm/worldgen/regional_overlay.json | 5 +- 9 files changed, 1336 insertions(+), 26 deletions(-) create mode 100644 data/mods/Magiclysm/items/books_lore.json create mode 100644 data/mods/Magiclysm/worldgen/magic_academy.json diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 2a4f1a8202ee1..45016883441b1 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -135,8 +135,8 @@ "items": [ { "group": "potions_common", "prob": 80 }, { "group": "alchemy_items", "prob": 30 }, - [ "crystallized_mana", 25 ], - { "item": "small_mana_crystal", "prob": 20, "charges-min": 5, "charges-max": 50 } + [ "crystallized_mana", 55 ], + { "item": "small_mana_crystal", "prob": 40, "charges-min": 5, "charges-max": 50 } ] }, { @@ -568,17 +568,19 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_tokens_tool", "prob": 20 }, - { "group": "enchanted_tokens_weapon", "prob": 1 }, - { "group": "enchanted_rings_common", "prob": 15 }, - { "group": "enchanted_rings_uncommon", "prob": 1 }, - { "group": "enchanted_wands_minor", "prob": 5 }, - { "group": "enchanted_masks", "prob": 1 }, - { "group": "magic_shop_potions", "prob": 20 }, + { "group": "enchanted_tokens_tool", "prob": 30 }, + { "group": "enchanted_tokens_weapon", "prob": 3 }, + { "group": "enchanted_rings_common", "prob": 20 }, + { "group": "enchanted_rings_uncommon", "prob": 5 }, + { "group": "enchanted_wands_minor", "prob": 10 }, + { "group": "enchanted_masks", "prob": 2 }, + { "group": "magic_shop_potions", "prob": 40 }, { "group": "spellbook_loot_1", "prob": 30 }, - { "group": "magic_CBM", "prob": 1 }, - [ "crystallized_mana", 10 ], - { "item": "small_mana_crystal", "prob": 20, "charges-min": 5, "charges-max": 50 } + { "group": "magic_CBM", "prob": 2 }, + { "item": "lair_map", "prob": 20 }, + { "item": "retreat_map", "prob": 30 }, + [ "crystallized_mana", 50 ], + { "item": "small_mana_crystal", "prob": 40, "charges-min": 5, "charges-max": 50 } ] }, { @@ -587,9 +589,9 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_bracers_lesser", "prob": 20 }, - { "group": "enchanted_boots", "prob": 5 }, - { "group": "enchanted_belts", "prob": 5 } + { "group": "enchanted_bracers_lesser", "prob": 25 }, + { "group": "enchanted_boots", "prob": 7 }, + { "group": "enchanted_belts", "prob": 7 } ] }, { @@ -598,9 +600,9 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_bracers_lesser", "prob": 20 }, - { "group": "enchanted_worn_items", "prob": 10 }, - { "group": "enchanted_melee_weapons_plus1", "prob": 2 }, + { "group": "enchanted_bracers_lesser", "prob": 25 }, + { "group": "enchanted_worn_items", "prob": 15 }, + { "group": "enchanted_melee_weapons_plus1", "prob": 3 }, { "group": "enchanted_small_items", "prob": 1 } ] }, @@ -610,12 +612,427 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_combat_items", "prob": 20 }, - { "group": "enchanted_misc", "prob": 40 }, - { "group": "enchanted_rings_unusual", "prob": 10 }, - { "group": "enchanted_rings_rare", "prob": 20 }, - { "group": "enchanted_wands_greater", "prob": 20 }, - { "group": "enchanted_wands_lesser", "prob": 10 } + { "group": "enchanted_combat_items", "prob": 40 }, + { "group": "enchanted_misc", "prob": 50 }, + { "group": "enchanted_rings_unusual", "prob": 20 }, + { "group": "enchanted_rings_rare", "prob": 30 }, + { "group": "enchanted_wands_greater", "prob": 30 }, + { "group": "enchanted_wands_lesser", "prob": 20 } + ] + }, + { + "id": "stormshaper_items", + "//": "A distribution of magical items for stormshaper themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_stormshaper_wall_of_fog", "prob": 50 }, + { "item": "spell_scroll_lightning_blast", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "spell_scroll_jolt", "prob": 50 }, + { "item": "spell_scroll_lightning_bolt", "prob": 50 }, + { "item": "spell_scroll_windstrike", "prob": 50 }, + { "item": "spell_scroll_windrun", "prob": 50 } + ], + "prob": 40 + }, + { + "distribution": [ + { "item": "tome_of_storms", "prob": 5 }, + { "item": "spell_scroll_storm_hammer", "prob": 50 }, + { "item": "spell_scroll_stormshaper_ionization", "prob": 50 }, + { "item": "lightning_storm_scroll", "prob": 10 } + ], + "prob": 10 + } + ] + }, + { + "id": "magus_items", + "//": "A distribution of magical items for magus themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "wizard_beginner", "prob": 30 }, + { "item": "wizard_utility", "prob": 20 }, + { "item": "spell_scroll_magic_missile", "prob": 70 }, + { "item": "spell_scroll_phase_door", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "wizard_advanced", "prob": 20 }, + { "item": "spell_scroll_magus_mana_bolt", "prob": 50 }, + { "item": "spell_scroll_magus_haste", "prob": 50 }, + { "item": "spell_scroll_magus_mana_beam", "prob": 50 }, + { "item": "spell_scroll_magus_escape", "prob": 50 }, + { "item": "spell_scroll_cats_grace", "prob": 50 }, + { "item": "spell_scroll_eagles_sight", "prob": 50 }, + { "item": "spell_scroll_ogres_strength", "prob": 50 }, + { "item": "spell_scroll_foxs_cunning", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "magus_spellbook_move", "prob": 25 }, + { "item": "magus_spellbook", "prob": 25 }, + { "item": "spell_scroll_magus_mana_blast", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "item": "recovery_spellbook", "prob": 10 }, { "item": "spell_scroll_invisibility", "prob": 50 } ], + "prob": 5 + } + ] + }, + { + "id": "animist_items", + "//": "A distribution of magical items for animist themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_smite", "prob": 50 }, + { "item": "spell_scroll_summon_zombie", "prob": 50 }, + { "item": "spell_scroll_necrotic_gaze", "prob": 50 }, + { "item": "spell_scroll_summon_wisps", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ { "item": "priest_advanced", "prob": 10 }, { "item": "spell_scroll_summon_skeleton", "prob": 50 } ], + "prob": 35 + }, + { + "distribution": [ + { "item": "recovery_spellbook", "prob": 5 }, + { "item": "winter_grasp", "prob": 10 }, + { "item": "spell_scroll_recover_mana", "prob": 50 }, + { "item": "spell_scroll_summon_decayed_pouncer", "prob": 50 }, + { "item": "spell_scroll_recover_pain", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ + { "item": "animist_doll_skeleton", "prob": 10 }, + { "item": "animist_doll_zombie", "prob": 20 }, + { "item": "animist_doll_decayed_pouncer", "prob": 3 } + ], + "prob": 20 + } + ] + }, + { + "id": "kelvinist_items", + "//": "A distribution of magical items for kelvinist themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ { "item": "spell_scroll_create_lighter", "prob": 50 }, { "item": "spell_scroll_chilling_touch", "prob": 50 } ], + "prob": 45 + }, + { + "distribution": [ + { "item": "wizard_utility", "prob": 10 }, + { "item": "spell_scroll_point_flare", "prob": 50 }, + { "item": "spell_scroll_ice_spike", "prob": 50 }, + { "item": "spell_scroll_burning_hands", "prob": 50 }, + { "item": "spell_scroll_frost_spray", "prob": 50 }, + { "item": "spell_scroll_glide_ice", "prob": 50 }, + { "item": "spell_scroll_ice_shield", "prob": 50 }, + { "item": "spell_scroll_frost_armor", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "wizard_advanced", "prob": 5 }, + { "item": "pyro", "prob": 5 }, + { "item": "spell_scroll_fireball", "prob": 10 }, + { "item": "spell_scroll_recover_bionic_power", "prob": 50 }, + { "item": "spell_scroll_cone_cold", "prob": 50 }, + { "item": "spell_scroll_hoary_blast", "prob": 50 } + ], + "prob": 10 + } + ] + }, + { + "id": "technomancer_items", + "//": "A distribution of magical items for technomancer themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "priest_beginner", "prob": 20 }, + { "item": "techno_idiots", "prob": 20 }, + { "item": "spell_scroll_x-ray", "prob": 50 }, + { "item": "spell_scroll_bless", "prob": 50 }, + { "item": "spell_scroll_create_atomic_lamp", "prob": 50 }, + { "item": "spell_scroll_taze", "prob": 50 }, + { "item": "spell_scroll_laze", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "priest_advanced", "prob": 20 }, + { "item": "techno_fundamentals", "prob": 20 }, + { "item": "spell_scroll_quantum_tunnel_lesser", "prob": 50 }, + { "item": "spell_scroll_holy_blade", "prob": 50 }, + { "item": "spell_scroll_spirit_armor", "prob": 50 }, + { "item": "spell_scroll_synaptic_stimulation", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "techno_em", "prob": 5 }, + { "item": "spell_scroll_holographic_transposition", "prob": 10 }, + { "item": "spell_scroll_recover_bionic_power", "prob": 50 }, + { "item": "spell_scroll_animated_blade", "prob": 50 }, + { "item": "spell_scroll_mirror_image", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "item": "recovery_spellbook", "prob": 10 }, { "item": "spell_scroll_invisibility", "prob": 50 } ], + "prob": 5 + }, + { "group": "magic_CBM", "prob": 2 } + ] + }, + { + "id": "earthshaper_items", + "//": "A distribution of magical items for earthshaper themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_stonefist", "prob": 50 }, + { "item": "spell_scroll_eshaper_piercing_bolt", "prob": 50 }, + { "item": "spell_scroll_eshaper_rockbolt", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "spell_scroll_seismic_stomp", "prob": 50 }, + { "item": "spell_scroll_clairvoyance", "prob": 50 }, + { "item": "spell_scroll_eshaper_shardspray", "prob": 50 }, + { "item": "spell_scroll_earthshaper_stoneskin", "prob": 50 }, + { "item": "spell_scroll_earthshaper_pillar", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "recovery_spellbook", "prob": 5 }, + { "item": "eshaper_spellbook", "prob": 10 }, + { "item": "spell_scroll_recover_stamina", "prob": 50 }, + { "item": "spell_scroll_eshaper_shardstorm", "prob": 50 }, + { "item": "spell_scroll_lava_bomb", "prob": 50 } + ], + "prob": 10 + } + ] + }, + { + "id": "biomancer_items", + "//": "A distribution of magical items for biomancer themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "priest_beginner", "prob": 30 }, + { "item": "spell_scroll_light_healing", "prob": 50 }, + { "item": "spell_scroll_bio_acidicspray", "prob": 50 }, + { "item": "spell_scroll_biomancer_paralytic_dart", "prob": 50 }, + { "item": "spell_scroll_biomancer_visceral_projection", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "wizard_utility", "prob": 20 }, + { "item": "spell_scroll_pain_split", "prob": 50 }, + { "item": "spell_scroll_bio_grotesque", "prob": 50 }, + { "item": "spell_scroll_biomancer_coagulant_weave", "prob": 50 }, + { "item": "spell_scroll_bio_fleshpouch", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "wizard_advanced", "prob": 10 }, + { "item": "biomancer_spellbook", "prob": 10 }, + { "item": "spell_scroll_vicious_tentacle", "prob": 50 }, + { "item": "spell_scroll_bio_bonespear", "prob": 50 } + ], + "prob": 10 + } + ] + }, + { + "id": "druid_items", + "//": "A distribution of magical items for druid themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_druid_woodshaft", "prob": 30 }, + { "item": "summon_scroll_smudged", "prob": 2 }, + { "item": "spell_scroll_summon_cats", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "druid_spellbook", "prob": 20 }, + { "item": "spell_scroll_druid_veggrasp", "prob": 100 }, + { "item": "spell_scroll_druid_naturebow1", "prob": 100 }, + { "item": "spell_scroll_druid_rootstrike", "prob": 100 }, + { "item": "spell_scroll_purification_seed", "prob": 100 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "recovery_spellbook", "prob": 10 }, + { "item": "spell_scroll_recover_fatigue", "prob": 100 }, + { "item": "spell_scroll_druidic_regrowth", "prob": 100 }, + { "item": "spell_scroll_druidic_healing", "prob": 100 } + ], + "prob": 10 + } ] + }, + { + "id": "technomancer_items", + "//": "A distribution of magical items for technomancer themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "priest_beginner", "prob": 20 }, + { "item": "techno_idiots", "prob": 20 }, + { "item": "spell_scroll_x-ray", "prob": 50 }, + { "item": "spell_scroll_bless", "prob": 50 }, + { "item": "spell_scroll_create_atomic_lamp", "prob": 50 }, + { "item": "spell_scroll_taze", "prob": 50 }, + { "item": "spell_scroll_laze", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "priest_advanced", "prob": 20 }, + { "item": "techno_fundamentals", "prob": 20 }, + { "item": "spell_scroll_quantum_tunnel_lesser", "prob": 50 }, + { "item": "spell_scroll_holy_blade", "prob": 50 }, + { "item": "spell_scroll_spirit_armor", "prob": 50 }, + { "item": "spell_scroll_synaptic_stimulation", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "techno_em", "prob": 5 }, + { "item": "spell_scroll_holographic_transposition", "prob": 10 }, + { "item": "spell_scroll_recover_bionic_power", "prob": 50 }, + { "item": "spell_scroll_animated_blade", "prob": 50 }, + { "item": "spell_scroll_mirror_image", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "item": "recovery_spellbook", "prob": 10 }, { "item": "spell_scroll_invisibility", "prob": 50 } ], + "prob": 5 + }, + { "group": "magic_CBM", "prob": 2 } + ] + }, + { + "id": "classless_items", + "//": "A distribution of magical items for classless themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { "group": "enchanted_tokens_tool", "prob": 15 }, + { "group": "enchanted_tokens_weapon", "prob": 5 }, + { "group": "potions_common", "prob": 35 }, + { + "distribution": [ + { "group": "enchanted_wands_lesser", "prob": 15 }, + { "group": "enchanted_combat_items", "prob": 5 }, + { "group": "enchanted_worn_items", "prob": 2 } + ], + "prob": 15 + }, + { + "distribution": [ + { "item": "priest_beginner", "prob": 20 }, + { "item": "wizard_beginner", "prob": 20 }, + { "item": "spell_scroll_create_atomic_light", "prob": 50 }, + { "item": "spell_scroll_ethereal_grasp", "prob": 50 }, + { "item": "spell_scroll_crystallize_mana", "prob": 50 }, + { "item": "spell_scroll_blinding_flash", "prob": 50 } + ], + "prob": 50 + }, + { + "distribution": [ + { "item": "wizard_utility", "prob": 10 }, + { "item": "spell_scroll_protection_aura", "prob": 50 }, + { "item": "spell_scroll_dark_sight", "prob": 30 }, + { "item": "spell_scroll_megablast", "prob": 30 } + ], + "prob": 40 + }, + { + "distribution": [ + { "item": "light_manipulation_spellbook", "prob": 5 }, + { "item": "translocate_spellbook", "prob": 2 }, + { "item": "spell_scroll_obfuscated_body", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "group": "enchanted_rings_common", "prob": 30 }, { "group": "enchanted_rings_uncommon", "prob": 10 } ], + "prob": 40 + }, + [ "crystallized_mana", 50 ], + [ "copper_circlet", 10 ], + { "item": "small_mana_crystal", "prob": 40, "charges-min": 5, "charges-max": 50 } + ] + }, + { + "type": "item_group", + "id": "academy_lore", + "items": [ [ "retreat_map", 100 ] ] + }, + { + "type": "item_group", + "id": "magic_basement_photo", + "items": [ [ "wizard_photo", 100 ] ] } ] diff --git a/data/mods/Magiclysm/items/books_lore.json b/data/mods/Magiclysm/items/books_lore.json new file mode 100644 index 0000000000000..858ce1fd3fdf6 --- /dev/null +++ b/data/mods/Magiclysm/items/books_lore.json @@ -0,0 +1,50 @@ +[ + { + "id": "retreat_map", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": "vacation brochure", + "description": "This is a glossy brochure encouraging students to book vactaions at a lake retreat or remote cabin. The brochure includes lush photographs of a tower on an island and a remote looking cabin in the woods. It includes a map of the areas.", + "color": "white", + "use_action": { + "type": "reveal_map", + "radius": 185, + "terrain": [ "lake_retreat_ground", "magic_cabin" ], + "message": "You add the locations to your map." + } + }, + { + "id": "lair_map", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": "lair map", + "description": "This is an well worn map. It has pictures of fantastical beasts embellishing the carefully drawn map markers.", + "color": "white", + "use_action": { + "type": "reveal_map", + "radius": 185, + "terrain": [ + "demon_spider_lair", + "black_dragon_lair_z-0_NW", + "black_dragon_lair_z-0_NE", + "black_dragon_lair_z-0_SW", + "black_dragon_lair_z-0_SE" + ], + "message": "You add the locations to your map." + } + }, + { + "id": "wizard_photo", + "type": "GENERIC", + "//": "Unique item for magic_basement.", + "category": "other", + "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, + "price": 800, + "material": [ "paper" ], + "symbol": "*", + "color": "light_gray" + } +] diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index b64a3b51f6cba..adacd77bf014b 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -14,6 +14,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_crystallize_mana", + "//": "Classless spell", "name": { "str": "Scroll of Crystallize Mana", "str_pl": "Scrolls of Crystallize Mana" }, "description": "A proper wizard is always prepared, crystallize your mana for the future!", "use_action": { "type": "learn_spell", "spells": [ "crystallize_mana" ] } @@ -22,6 +23,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_dark_sight", + "//": "Classless spell", "name": { "str": "Scroll of Dark Sight", "str_pl": "Scrolls of Dark Sight" }, "description": "The darkness holds no secrets for the arcane. Adjust your sight to see in perfect darkness!", "use_action": { "type": "learn_spell", "spells": [ "dark_sight" ] } @@ -30,6 +32,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_invisibility", + "//": "Technomancer spell", "name": { "str": "Scroll of Invisibility", "str_pl": "Scrolls of Invisibility" }, "description": "The light can not interact with you unless you want it to. Become invisible!", "use_action": { "type": "learn_spell", "spells": [ "invisibility" ] } @@ -38,6 +41,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_obfuscated_body", + "//": "Classless spell", "name": { "str": "Scroll of Obfuscated Body", "str_pl": "Scrolls of Obfuscated Body" }, "description": "A magical aura distorts light around your body, making it easier to dodge enemy attacks.", "use_action": { "type": "learn_spell", "spells": [ "obfuscated_body" ] } @@ -46,6 +50,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_holographic_transposition", + "//": "Technomancer spell", "name": { "str": "Scroll of Holographic Transposition", "str_pl": "Scrolls of Holographic Transposition" }, "description": "Allows you to swap places with a previously existing holographic image of yourself. If the universe itself can't tell you apart, who could?", "use_action": { "type": "learn_spell", "spells": [ "holographic_transposition" ] } @@ -54,6 +59,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_smite", + "//": "Animist spell", "name": { "str": "Scroll of Smite", "str_pl": "Scrolls of Smite" }, "description": "Evil has become pervasive throughout the world. Let your power be the light that shines in the darkness!", "use_action": { "type": "learn_spell", "spells": [ "smite" ] } @@ -62,6 +68,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_mana", + "//": "Animist spell", "name": { "str": "Scroll of Life Conversion", "str_pl": "Scrolls of Life Conversion" }, "description": "You channel your life force itself into your spiritual energy. You spend hp to regain mana.", "use_action": { "type": "learn_spell", "spells": [ "recover_mana" ] } @@ -70,6 +77,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_pain", + "//": "Animist spell", "name": { "str": "Scroll of Mind Over Pain", "str_pl": "Scrolls of Mind Over Pain" }, "description": "With an intense ritual that resembles crossfit, you manage to put some of your pain at bay.", "use_action": { "type": "learn_spell", "spells": [ "recover_pain" ] } @@ -78,6 +86,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_zombie", + "//": "Animist spell", "name": { "str": "Scroll of Summon Zombie", "str_pl": "Scrolls of Summon Zombie" }, "description": "An ethereal-looking zombie rises from the depths of the earth to fight for you. You may be able to summon more with a higher level in this spell.", "use_action": { "type": "learn_spell", "spells": [ "summon_zombie" ] } @@ -86,6 +95,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_skeleton", + "//": "Animist spell", "name": { "str": "Scroll of Summon Skeleton", "str_pl": "Scrolls of Summon Skeleton" }, "description": "A ghostly skeleton rises from the depths of the earth to fight for you. You may be able to summon more with a higher level in this spell.", "use_action": { "type": "learn_spell", "spells": [ "summon_skeleton" ] } @@ -94,6 +104,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_decayed_pouncer", + "//": "Animist spell", "name": { "str": "Scroll of Summon Decayed Pouncer", "str_pl": "Scrolls of Summon Decayed Pouncer" }, "description": "A decrepit looking large cat rises from the depths of the earth to fight for you. You may be able to summon more with a higher level in this spell.", "use_action": { "type": "learn_spell", "spells": [ "summon_decayed_pouncer" ] } @@ -102,6 +113,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_light_healing", + "//": "Biomancer spell", "name": { "str": "Scroll of Cure Light Wounds", "str_pl": "Scrolls of Cure Light Wounds" }, "description": "Heals a little bit of damage on the target.", "use_action": { "type": "learn_spell", "spells": [ "light_healing" ] } @@ -110,6 +122,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_pain_split", + "//": "Biomancer spell", "name": { "str": "Scroll of Pain Split", "str_pl": "Scrolls of Pain Split" }, "description": "Evens out damage among your limbs.", "use_action": { "type": "learn_spell", "spells": [ "pain_split" ] } @@ -118,6 +131,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_vicious_tentacle", + "//": "Biomancer spell", "name": { "str": "Scroll of Vicious Tentacle", "str_pl": "Scrolls of Vicious Tentacle" }, "description": "This spell extrudes a long nasty whiplike tentacle of sharp bones and oozing acid from your body, it has a long reach attack and vicious damage.", "use_action": { "type": "learn_spell", "spells": [ "vicious_tentacle" ] } @@ -126,6 +140,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_grotesque", + "//": "Biomancer spell", "name": { "str": "Scroll of Grotesque Enhancement", "str_pl": "Scrolls of Grotesque Enhancement" }, "description": "A spell that warps your body in alien ways to increase your physical abilities and strength.", "use_action": { "type": "learn_spell", "spells": [ "bio_grotesque" ] } @@ -134,6 +149,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_acidicspray", + "//": "Biomancer spell", "name": { "str": "Scroll of Acidic Spray", "str_pl": "Scrolls of Acidic Spray" }, "description": "When cast, the mage opens his mouth and sprays acid in a wide cone to dissolve his foes into goo. Just imagine what he'll do with the goo.", "use_action": { "type": "learn_spell", "spells": [ "bio_acidicspray" ] } @@ -142,6 +158,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_fleshpouch", + "//": "Biomancer spell", "name": { "str": "Scroll of Flesh Pouch", "str_pl": "Scrolls of Flesh Pouch" }, "description": "This spell grows a large pouch out of your skin on your back, allowing you to store your gear in it.", "use_action": { "type": "learn_spell", "spells": [ "bio_fleshpouch" ] } @@ -150,6 +167,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_bonespear", + "//": "Biomancer spell", "name": { "str": "Scroll of Conjure Bonespear", "str_pl": "Scrolls of Conjure Bonespear" }, "description": "This spell creates a long shaft of bone with a wicked point and blades along its length.", "use_action": { "type": "learn_spell", "spells": [ "bio_bonespear" ] } @@ -158,6 +176,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_megablast", + "//": "Classless spell", "name": { "str": "Scroll of Megablast", "str_pl": "Scrolls of Megablast" }, "description": "You always wanted to fire energy beams like in the animes you watched as a kid. Now you can!", "use_action": { "type": "learn_spell", "spells": [ "megablast" ] } @@ -166,6 +185,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_create_atomic_light", + "//": "Classless spell1", "name": { "str": "Scroll of Magical Light", "str_pl": "Scrolls of Magical Light" }, "description": "Creates a magical light.", "use_action": { "type": "learn_spell", "spells": [ "create_atomic_light" ] } @@ -174,6 +194,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_blinding_flash", + "//": "Classless spell", "name": { "str": "Scroll of Blinding Flash", "str_pl": "Scrolls of Blinding Flash" }, "description": "Blind enemies for a short time with a sudden, dazzling light. Higher levels deal slightly higher damage.", "use_action": { "type": "learn_spell", "spells": [ "blinding_flash" ] } @@ -182,6 +203,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ethereal_grasp", + "//": "Classless spell", "name": { "str": "Scroll of Ethereal Grasp", "str_pl": "Scrolls of Ethereal Grasp" }, "description": "A mass of spectral hands emerge from the ground, slowing everything in range. Higher levels allow a bigger AoE, and longer effect.", "use_action": { "type": "learn_spell", "spells": [ "ethereal_grasp" ] } @@ -190,6 +212,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_protection_aura", + "//": "Classless spell", "name": { "str": "Scroll of Aura of Protection", "str_pl": "Scrolls of Aura of Protection" }, "description": "Encases your whole body in a magical aura that protects you from the environment.", "use_action": { "type": "learn_spell", "spells": [ "protection_aura" ] } @@ -198,6 +221,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_veggrasp", + "//": "Druid spell", "name": { "str": "Scroll of Vegetative Grasp", "str_pl": "Scrolls of Vegetative Grasp" }, "description": "This spell causes roots and vines to burst forth from the ground and grab your foes, slowing them and doing a small amount of damage as they dig in.", "use_action": { "type": "learn_spell", "spells": [ "druid_veggrasp" ] } @@ -206,6 +230,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_rootstrike", + "//": "Druid spell", "name": { "str": "Scroll of Root Strike", "str_pl": "Scrolls of Root Strike" }, "description": "This spell causes roots to spear out the ground and stab into your foes in an arc, impaling them.", "use_action": { "type": "learn_spell", "spells": [ "druid_rootstrike" ] } @@ -214,6 +239,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_woodshaft", + "//": "Druid spell", "name": { "str": "Scroll of Wooden Shaft", "str_pl": "Scrolls of Wooden Shaft" }, "description": "This spell creates a projectile of hardwood that shoots forth from the caster's hand at high speed to stab into an enemy.", "use_action": { "type": "learn_spell", "spells": [ "druid_woodshaft" ] } @@ -222,6 +248,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_naturebow1", + "//": "Druid spell", "name": { "str": "Scroll of Nature's Bow", "str_pl": "Scrolls of Nature's Bow" }, "description": "This spell conjures a magical wooden recurve bow that fires endless arrows for as long as it lasts.", "use_action": { "type": "learn_spell", "spells": [ "druid_naturebow1" ] } @@ -230,6 +257,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_fatigue", + "//": "Druid spell", "name": { "str": "Scroll of Nature's Trance", "str_pl": "Scrolls of Nature's Trance" }, "description": "Your connection to living things allows you to go into a magical trance. This allows you to recover fatige quickly in exchange for mana.", "use_action": { "type": "learn_spell", "spells": [ "recover_fatigue" ] } @@ -238,6 +266,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_cats", + "//": "Druid spell", "name": { "str": "Scroll of Bag of Cats", "str_pl": "Scrolls of Bag of Cats" }, "description": "Are you the crazy cat lady?", "use_action": { "type": "learn_spell", "spells": [ "summon_cats" ] } @@ -246,6 +275,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_stonefist", + "//": "Earthshaper spell", "name": { "str": "Scroll of Stonefist", "str_pl": "Scrolls of Stonefist" }, "description": "Encases your arms and hands in a sheath of magical stone, you can punch and defend yourself with it in melee combat.", "use_action": { "type": "learn_spell", "spells": [ "stonefist" ] } @@ -254,6 +284,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_seismic_stomp", + "//": "Earthshaper spell", "name": { "str": "Scroll of Seismic Stomp", "str_pl": "Scrolls of Seismic Stomp" }, "description": "Focusing mana into your leg, you stomp your foot and send out a shockwave, knocking enemies around you onto the ground.", "use_action": { "type": "learn_spell", "spells": [ "seismic_stomp" ] } @@ -262,6 +293,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_stamina", + "//": "Earthshaper spell", "name": { "str": "Scroll of Stone's Endurance", "str_pl": "Scrolls of Stone's Endurance" }, "description": "You focus on the stones beneath you and draw from their agelessness. Your mana is converted to stamina.", "use_action": { "type": "learn_spell", "spells": [ "recover_stamina" ] } @@ -270,6 +302,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_shardspray", + "//": "Earthshaper spell", "name": { "str": "Scroll of Shardspray", "str_pl": "Scrolls of Shardspray" }, "description": "This spell projects a wide spray of sharp metal shards, cutting into your foes and friends alike.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_shardspray" ] } @@ -278,6 +311,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_piercing_bolt", + "//": "Earthshaper spell", "name": { "str": "Scroll of Piercing Bolt", "str_pl": "Scrolls of Piercing Bolt" }, "description": "This spell projects a piercing rod of conjured iron at those that dare oppose you.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_piercing_bolt" ] } @@ -286,6 +320,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_shardstorm", + "//": "Earthshaper spell", "name": { "str": "Scroll of Shardstorm", "str_pl": "Scrolls of Shardstorm" }, "description": "Creates an omnidirectional spray of razor sharp metal shards all around you.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_shardstorm" ] } @@ -294,6 +329,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_rockbolt", + "//": "Earthshaper spell", "name": { "str": "Scroll of Rockbolt", "str_pl": "Scrolls of Rockbolt" }, "description": "Fires a conjured stone projectile at high velocity.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_rockbolt" ] } @@ -302,6 +338,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_point_flare", + "//": "Kelvinist spell", "name": { "str": "Scroll of Point Flare", "str_pl": "Scrolls of Point Flare" }, "description": "Causes an intense heat at the location, damaging the target.", "use_action": { "type": "learn_spell", "spells": [ "point_flare" ] } @@ -310,6 +347,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_create_lighter", + "//": "Kelvinist spell", "name": { "str": "Scroll of Finger Firelighter", "str_pl": "Scrolls of Finger Firelighter" }, "description": "Summons a small flame that does not burn you, but you can use it to light things on fire. It seems to need you to have some intent to light things on fire, because you are able to put it in your pocket with no issue.", "use_action": { "type": "learn_spell", "spells": [ "create_lighter" ] } @@ -318,6 +356,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ice_spike", + "//": "Kelvinist spell", "name": { "str": "Scroll of Ice Spike", "str_pl": "Scrolls of Ice Spike" }, "description": "Causes jagged icicles to form in the air above the target, falling and damaging it.", "use_action": { "type": "learn_spell", "spells": [ "ice_spike" ] } @@ -326,6 +365,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_fireball", + "//": "Kelvinist spell", "name": { "str": "Scroll of Fireball", "str_pl": "Scrolls of Fireball" }, "description": "You hurl a pea-sized glowing orb that when reaches its target or an obstacle produces a pressure-less blast of searing heat.", "use_action": { "type": "learn_spell", "spells": [ "fireball" ] } @@ -334,6 +374,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_cone_cold", + "//": "Kelvinist spell", "name": { "str": "Scroll of Cone of Cold", "str_pl": "Scrolls of Cone of Cold" }, "description": "You blast a cone of frigid air toward the target.", "use_action": { "type": "learn_spell", "spells": [ "cone_cold" ] } @@ -342,6 +383,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_burning_hands", + "//": "Kelvinist spell", "name": { "str": "Scroll of Burning Hands", "str_pl": "Scrolls of Burning Hands" }, "description": "You're pretty sure you saw this in a game somewhere. You fire a short-range cone of fire.", "use_action": { "type": "learn_spell", "spells": [ "burning_hands" ] } @@ -350,6 +392,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_frost_spray", + "//": "Kelvinist spell", "name": { "str": "Scroll of Frost Spray", "str_pl": "Scrolls of Frost Spray" }, "description": "You're pretty sure you saw this in a game somewhere. You fire a short-range cone of ice and cold.", "use_action": { "type": "learn_spell", "spells": [ "frost_spray" ] } @@ -358,6 +401,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_chilling_touch", + "//": "Kelvinist spell", "name": { "str": "Scroll of Chilling Touch", "str_pl": "Scrolls of Chilling Touch" }, "description": "Freezes the touched target with intense cold.", "use_action": { "type": "learn_spell", "spells": [ "chilling_touch" ] } @@ -366,6 +410,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_glide_ice", + "//": "Kelvinist spell", "name": { "str": "Scroll of Glide on Ice", "str_pl": "Scrolls of Glide on Ice" }, "description": "Encases your feet in a magical coating of ice, allowing you to glide along smooth surfaces faster.", "use_action": { "type": "learn_spell", "spells": [ "glide_ice" ] } @@ -374,6 +419,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_hoary_blast", + "//": "Kelvinist spell", "name": { "str": "Scroll of Hoary Blast", "str_pl": "Scrolls of Hoary Blast" }, "description": "You project a glowing white crystal of ice and it explodes on impact into a blossom of shattering cold.", "use_action": { "type": "learn_spell", "spells": [ "hoary_blast" ] } @@ -382,6 +428,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ice_shield", + "//": "Kelvinist spell", "name": { "str": "Scroll of Ice Shield", "str_pl": "Scrolls of Ice Shield" }, "description": "Creates a magical shield of ice on your arm, you can defend yourself with it in melee combat and use it to bash.", "use_action": { "type": "learn_spell", "spells": [ "ice_shield" ] } @@ -390,6 +437,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_frost_armor", + "//": "Kelvinist spell", "name": { "str": "Scroll of Frost Armor", "str_pl": "Scrolls of Frost Armor" }, "description": "Covers you in a thin layer of magical ice to protect you from harm.", "use_action": { "type": "learn_spell", "spells": [ "frost_armor" ] } @@ -398,6 +446,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magic_missile", + "//": "Magus spell", "name": { "str": "Scroll of Magic Missile", "str_pl": "Scrolls of Magic Missile" }, "description": "I cast Magic Missile at the darkness!", "use_action": { "type": "learn_spell", "spells": [ "magic_missile" ] } @@ -406,6 +455,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_phase_door", + "//": "Magus spell", "name": { "str": "Scroll of Phase Door", "str_pl": "Scrolls of Phase Door" }, "description": "Teleports you in a random direction a short distance.", "use_action": { "type": "learn_spell", "spells": [ "phase_door" ] } @@ -414,6 +464,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_gravity_well", + "//": "Magus spell", "name": { "str": "Scroll of Gravity Well", "str_pl": "Scrolls of Gravity Well" }, "description": "Summons a well of gravity with the epicenter at the location. Deals bashing damage to all creatures in the affected area.", "use_action": { "type": "learn_spell", "spells": [ "gravity_well" ] } @@ -422,6 +473,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_mana_blast", + "//": "Magus spell", "name": { "str": "Scroll of Mana Blast", "str_pl": "Scrolls of Mana Blast" }, "description": "A blast of concentrated magical power that obliterates a large area.", "use_action": { "type": "learn_spell", "spells": [ "magus_mana_blast" ] } @@ -430,6 +482,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_mana_bolt", + "//": "Magus spell", "name": { "str": "Scroll of Mana Bolt", "str_pl": "Scrolls of Mana Bolt" }, "description": "A bolt of magical power that only damages your foes.", "use_action": { "type": "learn_spell", "spells": [ "magus_mana_bolt" ] } @@ -438,6 +491,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_haste", + "//": "Magus spell", "name": { "str": "Scroll of Haste", "str_pl": "Scrolls of Haste" }, "description": "This spell gives you an enormous boost of speed lasting a short period of time.", "use_action": { "type": "learn_spell", "spells": [ "magus_haste" ] } @@ -446,6 +500,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_mana_beam", + "//": "Magus spell", "name": { "str": "Scroll of Mana Beam", "str_pl": "Scrolls of Mana Beam" }, "description": "A beam of focused magical power that damages any foes in its path.", "use_action": { "type": "learn_spell", "spells": [ "magus_mana_beam" ] } @@ -454,6 +509,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_escape", + "//": "Magus spell", "name": { "str": "Scroll of Escape", "str_pl": "Scrolls of Escape" }, "description": "Teleports you in a random direction a medium distance, to help escape your foes in dangerous situations.", "use_action": { "type": "learn_spell", "spells": [ "magus_escape" ] } @@ -462,6 +518,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_cats_grace", + "//": "Magus spell", "name": { "str": "Scroll of Cat's Grace", "str_pl": "Scrolls of Cat's Grace" }, "description": "You become more graceful, agile, and coordinated.", "use_action": { "type": "learn_spell", "spells": [ "cats_grace" ] } @@ -470,6 +527,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eagles_sight", + "//": "Magus spell", "name": { "str": "Scroll of Eagle's Sight", "str_pl": "Scrolls of Eagle's Sight" }, "description": "You gain the perception of an eagle.", "use_action": { "type": "learn_spell", "spells": [ "eagles_sight" ] } @@ -478,6 +536,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ogres_strength", + "//": "Magus spell", "name": { "str": "Scroll of Ogre's Strength", "str_pl": "Scrolls of Ogre's Strength" }, "description": "You gain the strength of an ogre.", "use_action": { "type": "learn_spell", "spells": [ "ogres_strength" ] } @@ -486,6 +545,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_foxs_cunning", + "//": "Magus spell", "name": { "str": "Scroll of Fox's Cunning", "str_pl": "Scrolls of Fox's Cunning" }, "description": "You become wily like a fox.", "use_action": { "type": "learn_spell", "spells": [ "foxs_cunning" ] } @@ -494,6 +554,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_jolt", + "//": "Stormshaper spell", "name": { "str": "Scroll of Jolt", "str_pl": "Scrolls of Jolt" }, "description": "A short-ranged fan of electricity shoots from your fingers.", "use_action": { "type": "learn_spell", "spells": [ "jolt" ] } @@ -502,6 +563,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_lightning_bolt", + "//": "Stormshaper spell", "name": { "str": "Scroll of Lightning Bolt", "str_pl": "Scrolls of Lightning Bolt" }, "description": "The goto spell for many Stormshapers, this iconic spell does just what you expect: you shoot lightning from your fingertips. However, this lightning is more directed than most lightning, and travels in a line through most non-solid targets.", "use_action": { "type": "learn_spell", "spells": [ "lightning_bolt" ] } @@ -510,6 +572,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_windstrike", + "//": "Stormshaper spell", "name": { "str": "Scroll of Windstrike", "str_pl": "Scrolls of Windstrike" }, "description": "A powerful blast of wind slams into anything in front of your outstretched hand.", "use_action": { "type": "learn_spell", "spells": [ "windstrike" ] } @@ -518,6 +581,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_windrun", + "//": "Stormshaper spell", "name": { "str": "Scroll of Windrunning", "str_pl": "Scrolls of Windrunning" }, "description": "A magical wind pushes you forward as you move, easing your movements and increasing speed.", "use_action": { "type": "learn_spell", "spells": [ "windrun" ] } @@ -526,6 +590,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_storm_hammer", + "//": "Stormshaper spell", "name": { "str": "Scroll of Call Stormhammer", "str_pl": "Scrolls of Call Stormhammer" }, "description": "Creates a crackling magical warhammer full of lightning to smite your foes with, and of course, smash things to bits!", "use_action": { "type": "learn_spell", "spells": [ "storm_hammer" ] } @@ -534,6 +599,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bless", + "//": "Technomancer spell", "name": { "str": "Scroll of Bless", "str_pl": "Scrolls of Bless" }, "description": "A spell of blessing that gives you energy and boosts your abilities.", "use_action": { "type": "learn_spell", "spells": [ "bless" ] } @@ -542,6 +608,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_holy_blade", + "//": "Technomancer spell", "name": { "str": "Scroll of Holy Blade", "str_pl": "Scrolls of Holy Blade" }, "description": "This blade of light will cut through any evil it makes contact with!", "use_action": { "type": "learn_spell", "spells": [ "holy_blade" ] } @@ -550,6 +617,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_spirit_armor", + "//": "Technomancer spell", "name": { "str": "Scroll of Spiritual Armor", "str_pl": "Scrolls of Spiritual Armor" }, "description": "Evil will not make it through your defenses if your faith is strong enough!", "use_action": { "type": "learn_spell", "spells": [ "spirit_armor" ] } @@ -558,6 +626,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_create_atomic_lamp", + "//": "Technomancer spell", "name": { "str": "Scroll of Lamp", "str_pl": "Scrolls of Lamp" }, "description": "Creates a magical lamp.", "use_action": { "type": "learn_spell", "spells": [ "create_atomic_lamp" ] } @@ -566,6 +635,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_bionic_power", + "//": "Technomancer spell", "name": { "str": "Scroll of Manatricity", "str_pl": "Scrolls of Manatricity" }, "description": "You have found a way to convert your spiritual energy into power you can use for your bionics.", "use_action": { "type": "learn_spell", "spells": [ "recover_bionic_power" ] } @@ -574,6 +644,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_taze", + "//": "Technomancer spell", "name": { "str": "Scroll of Taze", "str_pl": "Scrolls of Taze" }, "description": "This spell creates a very short range bolt of electricity to shock your foes.", "use_action": { "type": "learn_spell", "spells": [ "taze" ] } @@ -582,6 +653,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_quantum_tunnel_lesser", + "//": "Technomancer spell", "name": { "str": "Scroll of Lesser Quantum Tunnel", "str_pl": "Scrolls of Lesser Quantum Tunnel" }, "description": "This spell manipulates some quantum something or other to tunnel you through a short distance of space, and even matter, unfortunately there's that whole uncertainty thing as to where you come out. It leaves you a little dazed on the other side as you reorient yourself.", "use_action": { "type": "learn_spell", "spells": [ "quantum_tunnel_lesser" ] } @@ -590,6 +662,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_synaptic_stimulation", + "//": "Technomancer spell", "name": { "str": "Scroll of Synaptic Stimulation", "str_pl": "Scrolls of Synaptic Stimulation" }, "description": "This spell stimulates the synapses in your brain beyond normal processing speeds, giving you a large boost in mental processing capability, including enhancing your reflexes, speed, and raw intellectual power. Use responsibly!", "use_action": { "type": "learn_spell", "spells": [ "synaptic_stimulation" ] } @@ -598,6 +671,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_laze", + "//": "Technomancer spell", "name": { "str": "Scroll of Laze", "str_pl": "Scrolls of Laze" }, "description": "You concentrate and release a focused beam of photons at a target, also known as a laser.", "use_action": { "type": "learn_spell", "spells": [ "laze" ] } @@ -606,6 +680,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_animated_blade", + "//": "Technomancer spell", "name": { "str": "Scroll of Animated Blade", "str_pl": "Scrolls of Animated Blade" }, "description": "This spell conjures flying animated blades that will cut your enemies down to size. Into small pieces that is.", "use_action": { "type": "learn_spell", "spells": [ "animated_blade" ] } @@ -614,6 +689,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_mirror_image", + "//": "Technomancer spell", "name": { "str": "Scroll of Mirror Image", "str_pl": "Scrolls of Mirror Image" }, "description": "This spell manipulates light into barely tangible duplicates of a living being, a magical hologram in short.", "use_action": { "type": "learn_spell", "spells": [ "mirror_image" ] } @@ -622,6 +698,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_lightning_blast", + "//": "Stormshaper spell", "name": { "str": "Scroll of Lightning Blast", "str_pl": "Scrolls of Lightning Blast" }, "description": "You fire a small concentrated ball of lightning at the target. The electricity diffuses quickly, so it doesn't do much damage, but you're able to fire off several quick ones in a row.", "use_action": { "type": "learn_spell", "spells": [ "lightning_blast" ] } @@ -630,6 +707,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_necrotic_gaze", + "//": "Animist spell", "name": { "str": "Scroll of Necrotic Gaze", "str_pl": "Scrolls of Necrotic Gaze" }, "description": "You use the power of your own blood to imbue necrotic energy into your gaze, damaging the target you look at.", "use_action": { "type": "learn_spell", "spells": [ "necrotic_gaze" ] } @@ -638,6 +716,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_purification_seed", + "//": "Druid spell", "name": { "str": "Scroll of Purification Seed", "str_pl": "Scrolls of Purification Seed" }, "description": "You summon a gift of the earth which will purify water. Greater levels yield greater numbers of seeds.", "use_action": { "type": "learn_spell", "spells": [ "purify_seed" ] } @@ -646,6 +725,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_x-ray", + "//": "Technomancer spell", "name": { "str": "Scroll of X-ray Vision", "str_pl": "Scrolls of X-ray Vision" }, "description": "You fire a cone of X-rays that magically allow you to see that area for a short time.", "use_action": { "type": "learn_spell", "spells": [ "x-ray" ] } @@ -654,6 +734,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_clairvoyance", + "//": "Earthshaper spell", "name": { "str": "Scroll of Clairvoyance", "str_pl": "Scrolls of Clairvoyance" }, "description": "You close your eyes and the earth surrenders its secrets to you.", "use_action": { "type": "learn_spell", "spells": [ "clairvoyance" ] } @@ -662,6 +743,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_lava_bomb", + "//": "Earthshaper spell", "name": { "str": "Scroll of Lava Bomb", "str_pl": "Scrolls of Lava Bomb" }, "description": "You tear up the ground beneath you to fire a lava bomb: a globe of lava surrounded by hot, solid rock. It shatters upon impact, spraying shards of rock and lava everywhere.", "use_action": { "type": "learn_spell", "spells": [ "lava_bomb_main" ] } @@ -670,6 +752,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_acid_resistance", + "//": "Classless spell, black dragon books", "name": { "str": "Scroll of Acid Resistance", "str_pl": "Scrolls of Acid Resistance" }, "description": "This spell creates an invisible aura to protect you from acid.", "use_action": { "type": "learn_spell", "spells": [ "acid_resistance" ] } @@ -678,6 +761,7 @@ "id": "lightning_storm_scroll", "type": "GENERIC", "name": { "str": "Scroll of Lightning Storm", "str_pl": "Scrolls of Lightning Storm" }, + "//": "Stormshaper spell", "description": "This scroll details how a spell called 'Lightning Blast' which is commonly used among Stormshapers can be altered to become much more powerful, at a much higher mana cost.", "weight": "129 g", "volume": "500 ml", @@ -690,6 +774,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druidic_regrowth", + "//": "Druid spell", "name": { "str": "Scroll of Sacrificial Regrowth", "str_pl": "Scrolls of Sacrificial Regrowth" }, "description": "Through giving of one's own life force, you restore withered and barren plant life nearby. What remains will need time to regrow its full strength.", "use_action": { "type": "learn_spell", "spells": [ "druidic_regrowth" ] } @@ -698,6 +783,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druidic_healing", + "//": "Druid spell", "name": { "str": "Scroll of Sacrificial Healing", "str_pl": "Scrolls of Sacrificial Healing" }, "description": "Channels some of the user's own life force into healing energy, for the sake of ones allies.", "use_action": { "type": "learn_spell", "spells": [ "druidic_healing" ] } @@ -706,6 +792,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_earthshaper_stoneskin", + "//": "Earthshaper spell", "name": { "str": "Scroll of Stoneskin", "str_pl": "Scrolls of Stoneskin" }, "description": "Envelops your entire body in armor formed from living rock, encumbering yet protective.", "use_action": { "type": "learn_spell", "spells": [ "earthshaper_stoneskin" ] } @@ -714,6 +801,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_earthshaper_pillar", + "//": "Earthshaper spell", "name": { "str": "Scroll of Pillar of Stone", "str_pl": "Scrolls of Pillar of Stone" }, "description": "Drawing upon the surrounding earth, you form a pillar of solid rock. Experience will make the task easier, and less disruptive to the surrounding area.", "use_action": { "type": "learn_spell", "spells": [ "earthshaper_pillar" ] } @@ -722,6 +810,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_biomancer_paralytic_dart", + "//": "Biomancer spell", "name": { "str": "Scroll of Paralytic Dart", "str_pl": "Scrolls of Paralytic Dart" }, "description": "Spits a warped needle of sinew and bone, carrying with it a sting that slows your victim.", "use_action": { "type": "learn_spell", "spells": [ "biomancer_paralytic_dart" ] } @@ -730,6 +819,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_biomancer_visceral_projection", + "//": "Biomancer spell", "name": { "str": "Scroll of Visceral Projection", "str_pl": "Scrolls of Visceral Projection" }, "description": "Projects a spray of acrid blood and gore all around you, growing to ensnare your prey in in a field of twitching poisonous tendrils.", "use_action": { "type": "learn_spell", "spells": [ "biomancer_visceral_projection" ] } @@ -738,6 +828,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_biomancer_coagulant_weave", + "//": "Biomancer spell", "name": { "str": "Scroll of Coagulant Weave", "str_pl": "Scrolls of Coagulant Weave" }, "description": "Turns your biological mastery inwards, medically enhancing your flesh. Rather than strength of healing, it staves off blood loss and purges wounds before they can turn septic, at the cost of increased hunger and thirst.", "use_action": { "type": "learn_spell", "spells": [ "biomancer_coagulant_weave" ] } @@ -746,6 +837,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_stormshaper_ionization", + "//": "Stormshaper spell", "name": { "str": "Scroll of Ionization", "str_pl": "Scrolls of Ionization" }, "description": "By manipulating the charge in the air, you can conjure a sharp snap of lightning over a wide area. While its destructive potential is a far cry from natural lightning, the light and thunderclap produced will leave your foes reeling.", "use_action": { "type": "learn_spell", "spells": [ "stormshaper_ionization" ] } @@ -754,6 +846,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_wisps", + "//": "Animist spell", "name": { "str": "Scroll of Ignus Fatuus", "str_pl": "Scrolls of Ignus Fatuus" }, "description": "Summons ghostly foxfire worked from living marsh vapor, to lead your enemies astray. With more experience, this spell can conjure multiple ghost lights.", "use_action": { "type": "learn_spell", "spells": [ "summon_wisps" ] } @@ -762,6 +855,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_stormshaper_wall_of_fog", + "//": "Stormshaper spell", "name": { "str": "Scroll of Wall of Fog", "str_pl": "Scrolls of Wall of Fog" }, "description": "Draws forth a broad wall of thick fog. While the sudden force of air pressure will floor any enemies caught in it, the conjuration is otherwise harmless.", "use_action": { "type": "learn_spell", "spells": [ "stormshaper_wall_of_fog" ] } diff --git a/data/mods/Magiclysm/items/spellbooks.json b/data/mods/Magiclysm/items/spellbooks.json index 7220c7c489f0d..dec578b1fb5a7 100644 --- a/data/mods/Magiclysm/items/spellbooks.json +++ b/data/mods/Magiclysm/items/spellbooks.json @@ -30,6 +30,7 @@ "id": "wizard_beginner", "type": "GENERIC", "name": { "str": "A Beginner's Guide to Magic", "str_pl": "copies of A Beginner's Guide to Magic" }, + "//": "2 Magus, 1 classless spell", "description": "You would describe this as more like a pamphlet than a spellbook, but it seems to have at least one interesting spell you can use.", "weight": "585 g", "volume": "250 ml", @@ -42,6 +43,7 @@ "id": "wizard_utility", "type": "GENERIC", "name": { "str": "Wizarding Guide to Backpacking", "str_pl": "copies of Wizarding Guide to Backpacking" }, + "//": "1 Magus, 1 Biomancer, 1, Kelvinist, 1 classless spell", "description": "This appears to be the spell version of a guide for what things to take with you when backpacking. It's a little bulky, but will certainly prove useful.", "weight": "1 kg", "volume": "1250 ml", @@ -54,6 +56,7 @@ "id": "pyro", "type": "GENERIC", "name": { "str": "Pyromancy for Heretics", "str_pl": "copies of Pyromancy for Heretics" }, + "//": "4 Kelvinist spells", "description": "This charred husk of a book still contains many ways to light things aflame.", "weight": "450 g", "volume": "1 L", @@ -65,6 +68,7 @@ { "id": "wizard_advanced", "type": "GENERIC", + "//": "1 Magus, 1 biomancer, 2 kelvinist spells", "name": { "str": "A Treatise on Magical Elements", "str_pl": "copies of A Treatise on Magical Elements" }, "description": "This details complex diagrams, rituals, and choreography that describes various spells.", "weight": "920 g", @@ -78,6 +82,7 @@ "id": "priest_beginner", "type": "GENERIC", "name": { "str": "Introduction to the Divine", "str_pl": "copies of Introduction to the Divine" }, + "//": "1 technomancer, 1 biomancer, 1 classless spells", "description": "This appears to mostly be a religious text, but it does have some notes on healing.", "weight": "585 g", "volume": "500 ml", @@ -93,6 +98,7 @@ "str": "The Paladin's Guide to Modern Spellcasting", "str_pl": "copies of The Paladin's Guide to Modern Spellcasting" }, + "//": "2 technomancer, 1 animist spells", "description": "Despite the title, this seems to be written in Middle English. A little obtuse, but you can make out most of the words well enough.", "weight": "830 g", "volume": "750 ml", @@ -105,6 +111,7 @@ "id": "winter_grasp", "type": "GENERIC", "name": { "str": "Winter's Eternal Grasp", "str_pl": "copies of Winter's Eternal Grasp" }, + "//": "5 Kelvinist spells", "description": "This slim book almost seems to be made from ice, it's cold to the touch.", "weight": "450 g", "volume": "1 L", @@ -116,6 +123,7 @@ { "id": "tome_of_storms", "type": "GENERIC", + "//": "6 Stormshaper spells", "name": { "str": "The Tome of The Oncoming Storm", "str_pl": "copies of The Tome of The Oncoming Storm" }, "description": "A large book embossed with crossed lightning bolts and storm clouds, it tingles to the touch.", "weight": "430 g", @@ -132,6 +140,7 @@ "id": "generic_spellbook", "type": "GENERIC", "name": { "str": "Nondescript Spellbook", "str_pl": "copies of Nondescript Spellbook" }, + "//": "1 technomancer, 1 earthshaper, 1 classless spell", "description": "A small book, containing spells created by a novice magician.", "weight": "355 g", "volume": "500 ml", @@ -143,6 +152,7 @@ "id": "light_manipulation_spellbook", "type": "GENERIC", "name": { "str": "Of Light and Falsehoods", "str_pl": "copies of Of Light and Falsehoods" }, + "//": "3 technomancer, 4 classless spell", "description": "A small white book, it subtly amplifies the ambient light around it.", "weight": "430 g", "volume": "750 ml", @@ -166,6 +176,7 @@ "id": "biomancer_spellbook", "type": "GENERIC", "name": { "str": "The Tome of Flesh", "str_pl": "copies of The Tome of Flesh" }, + "//": "5 Biomancer spells", "description": "A small tome, seemingly covered in tanned human skin.", "weight": "355 g", "volume": "500 ml", @@ -180,6 +191,7 @@ "id": "druid_spellbook", "type": "GENERIC", "name": { "str": "The Book of Trees", "str_pl": "copies of The Book of Trees" }, + "//": "4 Druid spells", "description": "A bark covered book.", "weight": "355 g", "volume": "500 ml", @@ -192,6 +204,7 @@ "type": "GENERIC", "name": { "str": "The Utility of Mana as an Energy Source", "str_pl": "copies of The Utility of Mana as an Energy Source" }, "description": "This book details spells that use your mana to recover various physiological effects.", + "//": "1 technomancer, 2 animist, 1 druid, 1 earthshaper spell", "weight": "728 g", "volume": "3 L", "symbol": "?", @@ -205,6 +218,7 @@ "id": "magus_spellbook", "type": "GENERIC", "name": { "str": "The Tome of The Battle Mage", "str_pl": "copies of The Tome of The Battle Mage" }, + "//": "3 Magus spells", "description": "Your standard wizardy looking spellbook, filled with Magus combat spells. You sure lucked out!", "weight": "434 g", "volume": "750 ml", @@ -216,6 +230,7 @@ "id": "eshaper_spellbook", "type": "GENERIC", "name": { "str": "The Tome of the Hollow Earth", "str_pl": "copies of The Tome of the Hollow Earth" }, + "//": "4 earthshaper spells", "description": "This large dusty spellbook seems perpetually, well, dusty. It contains the power of the earth.", "weight": "483 g", "volume": "825 ml", @@ -230,6 +245,7 @@ "id": "magus_spellbook_move", "type": "GENERIC", "name": { "str": "The Tome of Magical Movement", "str_pl": "copies of The Tome of Magical Movement" }, + "//": "3 Magus spells", "description": "This small lightweight book seems to almost not entirely exist, let's say it 97% does. It contains Magus spells focused on movement.", "weight": "231 g", "volume": "500 ml", @@ -241,6 +257,7 @@ "id": "summon_scroll_smudged", "type": "GENERIC", "name": "Smudged Scroll", + "//": "Druid spell", "description": "This looks like someone was designing a new spell, but spilled a mug of coffee on it and crumpled it up in anger. You can tell that it will definitely cast something, but you can't be sure that it will work very well.", "weight": "129 g", "volume": "100 ml", @@ -252,6 +269,7 @@ "id": "summon_undead_spellbook", "type": "GENERIC", "name": { "str": "Necromantic Minions for Dummies", "str_pl": "copies of Necromantic Minions for Dummies" }, + "//": "3 Animist spells", "description": "This book details various ways of summoning an undead minion to fight for you. They all appear to disappear after a short time, crumbling to dust.", "weight": "788 g", "volume": "2250 ml", @@ -263,6 +281,7 @@ "id": "techno_fundamentals", "type": "GENERIC", "name": { "str": "Fundamentals of Technomancy", "str_pl": "copies of Fundamentals of Technomancy" }, + "//": "3 Technomancer spells", "description": "This thick manual instructs the spellcaster on manipulating and empowering various forms of matter and energy.", "weight": "258 g", "volume": "750 ml", @@ -275,6 +294,7 @@ "type": "GENERIC", "name": { "str": "Complete Idiot's Guide to Technomancy", "str_pl": "copies of Complete Idiot's Guide to Technomancy" }, "description": "This colorful guide, full of diagrams and cartoons, teaches a couple of very basic Technomancy spells for the not-so-bright pupils.", + "//": "2 Technomancer spells", "weight": "211 g", "volume": "500 ml", "symbol": "?", @@ -288,6 +308,7 @@ "str": "Technomancy and the Electromagnetic Spectrum", "str_pl": "copies of Technomancy and the Electromagnetic Spectrum" }, + "//": "2 Technomancer spells", "description": "This lab reference material book is thick and overflowing with information on combining magic with EM radiation.", "weight": "284 g", "volume": "1 L", @@ -299,6 +320,7 @@ "id": "translocate_spellbook", "type": "GENERIC", "name": { "str": "Geospatial Systems: The Lie Of Linearity", "str_pl": "copies of Geospatial Systems: The Lie Of Linearity" }, + "//": "1 classless spell", "description": "This book outlines in great detail how time and space are wibbly-wobbly and non-Euclidean. It also appears to have a dozen different coordinate systems that it uses nearly interchangeably, which makes it hard to follow. There's lots of jargon, but with intense study you can probably learn a thing or two about portals.", "weight": "1200 g", "volume": "2500 ml", @@ -310,6 +332,7 @@ "id": "stat_up_spellbook", "type": "GENERIC", "name": { "str": "Transcendence of the Human Condition", "str_pl": "copies of Transcendence of the Human Condition" }, + "//": "4 Magus spells", "description": "The Human is the only creature that seeks to improve himself. This study examines different spells that can heighten various senses temporarily, in hopes to discover a more permanent solution.", "weight": "1300 g", "volume": "2500 ml", diff --git a/data/mods/Magiclysm/worldgen/magic_academy.json b/data/mods/Magiclysm/worldgen/magic_academy.json new file mode 100644 index 0000000000000..ba638ebfb2265 --- /dev/null +++ b/data/mods/Magiclysm/worldgen/magic_academy.json @@ -0,0 +1,617 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_ground", + "object": { + "fill_ter": "t_floor", + "rows": [ + ",.####################.,", + ",.#d h&o==jjjj==o%h d#.,", + ",.#@@ +========+ @@#.,", + ",.########=~~=########.,", + ",...#d h0o=~~=o$h d#...,", + ",...#@@ +====+ @@#...,", + ",...#######==#######...,", + ",[...##S +==+ S##..[.,", + ",.....#t ##++## t#.....,", + ",.....#9##< >##9#..[..,", + ",..[..###c c###.....,", + ",.....##c E E c##...[.,", + ",,,,,,* *,,,,,,", + ",,,,,,* HHHH *,,,,,,", + "......##c c##......", + "...[..###c rr c###......", + ".....##<## h ##<##..[..", + ".[...#B t##++##t B#.....", + "....##B S#==#S B##....", + "...####+###==###+####...", + "####xxy +======+ yxx####", + "#D ) Eoj=~~=joI ) D#", + "#@@#HHTR#j====j#IEHH#@@#", + "########################" + ], + "palettes": [ "standard_domestic_palette" ], + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ], + "terrain": { + "[": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ], + " ": "t_floor", + "#": "t_rock_wall", + ",": "t_concrete", + "~": "t_water_pool_shallow_outdoors", + "=": "t_grass_golf", + "j": "t_grass_golf", + "}": "t_grass_golf" + }, + "furniture": { ")": "f_beaded_door", "&": "f_desk", "%": "f_desk", "$": "f_desk", "0": "f_desk" }, + "place_loot": [ + { "item": "television", "x": 4, "y": 20, "chance": 100 }, + { "item": "television", "x": 19, "y": 20, "chance": 100 }, + { "item": "stereo", "x": 18, "y": 20, "chance": 100 }, + { "item": "stereo", "x": 5, "y": 20, "chance": 100 } + ], + "items": { + "&": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "druid_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "%": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "biomancer_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "$": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "earthshaper_items", "chance": 70, "repeat": [ 1, 3 ] } + ], + "0": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "technomancer_items", "chance": 70, "repeat": [ 1, 3 ] } + ], + "x": { "item": "enchanted_small_items", "chance": 25, "repeat": [ 1, 3 ] }, + "r": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "academy_lore", "chance": 100 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 10 }, + { "item": "enchanted_misc", "chance": 5 } + ], + "d": [ + { "item": "magic_shop_clothes", "chance": 25, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] } + ], + "D": [ + { "item": "magic_shop_clothes", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] } + ], + "R": [ + { "item": "magic_shop_books", "chance": 60, "repeat": [ 1, 3 ] }, + { "item": "spellbook_loot_2", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_misc", "chance": 5 } + ], + "j": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 10 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 5 }, + { "item": "enchanted_misc", "chance": 2 } + ] + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_basement", + "object": { + "fill_ter": "t_thconc_floor", + "rows": [ + "``####################``", + "``#@d|vRR H|FFF 666#``", + "``#@ ) lH| 6#``", + "``###||+|||||4 JA 6###``", + "````#H JWWQ|O J n#````", + "````#H Z|1 J 5#````", + "````##T Z|2 Y##````", + "`````##JJy Q|3 7##`````", + "``````#|||+|||+||#``````", + "``````#qq| < |U#``````", + "``````#q + +U#``````", + "``````#||||| ||#``````", + "``````# #``````", + "``````# $ $ ~~~ i#``````", + "``````# ~~~ i#``````", + "``````# ! ! ~~~ i#``````", + "`````## ~~~ ##`````", + "`````# % % ~~~ #`````", + "````## ~~~ ##````", + "```## = = = ~~~~~ ##```", + "####i ~~~~~ i####", + "#9 |i = = = ~~~~~ i| 9#", + "#9 ] ] 9#", + "########################" + ], + "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" }, + "place_loot": [ { "item": "television", "x": 8, "y": 1, "chance": 100 }, { "item": "stereo", "x": 7, "y": 1, "chance": 100 } ], + "items": { + "q": [ + { "item": "alchemy_items", "chance": 45, "repeat": [ 1, 3 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] } + ], + "l": { "item": "enchanted_small_items", "chance": 15 }, + "v": { "item": "boss_treasure_items", "chance": 70, "repeat": [ 1, 3 ] }, + "d": [ + { "item": "magic_shop_clothes", "chance": 25, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 15 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ], + "i": [ + { "item": "magic_shop_potions", "chance": 10 }, + { "item": "magic_shop_wands", "chance": 3 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 15 } + ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 2, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_2nd", + "object": { + "fill_ter": "t_floor", + "rows": [ + "__####################__", + "__#d h&o,______,o%h d#__", + "__#@@ +,,,__,,,+ @@#__", + "__########,__,########__", + "____#d h0o,__,o$h d#____", + "____#@@ +,,,,+ @@#____", + "____#######,,#######____", + "_____##S +,,+ S##_____", + "______#t ##++## t#______", + "______#9##> <##9#______", + "______### ###______", + "______## hhhh ##______", + "______)y ffff y)______", + "______)y hhhh y)______", + "______## ##______", + "______### ff ###______", + "_____##>## hh ##>##_____", + "_____#` v##))##vE`#_____", + "____##`E R#__#R `##____", + "___###)]))#__#))])###___", + "#####,,,===__===,,,#####", + "#k ],=}=______=}=,] k#", + "#RHH)====______====)HHR#", + "#########################" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { + "_": "t_open_air", + "/": "t_open_air_rooved_outside", + ",": "t_concrete", + "#": "t_rock_wall", + ")": "t_wall_glass", + "]": "t_door_glass_c", + "=": "t_grass_golf", + "j": "t_grass_golf", + "}": "t_grass_golf" + }, + "furniture": { + "y": [ "f_indoor_plant_y", "f_indoor_plant" ], + "`": "f_magic_bench", + "}": "f_huge_mana_crystal", + "&": "f_desk", + "%": "f_desk", + "$": "f_desk", + "0": "f_desk" + }, + "items": { + "&": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "kelvinist_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "%": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "animist_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "$": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "magus_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "0": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "stormshaper_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "H": [ + { "item": "magic_shop_clothes", "chance": 20 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_misc", "chance": 1 } + ], + "`": [ + { "item": "alchemy_items", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_tools_and_loot", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 20, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] } + ], + "v": { "item": "boss_treasure_items", "chance": 70, "repeat": [ 1, 3 ] }, + "d": [ + { "item": "magic_shop_clothes", "chance": 25, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] } + ], + "R": [ { "item": "classless_items", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_3rd", + "object": { + "fill_ter": "t_floor", + "rows": [ + "__....................__", + "__......________......__", + "__......________......__", + "__........____........__", + "____......____......____", + "____......____......____", + "____.......__.......____", + "_____......__......_____", + "______...##))##...______", + "______..##< >##..______", + "______.##))]]))##.______", + "______##y ##______", + "______)i h h h h )______", + "______)i & & & & )______", + "______## ##______", + "______.##R && R##.______", + "_____...## E y##..._____", + "_____....##))##...._____", + "____......#__#......____", + "___........__........___", + ".....______________.....", + ".....______________.....", + ".....______________.....", + "........................" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c", ".": "t_shingle_flat_roof" }, + "furniture": { "&": "f_magic_bench" }, + "items": { + "&": [ + { "item": "magic_tools_and_loot", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_wands", "chance": 5 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_4th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##> <##________", + "_______##))]]))##_______", + "______##y ##______", + "______)i h h h h )______", + "______)i & & & & )______", + "______## ##______", + "_______##R && R##_______", + "________## E y##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c" }, + "furniture": { "&": "f_magic_bench" }, + "items": { + "&": [ + { "item": "magic_tools_and_loot", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_wands", "chance": 5 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_5th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##< >##________", + "_______##))]]))##_______", + "______##Tx y##______", + "______)Hl ee lH)______", + "______)Hl ee lH)______", + "______##y ee T##______", + "_______##y y##_______", + "________##k Es##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c" }, + "place_loot": [ { "item": "television", "x": 9, "y": 11, "chance": 100 }, { "item": "stereo", "x": 13, "y": 16, "chance": 100 } ], + "items": { + "l": { "item": "enchanted_small_items", "chance": 15 }, + "H": [ + { "item": "magic_shop_clothes", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] } + ], + "s": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 10 }, + { "item": "enchanted_misc", "chance": 5 } + ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_6th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##> <##________", + "_______##))]]))##_______", + "______##R R##______", + "______)rh RRRR hr)______", + "______)rh RRRR hr)______", + "______##R R##______", + "_______##R hh R##_______", + "________##RrrR##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c" }, + "items": { + "r": [ + { "item": "magic_shop_books", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 2 }, + { "item": "enchanted_misc", "chance": 5 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_7th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##< >##________", + "_______##))]]))##_______", + "______##? ?##______", + "______) A= =A )______", + "______) A= =A )______", + "______##? - - ?##______", + "_______##? ?##_______", + "________##? ?##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "-": "t_floor", "]": "t_door_glass_c" }, + "furniture": { "=": "f_magic_bench", "-": "f_alembic", "?": "f_rack_wood" }, + "items": { + "=": [ + { "item": "alchemy_items", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "magic_recipe_basic", "chance": 40 }, + { "item": "magic_shop_wands", "chance": 5 } + ], + "?": [ + { "item": "alchemy_items", "chance": 45, "repeat": [ 1, 3 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] } + ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_8th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##> <##________", + "_______## ##_______", + "______## ==== ##______", + "______)i ===-== i)______", + "______)i ==0=== i)______", + "______## ==== ##______", + "_______## ##_______", + "________## ii ##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { + "_": "t_open_air", + ")": "t_wall_glass", + "#": "t_rock_wall", + "]": "t_door_glass_c", + "=": "t_grass_golf", + "0": "t_grass_golf", + "-": "t_grass_golf" + }, + "furniture": { "0": "f_orrery", "-": "f_magic_circle" }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________ _________", + "________ > ________", + "_______ _______", + "______ ______", + "______ ______", + "______ ______", + "______ ______", + "_______ _______", + "________ ________", + "_________ _________", + "__________ __ __________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "terrain": { ">": "t_stairs_down", "_": "t_open_air" }, + "items": { + "i": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 10 }, + { "item": "enchanted_misc", "chance": 5 } + ] + } + } + } +] diff --git a/data/mods/Magiclysm/worldgen/magic_basement.json b/data/mods/Magiclysm/worldgen/magic_basement.json index 5253206cdaeda..51f943221a705 100644 --- a/data/mods/Magiclysm/worldgen/magic_basement.json +++ b/data/mods/Magiclysm/worldgen/magic_basement.json @@ -34,7 +34,7 @@ ], "palettes": [ "standard_domestic_palette" ], "place_traps": [ { "trap": "tr_magic_door", "x": 21, "y": 4 } ], - "place_item": [ { "item": "television", "x": 21, "y": 10 } ], + "place_item": [ { "item": "television", "x": 21, "y": 10 }, { "item": "wizard_photo", "x": 16, "y": 6 } ], "place_loot": [ { "item": "corpse", "x": 2, "y": 6, "chance": 100 }, { "item": "translocate_spellbook", "x": 2, "y": 6, "chance": 100 }, diff --git a/data/mods/Magiclysm/worldgen/multitile_city_buildings.json b/data/mods/Magiclysm/worldgen/multitile_city_buildings.json index 21f0fe4c74725..8b3ed83644264 100644 --- a/data/mods/Magiclysm/worldgen/multitile_city_buildings.json +++ b/data/mods/Magiclysm/worldgen/multitile_city_buildings.json @@ -42,5 +42,22 @@ { "point": [ 0, 0, 1 ], "overmap": "house_detatched5_roof_north" }, { "point": [ 0, 0, -1 ], "overmap": "magic_basement_north" } ] + }, + { + "type": "city_building", + "id": "magic_academy", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "magic_academy_ground_north" }, + { "point": [ 0, 0, 1 ], "overmap": "magic_academy_2nd_north" }, + { "point": [ 0, 0, 2 ], "overmap": "magic_academy_3rd_north" }, + { "point": [ 0, 0, 3 ], "overmap": "magic_academy_4th_north" }, + { "point": [ 0, 0, 4 ], "overmap": "magic_academy_5th_north" }, + { "point": [ 0, 0, 5 ], "overmap": "magic_academy_6th_north" }, + { "point": [ 0, 0, 6 ], "overmap": "magic_academy_7th_north" }, + { "point": [ 0, 0, 7 ], "overmap": "magic_academy_8th_north" }, + { "point": [ 0, 0, 8 ], "overmap": "magic_academy_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "magic_academy_basement_north" } + ] } ] diff --git a/data/mods/Magiclysm/worldgen/overmap_terrain.json b/data/mods/Magiclysm/worldgen/overmap_terrain.json index 3047ecc6e4180..8405a6b82bd1d 100644 --- a/data/mods/Magiclysm/worldgen/overmap_terrain.json +++ b/data/mods/Magiclysm/worldgen/overmap_terrain.json @@ -352,5 +352,94 @@ "type": "overmap_terrain", "id": "wizardtower2_roof", "copy-from": "wizardtower1_ground" + }, + { + "type": "overmap_terrain", + "id": "magic_academy_ground", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "see_cost": 5, + "mondensity": 2, + "flags": [ "SIDEWALK" ] + }, + { + "type": "overmap_terrain", + "id": "magic_academy_2nd", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_3rd", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_4th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_5th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_6th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_7th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_8th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_basement", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_roof", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "see_cost": 5 } ] diff --git a/data/mods/Magiclysm/worldgen/regional_overlay.json b/data/mods/Magiclysm/worldgen/regional_overlay.json index 55f79dc7cd4ab..2480ba8fc2076 100644 --- a/data/mods/Magiclysm/worldgen/regional_overlay.json +++ b/data/mods/Magiclysm/worldgen/regional_overlay.json @@ -2,7 +2,10 @@ { "type": "region_overlay", "regions": [ "all" ], - "city": { "houses": { "wizard_tower_1": 10, "wizard_tower_2": 20 }, "shops": { "magic_shop": 100, "used_bookstore": 225 } }, + "city": { + "houses": { "wizard_tower_1": 10, "wizard_tower_2": 20 }, + "shops": { "magic_shop": 100, "used_bookstore": 225, "magic_academy": 150 } + }, "field_coverage": { "other": { "f_boulder_large": 0.6667, "f_glow_boulder": 0.3333 } } } ] From cc0f34818b7637bc81ab6a7a6319cdb95bed495d Mon Sep 17 00:00:00 2001 From: arijust <54635208+arijust@users.noreply.github.com> Date: Sun, 8 Mar 2020 18:09:51 +0100 Subject: [PATCH 027/219] Magiclysm: Forest Tomb (#37699) --- data/mods/Magiclysm/furniture.json | 19 +++ .../mods/Magiclysm/itemgroups/itemgroups.json | 5 + data/mods/Magiclysm/worldgen/forest_tomb.json | 134 ++++++++++++++++++ .../Magiclysm/worldgen/overmap_specials.json | 13 ++ .../Magiclysm/worldgen/overmap_terrain.json | 18 +++ 5 files changed, 189 insertions(+) create mode 100644 data/mods/Magiclysm/worldgen/forest_tomb.json diff --git a/data/mods/Magiclysm/furniture.json b/data/mods/Magiclysm/furniture.json index ec16f5732a843..e33595f37be77 100644 --- a/data/mods/Magiclysm/furniture.json +++ b/data/mods/Magiclysm/furniture.json @@ -186,5 +186,24 @@ { "item": "glass_shard", "count": [ 8, 12 ] } ] } + }, + { + "type": "furniture", + "id": "f_altar", + "name": "stone altar", + "move_cost_mod": 10, + "symbol": "H", + "color": "light_gray", + "coverage": 40, + "required_str": 30, + "flags": [ "BASHABLE" ], + "description": "This is big stone altar. Most commonly used in morally questionable rituals.", + "bash": { + "str_min": 30, + "str_max": 160, + "sound": "smash!", + "sound_fail": "thump.", + "items": [ { "item": "rock", "count": [ 5, 15 ] }, { "item": "sharp_rock", "count": [ 3, 5 ] } ] + } } ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 45016883441b1..594ec79cd6995 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -1034,5 +1034,10 @@ "type": "item_group", "id": "magic_basement_photo", "items": [ [ "wizard_photo", 100 ] ] + }, + { + "type": "item_group", + "id": "forest_tomb_spellbook", + "items": [ [ "summon_undead_spellbook", 100 ] ] } ] diff --git a/data/mods/Magiclysm/worldgen/forest_tomb.json b/data/mods/Magiclysm/worldgen/forest_tomb.json new file mode 100644 index 0000000000000..9e2e259afeba4 --- /dev/null +++ b/data/mods/Magiclysm/worldgen/forest_tomb.json @@ -0,0 +1,134 @@ +[ + { + "type": "palette", + "id": "tomb", + "terrain": { + ".": "t_rock_floor", + " ": [ [ "t_grass_dead", 15 ], [ "t_dirt", 4 ], [ "t_dirtmound", 3 ], [ "t_rock_floor_no_roof", 4 ] ], + "T": "t_tree_dead", + "R": "t_railroad_rubble", + "S": "t_shrub", + "<": "t_slope_up", + ">": "t_slope_down", + "#": "t_rock" + }, + "furniture": { "H": "f_altar", "C": "f_coffin_c" }, + "items": { "R": { "item": "animist_items", "chance": 25 }, "H": { "item": "forest_tomb_spellbook", "chance": 100 } }, + "monster": { "x": { "monster": "mon_skeleton", "chance": 50 }, "Z": { "monster": "mon_zombie_necro", "chance": 100 } } + }, + { + "type": "palette", + "id": "tomb_roof", + "terrain": { ".": "t_rock_roof", " ": "t_open_air", ">": "t_slope_down" } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "forest_tomb" ], + "//": "Ground level - Z-0.", + "weight": 100, + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + " S ", + " S ", + " S ", + " S ", + " S ", + " S S ", + " ##<############### ", + " ################## ", + " S ####C.##>>##..C### ", + " ###x..........###............... ", + " .................. ", + " .................. ", + " .................> ", + " .................. ", + " .................. ", + " .................. ", + " .................. ", + " .................. ", + " .............>.... ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "tomb_roof" ] + } + } +] diff --git a/data/mods/Magiclysm/worldgen/overmap_specials.json b/data/mods/Magiclysm/worldgen/overmap_specials.json index 793fa84e1f4bb..59bd3170213d4 100644 --- a/data/mods/Magiclysm/worldgen/overmap_specials.json +++ b/data/mods/Magiclysm/worldgen/overmap_specials.json @@ -114,5 +114,18 @@ "city_sizes": [ 4, 12 ], "occurrences": [ 0, 1 ], "flags": [ "CLASSIC", "LAKE" ] + }, + { + "type": "overmap_special", + "id": "forest_tomb", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "forest_tomb_north" }, + { "point": [ 0, 0, 1 ], "overmap": "forest_tomb_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "forest_tomb_bottom_north" } + ], + "locations": [ "wilderness" ], + "city_distance": [ 20, -1 ], + "city_sizes": [ 0, 20 ], + "occurrences": [ 0, 1 ] } ] diff --git a/data/mods/Magiclysm/worldgen/overmap_terrain.json b/data/mods/Magiclysm/worldgen/overmap_terrain.json index 8405a6b82bd1d..be7c1f4a01a69 100644 --- a/data/mods/Magiclysm/worldgen/overmap_terrain.json +++ b/data/mods/Magiclysm/worldgen/overmap_terrain.json @@ -353,6 +353,24 @@ "id": "wizardtower2_roof", "copy-from": "wizardtower1_ground" }, + { + "type": "overmap_terrain", + "id": "forest_tomb", + "name": "forest", + "sym": "F", + "color": "brown", + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "forest_tomb_roof", + "copy-from": "forest_tomb" + }, + { + "type": "overmap_terrain", + "id": "forest_tomb_bottom", + "copy-from": "forest_tomb" + }, { "type": "overmap_terrain", "id": "magic_academy_ground", From 67e14db9706a8ac70f483f1a142dc84f95f1089e Mon Sep 17 00:00:00 2001 From: LaVeyanFiend <51099123+LaVeyanFiend@users.noreply.github.com> Date: Sat, 14 Mar 2020 20:17:37 -0400 Subject: [PATCH 028/219] Add demon chitin armor & repairing dragon armor (#36733) --- .../Magiclysm/enchanted/enchanted_misc.json | 16 ++- .../mods/Magiclysm/itemgroups/itemgroups.json | 5 +- .../Magiclysm/itemgroups/recipe_books.json | 6 + data/mods/Magiclysm/items/armor.json | 78 ++++++++++++ data/mods/Magiclysm/items/recipe_books.json | 19 +++ data/mods/Magiclysm/items/tools.json | 79 ++++++++++++ data/mods/Magiclysm/materials.json | 4 +- data/mods/Magiclysm/recipes/armor.json | 117 ++++++++++++++++++ 8 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 data/mods/Magiclysm/recipes/armor.json diff --git a/data/mods/Magiclysm/enchanted/enchanted_misc.json b/data/mods/Magiclysm/enchanted/enchanted_misc.json index b717750e0ccfc..b43a6e4fed629 100644 --- a/data/mods/Magiclysm/enchanted/enchanted_misc.json +++ b/data/mods/Magiclysm/enchanted/enchanted_misc.json @@ -146,7 +146,19 @@ { "type": "repair_item", "item_action_type": "repair_fabric", - "materials": [ "cotton", "leather", "wool", "fur", "faux_fur", "nomex", "kevlar", "neoprene", "gutskin" ], + "materials": [ + "cotton", + "leather", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "neoprene", + "gutskin", + "black_dragon_hide", + "demon_chitin" + ], "skill": "tailor", "tool_quality": 1, "cost_scaling": 0.1, @@ -156,7 +168,7 @@ "type": "sew_advanced", "materials": [ "cotton", "leather", "wool", "fur", "faux_fur", "nomex", "kevlar", "neoprene", "gutskin", "plastic", "kevlar_rigid" ], "skill": "tailor", - "clothing_mods": [ "leather_padded", "kevlar_padded", "furred", "wooled" ] + "clothing_mods": [ "leather_padded", "steel_padded", "kevlar_padded", "furred", "wooled" ] } ], "flags": [ "ALLOWS_REMOTE_USE" ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 594ec79cd6995..f10240557c95e 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -31,6 +31,7 @@ "items": [ { "group": "spellbook_loot_1", "prob": 3 }, { "group": "magic_recipe_basic", "prob": 3 }, + { "group": "magic_recipe_advanced", "prob": 1 }, { "group": "dragon_books", "prob": 3 } ] }, @@ -40,6 +41,7 @@ "items": [ { "group": "spellbook_loot_0", "prob": 6 }, { "group": "magic_recipe_basic", "prob": 6 }, + { "group": "magic_recipe_advanced", "prob": 2 }, { "group": "dragon_books", "prob": 5 } ] }, @@ -105,7 +107,8 @@ { "group": "spell_scroll_tier_0", "prob": 80 }, { "group": "spell_scroll_tier_1", "prob": 60 }, { "group": "spell_scroll_tier_2", "prob": 30 }, - { "group": "magic_recipe_basic", "prob": 50 } + { "group": "magic_recipe_basic", "prob": 50 }, + { "group": "magic_recipe_advanced", "prob": 16 } ] }, { diff --git a/data/mods/Magiclysm/itemgroups/recipe_books.json b/data/mods/Magiclysm/itemgroups/recipe_books.json index c6cac26152c99..aaf2e28b742b7 100644 --- a/data/mods/Magiclysm/itemgroups/recipe_books.json +++ b/data/mods/Magiclysm/itemgroups/recipe_books.json @@ -10,5 +10,11 @@ [ "book_mythological", 10 ], [ "cooking_poison", 15 ] ] + }, + { + "id": "magic_recipe_advanced", + "type": "item_group", + "//": "Higher tier recipes, where most school-related recipes require their rune or rune weapon.", + "items": [ [ "magic_armormaking", 30 ] ] } ] diff --git a/data/mods/Magiclysm/items/armor.json b/data/mods/Magiclysm/items/armor.json index 1d637cfb5b7b1..13dcb8127e121 100644 --- a/data/mods/Magiclysm/items/armor.json +++ b/data/mods/Magiclysm/items/armor.json @@ -26,5 +26,83 @@ "copy-from": "quiver_large_birchbark", "type": "ARMOR", "use_action": { "type": "bandolier", "capacity": 60, "ammo": [ "arrow", "bolt", "arrow_orichalcum" ], "draw_cost": 20 } + }, + { + "id": "armguard_demonchitin", + "copy-from": "armguard_chitin", + "type": "ARMOR", + "name": { "str": "pair of demon chitin arm guards", "str_pl": "pairs of demon chitin arm guards" }, + "description": "A pair of arm guards crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "armor_demonchitin", + "copy-from": "armor_chitin", + "type": "ARMOR", + "name": { "str": "demon chitin armor" }, + "description": "Leg and body armor crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "helmet_demonchitin", + "copy-from": "helmet_chitin", + "type": "ARMOR", + "name": { "str": "demon chitin helmet" }, + "description": "A helmet crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Covers the entire head; fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "gauntlets_demonchitin", + "copy-from": "gauntlets_chitin", + "type": "ARMOR", + "name": { "str": "pair of demon chitin gauntlets", "str_pl": "pairs of demon chitin gauntlets" }, + "description": "Gauntlets crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "boots_demonchitin", + "copy-from": "boots_chitin", + "type": "ARMOR", + "name": { "str": "pair of demon chitin boots", "str_pl": "pairs of demon chitin boots" }, + "description": "Boots crafted from carefully cleaned and pruned pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "type": "PET_ARMOR", + "id": "demonchitin_harness_dog", + "copy-from": "kevlar_harness", + "color": "red", + "name": { "str": "demon chitin dog mesh harness", "str_pl": "demon chitin dog mesh harnesses" }, + "description": "A makeshift harness of demon chitin fitted to a thin mesh protecting the neck to flank of canines. You could put this on a friendly dog.", + "price": 50000, + "price_postapoc": 5000, + "material": [ "demon_chitin" ], + "weight": "4862 g", + "environmental_protection": 8 + }, + { + "type": "PET_ARMOR", + "id": "demonchitin_armor_horse", + "copy-from": "horse_armor", + "color": "green", + "name": { "str": "demon chitin horse armor" }, + "description": "A makeshift assembly of criniere, peytral and croupiere made from demon chitin fitted to a thin mesh. You could put this on a friendly horse.", + "price": 120000, + "price_postapoc": 12000, + "material": [ "demon_chitin", "steel" ], + "weight": "31500 g", + "volume": "150 L", + "material_thickness": 6, + "environmental_protection": 8 } ] diff --git a/data/mods/Magiclysm/items/recipe_books.json b/data/mods/Magiclysm/items/recipe_books.json index 504dd26599ddc..ac79f101d3cba 100644 --- a/data/mods/Magiclysm/items/recipe_books.json +++ b/data/mods/Magiclysm/items/recipe_books.json @@ -113,5 +113,24 @@ "intelligence": 9, "time": "20 m", "fun": 1 + }, + { + "id": "magic_armormaking", + "type": "BOOK", + "name": { "str": "Protection from Magical Beasts", "str_pl": "copies of Protection from Magical Beasts" }, + "description": "A leatherbound book with a picture of a shield holding back dragonfire on the cover. There are many ways to turn monster skins and hides into protective equipment inside.", + "weight": "1 kg", + "volume": "750 ml", + "price": 7900, + "bashing": 5, + "material": [ "paper" ], + "symbol": "?", + "color": "white", + "skill": "tailor", + "required_level": 6, + "max_level": 8, + "intelligence": 10, + "time": "25 m", + "fun": -1 } ] diff --git a/data/mods/Magiclysm/items/tools.json b/data/mods/Magiclysm/items/tools.json index c22bb65385f96..1ee4ba7663ec8 100644 --- a/data/mods/Magiclysm/items/tools.json +++ b/data/mods/Magiclysm/items/tools.json @@ -19,5 +19,84 @@ "watertight": true, "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 2 ] ], "use_action": "HEAT_FOOD" + }, + { + "id": "sewing_kit", + "name": "sewing kit", + "copy-from": "sewing_kit", + "type": "TOOL", + "use_action": { + "type": "repair_item", + "item_action_type": "repair_fabric", + "materials": [ + "cotton", + "leather", + "lycra", + "nylon", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "gutskin", + "demon_chitin", + "black_dragon_hide" + ], + "skill": "tailor", + "tool_quality": 0, + "cost_scaling": 0.1, + "move_cost": 1000 + } + }, + { + "id": "tailors_kit", + "name": "tailor's kit", + "copy-from": "tailors_kit", + "type": "TOOL", + "use_action": [ + { + "type": "repair_item", + "item_action_type": "repair_fabric", + "materials": [ + "cotton", + "leather", + "lycra", + "nylon", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "neoprene", + "gutskin", + "black_dragon_hide", + "demon_chitin" + ], + "skill": "tailor", + "tool_quality": 1, + "cost_scaling": 0.1, + "move_cost": 800 + }, + { + "type": "sew_advanced", + "materials": [ + "cotton", + "leather", + "lycra", + "nylon", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "neoprene", + "gutskin", + "plastic", + "kevlar_rigid" + ], + "skill": "tailor", + "clothing_mods": [ "leather_padded", "steel_padded", "kevlar_padded", "furred", "wooled" ] + } + ] } ] diff --git a/data/mods/Magiclysm/materials.json b/data/mods/Magiclysm/materials.json index 6fd108288441b..5236c46aa84e7 100644 --- a/data/mods/Magiclysm/materials.json +++ b/data/mods/Magiclysm/materials.json @@ -22,7 +22,7 @@ { "type": "material", "ident": "black_dragon_hide", - "name": "black dragon hide", + "name": "Black Dragon Hide", "density": 20, "specific_heat_liquid": 4.186, "specific_heat_solid": 2.108, @@ -53,6 +53,8 @@ "fire_resist": 18, "elec_resist": 2, "chip_resist": 10, + "repaired_with": "demon_chitin_piece", + "salvaged_into": "demon_chitin_piece", "dmg_adj": [ "scratched", "cut", "cracked", "shattered" ], "bash_dmg_verb": "cracked", "cut_dmg_verb": "chipped", diff --git a/data/mods/Magiclysm/recipes/armor.json b/data/mods/Magiclysm/recipes/armor.json new file mode 100644 index 0000000000000..962dbe57f405f --- /dev/null +++ b/data/mods/Magiclysm/recipes/armor.json @@ -0,0 +1,117 @@ +[ + { + "result": "helmet_demonchitin", + "byproducts": [ [ "demon_chitin_piece", 3 ] ], + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 7, + "time": "4 h", + "book_learn": [ [ "magic_armormaking", 6 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 1 ] ], [ [ "demon_chitin_piece", 1 ] ] ] + }, + { + "result": "armguard_demonchitin", + "byproducts": [ [ "demon_chitin_piece", 8 ] ], + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 6, + "time": "2 h", + "book_learn": [ [ "magic_armormaking", 5 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 1 ] ], [ [ "demon_chitin_piece", 2 ] ] ] + }, + { + "result": "armor_demonchitin", + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 8, + "time": "4 h", + "book_learn": [ [ "magic_armormaking", 7 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 4 ] ], [ [ "demon_chitin_piece", 6 ] ] ] + }, + { + "result": "boots_demonchitin", + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 5, + "time": "2 h 40 m", + "book_learn": [ [ "magic_armormaking", 4 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 1 ] ], [ [ "demon_chitin_piece", 2 ] ] ] + }, + { + "result": "gauntlets_demonchitin", + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 5, + "time": "2 h", + "book_learn": [ [ "magic_armormaking", 4 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_piece", 10 ] ] ] + }, + { + "result": "demonchitin_armor_horse", + "type": "recipe", + "copy-from": "armor_demonchitin", + "category": "CC_ANIMALS", + "subcategory": "CSC_ANIMALS_EQUINE ARMOR", + "time": "17 h 30 m", + "book_learn": [ [ "textbook_tailor", 5 ], [ "tailor_portfolio", 5 ] ], + "skills_required": [ [ "spellcraft", 6 ], [ "fabrication", 4 ], [ "survival", 4 ] ], + "using": [ [ "cordage", 7 ] ], + "components": [ [ [ "demon_chitin_plate", 4 ] ], [ [ "demon_chitin_piece", 20 ] ] ] + }, + { + "result": "demonchitin_harness_dog", + "type": "recipe", + "copy-from": "armor_demonchitin", + "category": "CC_ANIMALS", + "subcategory": "CSC_ANIMALS_CANINE ARMOR", + "skills_required": [ [ "spellcraft", 6 ], [ "fabrication", 4 ], [ "survival", 4 ] ], + "time": "5 h", + "using": [ [ "cordage", 1 ] ], + "components": [ [ [ "demon_chitin_piece", 12 ] ] ] + } +] From f8bf777cada40dba7ec8a7d986270ca7ff19d1fc Mon Sep 17 00:00:00 2001 From: KorGgenT Date: Sat, 22 Feb 2020 21:54:42 -0500 Subject: [PATCH 029/219] Read ids and save ids for enchantments (#38262) --- src/magic_enchantment.cpp | 7 +++++++ src/relic.cpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 6fb9375ac688c..e095fdd84644d 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -241,6 +241,13 @@ void enchantment::serialize( JsonOut &jsout ) const { jsout.start_object(); + if( !id.is_empty() ) { + jsout.member( "id", id ); + jsout.end_object(); + // if the enchantment has an id then it is defined elsewhere and does not need to be serialized. + return; + } + jsout.member( "has", io::enum_to_string( active_conditions.first ) ); jsout.member( "condition", io::enum_to_string( active_conditions.second ) ); diff --git a/src/relic.cpp b/src/relic.cpp index baeea1cd5e805..72bb8f238d271 100644 --- a/src/relic.cpp +++ b/src/relic.cpp @@ -37,6 +37,9 @@ void relic::load( const JsonObject &jo ) for( JsonObject jobj : jo.get_array( "passive_effects" ) ) { enchantment ench; ench.load( jobj ); + if( !ench.id.is_empty() ) { + ench = ench.id.obj(); + } add_passive_effect( ench ); } } From 2e4c68fa56c4305cb5c40f9a2cf07dbaa4aaa376 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 11 Mar 2020 02:54:37 -0400 Subject: [PATCH 030/219] Jsonize spell skills (#37368) --- src/activity_handlers.cpp | 4 ++-- src/magic.cpp | 15 +++++++++++---- src/magic.h | 3 +++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 3d2be998e8213..2f75554ca47f1 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -4661,8 +4661,8 @@ void activity_handlers::study_spell_finish( player_activity *act, player *p ) if( act->get_str_value( 1 ) == "study" ) { p->add_msg_if_player( m_good, _( "You gained %i experience from your study session." ), total_exp_gained ); - p->practice( skill_id( "spellcraft" ), total_exp_gained, - p->magic.get_spell( spell_id( act->name ) ).get_difficulty() ); + const spell &sp = p->magic.get_spell( spell_id( act->name ) ); + p->practice( sp.skill(), total_exp_gained, sp.get_difficulty() ); } else if( act->get_str_value( 1 ) == "learn" && act->values[2] == 0 ) { p->magic.learn_spell( act->name, *p ); } diff --git a/src/magic.cpp b/src/magic.cpp index 3edd6db825919..cb89ab44c848c 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -24,6 +24,7 @@ #include "mutation.h" #include "output.h" #include "player.h" +#include "skill.h" #include "sounds.h" #include "translations.h" #include "ui.h" @@ -231,6 +232,7 @@ void spell_type::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "id", id ); mandatory( jo, was_loaded, "name", name ); mandatory( jo, was_loaded, "description", description ); + optional( jo, was_loaded, "skill", skill, skill_id( "spellcraft" ) ); optional( jo, was_loaded, "message", message, to_translation( "You cast %s!" ) ); optional( jo, was_loaded, "sound_description", sound_description, to_translation( "an explosion" ) ); @@ -445,6 +447,11 @@ trait_id spell::spell_class() const return type->spell_class; } +skill_id spell::skill() const +{ + return type->skill; +} + int spell::field_intensity() const { return std::min( type->max_field_intensity, @@ -706,7 +713,7 @@ float spell::spell_fail( const player &p ) const // effective skill of 8 (8 int, 0 spellcraft, 0 spell level, spell difficulty 0) is ~50% failure // effective skill of 30 is 0% failure const float effective_skill = 2 * ( get_level() - get_difficulty() ) + p.get_int() + - p.get_skill_level( skill_id( "spellcraft" ) ); + p.get_skill_level( skill() ); // add an if statement in here because sufficiently large numbers will definitely overflow because of exponents if( effective_skill > 30.0f ) { return 0.0f; @@ -1022,7 +1029,7 @@ float spell::exp_modifier( const player &p ) const { const float int_modifier = ( p.get_int() - 8.0f ) / 8.0f; const float difficulty_modifier = get_difficulty() / 20.0f; - const float spellcraft_modifier = p.get_skill_level( skill_id( "spellcraft" ) ) / 10.0f; + const float spellcraft_modifier = p.get_skill_level( skill() ) / 10.0f; return ( int_modifier + difficulty_modifier + spellcraft_modifier ) / 5.0f + 1.0f; } @@ -1431,8 +1438,8 @@ int known_magic::time_to_learn_spell( const player &p, const std::string &str ) int known_magic::time_to_learn_spell( const player &p, const spell_id &sp ) const { const int base_time = to_moves( 30_minutes ); - return base_time * ( 1.0 + sp.obj().difficulty / ( 1.0 + ( p.get_int() - 8.0 ) / 8.0 ) + - ( p.get_skill_level( skill_id( "spellcraft" ) ) / 10.0 ) ); + return base_time * ( 1.0 + sp->difficulty / ( 1.0 + ( p.get_int() - 8.0 ) / 8.0 ) + + ( p.get_skill_level( sp->skill ) / 10.0 ) ); } int known_magic::get_spellname_max_width() diff --git a/src/magic.h b/src/magic.h index ff81b13e3fbe8..94bcf20c335e9 100644 --- a/src/magic.h +++ b/src/magic.h @@ -133,6 +133,7 @@ class spell_type translation message; // spell sound effect translation sound_description; + skill_id skill; sounds::sound_t sound_type = sounds::sound_t::_LAST; bool sound_ambient = false; std::string sound_id; @@ -355,6 +356,8 @@ class spell spell_id id() const; // get spell class (from type) trait_id spell_class() const; + // get skill id + skill_id skill() const; // get spell effect string (from type) std::string effect() const; // get spell effect_str data From 7460f0aac399378553d52681f3b3a01240515cd2 Mon Sep 17 00:00:00 2001 From: KorGgenT Date: Thu, 20 Feb 2020 20:18:52 -0500 Subject: [PATCH 031/219] JSONize AEP_EVIL and implement intermittent artifact effects (#38221) --- data/json/legacy_artifact_passive.json | 16 ++++++++++++++++ src/magic_enchantment.cpp | 12 +++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/data/json/legacy_artifact_passive.json b/data/json/legacy_artifact_passive.json index 20924033ff565..f7ab1028403f8 100644 --- a/data/json/legacy_artifact_passive.json +++ b/data/json/legacy_artifact_passive.json @@ -72,5 +72,21 @@ "type": "enchantment", "id": "AEP_SPEED_DOWN", "values": [ { "value": "SPEED", "add": -20 } ] + }, + { + "type": "SPELL", + "id": "AEP_EVIL_SPELL", + "name": "EEEEEEVVVVVIIIIILLLL!", + "description": "You debugged in this spell! It makes you evil for 30 minutes.", + "valid_targets": [ "hostile", "ally", "self" ], + "effect": "target_attack", + "effect_str": "evil", + "min_duration": 180000, + "max_duration": 180000 + }, + { + "type": "enchantment", + "id": "AEP_EVIL", + "intermittent_activation": { "effects": [ { "frequency": "15 minutes", "spell_effects": [ { "id": "AEP_EVIL_SPELL" } ] } ] } } ] diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index e095fdd84644d..d2b222fdd70bd 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -200,7 +200,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) if( jo.has_object( "intermittent_activation" ) ) { JsonObject jobj = jo.get_object( "intermittent_activation" ); - for( const JsonObject effect_obj : jo.get_array( "effects" ) ) { + for( const JsonObject effect_obj : jobj.get_array( "effects" ) ) { time_duration dur = read_from_json_string( *effect_obj.get_raw( "frequency" ), time_duration::units ); if( effect_obj.has_array( "spell_effects" ) ) { @@ -374,6 +374,16 @@ void enchantment::activate_passive( Character &guy ) const guy.mod_num_dodges_bonus( get_value_add( mod::BONUS_DODGE ) ); guy.mod_num_dodges_bonus( mult_bonus( mod::BONUS_DODGE, guy.get_num_dodges_base() ) ); + + for( const std::pair> &activation : + intermittent_activation ) { + // a random approximation! + if( one_in( to_seconds( activation.first ) ) ) { + for( const fake_spell &fake : activation.second ) { + fake.get_spell( 0 ).cast_all_effects( guy, guy.pos() ); + } + } + } } void enchantment::cast_hit_you( Character &caster, const tripoint &target ) const From b3d0b28236624f25afaa7f6df8f29867923ac6c9 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Thu, 12 Mar 2020 13:05:36 -0400 Subject: [PATCH 032/219] JSONize AEP_SMOKE and add emitters to enchantments (#38260) --- data/json/emit.json | 9 +++++++++ data/json/legacy_artifact_passive.json | 5 +++++ src/magic_enchantment.cpp | 8 ++++++++ src/magic_enchantment.h | 1 + 4 files changed, 23 insertions(+) diff --git a/data/json/emit.json b/data/json/emit.json index 6fb5cc798f6d9..f4f15d0f76d2d 100644 --- a/data/json/emit.json +++ b/data/json/emit.json @@ -15,6 +15,15 @@ "intensity": 3, "chance": 2 }, + { + "id": "emit_AEP_SMOKE", + "type": "emit", + "//": "Intermittent smoke from an artifact", + "field": "fd_smoke", + "intensity": 3, + "chance": 5, + "qty": 15 + }, { "id": "emit_smoke_blast", "type": "emit", diff --git a/data/json/legacy_artifact_passive.json b/data/json/legacy_artifact_passive.json index f7ab1028403f8..ed052a7bc71fa 100644 --- a/data/json/legacy_artifact_passive.json +++ b/data/json/legacy_artifact_passive.json @@ -73,6 +73,11 @@ "id": "AEP_SPEED_DOWN", "values": [ { "value": "SPEED", "add": -20 } ] }, + { + "type": "enchantment", + "id": "AEP_SMOKE", + "emitter": "emit_AEP_SMOKE" + }, { "type": "SPELL", "id": "AEP_EVIL_SPELL", diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index d2b222fdd70bd..8c6f0f700cb9f 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -1,6 +1,7 @@ #include "magic_enchantment.h" #include "character.h" +#include "emit.h" #include "enum_conversions.h" #include "game.h" #include "generic_factory.h" @@ -197,6 +198,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) jo.read( "hit_you_effect", hit_you_effect ); jo.read( "hit_me_effect", hit_me_effect ); + jo.read( "emitter", emitter ); if( jo.has_object( "intermittent_activation" ) ) { JsonObject jobj = jo.get_object( "intermittent_activation" ); @@ -250,6 +252,9 @@ void enchantment::serialize( JsonOut &jsout ) const jsout.member( "has", io::enum_to_string( active_conditions.first ) ); jsout.member( "condition", io::enum_to_string( active_conditions.second ) ); + if( emitter ) { + jsout.member( "emitter", emitter ); + } if( !hit_you_effect.empty() ) { jsout.member( "hit_you_effect", hit_you_effect ); @@ -375,6 +380,9 @@ void enchantment::activate_passive( Character &guy ) const guy.mod_num_dodges_bonus( get_value_add( mod::BONUS_DODGE ) ); guy.mod_num_dodges_bonus( mult_bonus( mod::BONUS_DODGE, guy.get_num_dodges_base() ) ); + if( emitter ) { + g->m.emit_field( guy.pos(), *emitter ); + } for( const std::pair> &activation : intermittent_activation ) { // a random approximation! diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 9fce4e38b0b8f..e8d66b3aa293b 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -138,6 +138,7 @@ class enchantment // casts all the hit_me_effects on self void cast_hit_me( Character &caster ) const; private: + cata::optional emitter; // values that add to the base value std::map values_add; // values that get multiplied to the base value From 4e00d6b9daf2ad6bd5e1f7ae2dcd78777680d493 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 11 Mar 2020 02:56:16 -0400 Subject: [PATCH 033/219] Traps can cast spells (#38122) --- data/mods/Magiclysm/Spells/monsterspells.json | 18 ++++++++++++++++++ data/mods/Magiclysm/traps.json | 15 +++++++++++++++ src/trap.cpp | 1 + src/trap.h | 4 ++++ src/trapfunc.cpp | 15 +++++++++++++++ 5 files changed, 53 insertions(+) create mode 100644 data/mods/Magiclysm/traps.json diff --git a/data/mods/Magiclysm/Spells/monsterspells.json b/data/mods/Magiclysm/Spells/monsterspells.json index 7976d85806aee..713afe9505de4 100644 --- a/data/mods/Magiclysm/Spells/monsterspells.json +++ b/data/mods/Magiclysm/Spells/monsterspells.json @@ -17,6 +17,24 @@ "effect": "projectile_attack", "extra_effects": [ { "id": "light_healing", "hit_self": true } ] }, + { + "id": "bear_trap", + "type": "SPELL", + "name": "Bear Trap", + "description": "A trap that summons bears! Not what you were expecting, is it?", + "valid_targets": [ "ground" ], + "flags": [ "HOSTILE_SUMMON", "LOUD" ], + "min_damage": 3, + "max_damage": 3, + "min_aoe": 5, + "max_aoe": 5, + "sound_description": "\"It's a trap!\"", + "min_duration": 30000, + "max_duration": 30000, + "sound_type": "speech", + "effect": "summon", + "effect_str": "mon_bear" + }, { "id": "rocket_punch", "type": "SPELL", diff --git a/data/mods/Magiclysm/traps.json b/data/mods/Magiclysm/traps.json new file mode 100644 index 0000000000000..278152784cf32 --- /dev/null +++ b/data/mods/Magiclysm/traps.json @@ -0,0 +1,15 @@ +[ + { + "type": "trap", + "id": "tr_bear", + "name": "bear trap", + "color": "blue", + "symbol": "^", + "action": "spell", + "visibility": 2, + "trap_radius": 2, + "avoidance": 99, + "difficulty": 99, + "spell_data": { "id": "bear_trap" } + } +] diff --git a/src/trap.cpp b/src/trap.cpp index 256a5f505217f..adbf172facd78 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -116,6 +116,7 @@ void trap::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "funnel_radius", funnel_radius_mm, 0 ); optional( jo, was_loaded, "comfort", comfort, 0 ); optional( jo, was_loaded, "floor_bedding_warmth", floor_bedding_warmth, 0 ); + optional( jo, was_loaded, "spell_data", spell_data ); assign( jo, "trigger_weight", trigger_weight ); for( const JsonValue entry : jo.get_array( "drops" ) ) { std::string item_type; diff --git a/src/trap.h b/src/trap.h index d93fcb6d76e85..038a66793e6f8 100644 --- a/src/trap.h +++ b/src/trap.h @@ -10,6 +10,7 @@ #include "color.h" #include "int_id.h" +#include "magic.h" #include "string_id.h" #include "translations.h" #include "type_id.h" @@ -62,6 +63,7 @@ bool shadow( const tripoint &p, Creature *c, item *i ); bool map_regen( const tripoint &p, Creature *c, item *i ); bool drain( const tripoint &p, Creature *c, item *i ); bool snake( const tripoint &p, Creature *c, item *i ); +bool cast_spell( const tripoint &p, Creature *critter, item * ); } // namespace trapfunc struct vehicle_handle_trap_data { @@ -116,6 +118,8 @@ struct trap { // For disassembly? std::vector> components; public: + // data required for trapfunc::spell() + fake_spell spell_data; int comfort = 0; int floor_bedding_warmth = 0; public: diff --git a/src/trapfunc.cpp b/src/trapfunc.cpp index 61b1daefeb034..0969e13227ab6 100644 --- a/src/trapfunc.cpp +++ b/src/trapfunc.cpp @@ -17,6 +17,7 @@ #include "messages.h" #include "monster.h" #include "mtype.h" +#include "npc.h" #include "output.h" #include "overmapbuffer.h" #include "rng.h" @@ -1376,6 +1377,19 @@ bool trapfunc::drain( const tripoint &, Creature *c, item * ) return false; } +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 ); + npc dummy; + trap_spell.cast_all_effects( dummy, critter->pos() ); + trap_spell.make_sound( p, 20 ); + g->m.remove_trap( p ); + return true; +} + bool trapfunc::snake( const tripoint &p, Creature *, item * ) { //~ the sound a snake makes @@ -1449,6 +1463,7 @@ const trap_function &trap_function_from_string( const std::string &function_name { "shadow", trapfunc::shadow }, { "map_regen", trapfunc::map_regen }, { "drain", trapfunc::drain }, + { "spell", trapfunc::cast_spell }, { "snake", trapfunc::snake } } }; From 28aa593051b4a6d56cadf163a1d70f156df245a5 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 6 Mar 2020 03:39:54 -0700 Subject: [PATCH 034/219] Add subway maps (#37540) --- data/json/items/book/maps.json | 17 ++++++++++++++++- data/json/mapgen/sub_station.json | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/data/json/items/book/maps.json b/data/json/items/book/maps.json index 095d1ac6720df..a599ac57fc740 100644 --- a/data/json/items/book/maps.json +++ b/data/json/items/book/maps.json @@ -71,12 +71,27 @@ "hospital", "school", "police", - "sub_station", + { "om_terrain": "sub_station", "om_terrain_match_type": "TYPE" }, "bank" ], "message": "You add roads and points of interest to your map." } }, + { + "id": "subwaymap", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": "subway maintenance map", + "looks_like": "roadmap", + "description": "This is a map of subway tunnels formerly used by public maintenance workers. Using it will add subway lines and underground stations to your map.", + "color": "light_blue", + "use_action": { + "type": "reveal_map", + "radius": 180, + "terrain": [ "subway", "sub_station" ], + "message": "You add subway lines and underground stations to your map." + } + }, { "id": "trailmap", "copy-from": "abstractmap", diff --git a/data/json/mapgen/sub_station.json b/data/json/mapgen/sub_station.json index 5881e8d04d858..200c1be0667f0 100644 --- a/data/json/mapgen/sub_station.json +++ b/data/json/mapgen/sub_station.json @@ -106,7 +106,8 @@ ], "palettes": [ "subway_underground" ], "vendingmachines": { "J": { "item_group": "vending_drink" }, "C": { "item_group": "vending_food" } }, - "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 6, 20 ], "y": [ 4, 9 ], "repeat": [ 5, 9 ] } ] + "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 6, 20 ], "y": [ 4, 9 ], "repeat": [ 5, 9 ] } ], + "place_item": [ { "item": "subwaymap", "x": 1, "y": [ 6, 7 ], "chance": 75 } ] } }, { From aa58733ef41061803de5f91adc8d856ed1f2f4e3 Mon Sep 17 00:00:00 2001 From: Karthas077 Date: Fri, 6 Mar 2020 02:41:15 -0800 Subject: [PATCH 035/219] Add The Satanic Bible (#37806) --- data/json/itemgroups/books.json | 3 +- data/json/items/book/misc.json | 39 ++++++++++++++++------- data/json/npcs/items_generic.json | 1 + data/mods/No_Religious_Books/modinfo.json | 3 +- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/data/json/itemgroups/books.json b/data/json/itemgroups/books.json index 96d1053bb9305..c859cea94334b 100644 --- a/data/json/itemgroups/books.json +++ b/data/json/itemgroups/books.json @@ -157,7 +157,8 @@ [ "holybook_pastafarian", 1 ], [ "holybook_slack", 1 ], [ "holybook_kallisti", 1 ], - [ "holybook_scientology", 1 ] + [ "holybook_scientology", 1 ], + [ "holybook_satanic", 1 ] ] }, { diff --git a/data/json/items/book/misc.json b/data/json/items/book/misc.json index 761eea45f34c1..1e577c457badb 100644 --- a/data/json/items/book/misc.json +++ b/data/json/items/book/misc.json @@ -323,7 +323,7 @@ "name": { "str": "Hadith", "str_pl": "copies of Hadith" }, "description": "A Muslim religious text containing an account of the sayings and actions of the prophet Muhammad.", "weight": "398 g", - "volume": "1 L", + "volume": "500 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -340,7 +340,7 @@ "name": { "str": "Principia Discordia", "str_pl": "copies of Principia Discordia" }, "description": "A book that embodies the main beliefs of Discordianism. It seems to primarily concern chaos, and features a card in the back which informs you that you are now a 'genuine and authorized Pope of Discordia'.", "weight": "292 g", - "volume": "1 L", + "volume": "150 ml", "price": 550, "price_postapoc": 2323, "material": [ "paper" ], @@ -357,7 +357,7 @@ "name": { "str": "The Kojiki", "str_pl": "copies of The Kojiki" }, "description": "The oldest extant chronicle of Japan's myths and history, the stories contained in the Kojiki are part of the inspiration behind Shinto practices.", "weight": "368 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -374,7 +374,7 @@ "name": { "str": "The Book of Mormon", "str_pl": "copies of The Book of Mormon" }, "description": "The sacred text of the Latter Day Saint movement of Christianity, originally published in 1830 by Joseph Smith.", "weight": "368 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -394,7 +394,7 @@ }, "description": "A book that embodies the main beliefs of the Church of the Flying Spaghetti Monster. It seems to involve a lot of pirates and some sort of invisible drunken monster made of pasta.", "weight": "292 g", - "volume": "1 L", + "volume": "500 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -411,7 +411,7 @@ "name": { "str": "Quran", "str_pl": "copies of Quran" }, "description": "An English translation of the Muslim book of holy scriptures, with explanatory notes and commentaries to aid in understanding.", "weight": "412 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -428,7 +428,7 @@ "name": { "str": "Dianetics", "str_pl": "copies of Dianetics" }, "description": "This book is the canonical text of Scientology. Written by a science fiction author, it contains self-improvement techniques and musings on psychology called Dianetics.", "weight": "486 g", - "volume": "1 L", + "volume": "1300 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -445,7 +445,7 @@ "name": { "str": "The Book of the SubGenius", "str_pl": "copies of The Book of the SubGenius" }, "description": "A book about the Church of the SubGenius. It seems to involve a salesman named J. R. \"Bob\" Dobbs and a concept called 'slack'.", "weight": "292 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -496,7 +496,7 @@ "name": { "str": "Tanakh", "str_pl": "copies of Tanakh" }, "description": "A single-volume book containing the complete canon of the Jewish Bible.", "weight": "512 g", - "volume": "1 L", + "volume": "1800 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -530,7 +530,7 @@ "name": { "str": "The Upanishads", "str_pl": "copies of The Upanishads" }, "description": "A collection of sacred Hindu writings regarding the nature of reality and describing the character and form of human salvation.", "weight": "482 g", - "volume": "1 L", + "volume": "750 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -547,7 +547,24 @@ "name": { "str": "The Four Vedas", "str_pl": "copies of The Four Vedas" }, "description": "A single volume containing all four Vedas, which are the oldest scriptures of Hinduism.", "weight": "540 g", - "volume": "1 L", + "volume": "1700 ml", + "price": 550, + "price_postapoc": 550, + "material": [ "paper" ], + "symbol": "?", + "color": "dark_gray", + "intelligence": 8, + "time": "10 m", + "fun": 1, + "flags": [ "INSPIRATIONAL" ] + }, + { + "id": "holybook_satanic", + "type": "BOOK", + "name": { "str": "The Satanic Bible", "str_pl": "copies of The Satanic Bible" }, + "description": "A collection of essays, observations, and rituals published by Anton LaVey in 1969.", + "weight": "130 g", + "volume": "250 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], diff --git a/data/json/npcs/items_generic.json b/data/json/npcs/items_generic.json index 1292d75184641..609959db1da90 100644 --- a/data/json/npcs/items_generic.json +++ b/data/json/npcs/items_generic.json @@ -611,6 +611,7 @@ [ "holybook_mormon", 1 ], [ "holybook_pastafarian", 1 ], [ "holybook_quran", 2 ], + [ "holybook_satanic", 1 ], [ "holybook_scientology", 1 ], [ "holybook_slack", 1 ], [ "holybook_sutras", 2 ], diff --git a/data/mods/No_Religious_Books/modinfo.json b/data/mods/No_Religious_Books/modinfo.json index 0b15b033e6a8b..11d936d70b156 100644 --- a/data/mods/No_Religious_Books/modinfo.json +++ b/data/mods/No_Religious_Books/modinfo.json @@ -31,7 +31,8 @@ "holybook_pastafarian", "holybook_slack", "holybook_kallisti", - "holybook_scientology" + "holybook_scientology", + "holybook_satanic" ] } ] From 7ad5914db8e6651a212411e12f396317a31c9782 Mon Sep 17 00:00:00 2001 From: Ashes <58862150+ashGlaw@users.noreply.github.com> Date: Tue, 10 Mar 2020 05:06:18 -0400 Subject: [PATCH 036/219] Indian cookbook (#37930) --- .../Locations_MapExtras/mansion.json | 1 + data/json/itemgroups/books.json | 4 ++++ .../json/itemgroups/collections_domestic.json | 1 + data/json/items/book/cooking.json | 21 +++++++++++++++++++ data/json/recipes/food/dairy_products.json | 2 +- data/json/recipes/recipe_food.json | 5 +++-- 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/data/json/itemgroups/Locations_MapExtras/mansion.json b/data/json/itemgroups/Locations_MapExtras/mansion.json index 261ae73a4ebc8..7a23ef26d3d0f 100644 --- a/data/json/itemgroups/Locations_MapExtras/mansion.json +++ b/data/json/itemgroups/Locations_MapExtras/mansion.json @@ -808,6 +808,7 @@ [ "tongs", 25 ], [ "coffeemaker", 10 ], [ "cookbook_daintydishes", 40 ], + [ "cookbook_indian", 10 ], [ "cookbook_foodfashions", 18 ] ] }, diff --git a/data/json/itemgroups/books.json b/data/json/itemgroups/books.json index c859cea94334b..d0fbddd6b6c85 100644 --- a/data/json/itemgroups/books.json +++ b/data/json/itemgroups/books.json @@ -264,6 +264,7 @@ [ "cookbook_liverforkids", 15 ], [ "cookbook_eatyrway", 15 ], [ "cookbook_foodfashions", 10 ], + [ "cookbook_indian", 10 ], [ "survnote", 1 ], [ "scots_cookbook", 8 ], [ "offalcooking", 2 ], @@ -314,6 +315,7 @@ [ "cookbook", 35 ], [ "offalcooking", 8 ], [ "cookbook_italian", 25 ], + [ "cookbook_indian", 10 ], [ "manual_electronics", 20 ], [ "manual_tailor", 15 ], [ "manual_carpentry", 10 ], @@ -359,6 +361,7 @@ [ "tailor_portfolio", 3 ], [ "textbook_chemistry", 11 ], [ "brewing_cookbook", 3 ], + [ "cookbook_indian", 5 ], [ "textbook_carpentry", 6 ], [ "SICP", 3 ], [ "survival_book", 8 ], @@ -458,6 +461,7 @@ [ "cookbook_human", 10 ], [ "collector_book", 10 ], [ "brewing_cookbook", 24 ], + [ "cookbook_indian", 10 ], [ "textbook_robots", 15 ], [ "manual_dodge", 15 ], [ "novel_experimental", 24 ], diff --git a/data/json/itemgroups/collections_domestic.json b/data/json/itemgroups/collections_domestic.json index 484b55de0c7a9..0b77905af551e 100644 --- a/data/json/itemgroups/collections_domestic.json +++ b/data/json/itemgroups/collections_domestic.json @@ -489,6 +489,7 @@ [ "funnel", 50 ], [ "vac_sealer", 10 ], [ "cookbook_italian", 10 ], + [ "cookbook_indian", 10 ], [ "cookbook_liverforkids", 10 ], [ "cookbook_foodfashions", 7 ], [ "cookbook_daintydishes", 10 ], diff --git a/data/json/items/book/cooking.json b/data/json/items/book/cooking.json index 7bd37a7b11305..fe972761f991c 100644 --- a/data/json/items/book/cooking.json +++ b/data/json/items/book/cooking.json @@ -524,5 +524,26 @@ "max_level": 4, "intelligence": 7, "copy-from": "cookbook_liverforkids" + }, + { + "id": "cookbook_indian", + "type": "BOOK", + "name": { "str": "Tasting India", "str_pl": "copies of Tasting India" }, + "//": "Statistics derived from a real book.", + "description": "A thick hardcover book as much about Indian culture as it is a cookbook, clearly written with adoration.", + "weight": "2950 g", + "volume": "3215 ml", + "price": 6000, + "price_postapoc": 10000, + "bashing": 7, + "material": [ "paper" ], + "symbol": "?", + "color": "yellow", + "skill": "cooking", + "required_level": 1, + "max_level": 3, + "intelligence": 7, + "time": "20 m", + "fun": 1 } ] diff --git a/data/json/recipes/food/dairy_products.json b/data/json/recipes/food/dairy_products.json index beaab800ef9a0..a4b11a732ff1e 100644 --- a/data/json/recipes/food/dairy_products.json +++ b/data/json/recipes/food/dairy_products.json @@ -46,7 +46,7 @@ "skill_used": "cooking", "difficulty": 2, "charges": 1, - "book_learn": [ [ "cookbook", 1 ] ], + "book_learn": [ [ "cookbook_indian", 1 ] ], "time": "30 m", "batch_time_factors": [ 80, 4 ], "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "COOK", "level": 2 } ], diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index d2e856113a851..02ef36ba64663 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -2119,6 +2119,7 @@ "charges": 2, "batch_time_factors": [ 50, 4 ], "autolearn": true, + "book_learn": [ [ "cookbook_indian", 1 ], [ "cookbook", 1 ] ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ [ [ "flour", 11 ] ], [ [ "water", 2 ], [ "water_clean", 2 ] ] ] @@ -3411,7 +3412,7 @@ "skill_used": "cooking", "difficulty": 2, "time": "20 m", - "autolearn": true, + "book_learn": [ [ "cookbook_indian", 1 ] ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ @@ -3446,7 +3447,7 @@ "skill_used": "cooking", "difficulty": 2, "time": "20 m", - "autolearn": true, + "book_learn": [ [ "cookbook_indian", 1 ] ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ From 106dece6284b36273ff3e9347fbe5e184c952c13 Mon Sep 17 00:00:00 2001 From: RarkGrames <50421549+RarkGrames@users.noreply.github.com> Date: Tue, 10 Mar 2020 10:11:25 +0100 Subject: [PATCH 037/219] AR pistols (#37768) --- .../itemgroups/Weapons_Mods_Ammo/guns.json | 3 ++ data/json/items/gun/223.json | 46 +++++++++++++++++++ .../firearms/gg_firearms_migration.json | 2 + 3 files changed, 51 insertions(+) diff --git a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json index 3424eaec673a8..d3c512ed4cdb9 100644 --- a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json +++ b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json @@ -167,6 +167,7 @@ "//": "Rifles commonly owned by citizens and found in many locations.", "items": [ { "item": "browning_blr", "prob": 25, "charges-min": 0, "charges-max": 4 }, + { "item": "ar_pistol", "prob": 52, "charges-min": 0, "charges-max": 30 }, { "item": "garand", "prob": 65, "charges-min": 0, "charges-max": 8 }, { "item": "ar10", "prob": 20, "charges-min": 0, "charges-max": 20 }, { "item": "ar15", "prob": 30, "charges-min": 0, "charges-max": 30 }, @@ -261,6 +262,7 @@ { "item": "bfg50", "prob": 5, "charges-min": 0, "charges-max": 1 }, { "item": "carbine_flintlock", "prob": 140 }, { "item": "rifle_flintlock", "prob": 180 }, + { "item": "oa93", "prob": 3, "charges-min": 0, "charges-max": 30 }, { "item": "steyr_aug", "prob": 40, "charges-min": 0, "charges-max": 30 }, { "item": "trex_gun", "prob": 60 }, { "item": "arx160", "prob": 40, "charges-min": 0, "charges-max": 30 }, @@ -548,6 +550,7 @@ "items": [ { "group": "guns_improvised", "prob": 200 }, { "item": "ar15", "prob": 5, "charges-min": 0, "charges-max": 30 }, + { "item": "ar_pistol", "prob": 3, "charges-min": 0, "charges-max": 30 }, { "item": "mossberg_500", "prob": 5, "charges-min": 0, "charges-max": 8 }, { "item": "remington_870", "prob": 5, "charges-min": 0, "charges-max": 6 }, { "item": "ruger_1022", "prob": 15, "charges-min": 0, "charges-max": 10 }, diff --git a/data/json/items/gun/223.json b/data/json/items/gun/223.json index 552d0d271edfb..958cb9bf4d437 100644 --- a/data/json/items/gun/223.json +++ b/data/json/items/gun/223.json @@ -45,6 +45,29 @@ "min_cycle_recoil": 1350, "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] }, + { + "id": "ar_pistol", + "copy-from": "rifle_semi", + "looks_like": "skorpion_61", + "type": "GUN", + "name": { "str": "AR pistol" }, + "description": "A compact, 7.5 inch barrel version of the classic AR-15 design, commercially marketed as a home defense weapon.", + "weight": "2267 g", + "volume": "1758 ml", + "price": 91400, + "to_hit": -2, + "bashing": 9, + "material": [ "steel", "aluminum" ], + "symbol": "(", + "color": "dark_gray", + "ammo": "223", + "range": -6, + "ranged_damage": -9, + "dispersion": 380, + "durability": 6, + "min_cycle_recoil": 1350, + "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] + }, { "id": "h&k416a5", "copy-from": "rifle_auto", @@ -184,6 +207,29 @@ "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ] ], "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] }, + { + "id": "oa93", + "copy-from": "rifle_semi", + "looks_like": "skorpion_61", + "type": "GUN", + "name": { "str": "OA-93" }, + "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", + "price": 125000, + "to_hit": -2, + "bashing": 9, + "material": [ "steel", "aluminum" ], + "symbol": "(", + "color": "dark_gray", + "ammo": "223", + "range": -6, + "ranged_damage": -11, + "dispersion": 380, + "durability": 6, + "min_cycle_recoil": 1350, + "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] + }, { "id": "rifle_223", "copy-from": "gun_base", diff --git a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json index 9e670dda9d701..70081298fc4e6 100644 --- a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json +++ b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json @@ -247,6 +247,8 @@ "arx160", "mosin91_30", "ar15", + "oa93", + "ar_pistol", "ruger_mini", "sig552", "steyr_aug", From 095118cd00aa33abbe3b07723b1f6fe9dced162b Mon Sep 17 00:00:00 2001 From: xanderrootslayer <46512498+xanderrootslayer@users.noreply.github.com> Date: Tue, 10 Mar 2020 05:14:07 -0400 Subject: [PATCH 038/219] SUS bathroom 3.5 (#37431) --- data/json/itemgroups/SUS/domestic.json | 60 ++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/data/json/itemgroups/SUS/domestic.json b/data/json/itemgroups/SUS/domestic.json index 626fc737a1cc7..6bd7b9ac804b2 100644 --- a/data/json/itemgroups/SUS/domestic.json +++ b/data/json/itemgroups/SUS/domestic.json @@ -606,14 +606,47 @@ "//2": "This group is for a bathroom sink.", "subtype": "collection", "entries": [ + { "item": "soap", "count": [ 1, 4 ], "prob": 75 }, { "item": "soap_holder", "prob": 40 }, - { "item": "soap", "count": [ 1, 4 ], "prob": 90 }, { "item": "razor_shaving", "count": [ 1, 2 ], "prob": 20 }, + { "item": "cotton_ball", "prob": 50 }, { "item": "bleach", "prob": 15 }, { "item": "ammonia", "prob": 20 }, + { "item": "string_floss", "count": [ 1, 2 ], "prob": 60 }, { "item": "toothbrush_plain", "count": [ 1, 3 ], "prob": 45 } ] }, + { + "id": "SUS_bathroom_medicine", + "type": "item_group", + "//": "SUS item groups are collections that contain a reasonable realistic distribution of items that might spawn in a given storage furniture.", + "//2": "This group is for the medicine cabinet.", + "subtype": "collection", + "entries": [ + { + "distribution": [ { "item": "aspirin", "prob": 160 }, { "item": "codeine", "prob": 30 }, { "item": "tramadol", "prob": 10 } ], + "prob": 95 + }, + { "item": "eyedrops", "prob": 15 }, + { "item": "pepto", "prob": 70 }, + { "item": "inhaler", "prob": 25 }, + { "item": "pills_sleep", "prob": 10 }, + { "distribution": [ { "item": "nyquil", "prob": 60 }, { "item": "dayquil", "prob": 20 } ], "prob": 50 }, + { + "distribution": [ + { "item": "vitamins", "prob": 60 }, + { "item": "gummy_vitamins", "prob": 20 }, + { "item": "calcium_tablet", "prob": 10 } + ], + "prob": 80 + }, + { + "distribution": [ { "item": "weak_antibiotic", "prob": 40 }, { "item": "antibiotics", "prob": 10 } ], + "prob": 10 + }, + { "distribution": [ { "item": "antifungal", "prob": 60 }, { "item": "antiparasitic", "prob": 20 } ], "prob": 5 } + ] + }, { "id": "SUS_hair_drawer", "type": "item_group", @@ -623,9 +656,10 @@ "entries": [ { "item": "hairbrush", "count": [ 1, 2 ], "prob": 90 }, { "item": "comb_pocket", "count": [ 1, 2 ], "prob": 75 }, - { "item": "curler_hair", "prob": 25 }, + { "item": "scissors", "count": [ 1, 2 ], "prob": 60 }, { "item": "hair_dryer", "prob": 60 }, - { "item": "curling_iron", "prob": 20 } + { "collection": [ { "item": "curling_iron", "count": [ 1, 2 ] }, { "item": "curler_hair" } ], "prob": 25 }, + { "item": "elec_hairtrimmer", "prob": 30 } ] }, { @@ -635,16 +669,20 @@ "//2": "This group is for things you often find stored on or next to a toilet.", "subtype": "collection", "entries": [ - { "distribution": [ { "item": "plunger_toilet", "prob": 90 }, { "item": "plunger_futuristic", "prob": 10 } ] }, + { + "distribution": [ { "item": "plunger_toilet", "prob": 90 }, { "item": "plunger_futuristic", "prob": 10 } ], + "prob": 90 + }, { "item": "brush_toilet", "prob": 75 }, - { "item": "toilet_paper", "prob": 80 } + { "item": "toilet_paper", "prob": 95, "container-item": "wrapper" }, + { "item": "bathroom_scale", "prob": 50 } ] }, { "id": "SUS_bathroom_cabinet", "type": "item_group", "//": "SUS item groups are collections that contain a reasonable realistic distribution of items that might spawn in a given storage furniture.", - "//2": "This group is for a bathroom cabinet.", + "//2": "This group is for a bathroom cabinet under the sink.", "subtype": "collection", "entries": [ { "item": "soap", "count": [ 1, 4 ], "prob": 70 }, @@ -652,11 +690,17 @@ "distribution": [ { "item": "razor_shaving", "count": [ 1, 2 ], "prob": 50 }, { "item": "shavingkit", "prob": 50 } ], "prob": 75 }, + { + "distribution": [ { "item": "bandages", "prob": 60 }, { "item": "medical_gauze", "prob": 20 }, { "item": "1st_aid", "prob": 10 } ], + "prob": 20 + }, + { "item": "disinfectant", "prob": 40 }, + { "item": "chem_hydrogen_peroxide", "prob": 50 }, { "item": "mirror", "prob": 25 }, - { "item": "string_floss", "count": [ 1, 2 ], "prob": 60 }, { "item": "sponge", "count": [ 1, 3 ], "prob": 75 }, { "collection": [ { "item": "candle", "count": [ 1, 2 ] }, { "item": "matches" } ], "prob": 20 }, - { "item": "toilet_paper", "prob": 80 } + { "item": "toilet_paper", "prob": 80 }, + { "item": "towel", "count": [ 1, 2 ], "prob": 75 } ] }, { From 2a009736a7047f3684e98e32ea739ef124a90048 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Tue, 10 Mar 2020 21:59:22 +0100 Subject: [PATCH 039/219] Add map_bash_info to fields (#37865) --- data/json/field_type.json | 8 ++++++ .../My_Sweet_Cataclysm/sweet_field_type.json | 9 ++++++ doc/JSON_INFO.md | 17 +++++++++++ src/field_type.cpp | 1 + src/field_type.h | 2 ++ src/handle_action.cpp | 28 +++++++++++++++---- src/mapdata.cpp | 27 +++++++++++------- src/mapdata.h | 9 +++++- 8 files changed, 84 insertions(+), 17 deletions(-) diff --git a/data/json/field_type.json b/data/json/field_type.json index 62edc326ade03..a9c4e1daf7618 100644 --- a/data/json/field_type.json +++ b/data/json/field_type.json @@ -82,6 +82,14 @@ "priority": 2, "phase": "solid", "display_items": false, + "bash": { + "str_min": 1, + "str_max": 3, + "sound_vol": 2, + "sound_fail_vol": 2, + "sound": "hsh!", + "msg_success": "You brush aside some webs." + }, "display_field": true }, { diff --git a/data/mods/My_Sweet_Cataclysm/sweet_field_type.json b/data/mods/My_Sweet_Cataclysm/sweet_field_type.json index 6c3cd61622f07..77c43ffcd5850 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_field_type.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_field_type.json @@ -58,6 +58,15 @@ "priority": 2, "phase": "solid", "half_life": "2 h", + "bash": { + "str_min": 1, + "str_max": 3, + "sound_vol": 2, + "sound_fail_vol": 2, + "sound": "shwip", + "sound_fail": "shwomp", + "msg_success": "You brush the gum web aside." + }, "display_items": false, "display_field": true }, diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 770e5b2e50c16..b31c3ce06e8e5 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -3012,4 +3012,21 @@ Setting of sprite sheets. Same as `tiles-new` field in `tile_config`. Sprite fil "type": "field_type", // this is a field type "id": "fd_gum_web", // id of the field "immune_mtypes": [ "mon_spider_gum" ], // list of monster immune to this field + "bash": { + "str_min": 1, // lower bracket of bashing damage required to bash + "str_max": 3, // higher bracket + "sound_vol": 2, // noise made when succesfully bashing the field + "sound_fail_vol": 2, // noise made when failing to bash the field + "sound": "shwip", // sound on success + "sound_fail": "shwomp", // sound on failure + "msg_success": "You brush the gum web aside.", // message on success + "move_cost": 120, // how many moves it costs to succesfully bash that field (default: 100) + "items": [ // item dropped upon succesful bashing + { "item": "2x4", "count": [ 5, 8 ] }, + { "item": "nail", "charges": [ 6, 8 ] }, + { "item": "splinter", "count": [ 3, 6 ] }, + { "item": "rag", "count": [ 40, 55 ] }, + { "item": "scrap", "count": [ 10, 20 ] } + ] + } } diff --git a/src/field_type.cpp b/src/field_type.cpp index f35fdc83a6512..891f435c113c0 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -244,6 +244,7 @@ void field_type::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "display_field", display_field, false ); optional( jo, was_loaded, "wandering_field", wandering_field_id, "fd_null" ); + bash_info.load( jo, "bash", map_bash_info::field ); if( was_loaded && jo.has_member( "copy-from" ) && looks_like.empty() ) { looks_like = jo.get_string( "copy-from" ); } diff --git a/src/field_type.h b/src/field_type.h index 7302b51f09b8b..d2af7b846ea48 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -15,6 +15,7 @@ #include "color.h" #include "effect.h" #include "enums.h" +#include "mapdata.h" #include "type_id.h" #include "string_id.h" #include "translations.h" @@ -143,6 +144,7 @@ struct field_type { bool has_elec = false; bool has_fume = false; description_affix desc_affix = description_affix::DESCRIPTION_AFFIX_NUM; + map_bash_info bash_info; // chance, issue, duration, speech std::tuple npc_complain_data; diff --git a/src/handle_action.cpp b/src/handle_action.cpp index feb3af45c4825..c1ba6a5912912 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -674,12 +674,28 @@ static void smash() crit->use_mech_power( -3 ); } } - if( m.get_field( smashp, fd_web ) != nullptr ) { - m.remove_field( smashp, fd_web ); - sounds::sound( smashp, 2, sounds::sound_t::combat, _( "hsh!" ), true, "smash", "web" ); - add_msg( m_info, _( "You brush aside some webs." ) ); - u.moves -= 100; - return; + for( std::pair &fd_to_smsh : m.field_at( smashp ) ) { + const map_bash_info &bash_info = fd_to_smsh.first->bash_info; + if( bash_info.str_min == -1 ) { + continue; + } + if( smashskill < bash_info.str_min && one_in( 10 ) ) { + add_msg( m_neutral, _( "You don't seem to be damaging the %s." ), fd_to_smsh.first->get_name() ); + return; + } else if( smashskill >= rng( bash_info.str_min, bash_info.str_max ) ) { + sounds::sound( smashp, bash_info.sound_vol, sounds::sound_t::combat, bash_info.sound, true, "smash", + "field" ); + m.remove_field( smashp, fd_to_smsh.first ); + m.spawn_items( smashp, item_group::items_from( bash_info.drop_group, calendar::turn ) ); + u.mod_moves( - bash_info.fd_bash_move_cost ); + add_msg( m_info, bash_info.field_bash_msg_success.translated() ); + return; + } else { + sounds::sound( smashp, bash_info.sound_fail_vol, sounds::sound_t::combat, bash_info.sound_fail, + true, "smash", + "field" ); + return; + } } for( const auto &maybe_corpse : m.i_at( smashp ) ) { diff --git a/src/mapdata.cpp b/src/mapdata.cpp index f0f0101330290..cbc472d9b1847 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -198,7 +198,8 @@ map_bash_info::map_bash_info() : str_min( -1 ), str_max( -1 ), drop_group( "EMPTY_GROUP" ), ter_set( ter_str_id::NULL_ID() ), furn_set( furn_str_id::NULL_ID() ) {} -bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, bool is_furniture ) +bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, + map_object_type obj_type ) { if( !jsobj.has_object( member ) ) { return false; @@ -230,13 +231,19 @@ bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, bo j.read( "sound", sound ); j.read( "sound_fail", sound_fail ); - if( is_furniture ) { - furn_set = furn_str_id( j.get_string( "furn_set", "f_null" ) ); - } else { - const std::string ter_set_string = j.get_string( "ter_set" ); - ter_set = ter_str_id( ter_set_string ); - ter_set_bashed_from_above = ter_str_id( j.get_string( "ter_set_bashed_from_above", - ter_set_string ) ); + switch( obj_type ) { + case map_bash_info::furniture: + furn_set = furn_str_id( j.get_string( "furn_set", "f_null" ) ); + break; + case map_bash_info::terrain: + ter_set = ter_str_id( j.get_string( "ter_set" ) ); + ter_set_bashed_from_above = ter_str_id( j.get_string( "ter_set_bashed_from_above", + ter_set.c_str() ) ); + break; + case map_bash_info::field: + fd_bash_move_cost = j.get_int( "move_cost", 100 ); + j.read( "msg_success", field_bash_msg_success ); + break; } if( j.has_member( "items" ) ) { @@ -1166,7 +1173,7 @@ void ter_t::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "transforms_into", transforms_into, ter_str_id::NULL_ID() ); optional( jo, was_loaded, "roof", roof, ter_str_id::NULL_ID() ); - bash.load( jo, "bash", false ); + bash.load( jo, "bash", map_bash_info::terrain ); deconstruct.load( jo, "deconstruct", false ); } @@ -1269,7 +1276,7 @@ void furn_t::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "open", open, string_id_reader {}, furn_str_id::NULL_ID() ); optional( jo, was_loaded, "close", close, string_id_reader {}, furn_str_id::NULL_ID() ); - bash.load( jo, "bash", true ); + bash.load( jo, "bash", map_bash_info::furniture ); deconstruct.load( jo, "deconstruct", true ); if( jo.has_object( "workbench" ) ) { diff --git a/src/mapdata.h b/src/mapdata.h index 184d8abc270bf..b709dbe7bac64 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -39,18 +39,25 @@ struct map_bash_info { int sound_vol; // sound volume of breaking terrain/furniture int sound_fail_vol; // sound volume on fail int collapse_radius; // Radius of the tent supported by this tile + int fd_bash_move_cost = 100; // cost to bash a field bool destroy_only; // Only used for destroying, not normally bashable bool bash_below; // This terrain is the roof of the tile below it, try to destroy that too std::string drop_group; // item group of items that are dropped when the object is bashed translation sound; // sound made on success ('You hear a "smash!"') translation sound_fail; // sound made on fail + translation field_bash_msg_success; // message upon successfully bashing a field ter_str_id ter_set; // terrain to set (REQUIRED for terrain)) ter_str_id ter_set_bashed_from_above; // terrain to set if bashed from above (defaults to ter_set) furn_str_id furn_set; // furniture to set (only used by furniture, not terrain) // ids used for the special handling of tents std::vector tent_centers; map_bash_info(); - bool load( const JsonObject &jsobj, const std::string &member, bool is_furniture ); + enum map_object_type { + furniture = 0, + terrain, + field + }; + bool load( const JsonObject &jsobj, const std::string &member, map_object_type obj_type ); }; struct map_deconstruct_info { // Only if true, the terrain/furniture can be deconstructed From 4d03fa9d224963dd8ad8529daa1c157e377897ba Mon Sep 17 00:00:00 2001 From: dpwb Date: Tue, 4 Feb 2020 10:11:54 +0000 Subject: [PATCH 040/219] Add shot counter to mods and gun (#37693) --- src/ranged.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ranged.cpp b/src/ranged.cpp index 5767a4d98a0c2..ac2a787a40cf8 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -486,7 +486,11 @@ int player::fire_gun( const tripoint &target, int shots, item &gun ) continue; // skip retargeting for launchers } } - + // apply shot counter to gun and its mods. + gun.set_var( "shot_counter", gun.get_var( "shot_counter", 0 ) + curshot ); + for( item *mod : gun.gunmods() ) { + mod->set_var( "shot_counter", mod->get_var( "shot_counter", 0 ) + curshot ); + } // apply delayed recoil recoil += delay; if( is_mech_weapon ) { From 26ea0895fa2a7cf3cafd73a765511d257147f5c8 Mon Sep 17 00:00:00 2001 From: davidpwbrown <39344466+davidpwbrown@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:34:18 +0000 Subject: [PATCH 041/219] Allow professions to start with a nearby vehicle (#37314) Adds trucker profession. --- data/json/professions.json | 17 +++++++++++++ doc/JSON_INFO.md | 16 +++++++++--- src/game.cpp | 52 ++++++++++++++++++++++++++++++++++++++ src/game.h | 4 ++- src/newcharacter.cpp | 9 ++++++- src/overmapbuffer.cpp | 3 ++- src/player.h | 2 +- src/profession.cpp | 13 +++++++++- src/profession.h | 3 +++ src/string_id_null_ids.cpp | 1 + 10 files changed, 111 insertions(+), 9 deletions(-) diff --git a/data/json/professions.json b/data/json/professions.json index cfa565f1af588..a6a973384eb1b 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -1481,6 +1481,23 @@ "female": [ "bra", "panties" ] } }, + { + "type": "profession", + "ident": "trucker", + "name": "Trucker", + "description": "You ruled the road in your big rig and managed to drive it somewhere you hoped was safe when the riots hit. Now it's just you and your trusty truck cab.", + "points": 5, + "skills": [ { "level": 1, "name": "mechanics" }, { "level": 4, "name": "driving" } ], + "vehicle": "semi_truck", + "items": { + "both": { + "items": [ "tank_top", "socks", "boots_steel", "pants", "multitool", "wristwatch", "gloves_work", "hat_ball" ], + "entries": [ { "group": "charged_cell_phone" } ] + }, + "male": [ "boxer_shorts" ], + "female": [ "bra", "panties" ] + } + }, { "type": "profession", "ident": "lumberjack", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index b31c3ce06e8e5..303daab1d8aa4 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -814,12 +814,20 @@ Example for mods: This mod removes one of the rocks (the other rock is still created), the t-shirt, adds a 2x4 item and gives female characters a t-shirt with the special snippet id. -#### `pet` +#### `pets` -(optional, string mtype_id) +(optional, array of string mtype_ids ) -A string that is the same as a monster id -player will start with this as a tamed pet. +A list of strings, each is the same as a monster id +player will start with these as tamed pets. + +#### `vehicle` + +(optional, string vproto_id ) + +A string, which is the same as a vehicle ( vproto_id ) +player will start with this as a nearby vehicle. +( it will find the nearest road and place it there, then mark it as "remembered" on the overmap ) #### `flags` diff --git a/src/game.cpp b/src/game.cpp index 48e63c554742d..5f47840d25822 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -838,6 +838,11 @@ bool game::start_game() add_msg( m_debug, "cannot place starting pet, no space!" ); } } + if( u.starting_vehicle && + !place_vehicle_nearby( u.starting_vehicle, u.global_omt_location().xy(), 1, 30, + std::vector {} ) ) { + debugmsg( "could not place starting vehicle" ); + } // Assign all of this scenario's missions to the player. for( const mission_type_id &m : scen->missions() ) { const auto mission = mission::reserve_new( m, character_id() ); @@ -848,6 +853,53 @@ bool game::start_game() return true; } +vehicle *game::place_vehicle_nearby( const vproto_id &id, const point &origin, int min_distance, + int max_distance, const std::vector &omt_search_types ) +{ + std::vector search_types = omt_search_types; + if( search_types.empty() ) { + vehicle veh( id ); + std::vector omt_search_types; + if( veh.max_ground_velocity() > 0 ) { + search_types.push_back( "road" ); + search_types.push_back( "field" ); + } else if( veh.can_float() ) { + search_types.push_back( "river" ); + search_types.push_back( "lake" ); + } + } + for( const std::string &search_type : search_types ) { + omt_find_params find_params; + find_params.must_see = false; + find_params.cant_see = false; + find_params.types.emplace_back( search_type, ot_match_type::type ); + // find nearest road + find_params.min_distance = min_distance; + find_params.search_range = max_distance; + // if player spawns underground, park their car on the surface. + const tripoint omt_origin( origin.x, origin.y, 0 ); + for( const tripoint &goal : overmap_buffer.find_all( omt_origin, find_params ) ) { + // try place vehicle there. + tinymap target_map; + target_map.load( omt_to_sm_copy( goal ), false ); + const tripoint origin( SEEX, SEEY, goal.z ); + static const std::vector angles = {0, 90, 180, 270}; + vehicle *veh = target_map.add_vehicle( id, origin, random_entry( angles ), rng( 50, 80 ), + 0, + false ); + if( veh ) { + tripoint abs_local = g->m.getlocal( target_map.getabs( origin ) ); + veh->sm_pos = ms_to_sm_remain( abs_local ); + veh->pos = abs_local.xy(); + overmap_buffer.add_vehicle( veh ); + target_map.save(); + return veh; + } + } + } + return nullptr; +} + //Make any nearby overmap npcs active, and put them in the right location. void game::load_npcs() { diff --git a/src/game.h b/src/game.h index 767ad951ee788..6c3aa728ce561 100644 --- a/src/game.h +++ b/src/game.h @@ -733,7 +733,9 @@ class game // Data Initialization void init_autosave(); // Initializes autosave parameters void create_starting_npcs(); // Creates NPCs that start near you - + // create vehicle nearby, for example; for a profession vehicle. + vehicle *place_vehicle_nearby( const vproto_id &id, const point &origin, int min_distance, + int max_distance, const std::vector &omt_search_types = {} ); // V Menu Functions and helpers: void list_items_monsters(); // Called when you invoke the `V`-menu diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 7504dc5d5b83c..092ef74843c8d 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -52,6 +52,7 @@ #include "pimpl.h" #include "type_id.h" #include "cata_string_consts.h" +#include "veh_type.h" // Colors used in this file: (Most else defaults to c_light_gray) #define COL_STAT_ACT c_white // Selected stat @@ -519,6 +520,7 @@ bool avatar::create( character_type type, const std::string &tempname ) for( mtype_id elem : prof->pets() ) { starting_pets.push_back( elem ); } + starting_vehicle = prof->vehicle(); std::list prof_items = prof->items( male, get_mutations() ); for( item &it : prof_items ) { @@ -1479,7 +1481,6 @@ tab_direction set_profession( const catacurses::window &w, avatar &u, points_lef } } // Profession pet - cata::optional montype; if( !sorted_profs[cur_id]->pets().empty() ) { buffer += colorize( _( "Pets:" ), c_light_blue ) + "\n"; for( auto elem : sorted_profs[cur_id]->pets() ) { @@ -1487,6 +1488,12 @@ tab_direction set_profession( const catacurses::window &w, avatar &u, points_lef buffer += mon.get_name() + "\n"; } } + // Profession vehicle + if( sorted_profs[cur_id]->vehicle() ) { + buffer += colorize( _( "Vehicle:" ), c_light_blue ) + "\n"; + vproto_id veh_id = sorted_profs[cur_id]->vehicle(); + buffer += veh_id->name; + } // Profession spells if( !sorted_profs[cur_id]->spells().empty() ) { buffer += colorize( _( "Spells:" ), c_light_blue ) + "\n"; diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index 2de6c86b85028..516c69e5fc9db 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -600,7 +600,8 @@ void overmapbuffer::remove_vehicle( const vehicle *veh ) void overmapbuffer::add_vehicle( vehicle *veh ) { - const point omt = ms_to_omt_copy( g->m.getabs( veh->global_pos3().xy() ) ); + const point abs_pos = g->m.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; // this *should* be unique but just in case diff --git a/src/player.h b/src/player.h index dcf5910a8ad0f..fedd52b66ff0f 100644 --- a/src/player.h +++ b/src/player.h @@ -938,7 +938,7 @@ class player : public Character bool reach_attacking = false; bool manual_examine = false; - + 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, diff --git a/src/profession.cpp b/src/profession.cpp index 20765f0229e7b..87f4c62ddd64f 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -171,6 +171,9 @@ void profession::load( const JsonObject &jo, const std::string & ) _description_male = to_translation( "prof_desc_male", desc ); _description_female = to_translation( "prof_desc_female", desc ); } + if( jo.has_string( "vehicle" ) ) { + _starting_vehicle = vproto_id( jo.get_string( "vehicle" ) ); + } if( jo.has_array( "pets" ) ) { for( JsonObject subobj : jo.get_array( "pets" ) ) { int count = subobj.get_int( "amount" ); @@ -286,7 +289,10 @@ void profession::check_definition() const if( !item_group::group_is_defined( _starting_items_female ) ) { debugmsg( "_starting_items_female group is undefined" ); } - + if( _starting_vehicle && !_starting_vehicle.is_valid() ) { + debugmsg( "vehicle prototype %s for profession %s does not exist", _starting_vehicle.c_str(), + id.c_str() ); + } for( const auto &a : _starting_CBMs ) { if( !a.is_valid() ) { debugmsg( "bionic %s for profession %s does not exist", a.c_str(), id.c_str() ); @@ -434,6 +440,11 @@ std::list profession::items( bool male, const std::vector &trait return result; } +vproto_id profession::vehicle() const +{ + return _starting_vehicle; +} + std::vector profession::pets() const { return _starting_pets; diff --git a/src/profession.h b/src/profession.h index 1c9427a717d05..61649631d7b31 100644 --- a/src/profession.h +++ b/src/profession.h @@ -13,6 +13,7 @@ #include "pldata.h" #include "translations.h" #include "type_id.h" +#include "veh_type.h" template class generic_factory; @@ -69,6 +70,7 @@ class profession std::vector _starting_CBMs; std::vector _starting_traits; std::vector _starting_pets; + vproto_id _starting_vehicle = vproto_id::NULL_ID(); // the int is what level the spell starts at std::map _starting_spells; std::set flags; // flags for some special properties of the profession @@ -103,6 +105,7 @@ class profession signed int point_cost() const; std::list items( bool male, const std::vector &traits ) const; std::vector addictions() const; + vproto_id vehicle() const; std::vector pets() const; std::vector CBMs() const; StartingSkillList skills() const; diff --git a/src/string_id_null_ids.cpp b/src/string_id_null_ids.cpp index 3c57688a3b1dd..b33c3e44c615e 100644 --- a/src/string_id_null_ids.cpp +++ b/src/string_id_null_ids.cpp @@ -55,3 +55,4 @@ MAKE_NULL_ID2( requirement_data, "null" ) MAKE_NULL_ID2( body_part_struct, "NUM_BP" ) MAKE_NULL_ID2( bionic_data, "" ) MAKE_NULL_ID2( construction, "constr_null", -1 ) +MAKE_NULL_ID2( vehicle_prototype, "null" ) From 7fdf88071abe66b2f715d181d785c52c50f0708e Mon Sep 17 00:00:00 2001 From: CountAlex Date: Fri, 6 Mar 2020 13:39:24 +0300 Subject: [PATCH 042/219] Add Crazy Party scenario and Frat Boy/Sorority Girl profession (#37512) --- data/json/professions.json | 14 ++++++++++++++ data/json/scenarios.json | 11 +++++++++++ data/json/start_locations.json | 6 ++++++ 3 files changed, 31 insertions(+) diff --git a/data/json/professions.json b/data/json/professions.json index a6a973384eb1b..5744aed4af56b 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -4023,5 +4023,19 @@ ] } } + }, + { + "type": "profession", + "ident": "frat", + "name": { "male": "Frat Boy", "female": "Sorority Girl" }, + "description": "You were living the high life, spending your parents money without a care in the world. You were at one of your usual crazy parties when the guests became hungry for more than your drugs. You still have a chance to use the last symbol of your luxurious life - your sport car - and get far away.", + "points": 2, + "skills": [ { "level": 1, "name": "speech" }, { "level": 2, "name": "driving" } ], + "vehicle": "car_sports", + "items": { + "both": { "items": [ "gold_watch", "water_mineral", "smart_phone", "money_bundle", "cig", "ref_lighter" ] }, + "male": [ "boxer_shorts", "pants", "dress_shoes", "polo_shirt", "socks" ], + "female": [ "tank_top", "bra", "panties", "skirt", "heels", "jacket_leather", "stockings" ] + } } ] diff --git a/data/json/scenarios.json b/data/json/scenarios.json index 1e032ba98a591..07d6c5bb45a83 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -527,5 +527,16 @@ "allowed_locs": [ "mil_base_2g" ], "professions": [ "unemployed", "soldier", "specops", "bio_soldier", "bio_sniper", "labtech", "medic" ], "flags": [ "CHALLENGE", "LONE_START" ] + }, + { + "type": "scenario", + "ident": "presort", + "name": "Crazy party", + "points": 0, + "description": "You thought things couldn't get any worse when the cops came over to bust your wild party, even though you booked it at a private resort. When the guests started fighting with the police you tried to get them to calm down, only to find out they hungered for more.", + "start_name": "Private resort", + "allowed_locs": [ "p_resort_2ss" ], + "professions": [ "frat", "gangster", "lost_sub", "lawyer", "politician", "dancer", "bio_gangster" ], + "flags": [ "CHALLENGE", "LONE_START" ] } ] diff --git a/data/json/start_locations.json b/data/json/start_locations.json index 1ba9161c863b4..f5ab7a21d8526 100644 --- a/data/json/start_locations.json +++ b/data/json/start_locations.json @@ -427,5 +427,11 @@ "ident": "mil_base_2g", "name": "Military Base Warehouse", "target": "mil_base_2g" + }, + { + "type": "start_location", + "ident": "p_resort_2ss", + "name": "Private resort", + "target": "p_resort_2ss" } ] From 0ac2bbc7fa840d14ac4d78ee71c356b4146245b5 Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 02:24:32 +0800 Subject: [PATCH 043/219] Window manager (#37894) For properly refreshing and resizing multiple layers of windows --- src/ncurses_def.cpp | 2 + src/sdltiles.cpp | 107 ++++++++++++++++++++++++------------- src/sdltiles.h | 15 ++++++ src/ui_manager.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++ src/ui_manager.h | 54 +++++++++++++++++++ src/wincurse.cpp | 5 ++ 6 files changed, 272 insertions(+), 37 deletions(-) create mode 100644 src/ui_manager.cpp create mode 100644 src/ui_manager.h diff --git a/src/ncurses_def.cpp b/src/ncurses_def.cpp index 8550acb7b7ffd..ca8a4bee7857b 100644 --- a/src/ncurses_def.cpp +++ b/src/ncurses_def.cpp @@ -19,6 +19,7 @@ #include "catacharset.h" #include "color.h" #include "game_ui.h" +#include "ui_manager.h" extern int VIEW_OFFSET_X; // X position of terrain window extern int VIEW_OFFSET_Y; // Y position of terrain window @@ -204,6 +205,7 @@ void catacurses::resizeterm() const int new_y = ::getmaxy( stdscr.get<::WINDOW>() ); if( ::is_term_resized( new_x, new_y ) ) { game_ui::init_ui(); + ui_manager::screen_resized(); } } diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index 53c7ae7aadddc..7b9063aa56e6b 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -57,6 +57,7 @@ #include "json.h" #include "optional.h" #include "point.h" +#include "ui_manager.h" #if defined(__linux__) # include // getenv()/setenv() @@ -1762,7 +1763,7 @@ bool handle_resize( int w, int h ) TERMINAL_HEIGHT = WindowHeight / fontheight / scaling_factor; SetupRenderTarget(); game_ui::init_ui(); - + ui_manager::screen_resized(); return true; } return false; @@ -2824,6 +2825,9 @@ static void CheckMessages() #endif last_input = input_event(); + + bool need_redraw = false; + while( SDL_PollEvent( &ev ) ) { switch( ev.type ) { case SDL_WINDOWEVENT: @@ -2854,17 +2858,14 @@ static void CheckMessages() break; #endif case SDL_WINDOWEVENT_SHOWN: - case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_MINIMIZED: - break; case SDL_WINDOWEVENT_FOCUS_GAINED: - // Main menu redraw - reinitialize_framebuffer(); - // TODO: redraw all game menus if they are open + break; + case SDL_WINDOWEVENT_EXPOSED: + need_redraw = true; needupdate = true; break; case SDL_WINDOWEVENT_RESTORED: - needupdate = true; #if defined(__ANDROID__) needs_sdl_surface_visibility_refresh = true; if( android_is_hardware_keyboard_available() ) { @@ -2880,6 +2881,10 @@ static void CheckMessages() break; } break; + case SDL_RENDER_TARGETS_RESET: + need_redraw = true; + needupdate = true; + break; case SDL_KEYDOWN: { #if defined(__ANDROID__) // Toggle virtual keyboard with Android back button. For some reason I get double inputs, so ignore everything once it's already down. @@ -3204,6 +3209,19 @@ static void CheckMessages() break; } } + if( need_redraw ) { + // FIXME: SDL_RENDER_TARGETS_RESET only seems to be fired after the first redraw + // when restoring the window after system sleep, rather than immediately + // on focus gain. This seems to mess up the first redraw and + // causes black screen that lasts ~0.5 seconds before the screen + // contents are redrawn in the following code. + + // Main menu redraw + reinitialize_framebuffer(); + window_dimensions dim = get_window_dimensions( catacurses::stdscr ); + ui_manager::invalidate( rectangle( point_zero, dim.window_size_pixel ) ); + ui_manager::redraw(); + } if( needupdate ) { try_sdl_update(); } @@ -3690,45 +3708,60 @@ void rescale_tileset( int size ) game_ui::init_ui(); } -cata::optional input_context::get_coordinates( const catacurses::window &capture_win_ ) +window_dimensions get_window_dimensions( const catacurses::window &win ) { - if( !coordinate_input_received ) { - return cata::nullopt; - } + cata_cursesport::WINDOW *const pwin = win.get(); - cata_cursesport::WINDOW *const capture_win = ( capture_win_.get() ? capture_win_ : - g->w_terrain ).get(); - - // this contains the font dimensions of the capture_win, - // not necessarily the global standard font dimensions. - int fw = fontwidth; - int fh = fontheight; - // tiles might have different dimensions than standard font - if( use_tiles && capture_win == g->w_terrain ) { - fw = tilecontext->get_tile_width(); - fh = tilecontext->get_tile_height(); - // add_msg( m_info, "tile map fw %d fh %d", fw, fh); - } else if( map_font && capture_win == g->w_terrain ) { + window_dimensions dim; + if( use_tiles && win == g->w_terrain ) { + // tiles might have different dimensions than standard font + dim.scaled_font_size.x = tilecontext->get_tile_width(); + dim.scaled_font_size.y = tilecontext->get_tile_height(); + } else if( map_font && win == g->w_terrain ) { // map font (if any) might differ from standard font - fw = map_font->fontwidth; - fh = map_font->fontheight; - } else if( overmap_font && capture_win == g->w_overmap ) { - fw = overmap_font->fontwidth; - fh = overmap_font->fontheight; + dim.scaled_font_size.x = map_font->fontwidth; + dim.scaled_font_size.y = map_font->fontheight; + } else if( overmap_font && win == g->w_overmap ) { + dim.scaled_font_size.x = overmap_font->fontwidth; + dim.scaled_font_size.y = overmap_font->fontheight; + } else { + dim.scaled_font_size.x = fontwidth; + dim.scaled_font_size.y = fontheight; } // multiplied by the user's specified scaling factor regardless of whether tiles are in use - fw = fw * get_scaling_factor(); - fh = fh * get_scaling_factor(); + dim.scaled_font_size *= get_scaling_factor(); + + dim.window_pos_cell = pwin->pos; + dim.window_size_cell.x = pwin->width; + dim.window_size_cell.y = pwin->height; - // Translate mouse coordinates to map coordinates based on tile size, // the window position is *always* in standard font dimensions! - const point win_min( capture_win->pos.x * fontwidth, capture_win->pos.y * fontheight ); + dim.window_pos_pixel = point( dim.window_pos_cell.x * fontwidth, + dim.window_pos_cell.y * fontheight ); // But the size of the window is in the font dimensions of the window. - const point win_size( capture_win->width * fw, capture_win->height * fh ); + dim.window_size_pixel.x = dim.window_size_cell.x * dim.scaled_font_size.x; + dim.window_size_pixel.y = dim.window_size_cell.y * dim.scaled_font_size.y; + + return dim; +} + +cata::optional input_context::get_coordinates( const catacurses::window &capture_win_ ) +{ + if( !coordinate_input_received ) { + return cata::nullopt; + } + + const catacurses::window &capture_win = capture_win_ ? capture_win_ : g->w_terrain; + const window_dimensions dim = get_window_dimensions( capture_win ); + + const int &fw = dim.scaled_font_size.x; + const int &fh = dim.scaled_font_size.y; + const point &win_min = dim.window_pos_pixel; + const point &win_size = dim.window_size_pixel; const point win_max = win_min + win_size; - // add_msg( m_info, "win_ left %d top %d right %d bottom %d", win_left,win_top,win_right,win_bottom); - // add_msg( m_info, "coordinate_ x %d y %d", coordinate_x, coordinate_y); + + // Translate mouse coordinates to map coordinates based on tile size // Check if click is within bounds of the window we care about const rectangle win_bounds( win_min, win_max ); if( !win_bounds.contains_inclusive( coordinate ) ) { @@ -3751,7 +3784,7 @@ cata::optional input_context::get_coordinates( const catacurses::windo p = view_offset + selected; } else { const point selected( screen_pos.x / fw, screen_pos.y / fh ); - p = view_offset + selected - point( capture_win->width / 2, capture_win->height / 2 ); + p = view_offset + selected - dim.window_size_cell / 2; } return tripoint( p, g->get_levz() ); diff --git a/src/sdltiles.h b/src/sdltiles.h index a7ab650c3ea4d..433561148e03d 100644 --- a/src/sdltiles.h +++ b/src/sdltiles.h @@ -9,10 +9,16 @@ #include #include "color_loader.h" +#include "point.h" #include "sdl_wrappers.h" class cata_tiles; +namespace catacurses +{ +class window; +} // namespace catacurses + extern SDL_Texture_Ptr alt_rect_tex; extern bool alt_rect_tex_enabled; extern std::unique_ptr tilecontext; @@ -25,6 +31,15 @@ void rescale_tileset( int size ); bool save_screenshot( const std::string &file_path ); void toggle_fullscreen_window(); +struct window_dimensions { + point scaled_font_size; + point window_pos_cell; + point window_size_cell; + point window_pos_pixel; + point window_size_pixel; +}; +window_dimensions get_window_dimensions( const catacurses::window &win ); + #endif // TILES #endif // CATA_SDLTILES_H diff --git a/src/ui_manager.cpp b/src/ui_manager.cpp new file mode 100644 index 0000000000000..9ee7387aa6aff --- /dev/null +++ b/src/ui_manager.cpp @@ -0,0 +1,126 @@ +#include "ui_manager.h" + +#include + +#include "cursesdef.h" +#include "point.h" +#include "sdltiles.h" + +static std::vector> ui_stack; + +ui_adaptor::ui_adaptor() : invalidated( false ) +{ + ui_stack.emplace_back( *this ); +} + +ui_adaptor::~ui_adaptor() +{ + for( auto it = ui_stack.rbegin(); it < ui_stack.rend(); ++it ) { + if( &it->get() == this ) { + ui_stack.erase( std::prev( it.base() ) ); + // TODO avoid invalidating portions that do not need to be redrawn + ui_manager::invalidate( dimensions ); + break; + } + } +} + +void ui_adaptor::position_from_window( const catacurses::window &win ) +{ + const rectangle old_dimensions = dimensions; + // ensure position is updated before calling invalidate +#ifdef TILES + const window_dimensions dim = get_window_dimensions( win ); + dimensions = rectangle( dim.window_pos_pixel, dim.window_pos_pixel + dim.window_size_pixel ); +#else + const point origin( getbegx( win ), getbegy( win ) ); + dimensions = rectangle( origin, origin + point( getmaxx( win ), getmaxy( win ) ) ); +#endif + invalidated = true; + ui_manager::invalidate( old_dimensions ); +} + +void ui_adaptor::on_redraw( const redraw_callback_t &fun ) +{ + redraw_cb = fun; +} + +void ui_adaptor::on_screen_resize( const screen_resize_callback_t &fun ) +{ + screen_resized_cb = fun; +} + +static bool contains( const rectangle &lhs, const rectangle &rhs ) +{ + return rhs.p_min.x >= lhs.p_min.x && rhs.p_max.x <= lhs.p_max.x && + rhs.p_min.y >= lhs.p_min.y && rhs.p_max.y <= lhs.p_max.y; +} + +static bool overlap( const rectangle &lhs, const rectangle &rhs ) +{ + return lhs.p_min.x < rhs.p_max.x && lhs.p_min.y < rhs.p_max.y && + rhs.p_min.x < lhs.p_max.x && rhs.p_min.y < lhs.p_max.y; +} + +void ui_adaptor::invalidate( const rectangle &rect ) +{ + if( rect.p_min.x >= rect.p_max.x || rect.p_min.y >= rect.p_max.y ) { + return; + } + // TODO avoid invalidating portions that do not need to be redrawn + for( auto it = ui_stack.crbegin(); it < ui_stack.crend(); ++it ) { + const ui_adaptor &ui = it->get(); + if( overlap( ui.dimensions, rect ) ) { + ui.invalidated = true; + if( contains( ui.dimensions, rect ) ) { + break; + } + } + } +} + +void ui_adaptor::redraw() +{ + // TODO refresh only when all stacked UIs are drawn + if( !ui_stack.empty() ) { + ui_stack.back().get().invalidated = true; + for( const ui_adaptor &ui : ui_stack ) { + if( ui.invalidated ) { + if( ui.redraw_cb ) { + ui.redraw_cb( ui ); + } + ui.invalidated = false; + } + } + } +} + +void ui_adaptor::screen_resized() +{ + for( ui_adaptor &ui : ui_stack ) { + if( ui.screen_resized_cb ) { + ui.screen_resized_cb( ui ); + } + } + redraw(); +} + +namespace ui_manager +{ + +void invalidate( const rectangle &rect ) +{ + ui_adaptor::invalidate( rect ); +} + +void redraw() +{ + ui_adaptor::redraw(); +} + +void screen_resized() +{ + ui_adaptor::screen_resized(); +} + +} // namespace ui_manager diff --git a/src/ui_manager.h b/src/ui_manager.h new file mode 100644 index 0000000000000..61c1f46915fd1 --- /dev/null +++ b/src/ui_manager.h @@ -0,0 +1,54 @@ +#pragma once +#ifndef UI_MANAGER_H +#define UI_MANAGER_H + +#include + +#include "point.h" + +namespace catacurses +{ +class window; +} // namespace catacurses + +class ui_adaptor +{ + public: + using redraw_callback_t = std::function; + using screen_resize_callback_t = std::function; + + ui_adaptor(); + ui_adaptor( const ui_adaptor &rhs ) = delete; + ui_adaptor( ui_adaptor &&rhs ) = delete; + ~ui_adaptor(); + + ui_adaptor &operator=( const ui_adaptor &rhs ) = delete; + ui_adaptor &operator=( ui_adaptor &&rhs ) = delete; + + void position_from_window( const catacurses::window &win ); + void on_redraw( const redraw_callback_t &fun ); + void on_screen_resize( const screen_resize_callback_t &fun ); + + static void invalidate( const rectangle &rect ); + static void redraw(); + static void screen_resized(); + private: + // pixel dimensions in tiles, console cell dimensions in curses + rectangle dimensions; + redraw_callback_t redraw_cb; + screen_resize_callback_t screen_resized_cb; + + mutable bool invalidated; +}; + +// export static funcs of ui_adaptor with a more coherent scope name +namespace ui_manager +{ +// rect is the pixel dimensions in tiles or console cell dimensions in curses +void invalidate( const rectangle &rect ); +// invalidate the top window and redraw all invalidated windows +void redraw(); +void screen_resized(); +} // namespace ui_manager + +#endif diff --git a/src/wincurse.cpp b/src/wincurse.cpp index 350759fc6516a..4337469a42080 100644 --- a/src/wincurse.cpp +++ b/src/wincurse.cpp @@ -24,6 +24,7 @@ #include "font_loader.h" #include "platform_win.h" #include "mmsystem.h" +#include "ui_manager.h" #include "wcwidth.h" //*********************************** @@ -189,6 +190,7 @@ bool handle_resize( int, int ) throw std::runtime_error( "SetDIBColorTable failed" ); } catacurses::refresh(); + ui_manager::screen_resized(); } return true; @@ -372,6 +374,9 @@ LRESULT CALLBACK ProcessMessages( HWND__ *hWnd, unsigned int Msg, case WM_PAINT: BitBlt( WindowDC, 0, 0, WindowWidth, WindowHeight, backbuffer, 0, 0, SRCCOPY ); + ui_manager::invalidate( rectangle( point_zero, point( getmaxx( catacurses::stdscr ), + getmaxy( catacurses::stdscr ) ) ) ); + ui_manager::redraw(); ValidateRect( WindowHandle, nullptr ); return 0; From 50b96168308e14c0d9e85e262fb42c34bc9ab9af Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:17:57 +0800 Subject: [PATCH 044/219] Use ui_adaptor in main game ui --- src/game.cpp | 7 ++++--- src/main.cpp | 11 ++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 5f47840d25822..0e9c32e95ac3f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -138,6 +138,7 @@ #include "ret_val.h" #include "tileray.h" #include "ui.h" +#include "ui_manager.h" #include "units.h" #include "int_id.h" #include "string_id.h" @@ -1492,7 +1493,7 @@ bool game::do_turn() } sounds::process_sound_markers( &u ); if( !u.activity && !u.has_distant_destination() && uquit != QUIT_WATCH ) { - draw(); + ui_manager::redraw(); } if( handle_action() ) { @@ -1589,7 +1590,7 @@ bool game::do_turn() mon_info_update(); u.process_turn(); if( u.moves < 0 && get_option( "FORCE_REDRAW" ) ) { - draw(); + ui_manager::redraw(); refresh_display(); } @@ -1602,7 +1603,7 @@ bool game::do_turn() if( player_is_sleeping ) { if( calendar::once_every( 30_minutes ) || !player_was_sleeping ) { - draw(); + ui_manager::redraw(); //Putting this in here to save on checking if( calendar::once_every( 1_hours ) ) { add_artifact_dreams( ); diff --git a/src/main.cpp b/src/main.cpp index 8da3f3577441b..6d5a46850faa7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include "debug.h" #include "filesystem.h" #include "game.h" +#include "input.h" #include "loading_ui.h" #include "main_menu.h" #include "mapsharing.h" @@ -35,8 +36,8 @@ #include "path_info.h" #include "rng.h" #include "translations.h" -#include "input.h" #include "type_id.h" +#include "ui_manager.h" #if defined(TILES) # if defined(_MSC_VER) && defined(USE_VCPKG) @@ -685,6 +686,14 @@ int main( int argc, char *argv[] ) } } + ui_adaptor main_ui; + main_ui.position_from_window( catacurses::stdscr ); + main_ui.on_redraw( []( const ui_adaptor & ) { + g->draw(); + } ); + main_ui.on_screen_resize( []( ui_adaptor & ui ) { + ui.position_from_window( catacurses::stdscr ); + } ); while( !g->do_turn() ); } From c2962dabb5e76f0508160b6d781fe4ee64335810 Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:24:17 +0800 Subject: [PATCH 045/219] Use ui_adaptor in query_popup --- src/animation.cpp | 1 + src/game.cpp | 3 +++ src/output.cpp | 2 ++ src/popup.cpp | 40 ++++++++++++++++++++++++++++++---------- src/popup.h | 5 +++++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/animation.cpp b/src/animation.cpp index 539e7b1cdf350..788ead6b44311 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -52,6 +52,7 @@ class basic_animation .on_top( true ) .show(); + catacurses::refresh(); refresh_display(); } diff --git a/src/game.cpp b/src/game.cpp index 0e9c32e95ac3f..c591add5a16e5 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1625,6 +1625,9 @@ bool game::do_turn() .wait_message( "%s", *progress ) .on_top( true ) .show(); + + catacurses::refresh(); + refresh_display(); } } diff --git a/src/output.cpp b/src/output.cpp index bd367b3218d91..cf93a8602461b 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -639,6 +639,8 @@ int popup( const std::string &text, PopupFlags flags ) if( flags & PF_NO_WAIT ) { pop.show(); + catacurses::refresh(); + refresh_display(); return UNKNOWN_UNICODE; } else { pop.context( "POPUP_WAIT" ); diff --git a/src/popup.cpp b/src/popup.cpp index 344819e0b920e..b91a7474433e3 100644 --- a/src/popup.cpp +++ b/src/popup.cpp @@ -4,10 +4,11 @@ #include #include +#include "catacharset.h" #include "ime.h" #include "input.h" #include "output.h" -#include "catacharset.h" +#include "ui_manager.h" extern bool test_mode; @@ -129,10 +130,6 @@ std::vector> query_popup::fold_query( void query_popup::invalidate_ui() const { if( win ) { - werase( win ); - wrefresh( win ); - catacurses::refresh(); - refresh_display(); win = {}; folded_msg.clear(); buttons.clear(); @@ -208,6 +205,11 @@ void query_popup::init() const const int win_x = ( TERMX - win_width ) / 2; const int win_y = ontop ? 0 : ( TERMY - win_height ) / 2; win = catacurses::newwin( win_height, win_width, point( win_x, win_y ) ); + + std::shared_ptr ui = adaptor.lock(); + if( ui ) { + ui->position_from_window( win ); + } } void query_popup::show() const @@ -233,10 +235,24 @@ void query_popup::show() const } wrefresh( win ); - // Need to refresh display when displaying popups wihout taking input, such - // as during saving. - catacurses::refresh(); - refresh_display(); +} + +std::shared_ptr query_popup::create_or_get_adaptor() +{ + std::shared_ptr ui = adaptor.lock(); + if( !ui ) { + adaptor = ui = std::make_shared(); + ui->on_redraw( [this]( const ui_adaptor & ) { + show(); + } ); + ui->on_screen_resize( [this]( ui_adaptor & ) { + init(); + } ); + if( win ) { + ui->position_from_window( win ); + } + } + return ui; } query_popup::result query_popup::query_once() @@ -249,7 +265,9 @@ query_popup::result query_popup::query_once() return { false, "ERROR", {} }; } - show(); + std::shared_ptr ui = create_or_get_adaptor(); + + ui_manager::redraw(); input_context ctxt( category ); if( cancel || !options.empty() ) { @@ -326,6 +344,8 @@ query_popup::result query_popup::query() { ime_sentry sentry( ime_sentry::disable ); + std::shared_ptr ui = create_or_get_adaptor(); + result res; do { res = query_once(); diff --git a/src/popup.h b/src/popup.h index f38bbf7c63d3f..6affb0e7590ba 100644 --- a/src/popup.h +++ b/src/popup.h @@ -13,6 +13,8 @@ #include "color.h" #include "string_formatter.h" +class ui_adaptor; + /** * UI class for displaying messages or querying player input with popups. * @@ -213,6 +215,9 @@ class query_popup point pos; }; + std::weak_ptr adaptor; + std::shared_ptr create_or_get_adaptor(); + // UI caches mutable catacurses::window win; mutable std::vector folded_msg; From ee2d313567ad5ac2f05b0b5c585fbca440611f52 Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:28:06 +0800 Subject: [PATCH 046/219] Use ui_adaptor in keybindings menu --- src/input.cpp | 58 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 4f31ac7bec4ee..fcac31418f167 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -30,6 +30,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "point.h" @@ -1014,13 +1015,32 @@ action_id input_context::display_menu( const bool permit_execute_action ) std::string hotkeys = ctxt.get_available_single_char_hotkeys( display_help_hotkeys ); - int maxwidth = max( FULL_SCREEN_WIDTH, TERMX ); - int width = min( 80, maxwidth ); - int maxheight = max( FULL_SCREEN_HEIGHT, TERMY ); - int height = min( maxheight, static_cast( hotkeys.size() ) + LEGEND_HEIGHT + BORDER_SPACE ); - - catacurses::window w_help = catacurses::newwin( height - 2, width - 2, - point( maxwidth / 2 - width / 2, maxheight / 2 - height / 2 ) ); + ui_adaptor ui; + int width = 0; + int height = 0; + catacurses::window w_help; + size_t display_height = 0; + size_t legwidth = 0; + string_input_popup spopup; + const auto recalc_size = [&]( ui_adaptor & ui ) { + int maxwidth = max( FULL_SCREEN_WIDTH, TERMX ); + width = min( 80, maxwidth ); + int maxheight = max( FULL_SCREEN_HEIGHT, TERMY ); + height = min( maxheight, static_cast( hotkeys.size() ) + LEGEND_HEIGHT + BORDER_SPACE ); + + w_help = catacurses::newwin( height - 2, width - 2, + point( maxwidth / 2 - width / 2, maxheight / 2 - height / 2 ) ); + // height of the area usable for display of keybindings, excludes headers & borders + display_height = height - LEGEND_HEIGHT - BORDER_SPACE; // -2 for the border + // width of the legend + legwidth = width - 4 - BORDER_SPACE; + spopup.window( w_help, 4, 8, legwidth ) + .max_length( legwidth ) + .context( ctxt ); + ui.position_from_window( w_help ); + }; + recalc_size( ui ); + ui.on_screen_resize( recalc_size ); // has the user changed something? bool changed = false; @@ -1042,10 +1062,6 @@ action_id input_context::display_menu( const bool permit_execute_action ) static const nc_color unbound_key = c_light_red; // (vertical) scroll offset size_t scroll_offset = 0; - // height of the area usable for display of keybindings, excludes headers & borders - const size_t display_height = height - LEGEND_HEIGHT - BORDER_SPACE; // -2 for the border - // width of the legend - const size_t legwidth = width - 4 - BORDER_SPACE; // keybindings help std::string legend; legend += colorize( _( "Unbound keys" ), unbound_key ) + "\n"; @@ -1060,14 +1076,8 @@ action_id input_context::display_menu( const bool permit_execute_action ) std::string filter_phrase; std::string action; int raw_input_char = 0; - string_input_popup spopup; - spopup.window( w_help, 4, 8, legwidth ) - .max_length( legwidth ) - .context( ctxt ); - // do not switch IME mode now, but restore previous mode on return - ime_sentry sentry( ime_sentry::keep ); - while( true ) { + const auto redraw = [&]( const ui_adaptor & ) { werase( w_help ); draw_border( w_help, BORDER_COLOR, _( "Keybindings" ), c_light_red ); draw_scrollbar( w_help, scroll_offset, display_height, @@ -1115,14 +1125,20 @@ action_id input_context::display_menu( const bool permit_execute_action ) } // spopup.query_string() will call wrefresh( w_help ) - catacurses::refresh(); - spopup.text( filter_phrase ); + spopup.query_string( false, true ); + }; + ui.on_redraw( redraw ); + + // do not switch IME mode now, but restore previous mode on return + ime_sentry sentry( ime_sentry::keep ); + while( true ) { + ui_manager::redraw(); + if( status == s_show ) { filter_phrase = spopup.query_string( false ); action = ctxt.input_to_action( ctxt.get_raw_input() ); } else { - spopup.query_string( false, true ); action = ctxt.handle_input(); } raw_input_char = ctxt.get_raw_input().get_first_input(); From a5d9e7fac53a4a9443e115147873ab1716c68ebe Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:44:32 +0800 Subject: [PATCH 047/219] Use ui_adaptor in uilist --- src/ui.cpp | 105 ++++++++++++++++++++++++++++++----------------------- src/ui.h | 14 +++++-- 2 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/ui.cpp b/src/ui.cpp index c36c98150dde0..43d7fe7ae5a12 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -18,6 +18,7 @@ #include "output.h" #include "player.h" #include "string_input_popup.h" +#include "ui_manager.h" #if defined(__ANDROID__) #include @@ -106,6 +107,8 @@ uilist::uilist( const point &start, int width, const std::string &msg, query(); } +uilist::~uilist() = default; + /* * Enables oneshot construction -> running -> exit */ @@ -233,60 +236,30 @@ void uilist::filterlist() } } -/** - * Call string_input_win / ui_element_input::input_filter and filter the entries list interactively - */ -std::string uilist::inputfilter() +void uilist::inputfilter() { - // TODO: uilist.filter_identifier ? - std::string identifier; - mvwprintz( window, point( 2, w_height - 1 ), border_color, "< " ); - mvwprintz( window, point( w_width - 3, w_height - 1 ), border_color, " >" ); - /* - //debatable merit - std::string origfilter = filter; - int origselected = selected; - int origfselected = fselected; - int origvshift = vshift; - */ - string_input_popup popup; - popup.text( filter ) + filter_popup = std::make_unique(); + filter_popup->text( filter ) .max_length( 256 ) - .window( window, 4, w_height - 1, w_width - 4 ) - .identifier( identifier ); + .window( window, 4, w_height - 1, w_width - 4 ); input_event event; ime_sentry sentry; do { - // filter=filter_input->query(filter, false); - filter = popup.query_string( false ); - event = popup.context().get_raw_input(); - // key = filter_input->keypress; + ui_manager::redraw(); + filter = filter_popup->query_string( false ); + event = filter_popup->context().get_raw_input(); if( event.get_first_input() != KEY_ESCAPE ) { if( !scrollby( scroll_amount_from_key( event.get_first_input() ) ) ) { filterlist(); } - show(); } } while( event.get_first_input() != '\n' && event.get_first_input() != KEY_ESCAPE ); if( event.get_first_input() == KEY_ESCAPE ) { - /* - //perhaps as an option - filter = origfilter; - selected = origselected; - fselected = origfselected; - vshift = origvshift; - */ filterlist(); } - wattron( window, border_color ); - for( int i = 1; i < w_width - 1; i++ ) { - mvwaddch( window, point( i, w_height - 1 ), LINE_OXOX ); - } - wattroff( window, border_color ); - - return filter; + filter_popup.reset(); } /** @@ -506,10 +479,12 @@ void uilist::setup() } } - if( w_x == -1 ) { + w_x_autoassigned = w_x == MENU_AUTOASSIGN; + if( w_x_autoassigned ) { w_x = static_cast( ( TERMX - w_width ) / 2 ); } - if( w_y == -1 ) { + w_y_autoassigned = w_y == MENU_AUTOASSIGN; + if( w_y_autoassigned ) { w_y = static_cast( ( TERMY - w_height ) / 2 ); } @@ -681,9 +656,15 @@ void uilist::show() } } - if( !filter.empty() ) { - mvwprintz( window, point( 2, w_height - 1 ), border_color, "< %s >", filter ); - mvwprintz( window, point( 4, w_height - 1 ), text_color, filter ); + if( filter_popup ) { + mvwprintz( window, point( 2, w_height - 1 ), border_color, "< " ); + mvwprintz( window, point( w_width - 3, w_height - 1 ), border_color, " >" ); + filter_popup->query( /*loop=*/false, /*draw_only=*/true ); + } else { + if( !filter.empty() ) { + mvwprintz( window, point( 2, w_height - 1 ), border_color, "< %s >", filter ); + mvwprintz( window, point( 4, w_height - 1 ), text_color, filter ); + } } apply_scrollbar(); @@ -845,7 +826,41 @@ void uilist::query( bool loop, int timeout ) } hotkeys = ctxt.get_available_single_char_hotkeys( hotkeys ); - show(); + ui_adaptor ui; + ui.on_redraw( [this]( const ui_adaptor & ) { + show(); + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + if( w_x_autoassigned || w_y_autoassigned ) { + // because the way `setup()` works we cannot call it again here, + // so just move the window to the center of the screen instead. + if( w_x_autoassigned ) { + if( w_width >= TERMX ) { + w_x = 0; + } else { + w_x = ( TERMX - w_width ) / 2; + } + } + if( w_y_autoassigned ) { + if( w_height > TERMY ) { + w_y = 0; + } else { + w_y = ( TERMY - w_height ) / 2; + } + } + window = catacurses::newwin( w_height, w_width, point( w_x, w_y ) ); + if( filter_popup ) { + filter_popup->window( window, 4, w_height - 1, w_width - 4 ); + } + ui.position_from_window( window ); + } + } ); + if( !started ) { + setup(); + } + ui.position_from_window( window ); + + ui_manager::redraw(); #if defined(__ANDROID__) for( const auto &entry : entries ) { @@ -898,7 +913,7 @@ void uilist::query( bool loop, int timeout ) } } - show(); + ui_manager::redraw(); } while( loop && ret == UILIST_WAIT_INPUT ); } diff --git a/src/ui.h b/src/ui.h index 00b9b90085ff0..00f9d439e1087 100644 --- a/src/ui.h +++ b/src/ui.h @@ -34,6 +34,7 @@ constexpr point MENU_AUTOASSIGN_POS( MENU_AUTOASSIGN, MENU_AUTOASSIGN ); struct input_event; class input_context; +class string_input_popup; catacurses::window new_centered_win( int nlines, int ncols ); @@ -229,6 +230,8 @@ class uilist: public ui_container uilist( const point &start, int width, const std::string &msg, std::initializer_list opts ); + ~uilist() override; + void init(); void setup(); void show(); @@ -238,7 +241,6 @@ class uilist: public ui_container void query( bool loop = true, int timeout = -1 ); void filterlist(); void apply_scrollbar(); - std::string inputfilter(); void refresh( bool refresh_callback = true ) override; void redraw( bool redraw_callback = true ); void addentry( const std::string &str ); @@ -260,10 +262,16 @@ class uilist: public ui_container operator int() const; - // pending refactor // ui_element_input * filter_input; - private: bool started = false; + std::unique_ptr filter_popup; + + bool w_x_autoassigned = false; + bool w_y_autoassigned = false; + + // This function assumes it's being called from `query` and should + // not be made public. + void inputfilter(); protected: std::string hotkeys; From a426858f3ef2510e153d8a5d0cd678e74ab7f197 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 18:03:58 +0800 Subject: [PATCH 048/219] Use ui_adaptor in main menu --- src/main_menu.cpp | 84 +++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index bca8cea985b9e..ca84a7758fc17 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -38,6 +38,7 @@ #include "options.h" #include "pldata.h" #include "string_formatter.h" +#include "ui_manager.h" static const holiday current_holiday = holiday::none; @@ -467,21 +468,63 @@ bool main_menu::opening_screen() sel1 = 2; } - while( !start ) { - // disable ime at program start - // somehow this need to be here to actually work - disable_ime(); - + ui_adaptor ui; + ui.on_redraw( [&]( const ui_adaptor & ) { print_menu( w_open, sel1, menu_offset ); if( layer == 1 ) { if( sel1 == 0 ) { // Print MOTD. display_text( mmenu_motd, "MOTD", sel_line ); - } else if( sel1 == 7 ) { // Print Credits. display_text( mmenu_credits, "Credits", sel_line ); } + } else if( layer == 2 ) { + if( sel1 == 4 ) { // Special game + std::vector special_names; + int xlen = 0; + for( int i = 1; i < NUM_SPECIAL_GAMES; i++ ) { + std::string spec_name = special_game_name( static_cast( i ) ); + special_names.push_back( spec_name ); + xlen += utf8_width( shortcut_text( c_white, spec_name ), true ) + 2; + } + xlen += special_names.size() - 1; + point offset( menu_offset + point( -( xlen / 4 ) + 32 + extra_w / 2, -2 ) ); + print_menu_items( w_open, special_names, sel2, offset ); + + wrefresh( w_open ); + } else if( sel1 == 5 ) { // Settings Menu + int settings_subs_to_display = vSettingsSubItems.size(); + std::vector settings_subs; + int xlen = 0; + for( int i = 0; i < settings_subs_to_display; ++i ) { + settings_subs.push_back( vSettingsSubItems[i] ); + // Open and close brackets added + xlen += utf8_width( shortcut_text( c_white, vSettingsSubItems[i] ), true ) + 2; + } + xlen += settings_subs.size() - 1; + point offset = menu_offset + point( 46 + extra_w / 2 - ( xlen / 4 ), -2 ); + if( settings_subs.size() > 1 ) { + offset.x -= 6; + } + print_menu_items( w_open, settings_subs, sel2, offset ); + wrefresh( w_open ); + } + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + + while( !start ) { + // disable ime at program start + // somehow this need to be here to actually work + disable_ime(); + + ui_manager::redraw(); + if( layer == 1 ) { std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; @@ -535,7 +578,6 @@ bool main_menu::opening_screen() } else { sel2 = 0; layer = 2; - print_menu( w_open, sel1, menu_offset ); switch( sel1 ) { case 1: @@ -560,19 +602,6 @@ bool main_menu::opening_screen() continue; } - std::vector special_names; - int xlen = 0; - for( int i = 1; i < NUM_SPECIAL_GAMES; i++ ) { - std::string spec_name = special_game_name( static_cast( i ) ); - special_names.push_back( spec_name ); - xlen += utf8_width( shortcut_text( c_white, spec_name ), true ) + 2; - } - xlen += special_names.size() - 1; - point offset( menu_offset + point( -( xlen / 4 ) + 32 + extra_w / 2, -2 ) ); - print_menu_items( w_open, special_names, sel2, offset ); - - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( action == "LEFT" ) { if( sel2 > 0 ) { @@ -620,21 +649,6 @@ bool main_menu::opening_screen() } } else if( sel1 == 5 ) { // Settings Menu int settings_subs_to_display = vSettingsSubItems.size(); - std::vector settings_subs; - int xlen = 0; - for( int i = 0; i < settings_subs_to_display; ++i ) { - settings_subs.push_back( vSettingsSubItems[i] ); - // Open and close brackets added - xlen += utf8_width( shortcut_text( c_white, vSettingsSubItems[i] ), true ) + 2; - } - xlen += settings_subs.size() - 1; - point offset = menu_offset + point( 46 + extra_w / 2 - ( xlen / 4 ), -2 ); - if( settings_subs.size() > 1 ) { - offset.x -= 6; - } - print_menu_items( w_open, settings_subs, sel2, offset ); - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; for( int i = 0; i < settings_subs_to_display; ++i ) { From 24f9d06ee9519d2a1100cdfba3f295153113399a Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 19:49:27 +0800 Subject: [PATCH 049/219] Use ui_adaptor in main menu new character submenu --- src/main_menu.cpp | 64 +++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index ca84a7758fc17..2d6518b4de719 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -732,11 +732,43 @@ bool main_menu::new_character_tab() vNewGameHotkeys.push_back( get_hotkeys( item ) ); } - bool start = false; - while( !start && sel1 == 1 && ( layer == 2 || layer == 3 ) ) { + ui_adaptor ui; + ui.on_redraw( [&]( const ui_adaptor & ) { print_menu( w_open, 1, menu_offset ); + if( layer == 2 && sel1 == 1 ) { center_print( w_open, getmaxy( w_open ) - 7, c_yellow, hints[sel2] ); + + print_menu_items( w_open, vSubItems, sel2, menu_offset + point( 0, -2 ) ); + wrefresh( w_open ); + } else if( layer == 3 && sel1 == 1 ) { + // Then view presets + if( templates.empty() ) { + mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -4 ), + c_red, "%s", _( "No templates found!" ) ); + } else { + mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -2 ), + c_white, "%s", _( "Press 'd' to delete a preset." ) ); + for( int i = 0; i < static_cast( templates.size() ); i++ ) { + int line = menu_offset.y - 4 - i; + mvwprintz( w_open, point( 20 + menu_offset.x + extra_w / 2, line ), + ( sel3 == i ? h_white : c_white ), "%s", + templates[i] ); + } + } + wrefresh( w_open ); + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + + bool start = false; + while( !start && sel1 == 1 && ( layer == 2 || layer == 3 ) ) { + ui_manager::redraw(); + if( layer == 2 && sel1 == 1 ) { // Then choose custom character, random character, preset, etc if( MAP_SHARING::isSharing() && world_generator->all_worldnames().empty() ) { //don't show anything when there are no worlds (will not work if there are special maps) @@ -745,10 +777,6 @@ bool main_menu::new_character_tab() continue; } - print_menu_items( w_open, vSubItems, sel2, menu_offset + point( 0, -2 ) ); - wrefresh( w_open ); - catacurses::refresh(); - std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vNewGameHotkeys.size(); ++i ) { @@ -812,16 +840,11 @@ bool main_menu::new_character_tab() } if( !g->u.create( play_type ) ) { load_char_templates(); - werase( w_background ); - wrefresh( w_background ); MAPBUFFER.reset(); overmap_buffer.clear(); continue; } - werase( w_background ); - wrefresh( w_background ); - if( !g->start_game() ) { continue; } @@ -835,27 +858,13 @@ bool main_menu::new_character_tab() } else if( layer == 3 && sel1 == 1 ) { // Then view presets if( templates.empty() ) { - mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -4 ), - c_red, "%s", _( "No templates found!" ) ); on_error(); - } else { - mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -2 ), - c_white, "%s", _( "Press 'd' to delete a preset." ) ); - for( int i = 0; i < static_cast( templates.size() ); i++ ) { - int line = menu_offset.y - 4 - i; - mvwprintz( w_open, point( 20 + menu_offset.x + extra_w / 2, line ), - ( sel3 == i ? h_white : c_white ), "%s", - templates[i] ); - } } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); sel1 = 1; layer = 2; - print_menu( w_open, sel1, menu_offset ); } else if( action == "DOWN" ) { if( sel3 > 0 ) { sel3--; @@ -871,7 +880,6 @@ bool main_menu::new_character_tab() } else if( action == "LEFT" || action == "QUIT" ) { sel1 = 1; layer = 2; - print_menu( w_open, sel1, menu_offset ); } else if( !templates.empty() && action == "DELETE_TEMPLATE" ) { if( query_yn( _( "Are you sure you want to delete %s?" ), templates[sel3].c_str() ) ) { @@ -903,14 +911,10 @@ bool main_menu::new_character_tab() } if( !g->u.create( PLTYPE_TEMPLATE, templates[sel3] ) ) { load_char_templates(); - werase( w_background ); - wrefresh( w_background ); MAPBUFFER.reset(); overmap_buffer.clear(); continue; } - werase( w_background ); - wrefresh( w_background ); if( !g->start_game() ) { continue; } From d20ab7e45054752a32d5c2347b10b6760cfc31f4 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 20:09:27 +0800 Subject: [PATCH 050/219] Use ui_adaptor in main menu load character submenu --- src/main_menu.cpp | 66 ++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 2d6518b4de719..b020b054b2f15 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -964,15 +964,17 @@ bool main_menu::load_character_tab( bool transfer ) } } - const int offset_x = transfer ? 25 : 15; - const int offset_y = transfer ? -1 : 0; - while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { + ui_adaptor ui; + ui.on_redraw( [&]( const ui_adaptor & ) { + const int offset_x = transfer ? 25 : 15; + const int offset_y = transfer ? -1 : 0; + print_menu( w_open, transfer ? 3 : 2, menu_offset ); + if( layer == 2 && sel1 == 2 ) { if( all_worldnames.empty() ) { mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 ), c_red, "%s", _( "No Worlds found!" ) ); - on_error(); } else { for( int i = 0; i < static_cast( all_worldnames.size() ); ++i ) { int line = menu_offset.y - 2 - i; @@ -992,7 +994,40 @@ bool main_menu::load_character_tab( bool transfer ) } } wrefresh( w_open ); - catacurses::refresh(); + } else if( layer == 3 && sel1 == 2 ) { + const std::string &wn = all_worldnames[sel2]; + + mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 - sel2 + offset_y ), h_white, + "%s", wn ); + + if( savegames.empty() ) { + mvwprintz( w_open, menu_offset + point( 40 + extra_w / 2, -2 - sel2 + offset_y ), + c_red, "%s", _( "No save games found!" ) ); + } else { + int line = menu_offset.y - 2; + + for( const auto &savename : savegames ) { + const bool selected = sel3 + line == menu_offset.y - 2; + mvwprintz( w_open, point( 40 + menu_offset.x + extra_w / 2, line-- + offset_y ), + selected ? h_white : c_white, + "%s", savename.player_name() ); + } + } + wrefresh( w_open ); + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + + while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { + ui_manager::redraw(); + if( layer == 2 && sel1 == 2 ) { + if( all_worldnames.empty() ) { + on_error(); + } std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); @@ -1018,7 +1053,6 @@ bool main_menu::load_character_tab( bool transfer ) } } else if( layer == 3 && sel1 == 2 ) { savegames = world_generator->get_world( all_worldnames[sel2] )->world_saves; - const std::string &wn = all_worldnames[sel2]; if( MAP_SHARING::isSharing() ) { auto new_end = std::remove_if( savegames.begin(), savegames.end(), @@ -1028,25 +1062,9 @@ bool main_menu::load_character_tab( bool transfer ) savegames.erase( new_end, savegames.end() ); } - mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 - sel2 + offset_y ), h_white, - "%s", wn ); - if( savegames.empty() ) { - mvwprintz( w_open, menu_offset + point( 40 + extra_w / 2, -2 - sel2 + offset_y ), - c_red, "%s", _( "No save games found!" ) ); on_error(); - } else { - int line = menu_offset.y - 2; - - for( const auto &savename : savegames ) { - const bool selected = sel3 + line == menu_offset.y - 2; - mvwprintz( w_open, point( 40 + menu_offset.x + extra_w / 2, line-- + offset_y ), - selected ? h_white : c_white, - "%s", savename.player_name() ); - } } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); @@ -1066,7 +1084,6 @@ bool main_menu::load_character_tab( bool transfer ) } else if( action == "LEFT" || action == "QUIT" ) { layer = transfer ? 1 : 2; sel3 = 0; - print_menu( w_open, sel1, menu_offset ); } if( action == "RIGHT" || action == "CONFIRM" ) { if( sel3 >= 0 && sel3 < static_cast( savegames.size() ) ) { @@ -1075,9 +1092,6 @@ bool main_menu::load_character_tab( bool transfer ) world_generator->set_active_world( nullptr ); } ); - werase( w_background ); - wrefresh( w_background ); - WORLDPTR world = world_generator->get_world( all_worldnames[sel2] ); world_generator->last_world_name = world->world_name; world_generator->last_character_name = savegames[sel3].player_name(); From 33575a61fa3ef2773048373b5f4a90a31fd181c5 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 20:51:18 +0800 Subject: [PATCH 051/219] Use ui_adaptor in world tab --- src/main_menu.cpp | 105 ++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index b020b054b2f15..c416c97f2a41f 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -1125,8 +1125,67 @@ bool main_menu::load_character_tab( bool transfer ) void main_menu::world_tab() { + ui_adaptor ui; + ui.on_redraw( [this]( const ui_adaptor & ) { + if( sel1 == 3 ) { // bail out if we're actually in load_character_tab + print_menu( w_open, 3, menu_offset ); + + if( layer == 3 ) { // World Menu + const point offset = menu_offset + point( 40 + extra_w / 2, -2 - sel2 ); + + const auto all_worldnames = world_generator->all_worldnames(); + mvwprintz( w_open, offset + point( -15, 0 ), h_white, "%s", all_worldnames[sel2 - 1] ); + + for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { + nc_color text_color; + nc_color key_color; + if( sel3 == static_cast( i ) ) { + text_color = h_white; + key_color = h_white; + } else { + text_color = c_light_gray; + key_color = c_white; + } + wmove( w_open, offset + point( 0, -i ) ); + wprintz( w_open, c_light_gray, "[" ); + shortcut_print( w_open, text_color, key_color, vWorldSubItems[i] ); + wprintz( w_open, c_light_gray, "]" ); + } + + wrefresh( w_open ); + } else if( layer == 2 ) { // Show world names + mvwprintz( w_open, menu_offset + point( 25 + extra_w / 2, -2 ), + ( sel2 == 0 ? h_white : c_white ), "%s", _( "Create World" ) ); + + int i = 1; + const auto all_worldnames = world_generator->all_worldnames(); + for( auto it = all_worldnames.begin(); it != all_worldnames.end(); ++it, i++ ) { + int savegames_count = world_generator->get_world( *it )->world_saves.size(); + int line = menu_offset.y - 2 - i; + nc_color color1, color2; + if( *it == "TUTORIAL" || *it == "DEFENSE" ) { + color1 = c_light_cyan; + color2 = h_light_cyan; + } else { + color1 = c_white; + color2 = h_white; + } + mvwprintz( w_open, point( 25 + menu_offset.x + extra_w / 2, line ), + ( sel2 == i ? color2 : color1 ), "%s (%d)", ( *it ).c_str(), savegames_count ); + } + + wrefresh( w_open ); + } + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + while( sel1 == 3 && ( layer == 2 || layer == 3 || layer == 4 ) ) { - print_menu( w_open, 3, menu_offset ); + ui_manager::redraw(); if( layer == 4 ) { //Character to Template if( load_character_tab( true ) ) { points_left points; @@ -1145,9 +1204,6 @@ void main_menu::world_tab() load_char_templates(); - werase( w_background ); - wrefresh( w_background ); - layer = 3; } } else if( layer == 3 ) { // World Menu @@ -1156,29 +1212,8 @@ void main_menu::world_tab() // Reset empties world of everything but options, then makes new world within it. // Destroy asks for confirmation, then destroys everything in world and then removes world folder. - const point offset = menu_offset + point( 40 + extra_w / 2, -2 - sel2 ); - const auto all_worldnames = world_generator->all_worldnames(); - mvwprintz( w_open, offset + point( -15, 0 ), h_white, "%s", all_worldnames[sel2 - 1] ); - - for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { - nc_color text_color; - nc_color key_color; - if( sel3 == static_cast( i ) ) { - text_color = h_white; - key_color = h_white; - } else { - text_color = c_light_gray; - key_color = c_white; - } - wmove( w_open, offset + point( 0, -i ) ); - wprintz( w_open, c_light_gray, "[" ); - shortcut_print( w_open, text_color, key_color, vWorldSubItems[i] ); - wprintz( w_open, c_light_gray, "]" ); - } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { @@ -1256,28 +1291,8 @@ void main_menu::world_tab() continue; } - mvwprintz( w_open, menu_offset + point( 25 + extra_w / 2, -2 ), - ( sel2 == 0 ? h_white : c_white ), "%s", _( "Create World" ) ); - - int i = 1; const auto all_worldnames = world_generator->all_worldnames(); - for( auto it = all_worldnames.begin(); it != all_worldnames.end(); ++it, i++ ) { - int savegames_count = world_generator->get_world( *it )->world_saves.size(); - int line = menu_offset.y - 2 - i; - nc_color color1, color2; - if( *it == "TUTORIAL" || *it == "DEFENSE" ) { - color1 = c_light_cyan; - color2 = h_light_cyan; - } else { - color1 = c_white; - color2 = h_white; - } - mvwprintz( w_open, point( 25 + menu_offset.x + extra_w / 2, line ), - ( sel2 == i ? color2 : color1 ), "%s (%d)", ( *it ).c_str(), savegames_count ); - } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( action == "DOWN" ) { From a3ff920a36fe7878c4141a29d465ef460ca6600f Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 21:23:12 +0800 Subject: [PATCH 052/219] Remove w_background and use ui_adaptor to erase background instead --- src/game.cpp | 1 - src/main_menu.cpp | 30 ++++++++++++++++++------------ src/main_menu.h | 1 - 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index c591add5a16e5..aa2898ea3438c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2766,7 +2766,6 @@ void game::load( const save_t &name ) calendar::set_season_length( ::get_option( "SEASON_LENGTH" ) ); u.reset(); - draw(); } void game::load_world_modfiles( loading_ui &ui ) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index c416c97f2a41f..e34598f48e3b7 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -256,10 +256,6 @@ void main_menu::init_windows() return; } - w_background = catacurses::newwin( TERMY, TERMX, point_zero ); - werase( w_background ); - wrefresh( w_background ); - // main window should also expand to use available display space. // expanding to evenly use up half of extra space, for now. extra_w = ( ( TERMX - FULL_SCREEN_WIDTH ) / 2 ) - 1; @@ -468,6 +464,16 @@ bool main_menu::opening_screen() sel1 = 2; } + ui_adaptor background; + background.on_redraw( []( const ui_adaptor & ) { + catacurses::erase(); + catacurses::refresh(); + } ); + background.on_screen_resize( []( ui_adaptor & background ) { + background.position_from_window( catacurses::stdscr ); + } ); + background.position_from_window( catacurses::stdscr ); + ui_adaptor ui; ui.on_redraw( [&]( const ui_adaptor & ) { print_menu( w_open, sel1, menu_offset ); @@ -513,9 +519,9 @@ bool main_menu::opening_screen() } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); while( !start ) { // disable ime at program start @@ -761,9 +767,9 @@ bool main_menu::new_character_tab() } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); bool start = false; while( !start && sel1 == 1 && ( layer == 2 || layer == 3 ) ) { @@ -1018,9 +1024,9 @@ bool main_menu::load_character_tab( bool transfer ) } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { ui_manager::redraw(); @@ -1180,9 +1186,9 @@ void main_menu::world_tab() } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); while( sel1 == 3 && ( layer == 2 || layer == 3 || layer == 4 ) ) { ui_manager::redraw(); diff --git a/src/main_menu.h b/src/main_menu.h index 3247fd1d893f5..d15f77ceb2661 100644 --- a/src/main_menu.h +++ b/src/main_menu.h @@ -71,7 +71,6 @@ class main_menu int layer = 1; point LAST_TERM; catacurses::window w_open; - catacurses::window w_background; point menu_offset; std::vector templates; int extra_w = 0; From 42a309afa29b1145a1fc91db6bfb5dc051a6fc0d Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 22:15:15 +0800 Subject: [PATCH 053/219] Remove main_menu::handle_input_timeout now that we have proper window resizing --- src/main_menu.cpp | 29 +++++++++-------------------- src/main_menu.h | 1 - 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index e34598f48e3b7..6988f1f5f7cc1 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -239,17 +239,6 @@ std::vector main_menu::load_file( const std::string &path, return result; } -std::string main_menu::handle_input_timeout( input_context &ctxt ) -{ - std::string action = ctxt.handle_input( 1000 ); - - if( action == "TIMEOUT" ) { - init_windows(); - } - - return action; -} - void main_menu::init_windows() { if( LAST_TERM == point( TERMX, TERMY ) ) { @@ -531,7 +520,7 @@ bool main_menu::opening_screen() ui_manager::redraw(); if( layer == 1 ) { - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; // check automatic menu shortcuts @@ -608,7 +597,7 @@ bool main_menu::opening_screen() continue; } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( action == "LEFT" ) { if( sel2 > 0 ) { sel2--; @@ -655,7 +644,7 @@ bool main_menu::opening_screen() } } else if( sel1 == 5 ) { // Settings Menu int settings_subs_to_display = vSettingsSubItems.size(); - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; for( int i = 0; i < settings_subs_to_display; ++i ) { for( const std::string &hotkey : vSettingsHotkeys[i] ) { @@ -783,7 +772,7 @@ bool main_menu::new_character_tab() continue; } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vNewGameHotkeys.size(); ++i ) { for( const std::string &hotkey : vNewGameHotkeys[i] ) { @@ -866,7 +855,7 @@ bool main_menu::new_character_tab() if( templates.empty() ) { on_error(); } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( errflag && action != "TIMEOUT" ) { clear_error(); sel1 = 1; @@ -1034,7 +1023,7 @@ bool main_menu::load_character_tab( bool transfer ) if( all_worldnames.empty() ) { on_error(); } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( errflag && action != "TIMEOUT" ) { clear_error(); layer = 1; @@ -1071,7 +1060,7 @@ bool main_menu::load_character_tab( bool transfer ) if( savegames.empty() ) { on_error(); } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( errflag && action != "TIMEOUT" ) { clear_error(); layer = transfer ? 1 : 2; @@ -1220,7 +1209,7 @@ void main_menu::world_tab() const auto all_worldnames = world_generator->all_worldnames(); - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { for( const std::string &hotkey : vWorldHotkeys[i] ) { @@ -1299,7 +1288,7 @@ void main_menu::world_tab() const auto all_worldnames = world_generator->all_worldnames(); - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( action == "DOWN" ) { if( sel2 > 0 ) { diff --git a/src/main_menu.h b/src/main_menu.h index d15f77ceb2661..03548a2ed490b 100644 --- a/src/main_menu.h +++ b/src/main_menu.h @@ -102,7 +102,6 @@ class main_menu void display_text( const std::string &text, const std::string &title, int &selected ); void init_windows(); - std::string handle_input_timeout( input_context &ctxt ); static std::string halloween_spider(); std::string halloween_graves(); From 09a01120f6008acab9ef3837dc54d6bf4d99bacf Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 22:18:07 +0800 Subject: [PATCH 054/219] Do not change ime status when navigating main menu --- src/main_menu.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 6988f1f5f7cc1..647fe26bd39c4 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -513,16 +513,22 @@ bool main_menu::opening_screen() ui.position_from_window( w_open ); while( !start ) { - // disable ime at program start - // somehow this need to be here to actually work - disable_ime(); - ui_manager::redraw(); if( layer == 1 ) { std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; + + // switch off ime at program start + if( ctxt.get_raw_input().sequence.empty() ) { + // FIXME: disable_ime only seems to work after receiving an input event + // with empty input sequence. (empty input event is also fired when the + // window loses focus, might be related?) + disable_ime(); + continue; + } + // check automatic menu shortcuts for( size_t i = 0; i < vMenuHotkeys.size(); ++i ) { for( const std::string &hotkey : vMenuHotkeys[i] ) { From f03ce5f825df15e93e27d915c0057aaec5478fc2 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 11:24:20 +0800 Subject: [PATCH 055/219] Remove reinitialize_framebuffer now that we refresh main menu properly using ui_manager --- src/sdltiles.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index 7b9063aa56e6b..c526a81b9bf39 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -3215,9 +3215,6 @@ static void CheckMessages() // on focus gain. This seems to mess up the first redraw and // causes black screen that lasts ~0.5 seconds before the screen // contents are redrawn in the following code. - - // Main menu redraw - reinitialize_framebuffer(); window_dimensions dim = get_window_dimensions( catacurses::stdscr ); ui_manager::invalidate( rectangle( point_zero, dim.window_size_pixel ) ); ui_manager::redraw(); From 794776417f452990fc6f9159d9e9b951214d04dc Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 14:16:08 +0800 Subject: [PATCH 056/219] Use ui_adaptor in options menu --- src/options.cpp | 120 +++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/src/options.cpp b/src/options.cpp index 6d7b3504b99bc..413a567bbdbd3 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -22,6 +22,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "worldfactory.h" #include "color.h" @@ -2438,7 +2439,9 @@ static void draw_borders_external( mvwputch( w, point( 0, horizontal_level ), BORDER_COLOR, LINE_XXXO ); // |- mvwputch( w, point( getmaxx( w ) - 1, horizontal_level ), BORDER_COLOR, LINE_XOXX ); // -| for( auto &mapLine : mapLines ) { - mvwputch( w, point( mapLine.first + 1, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_XXOX ); // _|_ + if( mapLine.second ) { + mvwputch( w, point( mapLine.first + 1, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_XXOX ); // _|_ + } } wrefresh( w ); } @@ -2475,37 +2478,11 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) ingame = false; } - const int iWorldOffset = world_options_only ? 2 : 0; - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - const int iTooltipHeight = 4; - const int iContentHeight = TERMY - 3 - iTooltipHeight - iWorldOffset; - std::map mapLines; - std::map mapLinesOriginal; mapLines[4] = true; mapLines[60] = true; - catacurses::window w_options_border = catacurses::newwin( TERMY, iMinScreenWidth, - point( iOffsetX, 0 ) ); - catacurses::window w_options_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 + iWorldOffset ) ); - catacurses::window w_options_header = catacurses::newwin( 1, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 + iTooltipHeight + iWorldOffset ) ); - catacurses::window w_options = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, iTooltipHeight + 2 + iWorldOffset ) ); - - if( world_options_only ) { - worldfactory::draw_worldgen_tabs( w_options_border, 1 ); - } - - mapLinesOriginal = mapLines; - draw_borders_external( w_options_border, iTooltipHeight + 1 + iWorldOffset, mapLines, - world_options_only ); - draw_borders_internal( w_options_header, mapLines ); - int iCurrentPage = world_options_only ? iWorldOptPage : 0; - int iLastPage = 0; int iCurrentLine = 0; int iStartPos = 0; @@ -2517,7 +2494,63 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) ctxt.register_action( "CONFIRM" ); ctxt.register_action( "HELP_KEYBINDINGS" ); - while( true ) { + const int iWorldOffset = world_options_only ? 2 : 0; + int iMinScreenWidth = 0; + const int iTooltipHeight = 4; + int iContentHeight = 0; + + catacurses::window w_options_border; + catacurses::window w_options_tooltip; + catacurses::window w_options_header; + catacurses::window w_options; + + const auto init_windows = [&]( ui_adaptor & ui ) { + if( OPTIONS.find( "TERMINAL_X" ) != OPTIONS.end() ) { + if( OPTIONS_OLD.find( "TERMINAL_X" ) != OPTIONS_OLD.end() ) { + OPTIONS_OLD["TERMINAL_X"] = OPTIONS["TERMINAL_X"]; + } + if( WOPTIONS_OLD.find( "TERMINAL_X" ) != WOPTIONS_OLD.end() ) { + WOPTIONS_OLD["TERMINAL_X"] = OPTIONS["TERMINAL_X"]; + } + } + if( OPTIONS.find( "TERMINAL_Y" ) != OPTIONS.end() ) { + if( OPTIONS_OLD.find( "TERMINAL_Y" ) != OPTIONS_OLD.end() ) { + OPTIONS_OLD["TERMINAL_Y"] = OPTIONS["TERMINAL_Y"]; + } + if( WOPTIONS_OLD.find( "TERMINAL_Y" ) != WOPTIONS_OLD.end() ) { + WOPTIONS_OLD["TERMINAL_Y"] = OPTIONS["TERMINAL_Y"]; + } + } + + + iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + iContentHeight = TERMY - 3 - iTooltipHeight - iWorldOffset; + + w_options_border = catacurses::newwin( TERMY, iMinScreenWidth, + point( iOffsetX, 0 ) ); + w_options_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 + iWorldOffset ) ); + w_options_header = catacurses::newwin( 1, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 + iTooltipHeight + iWorldOffset ) ); + w_options = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, iTooltipHeight + 2 + iWorldOffset ) ); + + ui.position_from_window( w_options_border ); + }; + + ui_adaptor ui; + ui.on_screen_resize( init_windows ); + init_windows( ui ); + ui.on_redraw( [&]( const ui_adaptor & ) { + if( world_options_only ) { + worldfactory::draw_worldgen_tabs( w_options_border, 1 ); + } + + draw_borders_external( w_options_border, iTooltipHeight + 1 + iWorldOffset, mapLines, + world_options_only ); + draw_borders_internal( w_options_header, mapLines ); + Page &page = pages_[iCurrentPage]; auto &page_items = page.items_; @@ -2656,22 +2689,31 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) current_opt.getDefaultText() ); } - if( iCurrentPage != iLastPage ) { - iLastPage = iCurrentPage; - if( ingame && iCurrentPage == iWorldOptPage ) { - mvwprintz( w_options_tooltip, point( 3, 3 ), c_light_red, "%s", _( "Note: " ) ); - wprintz( w_options_tooltip, c_white, "%s", - _( "Some of these options may produce unexpected results if changed." ) ); - } + if( ingame && iCurrentPage == iWorldOptPage ) { + mvwprintz( w_options_tooltip, point( 3, 3 ), c_light_red, "%s", _( "Note: " ) ); + wprintz( w_options_tooltip, c_white, "%s", + _( "Some of these options may produce unexpected results if changed." ) ); } wrefresh( w_options_tooltip ); wrefresh( w_options ); + } ); + + while( true ) { + ui_manager::redraw(); + + Page &page = pages_[iCurrentPage]; + auto &page_items = page.items_; + + auto &cOPTIONS = ( ingame || world_options_only ) && iCurrentPage == iWorldOptPage ? + ACTIVE_WORLD_OPTIONS : OPTIONS; + + const std::string &opt_name = *page_items[iCurrentLine]; + cOpt ¤t_opt = cOPTIONS[opt_name]; const std::string action = ctxt.handle_input(); if( world_options_only && ( action == "NEXT_TAB" || action == "PREV_TAB" || action == "QUIT" ) ) { - catacurses::refresh(); return action; } @@ -2754,9 +2796,6 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) } } } - } else if( action == "HELP_KEYBINDINGS" ) { - draw_borders_external( w_options_border, iTooltipHeight + 1 + iWorldOffset, mapLinesOriginal, - world_options_only ); } else if( action == "QUIT" ) { break; } @@ -2823,9 +2862,6 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) } } - catacurses::clear(); - catacurses::refresh(); - if( lang_changed ) { update_global_locale(); set_language(); From 71c40ab89f399456a7ce473efdcc795531b4bbc1 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 17:39:23 +0800 Subject: [PATCH 057/219] use ui_adaptor in worldfactory::pick_world --- src/worldfactory.cpp | 123 ++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 54 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 84d4cc4db38c8..3f5987788e4b5 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -28,6 +28,7 @@ #include "path_info.h" #include "string_formatter.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "game.h" #include "string_id.h" @@ -373,62 +374,75 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) } const int iTooltipHeight = 3; - const int iContentHeight = TERMY - 3 - iTooltipHeight; - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - const size_t num_pages = world_names.size() / iContentHeight + 1; // at least 1 page + int iContentHeight = 0; + int iMinScreenWidth = 0; + size_t num_pages = 1; std::map mapLines; mapLines[3] = true; std::map > world_pages; - size_t worldnum = 0; - for( size_t i = 0; i < num_pages; ++i ) { - for( int j = 0; j < iContentHeight && worldnum < world_names.size(); ++j ) { - world_pages[i].push_back( world_names[ worldnum++ ] ); - } - } size_t sel = 0, selpage = 0; - catacurses::window w_worlds_border = catacurses::newwin( TERMY, iMinScreenWidth, - point( iOffsetX, 0 ) ); - catacurses::window w_worlds_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 ) ); - catacurses::window w_worlds_header = catacurses::newwin( 1, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 + iTooltipHeight ) ); - catacurses::window w_worlds = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, iTooltipHeight + 2 ) ); - - draw_border( w_worlds_border, BORDER_COLOR, _( " WORLD SELECTION " ) ); - mvwputch( w_worlds_border, point( 0, 4 ), BORDER_COLOR, LINE_XXXO ); // |- - mvwputch( w_worlds_border, point( iMinScreenWidth - 1, 4 ), BORDER_COLOR, LINE_XOXX ); // -| - - for( auto &mapLine : mapLines ) { - mvwputch( w_worlds_border, point( mapLine.first + 1, TERMY - 1 ), BORDER_COLOR, - LINE_XXOX ); // _|_ - } + catacurses::window w_worlds_border; + catacurses::window w_worlds_tooltip; + catacurses::window w_worlds_header; + catacurses::window w_worlds; - wrefresh( w_worlds_border ); + ui_adaptor ui; - for( int i = 0; i < getmaxx( w_worlds_border ); i++ ) { - if( mapLines[i] ) { - mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXXX ); - } else { - mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXOX ); // Draw header line + const auto init_windows = [&]( ui_adaptor & ui ) { + iContentHeight = TERMY - 3 - iTooltipHeight; + iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + num_pages = world_names.size() / iContentHeight + 1; // at least 1 page + + world_pages.clear(); + size_t worldnum = 0; + for( size_t i = 0; i < num_pages; ++i ) { + for( int j = 0; j < iContentHeight && worldnum < world_names.size(); ++j ) { + world_pages[i].push_back( world_names[ worldnum++ ] ); + } } - } - wrefresh( w_worlds_header ); + w_worlds_border = catacurses::newwin( TERMY, iMinScreenWidth, + point( iOffsetX, 0 ) ); + w_worlds_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 ) ); + w_worlds_header = catacurses::newwin( 1, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 + iTooltipHeight ) ); + w_worlds = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, iTooltipHeight + 2 ) ); - input_context ctxt( "PICK_WORLD_DIALOG" ); - ctxt.register_updown(); - ctxt.register_action( "HELP_KEYBINDINGS" ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "NEXT_TAB" ); - ctxt.register_action( "PREV_TAB" ); - ctxt.register_action( "CONFIRM" ); + ui.position_from_window( w_worlds_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_worlds_border, BORDER_COLOR, _( " WORLD SELECTION " ) ); + mvwputch( w_worlds_border, point( 0, 4 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( w_worlds_border, point( iMinScreenWidth - 1, 4 ), BORDER_COLOR, LINE_XOXX ); // -| + + for( auto &mapLine : mapLines ) { + if( mapLine.second ) { + mvwputch( w_worlds_border, point( mapLine.first + 1, TERMY - 1 ), BORDER_COLOR, + LINE_XXOX ); // _|_ + } + } + + wrefresh( w_worlds_border ); + + for( int i = 0; i < getmaxx( w_worlds_border ); i++ ) { + if( mapLines[i] ) { + mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXXX ); + } else { + mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXOX ); // Draw header line + } + } + + wrefresh( w_worlds_header ); - while( true ) { //Clear the lines for( int i = 0; i < iContentHeight; i++ ) { for( int j = 0; j < getmaxx( w_worlds ); j++ ) { @@ -481,12 +495,22 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) wrefresh( w_worlds_tooltip ); wrefresh( w_worlds ); + } ); + + input_context ctxt( "PICK_WORLD_DIALOG" ); + ctxt.register_updown(); + ctxt.register_action( "HELP_KEYBINDINGS" ); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "NEXT_TAB" ); + ctxt.register_action( "PREV_TAB" ); + ctxt.register_action( "CONFIRM" ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "QUIT" ) { - catacurses::clear(); - catacurses::refresh(); break; } else if( !world_pages[selpage].empty() && action == "DOWN" ) { sel++; @@ -520,19 +544,10 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) } } while( world_pages[selpage].empty() ); } else if( action == "CONFIRM" ) { - werase( w_worlds ); - werase( w_worlds_border ); - werase( w_worlds_header ); - werase( w_worlds_tooltip ); return get_world( world_pages[selpage][sel] ); } } - werase( w_worlds ); - werase( w_worlds_border ); - werase( w_worlds_header ); - werase( w_worlds_tooltip ); - return nullptr; } From 961b60ca615f6d14fbe23a4f9d35b9e02155ae6f Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 19:00:52 +0800 Subject: [PATCH 058/219] Use ui_adaptor in worldfactory::make_new_world --- src/worldfactory.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 3f5987788e4b5..d1e400f39a625 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -139,19 +139,32 @@ WORLDPTR worldfactory::make_new_world( bool show_prompt, const std::string &worl retworld->COPY_WORLD( world_generator->get_world( world_to_copy ) ); } - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - if( show_prompt ) { // set up window - catacurses::window wf_win = catacurses::newwin( TERMY, iMinScreenWidth, point( iOffsetX, 0 ) ); + catacurses::window wf_win; + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + wf_win = catacurses::newwin( TERMY, iMinScreenWidth, point( iOffsetX, 0 ) ); + ui.position_from_window( wf_win ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int curtab = 0; + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_worldgen_tabs( wf_win, static_cast( curtab ) ); + wrefresh( wf_win ); + } ); + int lasttab = 0; // give placement memory to menus, sorta. const size_t numtabs = tabs.size(); while( static_cast( curtab ) < numtabs ) { + ui_manager::redraw(); lasttab = curtab; - draw_worldgen_tabs( wf_win, static_cast( curtab ) ); curtab += tabs[curtab]( wf_win, retworld.get() ); // If it is -1, or for unsigned size_t, it would be max. @@ -162,8 +175,6 @@ WORLDPTR worldfactory::make_new_world( bool show_prompt, const std::string &worl } } if( curtab < 0 ) { - catacurses::clear(); - catacurses::refresh(); return nullptr; } } From 078d82fd573aa62b269728213189ab25454312cd Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 10:18:00 +0800 Subject: [PATCH 059/219] Use ui_adaptor in world_factory::show_worldgen_tab_modselection --- src/worldfactory.cpp | 219 ++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 127 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index d1e400f39a625..86ec42963e186 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -825,33 +825,47 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, ctxt.register_action( "SAVE_DEFAULT_MODS" ); ctxt.register_action( "VIEW_MOD_DESCRIPTION" ); - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + catacurses::window w_header1; + catacurses::window w_header2; + catacurses::window w_shift; + catacurses::window w_list; + catacurses::window w_active; + catacurses::window w_description; + std::vector header_windows; + + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + + w_header1 = catacurses::newwin( 1, iMinScreenWidth / 2 - 5, + point( 1 + iOffsetX, 3 ) ); + w_header2 = catacurses::newwin( 1, iMinScreenWidth / 2 - 4, + point( iMinScreenWidth / 2 + 3 + iOffsetX, 3 ) ); + w_shift = catacurses::newwin( TERMY - 11, 5, + point( iMinScreenWidth / 2 - 3 + iOffsetX, 3 ) ); + w_list = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, + point( iOffsetX, 5 ) ); + w_active = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, + point( iMinScreenWidth / 2 + 2 + iOffsetX, 5 ) ); + w_description = catacurses::newwin( 4, iMinScreenWidth - 4, + point( 1 + iOffsetX, TERMY - 5 ) ); + + header_windows.clear(); + header_windows.push_back( w_header1 ); + header_windows.push_back( w_header2 ); + + ui.position_from_window( win ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); - // lots of small windows so that each section can be drawn to independently of the others as necessary - catacurses::window w_header1 = catacurses::newwin( 1, iMinScreenWidth / 2 - 5, - point( 1 + iOffsetX, 3 ) ); - catacurses::window w_header2 = catacurses::newwin( 1, iMinScreenWidth / 2 - 4, - point( iMinScreenWidth / 2 + 3 + iOffsetX, 3 ) ); - catacurses::window w_shift = catacurses::newwin( TERMY - 11, 5, - point( iMinScreenWidth / 2 - 3 + iOffsetX, 3 ) ); - catacurses::window w_list = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, - point( iOffsetX, 5 ) ); - catacurses::window w_active = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, - point( iMinScreenWidth / 2 + 2 + iOffsetX, 5 ) ); - catacurses::window w_description = catacurses::newwin( 4, iMinScreenWidth - 4, - point( 1 + iOffsetX, TERMY - 5 ) ); - - draw_modselection_borders( win, ctxt ); std::vector headers; headers.push_back( _( "Mod List" ) ); headers.push_back( _( "Mod Load Order" ) ); - std::vector header_windows; - header_windows.push_back( w_header1 ); - header_windows.push_back( w_header2 ); int tab_output = 0; - size_t last_active_header = 0; size_t active_header = 0; size_t useable_mod_count = mman->get_usable_mods().size(); int startsel[2] = {0, 0}; @@ -859,11 +873,6 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, size_t iCurrentTab = 0; std::vector current_tab_mods; - bool redraw_headers = true; - bool redraw_description = true; - bool redraw_list = true; - bool redraw_active = true; - bool selection_changed = false; bool recalc_tabs = true; // Helper function for determining the currently selected mod @@ -881,35 +890,68 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, return nullptr; }; - // Helper function to trigger full redraw on mod selection screen - const auto redraw_all = [&]() { - redraw_headers = true; - redraw_list = true; - redraw_active = true; - redraw_description = true; + ui.on_redraw( [&]( const ui_adaptor & ) { draw_worldgen_tabs( win, 0 ); draw_modselection_borders( win, ctxt ); - }; - while( tab_output == 0 ) { - if( redraw_headers ) { - for( size_t i = 0; i < headers.size(); ++i ) { - werase( header_windows[i] ); - const int header_x = ( getmaxx( header_windows[i] ) - utf8_width( headers[i] ) ) / 2; - mvwprintz( header_windows[i], point( header_x, 0 ), c_cyan, headers[i] ); - - if( active_header == i ) { - mvwputch( header_windows[i], point( header_x - 3, 0 ), c_red, '<' ); - mvwputch( header_windows[i], point( header_x + utf8_width( headers[i] ) + 2, 0 ), - c_red, '>' ); - } - wrefresh( header_windows[i] ); + // Redraw headers + for( size_t i = 0; i < headers.size(); ++i ) { + werase( header_windows[i] ); + const int header_x = ( getmaxx( header_windows[i] ) - utf8_width( headers[i] ) ) / 2; + mvwprintz( header_windows[i], point( header_x, 0 ), c_cyan, headers[i] ); + + if( active_header == i ) { + mvwputch( header_windows[i], point( header_x - 3, 0 ), c_red, '<' ); + mvwputch( header_windows[i], point( header_x + utf8_width( headers[i] ) + 2, 0 ), + c_red, '>' ); + } + wrefresh( header_windows[i] ); + } + + // Redraw description + werase( w_description ); + + if( const MOD_INFORMATION *selmod = get_selected_mod() ) { + // NOLINTNEXTLINE(cata-use-named-point-constants) + int num_lines = fold_and_print( w_description, point( 1, 0 ), + getmaxx( w_description ) - 1, + c_white, mman_ui->get_information( selmod ) ); + auto window_height = catacurses::getmaxy( w_description ); + auto window_width = catacurses::getmaxx( w_description ); + if( num_lines > window_height ) { + // The description didn't fit in the window, so provide a + // hint for how to see the whole thing + std::string message = string_format( _( "…%s = View full description " ), + ctxt.get_desc( "VIEW_MOD_DESCRIPTION" ) ); + nc_color color = c_green; + print_colored_text( w_description, point( window_width - utf8_width( message ), window_height - 1 ), + color, color, message ); } - redraw_list = true; - redraw_active = true; - redraw_headers = false; } + //redraw tabs + wmove( win, point( 2, 4 ) ); + for( size_t i = 0; i < get_mod_list_tabs().size(); i++ ) { + wprintz( win, c_white, "[" ); + wprintz( win, ( iCurrentTab == i ) ? hilite( c_light_green ) : c_light_green, + _( get_mod_list_tabs()[i].second ) ); + wprintz( win, c_white, "]" ); + wputch( win, BORDER_COLOR, LINE_OXOX ); + } + + wrefresh( w_description ); + wrefresh( win ); + + // Redraw list + draw_mod_list( w_list, startsel[0], cursel[0], current_tab_mods, active_header == 0, + _( "--NO AVAILABLE MODS--" ), catacurses::window() ); + + // Redraw active + draw_mod_list( w_active, startsel[1], cursel[1], active_mod_order, active_header == 1, + _( "--NO ACTIVE MODS--" ), w_shift ); + } ); + + while( tab_output == 0 ) { if( recalc_tabs ) { current_tab_mods.clear(); @@ -932,64 +974,8 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, recalc_tabs = false; } - if( selection_changed ) { - if( active_header == 0 ) { - redraw_list = true; - } - if( active_header == 1 ) { - redraw_active = true; - } - selection_changed = false; - redraw_description = true; - } - - if( redraw_description ) { - werase( w_description ); - - if( const MOD_INFORMATION *selmod = get_selected_mod() ) { - // NOLINTNEXTLINE(cata-use-named-point-constants) - int num_lines = fold_and_print( w_description, point( 1, 0 ), - getmaxx( w_description ) - 1, - c_white, mman_ui->get_information( selmod ) ); - auto window_height = catacurses::getmaxy( w_description ); - auto window_width = catacurses::getmaxx( w_description ); - if( num_lines > window_height ) { - // The description didn't fit in the window, so provide a - // hint for how to see the whole thing - std::string message = string_format( _( "…%s = View full description " ), - ctxt.get_desc( "VIEW_MOD_DESCRIPTION" ) ); - nc_color color = c_green; - print_colored_text( w_description, point( window_width - utf8_width( message ), window_height - 1 ), - color, color, message ); - } - } - - //redraw tabs - wmove( win, point( 2, 4 ) ); - for( size_t i = 0; i < get_mod_list_tabs().size(); i++ ) { - wprintz( win, c_white, "[" ); - wprintz( win, ( iCurrentTab == i ) ? hilite( c_light_green ) : c_light_green, - _( get_mod_list_tabs()[i].second ) ); - wprintz( win, c_white, "]" ); - wputch( win, BORDER_COLOR, LINE_OXOX ); - } - - redraw_description = false; - wrefresh( w_description ); - wrefresh( win ); - } - - if( redraw_list ) { - draw_mod_list( w_list, startsel[0], cursel[0], current_tab_mods, active_header == 0, - _( "--NO AVAILABLE MODS--" ), catacurses::window() ); - } - if( redraw_active ) { - draw_mod_list( w_active, startsel[1], cursel[1], active_mod_order, active_header == 1, - _( "--NO ACTIVE MODS--" ), w_shift ); - } - catacurses::refresh(); + ui_manager::redraw(); - last_active_header = active_header; const int next_header = ( active_header == 1 ) ? 0 : 1; const int prev_header = ( active_header == 0 ) ? 1 : 0; @@ -1020,12 +1006,9 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, if( active_header == 0 && !current_tab_mods.empty() ) { // try-add mman_ui->try_add( current_tab_mods[cursel[0]], active_mod_order ); - redraw_active = true; } else if( active_header == 1 && !active_mod_order.empty() ) { // try-rem mman_ui->try_rem( cursel[1], active_mod_order ); - redraw_active = true; - redraw_description = true; if( active_mod_order.empty() ) { // switch back to other list, we can't change // anything in the empty active mods list. @@ -1035,13 +1018,10 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, } else if( action == "ADD_MOD" ) { if( active_header == 1 && active_mod_order.size() > 1 ) { mman_ui->try_shift( '+', cursel[1], active_mod_order ); - redraw_active = true; } } else if( action == "REMOVE_MOD" ) { if( active_header == 1 && active_mod_order.size() > 1 ) { mman_ui->try_shift( '-', cursel[1], active_mod_order ); - redraw_active = true; - redraw_description = true; } } else if( action == "NEXT_CATEGORY_TAB" ) { if( active_header == 0 ) { @@ -1053,7 +1033,6 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, cursel[0] = 0; recalc_tabs = true; - redraw_description = true; } } else if( action == "PREV_CATEGORY_TAB" ) { @@ -1066,7 +1045,6 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, cursel[0] = 0; recalc_tabs = true; - redraw_description = true; } } else if( action == "NEXT_TAB" ) { tab_output = 1; @@ -1076,36 +1054,23 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, if( mman->set_default_mods( active_mod_order ) ) { popup( _( "Saved list of active mods as default" ) ); draw_modselection_borders( win, ctxt ); - redraw_description = true; - redraw_headers = true; } } else if( action == "VIEW_MOD_DESCRIPTION" ) { if( const MOD_INFORMATION *selmod = get_selected_mod() ) { popup( "%s", mman_ui->get_information( selmod ) ); - redraw_all(); } - } else if( action == "HELP_KEYBINDINGS" ) { - redraw_all(); } else if( action == "QUIT" ) { tab_output = -999; } // RESOLVE INPUTS - if( last_active_header != active_header ) { - redraw_headers = true; - redraw_description = true; - } if( last_selection != selection ) { if( active_header == 0 ) { - redraw_list = true; cursel[0] = selection; } else { - redraw_active = true; cursel[1] = selection; } - redraw_description = true; } if( active_mod_order.empty() ) { - redraw_active = true; cursel[1] = 0; } From 0601ce2f8704576dfdb567d879656b919f2e8c9d Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 10:48:55 +0800 Subject: [PATCH 060/219] Remove manual refresh in worldfactory::show_worldgen_tab_options --- src/worldfactory.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 86ec42963e186..973b34a64b77c 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -605,7 +605,7 @@ std::string worldfactory::pick_random_name() return get_next_valid_worldname(); } -int worldfactory::show_worldgen_tab_options( const catacurses::window &win, WORLDPTR world ) +int worldfactory::show_worldgen_tab_options( const catacurses::window &, WORLDPTR world ) { get_options().set_world_options( &world->WORLD_OPTIONS ); const std::string action = get_options().show( false, true ); @@ -616,10 +616,6 @@ int worldfactory::show_worldgen_tab_options( const catacurses::window &win, WORL } else if( action == "NEXT_TAB" ) { return 1; - } else if( action == "HELP_KEYBINDINGS" ) { - draw_worldgen_tabs( win, 1 ); - catacurses::refresh(); - } else if( action == "QUIT" ) { return -999; } From 860eecf9070c9fb9616b0e841f470898e6598c9d Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 12:11:30 +0800 Subject: [PATCH 061/219] Use ui_adaptor in worldfactory::show_worldgen_tab_confirm --- src/worldfactory.cpp | 69 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 973b34a64b77c..6846a016197f5 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -1091,15 +1091,23 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORLDPTR world ) { - const int iTooltipHeight = 1; - const int iContentHeight = TERMY - 3 - iTooltipHeight; - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + catacurses::window w_confirmation; + + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iTooltipHeight = 1; + const int iContentHeight = TERMY - 3 - iTooltipHeight; + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - const char *line_of_32_underscores = "________________________________"; + w_confirmation = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, iTooltipHeight + 2 ) ); - catacurses::window w_confirmation = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, iTooltipHeight + 2 ) ); + ui.position_from_window( win ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int namebar_y = 1; int namebar_x = 3 + utf8_width( _( "World Name:" ) ); @@ -1117,9 +1125,11 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL // do not switch IME mode now, but restore previous mode on return ime_sentry sentry( ime_sentry::keep ); - do { + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_worldgen_tabs( win, 2 ); + mvwprintz( w_confirmation, point( 2, namebar_y ), c_white, _( "World Name:" ) ); - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); fold_and_print( w_confirmation, point( 2, 3 ), getmaxx( w_confirmation ) - 2, c_light_gray, _( "Press %s to pick a random name for your world." ), ctxt.get_desc( "PICK_RANDOM_WORLDNAME" ) ); @@ -1128,64 +1138,56 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL _( "Press %s when you are satisfied with the world as it is and are ready " "to continue, or %s to go back and review your world." ), ctxt.get_desc( "NEXT_TAB" ), ctxt.get_desc( "PREV_TAB" ) ); - if( !noname ) { + if( noname ) { + mvwprintz( w_confirmation, point( namebar_x, namebar_y ), h_light_gray, + _( "________NO NAME ENTERED!________" ) ); + } else { mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, worldname ); wprintz( w_confirmation, h_light_gray, "_" ); - } - if( noname ) { - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); - noname = false; + for( int underscores = 31 - utf8_width( worldname ); + underscores > 0; --underscores ) { + wprintz( w_confirmation, c_light_gray, "_" ); + } } wrefresh( win ); wrefresh( w_confirmation ); - catacurses::refresh(); + } ); + + do { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "NEXT_TAB" ) { if( worldname.empty() ) { - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), h_light_gray, - _( "________NO NAME ENTERED!________" ) ); noname = true; - wrefresh( w_confirmation ); + ui_manager::redraw(); if( !query_yn( _( "Are you SURE you're finished? World name will be randomly generated." ) ) ) { - werase( w_confirmation ); + noname = false; continue; } else { + noname = false; world->world_name = pick_random_name(); if( !valid_worldname( world->world_name ) ) { continue; } - catacurses::clear(); - catacurses::refresh(); return 1; } } else if( query_yn( _( "Are you SURE you're finished?" ) ) ) { - // erase entire window to avoid overlapping of query with possible popup about invalid worldname - werase( w_confirmation ); - wrefresh( w_confirmation ); - catacurses::clear(); - catacurses::refresh(); - if( valid_worldname( worldname ) ) { world->world_name = worldname; - catacurses::refresh(); return 1; } else { continue; } } else { - werase( w_confirmation ); continue; } } else if( action == "PREV_TAB" ) { world->world_name = worldname; return -1; } else if( action == "PICK_RANDOM_WORLDNAME" ) { - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); world->world_name = worldname = pick_random_name(); - } else if( action == "HELP_KEYBINDINGS" ) { - draw_worldgen_tabs( win, 2 ); } else if( action == "QUIT" ) { // Cache the current name just in case they say No to the exit query. world->world_name = worldname; @@ -1211,9 +1213,6 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL wrap.append( newtext ); worldname = wrap.str(); } - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, worldname ); - wprintz( w_confirmation, h_light_gray, "_" ); } } while( true ); From be4d90719503d03e139f934dc23cc597ee0c6a33 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 12:38:57 +0800 Subject: [PATCH 062/219] Use ui_adaptor in worldfactory::show_active_world_mods --- src/worldfactory.cpp | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 6846a016197f5..2e8ecbbd725c2 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -742,30 +742,46 @@ void worldfactory::draw_mod_list( const catacurses::window &w, int &start, size_ void worldfactory::show_active_world_mods( const std::vector &world_mods ) { - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + ui_adaptor ui; + catacurses::window w_border; + catacurses::window w_mods; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - catacurses::window w_border = catacurses::newwin( TERMY - 11, iMinScreenWidth / 2 - 3, - point( iOffsetX, 4 ) ); - catacurses::window w_mods = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, - point( iOffsetX, 5 ) ); + w_border = catacurses::newwin( TERMY - 11, iMinScreenWidth / 2 - 3, + point( iOffsetX, 4 ) ); + w_mods = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, + point( iOffsetX, 5 ) ); + + ui.position_from_window( w_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int start = 0; int cursor = 0; const size_t num_mods = world_mods.size(); - draw_border( w_border, BORDER_COLOR, _( " ACTIVE WORLD MODS " ) ); - wrefresh( w_border ); + input_context ctxt( "DEFAULT" ); + ctxt.register_updown(); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "CONFIRM" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_border, BORDER_COLOR, _( " ACTIVE WORLD MODS " ) ); + wrefresh( w_border ); - while( true ) { draw_mod_list( w_mods, start, static_cast( cursor ), world_mods, true, _( "--NO ACTIVE MODS--" ), catacurses::window() ); wrefresh( w_mods ); + } ); + + while( true ) { + ui_manager::redraw(); - input_context ctxt( "DEFAULT" ); - ctxt.register_updown(); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "CONFIRM" ); const std::string action = ctxt.handle_input(); if( action == "UP" ) { @@ -783,8 +799,6 @@ void worldfactory::show_active_world_mods( const std::vector &world_mods } } else if( action == "QUIT" || action == "CONFIRM" ) { - catacurses::clear(); - catacurses::refresh(); break; } } From 8f7680eb2f507ba0b7bad97d59c1b8ab5b330618 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 13:53:18 +0800 Subject: [PATCH 063/219] Use ui_adaptor in auto pickup menu --- src/auto_pickup.cpp | 181 ++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 80 deletions(-) diff --git a/src/auto_pickup.cpp b/src/auto_pickup.cpp index 6a37e4b1e77c2..d9553a3529abc 100644 --- a/src/auto_pickup.cpp +++ b/src/auto_pickup.cpp @@ -23,6 +23,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "cursesdef.h" #include "item.h" @@ -45,29 +46,38 @@ void user_interface::show() } const int iHeaderHeight = 4; - const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; + int iContentHeight = 0; + const int iTotalCols = 2; - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; - const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + catacurses::window w_border; + catacurses::window w_header; + catacurses::window w; - const int iTotalCols = 2; + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + + w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, + point( iOffsetX, iOffsetY ) ); + w_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, 1 + iOffsetY ) ); + w = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); + + ui.position_from_window( w_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); + + size_t iTab = 0; + int iLine = 0; + int iColumn = 1; + int iStartPos = 0; - catacurses::window w_help = catacurses::newwin( FULL_SCREEN_HEIGHT / 2 + 2, - FULL_SCREEN_WIDTH * 3 / 4, - point( iOffsetX + 19 / 2, 7 + iOffsetY + FULL_SCREEN_HEIGHT / 2 / 2 ) ); - - catacurses::window w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, - point( iOffsetX, iOffsetY ) ); - catacurses::window w_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, 1 + iOffsetY ) ); - catacurses::window w = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); - - /** - * All of the stuff in this lambda needs to be drawn (1) initially, and - * (2) after closing the HELP_KEYBINDINGS window (since it mangles the screen) - */ - const auto initial_draw = [&]() { + ui.on_redraw( [&]( const ui_adaptor & ) { // Redraw the border draw_border( w_border, BORDER_COLOR, title ); // |- @@ -110,43 +120,7 @@ void user_interface::show() mvwprintz( w_header, point( 1, 3 ), c_white, "#" ); mvwprintz( w_header, point( 8, 3 ), c_white, _( "Rules" ) ); mvwprintz( w_header, point( 52, 3 ), c_white, _( "I/E" ) ); - wrefresh( w_header ); - }; - - initial_draw(); - size_t iTab = 0; - int iLine = 0; - int iColumn = 1; - int iStartPos = 0; - bStuffChanged = false; - input_context ctxt( "AUTO_PICKUP" ); - ctxt.register_cardinal(); - ctxt.register_action( "CONFIRM" ); - ctxt.register_action( "QUIT" ); - if( tabs.size() > 1 ) { - ctxt.register_action( "NEXT_TAB" ); - ctxt.register_action( "PREV_TAB" ); - } - ctxt.register_action( "ADD_RULE" ); - ctxt.register_action( "REMOVE_RULE" ); - ctxt.register_action( "COPY_RULE" ); - ctxt.register_action( "ENABLE_RULE" ); - ctxt.register_action( "DISABLE_RULE" ); - ctxt.register_action( "MOVE_RULE_UP" ); - ctxt.register_action( "MOVE_RULE_DOWN" ); - ctxt.register_action( "TEST_RULE" ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - - const bool allow_swapping = tabs.size() == 2; - if( allow_swapping ) { - ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); - } - if( is_autopickup ) { - ctxt.register_action( "SWITCH_AUTO_PICKUP_OPTION" ); - } - - while( true ) { rule_list &cur_rules = tabs[iTab].new_rules; int locx = 17; for( size_t i = 0; i < tabs.size(); i++ ) { @@ -176,8 +150,6 @@ void user_interface::show() } } - const bool currentPageNonEmpty = !cur_rules.empty(); - draw_scrollbar( w_border, iLine, iContentHeight, cur_rules.size(), point( 0, 5 ) ); wrefresh( w_border ); @@ -209,6 +181,42 @@ void user_interface::show() } wrefresh( w ); + } ); + + bStuffChanged = false; + input_context ctxt( "AUTO_PICKUP" ); + ctxt.register_cardinal(); + ctxt.register_action( "CONFIRM" ); + ctxt.register_action( "QUIT" ); + if( tabs.size() > 1 ) { + ctxt.register_action( "NEXT_TAB" ); + ctxt.register_action( "PREV_TAB" ); + } + ctxt.register_action( "ADD_RULE" ); + ctxt.register_action( "REMOVE_RULE" ); + ctxt.register_action( "COPY_RULE" ); + ctxt.register_action( "ENABLE_RULE" ); + ctxt.register_action( "DISABLE_RULE" ); + ctxt.register_action( "MOVE_RULE_UP" ); + ctxt.register_action( "MOVE_RULE_DOWN" ); + ctxt.register_action( "TEST_RULE" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + const bool allow_swapping = tabs.size() == 2; + if( allow_swapping ) { + ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); + } + + if( is_autopickup ) { + ctxt.register_action( "SWITCH_AUTO_PICKUP_OPTION" ); + } + + while( true ) { + rule_list &cur_rules = tabs[iTab].new_rules; + + const bool currentPageNonEmpty = !cur_rules.empty(); + + ui_manager::redraw(); const std::string action = ctxt.handle_input(); @@ -268,27 +276,43 @@ void user_interface::show() cur_rules.push_back( rule( "", true, false ) ); iLine = cur_rules.size() - 1; } + ui_manager::redraw(); if( iColumn == 1 || action == "ADD_RULE" ) { - // NOLINTNEXTLINE(cata-use-named-point-constants) - fold_and_print( w_help, point( 1, 1 ), 999, c_white, - _( - "* is used as a Wildcard. A few Examples:\n" - "\n" - "wooden arrow matches the itemname exactly\n" - "wooden ar* matches items beginning with wood ar\n" - "*rrow matches items ending with rrow\n" - "*avy fle*fi*arrow multiple * are allowed\n" - "heAVY*woOD*arrOW case insensitive search\n" - "\n" - "Pickup based on item materials:\n" - "m:kevlar matches items made of kevlar\n" - "M:copper matches items made purely of copper\n" - "M:steel,iron multiple materials allowed (OR search)" ) - ); - - draw_border( w_help ); - wrefresh( w_help ); + ui_adaptor help_ui; + catacurses::window w_help; + const auto init_help_window = [&]( ui_adaptor & help_ui ) { + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + w_help = catacurses::newwin( FULL_SCREEN_HEIGHT / 2 + 2, + FULL_SCREEN_WIDTH * 3 / 4, + point( iOffsetX + 19 / 2, 7 + iOffsetY + FULL_SCREEN_HEIGHT / 2 / 2 ) ); + help_ui.position_from_window( w_help ); + }; + init_help_window( help_ui ); + help_ui.on_screen_resize( init_help_window ); + + help_ui.on_redraw( [&]( const ui_adaptor & ) { + // NOLINTNEXTLINE(cata-use-named-point-constants) + fold_and_print( w_help, point( 1, 1 ), 999, c_white, + _( + "* is used as a Wildcard. A few Examples:\n" + "\n" + "wooden arrow matches the itemname exactly\n" + "wooden ar* matches items beginning with wood ar\n" + "*rrow matches items ending with rrow\n" + "*avy fle*fi*arrow multiple * are allowed\n" + "heAVY*woOD*arrOW case insensitive search\n" + "\n" + "Pickup based on item materials:\n" + "m:kevlar matches items made of kevlar\n" + "M:copper matches items made purely of copper\n" + "M:steel,iron multiple materials allowed (OR search)" ) + ); + + draw_border( w_help ); + wrefresh( w_help ); + } ); const std::string r = string_input_popup() .title( _( "Pickup Rule:" ) ) .width( 30 ) @@ -344,9 +368,6 @@ void user_interface::show() // TODO: Now that NPCs use this function, it could be used for them too get_options().get_option( "AUTO_PICKUP" ).setNext(); get_options().save(); - } else if( action == "HELP_KEYBINDINGS" ) { - // de-mangle parts of the screen - initial_draw(); } } From ecfe915419490c5a478a6b60b38d7b4a232306b7 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 20:29:47 +0800 Subject: [PATCH 064/219] Use ui_adaptor in string_input_popup --- src/string_input_popup.cpp | 87 +++++++++++++++++++++----------------- src/string_input_popup.h | 11 +++++ 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/string_input_popup.cpp b/src/string_input_popup.cpp index 21e7109f85bbf..977e1b098093a 100644 --- a/src/string_input_popup.cpp +++ b/src/string_input_popup.cpp @@ -8,9 +8,10 @@ #include "input.h" #include "optional.h" #include "output.h" +#include "translations.h" #include "ui.h" +#include "ui_manager.h" #include "uistate.h" -#include "translations.h" #if defined(__ANDROID__) #include @@ -29,15 +30,15 @@ string_input_popup::~string_input_popup() = default; void string_input_popup::create_window() { - int titlesize = utf8_width( remove_color_tags( _title ) ); // Occupied horizontal space + titlesize = utf8_width( remove_color_tags( _title ) ); // Occupied horizontal space if( _max_length <= 0 ) { _max_length = _width; } // 2 for border (top and bottom) and 1 for the input text line. - int w_height = 2 + 1; + w_height = 2 + 1; // |"w_width = width + titlesize (this text) + 5": _____ | - int w_width = FULL_SCREEN_WIDTH; + w_width = FULL_SCREEN_WIDTH; if( _width <= 0 ) { _width = std::max( 5, FULL_SCREEN_WIDTH - titlesize - 5 ); // Default if unspecified } else { @@ -45,7 +46,7 @@ void string_input_popup::create_window() w_width = _width + titlesize + 5; } - std::vector title_split = { _title }; + title_split = { _title }; if( w_width > FULL_SCREEN_WIDTH ) { // Out of horizontal space- wrap the title titlesize = FULL_SCREEN_WIDTH - _width - 5; @@ -60,7 +61,7 @@ void string_input_popup::create_window() w_height += static_cast( title_split.size() ) - 1; } - std::vector descformatted; + descformatted.clear(); if( !_description.empty() ) { const int twidth = std::min( utf8_width( remove_color_tags( _description ) ), w_width - 4 ); descformatted = foldstring( _description, twidth ); @@ -68,29 +69,19 @@ void string_input_popup::create_window() } // length of title + border (left) + space _startx = titlesize + 2; - // Below the description and below the top border - _starty = 1 + descformatted.size(); if( _max_length <= 0 ) { _max_length = 1024; } _endx = w_width - 3; - _position = -1; const int w_y = ( TERMY - w_height ) / 2; const int w_x = std::max( ( TERMX - w_width ) / 2, 0 ); w = catacurses::newwin( w_height, w_width, point( w_x, w_y ) ); - draw_border( w ); - - for( size_t i = 0; i < descformatted.size(); ++i ) { - trim_and_print( w, point( 1, 1 + i ), w_width - 2, _desc_color, descformatted[i] ); - } - for( int i = 0; i < static_cast( title_split.size() ) - 1; i++ ) { - mvwprintz( w, point( i + 1, _starty++ ), _title_color, title_split[i] ); - } - right_print( w, _starty, w_width - titlesize - 1, _title_color, title_split.back() ); _starty = w_height - 2; // The ____ looks better at the bottom right when the title folds + + custom_window = false; } void string_input_popup::create_context() @@ -209,6 +200,19 @@ void string_input_popup::update_input_history( utf8_wrapper &ret, bool up ) void string_input_popup::draw( const utf8_wrapper &ret, const utf8_wrapper &edit, const int shift ) const { + if( !custom_window ) { + draw_border( w ); + + for( size_t i = 0; i < descformatted.size(); ++i ) { + trim_and_print( w, point( 1, 1 + i ), w_width - 2, _desc_color, descformatted[i] ); + } + int pos_y = descformatted.size() + 1; + for( int i = 0; i < static_cast( title_split.size() ) - 1; i++ ) { + mvwprintz( w, point( i + 1, pos_y++ ), _title_color, title_split[i] ); + } + right_print( w, pos_y, w_width - titlesize - 1, _title_color, title_split.back() ); + } + const int scrmax = _endx - _startx; // remove the scrolled out of view part from the input string const utf8_wrapper ds( ret.substr_display( shift, scrmax ) ); @@ -219,7 +223,7 @@ void string_input_popup::draw( const utf8_wrapper &ret, const utf8_wrapper &edit mvwprintz( w, point( _startx, _starty ), _string_color, "%s", ds.c_str() ); size_t sx = ds.display_width(); // Print the cursor in its own color - if( _position < static_cast( ret.length() ) ) { + if( _position >= 0 && static_cast( _position ) < ret.length() ) { utf8_wrapper cursor = ret.substr( _position, 1 ); size_t a = _position; while( a > 0 && cursor.display_width() == 0 ) { @@ -260,6 +264,8 @@ void string_input_popup::draw( const utf8_wrapper &ret, const utf8_wrapper &edit if( !edit.empty() ) { mvwprintz( w, point( start_x_edit, _starty ), _cursor_color, "%s", edit.c_str() ); } + + wrefresh( w ); } void string_input_popup::query( const bool loop, const bool draw_only ) @@ -279,12 +285,14 @@ int64_t string_input_popup::query_int64_t( const bool loop, const bool draw_only const std::string &string_input_popup::query_string( const bool loop, const bool draw_only ) { - if( !w ) { + if( !custom_window && !w ) { create_window(); + _position = -1; } if( !ctxt ) { create_context(); } + cata::optional sentry; if( !draw_only && loop ) { sentry.emplace(); @@ -297,7 +305,19 @@ const std::string &string_input_popup::query_string( const bool loop, const bool const int scrmax = _endx - _startx; // in output (console) cells, not characters of the string! int shift = 0; - bool redraw = true; + + std::unique_ptr ui; + if( !draw_only && !custom_window ) { + ui = std::make_unique(); + ui->position_from_window( w ); + ui->on_screen_resize( [this]( ui_adaptor & ui ) { + create_window(); + ui.position_from_window( w ); + } ); + ui->on_redraw( [&]( const ui_adaptor & ) { + draw( ret, edit, shift ); + } ); + } int ch = 0; @@ -333,14 +353,12 @@ const std::string &string_input_popup::query_string( const bool loop, const bool shift++; } - if( redraw ) { - redraw = false; + if( ui ) { + ui_manager::redraw(); + } else { draw( ret, edit, shift ); - wrefresh( w ); } - wrefresh( w ); - if( draw_only ) { return _text; } @@ -387,26 +405,21 @@ const std::string &string_input_popup::query_string( const bool loop, const bool } else { update_input_history( ret, true ); } - redraw = true; } else if( ch == KEY_DOWN && !_hist_use_uilist ) { update_input_history( ret, false ); - redraw = true; } else if( ch == KEY_DOWN || ch == KEY_NPAGE || ch == KEY_PPAGE || ch == KEY_BTAB || ch == 9 ) { /* absolutely nothing */ } else if( ch == KEY_RIGHT ) { if( _position + 1 <= static_cast( ret.size() ) ) { _position++; } - redraw = true; } else if( ch == KEY_LEFT ) { if( _position > 0 ) { _position--; } - redraw = true; } else if( ch == 0x15 ) { // ctrl-u: delete all the things _position = 0; ret.erase( 0 ); - redraw = true; // Move the cursor back and re-draw it } else if( ch == KEY_BACKSPACE ) { // but silently drop input if we're at 0, instead of adding '^' @@ -414,18 +427,14 @@ const std::string &string_input_popup::query_string( const bool loop, const bool // TODO: it is safe now since you only input ASCII chars _position--; ret.erase( _position, 1 ); - redraw = true; } } else if( ch == KEY_HOME ) { _position = 0; - redraw = true; } else if( ch == KEY_END ) { _position = ret.size(); - redraw = true; } else if( ch == KEY_DC ) { if( _position < static_cast( ret.size() ) ) { ret.erase( _position, 1 ); - redraw = true; } } else if( ch == KEY_F( 2 ) ) { std::string tmp = get_input_string_from_file(); @@ -443,17 +452,14 @@ const std::string &string_input_popup::query_string( const bool loop, const bool _position += t.length(); edit.erase( 0 ); ctxt->set_edittext( edit.c_str() ); - redraw = true; } else if( ev.edit_refresh ) { const utf8_wrapper t( ev.edit ); edit.erase( 0 ); edit.insert( 0, t ); ctxt->set_edittext( edit.c_str() ); - redraw = true; } else if( ev.edit.empty() ) { edit.erase( 0 ); ctxt->set_edittext( edit.c_str() ); - redraw = true; } } while( loop ); _text = ret.str(); @@ -463,10 +469,15 @@ const std::string &string_input_popup::query_string( const bool loop, const bool string_input_popup &string_input_popup::window( const catacurses::window &w, int startx, int starty, int endx ) { + if( !custom_window && this->w ) { + // default window already created + return *this; + } this->w = w; _startx = startx; _starty = starty; _endx = endx; + custom_window = true; return *this; } diff --git a/src/string_input_popup.h b/src/string_input_popup.h index e1914e34f8215..8ea338b42b9ba 100644 --- a/src/string_input_popup.h +++ b/src/string_input_popup.h @@ -66,6 +66,14 @@ class string_input_popup // NOLINT(cata-xy) //Counts only when @_hist_use_uilist is false const size_t _hist_max_size = 100; + // Cache when using the default window + int w_width = 0; + int w_height = 0; + std::vector descformatted; + std::vector title_split; + int titlesize = 0; + + bool custom_window = false; catacurses::window w; std::unique_ptr ctxt_ptr; @@ -161,6 +169,9 @@ class string_input_popup // NOLINT(cata-xy) * text will be printed at the given part of the given window. * Integer parameters define the area (one line) where the editable * text is printed. + * + * This method only has effect before the default window is initialized. + * After that calls to this method are just ignored. */ string_input_popup &window( const catacurses::window &w, int startx, int starty, int endx ); /** From 41e759a75bf8b612e7d63d70e93c14dd594347a6 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 21:24:30 +0800 Subject: [PATCH 065/219] Use ui_adaptor in auto pickup test pattern window --- src/auto_pickup.cpp | 53 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/auto_pickup.cpp b/src/auto_pickup.cpp index d9553a3529abc..1754bd1d4a7b6 100644 --- a/src/auto_pickup.cpp +++ b/src/auto_pickup.cpp @@ -427,36 +427,51 @@ void rule::test_pattern() const vMatchingItems.push_back( sItemName ); } - const int iOffsetX = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); - const int iOffsetY = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : - 0 ); - int iStartPos = 0; - const int iContentHeight = FULL_SCREEN_HEIGHT - 8; - const int iContentWidth = FULL_SCREEN_WIDTH - 30; + int iContentHeight = 0; + int iContentWidth = 0; + + catacurses::window w_test_rule_border; + catacurses::window w_test_rule_content; + + ui_adaptor ui; - const catacurses::window w_test_rule_border = catacurses::newwin( iContentHeight + 2, iContentWidth, - point( iOffsetX, iOffsetY ) ); - const catacurses::window w_test_rule_content = catacurses::newwin( iContentHeight, - iContentWidth - 2, - point( 1 + iOffsetX, 1 + iOffsetY ) ); + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iOffsetX = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); + const int iOffsetY = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : + 0 ); + iContentHeight = FULL_SCREEN_HEIGHT - 8; + iContentWidth = FULL_SCREEN_WIDTH - 30; + + w_test_rule_border = catacurses::newwin( iContentHeight + 2, iContentWidth, + point( iOffsetX, iOffsetY ) ); + w_test_rule_content = catacurses::newwin( iContentHeight, + iContentWidth - 2, + point( 1 + iOffsetX, 1 + iOffsetY ) ); + + ui.position_from_window( w_test_rule_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int nmatch = vMatchingItems.size(); const std::string buf = string_format( ngettext( "%1$d item matches: %2$s", "%1$d items match: %2$s", nmatch ), nmatch, sRule ); - draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); - center_print( w_test_rule_border, iContentHeight + 1, red_background( c_white ), - _( "Won't display content or suffix matches" ) ); - wrefresh( w_test_rule_border ); int iLine = 0; input_context ctxt( "AUTO_PICKUP_TEST" ); ctxt.register_updown(); ctxt.register_action( "QUIT" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); + center_print( w_test_rule_border, iContentHeight + 1, red_background( c_white ), + _( "Won't display content or suffix matches" ) ); + wrefresh( w_test_rule_border ); - while( true ) { // Clear the lines for( int i = 0; i < iContentHeight; i++ ) { for( int j = 0; j < 79; j++ ) { @@ -487,6 +502,10 @@ void rule::test_pattern() const } wrefresh( w_test_rule_content ); + } ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "DOWN" ) { @@ -499,7 +518,7 @@ void rule::test_pattern() const if( iLine < 0 ) { iLine = vMatchingItems.size() - 1; } - } else { + } else if( action == "QUIT" ) { break; } } From 8bc51866fd078bbc7d73f7f4f8e83c8f81522e70 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 22:17:18 +0800 Subject: [PATCH 066/219] Use ui_adaptor in safe mode ui --- src/safemode_ui.cpp | 199 ++++++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 90 deletions(-) diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index 97ec1b858794b..fcbb42c0b3b69 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -23,6 +23,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "compatibility.h" #include "cursesdef.h" @@ -50,10 +51,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) auto character_rules_old = character_rules; const int header_height = 4; - const int content_height = FULL_SCREEN_HEIGHT - 2 - header_height; - - const int offset_x = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; - const int offset_y = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + int content_height = 0; enum Columns : int { COLUMN_RULE, @@ -72,23 +70,57 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) const int num_columns = column_pos.size(); - catacurses::window w_help = - catacurses::newwin( FULL_SCREEN_HEIGHT / 2 - 2, FULL_SCREEN_WIDTH * 3 / 4, - point( offset_x + 19 / 2, 7 + offset_y + FULL_SCREEN_HEIGHT / 2 / 2 ) ); - catacurses::window w_border = - catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, point( offset_x, offset_y ) ); - catacurses::window w_header = - catacurses::newwin( header_height, FULL_SCREEN_WIDTH - 2, - point( 1 + offset_x, 1 + offset_y ) ); - catacurses::window w = - catacurses::newwin( content_height, FULL_SCREEN_WIDTH - 2, - point( 1 + offset_x, header_height + 1 + offset_y ) ); - - /** - * All of the stuff in this lambda needs to be drawn (1) initially, and - * (2) after closing the HELP_KEYBINDINGS window (since it mangles the screen) - */ - const auto initial_draw = [&]() { + catacurses::window w_border; + catacurses::window w_header; + catacurses::window w; + + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + content_height = FULL_SCREEN_HEIGHT - 2 - header_height; + + const int offset_x = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int offset_y = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + + w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, point( offset_x, offset_y ) ); + w_header = catacurses::newwin( header_height, FULL_SCREEN_WIDTH - 2, + point( 1 + offset_x, 1 + offset_y ) ); + w = catacurses::newwin( content_height, FULL_SCREEN_WIDTH - 2, + point( 1 + offset_x, header_height + 1 + offset_y ) ); + + ui.position_from_window( w_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); + + int tab = GLOBAL_TAB; + int line = 0; + int column = 0; + int start_pos = 0; + bool changes_made = false; + input_context ctxt( "SAFEMODE" ); + ctxt.register_cardinal(); + ctxt.register_action( "CONFIRM" ); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "NEXT_TAB" ); + ctxt.register_action( "PREV_TAB" ); + ctxt.register_action( "ADD_DEFAULT_RULESET" ); + ctxt.register_action( "ADD_RULE" ); + ctxt.register_action( "REMOVE_RULE" ); + ctxt.register_action( "COPY_RULE" ); + ctxt.register_action( "ENABLE_RULE" ); + ctxt.register_action( "DISABLE_RULE" ); + ctxt.register_action( "MOVE_RULE_UP" ); + ctxt.register_action( "MOVE_RULE_DOWN" ); + ctxt.register_action( "TEST_RULE" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + if( is_safemode_in ) { + ctxt.register_action( "SWITCH_SAFEMODE_OPTION" ); + ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); + } + + ui.on_redraw( [&]( const ui_adaptor & ) { draw_border( w_border, BORDER_COLOR, custom_name_in ); mvwputch( w_border, point( 0, 3 ), c_light_gray, LINE_XXXO ); // |- @@ -138,39 +170,6 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) mvwprintz( w_header, point( column_pos[COLUMN_CATEGORY] + 2, 3 ), c_white, pgettext( "category", "Cat" ) ); - wrefresh( w_header ); - }; - - initial_draw(); - - int tab = GLOBAL_TAB; - int line = 0; - int column = 0; - int start_pos = 0; - bool changes_made = false; - input_context ctxt( "SAFEMODE" ); - ctxt.register_cardinal(); - ctxt.register_action( "CONFIRM" ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "NEXT_TAB" ); - ctxt.register_action( "PREV_TAB" ); - ctxt.register_action( "ADD_DEFAULT_RULESET" ); - ctxt.register_action( "ADD_RULE" ); - ctxt.register_action( "REMOVE_RULE" ); - ctxt.register_action( "COPY_RULE" ); - ctxt.register_action( "ENABLE_RULE" ); - ctxt.register_action( "DISABLE_RULE" ); - ctxt.register_action( "MOVE_RULE_UP" ); - ctxt.register_action( "MOVE_RULE_DOWN" ); - ctxt.register_action( "TEST_RULE" ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - - if( is_safemode_in ) { - ctxt.register_action( "SWITCH_SAFEMODE_OPTION" ); - ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); - } - - while( true ) { int locx = 17; locx += shortcut_print( w_header, point( locx, 2 ), c_white, ( tab == GLOBAL_TAB ) ? hilite( c_white ) : c_white, _( "[]" ) ) + 1; @@ -246,6 +245,12 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } wrefresh( w ); + } ); + + while( true ) { + auto ¤t_tab = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; + + ui_manager::redraw(); const std::string action = ctxt.handle_input(); @@ -261,9 +266,6 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) tab = MAX_TAB - 1; line = 0; } - } else if( action == "HELP_KEYBINDINGS" ) { - // de-mangle parts of the screen - initial_draw(); } else if( action == "QUIT" ) { break; } else if( tab == CHARACTER_TAB && g->u.name.empty() ) { @@ -320,39 +322,56 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } else if( action == "CONFIRM" && !current_tab.empty() ) { changes_made = true; if( column == COLUMN_RULE ) { - switch( current_tab[line].category ) { - case Categories::HOSTILE_SPOTTED: - // NOLINTNEXTLINE(cata-use-named-point-constants) - fold_and_print( w_help, point( 1, 1 ), 999, c_white, - _( - "* is used as a Wildcard. A few Examples:\n" - "\n" - "human matches every NPC\n" - "zombie matches the monster name exactly\n" - "acidic zo* matches monsters beginning with 'acidic zo'\n" - "*mbie matches monsters ending with 'mbie'\n" - "*cid*zo*ie multiple * are allowed\n" - "AcI*zO*iE case insensitive search" ) - ); - break; - case Categories::SOUND: - // NOLINTNEXTLINE(cata-use-named-point-constants) - fold_and_print( w_help, point( 1, 1 ), 999, c_white, - _( - "* is used as a Wildcard. A few Examples:\n" - "\n" - "footsteps matches the sound name exactly\n" - "a loud ba* matches sounds beginning with 'a loud ba'\n" - "*losion! matches sounds ending with 'losion!'\n" - "a *oud*ba* multiple * are allowed\n" - "*LoU*bA* case insensitive search" ) - ); - break; - default: - break; - } - draw_border( w_help ); - wrefresh( w_help ); + catacurses::window w_help; + ui_adaptor help_ui; + const auto init_help_window = [&]( ui_adaptor & help_ui ) { + const int offset_x = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int offset_y = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + + w_help = catacurses::newwin( FULL_SCREEN_HEIGHT / 2 - 2, FULL_SCREEN_WIDTH * 3 / 4, + point( offset_x + 19 / 2, 7 + offset_y + FULL_SCREEN_HEIGHT / 2 / 2 ) ); + + help_ui.position_from_window( w_help ); + }; + init_help_window( help_ui ); + help_ui.on_screen_resize( init_help_window ); + + help_ui.on_redraw( [&]( const ui_adaptor & ) { + switch( current_tab[line].category ) { + case Categories::HOSTILE_SPOTTED: + // NOLINTNEXTLINE(cata-use-named-point-constants) + fold_and_print( w_help, point( 1, 1 ), 999, c_white, + _( + "* is used as a Wildcard. A few Examples:\n" + "\n" + "human matches every NPC\n" + "zombie matches the monster name exactly\n" + "acidic zo* matches monsters beginning with 'acidic zo'\n" + "*mbie matches monsters ending with 'mbie'\n" + "*cid*zo*ie multiple * are allowed\n" + "AcI*zO*iE case insensitive search" ) + ); + break; + case Categories::SOUND: + // NOLINTNEXTLINE(cata-use-named-point-constants) + fold_and_print( w_help, point( 1, 1 ), 999, c_white, + _( + "* is used as a Wildcard. A few Examples:\n" + "\n" + "footsteps matches the sound name exactly\n" + "a loud ba* matches sounds beginning with 'a loud ba'\n" + "*losion! matches sounds ending with 'losion!'\n" + "a *oud*ba* multiple * are allowed\n" + "*LoU*bA* case insensitive search" ) + ); + break; + default: + break; + } + draw_border( w_help ); + wrefresh( w_help ); + } ); + current_tab[line].rule = wildcard_trim_rule( string_input_popup() .title( _( "Safe Mode Rule:" ) ) .width( 30 ) From 43e5e6358af39a57bf17012fd502cdbde82ede3c Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 22:59:22 +0800 Subject: [PATCH 067/219] Use ui_adaptor in safemode test pattern window --- src/safemode_ui.cpp | 54 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index fcbb42c0b3b69..906034df10585 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -500,37 +500,51 @@ void safemode::test_pattern( const int tab_in, const int row_in ) } } - const int offset_x = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); - const int offset_y = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : - 0 ); - int start_pos = 0; - const int content_height = FULL_SCREEN_HEIGHT - 8; - const int content_width = FULL_SCREEN_WIDTH - 30; + int content_height = 0; + int content_width = 0; + + catacurses::window w_test_rule_border; + catacurses::window w_test_rule_content; + + ui_adaptor ui; + const auto init_windows = [&]( ui_adaptor & ui ) { + const int offset_x = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); + const int offset_y = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : + 0 ); - const catacurses::window w_test_rule_border = catacurses::newwin( content_height + 2, content_width, - point( offset_x, offset_y ) ); - const catacurses::window w_test_rule_content = catacurses::newwin( content_height, - content_width - 2, - point( 1 + offset_x, 1 + offset_y ) ); + content_height = FULL_SCREEN_HEIGHT - 8; + content_width = FULL_SCREEN_WIDTH - 30; + + w_test_rule_border = catacurses::newwin( content_height + 2, content_width, + point( offset_x, offset_y ) ); + w_test_rule_content = catacurses::newwin( content_height, content_width - 2, + point( 1 + offset_x, 1 + offset_y ) ); + + ui.position_from_window( w_test_rule_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int nmatch = creature_list.size(); const std::string buf = string_format( ngettext( "%1$d monster matches: %2$s", "%1$d monsters match: %2$s", nmatch ), nmatch, temp_rules[row_in].rule.c_str() ); - draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); - center_print( w_test_rule_border, content_height + 1, red_background( c_white ), - _( "Lists monsters regardless of their attitude." ) ); - - wrefresh( w_test_rule_border ); int line = 0; input_context ctxt( "SAFEMODE_TEST" ); ctxt.register_updown(); ctxt.register_action( "QUIT" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); + center_print( w_test_rule_border, content_height + 1, red_background( c_white ), + _( "Lists monsters regardless of their attitude." ) ); + + wrefresh( w_test_rule_border ); - while( true ) { // Clear the lines for( int i = 0; i < content_height; i++ ) { for( int j = 0; j < 79; j++ ) { @@ -557,6 +571,10 @@ void safemode::test_pattern( const int tab_in, const int row_in ) } wrefresh( w_test_rule_content ); + } ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "DOWN" ) { @@ -569,7 +587,7 @@ void safemode::test_pattern( const int tab_in, const int row_in ) if( line < 0 ) { line = creature_list.size() - 1; } - } else { + } else if( action == "QUIT" ) { break; } } From 80325571e31be7cb168b0136ad6871dc13ddf59d Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 23:38:16 +0800 Subject: [PATCH 068/219] Use ui_adaptor in color manager --- src/color.cpp | 89 ++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/src/color.cpp b/src/color.cpp index cb3629f50d87b..782b733917d9e 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -18,6 +18,7 @@ #include "string_formatter.h" #include "translations.h" #include "ui.h" +#include "ui_manager.h" #include "cursesdef.h" void nc_color::serialize( JsonOut &jsout ) const @@ -718,10 +719,10 @@ static void draw_header( const catacurses::window &w ) void color_manager::show_gui() { const int iHeaderHeight = 4; - const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; + int iContentHeight = 0; - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; - const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + int iOffsetX = 0; + int iOffsetY = 0; std::vector vLines; vLines.push_back( -1 ); @@ -729,37 +730,29 @@ void color_manager::show_gui() const int iTotalCols = vLines.size(); - catacurses::window w_colors_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, - point( iOffsetX, iOffsetY ) ); - catacurses::window w_colors_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, 1 + iOffsetY ) ); - catacurses::window w_colors = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); + catacurses::window w_colors_border; + catacurses::window w_colors_header; + catacurses::window w_colors; - /** - * All of the stuff in this lambda needs to be drawn (1) initially, and - * (2) after closing the HELP_KEYBINDINGS window (since it mangles the screen) - */ - const auto initial_draw = [&]() { - draw_border( w_colors_border, BORDER_COLOR, _( " COLOR MANAGER " ) ); - mvwputch( w_colors_border, point( 0, 3 ), BORDER_COLOR, LINE_XXXO ); // |- - mvwputch( w_colors_border, point( getmaxx( w_colors_border ) - 1, 3 ), BORDER_COLOR, - LINE_XOXX ); // -| + ui_adaptor ui; + const auto init_windows = [&]( ui_adaptor & ui ) { + iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; - for( auto &iCol : vLines ) { - if( iCol > -1 ) { - mvwputch( w_colors_border, point( iCol + 1, FULL_SCREEN_HEIGHT - 1 ), BORDER_COLOR, - LINE_XXOX ); // _|_ - mvwputch( w_colors_header, point( iCol, 3 ), BORDER_COLOR, LINE_XOXO ); - } - } - wrefresh( w_colors_border ); + iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; - draw_header( w_colors_header ); + w_colors_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, + point( iOffsetX, iOffsetY ) ); + w_colors_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, 1 + iOffsetY ) ); + w_colors = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); + ui.position_from_window( w_colors_border ); }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); - initial_draw(); int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; @@ -779,7 +772,23 @@ void color_manager::show_gui() name_color_map[pr.first] = color_array[pr.second]; } - while( true ) { + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_colors_border, BORDER_COLOR, _( " COLOR MANAGER " ) ); + mvwputch( w_colors_border, point( 0, 3 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( w_colors_border, point( getmaxx( w_colors_border ) - 1, 3 ), BORDER_COLOR, + LINE_XOXX ); // -| + + for( auto &iCol : vLines ) { + if( iCol > -1 ) { + mvwputch( w_colors_border, point( iCol + 1, FULL_SCREEN_HEIGHT - 1 ), BORDER_COLOR, + LINE_XXOX ); // _|_ + mvwputch( w_colors_header, point( iCol, 3 ), BORDER_COLOR, LINE_XOXO ); + } + } + wrefresh( w_colors_border ); + + draw_header( w_colors_header ); + // Clear all lines for( int i = 0; i < iContentHeight; i++ ) { for( int j = 0; j < 79; j++ ) { @@ -801,8 +810,6 @@ void color_manager::show_gui() auto iter = name_color_map.begin(); std::advance( iter, iStartPos ); - std::string sActive; - // display color manager for( int i = iStartPos; iter != name_color_map.end(); ++iter, ++i ) { if( i >= iStartPos && @@ -810,7 +817,6 @@ void color_manager::show_gui() auto &entry = iter->second; if( iCurrentLine == i ) { - sActive = iter->first; mvwprintz( w_colors, point( vLines[iCurrentCol - 1] + 2, i - iStartPos ), c_yellow, ">" ); } @@ -833,6 +839,10 @@ void color_manager::show_gui() } wrefresh( w_colors ); + } ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); @@ -859,7 +869,7 @@ void color_manager::show_gui() iCurrentCol = 1; } } else if( action == "REMOVE_CUSTOM" ) { - auto &entry = name_color_map[sActive]; + auto &entry = std::next( name_color_map.begin(), iCurrentLine )->second; if( iCurrentCol == 1 && !entry.name_custom.empty() ) { bStuffChanged = true; @@ -911,12 +921,14 @@ void color_manager::show_gui() ui_colors.w_y = iHeaderHeight + 1 + iOffsetY; ui_colors.w_height = 18; + const auto &entry = std::next( name_color_map.begin(), iCurrentLine )->second; + std::string sColorType = _( "Normal" ); - std::string sSelected = name_color_map[sActive].name_custom; + std::string sSelected = entry.name_custom; if( iCurrentCol == 2 ) { sColorType = _( "Invert" ); - sSelected = name_color_map[sActive].name_invert_custom; + sSelected = entry.name_invert_custom; } @@ -944,15 +956,14 @@ void color_manager::show_gui() } ui_colors.query(); - initial_draw(); if( ui_colors.ret >= 0 && static_cast( ui_colors.ret ) < name_color_map.size() ) { bStuffChanged = true; - iter = name_color_map.begin(); + auto iter = name_color_map.begin(); std::advance( iter, ui_colors.ret ); - auto &entry = name_color_map[sActive]; + auto &entry = std::next( name_color_map.begin(), iCurrentLine )->second; if( iCurrentCol == 1 ) { entry.name_custom = iter->first; @@ -964,8 +975,6 @@ void color_manager::show_gui() } finalize(); // Need to recalculate caches - } else if( action == "HELP_KEYBINDINGS" ) { - initial_draw(); } } From 847c77df5133ecabcc128669530b295f4394ae6b Mon Sep 17 00:00:00 2001 From: Qrox Date: Fri, 28 Feb 2020 13:17:00 +0800 Subject: [PATCH 069/219] Use ui_adaptor in help menu --- src/help.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/help.cpp b/src/help.cpp index 546eb61c2d790..2e9cf21992c57 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -17,6 +17,7 @@ #include "path_info.h" #include "text_snippets.h" #include "translations.h" +#include "ui_manager.h" #include "cata_utility.h" #include "color.h" #include "debug.h" @@ -131,12 +132,21 @@ std::string help::get_note_colors() void help::display_help() { - catacurses::window w_help_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, - point( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0, - TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ); - catacurses::window w_help = catacurses::newwin( FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, - point( 1 + static_cast( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ), - 1 + static_cast( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ) ); + catacurses::window w_help_border; + catacurses::window w_help; + + ui_adaptor ui; + const auto init_windows = [&]( ui_adaptor & ui ) { + w_help_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, + point( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0, + TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ); + w_help = catacurses::newwin( FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, + point( 1 + static_cast( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ), + 1 + static_cast( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ) ); + ui.position_from_window( w_help_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); ctxt.register_cardinal(); ctxt.register_action( "QUIT" ); @@ -146,11 +156,14 @@ void help::display_help() std::string action; - do { + ui.on_redraw( [&]( const ui_adaptor & ) { draw_border( w_help_border, BORDER_COLOR, _( " HELP " ), c_black_white ); wrefresh( w_help_border ); draw_menu( w_help ); - catacurses::refresh(); + } ); + + do { + ui_manager::redraw(); action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; From 9c9eae9d785c604a486c62c86b959fa6bfd1740c Mon Sep 17 00:00:00 2001 From: Qrox Date: Fri, 28 Feb 2020 17:38:28 +0800 Subject: [PATCH 070/219] Use ui_adaptor in scrollable_text --- src/help.cpp | 11 ++++++++++- src/output.cpp | 50 ++++++++++++++++++++++++++++++++++++++------------ src/output.h | 2 ++ 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/help.cpp b/src/help.cpp index 2e9cf21992c57..1ab5936d9d8a0 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -194,12 +194,21 @@ void help::display_help() } ); if( !i18n_help_texts.empty() ) { - scrollable_text( w_help_border, _( " HELP " ), + ui.on_screen_resize( nullptr ); + + const auto get_w_help_border = [&]() { + init_windows( ui ); + return w_help_border; + }; + + scrollable_text( get_w_help_border, _( " HELP " ), std::accumulate( i18n_help_texts.begin() + 1, i18n_help_texts.end(), i18n_help_texts.front(), []( const std::string & lhs, const std::string & rhs ) { return lhs + "\n\n" + rhs; } ) ); + + ui.on_screen_resize( init_windows ); } action = "CONFIRM"; break; diff --git a/src/output.cpp b/src/output.cpp index cf93a8602461b..9850ef173667e 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -32,6 +32,7 @@ #include "rng.h" #include "string_formatter.h" #include "string_input_popup.h" +#include "ui_manager.h" #include "units.h" #include "point.h" #include "wcwidth.h" @@ -340,16 +341,16 @@ int fold_and_print_from( const catacurses::window &w, const point &begin, int wi void scrollable_text( const catacurses::window &w, const std::string &title, const std::string &text ) { - const int width = getmaxx( w ); - const int height = getmaxy( w ); + scrollable_text( [&w]() { + return w; + }, title, text ); +} + +void scrollable_text( const std::function &init_window, + const std::string &title, const std::string &text ) +{ constexpr int text_x = 1; constexpr int text_y = 1; - const int text_w = width - 2; - const int text_h = height - 2; - if( text_w <= 0 || text_h <= 0 ) { - debugmsg( "Oops, the window is too small to display anything!" ); - return; - } input_context ctxt( "SCROLLABLE_TEXT" ); ctxt.register_action( "UP" ); @@ -360,12 +361,32 @@ void scrollable_text( const catacurses::window &w, const std::string &title, ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); - const std::vector lines = foldstring( text, text_w ); + catacurses::window w; + int width = 0; + int height = 0; + int text_w = 0; + int text_h = 0; + std::vector lines; int beg_line = 0; - const int max_beg_line = std::max( 0, static_cast( lines.size() ) - text_h ); + int max_beg_line = 0; - std::string action; - do { + ui_adaptor ui; + const auto screen_resize_cb = [&]( ui_adaptor & ui ) { + w = init_window(); + + width = getmaxx( w ); + height = getmaxy( w ); + text_w = std::max( 0, width - 2 ); + text_h = std::max( 0, height - 2 ); + + lines = foldstring( text, text_w ); + max_beg_line = std::max( 0, static_cast( lines.size() ) - text_h ); + + ui.position_from_window( w ); + }; + screen_resize_cb( ui ); + ui.on_screen_resize( screen_resize_cb ); + ui.on_redraw( [&]( const ui_adaptor & ) { werase( w ); draw_border( w, BORDER_COLOR, title, c_black_white ); for( int line = beg_line, pos_y = text_y; line < std::min( beg_line + text_h, lines.size() ); @@ -376,6 +397,11 @@ void scrollable_text( const catacurses::window &w, const std::string &title, scrollbar().offset_x( width - 1 ).offset_y( text_y ).content_size( lines.size() ) .viewport_pos( std::min( beg_line, max_beg_line ) ).viewport_size( text_h ).apply( w ); wrefresh( w ); + } ); + + std::string action; + do { + ui_manager::redraw(); action = ctxt.handle_input(); if( action == "UP" ) { diff --git a/src/output.h b/src/output.h index bc4cfaa362271..1b10ee9c63e08 100644 --- a/src/output.h +++ b/src/output.h @@ -327,6 +327,8 @@ void display_table( const catacurses::window &w, const std::string &title, int c const std::vector &data ); void scrollable_text( const catacurses::window &w, const std::string &title, const std::string &text ); +void scrollable_text( const std::function &init_window, + const std::string &title, const std::string &text ); std::string name_and_value( const std::string &name, int value, int field_width ); std::string name_and_value( const std::string &name, const std::string &value, int field_width ); From 6b4a80ee291b98959ab834bd0c800e56a85bc96c Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 20:47:40 +0100 Subject: [PATCH 071/219] Remove manual JSON object member check: Just get the value and let the JSON system deal with the existence check and the error message. Also throw errors via the JSON system so it creates a nice message with error location. --- src/mapgen.cpp | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 4e7e55f9f358e..741dc805e5d7f 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -310,36 +310,21 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, } jio.allow_omitted_members(); return nullptr; // nothing - } else if( jio.has_string( "method" ) ) { - const std::string mgtype = jio.get_string( "method" ); - if( mgtype == "builtin" ) { // c-function - if( jio.has_string( "name" ) ) { - const std::string mgname = jio.get_string( "name" ); - if( const auto ptr = get_mapgen_cfunction( mgname ) ) { - ret = std::make_shared( ptr, mgweight ); - oter_mapgen[id_base].push_back( ret ); - } else { - debugmsg( "oter_t[%s]: builtin mapgen function \"%s\" does not exist.", id_base.c_str(), - mgname ); - } - } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"name\" value).", id_base.c_str() ); - } - } else if( mgtype == "json" ) { - if( jio.has_object( "object" ) ) { - JsonObject jo = jio.get_object( "object" ); - std::string jstr = jo.str(); - ret = std::make_shared( jstr, mgweight, offset ); - oter_mapgen[id_base].push_back( ret ); - } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"object\" object)", id_base.c_str() ); - } + } + const std::string mgtype = jio.get_string( "method" ); + if( mgtype == "builtin" ) { + if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { + ret = std::make_shared( ptr, mgweight ); + oter_mapgen[id_base].push_back( ret ); } else { - debugmsg( "oter_t[%s]: Invalid mapgen function type: %s", id_base.c_str(), mgtype.c_str() ); + jio.throw_error( "function does not exist", "name" ); } + } else if( mgtype == "json" ) { + const std::string jstr = jio.get_object( "object" ).str(); + ret = std::make_shared( jstr, mgweight, offset ); + oter_mapgen[id_base].push_back( ret ); } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"method\" value, must be \"builtin\" or \"json\").", - id_base.c_str() ); + jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); } return ret; } From 55f4772c6f7e3b0fb5a950b6f8ec0374a95696dd Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:03:30 +0100 Subject: [PATCH 072/219] Move some repeated code into a function get_mapgen_function. Basically the whole look up of the mapgen function pointer within the `oter_mapgen` and so on. --- src/mapgen.cpp | 255 ++++++++++++++++++++++--------------------------- 1 file changed, 114 insertions(+), 141 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 741dc805e5d7f..4b43b784d6a6f 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -265,6 +265,31 @@ void check_mapgen_definitions() } } +// @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. +static mapgen_function *get_mapgen_function( const std::string &key, + const int hardcoded_weight = 0 ) +{ + const auto fmapit = oter_mapgen.find( key ); + if( fmapit == oter_mapgen.end() ) { + return nullptr; + } + const std::vector> &vector = fmapit->second; + // Creating the entry in the map is only done when an entry in the vector is about to be made, + // so the map should not contain empty vectors. + assert( !vector.empty() ); + const auto weightit = oter_mapgen_weights.find( key ); + const int rlast = weightit->second.rbegin()->first; + const int roll = rng( 1, rlast + hardcoded_weight ); + if( roll > rlast ) { + return nullptr; + } + const int fidx = weightit->second.lower_bound( roll )->second; + assert( static_cast( fidx ) < vector.size() ); + const std::shared_ptr &ptr = vector[fidx]; + assert( ptr ); + return ptr.get(); +} + ///////////////////////////////////////////////////////////////////////////////// ///// json mapgen functions ///// 1 - init(): @@ -3470,18 +3495,8 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { - const std::string function_key = "lab_1side"; // terrain_type->get_mapgen_id(); - const auto fmapit = oter_mapgen.find( function_key ); - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast ); - - const int fidx = weightit->second.lower_bound( roll )->second; - - fmapit->second[fidx]->generate( dat ); + if( const auto ptr = get_mapgen_function( "lab_1side" ) ) { + ptr->generate( dat ); if( tw == 2 ) { rotate( 2 ); } @@ -3497,75 +3512,57 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( dat.above(), t_stairs_up ); maybe_insert_stairs( terrain_type, t_stairs_down ); } else { - const std::string function_key = "lab_4side"; - const auto fmapit = oter_mapgen.find( function_key ); const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. - bool use_hardcoded_4side_map = false; - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_4side_map_weight ); - - if( roll <= rlast ) { - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - - // If the map template hasn't handled borders, handle them in code. - // Rotated maps cannot handle borders and have to be caught in code. - // We determine if a border isn't handled by checking the east-facing - // border space where the door normally is -- it should be a wall or door. - tripoint east_border( 23, 11, abs_sub.z ); - if( !has_flag_ter( "WALL", east_border ) && - !has_flag_ter( "DOOR", east_border ) ) { - // TODO: create a ter_reset function that does ter_set, - // furn_set, and i_clear? - ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : - t_concrete_wall; - ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : - t_concrete_wall; - for( int i = 0; i < SEEX * 2; i++ ) { - ter_set( point( 23, i ), rw_type ); - furn_set( point( 23, i ), f_null ); - i_clear( tripoint( 23, i, get_abs_sub().z ) ); - - ter_set( point( i, 23 ), bw_type ); - furn_set( point( i, 23 ), f_null ); - i_clear( tripoint( i, 23, get_abs_sub().z ) ); - - if( lw == 2 ) { - ter_set( point( 0, i ), lw_type ); - furn_set( point( 0, i ), f_null ); - i_clear( tripoint( 0, i, get_abs_sub().z ) ); - } - if( tw == 2 ) { - ter_set( point( i, 0 ), tw_type ); - furn_set( point( i, 0 ), f_null ); - i_clear( tripoint( i, 0, get_abs_sub().z ) ); - } - } - if( rw != 2 ) { - ter_set( point( 23, 11 ), t_door_metal_c ); - ter_set( point( 23, 12 ), t_door_metal_c ); + if( const auto ptr = get_mapgen_function( "lab_4side", hardcoded_4side_map_weight ) ) { + ptr->generate( dat ); + // If the map template hasn't handled borders, handle them in code. + // Rotated maps cannot handle borders and have to be caught in code. + // We determine if a border isn't handled by checking the east-facing + // border space where the door normally is -- it should be a wall or door. + tripoint east_border( 23, 11, abs_sub.z ); + if( !has_flag_ter( "WALL", east_border ) && + !has_flag_ter( "DOOR", east_border ) ) { + // TODO: create a ter_reset function that does ter_set, + // furn_set, and i_clear? + ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : + t_concrete_wall; + ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : + t_concrete_wall; + for( int i = 0; i < SEEX * 2; i++ ) { + ter_set( point( 23, i ), rw_type ); + furn_set( point( 23, i ), f_null ); + i_clear( tripoint( 23, i, get_abs_sub().z ) ); + + ter_set( point( i, 23 ), bw_type ); + furn_set( point( i, 23 ), f_null ); + i_clear( tripoint( i, 23, get_abs_sub().z ) ); + + if( lw == 2 ) { + ter_set( point( 0, i ), lw_type ); + furn_set( point( 0, i ), f_null ); + i_clear( tripoint( 0, i, get_abs_sub().z ) ); } - if( bw != 2 ) { - ter_set( point( 11, 23 ), t_door_metal_c ); - ter_set( point( 12, 23 ), t_door_metal_c ); + if( tw == 2 ) { + ter_set( point( i, 0 ), tw_type ); + furn_set( point( i, 0 ), f_null ); + i_clear( tripoint( i, 0, get_abs_sub().z ) ); } } + if( rw != 2 ) { + ter_set( point( 23, 11 ), t_door_metal_c ); + ter_set( point( 23, 12 ), t_door_metal_c ); + } + if( bw != 2 ) { + ter_set( point( 11, 23 ), t_door_metal_c ); + ter_set( point( 12, 23 ), t_door_metal_c ); + } + } - maybe_insert_stairs( dat.above(), t_stairs_up ); - maybe_insert_stairs( terrain_type, t_stairs_down ); - } else { // then weighted roll was in the hardcoded section - use_hardcoded_4side_map = true; - } // end json maps + maybe_insert_stairs( dat.above(), t_stairs_up ); + maybe_insert_stairs( terrain_type, t_stairs_down ); } else { // then no json maps for lab_4side were found - use_hardcoded_4side_map = true; - } // end if no lab_4side was found. - if( use_hardcoded_4side_map ) { switch( rng( 1, 3 ) ) { case 1: // Cross shaped @@ -4060,69 +4057,51 @@ void map::draw_lab( mapgendata &dat ) bw = is_ot_match( "lab", dat.south(), ot_match_type::contains ) ? 1 : 2; lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; - const std::string function_key = "lab_finale_1level"; - const auto fmapit = oter_mapgen.find( function_key ); const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. - bool use_hardcoded_finale_map = false; - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_finale_map_weight ); - - if( roll <= rlast ) { - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - - // If the map template hasn't handled borders, handle them in code. - // Rotated maps cannot handle borders and have to be caught in code. - // We determine if a border isn't handled by checking the east-facing - // border space where the door normally is -- it should be a wall or door. - tripoint east_border( 23, 11, abs_sub.z ); - if( !has_flag_ter( "WALL", east_border ) && !has_flag_ter( "DOOR", east_border ) ) { - // TODO: create a ter_reset function that does ter_set, furn_set, and i_clear? - ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : t_concrete_wall; - ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : t_concrete_wall; - for( int i = 0; i < SEEX * 2; i++ ) { - ter_set( point( 23, i ), rw_type ); - furn_set( point( 23, i ), f_null ); - i_clear( tripoint( 23, i, get_abs_sub().z ) ); - - ter_set( point( i, 23 ), bw_type ); - furn_set( point( i, 23 ), f_null ); - i_clear( tripoint( i, 23, get_abs_sub().z ) ); - - if( lw == 2 ) { - ter_set( point( 0, i ), lw_type ); - furn_set( point( 0, i ), f_null ); - i_clear( tripoint( 0, i, get_abs_sub().z ) ); - } - if( tw == 2 ) { - ter_set( point( i, 0 ), tw_type ); - furn_set( point( i, 0 ), f_null ); - i_clear( tripoint( i, 0, get_abs_sub().z ) ); - } - } - if( rw != 2 ) { - ter_set( point( 23, 11 ), t_door_metal_c ); - ter_set( point( 23, 12 ), t_door_metal_c ); + if( const auto ptr = get_mapgen_function( "lab_finale_1level", hardcoded_finale_map_weight ) ) { + ptr->generate( dat ); + + // If the map template hasn't handled borders, handle them in code. + // Rotated maps cannot handle borders and have to be caught in code. + // We determine if a border isn't handled by checking the east-facing + // border space where the door normally is -- it should be a wall or door. + tripoint east_border( 23, 11, abs_sub.z ); + if( !has_flag_ter( "WALL", east_border ) && !has_flag_ter( "DOOR", east_border ) ) { + // TODO: create a ter_reset function that does ter_set, furn_set, and i_clear? + ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : t_concrete_wall; + ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : t_concrete_wall; + for( int i = 0; i < SEEX * 2; i++ ) { + ter_set( point( 23, i ), rw_type ); + furn_set( point( 23, i ), f_null ); + i_clear( tripoint( 23, i, get_abs_sub().z ) ); + + ter_set( point( i, 23 ), bw_type ); + furn_set( point( i, 23 ), f_null ); + i_clear( tripoint( i, 23, get_abs_sub().z ) ); + + if( lw == 2 ) { + ter_set( point( 0, i ), lw_type ); + furn_set( point( 0, i ), f_null ); + i_clear( tripoint( 0, i, get_abs_sub().z ) ); } - if( bw != 2 ) { - ter_set( point( 11, 23 ), t_door_metal_c ); - ter_set( point( 12, 23 ), t_door_metal_c ); + if( tw == 2 ) { + ter_set( point( i, 0 ), tw_type ); + furn_set( point( i, 0 ), f_null ); + i_clear( tripoint( i, 0, get_abs_sub().z ) ); } } - } else { // then weighted roll was in the hardcoded section - use_hardcoded_finale_map = true; - } // end json maps + if( rw != 2 ) { + ter_set( point( 23, 11 ), t_door_metal_c ); + ter_set( point( 23, 12 ), t_door_metal_c ); + } + if( bw != 2 ) { + ter_set( point( 11, 23 ), t_door_metal_c ); + ter_set( point( 12, 23 ), t_door_metal_c ); + } + } } else { // then no json maps for lab_finale_1level were found - use_hardcoded_finale_map = true; - } // end if no lab_4side was found. - - if( use_hardcoded_finale_map ) { // Start by setting up a large, empty room. for( int i = 0; i < SEEX * 2; i++ ) { for( int j = 0; j < SEEY * 2; j++ ) { @@ -7296,14 +7275,8 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - const auto fmapit = oter_mapgen.find( mapgen_id ); - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - mapgen_id ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast ); - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); + if( const auto ptr = get_mapgen_function( mapgen_id ) ) { + ptr->generate( dat ); return true; } return false; From 3face8572798ab604f1268e68ee35d4d999f7293 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:11:35 +0100 Subject: [PATCH 073/219] Move some code as function into mapgen.cpp This is mostly done to avoid having to expose `oter_mapgen` in the header. --- src/mapgen.cpp | 10 ++++++++++ src/mapgen.h | 7 +++++++ src/overmap.cpp | 5 +---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 4b43b784d6a6f..750c363585881 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -7281,3 +7281,13 @@ bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) } return false; } + +int register_mapgen_function( const std::string &key ) +{ + if( const auto ptr = get_mapgen_cfunction( key ) ) { + std::vector> &vector = oter_mapgen[key]; + vector.push_back( std::make_shared( ptr ) ); + return vector.size() - 1; + } + return -1; +} diff --git a/src/mapgen.h b/src/mapgen.h index 6c9e31034673d..91f924ea59109 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -378,6 +378,13 @@ std::shared_ptr load_mapgen_function( const JsonObject &jio, */ void load_mapgen( const JsonObject &jo ); void reset_mapgens(); +/** + * Attempts to register the build-in function @p key as mapgen for the overmap terrain @p key. + * If there is no matching function, it does nothing (no error message) and returns -1. + * Otherwise it returns the index of the added entry in the vector of @ref oter_mapgen. + */ +// @TODO this should go away. It is only used for old build-in mapgen. Mapgen should be done via JSON. +int register_mapgen_function( const std::string &key ); /* * stores function ref and/or required data */ diff --git a/src/overmap.cpp b/src/overmap.cpp index 555b786d0b879..f15b599d539dd 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -530,10 +530,7 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin bool default_mapgen = jo.get_bool( "default_mapgen", true ); int default_idx = -1; if( default_mapgen ) { - if( const auto ptr = get_mapgen_cfunction( fmapkey ) ) { - oter_mapgen[fmapkey].push_back( std::make_shared( ptr ) ); - default_idx = oter_mapgen[fmapkey].size() - 1; - } + default_idx = register_mapgen_function( fmapkey ); } if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { From 073f003516746aa79d73b4c362ab8a97176203cc Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:12:33 +0100 Subject: [PATCH 074/219] Remove redundant declaration. Those variables are already declared in a header or not even used within this cpp file. --- src/map_extras.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/map_extras.cpp b/src/map_extras.cpp index caf08d0a45d4b..2ef322a6be8f6 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -2832,9 +2832,6 @@ void map_extra::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "autonote", autonote, false ); } -extern std::map> > oter_mapgen; -extern std::map> > - nested_mapgen; extern std::map> > update_mapgen; From 8e0bb46484c0f0b71f5d8c2d33aa7ca3916b29e4 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:13:00 +0100 Subject: [PATCH 075/219] Remove commented out code. --- src/map_extras.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 2ef322a6be8f6..0cd274ad9dd3e 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -2847,13 +2847,6 @@ void map_extra::check() const break; } case map_extra_method::mapgen: { - /* - const auto fmapit = oter_mapgen.find( generator_id ); - const oter_id extra_oter( generator_id ); - if( ( fmapit == oter_mapgen.end() || !fmapit->second.empty() ) && !extra_oter.is_valid() ) { - debugmsg( "invalid mapgen function (%s) defined for map extra (%s)", generator_id, id.str() ); - } - */ break; } case map_extra_method::update_mapgen: { From 98043b59410c3fb2e54cc080b47e455bcffb2d87 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:15:00 +0100 Subject: [PATCH 076/219] Move access to oter_mapgen into mapgen.cpp Again: this is to avoid having to expose `oter_mapgen` in the header. --- src/mapgen.cpp | 5 +++++ src/mapgen.h | 4 ++++ src/overmap.cpp | 3 +-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 750c363585881..4643499fbda69 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -7291,3 +7291,8 @@ int register_mapgen_function( const std::string &key ) } return -1; } + +bool has_mapgen_for( const std::string &key ) +{ + return oter_mapgen.count( key ) != 0; +} diff --git a/src/mapgen.h b/src/mapgen.h index 91f924ea59109..8d01c465bc561 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -385,6 +385,10 @@ void reset_mapgens(); */ // @TODO this should go away. It is only used for old build-in mapgen. Mapgen should be done via JSON. int register_mapgen_function( const std::string &key ); +/** + * Check that @p key is present in @ref oter_mapgen. + */ +bool has_mapgen_for( const std::string &key ); /* * stores function ref and/or required data */ diff --git a/src/overmap.cpp b/src/overmap.cpp index f15b599d539dd..fd577a0639c84 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -787,9 +787,8 @@ void overmap_terrains::check_consistency() } const bool exists_hardcoded = elem.is_hardcoded(); - const bool exists_loaded = oter_mapgen.find( mid ) != oter_mapgen.end(); - if( exists_loaded ) { + if( has_mapgen_for( mid ) ) { if( test_mode && exists_hardcoded ) { debugmsg( "Mapgen terrain \"%s\" exists in both JSON and a hardcoded function. Consider removing the latter.", mid.c_str() ); From 561a4b2b473bf592328bc65f511fe96c3f3a5873 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:19:49 +0100 Subject: [PATCH 077/219] Remove exposing variables from mapgen.cpp in the header. Merges the comments from the header with the comments in the cpp file for the very same objects. --- src/mapgen.cpp | 3 ++- src/mapgen.h | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 4643499fbda69..8fe9687d7e367 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -195,7 +195,7 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// all sorts of ways to apply our hellish reality to a grid-o-squares /* - * ptr storage. + * stores function ref and/or required data */ std::map> > oter_mapgen; std::map> > nested_mapgen; @@ -203,6 +203,7 @@ std::map> /* * index to the above, adjusted to allow for rarity + * random selector list for the nested vector above, as per individual mapgen_function_::weight value */ std::map > oter_mapgen_weights; diff --git a/src/mapgen.h b/src/mapgen.h index 8d01c465bc561..b543a00b1bf0e 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -389,14 +389,6 @@ int register_mapgen_function( const std::string &key ); * Check that @p key is present in @ref oter_mapgen. */ bool has_mapgen_for( const std::string &key ); -/* - * stores function ref and/or required data - */ -extern std::map> > oter_mapgen; -/* - * random selector list for the nested vector above, as per individual mapgen_function_::weight value - */ -extern std::map > oter_mapgen_weights; /* * Sets the above after init, and initializes mapgen_function_json instances as well */ From 452d9a65ebec76bcf2d63f66828466c8e64b3303 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:20:09 +0100 Subject: [PATCH 078/219] Add separate function to register mapgen object: register_mapgen_function --- src/mapgen.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 8fe9687d7e367..3002559bb0168 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -266,6 +266,15 @@ void check_mapgen_definitions() } } +static int register_mapgen_function( const std::string &key, + const std::shared_ptr ptr ) +{ + assert( ptr ); + std::vector> &vector = oter_mapgen[key]; + vector.push_back( ptr ); + return vector.size() - 1; +} + // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. static mapgen_function *get_mapgen_function( const std::string &key, const int hardcoded_weight = 0 ) @@ -341,14 +350,14 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( mgtype == "builtin" ) { if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { ret = std::make_shared( ptr, mgweight ); - oter_mapgen[id_base].push_back( ret ); + register_mapgen_function( id_base, ret ); } else { jio.throw_error( "function does not exist", "name" ); } } else if( mgtype == "json" ) { const std::string jstr = jio.get_object( "object" ).str(); ret = std::make_shared( jstr, mgweight, offset ); - oter_mapgen[id_base].push_back( ret ); + register_mapgen_function( id_base, ret ); } else { jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); } @@ -405,7 +414,7 @@ void load_mapgen( const JsonObject &jo ) for( const std::string mapgenid : row_items ) { const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); if( mgfunc ) { - oter_mapgen[ mapgenid ].push_back( mgfunc ); + register_mapgen_function( mapgenid, mgfunc ); } offset.x++; } @@ -422,7 +431,7 @@ void load_mapgen( const JsonObject &jo ) const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); if( mgfunc ) { for( auto &i : mapgenid_list ) { - oter_mapgen[ i ].push_back( mgfunc ); + register_mapgen_function( i, mgfunc ); } } } @@ -7286,9 +7295,7 @@ bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) int register_mapgen_function( const std::string &key ) { if( const auto ptr = get_mapgen_cfunction( key ) ) { - std::vector> &vector = oter_mapgen[key]; - vector.push_back( std::make_shared( ptr ) ); - return vector.size() - 1; + return register_mapgen_function( key, std::make_shared( ptr ) ); } return -1; } From 93e1e09569ae7efd4e892700df5ffcd0d746f8ab Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:26:07 +0100 Subject: [PATCH 079/219] =?UTF-8?q?Change=20oter=5Fmapgen=20to=20contain?= =?UTF-8?q?=20=C3=ADnstances=20of=20a=20dedicated=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those instances can have their own members and stuff. --- src/mapgen.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 3002559bb0168..14243798da6b7 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -194,10 +194,19 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// mapgen_function class. ///// all sorts of ways to apply our hellish reality to a grid-o-squares +class mapgen_basic_container : public std::vector> +{ + public: + int add( const std::shared_ptr ptr ) { + assert( ptr ); + push_back( ptr ); + return size() - 1; + } +}; /* * stores function ref and/or required data */ -std::map> > oter_mapgen; +std::map oter_mapgen; std::map> > nested_mapgen; std::map> > update_mapgen; @@ -269,10 +278,7 @@ void check_mapgen_definitions() static int register_mapgen_function( const std::string &key, const std::shared_ptr ptr ) { - assert( ptr ); - std::vector> &vector = oter_mapgen[key]; - vector.push_back( ptr ); - return vector.size() - 1; + return oter_mapgen[key].add( ptr ); } // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. From c8431a6ac3d02a376ae2f9e393fb15d77246a242 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:41:11 +0100 Subject: [PATCH 080/219] Merge oter_mapgen_weights into oter_mapgen: Instead of having a separate map, this reuses the already existing entries in `oter_mapgen`. --- src/mapgen.cpp | 26 ++++++++++++-------------- src/mapgen.h | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 14243798da6b7..0d61fd1f6189e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -197,6 +197,12 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) class mapgen_basic_container : public std::vector> { public: + /** + * index to the above, adjusted to allow for rarity + * random selector list for the nested vector above, as per individual mapgen_function_::weight value + */ + std::map weights_; + int add( const std::shared_ptr ptr ) { assert( ptr ); push_back( ptr ); @@ -211,21 +217,14 @@ std::map> std::map> > update_mapgen; /* - * index to the above, adjusted to allow for rarity - * random selector list for the nested vector above, as per individual mapgen_function_::weight value - */ -std::map > oter_mapgen_weights; - -/* - * setup oter_mapgen_weights which mapgen uses to diceroll. Also setup mapgen_function_json + * setup mapgen_basic_container::weights_ which mapgen uses to diceroll. Also setup mapgen_function_json */ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { - oter_mapgen_weights.clear(); for( auto &omw : oter_mapgen ) { int funcnum = 0; int wtotal = 0; - oter_mapgen_weights[ omw.first ] = std::map(); + omw.second.weights_.clear(); for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { // int weight = ( *fit )->weight; @@ -237,7 +236,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup } ( *fit )->setup(); wtotal += weight; - oter_mapgen_weights[ omw.first ][ wtotal ] = funcnum; + omw.second.weights_[ wtotal ] = funcnum; dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): +" << weight << " = " << wtotal; ++funcnum; } @@ -289,17 +288,16 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( fmapit == oter_mapgen.end() ) { return nullptr; } - const std::vector> &vector = fmapit->second; + const mapgen_basic_container &vector = fmapit->second; // Creating the entry in the map is only done when an entry in the vector is about to be made, // so the map should not contain empty vectors. assert( !vector.empty() ); - const auto weightit = oter_mapgen_weights.find( key ); - const int rlast = weightit->second.rbegin()->first; + const int rlast = vector.weights_.rbegin()->first; const int roll = rng( 1, rlast + hardcoded_weight ); if( roll > rlast ) { return nullptr; } - const int fidx = weightit->second.lower_bound( roll )->second; + const int fidx = vector.weights_.lower_bound( roll )->second; assert( static_cast( fidx ) < vector.size() ); const std::shared_ptr &ptr = vector[fidx]; assert( ptr ); diff --git a/src/mapgen.h b/src/mapgen.h index b543a00b1bf0e..ec114176152df 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -374,7 +374,7 @@ std::shared_ptr load_mapgen_function( const JsonObject &jio, const std::string &id_base, int default_idx, const point &offset = point_zero ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check - * for oter_mapgen / oter_mapgen_weights key, multiple possible ( ie, [ "house", "house_base" ] ) + * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) */ void load_mapgen( const JsonObject &jo ); void reset_mapgens(); From 0b5463e36110ae66d26523a78c7da9ccfc575277 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:47:16 +0100 Subject: [PATCH 081/219] Store pointers directly in oter_mapgen weights map instead of indices into the vector itself. This avoids the repeated look up within the vector and it avoids a potential error situation: the index taken from `weight_` could be invalid. --- src/mapgen.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 0d61fd1f6189e..985dd96a2be22 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -201,7 +201,7 @@ class mapgen_basic_container : public std::vector weights_; + std::map> weights_; int add( const std::shared_ptr ptr ) { assert( ptr ); @@ -222,23 +222,18 @@ std::map> void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { for( auto &omw : oter_mapgen ) { - int funcnum = 0; int wtotal = 0; omw.second.weights_.clear(); for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { - // int weight = ( *fit )->weight; if( weight < 1 ) { - dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): (rej(1), " << weight << ") = " << - wtotal; - ++funcnum; + dbg( D_INFO ) << "wcalc " << omw.first << ": (rej(1), " << weight << ") = " << wtotal; continue; // rejected! } ( *fit )->setup(); wtotal += weight; - omw.second.weights_[ wtotal ] = funcnum; - dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): +" << weight << " = " << wtotal; - ++funcnum; + omw.second.weights_[ wtotal ] = *fit; + dbg( D_INFO ) << "wcalc " << omw.first << ": +" << weight << " = " << wtotal; } } // Not really calculate weights, but let's keep it here for now @@ -297,9 +292,7 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( roll > rlast ) { return nullptr; } - const int fidx = vector.weights_.lower_bound( roll )->second; - assert( static_cast( fidx ) < vector.size() ); - const std::shared_ptr &ptr = vector[fidx]; + const std::shared_ptr &ptr = vector.weights_.lower_bound( roll )->second; assert( ptr ); return ptr.get(); } From 585860916421b7bb1d6214ffb3183036cdfc887e Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:56:06 +0100 Subject: [PATCH 082/219] Use weighted_int_list for oter_mapgen weights We already have this class, so we should make use of it. --- src/mapgen.cpp | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 985dd96a2be22..5a21a2e22c157 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -197,11 +197,7 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) class mapgen_basic_container : public std::vector> { public: - /** - * index to the above, adjusted to allow for rarity - * random selector list for the nested vector above, as per individual mapgen_function_::weight value - */ - std::map> weights_; + weighted_int_list> weights_; int add( const std::shared_ptr ptr ) { assert( ptr ); @@ -222,19 +218,16 @@ std::map> void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { for( auto &omw : oter_mapgen ) { - int wtotal = 0; omw.second.weights_.clear(); - for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { - int weight = ( *fit )->weight; + for( const std::shared_ptr &ptr : omw.second ) { + const int weight = ptr->weight; if( weight < 1 ) { - dbg( D_INFO ) << "wcalc " << omw.first << ": (rej(1), " << weight << ") = " << wtotal; continue; // rejected! } - ( *fit )->setup(); - wtotal += weight; - omw.second.weights_[ wtotal ] = *fit; - dbg( D_INFO ) << "wcalc " << omw.first << ": +" << weight << " = " << wtotal; + omw.second.weights_.add( ptr, weight ); + ptr->setup(); } + // @TODO clear: omw.second.clear(); } // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { @@ -283,18 +276,18 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( fmapit == oter_mapgen.end() ) { return nullptr; } - const mapgen_basic_container &vector = fmapit->second; - // Creating the entry in the map is only done when an entry in the vector is about to be made, - // so the map should not contain empty vectors. - assert( !vector.empty() ); - const int rlast = vector.weights_.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_weight ); - if( roll > rlast ) { + const weighted_int_list> &weights = fmapit->second.weights_; + if( hardcoded_weight > 0 ) { + if( rng( 1, weights.get_weight() + hardcoded_weight ) > weights.get_weight() ) { + return nullptr; + } + } + const std::shared_ptr *ptr = weights.pick(); + if( !ptr ) { return nullptr; } - const std::shared_ptr &ptr = vector.weights_.lower_bound( roll )->second; - assert( ptr ); - return ptr.get(); + assert( *ptr ); + return ptr->get(); } ///////////////////////////////////////////////////////////////////////////////// From c029ea09ba7abc3997f4a25e5a501f375c2a9ab7 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:59:35 +0100 Subject: [PATCH 083/219] Move code into a member function mapgen_basic_container::pick --- src/mapgen.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 5a21a2e22c157..68d0e2cac9ef2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -204,6 +204,23 @@ class mapgen_basic_container : public std::vector 0 && + rng( 1, weights_.get_weight() + hardcoded_weight ) > weights_.get_weight() ) { + return nullptr; + } + const std::shared_ptr *const ptr = weights_.pick(); + if( !ptr ) { + return nullptr; + } + assert( *ptr ); + return ptr->get(); + } }; /* * stores function ref and/or required data @@ -276,18 +293,7 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( fmapit == oter_mapgen.end() ) { return nullptr; } - const weighted_int_list> &weights = fmapit->second.weights_; - if( hardcoded_weight > 0 ) { - if( rng( 1, weights.get_weight() + hardcoded_weight ) > weights.get_weight() ) { - return nullptr; - } - } - const std::shared_ptr *ptr = weights.pick(); - if( !ptr ) { - return nullptr; - } - assert( *ptr ); - return ptr->get(); + return fmapit->second.pick( hardcoded_weight ); } ///////////////////////////////////////////////////////////////////////////////// From bf62fd2bc3fa80efd8fa883467a2fb215e946b61 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:02:38 +0100 Subject: [PATCH 084/219] Move code into a member function: mapgen_basic_container::setup --- src/mapgen.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 68d0e2cac9ef2..22e5fb2716fc0 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -221,6 +221,18 @@ class mapgen_basic_container : public std::vectorget(); } + void setup() { + weights_.clear(); + for( const std::shared_ptr &ptr : *this ) { + const int weight = ptr->weight; + if( weight < 1 ) { + continue; // rejected! + } + weights_.add( ptr, weight ); + ptr->setup(); + } + // @TODO clear: clear(); + } }; /* * stores function ref and/or required data @@ -235,16 +247,7 @@ std::map> void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { for( auto &omw : oter_mapgen ) { - omw.second.weights_.clear(); - for( const std::shared_ptr &ptr : omw.second ) { - const int weight = ptr->weight; - if( weight < 1 ) { - continue; // rejected! - } - omw.second.weights_.add( ptr, weight ); - ptr->setup(); - } - // @TODO clear: omw.second.clear(); + omw.second.setup(); } // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { From 35c88934ebb964b717a7f2d6fbdf85d8edc0626a Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:02:42 +0100 Subject: [PATCH 085/219] Move code into a member function: mapgen_basic_container::check_consistency Note: the function name is chosen for consistency (no pun), our other consistency checking function are named that way. --- src/mapgen.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 22e5fb2716fc0..db2f43673b6b6 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -233,6 +233,11 @@ class mapgen_basic_container : public std::vectorcheck( key ); + } + } }; /* * stores function ref and/or required data @@ -266,9 +271,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup void check_mapgen_definitions() { for( auto &oter_definition : oter_mapgen ) { - for( auto &mapgen_function_ptr : oter_definition.second ) { - mapgen_function_ptr->check( oter_definition.first ); - } + oter_definition.second.check_consistency( oter_definition.first ); } for( auto &oter_definition : nested_mapgen ) { for( auto &mapgen_function_ptr : oter_definition.second ) { From 59ce8748eada9998df0704e602fa0c23bdaefda8 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:08:15 +0100 Subject: [PATCH 086/219] Make all data members of mapgen_basic_container private. No need to expose them. The last direct access to the vector had to be wrapped within a new member function. --- src/mapgen.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index db2f43673b6b6..5b30f648914ec 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -194,15 +194,25 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// mapgen_function class. ///// all sorts of ways to apply our hellish reality to a grid-o-squares -class mapgen_basic_container : public std::vector> +class mapgen_basic_container { - public: + private: + std::vector> mapgens_; weighted_int_list> weights_; + public: int add( const std::shared_ptr ptr ) { assert( ptr ); - push_back( ptr ); - return size() - 1; + mapgens_.push_back( ptr ); + return mapgens_.size() - 1; + } + void erase( const size_t index ) { + if( index > mapgens_.size() ) { + return; + } + assert( mapgens_[index] ); + // Can't actually erase it as this might invalid the index stored elsewhere + mapgens_[index]->weight = 0; } /** * Pick a mapgen function randomly. @@ -222,8 +232,7 @@ class mapgen_basic_container : public std::vectorget(); } void setup() { - weights_.clear(); - for( const std::shared_ptr &ptr : *this ) { + for( const std::shared_ptr &ptr : mapgens_ ) { const int weight = ptr->weight; if( weight < 1 ) { continue; // rejected! @@ -231,10 +240,11 @@ class mapgen_basic_container : public std::vectorsetup(); } - // @TODO clear: clear(); + // Not needed anymore, pointers are now stored in weights_ (or not used at all) + mapgens_.clear(); } void check_consistency( const std::string &key ) { - for( auto &mapgen_function_ptr : *this ) { + for( auto &mapgen_function_ptr : mapgens_ ) { mapgen_function_ptr->check( key ); } } @@ -341,7 +351,7 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( jio.has_string( "name" ) ) { const std::string mgname = jio.get_string( "name" ); if( mgname == id_base ) { - oter_mapgen[id_base][ default_idx ]->weight = 0; + oter_mapgen[id_base].erase( default_idx ); } } } From 0c8c075b2f1426aced1753b71f6ed6635cd58551 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:16:36 +0100 Subject: [PATCH 087/219] Make a separate class for oter_mapgen And move all the functions that deal with it into that class. --- src/mapgen.cpp | 91 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 5b30f648914ec..aa378880af3a2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -249,10 +249,50 @@ class mapgen_basic_container } } }; + +class mapgen_factory +{ + private: + std::map mapgens_; + + public: + void reset() { + mapgens_.clear(); + } + void setup() { + for( auto &omw : mapgens_ ) { + omw.second.setup(); + } + } + void check_consistency() { + for( auto &oter_definition : mapgens_ ) { + oter_definition.second.check_consistency( oter_definition.first ); + } + } + bool has( const std::string &key ) const { + return mapgens_.count( key ) != 0; + } + int add( const std::string &key, const std::shared_ptr ptr ) { + return mapgens_[key].add( ptr ); + } + // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. + mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { + const auto fmapit = mapgens_.find( key ); + if( fmapit == mapgens_.end() ) { + return nullptr; + } + return fmapit->second.pick( hardcoded_weight ); + } + void erase( const std::string &key, const size_t index ) { + mapgens_[key].erase( index ); + } +}; + +static mapgen_factory oter_mapgen; + /* * stores function ref and/or required data */ -std::map oter_mapgen; std::map> > nested_mapgen; std::map> > update_mapgen; @@ -261,9 +301,7 @@ std::map> */ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { - for( auto &omw : oter_mapgen ) { - omw.second.setup(); - } + oter_mapgen.setup(); // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { for( std::unique_ptr &ptr : pr.second ) { @@ -280,9 +318,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup void check_mapgen_definitions() { - for( auto &oter_definition : oter_mapgen ) { - oter_definition.second.check_consistency( oter_definition.first ); - } + oter_mapgen.check_consistency(); for( auto &oter_definition : nested_mapgen ) { for( auto &mapgen_function_ptr : oter_definition.second ) { mapgen_function_ptr->check( oter_definition.first ); @@ -295,23 +331,6 @@ void check_mapgen_definitions() } } -static int register_mapgen_function( const std::string &key, - const std::shared_ptr ptr ) -{ - return oter_mapgen[key].add( ptr ); -} - -// @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. -static mapgen_function *get_mapgen_function( const std::string &key, - const int hardcoded_weight = 0 ) -{ - const auto fmapit = oter_mapgen.find( key ); - if( fmapit == oter_mapgen.end() ) { - return nullptr; - } - return fmapit->second.pick( hardcoded_weight ); -} - ///////////////////////////////////////////////////////////////////////////////// ///// json mapgen functions ///// 1 - init(): @@ -351,7 +370,7 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( jio.has_string( "name" ) ) { const std::string mgname = jio.get_string( "name" ); if( mgname == id_base ) { - oter_mapgen[id_base].erase( default_idx ); + oter_mapgen.erase( id_base, default_idx ); } } } @@ -362,14 +381,14 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( mgtype == "builtin" ) { if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { ret = std::make_shared( ptr, mgweight ); - register_mapgen_function( id_base, ret ); + oter_mapgen.add( id_base, ret ); } else { jio.throw_error( "function does not exist", "name" ); } } else if( mgtype == "json" ) { const std::string jstr = jio.get_object( "object" ).str(); ret = std::make_shared( jstr, mgweight, offset ); - register_mapgen_function( id_base, ret ); + oter_mapgen.add( id_base, ret ); } else { jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); } @@ -426,7 +445,7 @@ void load_mapgen( const JsonObject &jo ) for( const std::string mapgenid : row_items ) { const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); if( mgfunc ) { - register_mapgen_function( mapgenid, mgfunc ); + oter_mapgen.add( mapgenid, mgfunc ); } offset.x++; } @@ -443,7 +462,7 @@ void load_mapgen( const JsonObject &jo ) const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); if( mgfunc ) { for( auto &i : mapgenid_list ) { - register_mapgen_function( i, mgfunc ); + oter_mapgen.add( i, mgfunc ); } } } @@ -462,7 +481,7 @@ void load_mapgen( const JsonObject &jo ) void reset_mapgens() { - oter_mapgen.clear(); + oter_mapgen.reset(); nested_mapgen.clear(); update_mapgen.clear(); } @@ -3517,7 +3536,7 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { - if( const auto ptr = get_mapgen_function( "lab_1side" ) ) { + if( const auto ptr = oter_mapgen.pick( "lab_1side" ) ) { ptr->generate( dat ); if( tw == 2 ) { rotate( 2 ); @@ -3535,7 +3554,7 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( terrain_type, t_stairs_down ); } else { const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. - if( const auto ptr = get_mapgen_function( "lab_4side", hardcoded_4side_map_weight ) ) { + if( const auto ptr = oter_mapgen.pick( "lab_4side", hardcoded_4side_map_weight ) ) { ptr->generate( dat ); // If the map template hasn't handled borders, handle them in code. // Rotated maps cannot handle borders and have to be caught in code. @@ -4080,7 +4099,7 @@ void map::draw_lab( mapgendata &dat ) lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. - if( const auto ptr = get_mapgen_function( "lab_finale_1level", hardcoded_finale_map_weight ) ) { + if( const auto ptr = oter_mapgen.pick( "lab_finale_1level", hardcoded_finale_map_weight ) ) { ptr->generate( dat ); // If the map template hasn't handled borders, handle them in code. @@ -7297,7 +7316,7 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - if( const auto ptr = get_mapgen_function( mapgen_id ) ) { + if( const auto ptr = oter_mapgen.pick( mapgen_id ) ) { ptr->generate( dat ); return true; } @@ -7307,12 +7326,12 @@ bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) int register_mapgen_function( const std::string &key ) { if( const auto ptr = get_mapgen_cfunction( key ) ) { - return register_mapgen_function( key, std::make_shared( ptr ) ); + return oter_mapgen.add( key, std::make_shared( ptr ) ); } return -1; } bool has_mapgen_for( const std::string &key ) { - return oter_mapgen.count( key ) != 0; + return oter_mapgen.has( key ); } From 6ac5b5c7cfc7c19789fbc1608ee22ebd065c2b38 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:17:23 +0100 Subject: [PATCH 088/219] Replace `auto` with actual type --- src/mapgen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index aa378880af3a2..285c877abceb2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -260,12 +260,12 @@ class mapgen_factory mapgens_.clear(); } void setup() { - for( auto &omw : mapgens_ ) { + for( std::pair &omw : mapgens_ ) { omw.second.setup(); } } void check_consistency() { - for( auto &oter_definition : mapgens_ ) { + for( std::pair &oter_definition : mapgens_ ) { oter_definition.second.check_consistency( oter_definition.first ); } } From 5e1b2964c971df60d9cc1d77ab6a6fcf7b63dc85 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:18:12 +0100 Subject: [PATCH 089/219] Consistent naming: "omw" just like in the other function --- src/mapgen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 285c877abceb2..eba3bd73635c4 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -265,8 +265,8 @@ class mapgen_factory } } void check_consistency() { - for( std::pair &oter_definition : mapgens_ ) { - oter_definition.second.check_consistency( oter_definition.first ); + for( std::pair &omw : mapgens_ ) { + omw.second.check_consistency( omw.first ); } } bool has( const std::string &key ) const { From dde60f4966c356cdab60cfaf844c2a46a3a10d08 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:18:47 +0100 Subject: [PATCH 090/219] Consistent naming: just "iter" as there is no need to hint the data type (and what does the "f" even stand for?) --- src/mapgen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index eba3bd73635c4..f8daedd3a5ee7 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -277,11 +277,11 @@ class mapgen_factory } // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { - const auto fmapit = mapgens_.find( key ); - if( fmapit == mapgens_.end() ) { + const auto iter = mapgens_.find( key ); + if( iter == mapgens_.end() ) { return nullptr; } - return fmapit->second.pick( hardcoded_weight ); + return iter->second.pick( hardcoded_weight ); } void erase( const std::string &key, const size_t index ) { mapgens_[key].erase( index ); From f1010d70efa9d2136db2056d38f90ceed054a2a8 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:50:58 +0100 Subject: [PATCH 091/219] Add usage checks for loaded mapgen instances. This will find mapgen instances that were loaded from JSON, but have no usage within the game (e.g. because the belong to undefined overmap terrain). Register some mapgen ids that are only used within the C++ code as used --- src/mapgen.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index f8daedd3a5ee7..048fd858041d1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -15,6 +15,7 @@ #include #include "clzones.h" +#include "generic_factory.h" #include "computer.h" #include "coordinate_conversions.h" #include "coordinates.h" @@ -255,6 +256,25 @@ class mapgen_factory private: std::map mapgens_; + static std::set get_usages() { + std::set result; + for( const oter_t &elem : overmap_terrains::get_all() ) { + result.insert( elem.get_mapgen_id() ); + result.insert( elem.id.str() ); + } + // Why do I have to repeat the MapExtras here? Wouldn't "MapExtras::factory" be enough? + for( const map_extra &elem : MapExtras::mapExtraFactory().get_all() ) { + if( elem.generator_method == map_extra_method::mapgen ) { + result.insert( elem.generator_id ); + } + } + // Used in C++ code only, see calls to `oter_mapgen.pick()` below + result.insert( "lab_1side" ); + result.insert( "lab_4side" ); + result.insert( "lab_finale_1level" ); + return result; + } + public: void reset() { mapgens_.clear(); @@ -265,8 +285,14 @@ class mapgen_factory } } void check_consistency() { + // Cache all strings that may get looked up here so we don't have to go through + // all the sources for them upon each loop. + const std::set usages = get_usages(); for( std::pair &omw : mapgens_ ) { omw.second.check_consistency( omw.first ); + if( usages.count( omw.first ) == 0 ) { + debugmsg( "Mapgen %s is not used by anything!", omw.first ); + } } } bool has( const std::string &key ) const { @@ -3536,6 +3562,7 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { + // If you remove the usage of "lab_1side" here, remove it from mapgen_factory::get_usages above as well. if( const auto ptr = oter_mapgen.pick( "lab_1side" ) ) { ptr->generate( dat ); if( tw == 2 ) { @@ -3554,6 +3581,7 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( terrain_type, t_stairs_down ); } else { const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. + // If you remove the usage of "lab_4side" here, remove it from mapgen_factory::get_usages above as well. if( const auto ptr = oter_mapgen.pick( "lab_4side", hardcoded_4side_map_weight ) ) { ptr->generate( dat ); // If the map template hasn't handled borders, handle them in code. @@ -4099,6 +4127,7 @@ void map::draw_lab( mapgendata &dat ) lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. + // If you remove the usage of "lab_finale_1level" here, remove it from mapgen_factory::get_usages above as well. if( const auto ptr = oter_mapgen.pick( "lab_finale_1level", hardcoded_finale_map_weight ) ) { ptr->generate( dat ); From c2e1bea61789238e29d46aae38bd93ac3fa2e39b Mon Sep 17 00:00:00 2001 From: BevapDin Date: Mon, 27 Jan 2020 00:06:08 +0100 Subject: [PATCH 092/219] Add some documentation. --- src/mapgen.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 048fd858041d1..875baedce8742 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -232,6 +232,11 @@ class mapgen_basic_container assert( *ptr ); return ptr->get(); } + /** + * Calls @ref mapgen_function::setup and sets up the internal weighted list using + * the **current** value of @ref mapgen_function::weight. This value may have + * changed since it was first added, so this is needed to recalculate the weighted list. + */ void setup() { for( const std::shared_ptr &ptr : mapgens_ ) { const int weight = ptr->weight; @@ -256,6 +261,7 @@ class mapgen_factory private: std::map mapgens_; + /// Collect all the possible and expected keys that may get used with @ref pick. static std::set get_usages() { std::set result; for( const oter_t &elem : overmap_terrains::get_all() ) { @@ -279,6 +285,7 @@ class mapgen_factory void reset() { mapgens_.clear(); } + /// @see mapgen_basic_container::setup void setup() { for( std::pair &omw : mapgens_ ) { omw.second.setup(); @@ -295,13 +302,19 @@ class mapgen_factory } } } + /** + * Checks whether we have an entry for the given key. + * Note that the entry itself may not contain any valid mapgen instance + * (could all have been removed via @ref erase). + */ bool has( const std::string &key ) const { return mapgens_.count( key ) != 0; } + /// @see mapgen_basic_container::add int add( const std::string &key, const std::shared_ptr ptr ) { return mapgens_[key].add( ptr ); } - // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. + /// @see mapgen_basic_container::pick mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { const auto iter = mapgens_.find( key ); if( iter == mapgens_.end() ) { @@ -309,6 +322,7 @@ class mapgen_factory } return iter->second.pick( hardcoded_weight ); } + /// @see mapgen_basic_container::erase void erase( const std::string &key, const size_t index ) { mapgens_[key].erase( index ); } From 22dc435c6b1e3fcf71cac08a83bcab2b10d131d0 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 00:11:30 +0100 Subject: [PATCH 093/219] Encapsulate the `mapgen_function` function pointers within `mapgen_factory` Don't expose them at all. All access to them is done internally. --- src/mapgen.cpp | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 875baedce8742..50f5d719d9a7c 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -216,21 +216,26 @@ class mapgen_basic_container mapgens_[index]->weight = 0; } /** - * Pick a mapgen function randomly. + * Pick a mapgen function randomly and call its generate function. + * This basically runs the mapgen functions with the given @ref mapgendata + * as argument. + * @return Whether the mapgen function has been run. It may not get run if + * the list of mapgen functions is effectively empty. * @p hardcoded_weight Weight for an additional entry. If that entry is chosen, - * a null pointer is returned. If unsure, just use 0 for it. + * false is returned. If unsure, just use 0 for it. */ - mapgen_function *pick( const int hardcoded_weight ) const { + bool generate( mapgendata &dat, const int hardcoded_weight ) const { if( hardcoded_weight > 0 && rng( 1, weights_.get_weight() + hardcoded_weight ) > weights_.get_weight() ) { - return nullptr; + return false; } const std::shared_ptr *const ptr = weights_.pick(); if( !ptr ) { - return nullptr; + return false; } assert( *ptr ); - return ptr->get(); + ( *ptr )->generate( dat ); + return true; } /** * Calls @ref mapgen_function::setup and sets up the internal weighted list using @@ -274,7 +279,7 @@ class mapgen_factory result.insert( elem.generator_id ); } } - // Used in C++ code only, see calls to `oter_mapgen.pick()` below + // Used in C++ code only, see calls to `oter_mapgen.generate()` below result.insert( "lab_1side" ); result.insert( "lab_4side" ); result.insert( "lab_finale_1level" ); @@ -314,13 +319,13 @@ class mapgen_factory int add( const std::string &key, const std::shared_ptr ptr ) { return mapgens_[key].add( ptr ); } - /// @see mapgen_basic_container::pick - mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { + /// @see mapgen_basic_container::generate + bool generate( mapgendata &dat, const std::string &key, const int hardcoded_weight = 0 ) const { const auto iter = mapgens_.find( key ); if( iter == mapgens_.end() ) { - return nullptr; + return false; } - return iter->second.pick( hardcoded_weight ); + return iter->second.generate( dat, hardcoded_weight ); } /// @see mapgen_basic_container::erase void erase( const std::string &key, const size_t index ) { @@ -3577,8 +3582,7 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { // If you remove the usage of "lab_1side" here, remove it from mapgen_factory::get_usages above as well. - if( const auto ptr = oter_mapgen.pick( "lab_1side" ) ) { - ptr->generate( dat ); + if( oter_mapgen.generate( dat, "lab_1side" ) ) { if( tw == 2 ) { rotate( 2 ); } @@ -3596,8 +3600,7 @@ void map::draw_lab( mapgendata &dat ) } else { const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. // If you remove the usage of "lab_4side" here, remove it from mapgen_factory::get_usages above as well. - if( const auto ptr = oter_mapgen.pick( "lab_4side", hardcoded_4side_map_weight ) ) { - ptr->generate( dat ); + if( oter_mapgen.generate( dat, "lab_4side", hardcoded_4side_map_weight ) ) { // If the map template hasn't handled borders, handle them in code. // Rotated maps cannot handle borders and have to be caught in code. // We determine if a border isn't handled by checking the east-facing @@ -4142,9 +4145,7 @@ void map::draw_lab( mapgendata &dat ) const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. // If you remove the usage of "lab_finale_1level" here, remove it from mapgen_factory::get_usages above as well. - if( const auto ptr = oter_mapgen.pick( "lab_finale_1level", hardcoded_finale_map_weight ) ) { - ptr->generate( dat ); - + if( oter_mapgen.generate( dat, "lab_finale_1level", hardcoded_finale_map_weight ) ) { // If the map template hasn't handled borders, handle them in code. // Rotated maps cannot handle borders and have to be caught in code. // We determine if a border isn't handled by checking the east-facing @@ -7359,11 +7360,7 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - if( const auto ptr = oter_mapgen.pick( mapgen_id ) ) { - ptr->generate( dat ); - return true; - } - return false; + return oter_mapgen.generate( dat, mapgen_id ); } int register_mapgen_function( const std::string &key ) From 6b2e56c11c80a3d956d51227174e5c3e4786d41e Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 11:32:24 +0100 Subject: [PATCH 094/219] Remove mapgen entries for overmap terrain "null". This terrain should never appears and is therefor never generated. Removing it here may free up some memory. --- src/mapgen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 50f5d719d9a7c..b2a95e240a090 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -295,6 +295,8 @@ class mapgen_factory for( std::pair &omw : mapgens_ ) { omw.second.setup(); } + // Dummy entry, overmap terrain null should never appear and is therefor never generated. + mapgens_.erase( "null" ); } void check_consistency() { // Cache all strings that may get looked up here so we don't have to go through From 3bad29635d391c2bf74a0a17fc17461c440bfef8 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 14:37:43 +0100 Subject: [PATCH 095/219] Follow recommendation of clang-tidy --- src/mapgen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index b2a95e240a090..3b2b9f24fd20e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -437,7 +437,7 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, ret = std::make_shared( jstr, mgweight, offset ); oter_mapgen.add( id_base, ret ); } else { - jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); + jio.throw_error( R"(invalid value: must be "builtin" or "json")", "method" ); } return ret; } From eca8787c80bb635b79c59083d1abc83bf8670223 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 15:58:30 +0100 Subject: [PATCH 096/219] Make parameter offset of load_mapgen_function mandatory. Adds the default value to all calls to it that did not supply a value. --- src/mapgen.cpp | 4 ++-- src/mapgen.h | 2 +- src/overmap.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 3b2b9f24fd20e..dc8ab33768038 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -506,7 +506,7 @@ void load_mapgen( const JsonObject &jo ) } if( !mapgenid_list.empty() ) { const std::string mapgenid = mapgenid_list[0]; - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, point_zero ); if( mgfunc ) { for( auto &i : mapgenid_list ) { oter_mapgen.add( i, mgfunc ); @@ -515,7 +515,7 @@ void load_mapgen( const JsonObject &jo ) } } } else if( jo.has_string( "om_terrain" ) ) { - load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1 ); + load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1, point_zero ); } else if( jo.has_string( "nested_mapgen_id" ) ) { load_nested_mapgen( jo, jo.get_string( "nested_mapgen_id" ) ); } else if( jo.has_string( "update_mapgen_id" ) ) { diff --git a/src/mapgen.h b/src/mapgen.h index ec114176152df..a73284aeead6e 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -371,7 +371,7 @@ class mapgen_function_json_nested : public mapgen_function_json_base * Load mapgen function of any type from a json object */ std::shared_ptr load_mapgen_function( const JsonObject &jio, - const std::string &id_base, int default_idx, const point &offset = point_zero ); + const std::string &id_base, int default_idx, const point &offset ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) diff --git a/src/overmap.cpp b/src/overmap.cpp index fd577a0639c84..ab859a3634d8e 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -534,7 +534,7 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin } if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { - load_mapgen_function( jio, fmapkey, default_idx ); + load_mapgen_function( jio, fmapkey, default_idx, point_zero ); } } } From 2071f2180ba1a57ae71dc2b01dc70ba315b53996 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 16:33:53 +0100 Subject: [PATCH 097/219] Remove default_idx parameter from load_mapgen_function. This feature is not available anymore. It was added by 04e45eabbdd80a238e61c771fcf0c05073b5ca54 without any explanation. --- src/mapgen.cpp | 30 ++++-------------------------- src/mapgen.h | 2 +- src/overmap.cpp | 8 ++------ 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index dc8ab33768038..c132880807012 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -207,14 +207,6 @@ class mapgen_basic_container mapgens_.push_back( ptr ); return mapgens_.size() - 1; } - void erase( const size_t index ) { - if( index > mapgens_.size() ) { - return; - } - assert( mapgens_[index] ); - // Can't actually erase it as this might invalid the index stored elsewhere - mapgens_[index]->weight = 0; - } /** * Pick a mapgen function randomly and call its generate function. * This basically runs the mapgen functions with the given @ref mapgendata @@ -329,10 +321,6 @@ class mapgen_factory } return iter->second.generate( dat, hardcoded_weight ); } - /// @see mapgen_basic_container::erase - void erase( const std::string &key, const size_t index ) { - mapgens_[key].erase( index ); - } }; static mapgen_factory oter_mapgen; @@ -406,21 +394,11 @@ static void set_mapgen_defer( const JsonObject &jsi, const std::string &member, * load a single mapgen json structure; this can be inside an overmap_terrain, or on it's own. */ std::shared_ptr -load_mapgen_function( const JsonObject &jio, const std::string &id_base, - int default_idx, const point &offset ) +load_mapgen_function( const JsonObject &jio, const std::string &id_base, const point &offset ) { int mgweight = jio.get_int( "weight", 1000 ); std::shared_ptr ret; if( mgweight <= 0 || jio.get_bool( "disabled", false ) ) { - const std::string mgtype = jio.get_string( "method" ); - if( default_idx != -1 && mgtype == "builtin" ) { - if( jio.has_string( "name" ) ) { - const std::string mgname = jio.get_string( "name" ); - if( mgname == id_base ) { - oter_mapgen.erase( id_base, default_idx ); - } - } - } jio.allow_omitted_members(); return nullptr; // nothing } @@ -490,7 +468,7 @@ void load_mapgen( const JsonObject &jo ) point offset; for( JsonArray row_items : ja ) { for( const std::string mapgenid : row_items ) { - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, offset ); if( mgfunc ) { oter_mapgen.add( mapgenid, mgfunc ); } @@ -506,7 +484,7 @@ void load_mapgen( const JsonObject &jo ) } if( !mapgenid_list.empty() ) { const std::string mapgenid = mapgenid_list[0]; - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, point_zero ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, point_zero ); if( mgfunc ) { for( auto &i : mapgenid_list ) { oter_mapgen.add( i, mgfunc ); @@ -515,7 +493,7 @@ void load_mapgen( const JsonObject &jo ) } } } else if( jo.has_string( "om_terrain" ) ) { - load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1, point_zero ); + load_mapgen_function( jo, jo.get_string( "om_terrain" ), point_zero ); } else if( jo.has_string( "nested_mapgen_id" ) ) { load_nested_mapgen( jo, jo.get_string( "nested_mapgen_id" ) ); } else if( jo.has_string( "update_mapgen_id" ) ) { diff --git a/src/mapgen.h b/src/mapgen.h index a73284aeead6e..8e051518b3673 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -371,7 +371,7 @@ class mapgen_function_json_nested : public mapgen_function_json_base * Load mapgen function of any type from a json object */ std::shared_ptr load_mapgen_function( const JsonObject &jio, - const std::string &id_base, int default_idx, const point &offset ); + const std::string &id_base, const point &offset ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) diff --git a/src/overmap.cpp b/src/overmap.cpp index ab859a3634d8e..73985f240d792 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -527,14 +527,10 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin { const std::string fmapkey( id_base + suffix ); const std::string jsonkey( "mapgen" + suffix ); - bool default_mapgen = jo.get_bool( "default_mapgen", true ); - int default_idx = -1; - if( default_mapgen ) { - default_idx = register_mapgen_function( fmapkey ); - } + register_mapgen_function( fmapkey ); if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { - load_mapgen_function( jio, fmapkey, default_idx, point_zero ); + load_mapgen_function( jio, fmapkey, point_zero ); } } } From 89411b6e54a8f98d7d2522d5b9f1889f39bc07df Mon Sep 17 00:00:00 2001 From: BevapDin Date: Tue, 10 Mar 2020 07:43:24 +0100 Subject: [PATCH 098/219] Refactor loading bonuses (#36562) --- data/json/martialarts.json | 189 ++++++---- data/json/martialarts_fictional.json | 103 ++++-- data/json/techniques.json | 323 ++++++++++++------ data/mods/Aftershock/player/techniques.json | 2 +- .../CRT_EXPANSION/martial/CRT_Bladework.json | 43 ++- .../martial/CRT_EnforcementBuff.json | 60 +++- .../CRT_EXPANSION/martial/CRT_MeleeBuffs.json | 97 ++++-- .../martial/crt_gun_techniques.json | 24 +- .../martial/dragonslayertechn.json | 47 ++- .../CRT_EXPANSION/martial/generaltechn.json | 93 +++-- .../mods/CRT_EXPANSION/martial/stabtechn.json | 30 +- data/mods/MMA/martialarts.json | 9 +- data/mods/MMA/techniques.json | 20 +- doc/JSON_INFO.md | 1 - doc/MARTIALART_JSON.md | 48 +-- src/bonuses.cpp | 46 +-- src/bonuses.h | 5 +- 17 files changed, 773 insertions(+), 367 deletions(-) diff --git a/data/json/martialarts.json b/data/json/martialarts.json index 5bdb0fa1cb50c..ffcecc7f36d5a 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -33,7 +33,7 @@ "name": "Aikido Stance", "description": "By disregarding offensive in favor of self-defense, you are better at protecting.\n\nBlocked damage reduced by 100%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "dex", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "dex", "scale": 1.0 } ] }, { "id": "buff_aikido_static2", @@ -43,7 +43,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "bonus_dodges": 1, "bonus_blocks": 1, - "flat_bonuses": [ [ "block", "dex", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "dex", "scale": 1.0 } ] }, { "id": "buff_aikido_static3", @@ -78,7 +78,7 @@ "name": "Boxing Stance", "description": "A solid stance allows you block more damage than normal and deliver better punches.\n\n+2 Bash damage, Blocked damge reduced by 50%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "str", 0.5 ], [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onmove_buffs": [ @@ -90,7 +90,7 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 2, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -101,7 +101,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] } ], "techniques": [ "tec_boxing_rapid", "tec_boxing_cross", "tec_boxing_upper", "tec_boxing_counter" ] @@ -143,7 +143,7 @@ "description": "You never stop moving while performing the ginga. This makes you very mobile while fighting.\n\n+1.0 Dodge skill, +1 Dodge attempts.", "unarmed_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -155,7 +155,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 2, "max_stacks": 3, - "mult_bonuses": [ [ "damage", "bash", 1.15 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.15 } ] } ], "onmove_buffs": [ @@ -166,7 +166,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 3, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "techniques": [ @@ -191,7 +191,10 @@ "name": "Crane's Precision", "description": "Your attacks strike at your opponents weakness with speed and precision instead of brute force.\nDexterity increases melee damage instead of Strength.\n\nBash damage increased by 75%% of Dexterity but decreased by 75%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "damage", "bash", "dex", 0.75 ], [ "damage", "bash", "str", -0.75 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "dex", "scale": 0.75 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": -0.75 } + ] } ], "onmove_buffs": [ @@ -202,7 +205,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 2, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -214,7 +217,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 2, "bonus_dodges": 1, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "techniques": [ "tec_crane_feint", "tec_crane_break", "tec_crane_counter", "tec_crane_precise" ] @@ -233,7 +236,7 @@ "name": "Dragon's Knowledge", "description": "You plan your attack far in advance relying on your intuition instead of your speed to strike true.\nIntelligence increases Accuracy instead of Dexterity.\n\nAccuracy increased by 25%% of Intelligence but decreased by 25%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", "int", 0.25 ], [ "hit", "dex", -0.25 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "int", "scale": 0.25 }, { "stat": "hit", "scaling-stat": "dex", "scale": -0.25 } ] } ], "onhit_buffs": [ @@ -244,7 +247,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 1, - "flat_bonuses": [ [ "hit", 1.0 ], [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ "tec_dragon_claw", "tec_dragon_blockcounter", "tec_dragon_dodgecounter", "tec_dragon_tail", "tec_dragon_strike" ] @@ -264,7 +267,7 @@ "name": "Eskrima Stance", "description": "You are skilled at getting the most out of your weapons. The term 'weapon' might be very subjective,\n\n+2 Accuracy.", "melee_allowed": true, - "flat_bonuses": [ [ "hit", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 } ] } ], "oncrit_buffs": [ @@ -276,7 +279,11 @@ "melee_allowed": true, "buff_duration": 3, "max_stacks": 3, - "mult_bonuses": [ [ "damage", "bash", 1.15 ], [ "damage", "cut", 1.15 ], [ "damage", "stab", 1.15 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.15 }, + { "stat": "damage", "type": "cut", "scale": 1.15 }, + { "stat": "damage", "type": "stab", "scale": 1.15 } + ] } ], "techniques": [ @@ -354,7 +361,7 @@ "name": "Fencing Stance", "description": "Your side stance minimizes the chances you will be harmed in a combat.\n\nBlocked damage reduced by 50%% of Dexterity.", "melee_allowed": true, - "flat_bonuses": [ [ "block", "dex", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "dex", "scale": 0.5 } ] } ], "onblock_buffs": [ @@ -365,7 +372,7 @@ "skill_requirements": [ { "name": "melee", "level": 1 } ], "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -376,7 +383,7 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "techniques": [ "tec_fencing_feint", "tec_fencing_lunge", "tec_fencing_riposte", "tec_fencing_compound" ], @@ -427,7 +434,7 @@ "description": "You are stalwart and will not budge against any threat.\n\n+2 Block attempts, -1.0 Dodge skill, blocked damage reduced by 50%% of Strength.", "melee_allowed": true, "bonus_blocks": 2, - "flat_bonuses": [ [ "block", "str", 0.5 ], [ "dodge", -1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 }, { "stat": "dodge", "scale": -1.0 } ] } ], "onmove_buffs": [ @@ -438,7 +445,7 @@ "melee_allowed": true, "buff_duration": 1, "bonus_blocks": -2, - "flat_bonuses": [ [ "block", "str", -0.5 ], [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": -0.5 }, { "stat": "dodge", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -460,7 +467,7 @@ "skill_requirements": [ { "name": "melee", "level": 1 } ], "buff_duration": 1, "max_stacks": 3, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "techniques": [ @@ -529,7 +536,7 @@ "name": "Karate Stance", "description": "Your no nonsense stance allows you hit more accurately.\n\n+2 Accuracy.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 } ] } ], "onhit_buffs": [ @@ -542,7 +549,7 @@ "buff_duration": 2, "bonus_blocks": 2, "bonus_dodges": 1, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] } ], "techniques": [ "tec_karate_rapid", "tec_karate_precise", "tec_karate_roundhouse", "tec_karate_counter" ] @@ -564,7 +571,7 @@ "melee_allowed": true, "unarmed_allowed": true, "bonus_blocks": 1, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "techniques": [ @@ -645,7 +652,10 @@ "name": "Leopard's Strategy", "description": "You fight by overwhelming your opponents with speedy strikes that are much harder to defend against.\nDexterity increases melee damage instead of Strength.\n\nBash damage increased by 75%% of Dexterity but decreased by 75%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "damage", "bash", "dex", 0.75 ], [ "damage", "bash", "str", -0.75 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "dex", "scale": 0.75 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": -0.75 } + ] }, { "id": "buff_leopard_static2", @@ -653,7 +663,7 @@ "description": "Just like a cat, you are quick, agile, and hard to pin down.\n\n+1.0 Dodge skill.", "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "onmove_buffs": [ @@ -664,7 +674,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "hit", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 } ] }, { "id": "buff_leopard_onmove2", @@ -674,7 +684,11 @@ "unarmed_allowed": true, "req_buffs": [ "buff_leopard_onmove1" ], "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.25 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.25 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ] } ], "techniques": [ "tec_leopard_rapid", "tec_leopard_feint", "tec_leopard_counter", "tec_leopard_precise" ] @@ -695,7 +709,7 @@ "description": "Through chivalry and vigilance, your defense with a blade has increased.\n\n+1 Dodge attempts, blocked damage decreased by 50%% of Strength.", "melee_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] } ], "onblock_buffs": [ @@ -761,7 +775,7 @@ "name": "Muay Thai Stance", "description": "Strength is everything in Muay Thai and you know how to make the most of yours.\n\nBlocked damage decreased by 50%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] } ], "ongethit_buffs": [ @@ -772,7 +786,10 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "buff_duration": 5, - "flat_bonuses": [ [ "damage", "bash", "str", 0.25 ], [ "block", "str", 0.5 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "block", "scaling-stat": "str", "scale": 0.5 } + ] } ], "techniques": [ "tec_muay_thai_elbow", "tec_muay_thai_kick", "tec_muay_thai_knee", "tec_muay_thai_break" ] @@ -801,7 +818,11 @@ "description": "To a true shinobi, the first strike and the last strike are one in the same.\n\n+50%% all damage.", "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] } ], "onattack_buffs": [ @@ -812,7 +833,11 @@ "unarmed_allowed": true, "melee_allowed": true, "buff_duration": 3, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] } ], "onmove_buffs": [ @@ -824,7 +849,7 @@ "unarmed_allowed": true, "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "dodge", 1.0 ], [ "hit", "dex", 0.2 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 }, { "stat": "hit", "scaling-stat": "dex", "scale": 0.2 } ] } ], "onkill_buffs": [ @@ -837,7 +862,7 @@ "melee_allowed": true, "buff_duration": 3, "bonus_dodges": 2, - "flat_bonuses": [ [ "speed", 10.0 ] ] + "flat_bonuses": [ { "stat": "speed", "scale": 10.0 } ] } ], "techniques": [ "tec_ninjutsu_swift", "tec_ninjutsu_takedown", "tec_ninjutsu_precise" ], @@ -927,7 +952,11 @@ "name": "Niten Ichi-Ryu Stance", "description": "Cautious watchful eyes\nmeasure and display your skill.\nPractice makes perfect.\n\nBash and Cut armor penetration increased by 50%% of Perception, blocked damage reduced by 100%% of Perception.", "melee_allowed": true, - "flat_bonuses": [ [ "arpen", "cut", "per", 0.5 ], [ "arpen", "bash", "per", 0.5 ], [ "block", "per", 1.0 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "cut", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "block", "scaling-stat": "per", "scale": 1.0 } + ] } ], "onmove_buffs": [ @@ -937,7 +966,7 @@ "description": "Blackened like darkness,\nnightmares approach from all sides.\nFlee at any cost!\n\n-5.0 Dodge skill.\nLasts 1 turn.", "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "dodge", -5.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": -5.0 } ] } ], "onattack_buffs": [ @@ -948,7 +977,11 @@ "melee_allowed": true, "buff_duration": 1, "max_stacks": 5, - "flat_bonuses": [ [ "dodge", -1.0 ], [ "damage", "cut", -1.0 ], [ "damage", "bash", -1.0 ] ] + "flat_bonuses": [ + { "stat": "dodge", "scale": -1.0 }, + { "stat": "damage", "type": "cut", "scale": -1.0 }, + { "stat": "damage", "type": "bash", "scale": -1.0 } + ] } ], "ondodge_buffs": [ @@ -968,7 +1001,7 @@ "description": "The eye of the storm,\na fleeting moment of peace,\ngone without a trace.\n\n+2 Accuracy, Dodge skill increased by 50%% of Perception.\nLasts 2 turns.", "melee_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "hit", 2.0 ], [ "dodge", "per", 0.5 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 }, { "stat": "dodge", "scaling-stat": "per", "scale": 0.5 } ] } ], "techniques": [ "niten_water_cut", "niten_red_leaf", "niten_stone_cut", "niten_timing_attack", "niten_feint" ], @@ -1007,7 +1040,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.1 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 } ] } ], "onhit_buffs": [ @@ -1019,7 +1052,7 @@ "unarmed_allowed": true, "req_buffs": [ "buff_pankration_ondodge" ], "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] } ], "techniques": [ @@ -1058,7 +1091,7 @@ "melee_allowed": true, "buff_duration": 2, "max_stacks": 3, - "flat_bonuses": [ [ "hit", "dex", 0.15 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "dex", "scale": 0.15 } ] } ], "onmove_buffs": [ @@ -1155,7 +1188,7 @@ "name": "Snake's Sight", "description": "You are patient and know where to hit your opponent for the best results.\n\nPerception increases Accuracy instead of Dexterity. Accuracy increased by 25%% of Perception but decreased by 25%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", "per", 0.25 ], [ "hit", "dex", -0.25 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "per", "scale": 0.25 }, { "stat": "hit", "scaling-stat": "dex", "scale": -0.25 } ] } ], "onpause_buffs": [ @@ -1167,7 +1200,12 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 3, - "flat_bonuses": [ [ "hit", 1.0 ], [ "arpen", "bash", "per", 0.5 ], [ "arpen", "cut", "per", 0.5 ], [ "arpen", "stab", "per", 0.5 ] ] + "flat_bonuses": [ + { "stat": "hit", "scale": 1.0 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "per", "scale": 0.5 } + ] } ], "techniques": [ "tec_snake_rapid", "tec_snake_feint", "tec_snake_break", "tec_snake_precise" ] @@ -1198,7 +1236,11 @@ "melee_allowed": true, "buff_duration": 1, "bonus_blocks": -1, - "mult_bonuses": [ [ "damage", "bash", 1.1 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.1 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ] } ], "techniques": [ "tec_sojutsu_push", "tec_sojutsu_shove", "tec_sojutsu_trip" ], @@ -1247,14 +1289,14 @@ "name": "Taekwondo Stance", "description": "Using your legs to attack allows your hands to be free for better defense.\n\nBlocked damage decreased by 50%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] }, { "id": "buff_taekwondo_static2", "name": "Unhindered", "description": "Your attacks are stronger if you are not holding anything in your hands.\n\n+33%% bash damage when not using a weapon.", "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.33 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 } ] } ], "techniques": [ @@ -1281,7 +1323,7 @@ "description": "You are focused of defense and predicting your opponents attacks.\n\n+1 Block attempts, blocked damage reduced by 100%% Perception.", "unarmed_allowed": true, "bonus_blocks": 1, - "flat_bonuses": [ [ "block", "per", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "per", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -1292,7 +1334,10 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "buff_duration": 2, - "flat_bonuses": [ [ "arpen", "bash", "per", 0.5 ], [ "hit", "per", 0.2 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "hit", "scaling-stat": "per", "scale": 0.2 } + ] } ], "onpause_buffs": [ @@ -1303,7 +1348,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 3, - "flat_bonuses": [ [ "block", "per", 0.5 ], [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "per", "scale": 0.5 }, { "stat": "dodge", "scale": 1.0 } ] } ], "techniques": [ "tec_taichi_disarm", "tec_taichi_palm", "tec_taichi_counter", "tec_taichi_precise" ] @@ -1321,7 +1366,7 @@ "name": "Tiger's Strength", "description": "You do not need defense. You do not need a plan. You need strength. Strength will break your opponents' defenses and overwhelm them completely.\nStrength increases Accuracy instead of Dexterity.\n\nAccuracy increased by 25%% of Strength but decreased by 25%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", "str", 0.25 ], [ "hit", "dex", -0.25 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "str", "scale": 0.25 }, { "stat": "hit", "scaling-stat": "dex", "scale": -0.25 } ] } ], "onhit_buffs": [ @@ -1333,7 +1378,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 3, "max_stacks": 4, - "mult_bonuses": [ [ "damage", "bash", 1.1 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.1 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ] } ], "oncrit_buffs": [ @@ -1345,7 +1394,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "buff_duration": 1, "max_stacks": 2, - "flat_bonuses": [ [ "arpen", "bash", "str", 0.5 ], [ "arpen", "cut", "str", 0.5 ], [ "arpen", "stab", "str", 0.5 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "str", "scale": 0.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "str", "scale": 0.5 } + ] } ], "techniques": [ "tec_tiger_palm", "tec_tiger_takedown" ] @@ -1368,7 +1421,7 @@ "name": "Chi-Sao Sensitivity", "description": "You have a greater understanding of balance and technique. This gives you a better chance to avoid your opponent's attacks.\n\n Dodging Skill increased by 15%% of Perception. Blocked damage reduced by 50%% of Perception.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "per", 0.5 ], [ "dodge", "per", 0.15 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "per", "scale": 0.5 }, { "stat": "dodge", "scaling-stat": "per", "scale": 0.15 } ] } ], "onhit_buffs": [ @@ -1380,7 +1433,7 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 3, - "mult_bonuses": [ [ "movecost", 0.9 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.9 } ] } ], "onpause_buffs": [ @@ -1391,7 +1444,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "hit", "per", 0.2 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "per", "scale": 0.2 } ] } ], "techniques": [ @@ -1416,7 +1469,7 @@ "name": "Zui Quan Stance", "description": "Others might think you stumble about at random but you know better. Each movement is calculated to make evading harm easier.\n\nDodging Skill increased by 15%% of Intelligence.", "unarmed_allowed": true, - "flat_bonuses": [ [ "dodge", "int", 0.15 ] ] + "flat_bonuses": [ { "stat": "dodge", "scaling-stat": "int", "scale": 0.15 } ] }, { "id": "buff_zuiquan_static2", @@ -1425,7 +1478,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "hit", "int", 0.15 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "int", "scale": 0.15 } ] } ], "onmove_buffs": [ @@ -1448,7 +1501,11 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 4, - "flat_bonuses": [ [ "arpen", "bash", "int", 0.25 ], [ "arpen", "cut", "int", 0.25 ], [ "arpen", "stab", "int", 0.25 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "int", "scale": 0.25 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "int", "scale": 0.25 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "int", "scale": 0.25 } + ] } ], "techniques": [ "tec_zuiquan_feint", "tec_zuiquan_break", "tec_zuiquan_counter" ] @@ -1468,10 +1525,10 @@ "description": "+Strength bash armor, +Dexterity acid armor, +Intelligence electricity armor, +Perception fire armor.", "unarmed_allowed": true, "flat_bonuses": [ - [ "armor", "bash", "str", 1.0 ], - [ "armor", "cut", "dex", 1.0 ], - [ "armor", "electric", "int", 1.0 ], - [ "armor", "heat", "per", 1.0 ] + { "stat": "armor", "type": "bash", "scaling-stat": "str", "scale": 1.0 }, + { "stat": "armor", "type": "cut", "scaling-stat": "dex", "scale": 1.0 }, + { "stat": "armor", "type": "electric", "scaling-stat": "int", "scale": 1.0 }, + { "stat": "armor", "type": "heat", "scaling-stat": "per", "scale": 1.0 } ] } ], @@ -1483,7 +1540,7 @@ "unarmed_allowed": true, "buff_duration": 3, "max_stacks": 2, - "flat_bonuses": [ [ "damage", "electric", "per", 1.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "electric", "scaling-stat": "per", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -1494,7 +1551,7 @@ "unarmed_allowed": true, "buff_duration": 2, "max_stacks": 5, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onkill_buffs": [ @@ -1504,7 +1561,7 @@ "description": "YOU ARE ON FIRE! +5 fire damage for 5 turns.", "unarmed_allowed": true, "buff_duration": 5, - "flat_bonuses": [ [ "damage", "heat", 5.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "heat", "scale": 5.0 } ] } ], "techniques": [ "tec_debug_slow", "tec_debug_arpen" ] diff --git a/data/json/martialarts_fictional.json b/data/json/martialarts_fictional.json index a03362af6ac57..7c9bfac7a873c 100644 --- a/data/json/martialarts_fictional.json +++ b/data/json/martialarts_fictional.json @@ -18,7 +18,7 @@ "unarmed_allowed": true, "melee_allowed": true, "bonus_blocks": 2, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "onkill_buffs": [ @@ -31,7 +31,12 @@ "skill_requirements": [ { "name": "melee", "level": 4 } ], "buff_duration": 3, "max_stacks": 3, - "flat_bonuses": [ [ "damage", "bash", 2.0 ], [ "damage", "cut", 2.0 ], [ "damage", "stab", 2.0 ], [ "hit", 1.0 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 2.0 }, + { "stat": "damage", "type": "cut", "scale": 2.0 }, + { "stat": "damage", "type": "stab", "scale": 2.0 }, + { "stat": "hit", "scale": 1.0 } + ] } ], "techniques": [ @@ -63,7 +68,7 @@ "unarmed_allowed": true, "buff_duration": 3, "max_stacks": 4, - "flat_bonuses": [ [ "movecost", -4.0 ] ] + "flat_bonuses": [ { "stat": "movecost", "scale": -4.0 } ] } ], "oncrit_buffs": [ @@ -74,7 +79,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ "tec_centipede_rapid", "tec_centipede_break", "tec_centipede_bite", "tec_centipede_disarm" ] @@ -94,7 +99,7 @@ "description": "By briefly scaling, leaping, or pushing off a nearby wall, you can avoid the worst of your opponents attacks.\n\n+3.0 Dodge skill when near a wall.\nEnables \"Lizard Tail\" and \"Lizard Wall Counter\" techniques when near a wall.", "unarmed_allowed": true, "wall_adjacent": true, - "flat_bonuses": [ [ "dodge", 3.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 3.0 } ] } ], "onhit_buffs": [ @@ -105,7 +110,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "buff_duration": 4, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onmove_buffs": [ @@ -116,7 +121,7 @@ "unarmed_allowed": true, "wall_adjacent": true, "buff_duration": 3, - "flat_bonuses": [ [ "hit", 3.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 3.0 } ] } ], "techniques": [ "tec_lizard_strike", "tec_lizard_break", "tec_lizard_wallcounter", "tec_lizard_counter", "tec_lizard_tail" ] @@ -135,7 +140,7 @@ "name": "Scorpion's Venom", "description": "Your venom is a constant threat that nothing can escape from.\n\n+2 bashing damage.", "unarmed_allowed": true, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onattack_buffs": [ @@ -158,7 +163,11 @@ "unarmed_allowed": true, "buff_duration": 2, "max_stacks": 2, - "mult_bonuses": [ [ "damage", "bash", 1.1 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.1 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ] } ], "techniques": [ "tec_scorpion_roundhouse", "tec_scorpion_precise", "tec_scorpion_brutal" ] @@ -178,7 +187,11 @@ "description": "Your body is as strong as iron but only if you don't move.\n\n+6 bash, cut, and stab armor.", "//": "FWIW, this is twice the amount of armor provided by bionic plating.", "unarmed_allowed": true, - "flat_bonuses": [ [ "armor", "bash", 6.0 ], [ "armor", "cut", 6.0 ], [ "armor", "stab", 6.0 ] ] + "flat_bonuses": [ + { "stat": "armor", "type": "bash", "scale": 6.0 }, + { "stat": "armor", "type": "cut", "scale": 6.0 }, + { "stat": "armor", "type": "stab", "scale": 6.0 } + ] } ], "onmove_buffs": [ @@ -189,7 +202,11 @@ "unarmed_allowed": true, "buff_duration": 6, "max_stacks": 6, - "flat_bonuses": [ [ "armor", "bash", -1.0 ], [ "armor", "cut", -1.0 ], [ "armor", "stab", -1.0 ] ] + "flat_bonuses": [ + { "stat": "armor", "type": "bash", "scale": -1.0 }, + { "stat": "armor", "type": "cut", "scale": -1.0 }, + { "stat": "armor", "type": "stab", "scale": -1.0 } + ] } ], "onpause_buffs": [ @@ -200,7 +217,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "armor", "bash", 3.0 ], [ "armor", "cut", 3.0 ], [ "armor", "stab", 3.0 ] ] + "flat_bonuses": [ + { "stat": "armor", "type": "bash", "scale": 3.0 }, + { "stat": "armor", "type": "cut", "scale": 3.0 }, + { "stat": "armor", "type": "stab", "scale": 3.0 } + ] } ], "ongethit_buffs": [ @@ -211,7 +232,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "buff_duration": 5, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ "tec_toad_counter", "tec_toad_critcounter", "tec_toad_grab" ] @@ -230,7 +251,7 @@ "name": "Viper's Patience", "description": "Every snake waits for the perfect moment to strike. Turn your opponents' mistakes into your opportunity to strike!\n\n+1.0 Dodge skill.", "unarmed_allowed": true, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -249,7 +270,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 3, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ @@ -280,7 +301,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -299,7 +320,7 @@ "name": "Measured Strike (melee)", "messages": [ "You make an efficient strike against %s", " makes an efficient strike against %s" ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -309,7 +330,7 @@ "unarmed_allowed": true, "unarmed_weapons_allowed": false, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -319,7 +340,11 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ], "stun_dur": 1 }, { @@ -353,7 +378,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -365,7 +390,7 @@ "wall_adjacent": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -391,7 +416,7 @@ "weighting": 2, "knockback_dist": 1, "knockback_spread": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -402,7 +427,7 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -421,7 +446,12 @@ "name": "Viper Fist", "messages": [ "You quickly chop %s", " quickly chops %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -433,7 +463,7 @@ "req_buffs": [ "buff_venom_snake_ondodge1" ], "crit_tec": true, "stun_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 1.33 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 } ] }, { "type": "technique", @@ -445,7 +475,7 @@ "stunned_target": true, "weighting": 2, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -464,7 +494,7 @@ "name": "Roundhouse Kick", "messages": [ "You roundhouse kick %s", " roundhouse kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -476,7 +506,7 @@ "stun_dur": 2, "knockback_dist": 3, "powerful_knockback": true, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ], "messages": [ "Your Stinger Kick sends %s flying", "'s Stinger Kick sends %s flying" ] }, { @@ -488,7 +518,7 @@ "unarmed_allowed": true, "req_buffs": [ "buff_scorpion_onmove" ], "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -499,7 +529,7 @@ "unarmed_allowed": true, "block_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -511,7 +541,7 @@ "block_counter": true, "crit_tec": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -522,7 +552,7 @@ "unarmed_allowed": true, "crit_ok": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -540,7 +570,12 @@ "name": "Centipede Strike", "messages": [ "You swiftly hit %s", " swiftly hits %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -551,7 +586,7 @@ "unarmed_allowed": true, "crit_tec": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", diff --git a/data/json/techniques.json b/data/json/techniques.json index a0feab2636216..b9c99e8a0d397 100644 --- a/data/json/techniques.json +++ b/data/json/techniques.json @@ -10,7 +10,7 @@ "id": "WBLOCK_1", "name": "Block", "dummy": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You block %s", " blocks %s" ], "description": "Medium blocking ability" }, @@ -19,7 +19,7 @@ "id": "WBLOCK_2", "name": "Parry", "dummy": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You parry %s", " parries %s" ], "description": "High blocking ability" }, @@ -28,7 +28,7 @@ "id": "WBLOCK_3", "name": "Shield", "dummy": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You shield against %s", " shields against %s" ], "description": "Very high blocking ability" }, @@ -101,7 +101,12 @@ "name": "Rapid Strike", "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ], "messages": [ "You quickly strike %s", " quickly strikes %s" ], "description": "50% moves, 66% damage" }, @@ -111,7 +116,7 @@ "name": "Vorpal Strike", "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "cut", 99 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "cut", "scale": 99 } ], "crit_tec": true, "weighting": -250, "messages": [ @@ -165,7 +170,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You counter-attack %s", " counter-attacks %s" ] }, { @@ -212,7 +217,7 @@ "disarms": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -226,7 +231,7 @@ "crit_ok": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -241,7 +246,7 @@ "crit_ok": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -257,7 +262,7 @@ "disarms": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -280,7 +285,7 @@ "name": "Cross", "messages": [ "You throw a heavy cross at %s", " throws a cross at %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -295,7 +300,7 @@ "knockback_spread": 1, "stun_dur": 1, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -304,7 +309,12 @@ "messages": [ "You quickly jab %s", " quickly jabs at %s" ], "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -315,7 +325,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -346,7 +356,7 @@ "melee_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -357,7 +367,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -433,7 +443,7 @@ "name": "Push Kick", "messages": [ "You push kick %s", " push kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -443,7 +453,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -455,7 +465,7 @@ "req_buffs": [ "buff_capoeira_onmove" ], "weighting": 2, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.75 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 } ] }, { "type": "technique", @@ -468,7 +478,7 @@ "weighting": 2, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.75 ], [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 }, { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -501,7 +511,7 @@ "unarmed_allowed": true, "dodge_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -514,7 +524,7 @@ "knockback_dist": 1, "knockback_spread": 1, "stun_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -522,7 +532,7 @@ "name": "Dragon Claw", "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ], "messages": [ "You lash out at %s with a Dragon Claw", " lashes out at %s with a Dragon Claw" ] }, { @@ -535,7 +545,12 @@ "req_buffs": [ "buff_dragon_onhit" ], "block_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -547,7 +562,12 @@ "req_buffs": [ "buff_dragon_onhit" ], "dodge_counter": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -559,7 +579,7 @@ "crit_tec": true, "stunned_target": true, "down_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -571,7 +591,7 @@ "crit_tec": true, "downed_target": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -580,7 +600,7 @@ "messages": [ "You round strike %s", " round strikes %s" ], "skill_requirements": [ { "name": "melee", "level": 4 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.6 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.6 } ] }, { "type": "technique", @@ -589,7 +609,7 @@ "messages": [ "You fan strike %s", " fan strikes %s" ], "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.75 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 } ] }, { "type": "technique", @@ -597,7 +617,7 @@ "name": "Snap Strike", "messages": [ "You snap out at %s", " snaps quickly at %s" ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -608,7 +628,12 @@ "melee_allowed": true, "req_buffs": [ "buff_eskrima_oncrit" ], "crit_tec": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -620,7 +645,12 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.6 ], [ "damage", "bash", 0.7 ], [ "damage", "cut", 0.0 ], [ "damage", "stab", 0.0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.6 }, + { "stat": "damage", "type": "bash", "scale": 0.7 }, + { "stat": "damage", "type": "cut", "scale": 0.0 }, + { "stat": "damage", "type": "stab", "scale": 0.0 } + ] }, { "type": "technique", @@ -650,7 +680,7 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -662,7 +692,11 @@ "req_buffs": [ "buff_fencing_onmiss" ], "weighting": 4, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 1.25 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.25 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.25 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ] }, { "type": "technique", @@ -674,7 +708,12 @@ "block_counter": true, "crit_ok": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.2 ], [ "damage", "stab", 1.2 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.2 }, + { "stat": "damage", "type": "stab", "scale": 1.2 } + ] }, { "type": "technique", @@ -686,7 +725,12 @@ "block_counter": true, "crit_ok": true, "down_dur": 2, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -695,7 +739,11 @@ "messages": [ "You swing high and strike at %s", " swings high and strikes %s" ], "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.2 ], [ "damage", "stab", 1.2 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.2 }, + { "stat": "damage", "type": "stab", "scale": 1.2 } + ] }, { "type": "technique", @@ -706,7 +754,7 @@ "melee_allowed": true, "defensive": true, "miss_recovery": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -729,7 +777,11 @@ "crit_ok": true, "weighting": 2, "down_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -741,7 +793,11 @@ "downed_target": true, "crit_tec": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -752,7 +808,7 @@ "melee_allowed": true, "unarmed_weapons_allowed": false, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -765,7 +821,7 @@ "unarmed_weapons_allowed": false, "disarms": true, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -780,7 +836,7 @@ "side_switch": true, "down_dur": 1, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -807,7 +863,7 @@ "unarmed_weapons_allowed": false, "dodge_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -818,7 +874,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -829,7 +885,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.33 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 } ] }, { "type": "technique", @@ -838,7 +894,12 @@ "messages": [ "You quickly strike %s with the back of your fist", " quickly strikes %s with the back of their fist" ], "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -846,7 +907,7 @@ "name": "Roundhouse Kick", "messages": [ "You roundhouse kick %s", " roundhouse kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -856,7 +917,12 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "melee_allowed": true, "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -893,8 +959,8 @@ "stunned_target": true, "human_target": true, "stun_dur": 1, - "flat_bonuses": [ [ "arpen", "bash", "str", 1.0 ] ], - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 1.0 } ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -917,7 +983,7 @@ "unarmed_allowed": true, "crit_ok": true, "block_counter": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -938,7 +1004,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -946,7 +1012,12 @@ "name": "Leopard Swipe", "messages": [ "You quickly swipe at %s", " quickly swipes at %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -959,7 +1030,7 @@ "dodge_counter": true, "knockback_dist": 1, "knockback_spread": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -971,7 +1042,11 @@ "crit_ok": true, "dodge_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "cut", 0 ], [ "damage", "stab", 0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "cut", "scale": 0 }, + { "stat": "damage", "type": "stab", "scale": 0 } + ] }, { "type": "technique", @@ -1005,7 +1080,11 @@ "req_buffs": [ "buff_swordsmanship_oncrit" ], "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -1020,7 +1099,12 @@ "req_buffs": [ "buff_swordsmanship_onblock" ], "crit_tec": true, "stun_dur": 2, - "mult_bonuses": [ [ "movecost", 1.5 ], [ "damage", "bash", 3 ], [ "damage", "cut", 0 ], [ "damage", "stab", 0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.5 }, + { "stat": "damage", "type": "bash", "scale": 3 }, + { "stat": "damage", "type": "cut", "scale": 0 }, + { "stat": "damage", "type": "stab", "scale": 0 } + ] }, { "type": "technique", @@ -1030,7 +1114,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -1039,7 +1123,7 @@ "messages": [ "You deal a powerful kick to %s", " deals a powerful kick to %s" ], "unarmed_allowed": true, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 1.3 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.3 } ] }, { "type": "technique", @@ -1050,7 +1134,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -1071,7 +1155,7 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -1083,7 +1167,11 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -1095,7 +1183,7 @@ "crit_tec": true, "down_dur": 2, "stun_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -1104,7 +1192,11 @@ "messages": [ "You strike %s with the slow power of flowing water", " strikes %s with the slow power of flowing water" ], "skill_requirements": [ { "name": "melee", "level": 4 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 1.75 ], [ "damage", "bash", 2.0 ], [ "damage", "cut", 2.0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.75 }, + { "stat": "damage", "type": "bash", "scale": 2.0 }, + { "stat": "damage", "type": "cut", "scale": 2.0 } + ] }, { "type": "technique", @@ -1124,7 +1216,7 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, { "stat": "damage", "type": "cut", "scale": 1.5 } ] }, { "type": "technique", @@ -1136,7 +1228,11 @@ "req_buffs": [ "buff_niten_ondodge" ], "crit_ok": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 } + ] }, { "type": "technique", @@ -1147,7 +1243,7 @@ "melee_allowed": true, "defensive": true, "miss_recovery": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -1155,7 +1251,7 @@ "name": "Cross", "messages": [ "You throw a heavy cross at %s", " throws a cross at %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1186,7 +1282,7 @@ "unarmed_allowed": true, "stunned_target": true, "weighting": 3, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -1200,7 +1296,7 @@ "weighting": 3, "disarms": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -1215,7 +1311,7 @@ "knockback_dist": 2, "knockback_spread": 2, "stunned_target": true, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -1237,7 +1333,11 @@ "crit_ok": true, "downed_target": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "bash", 1.33 ], [ "damage", "cut", 1.33 ], [ "damage", "stab", 1.33 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.33 }, + { "stat": "damage", "type": "cut", "scale": 1.33 }, + { "stat": "damage", "type": "stab", "scale": 1.33 } + ] }, { "type": "technique", @@ -1259,7 +1359,11 @@ "crit_ok": true, "stunned_target": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "bash", 1.33 ], [ "damage", "cut", 1.33 ], [ "damage", "stab", 1.33 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.33 }, + { "stat": "damage", "type": "cut", "scale": 1.33 }, + { "stat": "damage", "type": "stab", "scale": 1.33 } + ] }, { "type": "technique", @@ -1267,7 +1371,12 @@ "name": "Snake Snap", "messages": [ "You swiftly jab %s", " swiftly jabs %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -1298,7 +1407,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -1310,7 +1419,12 @@ "block_counter": true, "crit_ok": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -1320,7 +1434,11 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -1330,7 +1448,11 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -1341,7 +1463,7 @@ "unarmed_allowed": true, "weighting": 2, "take_weapon": true, - "mult_bonuses": [ [ "damage", "bash", 0.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 } ] }, { "type": "technique", @@ -1356,7 +1478,7 @@ "crit_tec": true, "stun_dur": 2, "knockback_dist": 2, - "mult_bonuses": [ [ "movecost", 1.5 ], [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 1.5 }, { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -1382,7 +1504,7 @@ "name": "Roundhouse Kick", "messages": [ "You roundhouse kick %s", " roundhouse kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1412,7 +1534,7 @@ "unarmed_allowed": true, "req_buffs": [ "buff_tai_chi_onpause" ], "knockback_dist": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -1424,7 +1546,7 @@ "block_counter": true, "crit_ok": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1437,7 +1559,7 @@ "req_buffs": [ "buff_tai_chi_onpause" ], "knockback_dist": 1, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -1465,7 +1587,7 @@ "name": "Straight Punch", "messages": [ "You deliver a vertical straight punch to %s", " delivers a vertical straight punch to %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.1 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 } ] }, { "type": "technique", @@ -1478,7 +1600,7 @@ "weighting": 2, "knockback_dist": 1, "knockback_follow": true, - "mult_bonuses": [ [ "damage", "bash", 1.1 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 } ] }, { "type": "technique", @@ -1489,7 +1611,7 @@ "unarmed_allowed": true, "crit_tec": true, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1504,7 +1626,7 @@ "down_dur": 1, "knockback_dist": 1, "knockback_follow": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1525,7 +1647,7 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -1545,7 +1667,7 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -1565,8 +1687,11 @@ "unarmed_allowed": true, "unarmed_weapons_allowed": false, "skill_requirements": [ { "name": "unarmed", "level": 3 } ], - "mult_bonuses": [ [ "damage", "bash", 3.0 ], [ "damage", "bash", "str", 0.1 ] ], - "flat_bonuses": [ [ "movecost", 100 ], [ "movecost", "str", 10 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 3.0 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.1 } + ], + "flat_bonuses": [ { "stat": "movecost", "scale": 100 }, { "stat": "movecost", "scaling-stat": "str", "scale": 10 } ], "messages": [ "You slowly strike %s", " slowly strikes %s" ] }, { @@ -1576,8 +1701,16 @@ "unarmed_allowed": true, "melee_allowed": true, "skill_requirements": [ { "name": "melee", "level": 3 } ], - "mult_bonuses": [ [ "damage", "bash", 0.2 ], [ "damage", "cut", 0.2 ], [ "damage", "stab", 0.2 ], [ "movecost", 0.3 ] ], - "flat_bonuses": [ [ "arpen", "bash", 10 ], [ "arpen", "bash", "per", 1 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scale": 0.2 }, + { "stat": "damage", "type": "stab", "scale": 0.2 }, + { "stat": "movecost", "scale": 0.3 } + ], + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scale": 10 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 1 } + ], "crit_tec": true, "messages": [ "You phase-strike %s", " phase-strikes %s" ] } diff --git a/data/mods/Aftershock/player/techniques.json b/data/mods/Aftershock/player/techniques.json index 3bb4fe7ef77af..c8aaf058f3142 100644 --- a/data/mods/Aftershock/player/techniques.json +++ b/data/mods/Aftershock/player/techniques.json @@ -7,7 +7,7 @@ "melee_allowed": true, "skill_requirements": [ { "name": "melee", "level": 3 } ], "crit_tec": true, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ], "stun_dur": 3, "knockback_dist": 2, "weighting": 1, diff --git a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json index 946fb273cbda3..62a6c43085714 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json @@ -28,7 +28,12 @@ "unarmed_allowed": true, "melee_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 2 } ], - "flat_bonuses": [ [ "damage", "stab", 1.0 ], [ "damage", "cut", 1.0 ], [ "arpen", "stab", 1.0 ], [ "arpen", "cut", 1.0 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scale": 1.0 }, + { "stat": "damage", "type": "cut", "scale": 1.0 }, + { "stat": "arpen", "type": "stab", "scale": 1.0 }, + { "stat": "arpen", "type": "cut", "scale": 1.0 } + ] } ], "onhit_buffs": [ @@ -41,7 +46,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "buff_duration": 1, "max_stacks": 4, - "flat_bonuses": [ [ "damage", "stab", 0.25 ], [ "damage", "cut", 0.5 ], [ "arpen", "cut", 1.0 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scale": 0.25 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scale": 1.0 } + ] } ], "techniques": [ "tec_crt_blade_normal", "tec_crt_blade_rapid", "tec_crt_blade_precise", "tec_crt_blade_arpen", "tec_feint" ], @@ -80,7 +89,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 }, { "name": "melee", "level": 1 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 0.8 ], [ "damage", "cut", 0.7 ], [ "damage", "stab", 0.6 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.8 }, + { "stat": "damage", "type": "cut", "scale": 0.7 }, + { "stat": "damage", "type": "stab", "scale": 0.6 } + ], "messages": [ "You release a blindingly fast slash at %s", " slashes at %s" ] }, { @@ -90,7 +103,12 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 }, { "name": "melee", "level": 2 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.77 ], [ "damage", "bash", 0.55 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.88 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.77 }, + { "stat": "damage", "type": "bash", "scale": 0.55 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.88 } + ], "messages": [ "You swiftly jab your weapon at %s", " swiftly jabs their weapon at %s" ] }, { @@ -100,7 +118,12 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 }, { "name": "melee", "level": 3 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 1.05 ], [ "damage", "stab", 1.0 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 1.05 }, + { "stat": "damage", "type": "stab", "scale": 1.0 } + ], "crit_tec": true, "messages": [ "You release a debilitating swipe at %s", " releases a debilitating swipe at %s" ], "down_dur": 2 @@ -114,11 +137,11 @@ "unarmed_allowed": true, "melee_allowed": true, "mult_bonuses": [ - [ "damage", "bash", 0.5 ], - [ "damage", "cut", 1.1 ], - [ "damage", "stab", 1.1 ], - [ "arpen", "stab", 0.25 ], - [ "arpen", "cut", 0.5 ] + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 }, + { "stat": "arpen", "type": "stab", "scale": 0.25 }, + { "stat": "arpen", "type": "cut", "scale": 0.5 } ], "crit_tec": true, "messages": [ diff --git a/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json b/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json index db9df86d9177c..386e88b9a543d 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json @@ -28,11 +28,11 @@ "unarmed_allowed": true, "melee_allowed": true, "flat_bonuses": [ - [ "arpen", "bash", "str", 0.15 ], - [ "armor", "bash", 1.0 ], - [ "armor", "cut", 1.0 ], - [ "armor", "stab", 1.0 ], - [ "hit", "str", 0.4 ] + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "armor", "type": "bash", "scale": 1.0 }, + { "stat": "armor", "type": "cut", "scale": 1.0 }, + { "stat": "armor", "type": "stab", "scale": 1.0 }, + { "stat": "hit", "scaling-stat": "str", "scale": 0.4 } ] } ], @@ -47,13 +47,13 @@ "buff_duration": 10, "max_stacks": 10, "flat_bonuses": [ - [ "damage", "bash", "str", 0.01 ], - [ "armor", "bash", 0.05 ], - [ "armor", "cut", 0.05 ], - [ "armor", "stab", 0.05 ], - [ "armor", "bash", "str", 0.15 ], - [ "armor", "cut", "str", 0.125 ], - [ "armor", "stab", "str", 0.075 ] + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.01 }, + { "stat": "armor", "type": "bash", "scale": 0.05 }, + { "stat": "armor", "type": "cut", "scale": 0.05 }, + { "stat": "armor", "type": "stab", "scale": 0.05 }, + { "stat": "armor", "type": "bash", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "armor", "type": "cut", "scaling-stat": "str", "scale": 0.125 }, + { "stat": "armor", "type": "stab", "scaling-stat": "str", "scale": 0.075 } ] } ], @@ -89,8 +89,15 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 }, { "name": "melee", "level": 1 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.0 ], [ "damage", "cut", 1.0 ], [ "damage", "stab", 1.0 ] ], - "flat_bonuses": [ [ "damage", "bash", "str", 0.15 ], [ "movecost", "str", -0.7 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.0 }, + { "stat": "damage", "type": "cut", "scale": 1.0 }, + { "stat": "damage", "type": "stab", "scale": 1.0 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -0.7 } + ], "messages": [ "You clock %s's in a weak spot to knock em down", " smashes in %s's face" ], "down_dur": 1 }, @@ -101,8 +108,16 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 }, { "name": "melee", "level": 2 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 1.04 ], [ "damage", "bash", 1.0 ], [ "damage", "cut", 1.05 ], [ "damage", "stab", 1.05 ] ], - "flat_bonuses": [ [ "arpen", "bash", "str", 0.2 ], [ "movecost", "str", -1.2 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.04 }, + { "stat": "damage", "type": "bash", "scale": 1.0 }, + { "stat": "damage", "type": "cut", "scale": 1.05 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.2 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -1.2 } + ], "messages": [ "You swiftly swipe your weapon's tip at %s", " swiftly jabs their weapon into %s" ] }, { @@ -112,8 +127,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 }, { "name": "melee", "level": 3 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 1.35 ], [ "damage", "bash", 1.15 ], [ "damage", "cut", 1.05 ], [ "damage", "stab", 1.0 ] ], - "flat_bonuses": [ [ "arpen", "bash", "str", 0.5 ], [ "damage", "cut", "str", 0.25 ], [ "movecost", "str", -1.5 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.35 }, + { "stat": "damage", "type": "bash", "scale": 1.15 }, + { "stat": "damage", "type": "cut", "scale": 1.05 }, + { "stat": "damage", "type": "stab", "scale": 1.0 } + ], + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -1.5 } + ], "crit_tec": true, "messages": [ "You steady your arm and release a crushing blow at %s", " releases a crushing blow at %s" ], "stun_dur": 3, diff --git a/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json b/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json index 7f34ed436f509..72055a8907ba1 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json @@ -38,14 +38,14 @@ "unarmed_allowed": true, "melee_allowed": true, "flat_bonuses": [ - [ "damage", "stab", "dex", 0.15 ], - [ "damage", "cut", "dex", 0.05 ], - [ "arpen", "stab", "dex", 0.25 ], - [ "arpen", "cut", "dex", 0.15 ], - [ "dodge", "dex", 0.1 ], - [ "hit", "dex", 0.15 ] + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.15 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.05 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "dex", "scale": 0.25 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "dex", "scale": 0.15 }, + { "stat": "dodge", "scaling-stat": "dex", "scale": 0.1 }, + { "stat": "hit", "scaling-stat": "dex", "scale": 0.15 } ], - "mult_bonuses": [ [ "damage", "bash", 0.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 } ] } ], "onhit_buffs": [ @@ -58,8 +58,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 2, "max_stacks": 10, - "flat_bonuses": [ [ "movecost", "dex", -0.05 ], [ "movecost", 0.1 ], [ "damage", "stab", 0.1 ] ], - "mult_bonuses": [ [ "damage", "stab", 1.075 ], [ "damage", "cut", 1.02 ], [ "arpen", "stab", 1.01 ], [ "dodge", 1.02 ] ] + "flat_bonuses": [ + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.05 }, + { "stat": "movecost", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scale": 0.1 } + ], + "mult_bonuses": [ + { "stat": "damage", "type": "stab", "scale": 1.075 }, + { "stat": "damage", "type": "cut", "scale": 1.02 }, + { "stat": "arpen", "type": "stab", "scale": 1.01 }, + { "stat": "dodge", "scale": 1.02 } + ] } ], "techniques": [ @@ -79,8 +88,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "melee_allowed": false, - "mult_bonuses": [ [ "movecost", 0.85 ], [ "damage", "bash", 0.8 ], [ "damage", "cut", 1.025 ], [ "damage", "stab", 1.05 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.2 ], [ "damage", "cut", "dex", 0.1 ], [ "movecost", "dex", -0.15 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.85 }, + { "stat": "damage", "type": "bash", "scale": 0.8 }, + { "stat": "damage", "type": "cut", "scale": 1.025 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.1 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.15 } + ], "messages": [ "You quickly dig your fingers into %s", " digs their fingers into %s" ] }, { @@ -90,8 +108,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.7 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.7 ], [ "damage", "stab", 0.8 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.015 ], [ "damage", "cut", "dex", 0.0125 ], [ "movecost", "dex", -0.35 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.7 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.7 }, + { "stat": "damage", "type": "stab", "scale": 0.8 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.015 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.0125 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.35 } + ], "messages": [ "You swiftly impale your fingers into %s joints", " swiftly impales their fingers into %s" ] }, { @@ -101,8 +128,17 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "unarmed_allowed": false, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.75 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.015 ], [ "damage", "cut", "dex", 0.0125 ], [ "movecost", "dex", -0.35 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.75 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.015 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.0125 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.35 } + ], "messages": [ "You explosively jab your weapon at %s joints", " explosively jabs at %s" ] }, { @@ -112,8 +148,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.25 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.2 ], [ "damage", "cut", "dex", 0.01 ], [ "movecost", "dex", -0.2 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.01 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.2 } + ], "crit_tec": true, "messages": [ "You steady your hand and release a piercing jab at %s", " releases a piercing jab at %s" ], "stun_dur": 1 @@ -127,14 +172,18 @@ "unarmed_allowed": true, "melee_allowed": true, "mult_bonuses": [ - [ "movecost", 0.9 ], - [ "damage", "bash", 0.2 ], - [ "damage", "cut", 1.25 ], - [ "arpen", "cut", "dex", 0.15 ], - [ "damage", "stab", 1.5 ], - [ "arpen", "stab", "dex", 0.3 ] + { "stat": "movecost", "scale": 0.9 }, + { "stat": "damage", "type": "bash", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "dex", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scale": 1.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "dex", "scale": 0.3 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.25 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.5 } ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.5 ], [ "damage", "cut", "dex", 0.25 ], [ "movecost", "dex", -0.5 ] ], "crit_tec": true, "messages": [ "You envision a gathering tempest in and then release it's energy on %s's top half", diff --git a/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json b/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json index 24b3738778380..9acc3d4967e6a 100644 --- a/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json +++ b/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json @@ -5,8 +5,13 @@ "name": "HOOK", "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.95 ], [ "damage", "bash", 0.88 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ], - "flat_bonuses": [ [ "movecost", "per", -0.25 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.95 }, + { "stat": "damage", "type": "bash", "scale": 0.88 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ], + "flat_bonuses": [ { "stat": "movecost", "scaling-stat": "per", "scale": -0.25 } ], "stun_dur": 2, "messages": [ "Your pistol whip sends %s careening", " smacks %s" ], "description": "95% moves, 88% Bash, 66% Cut, 66% Stab, Down two turns, STR (C) greatly reduces action cost" @@ -18,12 +23,17 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.6 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.6 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ], "flat_bonuses": [ - [ "movecost", "str", -1.0 ], - [ "damage", "bash", "per", 0.15 ], - [ "damage", "stab", "per", 0.1 ], - [ "damage", "cut", "per", 0.1 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -1.0 }, + { "stat": "damage", "type": "bash", "scaling-stat": "per", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.1 }, + { "stat": "damage", "type": "cut", "scaling-stat": "per", "scale": 0.1 } ], "messages": [ "Your swing the stock of your weapon at %s", " strikes at %s" ], "aoe": "wide", diff --git a/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json b/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json index 54115bfbf546c..c7a40fa52e2ea 100644 --- a/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json +++ b/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json @@ -6,12 +6,17 @@ "skill_requirements": [ { "name": "melee", "level": 1 } ], "unarmed_allowed": false, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.3 ], [ "damage", "bash", 0.77 ], [ "damage", "cut", 0.77 ], [ "damage", "stab", 0.77 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.3 }, + { "stat": "damage", "type": "bash", "scale": 0.77 }, + { "stat": "damage", "type": "cut", "scale": 0.77 }, + { "stat": "damage", "type": "stab", "scale": 0.77 } + ], "flat_bonuses": [ - [ "movecost", "str", -10 ], - [ "damage", "bash", "str", 0.8 ], - [ "damage", "stab", "str", 1.5 ], - [ "damage", "cut", "str", 0.8 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -10 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.8 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.8 } ], "down_dur": 2, "messages": [ "Your swing makes %s stagger and fall", " hooks %s" ], @@ -25,12 +30,17 @@ "unarmed_allowed": false, "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.15 ], [ "damage", "bash", 0.35 ], [ "damage", "cut", 0.35 ], [ "damage", "stab", 0.35 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.15 }, + { "stat": "damage", "type": "bash", "scale": 0.35 }, + { "stat": "damage", "type": "cut", "scale": 0.35 }, + { "stat": "damage", "type": "stab", "scale": 0.35 } + ], "flat_bonuses": [ - [ "movecost", "str", -15 ], - [ "damage", "bash", "str", 0.1 ], - [ "damage", "stab", "str", 0.3 ], - [ "damage", "cut", "str", 0.1 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -15 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.3 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.1 } ], "messages": [ "Your momentum causes your weapon to strike %s", " inertially strikes %s" ], "aoe": "wide", @@ -44,13 +54,18 @@ "unarmed_allowed": true, "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 0.35 ], [ "damage", "bash", 1.05 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.05 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.35 }, + { "stat": "damage", "type": "bash", "scale": 1.05 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], "flat_bonuses": [ - [ "movecost", "str", -15 ], - [ "movecost", "dex", -7 ], - [ "damage", "bash", "per", 0.15 ], - [ "damage", "cut", "per", 0.3 ], - [ "damage", "stab", "per", 0.15 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -15 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -7 }, + { "stat": "damage", "type": "bash", "scaling-stat": "per", "scale": 0.15 }, + { "stat": "damage", "type": "cut", "scaling-stat": "per", "scale": 0.3 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.15 } ], "messages": [ "You wind up the sword and release a well placed swing at %s", " chops %s" ], "description": "Crit only, 35% move cost, 105% Bash and Stab, 125% Cut, DEX (D) and PER (E) reduces action cost and increases overall (B) damage, min 2 melee" diff --git a/data/mods/CRT_EXPANSION/martial/generaltechn.json b/data/mods/CRT_EXPANSION/martial/generaltechn.json index 942c3d3e4c220..00846be7de403 100644 --- a/data/mods/CRT_EXPANSION/martial/generaltechn.json +++ b/data/mods/CRT_EXPANSION/martial/generaltechn.json @@ -3,8 +3,13 @@ "type": "technique", "id": "HOOK", "name": "HOOK", - "mult_bonuses": [ [ "movecost", 0.85 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.76 ], [ "damage", "stab", 0.86 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.25 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.85 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.76 }, + { "stat": "damage", "type": "stab", "scale": 0.86 } + ], + "flat_bonuses": [ { "stat": "movecost", "scaling-stat": "str", "scale": -0.25 } ], "down_dur": 2, "messages": [ "Your hooking attack makes %s stagger and fall", " hooks %s" ], "description": "85% moves, 66% Bash, 76% Cut, 86% Stab, Down two turns, STR (C) greatly reduces action cost" @@ -17,12 +22,17 @@ "unarmed_allowed": true, "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.6 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.6 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ], "flat_bonuses": [ - [ "movecost", "str", -1.0 ], - [ "damage", "bash", "str", 0.1 ], - [ "damage", "stab", "str", 0.1 ], - [ "damage", "cut", "str", 0.1 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -1.0 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.1 } ], "messages": [ "Your momentum causes your weapon to glance off of %s", " inertially strikes %s" ], "aoe": "wide", @@ -36,13 +46,18 @@ "unarmed_allowed": true, "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 1.18 ], [ "damage", "bash", 1.05 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.05 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.18 }, + { "stat": "damage", "type": "bash", "scale": 1.05 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], "flat_bonuses": [ - [ "movecost", "dex", -0.2 ], - [ "movecost", "per", -0.125 ], - [ "damage", "bash", "per", 0.15 ], - [ "damage", "cut", "per", 0.3 ], - [ "damage", "stab", "per", 0.15 ] + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.2 }, + { "stat": "movecost", "scaling-stat": "per", "scale": -0.125 }, + { "stat": "damage", "type": "bash", "scaling-stat": "per", "scale": 0.15 }, + { "stat": "damage", "type": "cut", "scaling-stat": "per", "scale": 0.3 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.15 } ], "messages": [ "You draw back your arm and release a well placed chop %s", " chops %s" ], "description": "Crit only, 118% move cost, 105% Bash and Stab, 125% Cut, DEX (D) and PER (E) reduces action cost and increases overall (B) damage, min 2 melee" @@ -55,13 +70,18 @@ "unarmed_allowed": true, "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 1.18 ], [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.05 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.18 }, + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], "flat_bonuses": [ - [ "movecost", "dex", -0.2 ], - [ "movecost", "str", -0.125 ], - [ "damage", "bash", "str", 0.25 ], - [ "damage", "cut", "str", 0.15 ], - [ "damage", "stab", "str", 0.15 ] + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.2 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -0.125 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.15 } ], "messages": [ "You grip your weapon with two hands and slam it into %s", " smashes their weapon onto %s" ], "description": "Crit only, 110% move cost, 120% Bash, 105% Stab, 110% Cut, DEX (C) and STR (D) reduces action cost and increases overall (C) damage, min 2 melee" @@ -75,8 +95,13 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 1.2 ], [ "damage", "bash", 1.25 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.25 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.8 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.2 }, + { "stat": "damage", "type": "bash", "scale": 1.25 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ], + "flat_bonuses": [ { "stat": "movecost", "scaling-stat": "str", "scale": -0.8 } ], "messages": [ "You lunge forward with all your weight and swing upwards at %s", " swings upwards with all their weight at %s" @@ -91,8 +116,16 @@ "melee_allowed": true, "knockback_dist": 2, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.65 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.15 ], [ "damage", "stab", 0.35 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.15 ], [ "movecost", "dex", -0.1 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.65 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scale": 0.35 } + ], + "flat_bonuses": [ + { "stat": "movecost", "scaling-stat": "str", "scale": -0.15 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.1 } + ], "messages": [ "You quickly shove %s out of the way", " quickly shoves %s" ], "description": "65% moves, dramatically reduced damage, knockback 2 tiles, stun 1 turn, STR (D) and DEX (E) reduce action cost" }, @@ -104,8 +137,16 @@ "unarmed_allowed": false, "melee_allowed": true, "knockback_dist": 2, - "mult_bonuses": [ [ "movecost", 0.75 ], [ "damage", "bash", 1.1 ], [ "damage", "cut", 0 ], [ "damage", "stab", 1.1 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.3 ], [ "movecost", "dex", -0.15 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.75 }, + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 0 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ], + "flat_bonuses": [ + { "stat": "movecost", "scaling-stat": "str", "scale": -0.3 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.15 } + ], "messages": [ "You quickly shove %s out of the way with your weapon", " quickly shoves %s" ], "description": "75% moves, no cut damage, 110% Bash and Stab damage, knockback 2 tiles, STR (B) and DEX (C) reduce action cost, min melee 1" }, @@ -118,7 +159,7 @@ "melee_allowed": true, "crit_tec": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.15 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "cut", "scale": 1.1 }, { "stat": "damage", "type": "stab", "scale": 1.15 } ], "messages": [ "You stab into %s and rake your blade out", " tears into %s flesh" ], "description": "Crit only, 110% Cut, 115% Stab, min melee 2" } diff --git a/data/mods/CRT_EXPANSION/martial/stabtechn.json b/data/mods/CRT_EXPANSION/martial/stabtechn.json index 7f9677dfcfd7c..b1948ea60ee88 100644 --- a/data/mods/CRT_EXPANSION/martial/stabtechn.json +++ b/data/mods/CRT_EXPANSION/martial/stabtechn.json @@ -8,8 +8,11 @@ "melee_allowed": true, "crit_tec": false, "weighting": 1, - "mult_bonuses": [ [ "damage", "stab", 1.1 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.1 ], [ "damage", "stab", "per", 0.2 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "stab", "scale": 1.1 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.2 } + ], "messages": [ "You step forward and stab at %s", " stabs into %s flesh" ], "description": "110% Stab damage, STR (E) and PER (D) provides bonus damage, min 1 melee" }, @@ -22,8 +25,11 @@ "melee_allowed": true, "crit_tec": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "stab", 1.15 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.2 ], [ "damage", "stab", "per", 0.2 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "stab", "scale": 1.15 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.2 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.2 } + ], "messages": [ "You explosively jab at %s", " violently jabs at %s" ], "description": "Crit only, 115% Stab damage, Crit only, Strength (D) and Perception (D) provides bonus damage, min 2 melee" }, @@ -36,8 +42,12 @@ "melee_allowed": true, "crit_tec": false, "weighting": 1, - "mult_bonuses": [ [ "movecost", 0.66 ], [ "damage", "stab", 0.7 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.15 ], [ "damage", "stab", "per", 0.25 ], [ "movecost", "dex", 0.25 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.66 }, { "stat": "damage", "type": "stab", "scale": 0.7 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.25 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": 0.25 } + ], "messages": [ "You prod at %s defensively", " prods at %s " ], "description": "66% movecost, 70% Stab damage, STR (E) and PER (C) provides bonus damage, DEX (C) reduces action cost, min 3 melee" }, @@ -50,8 +60,12 @@ "melee_allowed": true, "crit_tec": false, "weighting": 1, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "stab", 0.75 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.25 ], [ "damage", "stab", "per", 0.3 ], [ "arpen", "stab", "per", 0.12 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 }, { "stat": "damage", "type": "stab", "scale": 0.75 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.3 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "per", "scale": 0.12 } + ], "messages": [ "You probe %s's openings", " probe %s " ], "description": "80% movecost, 75% Stab damage, STR (C) and PER (C) provides bonus damage and also provides armor pierce (E), min 3 melee" } diff --git a/data/mods/MMA/martialarts.json b/data/mods/MMA/martialarts.json index 130d1ba5828a1..6b89932e29305 100644 --- a/data/mods/MMA/martialarts.json +++ b/data/mods/MMA/martialarts.json @@ -16,7 +16,7 @@ "unarmed_allowed": true, "melee_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "dodge", "per", 0.12 ] ] + "flat_bonuses": [ { "stat": "dodge", "scaling-stat": "per", "scale": 0.12 } ] } ], "ondodge_buffs": [ @@ -28,7 +28,12 @@ "unarmed_allowed": true, "melee_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "hit", 1.0 ], [ "arpen", "bash", "per", 0.5 ], [ "arpen", "cut", "per", 0.5 ], [ "arpen", "stab", "per", 0.5 ] ] + "flat_bonuses": [ + { "stat": "hit", "scale": 1.0 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "per", "scale": 0.5 } + ] } ], "techniques": [ "mma_tec_panzer_counter", "mma_tec_panzer_somersault", "mma_tec_panzer_precise", "mma_tec_panzer_rapid" ], diff --git a/data/mods/MMA/techniques.json b/data/mods/MMA/techniques.json index b06b672b32008..a6010240bed30 100644 --- a/data/mods/MMA/techniques.json +++ b/data/mods/MMA/techniques.json @@ -10,7 +10,12 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.2 ], [ "damage", "stab", 1.2 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.2 }, + { "stat": "damage", "type": "stab", "scale": 1.2 } + ] }, { "type": "technique", @@ -20,7 +25,7 @@ "messages": [ "You jump and somersault kick %s", " jump and somersault kick %s" ], "melee_allowed": true, "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -33,8 +38,8 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "flat_bonuses": [ [ "arpen", "bash", 10.0 ] ], - "mult_bonuses": [ [ "movecost", 1.2 ], [ "damage", "bash", 1.5 ] ] + "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scale": 10.0 } ], + "mult_bonuses": [ { "stat": "movecost", "scale": 1.2 }, { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -45,6 +50,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "melee_allowed": true, "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] } ] diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 303daab1d8aa4..3b19c0dc23de5 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1082,7 +1082,6 @@ Note that even though most statistics yield an integer, you should still use "profession": true, //Trait is a starting profession special trait. (default: false) "debug": false, //Trait is for debug purposes (default: false) "player_display": true, //Trait is displayed in the `@` player display menu -"initial_ma_styles" : [ "style_centipede", "style_venom_snake" ], //List of starting martial arts types. One of the list is selectable at start. Only works at character creation. "category": ["MUTCAT_BIRD", "MUTCAT_INSECT"], // Categories containing this mutation "prereqs": ["SKIN_ROUGH"], // Needs these mutations before you can mutate toward this mutation "prereqs2": ["LEAVES"], //Also need these mutations before you can mutate towards this mutation. When both set creates 2 different mutation paths, random from one is picked. Only use together with "prereqs" diff --git a/doc/MARTIALART_JSON.md b/doc/MARTIALART_JSON.md index 939be0bfd24ba..2331a993b9fc1 100644 --- a/doc/MARTIALART_JSON.md +++ b/doc/MARTIALART_JSON.md @@ -10,7 +10,7 @@ "description": "A secret martial art used only by developers and cheaters.", // In-game description "initiate": [ "You stand ready.", "%s stands ready." ], // Message shown when player or NPC chooses this art "autolearn": [ [ "unarmed", "2" ] ], // A list of skill requirements that if met, automatically teach the player the martial art -"learn_difficulty": 5, // Difficulty to learn a style from book based on "primary skill" +"learn_difficulty": 5, // Difficulty to learn a style from book based on "primary skill" // Total chance to learn a style from a single read of the book is equal to one in (10 + learn_difficulty - primary_skill) "arm_block" : 99, // Unarmed skill level at which arm blocking is unlocked "leg_block" : 99, // Unarmed skill level at which arm blocking is unlocked @@ -40,7 +40,7 @@ "name" : "phasing strike", // In-game name displayed "unarmed_allowed" : true, // Can an unarmed character use this technique "unarmed_weapons_allowed" : true, // Does this technique require the character to be actually unarmed or does it allow unarmed weapons -"melee_allowed" : true, // Means that ANY melee weapon can be used, NOT just the martial art's weapons +"melee_allowed" : true, // Means that ANY melee weapon can be used, NOT just the martial art's weapons "skill_requirements": [ { "name": "melee", "level": 3 } ], // Skills and their minimum levels required to use this technique. Can be any skill. "weapon_damage_requirements": [ { "type": "bash", "min": 5 } ], // Minimum weapon damage required to use this technique. Can be any damage type. "req_buffs": [ "eskrima_hit_buff" ], // This technique requires a named buff to be active @@ -84,32 +84,31 @@ "max_stacks" : 8, // Maximum number of stacks on the buff. Buff bonuses are multiplied by current buff intensity "bonus_blocks": 1 // Extra blocks per turn "bonus_dodges": 1 // Extra dodges per turn -"flat_bonuses" : [ // Flat bonuses - ["armor", "bash", "str", 1.0], - ["armor", "cut", "dex", 1.0], - ["armor", "electric", "int", 1.0], - ["armor", "heat", "per", 1.0] +"flat_bonuses" : [ // Flat bonuses, see below ], -"mult_bonuses" : [ // Multiplicative bonuses - ["damage", "bash", 2.0], - ["damage", "heat", "int", 1.1] +"mult_bonuses" : [ // Multiplicative bonuses, see below ] ``` ### Bonuses -Bonuses contain 2 to 4 of the following tokens, in order: +The bonuses arrays contain any number of bonus entries like this: -* Affected statistic. Any of: "hit", "dodge", "block", "speed", "movecost", "damage", "armor", "arpen" -* Damage type ("bash", "cut", "heat", etc.) if the affected statistic is damage, armor, or arpen -* Scaling stat. Any of: "str", "dex", "int", "per" -* The value of the bonus itself - -Bonuses must be written in the correct order. +```C++ +{ + "stat": "damage", + "type": "bash", + "scaling-stat": "per", + "scale": 0.15 +} +``` -If the affected statistic requires a damage type, a damage type must be provided. Otherwise, damage type must not be specified. +"stat": affected statistic, any of: "hit", "dodge", "block", "speed", "movecost", "damage", "armor", "arpen", +"type": damage type for the affected statistic ("bash", "cut", "heat", etc.), only needed if the affected statistic is "damage", "armor", or "arpen". +"scale": the value of the bonus itself. +"scaling-stat": scaling stat, any of: "str", "dex", "int", "per". Optional. If the scaling stat is specified, the value of the bonus is multiplied by the corresponding user stat. -If the scaling stat is specified, the value of the bonus is multiplied by the corresponding user stat. +Bonuses must be written in the correct order. Tokens of `useless` type will not cause an error, but will not have any effect. For example, `speed` in a technique will have no effect (`movecost` should be used for techniques). @@ -117,9 +116,14 @@ For example, `speed` in a technique will have no effect (`movecost` should be us Currently extra elemental damage is not applied, but extra elemental armor is (after regular armor). Examples: -* `flat_bonuses : [["armor", "bash", "str", 0.3]], // Incoming bashing damage is decreased by 30% of strength value. Only useful on buffs` -* ``mult_bonuses : [["damage", "cut", "dex", 0.1]], // All cutting damage dealt is multiplied by `(10% of dexterity)*(damage)` `` -* `flat_bonuses : [["movecost", "str", -1.0]], // Move cost is decreased by 100% of strength value` +Incoming bashing damage is decreased by 30% of strength value. Only useful on buffs: +* `flat_bonuses : [ { "stat": "armor", "type": "bash", "scaling-stat": "str", "scale": 0.3 } ]` + +All cutting damage dealt is multiplied by `(10% of dexterity)*(damage)`: +* `mult_bonuses : [ { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.1 } ]` + +Move cost is decreased by 100% of strength value +* `flat_bonuses : [ { "stat": "movecost", "scaling-stat": "str", "scale": -1.0 } ]` ### Place relevant items in the world and chargen diff --git a/src/bonuses.cpp b/src/bonuses.cpp index 9503dd06e1fd4..539ef96b22cb2 100644 --- a/src/bonuses.cpp +++ b/src/bonuses.cpp @@ -93,57 +93,43 @@ static std::string string_from_scaling_stat( const scaling_stat &s ) bonus_container::bonus_container() = default; -void effect_scaling::load( JsonArray &jarr ) +effect_scaling::effect_scaling( const JsonObject &obj ) { - if( jarr.test_string() ) { - stat = scaling_stat_from_string( jarr.next_string() ); + if( obj.has_string( "scaling-stat" ) ) { + stat = scaling_stat_from_string( obj.get_string( "scaling-stat" ) ); } else { stat = STAT_NULL; } - scale = jarr.next_float(); + scale = obj.get_float( "scale" ); } void bonus_container::load( const JsonObject &jo ) { - if( jo.has_array( "flat_bonuses" ) ) { - JsonArray jarr = jo.get_array( "flat_bonuses" ); - load( jarr, false ); - } - - if( jo.has_array( "mult_bonuses" ) ) { - JsonArray jarr = jo.get_array( "mult_bonuses" ); - load( jarr, true ); - } + load( jo.get_array( "flat_bonuses" ), false ); + load( jo.get_array( "mult_bonuses" ), true ); } -void bonus_container::load( JsonArray &jarr, bool mult ) +void bonus_container::load( const JsonArray &jarr, const bool mult ) { - while( jarr.has_more() ) { - JsonArray qualifiers = jarr.next_array(); - - damage_type dt = DT_NULL; - - const std::string affected_stat_string = qualifiers.next_string(); - const affected_stat as = affected_stat_from_string( affected_stat_string ); + for( const JsonObject &qualifiers : jarr ) { + const affected_stat as = affected_stat_from_string( qualifiers.get_string( "stat" ) ); if( as == AFFECTED_NULL ) { - jarr.throw_error( "Invalid affected stat" ); + qualifiers.throw_error( "Invalid affected stat", "stat" ); } + damage_type dt = DT_NULL; if( needs_damage_type( as ) ) { - const std::string damage_string = qualifiers.next_string(); - dt = dt_by_name( damage_string ); + dt = dt_by_name( qualifiers.get_string( "type" ) ); if( dt == DT_NULL ) { - jarr.throw_error( "Invalid damage type" ); + qualifiers.throw_error( "Invalid damage type", "type" ); } } - effect_scaling es; - es.load( qualifiers ); - affected_type at( as, dt ); - // Are we changing multipliers or flats? + const affected_type at( as, dt ); + auto &selected = mult ? bonuses_mult : bonuses_flat; - selected[at].push_back( es ); + selected[at].emplace_back( qualifiers ); } } diff --git a/src/bonuses.h b/src/bonuses.h index 070252cb1db8b..ccf1b1a54fb0e 100644 --- a/src/bonuses.h +++ b/src/bonuses.h @@ -63,7 +63,7 @@ struct effect_scaling { float get( const Character &u ) const; - void load( JsonArray &jarr ); + effect_scaling( const JsonObject &obj ); }; class bonus_container @@ -71,7 +71,6 @@ class bonus_container public: bonus_container(); void load( const JsonObject &jo ); - void load( JsonArray &jarr, bool mult ); float get_flat( const Character &u, affected_stat stat, damage_type dt ) const; float get_flat( const Character &u, affected_stat stat ) const; @@ -82,6 +81,8 @@ class bonus_container std::string get_description() const; private: + void load( const JsonArray &jarr, bool mult ); + using bonus_map = std::map>; /** All kinds of bonuses by types to damage, hit etc. */ bonus_map bonuses_flat; From 6defa755ed024aaf5345981fb3404d12a10d77c2 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 1 Feb 2020 07:54:13 -0500 Subject: [PATCH 099/219] Add utf8_display_split function This splits a string into a sequence of displayed characters. --- src/catacharset.cpp | 20 ++++++++++++++++++++ src/catacharset.h | 7 ++++++- tests/catacharset_test.cpp | 20 ++++++++++++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/catacharset.cpp b/src/catacharset.cpp index 9e680990d6c1d..7ab89e40ed394 100644 --- a/src/catacharset.cpp +++ b/src/catacharset.cpp @@ -479,6 +479,26 @@ std::u32string utf8_to_utf32( const std::string &str ) return ret; } +std::vector utf8_display_split( const std::string &s ) +{ + std::vector result; + std::string current_glyph; + const char *pos = s.c_str(); + int len = s.length(); + while( len > 0 ) { + const char *old_pos = pos; + const uint32_t ch = UTF8_getch( &pos, &len ); + const int width = mk_wcwidth( ch ); + if( width > 0 && !current_glyph.empty() ) { + result.push_back( current_glyph ); + current_glyph.clear(); + } + current_glyph += std::string( old_pos, pos ); + } + result.push_back( current_glyph ); + return result; +} + int center_text_pos( const char *text, int start_pos, int end_pos ) { int full_screen = end_pos - start_pos + 1; diff --git a/src/catacharset.h b/src/catacharset.h index f7722a9d97ea3..d2c2c0aceb6e6 100644 --- a/src/catacharset.h +++ b/src/catacharset.h @@ -5,6 +5,7 @@ #include #include #include +#include #define ANY_LENGTH 5 #define NULL_UNICODE 0x0000 @@ -56,11 +57,15 @@ std::string utf8_to_native( const std::string &str ); std::string utf32_to_utf8( const std::u32string &str ); std::u32string utf8_to_utf32( const std::string &str ); +// Split the given string into displayed characters. Each element of the returned vector +// contains one 'regular' codepoint and all subsequent combining characters. +std::vector utf8_display_split( const std::string & ); + /** * UTF8-Wrapper over std::string. * It looks and feels like a std::string, but uses code points counts * as index, not bytes. - * A multi-byte Unicode character might by represented + * A multi-byte Unicode character might be represented * as 3 bytes in UTF8, this class will see these 3 bytes as 1 character. * It will never separate them. It will however split between code points * which might be problematic when containing combination characters. diff --git a/tests/catacharset_test.cpp b/tests/catacharset_test.cpp index cb04e52404e59..b353d30d37688 100644 --- a/tests/catacharset_test.cpp +++ b/tests/catacharset_test.cpp @@ -4,22 +4,34 @@ #include "catch/catch.hpp" #include "catacharset.h" -TEST_CASE( "utf8_width" ) +TEST_CASE( "utf8_width", "[catacharset]" ) { CHECK( utf8_width( "Hello, world!", false ) == 13 ); CHECK( utf8_width( "你好,世界!", false ) == 12 ); CHECK( utf8_width( "Hello, 世界!", false ) == 12 ); CHECK( utf8_width( "激活", true ) == 4 ); CHECK( utf8_width( "激活", false ) == 25 ); + CHECK( utf8_width( "à", false ) == 1 ); + CHECK( utf8_width( "y\u0300", false ) == 1 ); + CHECK( utf8_width( "à̸̠你⃫", false ) == 3 ); } -TEST_CASE( "base64" ) +TEST_CASE( "utf8_display_split", "[catacharset]" ) +{ + CHECK( utf8_display_split( "你好" ) == std::vector { "你", "好" } ); + CHECK( utf8_display_split( "à" ) == std::vector { "à" } ); + CHECK( utf8_display_split( "y\u0300" ) == std::vector { "y\u0300" } ); + CHECK( utf8_display_split( "à̸̠你⃫" ) == std::vector { "à̸̠", "你⃫" } ); + CHECK( utf8_display_split( " " ) == std::vector { " ", " ", " ", " " } ); +} + +TEST_CASE( "base64", "[catacharset]" ) { CHECK( base64_encode( "hello" ) == "#aGVsbG8=" ); CHECK( base64_decode( "#aGVsbG8=" ) == "hello" ); } -TEST_CASE( "utf8_to_wstr" ) +TEST_CASE( "utf8_to_wstr", "[catacharset]" ) { // std::mbstowcs' returning -1 workaround setlocale( LC_ALL, "" ); @@ -28,7 +40,7 @@ TEST_CASE( "utf8_to_wstr" ) CHECK( utf8_to_wstr( src ) == dest ); } -TEST_CASE( "wstr_to_utf8" ) +TEST_CASE( "wstr_to_utf8", "[catacharset]" ) { // std::wcstombs' returning -1 workaround setlocale( LC_ALL, "" ); From ee984415dafc74b7bae3017a0b3f7fbb85ecbabb Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 2 Feb 2020 10:48:17 -0500 Subject: [PATCH 100/219] Switch mapgen keys from ints to strings Using new facility to split strings into displayed chunks, allow mapgen to use arbitrary Unicode characters (including combining characters) as keys. --- src/mapgen.cpp | 87 ++++++++++++++++++++++++++++---------------------- src/mapgen.h | 35 +++++++++++++++++--- 2 files changed, 80 insertions(+), 42 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index c132880807012..f5827a3282bc1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -762,6 +762,20 @@ void jmapgen_place::offset( const point &offset ) y.valmax -= offset.y; } +map_key::map_key( const std::string &s ) : str( s ) +{ + if( utf8_width( str ) != 1 ) { + debugmsg( "map key '%s' must be 1 column", str ); + } +} + +map_key::map_key( const JsonMember &member ) : str( member.name() ) +{ + if( utf8_width( str ) != 1 ) { + member.throw_error( "format map key must be 1 column" ); + } +} + /** * This is a generic mapgen piece, the template parameter PieceType should be another specific * type of jmapgen_piece. This class contains a vector of those objects and will chose one of @@ -2036,16 +2050,13 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string { if( jo.has_object( "mapping" ) ) { for( const JsonMember member : jo.get_object( "mapping" ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } + const map_key key( member ); JsonObject sub = member.get_object(); sub.allow_omitted_members(); if( !sub.has_member( member_name ) ) { continue; } - auto &vect = format_placings[ key[0] ]; + auto &vect = format_placings[ key ]; ::load_place_mapings( sub.get_member( member_name ), vect ); } } @@ -2059,11 +2070,8 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string return; } for( const JsonMember member : jo.get_object( member_name ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } - auto &vect = format_placings[ key[0] ]; + const map_key key( member ); + auto &vect = format_placings[ key ]; ::load_place_mapings( member, vect ); } } @@ -2141,20 +2149,17 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s // "terrain": { "a": "t_grass", "b": "t_lava" } if( jo.has_member( "terrain" ) ) { for( const JsonMember member : jo.get_object( "terrain" ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } + const map_key key( member ); if( member.test_string() ) { - format_terrain[key[0]] = ter_id( member.get_string() ); + format_terrain[key] = ter_id( member.get_string() ); } else { - auto &vect = format_placings[ key[0] ]; + auto &vect = format_placings[ key ]; ::load_place_mapings( member, vect ); if( !vect.empty() ) { // Dummy entry to signal that this terrain is actually defined, because // the code below checks that each square on the map has a valid terrain // defined somehow. - format_terrain[key[0]] = t_null; + format_terrain[key] = t_null; } } } @@ -2162,14 +2167,11 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s if( jo.has_object( "furniture" ) ) { for( const JsonMember member : jo.get_object( "furniture" ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } + const map_key key( member ); if( member.test_string() ) { - format_furniture[key[0]] = furn_id( member.get_string() ); + format_furniture[key] = furn_id( member.get_string() ); } else { - auto &vect = format_placings[ key[0] ]; + auto &vect = format_placings[ key ]; ::load_place_mapings( member, vect ); } } @@ -2307,27 +2309,35 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) return false; } - // mandatory: mapgensize rows of mapgensize character lines, each of which must have a matching key in "terrain", - // unless fill_ter is set + // mandatory: mapgensize rows of mapgensize character lines, each of which must have a + // matching key in "terrain", unless fill_ter is set // "rows:" [ "aaaajustlikeinmapgen.cpp", "this.must!be!exactly.24!", "and_must_match_terrain_", .... ] point expected_dim = mapgensize + m_offset; + assert( expected_dim.x >= 0 ); + assert( expected_dim.y >= 0 ); + parray = jo.get_array( "rows" ); if( static_cast( parray.size() ) < expected_dim.y ) { parray.throw_error( string_format( "format: rows: must have at least %d rows, not %d", expected_dim.y, parray.size() ) ); } for( int c = m_offset.y; c < expected_dim.y; c++ ) { - const auto tmpval = parray.get_string( c ); - if( static_cast( tmpval.size() ) < expected_dim.x ) { - parray.throw_error( string_format( "format: row %d must have at least %d columns, not %d", - c + 1, expected_dim.x, tmpval.size() ) ); + const std::string row = parray.get_string( c ); + std::vector row_keys; + for( const std::string &key : utf8_display_split( row ) ) { + row_keys.emplace_back( key ); + } + if( row_keys.size() < static_cast( expected_dim.x ) ) { + parray.throw_error( + string_format( " format: row %d must have at least %d columns, not %d", + c + 1, expected_dim.x, row_keys.size() ) ); } for( int i = m_offset.x; i < expected_dim.x; i++ ) { const point p = point( i, c ) - m_offset; - const int tmpkey = tmpval[i]; - const auto iter_ter = format_terrain.find( tmpkey ); - const auto iter_furn = format_furniture.find( tmpkey ); - const auto fpi = format_placings.find( tmpkey ); + const map_key key = row_keys[i]; + const auto iter_ter = format_terrain.find( key ); + const auto iter_furn = format_furniture.find( key ); + const auto fpi = format_placings.find( key ); const bool has_terrain = iter_ter != format_terrain.end(); const bool has_furn = iter_furn != format_furniture.end(); @@ -2336,18 +2346,19 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) if( !has_terrain && !fallback_terrain_exists ) { parray.throw_error( string_format( "format: rows: row %d column %d: " - "'%c' is not in 'terrain', and no 'fill_ter' is set!", - c + 1, i + 1, static_cast( tmpkey ) ) ); + "'%s' is not in 'terrain', and no 'fill_ter' is set!", + c + 1, i + 1, key.str ) ); } - if( test_mode && !has_terrain && !has_furn && !has_placing && tmpkey != ' ' && tmpkey != '.' ) { + if( test_mode && !has_terrain && !has_furn && !has_placing && + key.str != " " && key.str != "." ) { // TODO: Once all the in-tree mods don't report this error, // it should be changed to happen in regular games (not // just test_mode) and be non-fatal, so that mappers find // out about their issues before they PR their changes. parray.throw_error( string_format( "format: rows: row %d column %d: " - "'%c' has no terrain, furniture, or other definition", - c + 1, i + 1, static_cast( tmpkey ) ) ); + "'%s' has no terrain, furniture, or other definition", + c + 1, i + 1, key.str ) ); } if( has_terrain ) { format[ calc_index( p ) ].ter = iter_ter->second; diff --git a/src/mapgen.h b/src/mapgen.h index 8e051518b3673..e7355c75354f2 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -181,19 +181,46 @@ class jmapgen_place using palette_id = std::string; +// Strong typedef for strings used as map/palette keys +// Each key should be a UTF-8 string displayed in only one column (i.e. +// utf8_width of 1) but can contain multiple Unicode code points. +class map_key +{ + public: + map_key( const std::string & ); + map_key( const JsonMember & ); + + friend bool operator==( const map_key &l, const map_key &r ) { + return l.str == r.str; + } + + std::string str; +}; + +namespace std +{ +template<> +struct hash { + size_t operator()( const map_key &k ) const noexcept { + return hash {}( k.str ); + } +}; +} // namespace std + class mapgen_palette { public: palette_id id; /** - * The mapping from character code (key) to a list of things that should be placed. This is + * The mapping from character (key) to a list of things that should be placed. This is * similar to objects, but it uses key to get the actual position where to place things * out of the json "bitmap" (which is used to paint the terrain/furniture). */ - using placing_map = std::map< int, std::vector< shared_ptr_fast > >; + using placing_map = + std::unordered_map>>; - std::map format_terrain; - std::map format_furniture; + std::unordered_map format_terrain; + std::unordered_map format_furniture; placing_map format_placings; template From 696f88260a7030003dc8b829343934c963cfc2bb Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 8 Feb 2020 21:51:29 -0500 Subject: [PATCH 101/219] Test Unicode mapgen with bookcases in house_w MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace bookcase symbol in the house_w_nest_palette with a Unicode symbol that looks similar to a bookcase (▤). --- data/json/mapgen/nested/house_nested.json | 50 +++++++++---------- .../json/mapgen_palettes/house_w_palette.json | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/data/json/mapgen/nested/house_nested.json b/data/json/mapgen/nested/house_nested.json index ffd95d71e5cbb..032ef11d11771 100644 --- a/data/json/mapgen/nested/house_nested.json +++ b/data/json/mapgen/nested/house_nested.json @@ -467,7 +467,7 @@ "mapgensize": [ 4, 4 ], "rotation": [ 0, 3 ], "rows": [ - " CR ", + " C▤ ", "O ", " EE ", " EE " @@ -476,7 +476,7 @@ "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -492,13 +492,13 @@ " EE ", " EE ", "O ", - " CR " + " C▤ " ], "palettes": [ "house_w_nest_palette" ], "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -513,14 +513,14 @@ "rows": [ " ", "C EE", - "R EE", + "▤ EE", " O " ], "palettes": [ "house_w_nest_palette" ], "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -535,14 +535,14 @@ "rows": [ " ", "EE C", - "EE R", + "EE ▤", " O " ], "palettes": [ "house_w_nest_palette" ], "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -704,7 +704,7 @@ " ", "EE I", "L AI", - "y R", + "y ▤", "OCy " ], "palettes": [ "house_w_nest_palette" ], @@ -713,7 +713,7 @@ "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } } } }, @@ -729,8 +729,8 @@ " OO ", "IB L", "I EE", - "y R", - "RCa " + "y ▤", + "▤Ca " ], "palettes": [ "house_w_nest_palette" ], "items": { @@ -739,7 +739,7 @@ "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } } } }, @@ -1023,8 +1023,8 @@ "rotation": [ 0, 3 ], "rows": [ " @@p ", - " R", - " pp R", + " ▤", + " pp ▤", " ", " xxx " ], @@ -1118,11 +1118,11 @@ "mapgensize": [ 2, 2 ], "rotation": [ 0, 3 ], "rows": [ - "RR", + "▤▤", "C " ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { @@ -1135,10 +1135,10 @@ "rotation": [ 0, 3 ], "rows": [ "C ", - "R " + "▤ " ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { @@ -1151,10 +1151,10 @@ "rotation": [ 0, 3 ], "rows": [ " C", - "HR" + "H▤" ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { @@ -1230,12 +1230,12 @@ "mapgensize": [ 3, 3 ], "rotation": [ 0, 3 ], "rows": [ - "R H", - "RC ", - "R " + "▤ H", + "▤C ", + "▤ " ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { diff --git a/data/json/mapgen_palettes/house_w_palette.json b/data/json/mapgen_palettes/house_w_palette.json index 7d83fa5b9f07c..1cf6d42e0ae3b 100644 --- a/data/json/mapgen_palettes/house_w_palette.json +++ b/data/json/mapgen_palettes/house_w_palette.json @@ -22,7 +22,7 @@ "O": "f_dresser", "P": "f_locker", "Q": "f_rack", - "R": "f_bookcase", + "▤": "f_bookcase", "S": [ [ "f_filing_cabinet", 80 ], [ "f_shredder", 20 ] ], "U": "f_utility_shelf", "V": "f_glass_cabinet", From cc221dc15843a100d267ac84ed9414cb905af8ed Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 19 Feb 2020 04:45:10 -0500 Subject: [PATCH 102/219] Document the Unicode mapgen support --- doc/MAPGEN.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index 2f5b1fbee289c..c6b62497b6cc7 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -197,9 +197,11 @@ Example: "fill_ter": "t_grass" *required if "fill_ter" is unset* > Value: ([array]): blocks of 24 rows of blocks of 24 character lines. Each character is defined by "terrain" and optionally "furniture" or other entries below +Other parts can be linked with this map, for example one can place things like a gaspump (with gasoline) or a toilet (with water) or items from an item group or fields at the square given by a character. + Any character used here must have some definition elsewhere to indicate its purpose. Failing to do so is an error which will be caught by running the tests. The tests will run automatically when you make a pull request for adding new maps to the game. If you have defined `fill_ter` or you are writing nested mapgen, then there are a couple of exceptions. The space and period characters (` ` and `.`) are permitted to have no definition and be used for 'background' in the `rows`. -Other parts can be linked with this map, for example one can place things like a gaspump (with gasoline) or a toilet (with water) or items from an item group or fields at the square given by a character. +As keys, you can use any Unicode characters which are not double-width. This includes for example most European alphabets but not Chinese characters. If you intend to take advantage of this, ensure that your editor is saving the file with a UTF-8 encoding. Accents are acceptable, even when using [combining characters](https://en.wikipedia.org/wiki/Combining_character). No normalization is performed; comparison is done at the raw bytes (code unit) level. Therefore, there are literally an infinite number of mapgen key characters available. Please don't abuse this by using distinct characters that are visually indistinguishable, or which are so rare as to be unlikely to render correctly for other developers. Example: From 6d0d0e401a71f76bb9db62fb2181c1cbca8314d5 Mon Sep 17 00:00:00 2001 From: akozhevn Date: Tue, 17 Mar 2020 04:54:32 -0400 Subject: [PATCH 103/219] Advanced inv save settings (#35239) --- src/advanced_inv.cpp | 89 +++++++++-------------- src/advanced_inv.h | 5 +- src/advanced_inv_pane.cpp | 30 ++++++++ src/advanced_inv_pane.h | 9 ++- src/uistate.h | 148 +++++++++++++++++++------------------- 5 files changed, 145 insertions(+), 136 deletions(-) diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 76447402ed75e..baa59d70f9931 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -109,23 +109,23 @@ advanced_inventory::advanced_inventory() } } ) { + save_state = &uistate.transfer_save; } // *INDENT-ON* advanced_inventory::~advanced_inventory() { save_settings( false ); - auto &aim_code = uistate.adv_inv_exit_code; - if( aim_code != exit_re_entry ) { - aim_code = exit_okay; + if( save_state->exit_code != exit_re_entry ) { + save_state->exit_code = exit_okay; } // Only refresh if we exited manually, otherwise we're going to be right back if( exit ) { werase( head ); werase( minimap ); werase( mm_border ); - werase( left_window ); - werase( right_window ); + werase( panes[left].window ); + werase( panes[right].window ); g->refresh_all(); g->u.check_item_encumbrance_flag(); } @@ -134,44 +134,19 @@ advanced_inventory::~advanced_inventory() void advanced_inventory::save_settings( bool only_panes ) { if( !only_panes ) { - uistate.adv_inv_last_coords = g->u.pos(); - uistate.adv_inv_src = src; - uistate.adv_inv_dest = dest; + save_state->active_left = ( src == left ); } for( int i = 0; i < NUM_PANES; ++i ) { - uistate.adv_inv_in_vehicle[i] = panes[i].in_vehicle(); - uistate.adv_inv_area[i] = panes[i].get_area(); - uistate.adv_inv_index[i] = panes[i].index; - uistate.adv_inv_filter[i] = panes[i].filter; - uistate.adv_inv_sort[i] = panes[i].sortby; + panes[i].save_settings(); } } void advanced_inventory::load_settings() { - aim_exit aim_code = static_cast( uistate.adv_inv_exit_code ); - for( int i = 0; i < NUM_PANES; ++i ) { - aim_location location; - if( get_option( "OPEN_DEFAULT_ADV_INV" ) ) { - location = static_cast( uistate.adv_inv_default_areas[i] ); - } else { - location = static_cast( uistate.adv_inv_area[i] ); - } - auto square = squares[location]; - // determine the square's vehicle/map item presence - bool has_veh_items = square.can_store_in_vehicle() ? - !square.veh->get_items( square.vstor ).empty() : false; - bool has_map_items = !g->m.i_at( square.pos ).empty(); - // determine based on map items and settings to show cargo - bool show_vehicle = aim_code == exit_re_entry ? - uistate.adv_inv_in_vehicle[i] : has_veh_items ? true : - has_map_items ? false : square.can_store_in_vehicle(); - panes[i].set_area( square, show_vehicle ); - panes[i].sortby = static_cast( uistate.adv_inv_sort[i] ); - panes[i].index = uistate.adv_inv_index[i]; - panes[i].filter = uistate.adv_inv_filter[i]; - } - uistate.adv_inv_exit_code = exit_none; + aim_exit aim_code = static_cast( save_state->exit_code ); + panes[left].load_settings( save_state->saved_area, squares, aim_code == exit_re_entry ); + panes[right].load_settings( save_state->saved_area_right, squares, aim_code == exit_re_entry ); + save_state->exit_code = exit_none; } std::string advanced_inventory::get_sortname( advanced_inv_sortby sortby ) @@ -232,10 +207,13 @@ void advanced_inventory::init() square.init(); } + panes[left].save_state = &save_state->pane; + panes[right].save_state = &save_state->pane_right; + load_settings(); - src = static_cast( uistate.adv_inv_src ); - dest = static_cast( uistate.adv_inv_dest ); + src = ( save_state->active_left ) ? left : right; + dest = ( save_state->active_left ) ? right : left; w_height = TERMY < min_w_height + head_height ? min_w_height : TERMY - head_height; w_width = TERMX < min_w_width ? min_w_width : TERMX > max_w_width ? max_w_width : @@ -250,16 +228,13 @@ void advanced_inventory::init() point( colstart + ( w_width - ( minimap_width + 2 ) ), headstart ) ); minimap = catacurses::newwin( minimap_height, minimap_width, point( colstart + ( w_width - ( minimap_width + 1 ) ), headstart + 1 ) ); - left_window = catacurses::newwin( w_height, w_width / 2, point( colstart, - headstart + head_height ) ); - right_window = catacurses::newwin( w_height, w_width / 2, point( colstart + w_width / 2, - headstart + head_height ) ); + panes[left].window = catacurses::newwin( w_height, w_width / 2, point( colstart, + headstart + head_height ) ); + panes[right].window = catacurses::newwin( w_height, w_width / 2, point( colstart + w_width / 2, + headstart + head_height ) ); // 2 for the borders, 5 for the header stuff itemsPerPage = w_height - 2 - 5; - - panes[left].window = left_window; - panes[right].window = right_window; } void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool active ) @@ -795,9 +770,9 @@ bool advanced_inventory::move_all_items( bool nested_call ) advanced_inventory_pane shadow = panes[src]; // here we recursively call this function with each area in order to // put all items in the proper destination area, with minimal fuss - int &loc = uistate.adv_inv_aim_all_location; + int &loc = save_state->aim_all_location; // re-entry nonsense - int &entry = uistate.adv_inv_re_enter_move_all; + int &entry = save_state->re_enter_move_all; // if we are just starting out, set entry to initial value switch( static_cast( entry++ ) ) { case ENTRY_START: @@ -1134,7 +1109,8 @@ void advanced_inventory::display() left, right } ) { auto &pane = panes[cside]; - aim_location location = static_cast( uistate.adv_inv_default_areas[cside] ); + int i_location = cside == left ? save_state->saved_area : save_state->saved_area_right; + aim_location location = static_cast( i_location ); if( pane.get_area() != location || location == AIM_ALL ) { pane.recalc = true; } @@ -1142,8 +1118,8 @@ void advanced_inventory::display() } redraw = true; } else if( action == "SAVE_DEFAULT" ) { - uistate.adv_inv_default_areas[left] = panes[left].get_area(); - uistate.adv_inv_default_areas[right] = panes[right].get_area(); + save_state->saved_area = panes[left].get_area(); + save_state->saved_area_right = panes[right].get_area(); popup( _( "Default layout was saved." ) ); redraw = true; } else if( get_square( action, changeSquare ) ) { @@ -1352,7 +1328,6 @@ void advanced_inventory::display() } else if( action == "SORT" ) { if( show_sort_menu( spane ) ) { recalc = true; - uistate.adv_inv_sort[src] = spane.sortby; } redraw = true; } else if( action == "FILTER" ) { @@ -1575,7 +1550,7 @@ bool advanced_inventory::query_destination( aim_location &def ) } } // Selected keyed to uilist.entries, which starts at 0. - menu.selected = uistate.adv_inv_last_popup_dest - AIM_SOUTHWEST; + menu.selected = save_state->last_popup_dest - AIM_SOUTHWEST; // generate and show window. menu.show(); // query, but don't loop @@ -1590,7 +1565,7 @@ bool advanced_inventory::query_destination( aim_location &def ) // we have to set the destination pane so that move actions will target it // we can use restore_area later to undo this panes[dest].set_area( squares[def], true ); - uistate.adv_inv_last_popup_dest = menu.ret; + save_state->last_popup_dest = menu.ret; return true; } return false; @@ -1839,6 +1814,8 @@ void advanced_inventory::swap_panes() { // Switch left and right pane. std::swap( panes[left], panes[right] ); + // Switch save states + std::swap( panes[left].save_state, panes[right].save_state ); // Window pointer must be unchanged! std::swap( panes[left].window, panes[right].window ); // Recalculation required for weight & volume @@ -1852,15 +1829,15 @@ void advanced_inventory::do_return_entry() save_settings( true ); g->u.assign_activity( ACT_ADV_INVENTORY ); g->u.activity.auto_resume = true; - uistate.adv_inv_exit_code = exit_re_entry; + save_state->exit_code = exit_re_entry; } bool advanced_inventory::is_processing() const { - return uistate.adv_inv_re_enter_move_all != ENTRY_START; + return save_state->re_enter_move_all != ENTRY_START; } void cancel_aim_processing() { - uistate.adv_inv_re_enter_move_all = ENTRY_START; + uistate.transfer_save.re_enter_move_all = ENTRY_START; } diff --git a/src/advanced_inv.h b/src/advanced_inv.h index 78605f1b2dd05..ea081c6799dfd 100644 --- a/src/advanced_inv.h +++ b/src/advanced_inv.h @@ -17,6 +17,8 @@ class uilist; class vehicle; class item; +struct advanced_inv_save_state; + struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { bool operator()( char x, char y ) const { return toupper( static_cast< unsigned char >( x ) ) < toupper( static_cast< unsigned char >( y ) ); @@ -108,11 +110,10 @@ class advanced_inventory std::array squares; catacurses::window head; - catacurses::window left_window; - catacurses::window right_window; bool exit = false; + advanced_inv_save_state *save_state; // store/load settings (such as index, filter, etc) void save_settings( bool only_panes ); void load_settings(); diff --git a/src/advanced_inv_pane.cpp b/src/advanced_inv_pane.cpp index 067b682e92ba9..11468080586ba 100644 --- a/src/advanced_inv_pane.cpp +++ b/src/advanced_inv_pane.cpp @@ -29,6 +29,7 @@ #include "advanced_inv_pane.h" #include "vehicle.h" #include "map.h" +#include "options.h" #include #include @@ -44,6 +45,35 @@ #if defined(__ANDROID__) # include #endif +void advanced_inventory_pane::save_settings() +{ + save_state->in_vehicle = in_vehicle(); + save_state->area_idx = get_area(); + save_state->selected_idx = index; + save_state->filter = filter; + save_state->sort_idx = sortby; +} + +void advanced_inventory_pane::load_settings( int saved_area_idx, + const std::array &squares, bool is_re_enter ) +{ + const int i_location = ( get_option( "OPEN_DEFAULT_ADV_INV" ) ) ? saved_area_idx : + save_state->area_idx; + const aim_location location = static_cast( i_location ); + auto square = squares[location]; + // determine the square's vehicle/map item presence + bool has_veh_items = square.can_store_in_vehicle() ? + !square.veh->get_items( square.vstor ).empty() : false; + bool has_map_items = !g->m.i_at( square.pos ).empty(); + // determine based on map items and settings to show cargo + bool show_vehicle = is_re_enter ? + save_state->in_vehicle : has_veh_items ? true : + has_map_items ? false : square.can_store_in_vehicle(); + set_area( square, show_vehicle ); + sortby = static_cast( save_state->sort_idx ); + index = save_state->selected_idx; + filter = save_state->filter; +} bool advanced_inventory_pane::is_filtered( const advanced_inv_listitem &it ) const { diff --git a/src/advanced_inv_pane.h b/src/advanced_inv_pane.h index e20d91843c4ac..86c1e4b672643 100644 --- a/src/advanced_inv_pane.h +++ b/src/advanced_inv_pane.h @@ -10,6 +10,8 @@ #include #include +struct advanced_inv_pane_save_state; + enum aim_location : char; enum advanced_inv_sortby { @@ -57,9 +59,10 @@ class advanced_inventory_pane bool in_vehicle() const { return viewing_cargo; } - bool on_ground() const { - return area > AIM_INVENTORY && area < AIM_DRAGGED; - } + advanced_inv_pane_save_state *save_state; + void save_settings(); + void load_settings( int saved_area_idx, + const std::array &squares, bool is_re_enter ); /** * Index of the selected item (index of @ref items), */ diff --git a/src/uistate.h b/src/uistate.h index 8a70e4e9f0777..aea5f15eeeb94 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -14,6 +14,71 @@ class item; + +struct advanced_inv_pane_save_state { + public: + int sort_idx = 1; + std::string filter; + int area_idx = 11; + int selected_idx = 0; + + bool in_vehicle = false; + + template + void serialize( JsonStream &json, std::string prefix ) const { + json.member( prefix + "sort_idx", sort_idx ); + json.member( prefix + "filter", filter ); + json.member( prefix + "area_idx", area_idx ); + json.member( prefix + "selected_idx", selected_idx ); + json.member( prefix + "in_vehicle", in_vehicle ); + } + + void deserialize( JsonObject &jo, std::string prefix ) { + jo.read( prefix + "sort_idx", sort_idx ); + jo.read( prefix + "filter", filter ); + jo.read( prefix + "area_idx", area_idx ); + jo.read( prefix + "selected_idx", selected_idx ); + jo.read( prefix + "in_vehicle", in_vehicle ); + } +}; + +struct advanced_inv_save_state { + public: + int exit_code = 0; + int re_enter_move_all = 0; + int aim_all_location = 1; + + bool active_left = true; + int last_popup_dest = 0; + + int saved_area = 11; + int saved_area_right = 0; + advanced_inv_pane_save_state pane; + advanced_inv_pane_save_state pane_right; + + template + void serialize( JsonStream &json, std::string prefix ) const { + json.member( prefix + "active_left", active_left ); + json.member( prefix + "last_popup_dest", last_popup_dest ); + + json.member( prefix + "saved_area", saved_area ); + json.member( prefix + "saved_area_right", saved_area_right ); + pane.serialize( json, prefix + "pane_" ); + pane_right.serialize( json, prefix + "pane_right_" ); + } + + void deserialize( JsonObject &jo, std::string prefix ) { + jo.read( prefix + "active_left", active_left ); + jo.read( prefix + "last_popup_dest", last_popup_dest ); + + jo.read( prefix + "saved_area", saved_area ); + jo.read( prefix + "saved_area_right", saved_area_right ); + pane.area_idx = saved_area; + pane_right.area_idx = saved_area_right; + pane.deserialize( jo, prefix + "pane_" ); + pane_right.deserialize( jo, prefix + "pane_right_" ); + } +}; /* centralized depot for trivial ui data such as sorting, string_input_popup history, etc. To use this, see the ****notes**** below @@ -27,7 +92,7 @@ class uistatedata private: // not needed for compilation, but keeps syntax plugins happy using itype_id = std::string; - enum side { left = 0, right = 1, NUM_PANES = 2 }; + enum side { left = 0, right = 1, NUM_PANES = 2 }; public: int ags_pay_gas_selected_pump = 0; @@ -35,25 +100,15 @@ class uistatedata int wishmutate_selected = 0; int wishmonster_selected = 0; int iexamine_atm_selected = 0; - std::array adv_inv_sort = {{1, 1}}; - std::array adv_inv_area = {{5, 0}}; - std::array adv_inv_index = {{0, 0}}; - std::array adv_inv_in_vehicle = {{false, false}}; - std::array adv_inv_filter = {{"", ""}}; - std::array adv_inv_default_areas = {{11, 0}}; //left: All, right: Inventory - int adv_inv_src = left; - int adv_inv_dest = right; - int adv_inv_last_popup_dest = 0; + int adv_inv_container_location = -1; int adv_inv_container_index = 0; - int adv_inv_exit_code = 0; itype_id adv_inv_container_type = "null"; itype_id adv_inv_container_content_type = "null"; - int adv_inv_re_enter_move_all = 0; - int adv_inv_aim_all_location = 1; - std::map> adv_inv_veh_items, adv_inv_map_items; bool adv_inv_container_in_vehicle = false; + advanced_inv_save_state transfer_save; + bool editmap_nsa_viewmode = false; // true: ignore LOS and lighting bool overmap_blinking = true; // toggles active blinking of overlays. bool overmap_show_overlays = false; // whether overlays are shown or not. @@ -63,11 +118,6 @@ class uistatedata bool overmap_show_hordes = true; bool overmap_show_forest_trails = true; - bool debug_ranged = false; - tripoint adv_inv_last_coords = {-999, -999, -999}; - int last_inv_start = -2; - int last_inv_sel = -2; - // V Menu Stuff int list_item_sort = 0; std::string list_item_filter; @@ -125,17 +175,10 @@ class uistatedata const unsigned int input_history_save_max = 25; json.start_object(); + transfer_save.serialize( json, "transfer_save_" ); + /**** if you want to save whatever so it's whatever when the game is started next, declare here and.... ****/ - serialize_array( json, "adv_inv_sort", adv_inv_sort ); - serialize_array( json, "adv_inv_area", adv_inv_area ); - serialize_array( json, "adv_inv_index", adv_inv_index ); - serialize_array( json, "adv_inv_in_vehicle", adv_inv_in_vehicle ); - serialize_array( json, "adv_inv_filter", adv_inv_filter ); - serialize_array( json, "adv_inv_default_areas", adv_inv_default_areas ); // non array stuffs - json.member( "adv_inv_src", adv_inv_src ); - json.member( "adv_inv_dest", adv_inv_dest ); - json.member( "adv_inv_last_popup_dest", adv_inv_last_popup_dest ); json.member( "adv_inv_container_location", adv_inv_container_location ); json.member( "adv_inv_container_index", adv_inv_container_index ); json.member( "adv_inv_container_in_vehicle", adv_inv_container_in_vehicle ); @@ -182,54 +225,9 @@ class uistatedata template void deserialize( JsonStream &jsin ) { auto jo = jsin.get_object(); - /**** here ****/ - if( jo.has_array( "adv_inv_sort" ) ) { - auto tmp = jo.get_int_array( "adv_inv_sort" ); - std::move( tmp.begin(), tmp.end(), adv_inv_sort.begin() ); - } else { - jo.read( "adv_inv_leftsort", adv_inv_sort[left] ); - jo.read( "adv_inv_rightsort", adv_inv_sort[right] ); - } - // pane area selected - if( jo.has_array( "adv_inv_area" ) ) { - auto tmp = jo.get_int_array( "adv_inv_area" ); - std::move( tmp.begin(), tmp.end(), adv_inv_area.begin() ); - } else { - jo.read( "adv_inv_leftarea", adv_inv_area[left] ); - jo.read( "adv_inv_rightarea", adv_inv_area[right] ); - } - // pane current index - if( jo.has_array( "adv_inv_index" ) ) { - auto tmp = jo.get_int_array( "adv_inv_index" ); - std::move( tmp.begin(), tmp.end(), adv_inv_index.begin() ); - } else { - jo.read( "adv_inv_leftindex", adv_inv_index[left] ); - jo.read( "adv_inv_rightindex", adv_inv_index[right] ); - } - // viewing vehicle cargo - if( jo.has_array( "adv_inv_in_vehicle" ) ) { - const JsonArray ja = jo.get_array( "adv_inv_in_vehicle" ); - for( size_t i = 0; i < adv_inv_in_vehicle.size() && i < ja.size(); ++i ) { - adv_inv_in_vehicle[i] = ja.get_bool( i ); - } - } - // filter strings - if( jo.has_array( "adv_inv_filter" ) ) { - auto tmp = jo.get_string_array( "adv_inv_filter" ); - std::move( tmp.begin(), tmp.end(), adv_inv_filter.begin() ); - } else { - jo.read( "adv_inv_leftfilter", adv_inv_filter[left] ); - jo.read( "adv_inv_rightfilter", adv_inv_filter[right] ); - } - // default areas - if( jo.has_array( "adv_inv_deafult_areas" ) ) { - auto tmp = jo.get_int_array( "adv_inv_deafult_areas" ); - std::move( tmp.begin(), tmp.end(), adv_inv_default_areas.begin() ); - } + + transfer_save.deserialize( jo, "transfer_save_" ); // the rest - jo.read( "adv_inv_src", adv_inv_src ); - jo.read( "adv_inv_dest", adv_inv_dest ); - jo.read( "adv_inv_last_popup_dest", adv_inv_last_popup_dest ); jo.read( "adv_inv_container_location", adv_inv_container_location ); jo.read( "adv_inv_container_index", adv_inv_container_index ); jo.read( "adv_inv_container_in_vehicle", adv_inv_container_in_vehicle ); From ae5930fdc19723def97f9b28ac85c5c41dc6bc5b Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Sun, 15 Mar 2020 14:55:50 +0300 Subject: [PATCH 104/219] Refluff power armour and adjust stats slightly (#37578) --- data/json/items/armor/power_armor.json | 49 +++++++++++++------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/data/json/items/armor/power_armor.json b/data/json/items/armor/power_armor.json index 9749a669768af..f19ed171154cb 100644 --- a/data/json/items/armor/power_armor.json +++ b/data/json/items/armor/power_armor.json @@ -5,7 +5,7 @@ "category": "armor", "name": { "str": "salvaged power armor" }, "//": "These are much cheaper than powered suits, because they're extremely heavy and impractical. The good stuff is gone!", - "description": "The DoubleTech Power Armor, Mk. I: A heavy suit of basic power armor, offering very good protection against attacks, but hard to move in. This suit has had its servos and cooling system stripped out, meaning it no longer requires power, but also encumbers you greatly and doesn't provide internal thermal regulation.", + "description": "This used to be a powered exoskeleton with a set of heavy armor plates, made wearable by the assist of the servos. Now it's just the armor plating and a stripped down chassis: as one might expect, it's a lot harder to wear.", "weight": "12214 g", "volume": "25 L", "price": 70000, @@ -30,7 +30,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "salvaged power armor helmet" }, - "description": "A basic helmet, designed for use with the DoubleTech Power Armor, Mk. I. Offers excellent protection from both attacks and environmental hazards. This suit has had its internal computer and cooling system stripped out, meaning it no longer requires power, but it has no internal chronometer and doesn't provide internal thermal regulation.", + "description": "This used to be a military-grade full-head helmet with advanced optics and environmental filters. It looks like it was decommissioned or otherwise stripped for parts; now it's a very expensive hat. It's still quite durable, but quite hard to see out of.", "weight": "2416 g", "volume": "5 L", "price": 30000, @@ -54,15 +54,15 @@ "id": "power_armor_basic", "type": "ARMOR", "category": "armor", - "name": { "str": "basic power armor" }, - "description": "The DoubleTech Power Armor, Mk. I: A heavy suit of basic power armor, offering very good protection against attacks, but hard to move in. The UPS compartment can store other things if you don't mind powering the suit yourself. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", - "weight": "20339 g", - "volume": "25 L", + "name": { "str": "combat exoskeleton" }, + "description": "These were the second wave of military combat exoskeleton, and got a lot of media attention, with popular Navy commercials featuring them heavily. It consists of a muscle-boosting exoskeleton frame with overlayed segmented alloy plating. Despite advancements over the original bulky 'tank suits', the wearer still cannot easily fit through narrow spaces, or sit down comfortably (and it ruins upholstery). There is an integrated chemical resistant bodyglove that precludes wearing other clothing.", + "weight": "55 kg", + "volume": "100 L", "price": 7000000, "price_postapoc": 7000000, "to_hit": 1, "bashing": 1, - "material": [ "steel" ], + "material": [ "hardsteel", "steel" ], "symbol": "[", "looks_like": "depowered_armor", "color": "light_gray", @@ -82,7 +82,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "power armor hauling frame" }, - "description": "A heavy-duty hauling frame designed to interface with power armor.", + "description": "A heavy duty hauling frame designed to interface with military exoskeletons.", "weight": "1640 g", "volume": "12 L", "price": 1000000, @@ -104,10 +104,11 @@ "id": "power_armor_heavy", "type": "ARMOR", "category": "armor", - "name": { "str": "heavy power armor" }, - "description": "A suit of DoubleTech Power Armor, Mk. II-H. This model offers several improvements over the Mk. I, most notably the improved environmental protection. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", - "weight": "29009 g", - "volume": "30 L", + "name": { "str": "heavy combat exoskeleton" }, + "description": "Colloquially known as a 'tank suit' in the media, these bulky exoskeletons, covered in thick segmented armor plates, were tested in military service a few years back and determined to be too heavy and expensive for regular use. Now that it's in your hands, though, you have a massive suit of power armor capable of resisting almost any small arms fire and most other forms of attack. On the other hand, it doubles your effective weight, and it's almost impossible not to bump into things. There is an integrated chemical resistant bodyglove that precludes wearing other clothing.", + "//": "This should probably changed to a pseudo-vehicle like the civilian exoskeleton", + "weight": "75 kg", + "volume": "130 L", "price": 11500000, "price_postapoc": 11500000, "to_hit": 1, @@ -131,15 +132,15 @@ "id": "power_armor_helmet_basic", "type": "ARMOR", "category": "armor", - "name": { "str": "basic power armor helmet" }, - "description": "A basic helmet, designed for use with the DoubleTech Power Armor, Mk. I. Offers excellent protection from both attacks and environmental hazards. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", + "name": { "str": "environmental combat helmet" }, + "description": "A fully enclosed combat helmet for hazardous environments, this was designed to fit with a powered exoskeleton, using cameras to expand visual range. In practice, the cameras were unreliable and easily fouled. The environmental controls function best with direct-skin contact.", "weight": "3628 g", "volume": "5 L", "price": 2500000, "price_postapoc": 2500000, "to_hit": 1, "bashing": 1, - "material": [ "steel" ], + "material": [ "hardsteel", "steel" ], "symbol": "[", "looks_like": "depowered_helmet", "color": "light_gray", @@ -157,8 +158,8 @@ "id": "power_armor_helmet_heavy", "type": "ARMOR", "category": "armor", - "name": { "str": "heavy power armor helmet" }, - "description": "A power armor helmet designed for use with the DoubleTech Power Armor, Mk. II-H. This improved design is heavier than the Mk. I helmet, but cooler, and offers better environmental protection. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", + "name": { "str": "heavy environmental combat helmet" }, + "description": "An extremely heavy-duty fully enclosed combat helmet for hazardous environments, this was designed to fit with a powered exoskeleton. In the field, soldiers reported that the protection was not worth the awkward size and limited visuals. The environmental controls function best with direct-skin contact.", "weight": "5442 g", "volume": "7 L", "price": 3750000, @@ -183,8 +184,8 @@ "id": "power_armor_helmet_light", "type": "ARMOR", "category": "armor", - "name": { "str": "light power armor helmet" }, - "description": "A power armor helmet designed for use with the DoubleTech Power Armor, Mk. II-L. This improved design is lighter and cooler than the Mk. I helmet. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", + "name": { "str": "light environmental combat helmet" }, + "description": "This full-enclosure helmet was designed based on commercial diving equipment, in response to complaints that earlier designs were impossible to use in combat. While still a little more restrictive than regular combat headgear - and frustrating should your nose itch - this one received far better reviews from soldiers. Sadly, civilization ended before they could roll out in significant numbers. The environmental controls function best with direct-skin contact.", "weight": "1814 g", "volume": "4 L", "price": 3750000, @@ -202,16 +203,16 @@ "power_armor": true, "material_thickness": 9, "environmental_protection": 16, - "qualities": [ [ "GLARE", 2 ] ], - "flags": [ "WATCH", "WATERPROOF", "STURDY", "PARTIAL_DEAF", "THERMOMETER", "SUN_GLASSES" ] + "qualities": [ [ "GLARE", 1 ] ], + "flags": [ "WATCH", "WATERPROOF", "STURDY", "THERMOMETER", "SUN_GLASSES" ] }, { "id": "power_armor_light", "type": "ARMOR", "category": "armor", - "name": { "str": "light power armor" }, - "description": "A suit of DoubleTech Power Armor, Mk. II-L. This model offers several improvements over the Mk. I, most notably the reduced weight. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", - "weight": "7670 g", + "name": { "str": "field combat exoskeleton" }, + "description": "The final iteration of military power armor before the fall of civilization, this type - a powered exoskeleton with high-tech segmented plating - was designed for actual widespread combat use and was seen on the front lines during the last days of the cataclysm. Like the heavier suits, it is resistant to most modern weaponry, but it is light and maneuverable, and can fit into normal vehicles and doorways without fuss, a huge advantage over predecessors. Unfortunately, the world ended before it could roll out in significant numbers. There is an integrated chemical resistant bodyglove that precludes wearing other clothing.", + "weight": "12670 g", "volume": "15 L", "price": 11500000, "price_postapoc": 1150000, From 0f245019e56f2449a67ee6ac88ebc0bec9cb99d0 Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:12 +0100 Subject: [PATCH 105/219] Match armor layers ui and help text (#38762) --- src/armor_layers.cpp | 59 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index a8dc810618923..09635464c4ee7 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -526,7 +526,8 @@ void player::sort_armor() wprintz( w_sort_cat, c_white, _( "Sort Armor" ) ); wprintz( w_sort_cat, c_yellow, " << %s >>", armor_cat[tabindex] ); right_print( w_sort_cat, 0, 0, c_white, string_format( - _( "Press %s for help. Press %s to change keybindings." ), + _( "Press [%s] for help. " + "Press [%s] to change keybindings." ), ctxt.get_desc( "USAGE_HELP" ), ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); @@ -828,32 +829,36 @@ void player::sort_armor() } } } else if( action == "USAGE_HELP" ) { - popup_getkey( _( "Use the arrow- or keypad keys to navigate the left list.\n" - "[%s] to select highlighted armor for reordering.\n" - "[%s] / [%s] to scroll the right list.\n" - "[%s] to assign special inventory letters to clothing.\n" - "[%s] to change the side on which item is worn.\n" - "[%s] to sort armor into natural layer order.\n" - "[%s] to equip a new item.\n" - "[%s] to equip a new item at the currently selected position.\n" - "[%s] to remove selected armor from oneself.\n" - "\n" - "[Encumbrance and Warmth] explanation:\n" - "The first number is the summed encumbrance from all clothing on that bodypart.\n" - "The second number is an additional encumbrance penalty caused by wearing multiple items " - "on one of the bodypart's layers or wearing items outside of other items they would " - "normally be work beneath (e.g. a shirt over a backpack).\n" - "The sum of these values is the effective encumbrance value your character has for that bodypart." ), - ctxt.get_desc( "MOVE_ARMOR" ), - ctxt.get_desc( "PREV_TAB" ), - ctxt.get_desc( "NEXT_TAB" ), - ctxt.get_desc( "ASSIGN_INVLETS" ), - ctxt.get_desc( "CHANGE_SIDE" ), - ctxt.get_desc( "SORT_ARMOR" ), - ctxt.get_desc( "EQUIP_ARMOR" ), - ctxt.get_desc( "EQUIP_ARMOR_HERE" ), - ctxt.get_desc( "REMOVE_ARMOR" ) - ); + popup_getkey( + _( "Use the [arrow- or keypad keys] to navigate the left list.\n" + "[%s] to select highlighted armor for reordering.\n" + "[%s] / [%s] to scroll the right list.\n" + "[%s] to assign special inventory letters to clothing.\n" + "[%s] to change the side on which item is worn.\n" + "[%s] to sort armor into natural layer order.\n" + "[%s] to equip a new item.\n" + "[%s] to equip a new item at the currently selected position.\n" + "[%s] to remove selected armor from oneself.\n" + "\n" + "\n" + "Encumbrance explanation:\n" + "\n" + "The first number is the summed encumbrance from all clothing " + "on that bodypart. The second number is an additional encumbrance penalty " + "caused by wearing either multiple items on one of the bodypart's layers or " + "wearing items the wrong way (e.g. a shirt over a backpack). " + "The sum of these values is the effective encumbrance value " + "your character has for that bodypart." ), + ctxt.get_desc( "MOVE_ARMOR" ), + ctxt.get_desc( "PREV_TAB" ), + ctxt.get_desc( "NEXT_TAB" ), + ctxt.get_desc( "ASSIGN_INVLETS" ), + ctxt.get_desc( "CHANGE_SIDE" ), + ctxt.get_desc( "SORT_ARMOR" ), + ctxt.get_desc( "EQUIP_ARMOR" ), + ctxt.get_desc( "EQUIP_ARMOR_HERE" ), + ctxt.get_desc( "REMOVE_ARMOR" ) + ); draw_grid( w_sort_armor, left_w, middle_w ); } else if( action == "HELP_KEYBINDINGS" ) { draw_grid( w_sort_armor, left_w, middle_w ); From c6a6b45d2fcd0022f410176ff188282b255d37bc Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:25 +0100 Subject: [PATCH 106/219] Match advanced inventory UI and info text (#38763) --- src/advanced_inv.cpp | 7 +++---- src/output.cpp | 8 +++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index baa59d70f9931..0fc5f27cbc9a1 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -1077,10 +1077,9 @@ void advanced_inventory::display() draw_border( head ); Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); draw_minimap(); - const std::string msg = string_format( _( "< [%s] Show help >" ), - ctxt.get_desc( "HELP_KEYBINDINGS" ) ); - mvwprintz( head, point( w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, 0 ), - c_white, msg ); + right_print( head, 0, +3, c_white, string_format( + _( "< [%s] keybindings >" ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); if( g->u.has_watch() ) { const std::string time = to_string_time_of_day( calendar::turn ); mvwprintz( head, point( 2, 0 ), c_white, time ); diff --git a/src/output.cpp b/src/output.cpp index 9850ef173667e..459daf60e54c3 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -773,21 +773,23 @@ void draw_item_filter_rules( const catacurses::window &win, int starty, int heig starty += fold_and_print( win, point( 1, starty ), len, c_white, // NOLINTNEXTLINE(cata-text-style): literal comma - _( "Separate multiple items with ," ) ); + _( "Separate multiple items with [,]." ) ); starty += 1 + fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to separate multiple items with a comma when filtering items. _( "Example: back,flash,aid, ,band" ) ); // NOLINT(cata-text-style): literal comma if( type == item_filter_type::FILTER ) { starty += fold_and_print( win, point( 1, starty ), len, c_white, - _( "To exclude items, place - in front." ) ); + _( "To exclude items, place [-] in front." ) ); starty += 1 + fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to exclude items with - when filtering items. _( "Example: -pipe,-chunk,-steel" ) ); } starty += fold_and_print( win, point( 1, starty ), len, c_white, - _( "Search [c]ategory, [m]aterial, [q]uality, [n]otes or [d]isassembled components:" ) ); + _( "Search [c]ategory, [m]aterial, " + "[q]uality, [n]otes or " + "[d]isassembled components." ) ); fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to filter items based on category or material. _( "Examples: c:food,m:iron,q:hammering,n:toolshelf,d:pipe" ) ); From 377b84c58a2ee42423475c5d369df580ad1776ee Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:37 +0100 Subject: [PATCH 107/219] Match message log filter info and construction filter (#38764) --- src/messages.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/messages.cpp b/src/messages.cpp index f9750c6c15071..801c29068eee3 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -750,11 +750,15 @@ void Messages::dialog::run() std::vector Messages::dialog::filter_help_text( int width ) { const auto &help_fmt = _( - "Format is [[TYPE]:]TEXT. The values for TYPE are: %s\n" - "Examples:\n" - " good:mutation\n" - " :you pick up: 1\n" - " crash!\n" + "The default is to search the entire message log. " + "Use message-types as prefixes followed by (:) to filter more specific.\n" + "Valid message-type values are: %s\n" + "\n" + "Examples:\n" + " good:mutation\n" + " :you pick up: 1\n" + " bad:\n" + "\n" ); std::string type_text; const auto &type_list = msg_type_and_names(); From 497c0fa9d0af161cbab40a9d9abb99cbbba7b5ad Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:49 +0100 Subject: [PATCH 108/219] Match construction UI (#38765) --- src/construction.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/construction.cpp b/src/construction.cpp index f464a6f665344..e85ba7586c1d2 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -388,15 +388,19 @@ construction_id construction_menu( const bool blueprint ) std::vector notes; if( tabindex == tabcount - 1 && !filter.empty() ) { - notes.push_back( string_format( _( "Press %s to clear filter" ), + notes.push_back( string_format( _( "Press [%s] to clear filter" ), ctxt.get_desc( "RESET_FILTER" ) ) ); } - notes.push_back( string_format( _( "Press %s or %s to tab." ), ctxt.get_desc( "LEFT" ), + notes.push_back( string_format( _( "Press [%s or %s] " + "to tab." ), ctxt.get_desc( "LEFT" ), ctxt.get_desc( "RIGHT" ) ) ); - notes.push_back( string_format( _( "Press %s to search." ), ctxt.get_desc( "FILTER" ) ) ); - notes.push_back( string_format( _( "Press %s to toggle unavailable constructions." ), + notes.push_back( string_format( _( "Press [%s] " + "to search." ), ctxt.get_desc( "FILTER" ) ) ); + notes.push_back( string_format( _( "Press [%s] " + "to toggle unavailable constructions." ), ctxt.get_desc( "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ) ) ); - notes.push_back( string_format( _( "Press %s to view and edit key-bindings." ), + notes.push_back( string_format( _( "Press [%s] " + "to view and edit keybindings." ), ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); //leave room for top and bottom UI text From 3b635c874029bec2f220957800539fd8877456a3 Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:11:39 +0100 Subject: [PATCH 109/219] Match player info and martial arts UI (#38766) --- src/player.cpp | 6 ++++-- src/player_display.cpp | 16 +++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/player.cpp b/src/player.cpp index 218f250c64685..66181c5a60016 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -3220,8 +3220,10 @@ bool character_martial_arts::pick_style( const avatar &you ) // Style selection ctxt.register_action( "SHOW_DESCRIPTION" ); uilist kmenu; - kmenu.text = string_format( _( "Select a style. (press %s for more info)" ), - ctxt.get_desc( "SHOW_DESCRIPTION" ) ); + kmenu.text = colorize( string_format( _( "Select a style. " + "Press [%s] for more info." ), + "Press %s for more info.", + ctxt.get_desc( "SHOW_DESCRIPTION" ) ), c_white ); ma_style_callback callback( static_cast( STYLE_OFFSET ), selectable_styles ); kmenu.callback = &callback; kmenu.input_category = "MELEE_STYLE_PICKER"; diff --git a/src/player_display.cpp b/src/player_display.cpp index 3789f58e96e79..a580558cc10b7 100644 --- a/src/player_display.cpp +++ b/src/player_display.cpp @@ -503,7 +503,8 @@ static void draw_bionics_tab( const catacurses::window &w_bionics, const catacur center_print( w_bionics, 0, h_light_gray, _( title_BIONICS ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) trim_and_print( w_bionics, point( 1, 1 ), getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d / %2$d" ), + string_format( _( "Bionic Power: %1$d" + " / %2$d" ), units::to_kilojoule( you.get_power_level() ), units::to_kilojoule( you.get_max_power_level() ) ) ); const size_t useful_y = bionics_win_size_y - 1; @@ -550,7 +551,8 @@ static void draw_bionics_tab( const catacurses::window &w_bionics, const catacur center_print( w_bionics, 0, c_light_gray, _( title_BIONICS ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) trim_and_print( w_bionics, point( 1, 1 ), getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d / %2$d" ), + string_format( _( "Bionic Power: %1$d" + " / %2$d" ), units::to_kilojoule( you.get_power_level() ), units::to_kilojoule( you.get_max_power_level() ) ) ); for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y - 1; i++ ) { mvwprintz( w_bionics, point( 1, static_cast( i + 2 ) ), c_black, " " ); @@ -973,7 +975,8 @@ static void draw_initial_windows( const catacurses::window &w_stats, center_print( w_bionics, 0, c_light_gray, _( title_BIONICS ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) trim_and_print( w_bionics, point( 1, 1 ), getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d / %2$d" ), + string_format( _( "Bionic Power: %1$d" + " / %2$d" ), units::to_kilojoule( you.get_power_level() ), units::to_kilojoule( you.get_max_power_level() ) ) ); for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y - 1; i++ ) { trim_and_print( w_bionics, point( 1, static_cast( i ) + 2 ), getmaxx( w_bionics ) - 1, c_white, @@ -1308,10 +1311,9 @@ void player::disp_info() ctxt.register_action( "HELP_KEYBINDINGS" ); std::string action; - std::string help_msg = string_format( _( "Press %s for help." ), - ctxt.get_desc( "HELP_KEYBINDINGS" ) ); - mvwprintz( w_tip, point( FULL_SCREEN_WIDTH - utf8_width( help_msg ), 0 ), c_light_red, help_msg ); - help_msg.clear(); + right_print( w_tip, 0, +4, c_white, string_format( + _( "< [%s] keybindings >" ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); wrefresh( w_tip ); draw_initial_windows( w_stats, w_encumb, w_traits, w_bionics, w_effects, w_skills, w_speed, *this, From 1be56660711dbd5fd713bbc94126e76cb49db129 Mon Sep 17 00:00:00 2001 From: NastyNate2612 <59994204+NastyNate2612@users.noreply.github.com> Date: Mon, 16 Mar 2020 05:04:40 -0700 Subject: [PATCH 110/219] Extracts and Concentrates pt 1 (#37936) --- data/json/items/tool/misc.json | 102 +++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/data/json/items/tool/misc.json b/data/json/items/tool/misc.json index 498c7b8409545..045ae7067326e 100644 --- a/data/json/items/tool/misc.json +++ b/data/json/items/tool/misc.json @@ -43,6 +43,30 @@ "color": "yellow", "flags": [ "WATCH", "ALARMCLOCK" ] }, + { + "type": "TOOL", + "id": "butane_can", + "name": { "str": "can of butane", "str_pl": "cans of butane" }, + "description": "A typical can of butane that you would normally use to fill a lighter. It could be useful as a fuel, but also as a solvent or chemical reagent.", + "symbol": "!", + "color": "dark_gray", + "looks_like": "spray_can", + "weight": "420 g", + "volume": "500 ml", + "price": 1500, + "initial_charges": 30, + "max_charges": 30, + "charges_per_use": 1, + "material": "steel", + "flags": [ "EXPLOSIVE", "EXPLODES" ], + "explosion": { + "power": 4503, + "distance_factor": 0.1, + "fire": true, + "shrapnel": { "casing_mass": 50, "fragment_mass": 0.05, "recovery": 0 } + }, + "explode_in_fire": true + }, { "id": "cow_bell", "type": "TOOL", @@ -58,6 +82,68 @@ "color": "brown", "use_action": "BELL" }, + { + "type": "TOOL", + "id": "dab_pen", + "name": { "str": "dab pen" }, + "description": "A battery operated dab pen used for smoking cannabis distillate cartridges.", + "symbol": "!", + "color": "dark_gray", + "looks_like": "ecig", + "weight": "20 g", + "volume": "100 ml", + "price": 2500, + "material": "plastic", + "ammo": "battery", + "magazines": [ + [ + "battery", + [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ] + ] + ], + "charges_per_use": 1, + "max_charges": 100, + "use_action": { + "target": "dab_pen_on", + "msg": "You turn on the dab pen.", + "active": true, + "need_charges": 1, + "need_charges_msg": "The dab pen's batteries need more charge.", + "type": "transform" + } + }, + { + "type": "TOOL", + "id": "dab_pen_on", + "name": { "str": "dab pen (on)", "str_pl": "dab pens (on)" }, + "description": "This dab pen, for vaporizing cannabis, is turned on. Now all you need is a distillate cartridge and you're ready to rock and roll.", + "symbol": "!", + "color": "dark_gray", + "looks_like": "ecig", + "weight": "20 g", + "volume": "100 ml", + "price": 2500, + "material": "plastic", + "ammo": "battery", + "power_draw": 9000, + "revert_to": "dab_pen", + "magazines": [ + [ + "battery", + [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ] + ] + ], + "charges_per_use": 1, + "max_charges": 100, + "use_action": { + "target": "dab_pen", + "msg": "You turn off the dab pen.", + "active": false, + "need_charges": 0, + "need_charges_msg": "The dab pen's batteries need more charge.", + "type": "transform" + } + }, { "id": "e_tool", "type": "TOOL", @@ -345,6 +431,22 @@ "weight": "600 g", "flags": [ "TRADER_AVOID" ] }, + { + "type": "TOOL", + "id": "gasket_plastic", + "name": { "str": "plastic gasket" }, + "description": " A single-use plastic gasket.", + "symbol": "(", + "color": "dark_gray", + "looks_like": "plastic_chunk", + "weight": "5 g", + "volume": "30 ml", + "//": "gasket sizes range from 1in diameter to 6in.", + "price": 150, + "to_hit": 10, + "bashing": 1, + "material": "plastic" + }, { "id": "permanent_marker", "type": "TOOL", From 329e489045565800949f63efcfc362200b7d84f9 Mon Sep 17 00:00:00 2001 From: np-vortex <58790761+np-vortex@users.noreply.github.com> Date: Mon, 16 Mar 2020 23:06:58 +0200 Subject: [PATCH 111/219] Add "forbidden traits" to professions (#36074) --- src/mutation.cpp | 31 +++++++++++++++++++++++++++++++ src/mutation.h | 7 +++++++ src/newcharacter.cpp | 3 +++ src/profession.cpp | 11 +++++++++++ src/profession.h | 3 +++ src/scenario.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- src/scenario.h | 1 + 7 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index be6c9f4be32f9..344087e87ad61 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1409,3 +1409,34 @@ void test_crossing_threshold( Character &guy, const mutation_category_trait &m_c guy.add_effect( effect_stunned, rng( 2_turns, 3_turns ) ); } } + +bool are_conflicting_traits( const trait_id &trait_1, const trait_id &trait_2 ) +{ + return ( are_opposite_traits( trait_1, trait_2 ) || b_is_lower_trait_of_a( trait_1, trait_2 ) + || b_is_higher_trait_of_a( trait_1, trait_2 ) || are_same_type_traits( trait_1, trait_2 ) ); +} + +bool are_opposite_traits( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( trait_a->cancels, trait_b ); +} + +bool b_is_lower_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( trait_a->prereqs, trait_b ); +} + +bool b_is_higher_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( trait_a->replacements, trait_b ); +} + +bool are_same_type_traits( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( get_mutations_in_types( trait_a->types ), trait_b ); +} + +bool contains_trait( std::vector> traits, const trait_id &trait ) +{ + return std::find( traits.begin(), traits.end(), trait ) != traits.end(); +} diff --git a/src/mutation.h b/src/mutation.h index 5926e6f68898f..63f449e05c7b9 100644 --- a/src/mutation.h +++ b/src/mutation.h @@ -465,6 +465,13 @@ std::vector get_mutations_in_types( const std::set &ids ) std::vector get_mutations_in_type( const std::string &id ); bool trait_display_sort( const trait_id &a, const trait_id &b ) noexcept; +bool are_conflicting_traits( const trait_id &trait_a, const trait_id &trait_b ); +bool b_is_lower_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ); +bool b_is_higher_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ); +bool are_opposite_traits( const trait_id &trait_a, const trait_id &trait_b ); +bool are_same_type_traits( const trait_id &trait_a, const trait_id &trait_b ); +bool contains_trait( std::vector> traits, const trait_id &trait ); + enum class mutagen_technique : int { consumed_mutagen, injected_mutagen, diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 092ef74843c8d..88bc47204afbf 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1187,6 +1187,9 @@ tab_direction set_traits( const catacurses::window &w, avatar &u, points_left &p popup( _( "You already picked a conflicting trait!" ) ); } else if( g->scen->is_forbidden_trait( cur_trait ) ) { popup( _( "The scenario you picked prevents you from taking this trait!" ) ); + } else if( u.prof->is_forbidden_trait( cur_trait ) ) { + popup( _( "Your profession of %s prevents you from taking this trait." ), + u.prof->gender_appropriate_name( u.male ) ); } else if( iCurWorkingPage == 0 && num_good + mdata.points > max_trait_points && !points.is_freeform() ) { popup( ngettext( "Sorry, but you can only take %d point of advantages.", diff --git a/src/profession.cpp b/src/profession.cpp index 87f4c62ddd64f..4042e50c6e48b 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -225,6 +225,7 @@ void profession::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "CBMs", _starting_CBMs, auto_flags_reader {} ); // 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 {} ); optional( jo, was_loaded, "flags", flags, auto_flags_reader<> {} ); } @@ -465,6 +466,11 @@ std::vector profession::get_locked_traits() const return _starting_traits; } +std::set profession::get_forbidden_traits() const +{ + return _forbidden_traits; +} + profession::StartingSkillList profession::skills() const { return _starting_skills; @@ -486,6 +492,11 @@ bool profession::is_locked_trait( const trait_id &trait ) const _starting_traits.end(); } +bool profession::is_forbidden_trait( const trait_id &trait ) const +{ + return _forbidden_traits.count( trait ) != 0; +} + std::map profession::spells() const { return _starting_spells; diff --git a/src/profession.h b/src/profession.h index 61649631d7b31..28cc0ddd184ad 100644 --- a/src/profession.h +++ b/src/profession.h @@ -69,6 +69,7 @@ class profession std::vector _starting_addictions; std::vector _starting_CBMs; std::vector _starting_traits; + std::set _forbidden_traits; std::vector _starting_pets; vproto_id _starting_vehicle = vproto_id::NULL_ID(); // the int is what level the spell starts at @@ -128,7 +129,9 @@ class profession */ bool can_pick( const player &u, int points ) const; bool is_locked_trait( const trait_id &trait ) const; + bool is_forbidden_trait( const trait_id &trait ) const; std::vector get_locked_traits() const; + std::set get_forbidden_traits() const; }; #endif diff --git a/src/scenario.cpp b/src/scenario.cpp index 4f095057a826f..50997cf28db0a 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -299,16 +299,24 @@ std::vector> scenario::permitted_professions() const for( const profession &p : all ) { const bool present = std::find( professions.begin(), professions.end(), p.ident() ) != professions.end(); + + bool conflicting_traits = scenario_traits_conflict_with_profession_traits( p ); + if( blacklist || professions.empty() ) { - if( !present && !p.has_flag( "SCEN_ONLY" ) ) { + if( !present && !p.has_flag( "SCEN_ONLY" ) && !conflicting_traits ) { + res.push_back( p.ident() ); + } + } else if( present ) { + if( !conflicting_traits ) { res.push_back( p.ident() ); + } else { + debugmsg( "Scenario %s and profession %s have conflicting trait requirements", + id.c_str(), p.ident().c_str() ); } } else if( extra_professions ) { - if( present || !p.has_flag( "SCEN_ONLY" ) ) { + if( !p.has_flag( "SCEN_ONLY" ) && !conflicting_traits ) { res.push_back( p.ident() ); } - } else if( present ) { - res.push_back( p.ident() ); } } @@ -319,6 +327,33 @@ std::vector> scenario::permitted_professions() const return res; } +bool scenario::scenario_traits_conflict_with_profession_traits( const profession &p ) const +{ + for( auto &pt : p.get_forbidden_traits() ) { + if( is_locked_trait( pt ) ) { + return true; + } + } + + for( auto &pt : p.get_locked_traits() ) { + if( is_forbidden_trait( pt ) ) { + return true; + } + } + + // check if: + // locked traits for scenario prevent taking locked traits for professions + // locked traits for professions prevent taking locked traits for scenario + for( auto &st : get_locked_traits() ) { + for( auto &pt : p.get_locked_traits() ) { + if( are_conflicting_traits( st, pt ) || are_conflicting_traits( pt, st ) ) { + return true; + } + } + } + return false; +} + const profession *scenario::weighted_random_profession() const { // Strategy: 1/3 of the time, return the generic profession (if it's permitted). diff --git a/src/scenario.h b/src/scenario.h index da7aa116c34b3..78fd07c17afd8 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -50,6 +50,7 @@ class scenario std::vector _missions; void load( const JsonObject &jo, const std::string &src ); + bool scenario_traits_conflict_with_profession_traits( const profession &p ) const; public: //these three aren't meant for external use, but had to be made public regardless From 3bb953ecf7ddcfab3fcfc90009ffb8060403a1e6 Mon Sep 17 00:00:00 2001 From: klorpa <30924131+klorpa@users.noreply.github.com> Date: Tue, 17 Mar 2020 02:27:12 -0500 Subject: [PATCH 112/219] Volleyballs (#38192) --- .../Clothing_Gear/gear_civilian.json | 1 + .../locations_mapextras.json | 2 ++ .../Locations_MapExtras/mansion.json | 2 ++ data/json/itemgroups/activities_hobbies.json | 2 ++ data/json/itemgroups/supplies.json | 1 + data/json/items/armor/torso_clothes.json | 8 +++++ data/json/items/generic/toys_and_sports.json | 32 ++++++++++++++++++- data/json/mapgen/park.json | 1 + 8 files changed, 48 insertions(+), 1 deletion(-) diff --git a/data/json/itemgroups/Clothing_Gear/gear_civilian.json b/data/json/itemgroups/Clothing_Gear/gear_civilian.json index aad8f069982b7..d7d767a11db22 100644 --- a/data/json/itemgroups/Clothing_Gear/gear_civilian.json +++ b/data/json/itemgroups/Clothing_Gear/gear_civilian.json @@ -109,6 +109,7 @@ [ "novel_pulp", 16 ], [ "radio_car_box", 1 ], [ "basketball", 8 ], + [ "beach_volleyball", 8 ], [ "radiocontrol", 5 ], [ "whistle", 3 ], [ "slingshot", 10 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json index eabc414cc1fb6..5ba22bc41f2a2 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json @@ -195,6 +195,8 @@ [ "helmet_football", 20 ], [ "jersey", 100 ], [ "basketball", 100 ], + [ "beach_volleyball", 25 ], + [ "indoor_volleyball", 50 ], [ "armguard_soft", 50 ], [ "chestguard_hard", 20 ], [ "armguard_hard", 20 ], diff --git a/data/json/itemgroups/Locations_MapExtras/mansion.json b/data/json/itemgroups/Locations_MapExtras/mansion.json index 7a23ef26d3d0f..70996f84a8b51 100644 --- a/data/json/itemgroups/Locations_MapExtras/mansion.json +++ b/data/json/itemgroups/Locations_MapExtras/mansion.json @@ -747,6 +747,8 @@ [ "helmet_football", 10 ], [ "football", 60 ], [ "basketball", 50 ], + [ "beach_volleyball", 40 ], + [ "indoor_volleyball", 40 ], [ "helmet_bike", 25 ], [ "helmet_ball", 25 ], [ "headgear", 20 ], diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index 85dc53dacc185..00a8643e9c4d2 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -37,6 +37,8 @@ [ "jersey", 30 ], [ "puck", 30 ], [ "basketball", 25 ], + [ "indoor_volleyball", 20 ], + [ "beach_volleyball", 20 ], [ "golf_club", 35 ], [ "hat_golf", 20 ], [ "gloves_golf", 20 ], diff --git a/data/json/itemgroups/supplies.json b/data/json/itemgroups/supplies.json index d34df1cd111a7..87a2e370cba35 100644 --- a/data/json/itemgroups/supplies.json +++ b/data/json/itemgroups/supplies.json @@ -484,6 +484,7 @@ "type": "item_group", "items": [ [ "basketball", 100 ], + [ "indoor_volleyball", 50 ], [ "baseball", 100 ], [ "hat_ball", 10 ], [ "helmet_ball", 20 ], diff --git a/data/json/items/armor/torso_clothes.json b/data/json/items/armor/torso_clothes.json index 893e88631b97b..901d67bff1c8c 100644 --- a/data/json/items/armor/torso_clothes.json +++ b/data/json/items/armor/torso_clothes.json @@ -280,6 +280,14 @@ { "id": "monroeville", "text": "A hockey jersey made of thick material imprinted with the logo of the Monroeville Zombies." + }, + { + "id": "rugby", + "text": "A rugby jersey made of thick material imprinted with the logo of the Canberra Drop Bears." + }, + { + "id": "volleyball", + "text": "A volleyball jersey made of thick material imprinted with the logo of the Ooarai Ducks." } ], "flags": [ "VARSIZE" ] diff --git a/data/json/items/generic/toys_and_sports.json b/data/json/items/generic/toys_and_sports.json index 19f4f2cb86129..c4148a7296a1a 100644 --- a/data/json/items/generic/toys_and_sports.json +++ b/data/json/items/generic/toys_and_sports.json @@ -115,7 +115,7 @@ "name": { "str": "bowling ball" }, "description": "A large, heavy ball. Before the apocalypse, its main purpose was to be rolled along waxed floors.", "category": "other", - "price": 30, + "price": 3000, "material": "ceramic", "weight": "2000 g", "volume": "2500 ml", @@ -167,6 +167,36 @@ "bashing": 6, "to_hit": -1 }, + { + "type": "GENERIC", + "id": "indoor_volleyball", + "symbol": "*", + "color": "white", + "name": "volleyball", + "category": "other", + "description": "A standard regulation volleyball.", + "price": 1000, + "material": "leather", + "weight": "260 g", + "volume": "1 L", + "bashing": 4, + "to_hit": -1 + }, + { + "type": "GENERIC", + "id": "beach_volleyball", + "symbol": "*", + "color": "green", + "name": "beach volleyball", + "category": "other", + "description": "A brightly colored beach volleyball. It is slightly larger than a regular white one.", + "price": 1200, + "material": "leather", + "weight": "280 g", + "volume": "1 L", + "bashing": 4, + "to_hit": -1 + }, { "type": "GENERIC", "id": "puck", diff --git a/data/json/mapgen/park.json b/data/json/mapgen/park.json index b1cada928c3c3..0c1b13e5adbab 100644 --- a/data/json/mapgen/park.json +++ b/data/json/mapgen/park.json @@ -157,6 +157,7 @@ ], "palettes": [ "park_asphalt_palette" ], "items": { "b": { "item": "shoes", "chance": 15, "repeat": [ 2, 5 ] } }, + "place_item": [ { "item": "beach_volleyball", "x": 8, "y": 6 } ], "monsters": { "$": { "monster": "GROUP_PARK_SCENIC", "chance": 50 }, " ": { "monster": "GROUP_PARK_PLAYGROUND", "chance": 100 } } } }, From dea3588d1b3eb889be8cd153a5e76257be90480a Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Tue, 17 Mar 2020 12:04:46 +0300 Subject: [PATCH 113/219] Rename bionicsDisplayType.json to bionics_display_types.json --- data/json/{bionicsDisplayType.json => bionics_display_types.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/json/{bionicsDisplayType.json => bionics_display_types.json} (100%) diff --git a/data/json/bionicsDisplayType.json b/data/json/bionics_display_types.json similarity index 100% rename from data/json/bionicsDisplayType.json rename to data/json/bionics_display_types.json From 07f8fa0551615e44b12026cb2995f3c7822fcc1a Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Tue, 17 Mar 2020 12:06:05 +0300 Subject: [PATCH 114/219] Rename bionics_display_types.json to bionicsDisplayType.json --- data/json/{bionics_display_types.json => bionicsDisplayType.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/json/{bionics_display_types.json => bionicsDisplayType.json} (100%) diff --git a/data/json/bionics_display_types.json b/data/json/bionicsDisplayType.json similarity index 100% rename from data/json/bionics_display_types.json rename to data/json/bionicsDisplayType.json From 309ad05f9acd858adc8372c051a0f8b4a532499c Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Tue, 17 Mar 2020 13:59:19 +0300 Subject: [PATCH 115/219] Update bionics.h --- src/bionics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bionics.h b/src/bionics.h index d3c5d770fab14..bb0cba931d8dc 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -202,7 +202,7 @@ class BionicsDisplayType bool _hide_columns; public: static std::vector displayTypes; - static void load( JsonObject &jsobj ); + static void load( const JsonObject &jsobj ); static void reset(); //if bionic doesn't have "display_type" filed in .json, use this to infer it from other parameters static bionics_displayType_id infer_type( const bionic_data &b ); From 7dd502aaa35d42bc65f4283697a06bdb48593a3e Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Tue, 17 Mar 2020 13:59:57 +0300 Subject: [PATCH 116/219] Update bionics.cpp --- src/bionics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bionics.cpp b/src/bionics.cpp index c7deb9005a300..b04f06ca913d6 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2752,7 +2752,7 @@ BionicsDisplayType::BionicsDisplayType( const bionics_displayType_id &ident, { } -void BionicsDisplayType::load( JsonObject &jsobj ) +void BionicsDisplayType::load( const JsonObject &jsobj ) { bionics_displayType_id ident = bionics_displayType_id( jsobj.get_string( "ident" ) ); displayTypes.erase( std::remove_if( begin( displayTypes ), From 81b97aaf5cc377763d21773853be00ac2b941fea Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Tue, 17 Mar 2020 14:31:15 +0300 Subject: [PATCH 117/219] Update bionics_ui.cpp --- src/bionics_ui.cpp | 150 +++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 95 deletions(-) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 8854f8dea997a..add9859484d73 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -1,6 +1,7 @@ #include "player.h" // IWYU pragma: associated #include //std::min +#include #include #include "bionics.h" @@ -12,7 +13,6 @@ #include "translations.h" #include "options.h" #include "string_id.h" -#include "cata_string_consts.h" // '!', '-' and '=' are uses as default bindings in the menu const invlet_wrapper @@ -54,8 +54,14 @@ bionic_col_data get_col_data( int col_idx ) 3, translate_marker( "Status" ), translate_marker( "CBM Status:\n + - activated\n x - incapacitated. This CBM cannot be used for some time." ) }, - {8, translate_marker( "Activation" ), translate_marker( "Amount of Bionic Power required to activeate this CBM." )}, - {8, translate_marker( "Turn Cost" ), translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) } + { + 8, translate_marker( "Activation" ), + translate_marker( "Amount of Bionic Power required to activate this CBM." ) + }, + { + 8, translate_marker( "Turn Cost" ), + translate_marker( "Amount of Bionic Power this CBM consumes every turn while activated. Values like 1 /600 mean that 1 Power will be consumed every 600 turns." ) + } } }; return col_data[col_idx]; @@ -162,43 +168,19 @@ char get_free_invlet( player &p ) static void draw_bionics_titlebar( const catacurses::window &window, player *p ) { - input_context ctxt( "BIONICS" ); - werase( window ); - std::string fuel_string; - bool found_fuel = false; - fuel_string = _( "Available Fuel: " ); + std::ostringstream fuel_stream; + fuel_stream << _( "Available Fuel: " ); for( const bionic &bio : *p->my_bionics ) { - for( const itype_id &fuel : p->get_fuel_available( bio.id ) ) { - found_fuel = true; - const item temp_fuel( fuel ); - if( temp_fuel.has_flag( flag_PERPETUAL ) ) { - if( fuel == itype_id( "sunlight" ) && !g->is_in_sunlight( p->pos() ) ) { - continue; - } - fuel_string += colorize( temp_fuel.tname(), c_green ) + " "; + for( const itype_id fuel : p->get_fuel_available( bio.id ) ) { + const item temp_fuel( fuel ) ; + if( temp_fuel.has_flag( "PERPETUAL" ) ) { continue; } - fuel_string += temp_fuel.tname() + ": " + colorize( p->get_value( fuel ), - c_green ) + "/" + std::to_string( p->get_total_fuel_capacity( fuel ) ) + " "; - } - if( bio.info().is_remote_fueled && p->has_active_bionic( bio.id ) ) { - const itype_id rem_fuel = p->find_remote_fuel( true ); - if( !rem_fuel.empty() ) { - const item tmp_rem_fuel( rem_fuel ); - if( tmp_rem_fuel.has_flag( flag_PERPETUAL ) ) { - fuel_string += colorize( tmp_rem_fuel.tname(), c_green ) + " "; - } else { - fuel_string += tmp_rem_fuel.tname() + ": " + colorize( p->get_value( "rem_" + rem_fuel ), - c_green ) + " "; - } - found_fuel = true; - } + fuel_stream << temp_fuel.tname() << ": " << "" << p->get_value( + fuel ) << "" << "/" << p->get_total_fuel_capacity( fuel ) << " "; } } - if( !found_fuel ) { - fuel_string.clear(); - } fold_and_print( window, point_east, getmaxx( window ), c_white, fuel_stream.str() ); wrefresh( window ); } @@ -223,15 +205,11 @@ static void draw_bionics_tabs( const catacurses::window &win, std::vector( cur_tab_idx ) < bionics_by_type.size() && @@ -548,10 +526,8 @@ void player::power_bionics() const std::string action = ctxt.handle_input(); const int ch = ctxt.get_raw_input().get_first_input(); bionic *tmp = nullptr; - bool confirmCheck = false; bool toggle_safe_fuel = false; bool toggle_auto_start = false; - bool need_activate = false; if( action == "DOWN" ) { redraw = true; @@ -626,11 +602,15 @@ void player::power_bionics() } } while( bionics_by_type[cur_tab_idx].empty() ); } - } else if( action == "REASSIGN" ) { - menu_mode = REASSIGNING; } else if( action == "TOGGLE_SAFE_FUEL" ) { + if( !current_bionic_list.empty() ) { + tmp = current_bionic_list[cursor]; + } toggle_safe_fuel = true; } else if( action == "TOGGLE_AUTO_START" ) { + if( !current_bionic_list.empty() ) { + tmp = current_bionic_list[cursor]; + } toggle_auto_start = true; } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; @@ -651,7 +631,7 @@ void player::power_bionics() popup( help_str ); redraw = true; } else { -< if( ch == ' ' || ch == KEY_ESCAPE ) { + if( ch == ' ' || ch == KEY_ESCAPE ) { break; } tmp = bionic_by_invlet( ch ); @@ -671,50 +651,6 @@ void player::power_bionics() scroll_position++; } is_found = true; - confirmCheck = true; - } - - if( toggle_safe_fuel ) { - auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; - if( !current_bionic_list->empty() ) { - tmp = bio_list[cursor]; - if( !tmp->info().fuel_opts.empty() || tmp->info().is_remote_fueled ) { - tmp->toggle_safe_fuel_mod(); - g->refresh_all(); - redraw = true; - } else { - popup( _( "You can't toggle fuel saving mode on a non-fueled CBM." ) ); - } - - } - } - - if( toggle_auto_start ) { - auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; - if( !current_bionic_list->empty() ) { - tmp = bio_list[cursor]; - if( !tmp->info().fuel_opts.empty() || tmp->info().is_remote_fueled ) { - tmp->toggle_auto_start_mod(); - g->refresh_all(); - redraw = true; - } else { - popup( _( "You can't toggle auto start mode on a non-fueled CBM." ) ); - } - } - } - - //confirmation either occurred by pressing enter where the bionic cursor is, or the hotkey was selected - if( confirmCheck ) { - auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; - if( action == "CONFIRM" && !current_bionic_list->empty() ) { - tmp = bio_list[cursor]; - } else { - tmp = bionic_by_invlet( ch ); - if( tmp && tmp != bio_last ) { - // new bionic selected, update cursor and scroll position - int temp_cursor = 0; - for( temp_cursor = 0; temp_cursor < static_cast( bio_list.size() ); temp_cursor++ ) { - if( bio_list[temp_cursor] == tmp ) { break; } } @@ -726,9 +662,33 @@ void player::power_bionics() need_activate = true; redraw = true; } + if( tmp == nullptr ) { - //Do nothing - } else if( need_activate ) { + return; + } + + + if( toggle_safe_fuel ) { + if( !tmp->info().fuel_opts.empty() || tmp->info().is_remote_fueled ) { + tmp->toggle_safe_fuel_mod(); + g->refresh_all(); + redraw = true; + } else { + popup( _( "You can't toggle fuel saving mode on a non-fueled CBM." ) ); + } + } + + if( toggle_auto_start ) { + if( !tmp->info().fuel_opts.empty() || tmp->info().is_remote_fueled ) { + tmp->toggle_auto_start_mod(); + g->refresh_all(); + redraw = true; + } else { + popup( _( "You can't toggle auto start mode on a non-fueled CBM." ) ); + } + } + + if( need_activate ) { const bionic_id &bio_id = tmp->id; const bionic_data &bio_data = bio_id.obj(); if( bio_data.activated ) { From 38fabc768ca4798263e4a323f0c6f9a61536bb9b Mon Sep 17 00:00:00 2001 From: LyleSY Date: Fri, 6 Mar 2020 05:09:42 -0500 Subject: [PATCH 118/219] DinoModv3: DinoDNA (#26525) --- data/mods/DinoMod/dinosaur.json | 440 ++++++++++++------ data/mods/DinoMod/egg.json | 108 +++++ data/mods/DinoMod/forage.json | 14 + data/mods/DinoMod/lab_notes.json | 10 + data/mods/DinoMod/monstergroups_egg.json | 23 + .../mods/DinoMod/recipe_medsandchemicals.json | 20 + 6 files changed, 475 insertions(+), 140 deletions(-) create mode 100644 data/mods/DinoMod/egg.json create mode 100644 data/mods/DinoMod/forage.json create mode 100644 data/mods/DinoMod/lab_notes.json create mode 100644 data/mods/DinoMod/monstergroups_egg.json create mode 100644 data/mods/DinoMod/recipe_medsandchemicals.json diff --git a/data/mods/DinoMod/dinosaur.json b/data/mods/DinoMod/dinosaur.json index 18fda81786c73..a26fc5b2278bf 100644 --- a/data/mods/DinoMod/dinosaur.json +++ b/data/mods/DinoMod/dinosaur.json @@ -13,25 +13,41 @@ "default_faction": "compsognathus", "symbol": "D", "color": "green_yellow", - "volume": "30000 ml", - "weight": "40750 g", + "volume": "5500 ml", + "weight": 5500, "material": "flesh", - "aggression": -80, - "morale": -8, + "aggression": 3, + "morale": 20, "speed": 140, - "melee_skill": 4, + "melee_skill": 5, "melee_dice": 1, - "melee_dice_sides": 1, - "melee_cut": 0, + "melee_dice_sides": 2, + "melee_cut": 1, "dodge": 4, "vision_day": 50, "armor_bash": 1, "armor_cut": 0, - "luminance": 0, "hp": 20, "death_function": [ "NORMAL" ], "description": "A bipedal dinosaur about the size of a turkey. Its teeth and claws are small but sharp.", - "flags": [ "SEES", "SMELLS", "HEARS", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "BLEED", "WARM" ], + "reproduction": { "baby_egg": "egg_compsognathus", "baby_count": 3, "baby_timer": 12 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "HIT_AND_RUN", + "ANIMAL", + "PATH_AVOID_DANGER_1", + "BLEED", + "WARM", + "SWIMS", + "CATFOOD", + "SWARMS", + "ATTACKMON", + "GROUP_MORALE" + ], "harvest": "mammal_leather", "anger_triggers": [ "PLAYER_WEAK", "HURT" ], "fear_triggers": [ "PLAYER_CLOSE", "FIRE", "FRIEND_DIED" ], @@ -46,8 +62,8 @@ "default_faction": "gallimimus", "symbol": "D", "color": "light_green_yellow", - "volume": "62500 ml", - "weight": "81500 g", + "volume": "440000 ml", + "weight": 440000, "material": "flesh", "aggression": -60, "morale": -20, @@ -59,45 +75,26 @@ "dodge": 3, "armor_bash": 1, "armor_cut": 1, - "luminance": 0, "hp": 40, "death_function": [ "NORMAL" ], "description": "A feathered bipedal dinosaur, standing as tall as a human. It looks somewhat like a reptilian ostrich.", - "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM" ], - "harvest": "dino_feather_leather", - "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "FIRE" ], - "categories": [ "DINOSAUR" ] - }, - { - "type": "MONSTER", - "id": "mon_titanis", - "name": { "str": "Titanis", "str_pl": "Titanis" }, - "species": "DINOSAUR", - "default_faction": "titanis", - "symbol": "D", - "color": "blue_green", - "volume": "92500 ml", - "weight": "120 kg", - "material": "flesh", - "aggression": -20, - "morale": 60, - "speed": 150, - "melee_skill": 8, - "melee_dice": 1, - "melee_dice_sides": 8, - "melee_cut": 2, - "dodge": 1, - "armor_bash": 1, - "armor_cut": 1, - "luminance": 0, - "hp": 60, - "death_function": [ "NORMAL" ], - "description": "It looks like a dodo, only much bigger, with longer, muscular legs and a predatory gleam in its eyes.", - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "GRABS", "KEENNOSE", "BLEED", "WARM" ], + "reproduction": { "baby_egg": "egg_gallimimus", "baby_count": 3, "baby_timer": 12 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, + "flags": [ + "SEES", + "SMELLS", + "HEARS", + "GOODHEARING", + "ANIMAL", + "PATH_AVOID_DANGER_1", + "PET_MOUNTABLE", + "CATTLEFODDER", + "PET_WONT_FOLLOW", + "WARM" + ], "harvest": "dino_feather_leather", - "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], - "fear_triggers": [ "SOUND", "FIRE" ], - "placate_triggers": [ "MEAT" ], + "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "HURT", "FIRE" ], "categories": [ "DINOSAUR" ] }, { @@ -108,8 +105,8 @@ "default_faction": "spinosaurus", "symbol": "D", "color": "red_white", - "volume": "875000 ml", - "weight": "200 kg", + "volume": "16000000 ml", + "weight": 16000000, "material": "flesh", "aggression": 100, "morale": 100, @@ -121,11 +118,25 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 2, - "luminance": 0, "hp": 400, "death_function": [ "NORMAL" ], "description": "A huge dinosaur about the size of a small house, with a ferocious crocodile-like head and a sail on its back.", - "flags": [ "SEES", "SMELLS", "HEARS", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "DESTROYS", "BLEED", "ATTACKMON", "WARM" ], + "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" + ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], "fear_triggers": [ "SOUND", "FIRE" ], @@ -140,8 +151,8 @@ "default_faction": "t-rex", "symbol": "D", "color": "light_red_white", - "volume": "875000 ml", - "weight": "200 kg", + "volume": "5500000 ml", + "weight": 5500000, "material": "flesh", "aggression": 100, "morale": 100, @@ -153,10 +164,12 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 2, - "luminance": 0, "hp": 300, "death_function": [ "NORMAL" ], - "description": "Look at those TEETH!", + "description": "Look at those teeth! Tiny little claws though.", + "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" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], @@ -172,9 +185,10 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "light_green_magenta", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "6000000 ml", + "weight": 6000000, "material": "flesh", + "diff": 30, "aggression": -50, "morale": 50, "speed": 80, @@ -185,10 +199,12 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 2, - "luminance": 0, "hp": 150, "death_function": [ "NORMAL" ], "description": "A massive rhino-like dinosaur with a bony crest from which three large horns emerge.", + "reproduction": { "baby_egg": "egg_triceratops", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], @@ -203,8 +219,8 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "green_magenta", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "3000000 ml", + "weight": 3000000, "material": "flesh", "aggression": -50, "morale": -20, @@ -216,10 +232,12 @@ "dodge": 1, "armor_bash": 3, "armor_cut": 1, - "luminance": 0, "hp": 150, "death_function": [ "NORMAL" ], "description": "A large quadruped dinosaur with plates on its back, and a spiked tail.", + "reproduction": { "baby_egg": "egg_stegosaurus", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], @@ -234,8 +252,8 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "brown_magenta", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "6000000 ml", + "weight": 6000000, "material": "flesh", "aggression": -50, "morale": 30, @@ -247,10 +265,12 @@ "dodge": 1, "armor_bash": 6, "armor_cut": 4, - "luminance": 0, "hp": 120, "death_function": [ "NORMAL" ], "description": "This dinosaur looks like a giant prehistoric armadillo. Its tail ends in a massive spiked club of bone.", + "reproduction": { "baby_egg": "egg_ankylosaurus", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], @@ -265,8 +285,8 @@ "default_faction": "allosaurus", "symbol": "D", "color": "brown_white", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "1000000 ml", + "weight": 1000000, "material": "flesh", "aggression": 80, "morale": 80, @@ -278,10 +298,12 @@ "dodge": 1, "armor_bash": 3, "armor_cut": 1, - "luminance": 0, "hp": 120, "death_function": [ "NORMAL" ], "description": "A large predatory bipedal dinosaur, with tiger-like stripes on its broad back.", + "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" ], "harvest": "mammal_large_leather", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT" ], @@ -297,8 +319,8 @@ "default_faction": "eoraptor", "symbol": "D", "color": "dark_gray_yellow", - "volume": "750 ml", - "weight": "1 kg", + "volume": "15000 ml", + "weight": 15000, "material": "flesh", "aggression": -60, "morale": -60, @@ -310,10 +332,12 @@ "dodge": 4, "armor_bash": 1, "armor_cut": 0, - "luminance": 0, "hp": 10, "death_function": [ "NORMAL" ], "description": "A bipedal dinosaur about the size of a chicken. It roots around the undergrowth, scavenging on small animals and plants.", + "reproduction": { "baby_egg": "egg_eoraptor", "baby_count": 3, "baby_timer": 12 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM" ], "harvest": "mammal_tiny", "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "FIRE" ], @@ -327,8 +351,8 @@ "default_faction": "velociraptor", "symbol": "D", "color": "light_red_green", - "volume": "30000 ml", - "weight": "40750 g", + "volume": "15000 ml", + "weight": 15000, "material": "flesh", "aggression": 0, "morale": 20, @@ -340,11 +364,13 @@ "dodge": 3, "armor_bash": 1, "armor_cut": 1, - "luminance": 0, "hp": 30, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], "description": "A small bipedal dinosaur covered with feathers. Small, hooked claws emerge from its feet and hands.", + "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" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], @@ -357,11 +383,11 @@ "id": "mon_deinonychus", "name": { "str": "Deinonychus", "str_pl": "Deinonychus" }, "species": "DINOSAUR", - "default_faction": "deinoychus", + "default_faction": "deinonychus", "symbol": "D", "color": "red_green", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "75000 ml", + "weight": 75000, "material": "flesh", "aggression": 1, "morale": 50, @@ -373,11 +399,13 @@ "dodge": 2, "armor_bash": 1, "armor_cut": 1, - "luminance": 0, "hp": 60, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], "description": "A medium-sized bipedal dinosaur covered with feathers. At the end of each foot is a large sickle-like claw.", + "reproduction": { "baby_egg": "egg_deinonychus", "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" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], @@ -393,8 +421,8 @@ "default_faction": "utahraptor", "symbol": "D", "color": "dark_gray_white", - "volume": "92500 ml", - "weight": "120 kg", + "volume": "500000 ml", + "weight": 500000, "material": "flesh", "aggression": 30, "morale": 80, @@ -406,11 +434,13 @@ "dodge": 1, "armor_bash": 2, "armor_cut": 1, - "luminance": 0, "hp": 100, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], "description": "A large bipedal dinosaur with feathered arms, a long tail, and scythe-like claws.", + "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" ], "harvest": "dino_feather_leather", "anger_triggers": [ "STALK", "FRIEND_ATTACKED", "FRIEND_DIED", "PLAYER_WEAK", "HURT" ], @@ -426,8 +456,8 @@ "default_faction": "herbivore_dino", "symbol": "D", "color": "dark_gray_magenta", - "volume": "875000 ml", - "weight": "200 kg", + "volume": "3500000 ml", + "weight": 3500000, "material": "flesh", "aggression": -40, "morale": -10, @@ -439,48 +469,18 @@ "dodge": 0, "armor_bash": 4, "armor_cut": 4, - "luminance": 0, "hp": 300, "death_function": [ "NORMAL" ], "description": "A huge mottled dinosaur with a blunt head crest. It contentedly strips leaves from a nearby shrub.", + "reproduction": { "baby_egg": "egg_parasaurolophus", "baby_count": 3, "baby_timer": 24 }, + "baby_flags": [ "SPRING", "SUMMER" ], + "biosignature": { "biosig_item": "feces_bird", "biosig_timer": 3 }, "flags": [ "SEES", "SMELLS", "HEARS", "GOODHEARING", "ANIMAL", "PATH_AVOID_DANGER_1", "BASHES", "WARM" ], "harvest": "mammal_large_leather", "anger_triggers": [ "HURT" ], "fear_triggers": [ "SOUND", "PLAYER_CLOSE", "FIRE" ], "categories": [ "DINOSAUR" ] }, - { - "type": "MONSTER", - "id": "mon_dimorphodon", - "name": "Dimorphodon", - "species": "DINOSAUR", - "default_faction": "dimorphodon", - "symbol": "D", - "color": "light_gray_yellow", - "volume": "30000 ml", - "weight": "40750 g", - "material": "flesh", - "aggression": -80, - "morale": -8, - "speed": 110, - "melee_skill": 5, - "melee_dice": 2, - "melee_dice_sides": 6, - "melee_cut": 0, - "dodge": 3, - "armor_bash": 3, - "armor_cut": 1, - "luminance": 0, - "vision_day": 50, - "hp": 30, - "death_function": [ "NORMAL" ], - "description": "A small flying reptile, circling overhead looking for prey.", - "flags": [ "SEES", "SMELLS", "HEARS", "FLIES", "HIT_AND_RUN", "ANIMAL", "PATH_AVOID_DANGER_1", "BLEED" ], - "harvest": "animal_noskin", - "fear_triggers": [ "PLAYER_CLOSE", "FIRE", "FRIEND_DIED" ], - "placate_triggers": [ "MEAT" ], - "categories": [ "DINOSAUR" ] - }, { "type": "MONSTER", "id": "mon_dilophosaurus", @@ -489,8 +489,8 @@ "default_faction": "dilophosaurus", "symbol": "D", "color": "magenta_green", - "volume": "62500 ml", - "weight": "81500 g", + "volume": "400000 ml", + "weight": 400000, "material": "flesh", "aggression": 10, "morale": 30, @@ -502,11 +502,13 @@ "dodge": 1, "armor_bash": 3, "armor_cut": 1, - "luminance": 0, "hp": 120, "death_function": [ "NORMAL" ], "special_attacks": [ [ "BOOMER", 20 ] ], "description": "A medium dinosaur with a sticky green bile dripping from its teeth.", + "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" ], "harvest": "mammal_leather", "anger_triggers": [ "PLAYER_WEAK", "HURT" ], @@ -514,6 +516,126 @@ "placate_triggers": [ "MEAT" ], "categories": [ "DINOSAUR" ] }, + { + "id": "mon_compsognathus_hatchling", + "type": "MONSTER", + "name": "greenish yellow hatchling", + "description": "A tiny dinosaur hatchling with huge shiny eyes, it could be from a number of different species.", + "default_faction": "compsognathus", + "categories": [ "DINOSAUR" ], + "species": [ "DINOSAUR" ], + "diff": 10, + "volume": "2000 ml", + "weight": 2000, + "hp": 2, + "speed": 60, + "material": [ "flesh" ], + "symbol": "v", + "color": "green_yellow", + "looks_like": "mon_compsognathus", + "aggression": -99, + "morale": -8, + "melee_skill": 1, + "melee_dice": 1, + "melee_dice_sides": 1, + "melee_cut": 1, + "dodge": 1, + "death_function": [ "NORMAL" ], + "upgrades": { "age_grow": 14, "into": "mon_compsognathus" }, + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "CATFOOD" ], + "harvest": "mammal_tiny" + }, + { + "id": "mon_gallimimus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "light green and yellow hatchling", + "upgrades": { "age_grow": 20, "into": "mon_gallimimus" } + }, + { + "id": "mon_spinosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "red and white hatchling", + "upgrades": { "age_grow": 30, "into": "mon_spinosaurus" } + }, + { + "id": "mon_tyrannosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "light red and white hatchling", + "upgrades": { "age_grow": 30, "into": "mon_tyrannosaurus" } + }, + { + "id": "mon_triceratops_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "light green and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_triceratops" } + }, + { + "id": "mon_stegosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "green and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_stegosaurus" } + }, + { + "id": "mon_ankylosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "brown and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_ankylosaurus" } + }, + { + "id": "mon_allosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "brown and white hatchling", + "upgrades": { "age_grow": 30, "into": "mon_allosaurus" } + }, + { + "id": "mon_eoraptor_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and yellow hatchling", + "upgrades": { "age_grow": 10, "into": "mon_eoraptor" } + }, + { + "id": "mon_velociraptor_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and yellow hatchling", + "upgrades": { "age_grow": 20, "into": "mon_velociraptor" } + }, + { + "id": "mon_deinonychus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "red and green hatchling", + "upgrades": { "age_grow": 20, "into": "mon_deinonychus" } + }, + { + "id": "mon_utahraptor_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and white hatchling", + "upgrades": { "age_grow": 20, "into": "mon_utahraptor" } + }, + { + "id": "mon_parasaurolophus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "dark gray and magenta hatchling", + "upgrades": { "age_grow": 30, "into": "mon_parasaurolophus" } + }, + { + "id": "mon_dilophosaurus_hatchling", + "type": "MONSTER", + "copy-from": "mon_compsognathus_hatchling", + "name": "magenta and green hatchling", + "upgrades": { "age_grow": 20, "into": "mon_dilophosaurus" } + }, { "type": "monstergroup", "name": "GROUP_DINOSAUR", @@ -521,7 +643,6 @@ "monsters": [ { "monster": "mon_compsognathus", "freq": 100, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_gallimimus", "freq": 50, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, - { "monster": "mon_titanis", "freq": 10, "cost_multiplier": 10 }, { "monster": "mon_spinosaurus", "freq": 1, "cost_multiplier": 50 }, { "monster": "mon_tyrannosaurus", "freq": 1, "cost_multiplier": 40 }, { "monster": "mon_triceratops", "freq": 3, "cost_multiplier": 30, "pack_size": [ 1, 2 ] }, @@ -533,7 +654,6 @@ { "monster": "mon_deinonychus", "freq": 10, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, { "monster": "mon_utahraptor", "freq": 5, "cost_multiplier": 30 }, { "monster": "mon_parasaurolophus", "freq": 3, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_dimorphodon", "freq": 50, "cost_multiplier": 0, "pack_size": [ 2, 4 ] }, { "monster": "mon_dilophosaurus", "freq": 15, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] }, @@ -542,7 +662,6 @@ "name": "GROUP_DINOSAUR_HARMLESS", "default": "mon_null", "monsters": [ - { "monster": "mon_compsognathus", "freq": 100, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_gallimimus", "freq": 50, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, { "monster": "mon_eoraptor", "freq": 20, "cost_multiplier": 0, "pack_size": [ 4, 12 ] } ] @@ -552,7 +671,7 @@ "name": "GROUP_DINOSAUR_DANGEROUS", "default": "mon_null", "monsters": [ - { "monster": "mon_titanis", "freq": 10, "cost_multiplier": 10 }, + { "monster": "mon_compsognathus", "freq": 100, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_allosaurus", "freq": 2, "cost_multiplier": 30 }, { "monster": "mon_velociraptor", "freq": 15, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, { "monster": "mon_deinonychus", "freq": 10, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, @@ -560,12 +679,6 @@ { "monster": "mon_dilophosaurus", "freq": 15, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] }, - { - "type": "monstergroup", - "name": "GROUP_DINOSAUR_FLY", - "default": "mon_null", - "monsters": [ { "monster": "mon_dimorphodon", "freq": 50, "cost_multiplier": 0, "pack_size": [ 2, 4 ] } ] - }, { "type": "monstergroup", "name": "GROUP_DINOSAUR_MEGA_HERBIVORE", @@ -587,11 +700,64 @@ { "monster": "mon_allosaurus", "freq": 2, "cost_multiplier": 30 } ] }, + { + "type": "monstergroup", + "name": "GROUP_FOREST", + "default": "mon_null", + "is_animal": true, + "monsters": [ + { + "monster": "mon_gallimimus", + "freq": 20, + "cost_multiplier": 0, + "pack_size": [ 4, 8 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_stegosaurus", + "freq": 10, + "cost_multiplier": 20, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_ankylosaurus", + "freq": 3, + "cost_multiplier": 20, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_triceratops", + "freq": 10, + "cost_multiplier": 30, + "pack_size": [ 1, 2 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_dilophosaurus", + "freq": 5, + "cost_multiplier": 10, + "pack_size": [ 1, 2 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { "monster": "mon_utahraptor", "freq": 3, "cost_multiplier": 30 }, + { + "monster": "mon_eoraptor", + "freq": 3, + "cost_multiplier": 0, + "pack_size": [ 4, 12 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + } + ] + }, { "type": "monstergroup", "name": "GROUP_SWAMP", "default": "mon_null", + "is_animal": true, "monsters": [ + { "monster": "mon_parasaurolophus", "freq": 30, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, + { "monster": "mon_deinonychus", "freq": 10, "cost_multiplier": 15, "pack_size": [ 2, 3 ] }, { "monster": "mon_spinosaurus", "freq": 1, "cost_multiplier": 50 }, { "monster": "mon_tyrannosaurus", "freq": 1, "cost_multiplier": 40 }, { "monster": "mon_allosaurus", "freq": 2, "cost_multiplier": 30 } @@ -601,17 +767,13 @@ "type": "monstergroup", "name": "GROUP_SEWER", "default": "mon_sewer_rat", + "is_animal": true, "monsters": [ - { "monster": "mon_compsognathus", "freq": 600, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, - { "monster": "mon_gallimimus", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, - { "monster": "mon_titanis", "freq": 150, "cost_multiplier": 10 }, - { "monster": "mon_spinosaurus", "freq": 50, "cost_multiplier": 50 }, - { "monster": "mon_ankylosaurus", "freq": 80, "cost_multiplier": 20 }, + { "monster": "mon_compsognathus", "freq": 300, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_eoraptor", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_velociraptor", "freq": 150, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 2, 3 ] }, { "monster": "mon_utahraptor", "freq": 100, "cost_multiplier": 30 }, - { "monster": "mon_parasaurolophus", "freq": 80, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, { "monster": "mon_dilophosaurus", "freq": 150, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] }, @@ -621,19 +783,18 @@ "is_safe": true, "default": "mon_null", "monsters": [ - { "monster": "mon_compsognathus", "freq": 1, "cost_multiplier": 1, "pack_size": [ 4, 12 ] }, - { "monster": "mon_gallimimus", "freq": 1, "cost_multiplier": 1, "pack_size": [ 4, 8 ] }, - { "monster": "mon_eoraptor", "freq": 1, "cost_multiplier": 1, "pack_size": [ 4, 12 ] } + { "monster": "mon_gallimimus", "freq": 50, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, + { "monster": "mon_eoraptor", "freq": 20, "cost_multiplier": 0, "pack_size": [ 4, 12 ] } ] }, { "type": "monstergroup", "name": "GROUP_CAVE", "default": "mon_null", + "is_animal": true, "monsters": [ { "monster": "mon_compsognathus", "freq": 600, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_gallimimus", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 8 ] }, - { "monster": "mon_titanis", "freq": 150, "cost_multiplier": 10 }, { "monster": "mon_spinosaurus", "freq": 50, "cost_multiplier": 50 }, { "monster": "mon_tyrannosaurus", "freq": 50, "cost_multiplier": 40 }, { "monster": "mon_triceratops", "freq": 80, "cost_multiplier": 30, "pack_size": [ 1, 2 ] }, @@ -642,10 +803,9 @@ { "monster": "mon_allosaurus", "freq": 100, "cost_multiplier": 30 }, { "monster": "mon_eoraptor", "freq": 200, "cost_multiplier": 0, "pack_size": [ 4, 12 ] }, { "monster": "mon_velociraptor", "freq": 150, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "mon_deinonychus", "freq": 100, "cost_multiplier": 15, "pack_size": [ 2, 3 ] }, { "monster": "mon_utahraptor", "freq": 100, "cost_multiplier": 30 }, { "monster": "mon_parasaurolophus", "freq": 80, "cost_multiplier": 10, "pack_size": [ 2, 4 ] }, - { "monster": "mon_dimorphodon", "freq": 500, "cost_multiplier": 0, "pack_size": [ 2, 4 ] }, { "monster": "mon_dilophosaurus", "freq": 150, "cost_multiplier": 10, "pack_size": [ 1, 2 ] } ] } diff --git a/data/mods/DinoMod/egg.json b/data/mods/DinoMod/egg.json new file mode 100644 index 0000000000000..e92131e9cd3cf --- /dev/null +++ b/data/mods/DinoMod/egg.json @@ -0,0 +1,108 @@ +[ + { + "type": "COMESTIBLE", + "id": "egg_dino", + "name": "dinosaur egg", + "weight": 75, + "color": "green", + "spoils_in": "14 days", + "comestible_type": "FOOD", + "symbol": "o", + "quench": 4, + "healthy": 1, + "calories": 113, + "description": "Pale, football-shaped egg laid by a dinosaur.", + "price": 500, + "material": "egg", + "volume": 1, + "stack_size": 4, + "fun": -6, + "flags": [ "FREEZERBURN" ], + "rot_spawn": "GROUP_EGG_DINO", + "rot_spawn_chance": 70 + }, + { + "type": "COMESTIBLE", + "id": "egg_compsognathus", + "name": "compsognathus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_gallimimus", + "name": "gallimimus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_spinosaurus", + "name": "spinosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_tyrannosaurus", + "name": "tyrannosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_triceratops", + "name": "triceratops egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_stegosaurus", + "name": "stegosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_ankylosaurus", + "name": "ankylosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_allosaurus", + "name": "allosaurus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_eoraptor", + "name": "eoraptor egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_velociraptor", + "name": "velociraptor egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_deinonychus", + "name": "deinonychus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_utahraptor", + "name": "utahraptor egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_parasaurolophus", + "name": "parasaurolophus egg", + "copy-from": "egg_dino" + }, + { + "type": "COMESTIBLE", + "id": "egg_dilophosaurus", + "name": "dilophosaurus egg", + "copy-from": "egg_dino" + } +] diff --git a/data/mods/DinoMod/forage.json b/data/mods/DinoMod/forage.json new file mode 100644 index 0000000000000..a9f60cbefe80d --- /dev/null +++ b/data/mods/DinoMod/forage.json @@ -0,0 +1,14 @@ +[ + { + "id": "forage_spring", + "type": "item_group", + "subtype": "distribution", + "entries": [ { "item": "egg_dino", "prob": 3, "count-min": 2, "count-max": 5 } ] + }, + { + "id": "forage_summer", + "type": "item_group", + "subtype": "distribution", + "entries": [ { "item": "egg_dino", "prob": 3, "count-min": 2, "count-max": 5 } ] + } +] diff --git a/data/mods/DinoMod/lab_notes.json b/data/mods/DinoMod/lab_notes.json new file mode 100644 index 0000000000000..ae03e7703214b --- /dev/null +++ b/data/mods/DinoMod/lab_notes.json @@ -0,0 +1,10 @@ +{ + "type": "snippet", + "category": "lab_notes", + "text": [ + "Research on our visitors is proceeding nicely. The raptor DNA is of special interest, with some novel protein chains that may lead to medical breakthroughs.", + "Dr. Yoshimi has been reprimanded for unauthorized contact with the procompsignathids. Disgusting behavior, and a terrible example to the junior researchers.", + "Dr. Yoshimi has escaped, along with an unknown number of dinosaurs. Unfortunately, we have bigger problems with XE037.", + "Strange sounds have been reported from the swamp nearby. An enhanced security team was dispatched, but has not returned in 48 hours. The facility is on lockdown. We can’t let them get back in." + ] +} diff --git a/data/mods/DinoMod/monstergroups_egg.json b/data/mods/DinoMod/monstergroups_egg.json new file mode 100644 index 0000000000000..b44b015cc31af --- /dev/null +++ b/data/mods/DinoMod/monstergroups_egg.json @@ -0,0 +1,23 @@ +[ + { + "name": "GROUP_EGG_DINO", + "type": "monstergroup", + "default": "mon_compsognathus_hatchling", + "monsters": [ + { "monster": "mon_compsognathus_hatchling", "freq": 100, "cost_multiplier": 1 }, + { "monster": "mon_gallimimus_hatchling", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_spinosaurus_hatchling", "freq": 1, "cost_multiplier": 1 }, + { "monster": "mon_tyrannosaurus_hatchling", "freq": 1, "cost_multiplier": 1 }, + { "monster": "mon_triceratops_hatchling", "freq": 3, "cost_multiplier": 1 }, + { "monster": "mon_stegosaurus_hatchling", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_ankylosaurus_hatchling", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_allosaurus_hatchling", "freq": 2, "cost_multiplier": 1 }, + { "monster": "mon_eoraptor_hatchling", "freq": 20, "cost_multiplier": 1 }, + { "monster": "mon_velociraptor_hatchling", "freq": 15, "cost_multiplier": 1 }, + { "monster": "mon_deinonychus_hatchling", "freq": 10, "cost_multiplier": 1 }, + { "monster": "mon_utahraptor_hatchling", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_parasaurolophus_hatchling", "freq": 3, "cost_multiplier": 1 }, + { "monster": "mon_dilophosaurus_hatchling", "freq": 15, "cost_multiplier": 1 } + ] + } +] diff --git a/data/mods/DinoMod/recipe_medsandchemicals.json b/data/mods/DinoMod/recipe_medsandchemicals.json new file mode 100644 index 0000000000000..05fe942030cff --- /dev/null +++ b/data/mods/DinoMod/recipe_medsandchemicals.json @@ -0,0 +1,20 @@ +[ + { + "type": "recipe", + "result": "mutagen_raptor", + "category": "CC_CHEM", + "subcategory": "CSC_CHEM_MUTAGEN", + "skill_used": "cooking", + "skills_required": [ "firstaid", 1 ], + "difficulty": 9, + "time": 10000, + "book_learn": [ [ "recipe_raptor", 9 ] ], + "qualities": [ { "id": "CHEM", "level": 3 } ], + "tools": [ [ [ "surface_heat", 25, "LIST" ] ] ], + "components": [ + [ [ "mutagen", 1 ] ], + [ [ "egg_dino", 1 ], [ "egg_velociraptor", 1 ], [ "egg_deinonychus", 1 ], [ "egg_utahraptor", 1 ] ], + [ [ "ammonia", 1 ], [ "lye_powder", 100 ] ] + ] + } +] From 717a8ebd2203162ed5983053d752b262a9e5c196 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 6 Mar 2020 05:09:21 -0500 Subject: [PATCH 119/219] [Aftershock] Millyficent whately and the migo (#36908) --- data/mods/Aftershock/effects.json | 58 +++ data/mods/Aftershock/items/mutagen.json | 22 ++ .../maps/mapgen/millyficent_lab.json | 335 ++++++++++++++++++ .../Aftershock/maps/overmap_specials.json | 16 + .../mods/Aftershock/maps/overmap_terrain.json | 33 ++ .../mods/Aftershock/mobs/monster_faction.json | 7 + data/mods/Aftershock/mutations/dreams.json | 35 ++ data/mods/Aftershock/mutations/mutations.json | 264 ++++++++++++++ data/mods/Aftershock/npcs/classes.json | 37 ++ data/mods/Aftershock/npcs/factions.json | 70 ++++ .../Aftershock/npcs/whately_dialogue.json | 193 ++++++++++ 11 files changed, 1070 insertions(+) create mode 100644 data/mods/Aftershock/effects.json create mode 100644 data/mods/Aftershock/items/mutagen.json create mode 100644 data/mods/Aftershock/maps/mapgen/millyficent_lab.json create mode 100644 data/mods/Aftershock/mutations/dreams.json create mode 100644 data/mods/Aftershock/npcs/whately_dialogue.json diff --git a/data/mods/Aftershock/effects.json b/data/mods/Aftershock/effects.json new file mode 100644 index 0000000000000..f0a14dc006566 --- /dev/null +++ b/data/mods/Aftershock/effects.json @@ -0,0 +1,58 @@ +[ + { + "id": "fd_migo_atmosphere", + "type": "field_type", + "intensity_levels": [ + { + "name": "foul-smelling air", + "sym": "8", + "dangerous": true, + "effects": [ + { + "effect_id": "migo_atmosphere", + "body_part": "MOUTH", + "intensity": 1, + "min_duration": "5 seconds", + "max_duration": "10 seconds", + "immune_inside_vehicle": true + } + ] + }, + { + "name": "foul-smelling air", + "translucency": 1, + "effects": [ + { + "effect_id": "migo_atmosphere", + "body_part": "MOUTH", + "intensity": 2, + "min_duration": "10 seconds", + "max_duration": "25 seconds" + } + ] + }, + { + "name": "foul-smelling air", + "effects": [ + { + "effect_id": "migo_atmosphere", + "body_part": "MOUTH", + "intensity": 4, + "min_duration": "15 seconds", + "max_duration": "25 seconds" + } + ] + } + ], + "decay_amount_factor": 5, + "gas_absorption_factor": 15, + "percent_spread": 30, + "outdoor_age_speedup": "3 minutes", + "dirty_transparency_cache": true, + "has_fume": true, + "immunity_data": { "body_part_env_resistance": [ [ "MOUTH", 15 ] ], "traits": [ "MIGO_BREATHE" ] }, + "priority": 8, + "half_life": "10 minutes", + "phase": "gas" + } +] diff --git a/data/mods/Aftershock/items/mutagen.json b/data/mods/Aftershock/items/mutagen.json new file mode 100644 index 0000000000000..b17547f34c6cd --- /dev/null +++ b/data/mods/Aftershock/items/mutagen.json @@ -0,0 +1,22 @@ +[ + { + "id": "iv_mutagen_migo", + "copy-from": "iv_mutagen_flavor", + "type": "COMESTIBLE", + "name": "mi-go serum", + "description": "A super-concentrated mutagen strongly resembling a lava lamp. You need a syringe to inject it… if you really want to?", + "price": 1000000, + "color": "red", + "healthy": -4, + "use_action": { "type": "mutagen_iv", "mutation_category": "MIGO" } + }, + { + "id": "mutagen_migo", + "copy-from": "mutagen_flavor", + "type": "COMESTIBLE", + "name": "mi-go mutagen", + "description": "An extremely rare mutagen cocktail, it smells of sulphur and glows orange.", + "price": 500000, + "use_action": { "type": "mutagen", "mutation_category": "MIGO" } + } +] diff --git a/data/mods/Aftershock/maps/mapgen/millyficent_lab.json b/data/mods/Aftershock/maps/mapgen/millyficent_lab.json new file mode 100644 index 0000000000000..820ffad36f229 --- /dev/null +++ b/data/mods/Aftershock/maps/mapgen/millyficent_lab.json @@ -0,0 +1,335 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "mortuary_2story" ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + "..,,,,,...uuuu...,,,,,..", + "..,,,,,..uaaaau..,,,,,..", + "..,,,,,.uaffffau.,,,,,..", + "..,,,,,..uuuuuu..,,,,,..", + "..,,,,,..........,,,,,..", + "..,,,,,,........,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "..,,,,,,,,,,,,,,,,,,,,..", + "...,,,,,,,,,,,,,,,,,,...", + "....uuuu.|o++o|.uuuu....", + "..|-oooo-|P P|-oooo-|u.", + "..oP cc P|H H| |fu", + "|-|c c|H H| H H ofu", + "|&|c c| | H H |fu", + "| + + DD + H H P|u.", + "|i|D ll P|P hP| H H C|..", + "--|------|-++-| H H P|u.", + ".4|dT~T~i|C O| |fu", + "..|------|-++-|-o--o-|u.", + ".........u.,,.u........." + ], + "terrain": { + " ": "t_floor", + "*": "t_door_locked_interior", + "+": "t_door_c", + ",": "t_pavement", + "-": "t_wall_w", + ".": "t_grass", + "L": "t_linoleum_white", + "T": "t_linoleum_white", + "a": "t_dirt", + "d": "t_linoleum_white", + "f": "t_dirt", + "i": "t_linoleum_white", + "o": "t_window_bars_curtains", + "u": "t_shrub", + "|": "t_wall_w", + "~": "t_linoleum_white", + "4": "t_gutter_downspout", + ">": "t_wood_stairs_down", + "<": "t_wood_stairs_up" + }, + "toilets": { "&": { "amount": [ 0, 50 ] } }, + "furniture": { + "C": "f_coffin_c", + "D": "f_desk", + "H": "f_bench", + "h": "f_chair", + "L": "f_locker", + "O": "f_coffin_o", + "P": [ "f_indoor_plant_y", "f_indoor_plant" ], + "T": "f_table", + "a": "f_dahlia", + "c": "f_sofa", + "d": "f_rack", + "f": [ "f_datura", "f_bluebell", "f_mutpoppy", "f_dahlia", "f_flower_tulip", "f_chamomile", "f_flower_spurge", "f_lily" ], + "i": "f_sink", + "l": "f_bookcase" + }, + "place_signs": [ { "signage": "Whately Family Mortuary Services. Serving New England for three hundred years.'", "x": 15, "y": 11 } ], + "place_items": [ + { "item": "cleaning", "x": 3, "y": [ 19, 20 ], "chance": 50 }, + { "item": "dissection", "x": 3, "y": 21, "chance": 70 }, + { "item": "church", "x": [ 16, 18 ], "y": [ 14, 20 ], "chance": 50 }, + { "item": "lab_torso", "x": 8, "y": 19, "chance": 50 }, + { "item": "bionics_common", "x": 8, "y": 19, "chance": 30 }, + { "item": "homebooks", "x": [ 5, 6 ], "y": 17, "chance": 50 }, + { "item": "magazines", "x": 3, "y": 17, "chance": 50 } + ], + "place_loot": [ + { "group": "corpse_male_mortuary", "x": 4, "y": 19, "chance": 40 }, + { "group": "corpse_female_mortuary", "x": 6, "y": 19, "chance": 40 }, + { "group": "corpse_female_mortuary", "x": 6, "y": 21, "chance": 40 }, + { "group": "corpse_viewing", "x": 20, "y": 17, "chance": 50 } + ], + "place_vehicles": [ { "vehicle": "hearse", "x": 12, "y": 7, "chance": 90 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "mortuary_basement" ], + "weight": 200, + "object": { + "rotation": [ 0, 3 ], + "fill_ter": "t_rock", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " |||||||||||| ", + " |T8T5CfHH??| ", + " |,h,,,,,,,?| ", + " |n,,,*,,???| ", + " ||||,,,,|||| ", + " |ffG,,,,ACA| ", + " ||||,,,,,,,,,,||||| ", + " |&_+*,,,,,*,TTT|EWU| ", + " |i_|,,TT,,,,,,+_*_| ", + " |||||+||,,||+|||||| ", + " |i,A,F|++|U__XU| ", + " |D,*,T|..|U_*_c| ", + " |b,,hT|<<|U___c| ", + " |b,n,T||||U_U_U| ", + " ||||||| ||||||| ", + " ", + " ", + " " + ], + "terrain": { + "|": "t_wall", + "<": "t_stairs_up", + "+": "t_door_c", + ".": "t_floor", + "_": "t_linoleum_gray", + "c": "t_linoleum_gray", + "U": "t_linoleum_gray", + "X": "t_linoleum_gray", + "E": "t_linoleum_gray", + "i": "t_linoleum_gray", + "&": "t_linoleum_gray", + ",": "t_linoleum_white", + "C": "t_linoleum_white", + "?": "t_linoleum_white", + "A": "t_linoleum_white", + "h": "t_linoleum_white", + "D": "t_linoleum_white", + "5": "t_linoleum_white", + "F": "t_linoleum_white", + "f": "t_linoleum_white", + "G": "t_linoleum_white", + "b": "t_linoleum_white", + "n": "t_linoleum_white", + "H": "t_linoleum_white", + "T": "t_linoleum_white", + "8": "t_console_broken", + "W": "t_water_dispenser", + "*": "t_utility_light" + }, + "liquids": { "E": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, + "furniture": { + "T": "f_workbench", + "G": "f_glass_cabinet", + "c": "f_counter", + "h": "f_chair", + "A": "f_air_filter", + "C": "f_air_conditioner", + "E": "f_water_heater", + "X": [ "f_crate_c", "f_crate_o", "f_cardboard_box" ], + "U": "f_utility_shelf", + "H": "f_bookcase", + "F": "f_glass_fridge", + "i": "f_sink", + "?": "f_sofa", + "n": "f_trashcan", + "f": "f_filing_cabinet", + "5": "f_server", + "b": "f_lab_bench", + "D": "f_fume_hood" + }, + "items": { + "U": [ + { "item": "cleaning", "chance": 30 }, + { "item": "supplies_reagents_lab", "chance": 10 }, + { "item": "home_hw", "chance": 50 }, + { "item": "supplies_electronics", "chance": 50 } + ], + "c": [ { "item": "home_hw", "chance": 70 } ], + "X": [ { "item": "electronics", "chance": 70 } ], + "b": [ { "item": "chem_home", "chance": 30 } ], + "D": [ { "item": "chem_home", "chance": 60 } ], + "i": [ { "item": "trash", "chance": 60 } ], + "F": [ { "item": "chem_home", "chance": 50 }, { "item": "supplies_reagents_lab", "chance": 20 } ], + "T": [ { "item": "chem_home", "chance": 30 }, { "item": "electronics", "chance": 50 } ], + "f": [ { "item": "file_room", "chance": 70, "repeat": [ 1, 5 ] } ], + "G": [ { "item": "office_paper", "chance": 30 } ], + "H": [ { "item": "magazines", "chance": 40, "repeat": [ 1, 2 ] }, { "item": "lab_bookshelves", "chance": 20 } ] + }, + "toilets": { "&": { "amount": [ 0, 50 ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "mortuary_2story_second" ], + "object": { + "fill_ter": "t_open_air", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________|w||w|_________", + "__||wwww||%%%%||wwww||__", + "__wZZil.b|%%%%|8....1|__", + "|||ZZ..cb|%%%%|F.....w__", + "|&|A....b|%%%%|e.....|__", + "|%+......+%%%%m.....1|__", + "|S|D ll P|%%%%|E.....|__", + "||||||||||:++:|h.....|__", + "__|BB>CoC|1..t|a....1|__", + "__|B..*..+.*st|o.....w__", + "__|TBBfiB|1..t|......|__", + "__||||||||||||||w||w||__", + "________________________" + ], + "toilets": { "&": { } }, + "terrain": { + ".": "t_floor", + "#": "t_brick_wall", + "|": "t_strconc_wall", + " ": "t_strconc_floor", + "%": "t_linoleum_white", + "+": "t_door_c", + "-": "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", + "*": "t_utility_light", + "w": "t_window_bars_curtains", + ">": "t_wood_stairs_down" + }, + "furniture": { + "T": "f_trashcan", + "1": [ "f_indoor_plant", "f_indoor_plant_y" ], + "5": "f_server", + "8": "f_sample_freezer", + "a": "f_autoclave", + "A": "f_air_filter", + "b": "f_lab_bench", + "B": "f_bookcase", + "C": "f_counter", + "c": "f_chair", + "d": "f_desk", + "D": "f_dishwasher", + "e": "f_eyewash", + "E": "f_electron_microscope", + "F": "f_fume_hood", + "f": "f_fridge", + "G": "f_GC", + "h": "f_shaker", + "H": "f_HPLC", + "i": "f_filing_cabinet", + "I": "f_scan_bed", + "l": "f_locker", + "M": "f_MS", + "N": "f_NMR", + "O": "f_MRI", + "0": "f_CTscan", + "r": "f_rack", + "s": "f_stool", + "S": "f_sink", + "t": "f_table", + "U": "f_utility_shelf", + "v": "f_ventilator", + "Z": "f_bed" + }, + "place_npcs": [ { "class": "millyficent_whately", "x": 17, "y": 14 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "mortuary_2story_roof", + "object": { + "fill_ter": "t_flat_roof", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |22223 ", + " |222222|....|2222223 ", + " |..................3 ", + "|2|..................3 ", + "|....................3 ", + "|.U..................3 ", + "|....................3 ", + "--5..................3 ", + " |..................3 ", + " |..................3 ", + " |..................3 ", + " |------------------3 ", + " " + ], + "palettes": [ "roof_palette" ], + "nested": { "U": { "chunks": [ "roof_2x2_infrastructure" ] } }, + "place_nested": [ + { + "chunks": [ + [ "null", 20 ], + [ "roof_2x2_utilities_b", 15 ], + [ "roof_2x2_utilities_c", 5 ], + [ "roof_2x2_utilities_d", 40 ], + [ "roof_2x2_utilities", 50 ] + ], + "x": [ 4, 17 ], + "y": [ 14, 19 ] + } + ] + } + } +] diff --git a/data/mods/Aftershock/maps/overmap_specials.json b/data/mods/Aftershock/maps/overmap_specials.json index 4925449cd2642..71cb777cac0dd 100644 --- a/data/mods/Aftershock/maps/overmap_specials.json +++ b/data/mods/Aftershock/maps/overmap_specials.json @@ -45,5 +45,21 @@ "flags": [ "FUNGAL" ], "rotate": false, "spawns": { "group": "GROUP_FUNGI_TOWER", "population": [ 125, 175 ], "radius": [ 2, 2 ] } + }, + { + "type": "overmap_special", + "id": "mortuary_2story", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "mortuary_2story_north" }, + { "point": [ 0, 0, 1 ], "overmap": "mortuary_2story_second_north" }, + { "point": [ 0, 0, -1 ], "overmap": "mortuary_basement_north" }, + { "point": [ 0, 0, 2 ], "overmap": "mortuary_roof_north" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road" } ], + "locations": [ "land" ], + "city_distance": [ 5, -1 ], + "city_sizes": [ 2, -1 ], + "occurrences": [ 0, 1 ], + "flags": [ "CLASSIC" ] } ] diff --git a/data/mods/Aftershock/maps/overmap_terrain.json b/data/mods/Aftershock/maps/overmap_terrain.json index 0fb0e584e5349..0361a3988aee4 100644 --- a/data/mods/Aftershock/maps/overmap_terrain.json +++ b/data/mods/Aftershock/maps/overmap_terrain.json @@ -73,5 +73,38 @@ "see_cost": 3, "extras": "marloss", "flags": [ "NO_ROTATE", "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "mortuary_2story", + "name": "county mortuary", + "sym": "M", + "color": "light_green", + "see_cost": 3, + "flags": [ "SIDEWALK" ] + }, + { + "type": "overmap_terrain", + "id": "mortuary_basement", + "name": "county mortuary basement", + "sym": "M", + "color": "white", + "see_cost": 3 + }, + { + "type": "overmap_terrain", + "id": "mortuary_2story_second", + "name": "county mortuary second floor", + "sym": "M", + "color": "light_green", + "see_cost": 3 + }, + { + "type": "overmap_terrain", + "id": "mortuary_2story_roof", + "name": "county mortuary roof", + "sym": "M", + "color": "light_green", + "see_cost": 3 } ] diff --git a/data/mods/Aftershock/mobs/monster_faction.json b/data/mods/Aftershock/mobs/monster_faction.json index 1c23ef23ed06d..91b25239f299d 100644 --- a/data/mods/Aftershock/mobs/monster_faction.json +++ b/data/mods/Aftershock/mobs/monster_faction.json @@ -5,5 +5,12 @@ "friendly": [ "Prepnet_Phyle", "human", "PrepNet", "player" ], "neutral": "herbivore", "by_mood": [ "insect", "small_animal" ] + }, + { + "type": "MONSTER_FACTION", + "name": "whately", + "friendly": [ "human", "player" ], + "neutral": "herbivore", + "by_mood": [ "insect", "small_animal" ] } ] diff --git a/data/mods/Aftershock/mutations/dreams.json b/data/mods/Aftershock/mutations/dreams.json new file mode 100644 index 0000000000000..8d9c5a3928e8c --- /dev/null +++ b/data/mods/Aftershock/mutations/dreams.json @@ -0,0 +1,35 @@ +[ + { + "type": "dream", + "messages": [ "You dream of warm, alien winds.", "You dream of landscapes lit by the light of alien moons." ], + "category": "MIGO", + "strength": 1 + }, + { + "type": "dream", + "messages": [ + "You stand at the edge of a fissure into strange earth. Mustard brown gasses caress and lift your fronds", + "You dream of being vivsected by humans. One asks if the other thinks you can feel pain." + ], + "category": "MIGO", + "strength": 2 + }, + { + "type": "dream", + "messages": [ + "Trapped in a cage, you mimic the sounds of your guard's spawn. He threatens you and enters the cage. He screams, you recall.", + "It's your birthday. But everyone has given you these hideous metal and plastic objects." + ], + "category": "MIGO", + "strength": 3 + }, + { + "type": "dream", + "messages": [ + "The stars await you, your chariot of fire is ready. The holds are full of slaves.", + "You have transitioned from a dying race to a glorious future." + ], + "category": "MIGO", + "strength": 4 + } +] diff --git a/data/mods/Aftershock/mutations/mutations.json b/data/mods/Aftershock/mutations/mutations.json index f20602050727b..79c6da950a6d4 100644 --- a/data/mods/Aftershock/mutations/mutations.json +++ b/data/mods/Aftershock/mutations/mutations.json @@ -8,5 +8,269 @@ "description": "NPC trait that makes monsters see it as a Prepnet. It is a bug if you have it.", "player_display": false, "threshold": true + }, + { + "type": "mutation_category", + "id": "MIGO", + "name": "YUGGOTH", + "threshold_mut": "THRESH_YUGGOTH", + "mutagen_message": "Strange memories of another world overwhelm you…", + "iv_message": "You look into your own cells and change them.", + "iv_pain": 10, + "iv_morale": 25, + "iv_morale_max": 100, + "iv_sleep": true, + "//": "Should be out for two minutes. Nightmare realm becomes home", + "iv_sleep_dur": 20, + "iv_sleep_message": "You gaze inside, past your fear, past good and evil, into the future.", + "memorial_message": "Prepared the way into the galaxy." + }, + { + "type": "mutation", + "id": "MIGO_HEAT_RESIST", + "name": "Mi-go acclimatization", + "points": 4, + "bodytemp_modifiers": [ -2500, -6500 ], + "description": "Fleshy fronds grown from your scalp function like organic heat sinks. They allow you to live comfortably within the mi-go atmosphere.", + "player_display": true, + "threshreq": [ "THRESH_YUGGOTH" ], + "starting_trait": false, + "types": [ "METABOLISM" ], + "active": true, + "category": [ "MIGO" ], + "prereqs": [ "WARM_NATURED" ] + }, + { + "type": "mutation", + "id": "FACIAL_TENTACLES", + "name": "Facial Tentacles", + "points": 1, + "visibility": 8, + "ugliness": 5, + "description": "A set of tentacles surrounds your mouth. They allow you to eat twice as fast. Slightly decreases wet penalties.", + "prereqs": [ "MOUTH_TENDRILS" ], + "cancels": [ "MANDIBLES" ], + "category": [ "MIGO" ], + "wet_protection": [ { "part": "MOUTH", "neutral": 4 } ] + }, + { + "type": "mutation", + "id": "MOUTH_TENDRILS", + "name": "Mouth Tendrils", + "points": -1, + "visibility": 7, + "ugliness": 6, + "description": "Skin tabs and odd flaps of skin surround your mouth. They don't affect your eating, but are unpleasant to look at.", + "category": [ "MIGO" ], + "leads_to": [ "FACIAL_TENTACLES" ] + }, + { + "type": "mutation", + "id": "WARM_NATURED", + "name": "Warm Natured", + "points": 2, + "description": "Your body becomes much more efficient at distributing heat from itself.", + "category": [ "MIGO" ], + "leads_to": [ "MIGO_HEAT_RESIST" ], + "bodytemp_modifiers": [ -500, -1250 ] + }, + { + "type": "mutation", + "id": "NEURAL_IMPROVEMENT", + "name": "Neural Improvement", + "points": 1, + "description": "You see the world a little differently today. Intelligence + 1", + "changes_to": [ "EXPANDED_CONSCIOUSNESS" ], + "category": [ "MIGO" ], + "passive_mods": { "int_mod": 1 } + }, + { + "type": "mutation", + "id": "EXPANDED_CONSCIOUSNESS", + "name": "Expanded Consciousness", + "points": 2, + "description": "You are beginning to see a way off this planet. Intelligence + 2", + "prereqs": [ "NEURAL_IMPROVEMENT" ], + "changes_to": [ "UPLIFTED" ], + "category": [ "MIGO" ], + "passive_mods": { "int_mod": 2 } + }, + { + "type": "mutation", + "id": "UPLIFTED", + "name": "Extremely Smart", + "points": 3, + "visibility": 1, + "ugliness": 1, + "description": "As humans uplifted our pets in the final years this process is lifting you to a new level of intelligence. Intelligence + 4", + "prereqs": [ "EXPANDED_CONSCIOUSNESS" ], + "changes_to": [ "ALIEN_INT" ], + "category": [ "MIGO" ], + "passive_mods": { "int_mod": 4 } + }, + { + "type": "mutation", + "id": "ALIEN_INT", + "name": "Alien Intelligence", + "points": 3, + "visibility": 3, + "ugliness": 6, + "description": "You can see the connections from A to B to C to D. You look at fellow survivors like you are imagining taking them apart. Intelligence + 5", + "prereqs": [ "UPLIFTED" ], + "category": [ "MIGO" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "starting_trait": false, + "passive_mods": { "int_mod": 5 } + }, + { + "type": "mutation", + "id": "ENHANCED_REACTIONS", + "name": "Enhanced Reactions", + "points": 1, + "description": "Today is the day to start juggling. Dexterity + 1", + "changes_to": [ "QUICKENING" ], + "category": [ "MIGO" ], + "passive_mods": { "dex_mod": 1 } + }, + { + "type": "mutation", + "id": "QUICKENING", + "name": "Quickening", + "points": 2, + "description": "You are starting to move like they do. Dexterity + 2", + "prereqs": [ "ENHANCED_REACTIONS" ], + "changes_to": [ "OTHERWORLDLY_GRACE" ], + "category": [ "MIGO" ], + "passive_mods": { "dex_mod": 2 } + }, + { + "type": "mutation", + "id": "OTHERWORLDLY_GRACE", + "name": "Otherworldly Grace", + "points": 3, + "description": "You no longer move like a human, others find it disconcerting. Dexterity + 4", + "prereqs": [ "ENHANCED_REACTIONS" ], + "category": [ "MIGO" ], + "passive_mods": { "dex_mod": 4 } + }, + { + "type": "mutation", + "id": "NEW_MUSCLES", + "name": "New Muscles", + "points": 1, + "description": "You see some new muscles that you aren't sure you've seen on humans before. Strength + 1", + "changes_to": [ "MUSCLE_FIBER" ], + "category": [ "MIGO" ], + "passive_mods": { "str_mod": 1 } + }, + { + "type": "mutation", + "id": "MUSCLE_FIBER", + "name": "Muscle Fiber", + "points": 2, + "description": "Fibrous tissue seems to be spreading through your body. Strength + 2", + "prereqs": [ "STR_UP" ], + "category": [ "MIGO" ], + "passive_mods": { "str_mod": 2 } + }, + { + "type": "mutation", + "id": "MIGO_EARS", + "name": "Mi-go Ears", + "points": 1, + "visibility": 4, + "description": "Your ears have split into a series of tuberous projections. They waggle towards far away sounds.", + "types": [ "EARS" ], + "category": [ "MIGO" ], + "hearing_modifier": 1.4 + }, + { + "type": "mutation", + "id": "DETACHMENT", + "name": "Detachment", + "points": 2, + "flags": [ "PRED1" ], + "description": "When were you ever like these creatures, helpless before the changes ravaging this world. ", + "purifiable": false, + "changes_to": [ "PRED2" ], + "prereqs": [ "THRESH_YUGGOTH" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "cancels": [ "PACIFIST" ], + "category": [ "MIGO" ] + }, + { + "type": "mutation", + "id": "ELDRITCH", + "name": "Eldritch", + "points": 3, + "description": "You have a sinister aspect to your demeanor, no longer part of this world. You feel no sorrow at the deaths of humans and your brain now processes combat skills more efficiently as you mentally dissect your opponents.", + "social_modifiers": { "intimidate": 3 }, + "purifiable": false, + "flags": [ "PRED1" ], + "prereqs": [ "THRESH_YUGGOTH" ], + "prereqs2": [ "DETACHMENT" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "cancels": [ "PACIFIST" ], + "category": [ "MIGO" ] + }, + { + "type": "mutation", + "id": "THRESH_YUGGOTH", + "name": "YUGGOTH", + "points": 1, + "description": "This death throes of this world are the birthing pangs of yours.", + "valid": false, + "purifiable": false, + "threshold": true + }, + { + "type": "mutation", + "id": "MIGO_SCENT", + "name": "Fetid scent", + "points": 6, + "description": "Your sweat now smells otherworldly, and not in a good way. The mi-go still hate you but at least they aren't offended by your smell. ", + "valid": false, + "purifiable": false, + "types": [ "LEGS" ], + "prereqs": [ "SMELLY", "SMELLY2" ], + "threshreq": [ "THRESH_YUGGOTH" ], + "category": [ "MIGO" ], + "scent_type": "sc_fetid" + }, + { + "type": "mutation", + "id": "EERIE", + "name": "Eerie", + "points": 1, + "description": "You are offputting to others. You're mannerisms have changed as if human interaction is becoming foreign.", + "category": [ "MIGO" ], + "social_modifiers": { "intimidate": 15 } + }, + { + "type": "mutation", + "id": "WINGS_migo", + "name": "Mi-go Wings", + "points": 1, + "visibility": 4, + "ugliness": 8, + "description": "You have a pair of large, veiny wings. They don't appear to be made for this atmosphere but they grant a powerful buffeting attack.", + "types": [ "WINGS" ], + "prereqs": [ "WINGS_STUB" ], + "category": [ "MIGO" ], + "attacks": { + "attack_text_u": "You buffet %s with your wings", + "attack_text_npc": "%1$s buffets %2$s with their wings", + "chance": 20, + "base_damage": { "damage_type": "bash", "amount": 26 } + } + }, + { + "type": "mutation", + "id": "MIGO_BREATHE", + "name": "Mi-go breathe", + "points": 4, + "description": "You can now breathe the gasses the mi-go thrive in.", + "starting_trait": false, + "category": [ "MIGO" ] } ] diff --git a/data/mods/Aftershock/npcs/classes.json b/data/mods/Aftershock/npcs/classes.json index b1c8d915a4610..53ea486f9e5a5 100644 --- a/data/mods/Aftershock/npcs/classes.json +++ b/data/mods/Aftershock/npcs/classes.json @@ -41,5 +41,42 @@ { "id": "bio_tools", "chance": 100 }, { "id": "bio_torsionratchet", "chance": 100 } ] + }, + { + "type": "npc", + "id": "millyficent_whately", + "name_unique": "Millyficen Whately", + "name_suffix": "Xenobiologist, madwoman", + "class": "afs_xenobiologist_madwoman", + "attitude": 0, + "mission": 7, + "chat": "TALK_Millyficent_1", + "mission_offered": "MISSION_migo_biology_1", + "faction": "whately_family" + }, + { + "type": "npc_class", + "id": "afs_xenobiologist_madwoman", + "name": "mi-go enthusiast", + "job_description": "I've been studying the mi-go for years…", + "common": false, + "traits": [ + [ "hair_red_long", 100 ], + [ "SKIN_LIGHT", 100 ], + [ "WARM_NATURED", 100 ], + [ "INT_UP_3", 100 ], + [ "DEX_UP_2", 100 ], + [ "STR_UP", 100 ], + { "group": "Appearance_demographics", "prob": 100 } + ], + "bonus_dex": { "rng": [ -1, 0 ] }, + "bonus_int": { "rng": [ 2, 5 ] }, + "skills": [ + { "skill": "ALL", "level": { "mul": [ { "one_in": 3 }, { "sum": [ { "dice": [ 2, 2 ] }, { "constant": -4 } ] } ] } }, + { "skill": "computer", "bonus": { "rng": [ 1, 5 ] } }, + { "skill": "electronics", "bonus": { "rng": [ 1, 5 ] } }, + { "skill": "firstaid", "bonus": { "rng": [ 1, 4 ] } }, + { "skill": "cooking", "bonus": { "rng": [ 6, 8 ] } } + ] } ] diff --git a/data/mods/Aftershock/npcs/factions.json b/data/mods/Aftershock/npcs/factions.json index 4df287e763e82..82862cff9bdda 100644 --- a/data/mods/Aftershock/npcs/factions.json +++ b/data/mods/Aftershock/npcs/factions.json @@ -69,5 +69,75 @@ "marloss": { "kill on sight": true } }, "description": "A group of bionic preppers who had expected the collapse of the economy and global chaos, instead they were slightly more ready than others for the Cataclysm." + }, + { + "type": "faction", + "id": "whately_family", + "name": "Whately Family", + "mon_faction": "whately", + "likes_u": 0, + "respects_u": 0, + "known_by_u": false, + "size": 15, + "power": 20, + "food_supply": 1200, + "wealth": 7500, + "relations": { + "free_merchants": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": true, + "defends your space": false, + "knows your voice": true + }, + "old_guard": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": false, + "defends your space": false, + "knows your voice": false + }, + "tacoma_commune": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": true, + "defends your space": false + }, + "lobby_beggars": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": true, + "lets you in": false, + "defends your space": false + }, + "no_faction": { + "kill on sight": false, + "watch your back": false, + "share my stuff": false, + "guard your stuff": false, + "lets you in": false, + "defends your space": false, + "knows your voice": true + }, + "wasteland_scavengers": { + "kill on sight": false, + "watch your back": true, + "share my stuff": false, + "guard your stuff": true, + "lets you in": false, + "defends your space": false, + "knows your voice": true + }, + "hells_raiders": { "kill on sight": true }, + "marloss": { "kill on sight": true } + }, + "description": "The Whately's are an old New England family of eccentrics. Eccentrics being the kind words used about them." } ] diff --git a/data/mods/Aftershock/npcs/whately_dialogue.json b/data/mods/Aftershock/npcs/whately_dialogue.json new file mode 100644 index 0000000000000..cb9a3470e2877 --- /dev/null +++ b/data/mods/Aftershock/npcs/whately_dialogue.json @@ -0,0 +1,193 @@ +[ + { + "type": "effect_type", + "id": "u_met_millyficent" + }, + { + "type": "talk_topic", + "id": "TALK_Millyficent_1", + "dynamic_line": { + "u_has_var": "u_met_millyficent", + "type": "general", + "context": "meeting", + "value": "yes", + "yes": [ "What did you bring me?", "Hello.", "How are you?", "Welcome!", "Do you smell something?" ], + "no": "New test subjects! I'm so glad you showed up!" + }, + "responses": [ + { + "text": "Who are you?", + "effect": { "u_add_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "condition": { "not": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" } }, + "topic": "TALK_millyficent_firstmeet" + }, + { + "text": "What is this place?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_millyficent_place" + }, + { + "text": "How did you get here?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_millyficent_ask_past" + }, + { + "text": "How are things here?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_millyficent_ask_mood" + }, + { + "text": "Can I do anything for you? Do I want to?", + "condition": { "u_has_var": "u_met_millyficent", "type": "general", "context": "meeting", "value": "yes" }, + "topic": "TALK_MISSION_LIST" + }, + { "text": "I'm going on my way now.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_firstmeet", + "dynamic_line": "Millyficent Whately. I'm so glad you finally arrived. It's been a while since I last received new lab partners.", + "responses": [ + { "text": "I'm so hungry, can you help me?", "topic": "TALK_millyficent_food" }, + { "text": "You are aware of the Cataclysm?", "topic": "TALK_millyficent_cataclysm" }, + { "text": "I am your new lab partner.", "topic": "TALK_Millyficent_1" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_place", + "dynamic_line": "Welcome to my lab! Here we explore the boundaries of the possible beyond the reach of small minds.", + "responses": [ + { "text": "Can you give me something to eat then?", "topic": "TALK_millyficent_food" }, + { "text": "Oh, okay.", "topic": "TALK_Millyficent_1" }, + { "text": "I think there's been a mistake.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_food", + "dynamic_line": "No, no, no! No food without succesfully completed experiments. We mustn't break the contract!", + "responses": [ + { "text": "What do I have to do?", "topic": "TALK_MISSION_LIST" }, + { "text": "I don't think you are well.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_ask_past", + "dynamic_line": "Well after I did my graduate thesis on theoretical xenobiology the government hired me to join the most interesting program. Yes there were deaths but we learned so much.", + "responses": [ { "text": "Let's talk about something else.", "topic": "TALK_Millyficent_1" } ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_cataclysm", + "dynamic_line": "What I know is that I pay well for test subjects and I deliver results and at this rate we will not be releasing on time!", + "responses": [ { "text": "Let's talk about something else.", "topic": "TALK_Millyficent_1" } ] + }, + { + "type": "talk_topic", + "id": "TALK_millyficent_ask_mood", + "dynamic_line": "Ever since they moved me to my own lab my research has progressed so much faster.", + "responses": [ { "text": "This is not reassuring.", "topic": "TALK_Millyficent_1" } ] + }, + { + "id": "MISSION_migo_biology_1", + "type": "mission_definition", + "name": "Migo biology", + "description": "Find fetid goop.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 5, + "value": 0, + "item": "fetid_goop", + "count": 14, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_migo_biology_2", + "dialogue": { + "describe": "I need 14 fetid goops from mi-go locations.", + "offer": "My experiments are at a critical point. Could you find about… 14 fetid goops for me?", + "accepted": "Don't forget to tell me when you have them.", + "rejected": "Then why are you even here? Just let me know if you reconsider.", + "advice": "Find a mi-go base, find a way inside, smash things until you find what I need.", + "inquire": "Why aren't you done yet?", + "success": "Taste this.", + "success_lie": "Thanks for trying… I guess.", + "failure": "You are holding back the evolution of the human race." + }, + "end": { "effect": [ { "u_buy_item": "mutagen_migo", "container": "flask_glass", "count": 1 } ] } + }, + { + "id": "MISSION_migo_biology_2", + "type": "mission_definition", + "name": "Migo Resin", + "description": "Find 56 chunks of mi-go resin.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 6, + "value": 0, + "item": "resin_chunk", + "count": 50, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_migo_biology_3", + "dialogue": { + "describe": "I need 56 chunks of mi-go resin.", + "offer": "I need to understand more about their environment and how they create it. This research wasn't even possible previously. Bring me fifty six chunks of mi-go resin.", + "accepted": "My notes suggest that their building materials are alive. I need you to help me confirm that.", + "rejected": "You can't just walk away from this. We're changing the world!", + "advice": "Find their buildings, jackhammer them. What did you do before the world changed for the better, cold call salesman?", + "inquire": "Have you found my resin?", + "success": "Drink this.", + "success_lie": "Did you act on Broadway? Because I bet that skill isn't useful anymore.", + "failure": "I wonder if I could trade you to them for what I need?" + }, + "end": { "effect": [ { "u_buy_item": "mutagen_migo", "container": "flask_glass", "count": 1 } ] } + }, + { + "id": "MISSION_migo_biology_3", + "type": "mission_definition", + "name": "Mutagen", + "description": "Bring me 3 mutagen.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 3, + "value": 0, + "item": "mutagen", + "count": 3, + "origins": [ "ORIGIN_SECONDARY" ], + "followup": "MISSION_migo_biology_4", + "dialogue": { + "describe": "I need three mutagen.", + "offer": "I need some mutagen and I don't want to spend the time making it myself. Bring me three doses, if you would be so kind.", + "accepted": "Mutagen makes the world go round, it's definitely more valuable than love.", + "rejected": "Are you scared of where I'm taking you?", + "advice": "If you can't make it yourself go hit up a government lab. Be prepared for anything in there.", + "inquire": "Mutagen? Why are you in front of me if not?", + "success": "I've got something more potent for you this time.", + "success_lie": "Lies and the lying liars who tell them.", + "failure": "You are keeping me from my experiments. Would you like to become one?" + }, + "end": { "effect": [ { "u_buy_item": "iv_mutagen_migo", "container": "flask_glass", "count": 1 } ] } + }, + { + "id": "MISSION_migo_biology_4", + "type": "mission_definition", + "name": "Humming Hearts", + "description": "Find 2 humming hearts.", + "goal": "MGOAL_FIND_ITEM", + "difficulty": 8, + "value": 0, + "item": "humming_heart", + "count": 2, + "origins": [ "ORIGIN_SECONDARY" ], + "dialogue": { + "describe": "Parts, parts, parts. Bring me some hearts. ", + "offer": "The Whately's are known in these parts for gathering body parts. Ha! That's just rumors and hearsay. But I do need two humming hearts.", + "accepted": "I have some relatives you should meet, if you don't mind hard work for the advancement of science.", + "rejected": "Even I understand this is dangerous.", + "advice": "Brain blasters, that's what I call them. Some kind of automated weapon system the mi-go use.", + "inquire": "They speak sometimes. I wonder if they still think.", + "success": "Let's see what improvements we can divine from these beauties.", + "success_lie": "Thanks for trying… I guess.", + "failure": "I can't be Dr Frankenstein unless you get me these." + }, + "end": { "effect": [ { "u_buy_item": "mutagen_migo", "container": "flask_glass", "count": 2 } ] } + } +] From 5723abaa9d1c13bd0c86d3a65a6ff87baec4c4a9 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 6 Mar 2020 05:29:40 -0500 Subject: [PATCH 120/219] [Aftershock] Mutant npcs to aftershock (#37530) --- .../npcs/mutant_npcs/npc_classes_mutant.json | 385 ++++++++ .../npcs/mutant_npcs/trait_groups.json | 924 ++++++++++++++++++ 2 files changed, 1309 insertions(+) create mode 100644 data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json create mode 100644 data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json diff --git a/data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json b/data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json new file mode 100644 index 0000000000000..ab0677b3ac616 --- /dev/null +++ b/data/mods/Aftershock/npcs/mutant_npcs/npc_classes_mutant.json @@ -0,0 +1,385 @@ +[ + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_LIZARD", + "name": "Lizard Mutant", + "job_description": "I'm looking for lizard mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 4, + "bonus_dex": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_lizard" }, + { "distribution": [ { "group": "trait_group_lizard_nonthres" }, { "group": "trait_group_lizard_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_MEDICAL", + "name": "Medical Mutant", + "job_description": "I'm looking for medical mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_medical" }, + { + "distribution": [ { "group": "trait_group_medical_nonthres" }, { "group": "trait_group_medical_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_BIRD", + "name": "Bird Mutant", + "job_description": "I'm looking for bird mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 4, + "bonus_per": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_bird" }, + { "distribution": [ { "group": "trait_group_bird_nonthres" }, { "group": "trait_group_bird_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_FISH", + "name": "Fish Mutant", + "job_description": "I'm looking for fish mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "swimming", "bonus": { "rng": [ 5, 15 ] } } + ], + "bonus_dex": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_fish" }, + { "distribution": [ { "group": "trait_group_fish_nonthres" }, { "group": "trait_group_fish_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_BEAST", + "name": "Beast Mutant", + "job_description": "I'm looking for beast mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 4, 8 ] } } + ], + "bonus_str": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_beast" }, + { "distribution": [ { "group": "trait_group_beast_nonthres" }, { "group": "trait_group_beast_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_URSINE", + "name": "Ursine Mutant", + "job_description": "I'm looking for ursine mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 11, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_ursine" }, + { "distribution": [ { "group": "trait_group_ursine_nonthres" }, { "group": "trait_group_ursine_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_FELINE", + "name": "Feline Mutant", + "job_description": "I'm looking for feline mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_feline" }, + { "distribution": [ { "group": "trait_group_feline_nonthres" }, { "group": "trait_group_feline_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_LUPINE", + "name": "Lupine Mutant", + "job_description": "I'm looking for lupine mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_lupine" }, + { "distribution": [ { "group": "trait_group_lupine_nonthres" }, { "group": "trait_group_lupine_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_CATTLE", + "name": "Cattle Mutant", + "job_description": "I'm looking for cattle mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 6, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_cattle" }, + { "distribution": [ { "group": "trait_group_cattle_nonthres" }, { "group": "trait_group_cattle_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_INSECT", + "name": "Insect Mutant", + "job_description": "I'm looking for insect mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 1, + "bonus_dex": 1, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_insect" }, + { "distribution": [ { "group": "trait_group_insect_nonthres" }, { "group": "trait_group_insect_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_PLANT", + "name": "Plant Mutant", + "job_description": "I'm looking for plant mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_plant" }, + { "distribution": [ { "group": "trait_group_plant_nonthres" }, { "group": "trait_group_plant_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_SLIME", + "name": "Slime Mutant", + "job_description": "I'm looking for slime mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 4 ] } } + ], + "bonus_str": -4, + "bonus_dex": 5, + "bonus_int": 10, + "bonus_per": 5, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_slime" }, + { "distribution": [ { "group": "trait_group_slime_nonthres" }, { "group": "trait_group_slime_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_TROGLOBITE", + "name": "Troglobite Mutant", + "job_description": "I'm looking for troglobite mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "melee", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 4, 8 ] } } + ], + "bonus_str": 6, + "bonus_dex": -2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_troglobite" }, + { + "distribution": [ { "group": "trait_group_troglobite_nonthres" }, { "group": "trait_group_troglobite_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_CEPHALOPOD", + "name": "Cephalopod Mutant", + "job_description": "I'm looking for cephalopod mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "swimming", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 7, + "bonus_int": 7, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_cephalopod" }, + { + "distribution": [ { "group": "trait_group_cephalopod_nonthres" }, { "group": "trait_group_cephalopod_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_SPIDER", + "name": "Spider Mutant", + "job_description": "I'm looking for spider mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_dex": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_spider" }, + { "distribution": [ { "group": "trait_group_spider_nonthres" }, { "group": "trait_group_spider_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_RAT", + "name": "Rat Mutant", + "job_description": "I'm looking for rat mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_rat" }, + { "distribution": [ { "group": "trait_group_rat_nonthres" }, { "group": "trait_group_rat_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_MOUSE", + "name": "Mouse Mutant", + "job_description": "I'm looking for mouse mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 7 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 5 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 5 ] } } + ], + "bonus_dex": 6, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_mouse" }, + { "distribution": [ { "group": "trait_group_mouse_nonthres" }, { "group": "trait_group_mouse_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_ALPHA", + "name": "Alpha Mutant", + "job_description": "I'm looking for alpha mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "melee", "bonus": { "rng": [ 3, 6 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 3, 6 ] } } + ], + "bonus_str": 5, + "bonus_dex": 5, + "bonus_int": 5, + "bonus_per": 5, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_alpha" }, + { "distribution": [ { "group": "trait_group_alpha_nonthres" }, { "group": "trait_group_alpha_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_ELFA", + "name": "Elfa Mutant", + "job_description": "I'm looking for elfa mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 2, 4 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 2, 4 ] } } + ], + "bonus_str": 1, + "bonus_dex": 5, + "bonus_int": 4, + "bonus_per": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_elfa" }, + { "distribution": [ { "group": "trait_group_elfa_nonthres" }, { "group": "trait_group_elfa_postthres" } ] } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_CHIMERA", + "name": "Chimera Mutant", + "job_description": "I'm looking for chimera mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "melee", "bonus": { "rng": [ 4, 8 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 4, 8 ] } } + ], + "bonus_str": 4, + "bonus_dex": 2, + "bonus_per": 2, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_chimera" }, + { + "distribution": [ { "group": "trait_group_chimera_nonthres" }, { "group": "trait_group_chimera_postthres" } ] + } + ] + }, + { + "type": "npc_class", + "id": "NC_NPC_MUTANT_RAPTOR", + "name": "Raptor Mutant", + "job_description": "I'm looking for raptor mutagen… this world is no place for humans anymore, and I don't plan to keep being one.", + "skills": [ + { "skill": "dodge", "bonus": { "rng": [ 6, 10 ] } }, + { "skill": "melee", "bonus": { "rng": [ 6, 10 ] } }, + { "skill": "unarmed", "bonus": { "rng": [ 6, 10 ] } } + ], + "bonus_str": 1, + "bonus_dex": 2, + "bonus_per": 4, + "traits": [ + { "group": "trait_mutant_npc_common" }, + { "group": "trait_group_raptor" }, + { "distribution": [ { "group": "trait_group_raptor_nonthres" }, { "group": "trait_group_raptor_postthres" } ] } + ] + } +] diff --git a/data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json b/data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json new file mode 100644 index 0000000000000..c8b08a0792f54 --- /dev/null +++ b/data/mods/Aftershock/npcs/mutant_npcs/trait_groups.json @@ -0,0 +1,924 @@ +[ + { + "type": "trait_group", + "id": "trait_group_spider", + "subtype": "collection", + "traits": [ + { "trait": "FLEET", "prob": 50 }, + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "NIGHTVISION3", "prob": 50 }, + { "trait": "INFRARED", "prob": 50 }, + { "trait": "WEB_WALKER", "prob": 50 }, + { "trait": "DEX_UP_2" }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "COLDBLOOD", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_spider_nonthres", + "subtype": "collection", + "traits": [ + { "trait": "POISONOUS", "prob": 50 }, + { "trait": "MANDIBLES", "prob": 50 }, + { "distribution": [ { "trait": "CHITIN3" }, { "trait": "CHITIN_FUR2" } ] } + ] + }, + { + "type": "trait_group", + "id": "trait_group_spider_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_SPIDER" }, + { "distribution": [ { "trait": "ARACHNID_ARMS" }, { "trait": "ARACHNID_ARMS_OK" } ] }, + { "trait": "CHITIN_FUR3" }, + { "trait": "CF_HAIR", "prob": 50 }, + { "trait": "POISONOUS2", "prob": 50 }, + { "trait": "PRED3", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "FANGS_SPIDER", "prob": 50 }, + { + "distribution": [ + { "trait": "WEB_SPINNER" }, + { "collection": [ { "trait": "WEB_WEAVER" }, { "trait": "WEB_RAPPEL" }, { "trait": "WEB_ROPE" } ] } + ] + } + ] + }, + { + "type": "trait_group", + "id": "trait_group_alpha", + "subtype": "collection", + "traits": [ + { "trait": "GOODHEARING", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "PRETTY", "prob": 50 }, + { "trait": "ANTIJUNK", "prob": 50 }, + { "trait": "NAUSEA", "prob": 50 }, + { "trait": "HUNGER", "prob": 50 }, + { "trait": "ROT3", "prob": 50 }, + { "trait": "STR_ALPHA" }, + { "trait": "DEX_ALPHA" }, + { "trait": "INT_ALPHA" }, + { "trait": "PER_ALPHA" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_alpha_nonthres", + "subtype": "collection", + "traits": [ { "trait": "WAKEFUL", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_alpha_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_ALPHA" }, { "trait": "WAKEFUL2", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_fish", + "subtype": "collection", + "traits": [ + { "trait": "GOODCARDIO", "prob": 50 }, + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "NIGHTVISION3", "prob": 50 }, + { "trait": "FANGS", "prob": 50 }, + { "trait": "MEMBRANE", "prob": 50 }, + { "trait": "GILLS", "prob": 50 }, + { "trait": "SLEEK_SCALES", "prob": 50 }, + { "trait": "TAIL_FIN", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "THIRST2", "prob": 50 }, + { "trait": "WEBBED", "prob": 50 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "COLDBLOOD", "prob": 50 }, + { "trait": "DEX_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_fish_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_fish_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_FISH" } ] + }, + { + "type": "trait_group", + "id": "trait_group_lupine", + "subtype": "collection", + "traits": [ + { "trait": "GOODCARDIO", "prob": 50 }, + { "trait": "SMELLY", "prob": 50 }, + { "distribution": [ { "trait": "UGLY" }, { "trait": "DEFORMED" }, { "trait": "PRETTY" } ] }, + { "trait": "ANIMALDISCORD", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "FANGS", "prob": 50 }, + { "trait": "LUPINE_FUR", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "TAIL_FLUFFY", "prob": 50 }, + { "trait": "LUPINE_EARS", "prob": 50 }, + { "trait": "STR_UP_3" }, + { "trait": "MUZZLE", "prob": 50 }, + { "trait": "HEAVYSLEEPER2", "prob": 50 }, + { "trait": "PAWS", "prob": 50 }, + { "trait": "GROWL", "prob": 50 }, + { "trait": "SHOUT3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lupine_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_lupine_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_LUPINE" }, { "trait": "PRED3", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_bird", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "NIGHTVISION", "prob": 50 }, + { "trait": "DEFT", "prob": 50 }, + { "trait": "LIGHTSTEP", "prob": 50 }, + { "trait": "BADBACK", "prob": 50 }, + { "trait": "GLASSJAW", "prob": 50 }, + { "trait": "BIRD_EYE", "prob": 50 }, + { "trait": "FEATHERS", "prob": 50 }, + { "trait": "WINGS_BIRD", "prob": 50 }, + { "trait": "DEX_UP_3" }, + { "trait": "HOLLOW_BONES", "prob": 50 }, + { "trait": "PER_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_bird_nonthres", + "subtype": "collection", + "traits": [ { "trait": "BEAK", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_bird_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_BIRD" }, + { "trait": "DOWN", "prob": 50 }, + { "trait": "TALONS", "prob": 50 }, + { "trait": "GIZZARD", "prob": 50 }, + { "trait": "FLEET2", "prob": 50 }, + { "distribution": [ { "trait": "BEAK_PECK", "prob": 50 }, { "trait": "BEAK_HUM", "prob": 50 } ] } + ] + }, + { + "type": "trait_group", + "id": "trait_group_insect", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "NIGHTVISION", "prob": 50 }, + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "TERRIFYING", "prob": 50 }, + { "trait": "HEAVYSLEEPER", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "INFRARED", "prob": 50 }, + { "trait": "CHITIN2", "prob": 50 }, + { "trait": "PHEROMONE_INSECT", "prob": 50 }, + { "trait": "COMPOUND_EYES", "prob": 50 }, + { "trait": "ANTENNAE", "prob": 50 }, + { "trait": "TAIL_STING", "prob": 50 }, + { "trait": "MANDIBLES", "prob": 50 }, + { "trait": "STR_UP", "prob": 50 }, + { "trait": "DEX_UP" }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "COLDBLOOD3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_insect_nonthres", + "subtype": "collection", + "traits": [ { "trait": "WINGS_INSECT", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_insect_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_INSECT" }, + { "distribution": [ { "trait": "WINGS_BUTTERFLY", "prob": 50 }, { "trait": "WINGS_INSECT", "prob": 50 } ] }, + { "trait": "PROBOSCIS", "prob": 50 }, + { "distribution": [ { "trait": "INSECT_ARMS", "prob": 50 }, { "trait": "INSECT_ARMS_OK", "prob": 50 } ] } + ] + }, + { + "type": "trait_group", + "id": "trait_group_troglobite", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "LIGHTEATER", "prob": 50 }, + { "trait": "MYOPIC", "prob": 50 }, + { "trait": "NIGHTVISION3", "prob": 50 }, + { "trait": "INFRARED", "prob": 50 }, + { "trait": "REGEN", "prob": 50 }, + { "trait": "DISIMMUNE", "prob": 50 }, + { "trait": "INFRESIST", "prob": 50 }, + { "trait": "POISONOUS", "prob": 50 }, + { "trait": "ALCMET", "prob": 50 }, + { "trait": "SAPROVORE", "prob": 50 }, + { "trait": "STR_UP_3" }, + { "trait": "SUNBURN", "prob": 50 }, + { "trait": "TROGLO3", "prob": 50 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "STOCKY_TROGLO" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_troglobite_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_troglobite_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_TROGLOBITE" }, { "trait": "PAINRESIST_TROGLO", "prob": 50 }, { "trait": "EATPOISON", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_chimera", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "TERRIFYING", "prob": 50 }, + { "trait": "ADRENALINE", "prob": 50 }, + { "trait": "SLEEPY", "prob": 50 }, + { "trait": "BADTEMPER", "prob": 50 }, + { "trait": "FORGETFUL", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "SCALES", "prob": 50 }, + { "trait": "LIGHTFUR", "prob": 50 }, + { "trait": "TALONS", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "HOOVES", "prob": 50 }, + { "trait": "SAPROVORE", "prob": 50 }, + { "trait": "HORNS_CURLED", "prob": 50 }, + { "trait": "TAIL_CLUB", "prob": 50 }, + { "trait": "CANINE_EARS", "prob": 50 }, + { "trait": "STR_UP_3" }, + { "trait": "DEX_UP_2" }, + { "trait": "PER_UP_2" }, + { "trait": "MOUTH_FLAPS", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED3", "prob": 50 }, + { "trait": "HUNGER3", "prob": 50 }, + { "trait": "THIRST", "prob": 50 }, + { "trait": "ROT2", "prob": 50 }, + { "distribution": [ { "trait": "UNSTABLE", "prob": 10 }, { "trait": "CHAOTIC", "prob": 10 } ] }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "SNARL", "prob": 50 }, + { "trait": "SHOUT3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_chimera_nonthres", + "subtype": "collection", + "traits": [ { "trait": "FANGS", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_chimera_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_CHIMERA" }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "MUT_JUNKIE", "prob": 50 }, + { "trait": "MUT_TOUGH2", "prob": 50 }, + { "trait": "EATPOISON", "prob": 50 }, + { "trait": "EATDEAD", "prob": 50 }, + { "trait": "SABER_TEETH", "prob": 50 }, + { "trait": "EATHEALTH", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_raptor", + "subtype": "collection", + "traits": [ + { "trait": "QUICK", "prob": 50 }, + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "DEFT", "prob": 50 }, + { "trait": "ANTIJUNK", "prob": 50 }, + { "trait": "GLASSJAW", "prob": 50 }, + { "trait": "ANIMALDISCORD", "prob": 50 }, + { "trait": "UGLY", "prob": 50 }, + { "trait": "LIZ_EYE", "prob": 50 }, + { "trait": "SCALES", "prob": 50 }, + { "trait": "NAILS", "prob": 50 }, + { "trait": "RAP_TALONS", "prob": 50 }, + { "trait": "TAIL_RAPTOR", "prob": 50 }, + { "trait": "STR_UP" }, + { "trait": "DEX_UP_2" }, + { "trait": "PER_UP_3" }, + { "trait": "SLIT_NOSTRILS", "prob": 50 }, + { "trait": "FORKED_TONGUE", "prob": 50 }, + { "trait": "HUNGER2", "prob": 50 }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "COLDBLOOD2", "prob": 50 }, + { "trait": "HISS", "prob": 50 }, + { "trait": "SHOUT1", "prob": 50 }, + { "trait": "ARM_FEATHERS", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_raptor_nonthres", + "subtype": "collection", + "traits": [ { "trait": "FANGS", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_raptor_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_RAPTOR" }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "EATPOISON", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_medical", + "subtype": "collection", + "traits": [ + { "trait": "FASTHEALER", "prob": 50 }, + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "SELFAWARE", "prob": 50 }, + { "trait": "MASOCHIST", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "HEAVYSLEEPER", "prob": 50 }, + { "trait": "INSOMNIA", "prob": 50 }, + { "trait": "FORGETFUL", "prob": 50 }, + { "trait": "LIGHTWEIGHT", "prob": 50 }, + { "trait": "ADDICTIVE", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "SCHIZOPHRENIC", "prob": 50 }, + { "trait": "JITTERY", "prob": 50 }, + { "trait": "MOODSWINGS", "prob": 50 }, + { "trait": "RADIOGENIC", "prob": 50 }, + { "trait": "INFIMMUNE", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "PAINREC3", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "HUNGER", "prob": 50 }, + { "trait": "UNSTABLE", "prob": 10 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_medical_nonthres", + "subtype": "collection", + "traits": [ { "trait": "PAINRESIST", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_medical_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_MEDICAL", "prob": 50 }, + { "trait": "MUT_TOUGH2", "prob": 50 }, + { "trait": "CENOBITE", "prob": 50 }, + { "trait": "NOPAIN", "prob": 50 }, + { "trait": "MUT_JUNKIE", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cattle", + "subtype": "collection", + "traits": [ + { "trait": "NIGHTVISION", "prob": 50 }, + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "FUR", "prob": 50 }, + { "trait": "HOOVES", "prob": 50 }, + { "trait": "HORNS", "prob": 50 }, + { "trait": "TAIL_CATTLE", "prob": 50 }, + { "trait": "CANINE_EARS", "prob": 50 }, + { "trait": "STR_UP_2" }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "MINOTAUR", "prob": 50 }, + { "trait": "PONDEROUS2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cattle_nonthres", + "subtype": "collection", + "traits": [ { "trait": "RUMINANT", "prob": 50 }, { "trait": "HUGE" } ] + }, + { + "type": "trait_group", + "id": "trait_group_cattle_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_CATTLE" }, + { "trait": "GRAZER", "prob": 50 }, + { "trait": "HUGE_OK" }, + { "trait": "MUT_TOUGH3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_slime", + "subtype": "collection", + "traits": [ + { "trait": "POISRESIST", "prob": 50 }, + { "trait": "ROBUST", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "REGEN", "prob": 50 }, + { "trait": "RADIOGENIC", "prob": 50 }, + { "trait": "DISIMMUNE", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "POISONOUS", "prob": 50 }, + { "trait": "SLIME_HANDS", "prob": 50 }, + { "trait": "DEX_UP" }, + { "trait": "DEFORMED3", "prob": 50 }, + { "trait": "HOLLOW_BONES", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "HUNGER2", "prob": 50 }, + { "trait": "THIRST2", "prob": 50 }, + { "trait": "SORES", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "WEBBED", "prob": 50 }, + { "trait": "UNSTABLE", "prob": 10 }, + { "trait": "RADIOACTIVE1", "prob": 0 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "INT_SLIME" }, + { "trait": "BENDY3" }, + { "trait": "PER_SLIME_OK" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_slime_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_slime_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_SLIME" }, + { "trait": "VISCOUS", "prob": 50 }, + { "trait": "AMORPHOUS", "prob": 50 }, + { "trait": "SLIMESPAWNER", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lizard", + "subtype": "collection", + "traits": [ + { "trait": "THICKSKIN", "prob": 50 }, + { "trait": "BADTEMPER", "prob": 50 }, + { "trait": "LIZ_EYE", "prob": 50 }, + { "trait": "REGEN_LIZ", "prob": 50 }, + { "trait": "FANGS", "prob": 50 }, + { "trait": "MEMBRANE", "prob": 50 }, + { "trait": "TAIL_THICK", "prob": 50 }, + { "trait": "STR_UP_2" }, + { "trait": "DEX_UP_2" }, + { "trait": "SLIT_NOSTRILS", "prob": 50 }, + { "trait": "FORKED_TONGUE", "prob": 50 }, + { "trait": "MUZZLE_LONG", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "WEBBED", "prob": 50 }, + { "trait": "HISS", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lizard_nonthres", + "subtype": "collection", + "traits": [ + { "trait": "SCALES", "prob": 50 }, + { "trait": "LARGE" }, + { "trait": "CARNIVORE", "prob": 50 }, + { "trait": "COLDBLOOD3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_lizard_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_LIZARD" }, + { "trait": "THICK_SCALES", "prob": 50 }, + { "trait": "TALONS", "prob": 50 }, + { "trait": "MUT_TOUGH", "prob": 50 }, + { "trait": "PRED3", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "LARGE_OK" }, + { "trait": "COLDBLOOD4", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_beast", + "subtype": "collection", + "traits": [ + { "trait": "DEFT", "prob": 50 }, + { "trait": "ANIMALEMPATH", "prob": 50 }, + { "trait": "TERRIFYING", "prob": 50 }, + { "trait": "ADRENALINE", "prob": 50 }, + { "trait": "MYOPIC", "prob": 50 }, + { "trait": "SLEEPY", "prob": 50 }, + { "trait": "ANTIJUNK", "prob": 50 }, + { "trait": "FORGETFUL", "prob": 50 }, + { "trait": "ANIMALDISCORD", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "FUR", "prob": 50 }, + { "trait": "CLAWS", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "TAIL_FLUFFY", "prob": 50 }, + { "trait": "CANINE_EARS", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED2", "prob": 50 }, + { "trait": "MUZZLE", "prob": 50 }, + { "trait": "HUNGER2", "prob": 50 }, + { "trait": "HEAVYSLEEPER2", "prob": 50 }, + { "trait": "TROGLO", "prob": 50 }, + { "trait": "PAWS_LARGE", "prob": 50 }, + { "trait": "SNARL", "prob": 50 }, + { "trait": "SHOUT2", "prob": 50 }, + { "trait": "STR_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_beast_nonthres", + "subtype": "collection", + "traits": [ { "trait": "CARNIVORE", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_beast_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_BEAST" }, + { "trait": "MUT_TOUGH", "prob": 50 }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_rat", + "subtype": "collection", + "traits": [ + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "INCISORS", "prob": 50 }, + { "trait": "FUR", "prob": 50 }, + { "trait": "TAIL_RAT", "prob": 50 }, + { "trait": "WHISKERS_RAT", "prob": 50 }, + { "trait": "DEFORMED3", "prob": 50 }, + { "trait": "MUZZLE_RAT", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "MET_RAT", "prob": 50 }, + { "trait": "PAWS", "prob": 50 }, + { "trait": "GROWL", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_rat_nonthres", + "subtype": "collection", + "traits": [ { "trait": "CLAWS_RAT", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_rat_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_RAT" }, + { "trait": "CLAWS_ST", "prob": 50 }, + { "trait": "BURROW", "prob": 50 }, + { "trait": "INFRESIST", "prob": 50 }, + { "trait": "EATDEAD", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_mouse", + "subtype": "collection", + "traits": [ + { "trait": "DISRESISTANT", "prob": 50 }, + { "trait": "NIGHTVISION2", "prob": 50 }, + { "trait": "FELINE_FUR", "prob": 50 }, + { "trait": "TAIL_RAT", "prob": 50 }, + { "trait": "MET_RAT", "prob": 50 }, + { "trait": "ANIMALDISCORD2", "prob": 50 }, + { "trait": "WHISKERS_RAT", "prob": 50 }, + { "trait": "PROJUNK", "prob": 50 }, + { "trait": "SMALL2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_mouse_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_mouse_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_MOUSE" }, + { "trait": "GOODCARDIO2", "prob": 50 }, + { "trait": "SMALL_OK", "prob": 50 }, + { "trait": "INFRESIST", "prob": 50 }, + { "trait": "PROJUNK2", "prob": 50 }, + { "trait": "EASYSLEEPER2", "prob": 50 }, + { "trait": "CRAFTY", "prob": 50 }, + { "trait": "EATDEAD", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_elfa", + "subtype": "collection", + "traits": [ + { "trait": "LIGHTSTEP", "prob": 50 }, + { "trait": "WEAKSCENT", "prob": 50 }, + { "trait": "BADBACK", "prob": 50 }, + { "trait": "CHEMIMBALANCE", "prob": 50 }, + { "trait": "ELFAEYES", "prob": 50 }, + { "trait": "ELFA_FNV", "prob": 50 }, + { "trait": "PLANTSKIN", "prob": 50 }, + { "trait": "LEAVES", "prob": 50 }, + { "trait": "PARAIMMUNE", "prob": 50 }, + { "trait": "ELFA_EARS", "prob": 50 }, + { "trait": "STR_UP" }, + { "trait": "DEX_UP_3" }, + { "trait": "INT_UP_3" }, + { "trait": "PER_UP_3" }, + { "trait": "BEAUTIFUL3", "prob": 50 }, + { "trait": "HOLLOW_BONES", "prob": 50 }, + { "trait": "VOMITOUS", "prob": 50 }, + { "trait": "HUNGER", "prob": 50 }, + { "trait": "THIRST", "prob": 50 }, + { "trait": "ROT1", "prob": 50 }, + { "trait": "RADIOACTIVE2", "prob": 0 }, + { "trait": "BENDY1" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_elfa_nonthres", + "subtype": "collection", + "traits": [ { "trait": "WAKEFUL", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_elfa_postthres", + "subtype": "collection", + "traits": [ { "trait": "THRESH_ELFA" }, { "trait": "WAKEFUL3", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_feline", + "subtype": "collection", + "traits": [ + { "trait": "LIGHTSTEP", "prob": 50 }, + { "trait": "SMELLY", "prob": 50 }, + { "distribution": [ { "trait": "PRETTY" }, { "trait": "DEFORMED" }, { "trait": "UGLY" } ] }, + { "trait": "FEL_EYE", "prob": 50 }, + { "trait": "FEL_NV", "prob": 50 }, + { "trait": "FELINE_FUR", "prob": 50 }, + { "trait": "LYNX_FUR", "prob": 50 }, + { "trait": "CLAWS_RETRACT", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "FELINE_EARS", "prob": 50 }, + { "trait": "WHISKERS", "prob": 50 }, + { "trait": "DEX_UP_3" }, + { "trait": "SNOUT", "prob": 50 }, + { "trait": "SLEEPY2", "prob": 50 }, + { "trait": "PAWS", "prob": 50 }, + { "trait": "SNARL", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_feline_nonthres", + "subtype": "collection", + "traits": [ { "trait": "FANGS", "prob": 50 }, { "trait": "CARNIVORE", "prob": 50 } ] + }, + { + "type": "trait_group", + "id": "trait_group_feline_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_FELINE" }, + { "trait": "PRED3", "prob": 50 }, + { "trait": "SABER_TEETH", "prob": 50 }, + { "trait": "TAIL_LONG", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_plant", + "subtype": "collection", + "traits": [ + { "trait": "HEAVYSLEEPER", "prob": 50 }, + { "trait": "BADHEARING", "prob": 50 }, + { "trait": "FASTHEALER2", "prob": 50 }, + { "trait": "BARK", "prob": 50 }, + { "trait": "THORNS", "prob": 50 }, + { "trait": "LEAVES", "prob": 50 }, + { "trait": "STR_UP_2" }, + { "trait": "DEFORMED2", "prob": 50 }, + { "trait": "PONDEROUS3", "prob": 50 }, + { "trait": "SUNLIGHT_DEPENDENT", "prob": 50 }, + { "trait": "VINES3", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_plant_nonthres", + "subtype": "collection", + "traits": [ ] + }, + { + "type": "trait_group", + "id": "trait_group_plant_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_PLANT" }, + { "trait": "FLOWERS", "prob": 50 }, + { "trait": "DISIMMUNE", "prob": 50 }, + { "trait": "SAPROPHAGE", "prob": 50 }, + { "trait": "ROOTS3", "prob": 50 }, + { "trait": "CHLOROMORPH", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_ursine", + "subtype": "collection", + "traits": [ + { "trait": "BADTEMPER", "prob": 50 }, + { "trait": "URSINE_EYE", "prob": 50 }, + { "trait": "URSINE_FUR", "prob": 50 }, + { "trait": "CLAWS", "prob": 50 }, + { "trait": "PADDED_FEET", "prob": 50 }, + { "trait": "TAIL_STUB", "prob": 50 }, + { "trait": "HIBERNATE", "prob": 50 }, + { "trait": "URSINE_EARS", "prob": 50 }, + { "trait": "FAT", "prob": 50 }, + { "trait": "SMELLY2", "prob": 50 }, + { "trait": "DEFORMED2", "prob": 50 }, + { "trait": "MUZZLE_BEAR", "prob": 50 }, + { "trait": "PAWS_LARGE", "prob": 50 }, + { "trait": "PONDEROUS1", "prob": 50 }, + { "trait": "GROWL", "prob": 50 }, + { "trait": "STR_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_ursine_nonthres", + "subtype": "collection", + "traits": [ { "trait": "HUGE" } ] + }, + { + "type": "trait_group", + "id": "trait_group_ursine_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_URSINE" }, + { "trait": "MUT_TOUGH3", "prob": 50 }, + { "trait": "PRED4", "prob": 50 }, + { "trait": "SAPIOVORE", "prob": 50 }, + { "trait": "HUGE_OK" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cephalopod", + "subtype": "collection", + "traits": [ + { "trait": "CEPH_EYES", "prob": 50 }, + { "trait": "CEPH_VISION", "prob": 50 }, + { "trait": "GILLS_CEPH", "prob": 50 }, + { "trait": "SLIT_NOSTRILS", "prob": 50 }, + { "trait": "DEFORMED", "prob": 50 }, + { "trait": "THIRST2", "prob": 50 }, + { "trait": "BEAK", "prob": 50 }, + { "trait": "SLIMY", "prob": 50 }, + { "trait": "COLDBLOOD", "prob": 50 }, + { "trait": "DEX_UP_4" }, + { "trait": "INT_UP_4" } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cephalopod_nonthres", + "subtype": "collection", + "traits": [ + { "trait": "LEG_TENTACLES", "prob": 50 }, + { "distribution": [ { "trait": "ARM_TENTACLES" }, { "trait": "ARM_TENTACLES_4" } ], "prob": 50 }, + { "trait": "SHELL", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_group_cephalopod_postthres", + "subtype": "collection", + "traits": [ + { "trait": "THRESH_CEPHALOPOD" }, + { "trait": "MOUTH_TENTACLES", "prob": 50 }, + { + "distribution": [ { "trait": "ARM_TENTACLES" }, { "trait": "ARM_TENTACLES_4" }, { "trait": "ARM_TENTACLES_8" } ] + }, + { "trait": "CLAWS_TENTACLE", "prob": 50 }, + { "trait": "LEG_TENTACLES" }, + { "trait": "LEG_TENT_BRACE", "prob": 50 }, + { "trait": "SHELL2", "prob": 50 } + ] + }, + { + "type": "trait_group", + "id": "trait_mutant_npc_common", + "subtype": "collection", + "traits": [ + { "distribution": [ { "trait": "FASTLEARNER" }, { "trait": "SLOWLEARNER" } ], "prob": 10 }, + { + "distribution": [ { "trait": "FASTREADER" }, { "trait": "SLOWREADER" }, { "trait": "ILLITERATE", "prob": 5 } ], + "prob": 10 + }, + { "distribution": [ { "trait": "PARKOUR" }, { "trait": "BADKNEES" } ], "prob": 10 }, + { "distribution": [ { "trait": "LIAR" }, { "trait": "TRUTHTELLER" } ], "prob": 10 }, + { + "distribution": [ + { "trait": "MARTIAL_ARTS" }, + { "trait": "MARTIAL_ARTS2" }, + { "trait": "MARTIAL_ARTS3" }, + { "trait": "MARTIAL_ARTS4" }, + { "trait": "MARTIAL_ARTS5" } + ], + "prob": 10 + }, + { "trait": "DEFT", "prob": 10 }, + { "trait": "ADRENALINE", "prob": 10 }, + { "trait": "OUTDOORSMAN", "prob": 10 }, + { "trait": "PAINRESIST", "prob": 10 }, + { "trait": "QUICK", "prob": 10 }, + { "trait": "ROBUST", "prob": 10 }, + { "trait": "SELFAWARE", "prob": 10 }, + { "trait": "SPIRITUAL", "prob": 10 }, + { "trait": "STYLISH", "prob": 10 }, + { "trait": "ALBINO", "prob": 5 }, + { "trait": "ASTHMA", "prob": 5 }, + { "trait": "CHEMIMBALANCE", "prob": 10 }, + { "trait": "HOARDER", "prob": 10 }, + { "trait": "JITTERY", "prob": 10 }, + { "trait": "MOODSWINGS", "prob": 10 }, + { "trait": "SAVANT", "prob": 10 }, + { "trait": "SCHIZOPHRENIC", "prob": 10 }, + { "trait": "SQUEAMISH", "prob": 10 }, + { "trait": "TRIGGERHAPPY", "prob": 10 }, + { "group": "Appearance_demographics", "prob": 100 } + ] + } +] From e104fce96994da30b04275fda26d659fdf4b3c3d Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 6 Mar 2020 04:29:57 -0600 Subject: [PATCH 121/219] Aftershock Crafting System (#37707) --- data/mods/Aftershock/crafting_system.md | 67 ++++++++++++++++ .../items/crafting_scrap/abstract_scrap.json | 49 ++++++++++++ .../items/crafting_scrap/circuity_scrap.json | 42 ++++++++++ .../crafting_scrap/energy_storage_scrap.json | 42 ++++++++++ .../items/crafting_scrap/magnet_scrap.json | 26 ++++++ .../items/crafting_scrap/material_scrap.json | 42 ++++++++++ .../items/crafting_scrap/neural_io_scrap.json | 42 ++++++++++ data/mods/Aftershock/items/grenades.json | 24 ++++++ data/mods/Aftershock/items/item_groups.json | 18 +++++ data/mods/Aftershock/items/items.json | 2 +- data/mods/Aftershock/items/tool_quality.json | 5 ++ data/mods/Aftershock/items/tools.json | 8 ++ .../Aftershock/recipes/bionic_recipes.json | 80 ++++++++++--------- .../deconstruction/bionic_deconstruction.json | 18 +++++ data/mods/Aftershock/recipes/grenades.json | 15 ++++ 15 files changed, 441 insertions(+), 39 deletions(-) create mode 100644 data/mods/Aftershock/crafting_system.md create mode 100644 data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/material_scrap.json create mode 100644 data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json create mode 100644 data/mods/Aftershock/items/grenades.json create mode 100644 data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json create mode 100644 data/mods/Aftershock/recipes/grenades.json diff --git a/data/mods/Aftershock/crafting_system.md b/data/mods/Aftershock/crafting_system.md new file mode 100644 index 0000000000000..84a2d111fb110 --- /dev/null +++ b/data/mods/Aftershock/crafting_system.md @@ -0,0 +1,67 @@ +# Scrap Crafting System + +## Overview + +As one of its main goals, Aftershock allows the crafting of miscellaneous, highly technological devices that have no actual basis in reality. To make the crafting of these devices more balanced an intuitive, and to make adding more recipes and items easier, aftershock utilizes a crafting a system in which abstracted pieces of increasingly rare scrap are used to craft increasingly useful tools. + + +### Current Scrap Categories + +The following table lists the currently planned/implemented scrap categories and their tiers. + +| Category | Tier 1 | Tier 2 | Tier 3 | Tier 4 | Tier 5 | +| ----------------- | -------------------- | ------------------------ | -------------------------- | ------------------------- | ------------------------------------ | +| `Circuitry` | scrap photonics | photonic circuitry | photonic computation core | hypergeometric photonics | acausal logic permutator | +| `Energy Storage` | Nanowire battery | ultracapacitor | Ultracapacitor array | Superconductive Coil | zero-point energy extractor | +| `Material` | Composite Superalloy | vacuum cast Carbide | Nanoprinted Alloys | crystal forged neutrite | phase-uneven matter | +| `Cloth` | E-textile | monofilament silk | graphene weave | woven metamaterial | | +| `Magnet` | Emag | cryo electromagnet | super conductive emag | ferrofluid dynamo | | +| `Optics ` | | Laser Optics | Phased Array Optics | Nano-optics | | +| `Neural I/O` | peripheral electrode | neural electrode | Brain implant prod | Synthetic Neural Tissue | neurosynaptic interface matrix | +| `Biomaterial` | monomeric slurry | micellular growth medium | artificial muscle fibers | self healing polymers | autologous totipotent tissue culture | + +Note that more categories can be added, and that it inst necessary for a category to encompass the five tiers, although its better if they do. + +## Scrap Tiers Briefly Explained + +### Tier 1 + +Tier 1 scrap is plentiful, and can be easily found even when you aren't specifically looking for it. It might be dropped by defeating common enemies, or by disassembling common household objects. Ideally Tier 1 scrap is mostly used as a filler component in more advanced recipes. Things that might be crafted using only this tier of scrap must be single-use and not very effective, and should see little use outside of the early game.For example + +- Makeshift ammunition of all kinds, that might risk damaging your gun. +- Weak grenades with very limited range. + +### Tier 2 + +Tier 2 scrap remains common, but requires some measure of effort to acquire. Perhaps it spawns only in certain locations or requires specialized tools and skills to extract. This scrap might be used to craft disposable tools and weapons or to make decent quality ammunition and explosives. For example: + +- Bulky, makeshift version of an UPS with very limited charge capacity. +- A rail gun/laser that works only for a limited number of shots before melting. +- A grenade that emits a low range electric field. + +### Tier 3 + +Much like tier 2 above, this type of scrap is common, but is only meant to spawn in locations that might prove dangerous to a mid-game characters. Additionally, it should always need tools and skills to extract. Tier 3 scrap might be used to craft basic rechargeable tools, mid-quality weapons and exotic ammunition and grenades. For example: + +- UPS +- Non relaodable charge packs for Laser Weapons +- Shoddy laser Rifle + +### Tier 4 + +This tier of scrap is properly uncommon, it spawns should be limited to the 'boss rooms' of mid-game and to end-game dungeons, and should prove challenging to acquire. It might be used to craft tools that provide great convenience in the non combat aspects of the game, single use items that grant very powerful abilities and good quality weapons. For Example + +- Most utility bionics. +- Laser Weapons. +- Atomic tools. +- Singe use invisibility cloak. + +### Tier 5 + +Very rare loot occasionally dropped by endgame threats and dungeons, extracting it requires very high skills and specialized tools. Thematically linked to the dimensional technology that caused the cataclysm. Might be used to craft items that severely and permanently alter the combat aspects of gameplay. For example: + +- Hologram Cloak Mk. II +- Rechargeable Spell Casters +- CBMs that interact with space-time +- Most combat bionics. + diff --git a/data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json b/data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json new file mode 100644 index 0000000000000..b529cda9d6512 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/abstract_scrap.json @@ -0,0 +1,49 @@ +[ + { + "abstract": "afs_scrap_1", + "type": "GENERIC", + "category": "spare_parts", + "name": "ur-scrap", + "description": "A small techno doodad.", + "looks_like": "e_scrap", + "price": 500, + "price_postapoc": 1000, + "weight": "250 g", + "volume": "50 ml", + "to_hit": -3, + "symbol": "*", + "color": "light_gray" + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_2", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 5000, + "price_postapoc": 10000 + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_3", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 5000, + "price_postapoc": 50000 + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_4", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 50000, + "price_postapoc": 100000 + }, + { + "type": "GENERIC", + "abstract": "afs_scrap_5", + "name": "ur-scrap", + "copy-from": "afs_scrap_1", + "price": 500000, + "price_postapoc": 1000000 + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json b/data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json new file mode 100644 index 0000000000000..648f8deda18f1 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/circuity_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_circuitry_1", + "copy-from": "afs_scrap_1", + "name": "scrap photonics", + "description": "Small circuits blue and gold, transmitting signals through light.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_2", + "copy-from": "afs_scrap_2", + "name": "photonic circuitry", + "description": "A resplendent golden grid inlaid on dark blue substrate.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_3", + "copy-from": "afs_scrap_3", + "name": "photonic computation core", + "description": "A monolithic circuit shaped as a glowing cube of crystal.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_4", + "copy-from": "afs_scrap_4", + "name": "hypergeometric photonics", + "description": "In your hands lies a self-contained digital universe. Its programs glowing like stars fixed on computational shells infinitely layered.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_circuitry_5", + "copy-from": "afs_scrap_5", + "name": "acausal logic permutator", + "description": "It has given you an answer, but you are yet to ask anything.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json b/data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json new file mode 100644 index 0000000000000..110562c24db93 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/energy_storage_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_energy_storage_1", + "copy-from": "afs_scrap_1", + "name": "nanowire battery", + "description": "A small battery component with a very high energy density.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_2", + "copy-from": "afs_scrap_2", + "name": "ultracapacitor", + "description": "A capacitor made from exotic compounds, capable of storing a high amount of electric charge.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_3", + "copy-from": "afs_scrap_3", + "name": "ultracapacitor array", + "description": "Ultracapacitors assembled into a finely tunned energy storage array.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_4", + "copy-from": "afs_scrap_4", + "name": "superconductive coil", + "description": "Superconductive wire warped upon itself manipulates the electromagnetic spectrum to store vast amounts of power.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_energy_storage_5", + "copy-from": "afs_scrap_5", + "name": "zero-point energy extractor", + "description": "A complex grid pins space-time to the surface of the multiversal hyper-torus, allowing the energies within to leak into our sliver of existence.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json b/data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json new file mode 100644 index 0000000000000..64fa59e99bcf3 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/magnet_scrap.json @@ -0,0 +1,26 @@ +[ + { + "type": "GENERIC", + "id": "afs_magnet_1", + "copy-from": "afs_scrap_1", + "name": "high quality electromagnet", + "description": "A sturdy, industrially crafted electromagnet.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_magnet_2", + "copy-from": "afs_scrap_2", + "name": "cryo electromagnet", + "description": "A powerful super conductive electromagnet, that must be kept at very low temperatures to operate.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_magnet_3", + "copy-from": "afs_scrap_3", + "name": "super conductive electromagnet", + "description": "A powerful electromagnet made from a room temperature superconductor .", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/material_scrap.json b/data/mods/Aftershock/items/crafting_scrap/material_scrap.json new file mode 100644 index 0000000000000..ef49f59636b74 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/material_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_material_1", + "copy-from": "afs_scrap_1", + "name": "composite alloy", + "description": "Miscellaneous scrap pieces made from a composite alloy.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_2", + "copy-from": "afs_scrap_2", + "name": "vacuum cast carbide", + "description": "Malleable carbide cast by forges on high earth orbit.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_3", + "copy-from": "afs_scrap_1", + "name": "nanoprinted alloy", + "description": "A meta material fabricated by precisely layering different elements at an atomic scale.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_4", + "copy-from": "afs_scrap_4", + "name": "crystal forged neutrite", + "description": "Great forges within the Earth's core wrought hydrogen into flaming metal and poured it within lattices of super conductive lanthanum. Locked in magnetic equilibrium, it was left to cool into a dark unbreakable metal", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_material_5", + "copy-from": "afs_scrap_5", + "name": "phase uneven matter", + "description": "Matter condensed from the liminal spaces between dimmensions.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json b/data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json new file mode 100644 index 0000000000000..538390ee5dec5 --- /dev/null +++ b/data/mods/Aftershock/items/crafting_scrap/neural_io_scrap.json @@ -0,0 +1,42 @@ +[ + { + "type": "GENERIC", + "id": "afs_neural_io_1", + "copy-from": "afs_scrap_1", + "name": "peripheral electrode", + "description": "A thin strand of wire and a clamp, meant to be spliced into the smaller nerves of the human body.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_2", + "copy-from": "afs_scrap_2", + "name": "neural electrode", + "description": "A small array of metallic needles allows complex communication between machine and human mind.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_3", + "copy-from": "afs_scrap_3", + "name": "brain implant prod", + "description": "A complexly etched rod of metal interfaces with the corpus callosum of the patient, granting increased control of bionic functions.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_4", + "copy-from": "afs_scrap_4", + "name": "artificial neural tissue", + "description": "Photonic axons process thought at speeds far surpassing primitive, chemical-driven communication.", + "looks_like": "scrap" + }, + { + "type": "GENERIC", + "id": "afs_neural_io_5", + "copy-from": "afs_scrap_5", + "name": "neurosynaptic interface matrix", + "description": "A membrane of artificial neurons envelops the cerebral cortex, melding machine and human intellect into a gestalt much greater than its individual parts.", + "looks_like": "scrap" + } +] diff --git a/data/mods/Aftershock/items/grenades.json b/data/mods/Aftershock/items/grenades.json new file mode 100644 index 0000000000000..b69bbb3af2764 --- /dev/null +++ b/data/mods/Aftershock/items/grenades.json @@ -0,0 +1,24 @@ +[ + { + "id": "afs_electroshock_grenade_1", + "type": "TOOL", + "copy-from": "grenade_canister", + "category": "weapons", + "looks_like": "grenade_emp", + "name": "electroshock grenade", + "description": "This is an electronic weapon that will emit a short ranged electric field. When activated, you'll have five turns before it starts doing so; throwing it before that would be a good idea.", + "countdown_action": { "menu_text": "Pull pin", "type": "transform", "target": "afs_electroshock_grenade_1_act" } + }, + { + "id": "afs_electroshock_grenade_1_act", + "type": "TOOL", + "copy-from": "afs_electroshock_grenade_1", + "looks_like": "grenade_emp_act", + "name": "armed electroshock grenade", + "description": "This electroshock grenade is currently creating a dangerous electric field.", + "emits": [ "emit_shock_cloud" ], + "countdown_interval": 20, + "countdown_action": { "type": "transform", "target": "null" }, + "flags": [ "TRADER_AVOID" ] + } +] diff --git a/data/mods/Aftershock/items/item_groups.json b/data/mods/Aftershock/items/item_groups.json index b18fd6cd6119d..74f51f2e177a3 100644 --- a/data/mods/Aftershock/items/item_groups.json +++ b/data/mods/Aftershock/items/item_groups.json @@ -78,6 +78,24 @@ [ "schematics_searchlight", 50 ] ] }, + { + "id": "science", + "//": "extension of vanilla itemgroup", + "type": "item_group", + "items": [ [ "bionic_maintenance_toolkit", 20 ] ] + }, + { + "id": "tools_medical", + "//": "extension of vanilla itemgroup", + "type": "item_group", + "items": [ [ "bionic_maintenance_toolkit", 20 ] ] + }, + { + "id": "surgery", + "//": "extension of vanilla itemgroup", + "type": "item_group", + "items": [ [ "bionic_maintenance_toolkit", 20 ] ] + }, { "id": "jewelry_accessories", "type": "item_group", diff --git a/data/mods/Aftershock/items/items.json b/data/mods/Aftershock/items/items.json index 0a4284cc68331..411ea74140d05 100644 --- a/data/mods/Aftershock/items/items.json +++ b/data/mods/Aftershock/items/items.json @@ -5,7 +5,7 @@ "type": "TOOL", "name": { "str": "precision solderers", "str_pl": "precision solderers" }, "flags": "TRADER_AVOID", - "qualities": [ [ "SAW_M_FINE", 1 ], [ "SCREW_FINE", 1 ], [ "CUT_FINE", 2 ] ] + "qualities": [ [ "SAW_M_FINE", 1 ], [ "SCREW_FINE", 1 ], [ "CUT_FINE", 2 ], [ "BIONIC_ASSEMBLY", 2 ] ] }, { "type": "GENERIC", diff --git a/data/mods/Aftershock/items/tool_quality.json b/data/mods/Aftershock/items/tool_quality.json index 646e2f5df34d6..2ed36b8777d4d 100644 --- a/data/mods/Aftershock/items/tool_quality.json +++ b/data/mods/Aftershock/items/tool_quality.json @@ -4,5 +4,10 @@ "id": "CHURN", "name": "churn", "//": "Delete this when you mainline Dairy products existing PR" + }, + { + "type": "tool_quality", + "id": "BIONIC_ASSEMBLY", + "name": "bionic assembly" } ] diff --git a/data/mods/Aftershock/items/tools.json b/data/mods/Aftershock/items/tools.json index e48ead4b0c5d5..f015e62b0e767 100644 --- a/data/mods/Aftershock/items/tools.json +++ b/data/mods/Aftershock/items/tools.json @@ -240,6 +240,14 @@ "covers": [ "LEG_EITHER" ], "flags": [ "WAIST", "FRAGILE", "OVERSIZE", "IS_UPS" ] }, + { + "id": "bionic_maintenance_toolkit", + "copy-from": "screwdriver_set", + "type": "TOOL", + "name": { "str": "bionic maintenance toolkit", "str_pl": "bionic maintenance toolkits" }, + "description": "A set of very small tools and encrypted digital keys normally used to repair bionic modules in clinical settings. They will allow you to disassemble simple bionics, but anything more complex would require even more specialized tools.", + "qualities": [ [ "BIONIC_ASSEMBLY", 1 ], [ "SAW_M_FINE", 1 ] ] + }, { "id": "afs_bionic_power_mod", "copy-from": "mod_battery", diff --git a/data/mods/Aftershock/recipes/bionic_recipes.json b/data/mods/Aftershock/recipes/bionic_recipes.json index e4ba280ffe77e..d684f316cd313 100644 --- a/data/mods/Aftershock/recipes/bionic_recipes.json +++ b/data/mods/Aftershock/recipes/bionic_recipes.json @@ -12,8 +12,7 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_augs", 5 ], [ "recipe_lab_elec", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 6 ], [ "UPS_off", 1 ] ], [ [ "amplifier", 4 ] ], @@ -33,9 +32,8 @@ "reversible": true, "decomp_learn": 8, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], - "using": [ [ "soldering_standard", 32 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "using": [ [ "soldering_standard", 20 ] ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 10 ], [ "UPS_off", 2 ], [ "adv_UPS_off", 1 ] ], [ [ "amplifier", 6 ] ], @@ -56,8 +54,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 4 ] ], [ [ "amplifier", 2 ] ], [ [ "solar_cell", 4 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -73,8 +70,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "amplifier", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -106,8 +102,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "hose", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -123,8 +118,7 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 1 ] ], [ [ "amplifier", 1 ] ], [ [ "lens", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -140,8 +134,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "element", 1 ] ], [ [ "hose", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -155,10 +148,8 @@ "time": 50000, "reversible": true, "decomp_learn": 8, - "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "element", 4 ] ], @@ -180,8 +171,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "amplifier", 3 ] ], @@ -203,8 +193,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "mold_plastic", -1 ] ], [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "power_supply", 2 ] ], [ [ "syringe", 1 ] ], [ [ "plastic_chunk", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -220,8 +209,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "spring", 4 ] ], [ [ "plastic_chunk", 3 ] ], @@ -243,8 +231,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "spring", 4 ] ], [ [ "afs_scrap_titanium", 4 ] ], [ [ "wire", 4 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -260,8 +247,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "glass_tinted", 4 ] ], [ [ "cable", 7 ] ], [ [ "wire", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -277,8 +263,7 @@ "decomp_learn": 6, "book_learn": [ [ "recipe_lab_elec", 5 ], [ "recipe_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "glass_tinted", 4 ] ], [ [ "cable", 7 ] ], [ [ "wire", 2 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -293,9 +278,8 @@ "reversible": true, "decomp_learn": 9, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 6 ] ], - "using": [ [ "soldering_standard", 20 ], [ "welding_standard", 5 ] ], - "tools": [ [ [ "afs_solderers_item", -1 ], [ "toolset", -1 ] ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ], + "using": [ [ "soldering_standard", 20 ] ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 2 } ], "components": [ [ [ "pipe", 1 ] ], [ [ "spring", 1 ] ], [ [ "plastic_chunk", 2 ] ], [ [ "nail", 1 ] ] ] }, { @@ -311,7 +295,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -327,7 +316,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -343,7 +337,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 5 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -359,7 +358,12 @@ "decomp_learn": 5, "book_learn": [ [ "recipe_lab_elec", 6 ], [ "recipe_mil_augs", 6 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "HAMMER", "level": 3 }, { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 } ], + "qualities": [ + { "id": "HAMMER", "level": 3 }, + { "id": "SCREW", "level": 1 }, + { "id": "WRENCH", "level": 1 }, + { "id": "BIONIC_ASSEMBLY", "level": 2 } + ], "components": [ [ [ "alloy_sheet", 4 ], [ "alloy_plate", 1 ] ], [ [ "burnt_out_bionic", 1 ] ] ] }, { @@ -375,7 +379,7 @@ "decomp_learn": 7, "book_learn": [ [ "recipe_lab_elec", 4 ], [ "recipe_augs", 4 ] ], "using": [ [ "soldering_standard", 20 ] ], - "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 1 } ], "components": [ [ [ "scrap", 4 ] ], [ [ "element", 3 ] ], [ [ "cable", 10 ] ], [ [ "burnt_out_bionic", 1 ] ] ] } ] diff --git a/data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json b/data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json new file mode 100644 index 0000000000000..9b2cc4e0c1d3b --- /dev/null +++ b/data/mods/Aftershock/recipes/deconstruction/bionic_deconstruction.json @@ -0,0 +1,18 @@ +[ + { + "result": "burnt_out_bionic", + "type": "uncraft", + "skill_used": "electronics", + "difficulty": 7, + "time": "10 m", + "using": [ [ "soldering_standard", 10 ], [ "welding_standard", 10 ] ], + "qualities": [ { "id": "BIONIC_ASSEMBLY", "level": 1 } ], + "components": [ + [ [ "afs_circuitry_2", 1 ] ], + [ [ "afs_magnet_1", 2 ] ], + [ [ "afs_energy_storage_2", 1 ] ], + [ [ "afs_neural_io_1", 2 ] ], + [ [ "afs_material_1", 1 ] ] + ] + } +] diff --git a/data/mods/Aftershock/recipes/grenades.json b/data/mods/Aftershock/recipes/grenades.json new file mode 100644 index 0000000000000..c0004dd60a86e --- /dev/null +++ b/data/mods/Aftershock/recipes/grenades.json @@ -0,0 +1,15 @@ +[ + { + "result": "afs_electroshock_grenade_1", + "type": "recipe", + "category": "CC_ELECTRONIC", + "subcategory": "CSC_WEAPON_EXPLOSIVE", + "skill_used": "electronics", + "difficulty": 3, + "autolearn": true, + "time": "5 m", + "qualities": [ { "id": "SCREW_FINE", "level": 1 } ], + "using": [ [ "soldering_standard", 10 ] ], + "components": [ [ [ "afs_energy_storage_2", 1 ] ], [ [ "afs_material_1", 2 ] ] ] + } +] From ec213d75f5caca6f7fc5e92681494c0684346b43 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 1 Mar 2020 15:08:18 -0500 Subject: [PATCH 122/219] Dark Skies Part 2: Blacklists (#38501) --- .../blacklists/item_blacklist.json | 264 ++++++++++++++++++ .../blacklists/location_blacklist.json | 89 ++++++ .../blacklists/mon_blacklist.json | 8 + .../blacklists/scenario_blacklist.json | 19 ++ .../blacklists/trait_blacklist.json | 7 + 5 files changed, 387 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/blacklists/item_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/location_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json create mode 100644 data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json diff --git a/data/mods/Dark-Skies-Above/blacklists/item_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/item_blacklist.json new file mode 100644 index 0000000000000..544b4ae9376d9 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/item_blacklist.json @@ -0,0 +1,264 @@ +[ + { + "//": "blacklists sci-fi items native to cata's default setting, as they don't fit C:DSA's lore at the moment", + "type": "ITEM_BLACKLIST", + "items": [ + "12mm", + "20x66_10_mag", + "20x66_20_mag", + "20x66_40_mag", + "20x66_beanbag", + "20x66_bootleg_flechette", + "20x66_bootleg_shot", + "20x66_bootleg_slug", + "20x66_exp", + "20x66_flare", + "20x66_flechette", + "20x66_frag", + "20x66_inc", + "20x66_shot", + "20x66_slug", + "360_200_mag", + "360_400_mag", + "5x50_100_mag", + "5x50_50_mag", + "5x50_hull", + "5x50dart", + "5x50heavy", + "8mm_bootleg", + "8mm_caseless", + "8mm_civilian", + "8mm_fmj", + "8mm_inc", + "8mm_jhp", + "8x40_10_mag", + "8x40_100_mag", + "8x40_25_mag", + "8x40_250_mag", + "8x40_50_mag", + "8x40_500_mag", + "alien_pod_resin", + "arm", + "atomic_coffee", + "atomic_coffeepot", + "atomic_lamp", + "atomic_light", + "bio_adrenaline", + "bio_ads", + "bio_alarm", + "bio_armor_arms", + "bio_armor_eyes", + "bio_armor_head", + "bio_armor_legs", + "bio_armor_torso", + "bio_batteries", + "bio_blade", + "bio_blood_anal", + "bio_blood_filter", + "bio_cable", + "bio_carbon", + "bio_chain_lightning", + "bio_claws", + "bio_climate", + "bio_cloak", + "bio_dex_enhancer", + "bio_digestion", + "bio_ears", + "bio_emp", + "bio_emp_armgun", + "bio_ethanol", + "bio_evap", + "bio_eye_enhancer", + "bio_eye_optic", + "bio_face_mask", + "bio_faraday", + "bio_fingerhack", + "bio_flashbang", + "bio_flashlight", + "bio_fuel_cell_gasoline", + "bio_geiger", + "bio_gills", + "bio_ground_sonar", + "bio_heat_absorb", + "bio_heatsink", + "bio_hydraulics", + "bio_infrared", + "bio_int_enhancer", + "bio_jointservo", + "bio_laser", + "bio_leukocyte", + "bio_lighter", + "bio_lockpick", + "bio_magnet", + "bio_membrane", + "bio_memory", + "bio_metabolics", + "bio_nanobots", + "bio_night", + "bio_night_vision", + "bio_ods", + "bio_painkiller", + "bio_power_armor_interface", + "bio_power_armor_interface_mkII", + "bio_power_storage", + "bio_probability_travel", + "bio_purifier", + "bio_radscrubber", + "bio_railgun", + "bio_razors", + "bio_recycler", + "bio_remote", + "bio_resonator", + "bio_scent_mask", + "bio_scent_vision", + "bio_shock", + "bio_shock_absorber", + "bio_shockwave", + "bio_shotgun", + "bio_soporific", + "bio_speed", + "bio_str_enhancer", + "bio_sunglasses", + "bio_surgical_razor", + "bio_syringe", + "bio_targeting", + "bio_taste_blocker", + "bio_tattoo_led", + "bio_teleport", + "bio_time_freeze", + "bio_tools", + "bio_torsionratchet", + "bio_uncanny_dodge", + "bio_ups", + "bio_watch", + "bio_water_extractor", + "bio_weight", + "bot_rifleturret", + "bot_crows_m240", + "bot_turret_riot", + "cerberus_laser", + "coilgun", + "depowered_armor", + "depowered_helmet", + "emp_gun", + "fetus", + "ftk93", + "heavy_atomic_battery_cell", + "hk_g80", + "huge_atomic_battery_cell", + "iv_mutagen", + "iv_mutagen_alpha", + "iv_mutagen_beast", + "iv_mutagen_bird", + "iv_mutagen_cattle", + "iv_mutagen_cephalopod", + "iv_mutagen_chimera", + "iv_mutagen_elfa", + "iv_mutagen_feline", + "iv_mutagen_fish", + "iv_mutagen_insect", + "iv_mutagen_lizard", + "iv_mutagen_lupine", + "iv_mutagen_medical", + "iv_mutagen_plant", + "iv_mutagen_raptor", + "iv_mutagen_rat", + "iv_mutagen_slime", + "iv_mutagen_spider", + "iv_mutagen_troglobite", + "iv_mutagen_ursine", + "iv_purifier", + "l_bak_223", + "l_base_223", + "l_car_223", + "l_dsr_223", + "l_enforcer_45", + "l_HFPack", + "l_lmg_223", + "l_long_45", + "l_lookout_9mm", + "l_mbr_223", + "l_mp_45", + "l_mp_9mm", + "l_sp_45", + "l_sp_9mm", + "laser_pack", + "laser_rifle", + "leg", + "light_atomic_battery_cell", + "light_minus_atomic_battery_cell", + "lw12mag", + "lw21mag", + "lwfeed", + "marloss_berry", + "marloss_gel", + "marloss_scarf", + "marloss_seed", + "medium_atomic_battery_cell", + "mutagen", + "mutagen_alpha", + "mutagen_beast", + "mutagen_bird", + "mutagen_cattle", + "mutagen_cephalopod", + "mutagen_chimera", + "mutagen_elfa", + "mutagen_feline", + "mutagen_fish", + "mutagen_insect", + "mutagen_lizard", + "mutagen_lupine", + "mutagen_medical", + "mutagen_plant", + "mutagen_raptor", + "mutagen_rat", + "mutagen_slime", + "mutagen_spider", + "mutagen_troglobite", + "mutagen_ursine", + "mycus_fruit", + "needlegun", + "needlepistol", + "pheromone", + "plasma_gun", + "plasma_rifle", + "plut_cell", + "power_armor_basic", + "power_armor_frame", + "power_armor_heavy", + "power_armor_helmet_basic", + "power_armor_helmet_heavy", + "power_armor_helmet_light", + "power_armor_light", + "purifier", + "razorclaw_roe", + "rebar_rail", + "rebar_rifle", + "recipe_caseless", + "reloaded_5x50dart", + "resin_chunk", + "rm103a_pistol", + "rm120c", + "rm121aux", + "rm13_armor", + "rm13_armor_on", + "rm20", + "rm2000_smg", + "rm228", + "rm298", + "rm360_carbine", + "rm451_flamethrower", + "rm51_assault_rifle", + "rm614_lmg", + "rm802", + "rm88_battle_rifle", + "rm99_pistol", + "steel_rail", + "taint_tornado", + "unbio_blaster_gun", + "v29", + "v29_cheap", + "wine_mycus" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json new file mode 100644 index 0000000000000..80201b69af785 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json @@ -0,0 +1,89 @@ +[ + { + "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be readded with time", + "type": "overmap_special", + "id": "Necropolis", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "St_Johns_farm", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Strangle Temple", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "evac_center", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "hub_01", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Hazardous Waste Sarcophagus", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Isherwood Farms", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "//": "sorry Mr. Lapin ;w;. temporary until I work on NPCs", + "type": "overmap_special", + "id": "Cabin_Lapin", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Strange Cabin", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "//": "there will be 'FEMA camps' in the future, but almost even more sinister", + "type": "overmap_special", + "id": "FEMA Camp", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "FEMA_camp", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "lab_surface_big", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Mass Grave", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Mine Entrance", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json new file mode 100644 index 0000000000000..ed0d7c07cf6ad --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/mon_blacklist.json @@ -0,0 +1,8 @@ +[ + { + "//": "edited from no_wildlife", + "type": "MONSTER_WHITELIST", + "mode": "EXCLUSIVE", + "categories": [ "ALIEN", "WILDLIFE" ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json new file mode 100644 index 0000000000000..eb53b77bf1bc2 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/scenario_blacklist.json @@ -0,0 +1,19 @@ +[ + { + "type": "SCENARIO_BLACKLIST", + "subtype": "whitelist", + "scenarios": [ + "evacuee", + "missed", + "largebuilding", + "surrounded", + "isolationist", + "infected", + "fire", + "bad_day", + "patient", + "wilderness", + "heli_crash" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json new file mode 100644 index 0000000000000..3074ac0086318 --- /dev/null +++ b/data/mods/Dark-Skies-Above/blacklists/trait_blacklist.json @@ -0,0 +1,7 @@ +[ + { + "//": "no need for robust genetics atm", + "type": "ITEM_BLACKLIST", + "traits": [ "ROBUST" ] + } +] From 71cff0291198507b86f247cf4e2671b4bdcc05ec Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 1 Mar 2020 16:33:03 -0500 Subject: [PATCH 123/219] Dark Skies Part 3: Effects and Items (#38520) --- data/mods/Dark-Skies-Above/ammo_effect.json | 27 ++++++++ data/mods/Dark-Skies-Above/effects.json | 14 ++++ .../items/clothing+armor.json | 68 +++++++++++++++++++ .../Dark-Skies-Above/items/electronics.json | 44 ++++++++++++ data/mods/Dark-Skies-Above/items/weapons.json | 43 ++++++++++++ .../Dark-Skies-Above/mutations/traits.json | 33 +++++++++ .../speech/neworder_speech.json | 68 +++++++++++++++++++ 7 files changed, 297 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/ammo_effect.json create mode 100644 data/mods/Dark-Skies-Above/effects.json create mode 100644 data/mods/Dark-Skies-Above/items/clothing+armor.json create mode 100644 data/mods/Dark-Skies-Above/items/electronics.json create mode 100644 data/mods/Dark-Skies-Above/items/weapons.json create mode 100644 data/mods/Dark-Skies-Above/mutations/traits.json create mode 100644 data/mods/Dark-Skies-Above/speech/neworder_speech.json diff --git a/data/mods/Dark-Skies-Above/ammo_effect.json b/data/mods/Dark-Skies-Above/ammo_effect.json new file mode 100644 index 0000000000000..62ba6a77ad085 --- /dev/null +++ b/data/mods/Dark-Skies-Above/ammo_effect.json @@ -0,0 +1,27 @@ +[ + { + "id": "DKS_NUKEGAS", + "type": "ammo_effect", + "aoe": { "field_type": "fd_nuke_gas", "intensity_min": 0, "intensity_max": 3 } + }, + { + "id": "DKS_RELAXGAS", + "type": "ammo_effect", + "aoe": { "field_type": "fd_relax_gas", "intensity_min": 0, "intensity_max": 3, "radius": 2 } + }, + { + "id": "DKS_RELAXTRAIL", + "type": "ammo_effect", + "trail": { "field_type": "fd_relax_gas", "intensity_min": 1, "intensity_max": 2, "chance": 75 } + }, + { + "id": "DKS_TOXTRAIL", + "type": "ammo_effect", + "aoe": { "field_type": "fd_toxic_gas", "intensity_min": 0, "intensity_max": 3 } + }, + { + "id": "DKS_TOXGAS_BIG", + "type": "ammo_effect", + "aoe": { "field_type": "fd_toxic_gas", "intensity_min": 3, "intensity_max": 3, "radius": 3 } + } +] diff --git a/data/mods/Dark-Skies-Above/effects.json b/data/mods/Dark-Skies-Above/effects.json new file mode 100644 index 0000000000000..deda33e111896 --- /dev/null +++ b/data/mods/Dark-Skies-Above/effects.json @@ -0,0 +1,14 @@ +[ + { + "type": "effect_type", + "id": "panic", + "name": [ "Panicking" ], + "desc": [ "You just can't stop shaking and are overwhelmed by fear." ], + "apply_message": "An all consuming dread overwhelms your mind and you begin to shake uncontrollably!", + "rating": "bad", + "remove_message": "Your heartrate slows back to normal!", + "miss_messages": [ [ "You shake uncontrollably", 4 ] ], + "base_mods": { "dex_mod": [ -2 ], "int_mod": [ -1 ], "per_mod": [ -3 ] }, + "show_in_info": true + } +] diff --git a/data/mods/Dark-Skies-Above/items/clothing+armor.json b/data/mods/Dark-Skies-Above/items/clothing+armor.json new file mode 100644 index 0000000000000..c7489ff632ae3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/items/clothing+armor.json @@ -0,0 +1,68 @@ +[ + { + "//": "a bit of a placeholder until I work on this more in-depth", + "id": "dks_neworder_armor_salvaged", + "type": "ARMOR", + "category": "armor", + "name": "salvaged new order armor", + "description": "A suit of armor belonging to a human-sized soldier of the New Order. Its terribly damaged from some combination of the combat its seen, the process needed to pry it off its wearer, and some sort of dead man's switch on the elements that actually power the thing and make it easy to wear.", + "weight": "12214 g", + "volume": "25 L", + "price": 70000, + "price_postapoc": 70000, + "to_hit": 1, + "bashing": 1, + "material": [ "steel", "nomex" ], + "symbol": "[", + "looks_like": "power_armor", + "color": "light_gray", + "covers": [ "TORSO", "ARMS", "HANDS", "LEGS", "FEET", "HEAD" ], + "coverage": 95, + "encumbrance": 40, + "storage": "2500 ml", + "warmth": 50, + "material_thickness": 4, + "environmental_protection": 6, + "flags": [ "WATERPROOF", "STURDY" ] + }, + { + "id": "dks_riotshield", + "type": "ARMOR", + "name": "new order shield", + "category": "armor", + "description": "A simple shield made of some sort of polycarbonates, used extensively by the Vigilants, the gendarmerie of the New Order. Alongside their infamous shock batons, this is an essential tool in 'keeping the peace'.", + "weight": "3400 g", + "volume": "4 L", + "price": 110000, + "bashing": 8, + "material": [ "plastic" ], + "symbol": "[", + "color": "dark_gray", + "covers": [ "ARM_EITHER", "HAND_EITHER" ], + "coverage": 85, + "encumbrance": 16, + "material_thickness": 3, + "techniques": [ "WBLOCK_2" ], + "flags": [ "OVERSIZE", "BELTED", "RESTRICT_HANDS", "BLOCK_WHILE_WORN" ] + }, + { + "id": "dks_battleshield", + "type": "ARMOR", + "name": "new order battle shield", + "category": "armor", + "description": "A well forged shield made of steel, emblazed with what appears to be a highly stylized depiction of a sword piercing a star.", + "weight": "3300 g", + "volume": "5 L", + "price": 110000, + "bashing": 8, + "material": [ "steel" ], + "symbol": "[", + "color": "dark_gray", + "covers": [ "ARM_EITHER", "HAND_EITHER" ], + "coverage": 90, + "encumbrance": 20, + "material_thickness": 3, + "techniques": [ "WBLOCK_3" ], + "flags": [ "OVERSIZE", "BELTED", "RESTRICT_HANDS", "BLOCK_WHILE_WORN" ] + } +] diff --git a/data/mods/Dark-Skies-Above/items/electronics.json b/data/mods/Dark-Skies-Above/items/electronics.json new file mode 100644 index 0000000000000..477d94a92abc4 --- /dev/null +++ b/data/mods/Dark-Skies-Above/items/electronics.json @@ -0,0 +1,44 @@ +[ + { + "type": "GENERIC", + "id": "broken_dks_emissary", + "symbol": ",", + "color": "green", + "name": "broken emissary", + "category": "other", + "description": "The massive body of a collapsed emissary. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts.", + "price": 1000, + "material": [ "superalloy" ], + "volume": "875000 ml", + "weight": "200 kg", + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] + }, + { + "type": "GENERIC", + "id": "broken_dks_emissary_war", + "symbol": ",", + "color": "green", + "name": "broken emissary of war", + "category": "other", + "description": "The massive body of a collapsed emissary of war. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts.", + "price": 1000, + "material": [ "superalloy" ], + "volume": "875000 ml", + "weight": "200 kg", + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] + }, + { + "type": "GENERIC", + "id": "broken_dks_emissary_flame", + "symbol": ",", + "color": "green", + "name": "broken emissary of flame", + "category": "other", + "description": "The massive body of a collapsed emissary of flame. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts.", + "price": 1000, + "material": [ "superalloy" ], + "volume": "875000 ml", + "weight": "200 kg", + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] + } +] diff --git a/data/mods/Dark-Skies-Above/items/weapons.json b/data/mods/Dark-Skies-Above/items/weapons.json new file mode 100644 index 0000000000000..cb8eee3ac4ef9 --- /dev/null +++ b/data/mods/Dark-Skies-Above/items/weapons.json @@ -0,0 +1,43 @@ +[ + { + "id": "dks_flamesword_salvaged", + "type": "TOOL", + "category": "weapons", + "looks_like": "zweihander", + "name": { "str": "salvaged consecrator's sword" }, + "description": "A well built and decorated sword forged from dense alien metal. Its ability to conjure fireballs does not seem to respond to your will, but the cutting edge is perfectly servicable.", + "weight": "5400 g", + "volume": "3750 ml", + "price": 310000, + "bashing": 17, + "cutting": 40, + "material": "superalloy", + "symbol": "/", + "color": "light_gray", + "charges_per_use": 1, + "max_charges": 50, + "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 1 ] ], + "flags": [ "DURABLE_MELEE", "SHEATH_SWORD", "ALWAYS_TWOHAND" ] + }, + { + "id": "dks_knightsword_salvaged", + "type": "TOOL", + "symbol": "/", + "color": "light_gray", + "looks_like": "arming_sword", + "name": { "str": "salvaged knight's sword" }, + "description": "A well built sword made from dense alien metal, in service of the knights of the New Order. The runes that adorn it no longer glow, but its cutting edge is perfectly servicable.", + "price": 100000, + "material": "superalloy", + "techniques": [ "WBLOCK_2" ], + "weight": "3360 g", + "volume": "2 L", + "bashing": 14, + "cutting": 31, + "to_hit": 1, + "category": "weapons", + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 8 ] ], + "flags": [ "DURABLE_MELEE", "SHEATH_SWORD" ] + } +] diff --git a/data/mods/Dark-Skies-Above/mutations/traits.json b/data/mods/Dark-Skies-Above/mutations/traits.json new file mode 100644 index 0000000000000..578d13a0df98b --- /dev/null +++ b/data/mods/Dark-Skies-Above/mutations/traits.json @@ -0,0 +1,33 @@ +[ + { + "//": "RP traits that help define your character in the world. allows you to indicate your character's background, affecting some NPC interactions. somewhat experimental", + "type": "mutation", + "id": "DKS_COMBAT", + "name": "RP: Combatant", + "points": 0, + "description": "You've seen your fair share of scruffs and scrapes, and when the Cataclysm hit, you fought the Occupiers and managed to survive to tell the tale. Has no direct skill benefit, but allows you to present yourself as a fighter to certain NPCs. Some might even recognize you.", + "valid": false, + "starting_trait": true, + "purifiable": false + }, + { + "type": "mutation", + "id": "DKS_MED", + "name": "RP: Medic", + "points": 0, + "description": "Your job or experiences had you seeing all sorts of trauma, both physical and mental, and you were trusted during the Cataclysm to provide life-saving care. Has no direct skill benefit, but allows you to present yourself as a healer to certain NPCs. Some might even recognize you.", + "valid": false, + "starting_trait": true, + "purifiable": false + }, + { + "type": "mutation", + "id": "DKS_LEADER", + "name": "RP: Leader", + "points": 0, + "description": "Whether or not you like it, you've always had a knack for managing people and have some hard-won skill in doing so. During the arrival and the ensuing chaos, you helped lead people around you to safety. Has no direct skill benefit, but allows you to present yourself as a leader to certain NPCs. Some might even recognize you.", + "valid": false, + "starting_trait": true, + "purifiable": false + } +] diff --git a/data/mods/Dark-Skies-Above/speech/neworder_speech.json b/data/mods/Dark-Skies-Above/speech/neworder_speech.json new file mode 100644 index 0000000000000..09bfd1ac33562 --- /dev/null +++ b/data/mods/Dark-Skies-Above/speech/neworder_speech.json @@ -0,0 +1,68 @@ +[ + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter.", + "volume": 20 + }, + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter.", + "volume": 20 + }, + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter, followed by a response.", + "volume": 25 + }, + { + "type": "speech", + "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], + "sound": "unintelligble radio chatter.", + "volume": 20 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war" ], + "sound": "a haunting mechanical humming.", + "volume": 60 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary_flame" ], + "sound": "a semi-musical chirping that echos across the landscape.", + "volume": 60 + }, + { + "type": "speech", + "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], + "sound": "booming footsteps.", + "volume": 50 + } +] From 8957b2f92e8025659ca5847885ac63f0aa96d9e4 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Fri, 6 Mar 2020 05:26:11 -0500 Subject: [PATCH 124/219] Dark Skies Part 4: Overrides (#38526) --- .../furniture_terrain/indoor_furniture.json | 31 ++++ .../furniture_terrain/outdoor-furniture.json | 9 ++ .../overrides/items/armor.json | 16 ++ .../overrides/items/books.json | 30 ++++ .../overrides/items/carnivore.json | 139 ++++++++++++++++++ .../overrides/items/electronic.json | 24 +++ .../overrides/items/generics.json | 16 ++ .../overrides/items/newspaper.json | 74 ++++++++++ .../overrides/items/ranged.json | 18 +++ .../overrides/items/tools.json | 51 +++++++ .../overrides/items/vehicle.json | 16 ++ .../overrides/items/weapons.json | 16 ++ .../overrides/locations/cemetery.json | 93 ++++++++++++ .../overrides/locations/overmap_special.json | 12 ++ .../Dark-Skies-Above/overrides/monsters.json | 56 +++++++ 15 files changed, 601 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json create mode 100644 data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/armor.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/books.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/carnivore.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/electronic.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/generics.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/newspaper.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/ranged.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/tools.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/vehicle.json create mode 100644 data/mods/Dark-Skies-Above/overrides/items/weapons.json create mode 100644 data/mods/Dark-Skies-Above/overrides/locations/cemetery.json create mode 100644 data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json create mode 100644 data/mods/Dark-Skies-Above/overrides/monsters.json diff --git a/data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json new file mode 100644 index 0000000000000..691ad164b9879 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/indoor_furniture.json @@ -0,0 +1,31 @@ +[ + { + "//": "todo: add more tech junk to salvage from these things", + "type": "terrain", + "id": "t_plut_generator", + "copy-from": "t_plut_generator", + "name": "Edison generator", + "description": "This imposing apparatus harnesses 'atmospheric charges', or at least thats what the news said when these things came out. Pioneered by Elton Moosek and his Bluebox team, these were immediately snapped up by the government due to their potential to generate near limitless power. It's not doing much good here though. Perhaps it could be salvaged for other purposes.", + "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": "scrap", "count": [ 8, 16 ] } + ] + } + }, + { + "type": "furniture", + "id": "f_dresser", + "copy-from": "f_dresser", + "name": "dresser", + "description": "Dress yourself!" + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json new file mode 100644 index 0000000000000..646f31a041806 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/furniture_terrain/outdoor-furniture.json @@ -0,0 +1,9 @@ +[ + { + "type": "furniture", + "id": "f_mutpoppy", + "copy-from": "f_mutpoppy", + "name": "poppy bush", + "description": "An invasive species brought to Earth by the invaders and found it quite to its liking. It spiny, writhing fronds make it look more like a jungle bush than a conventional poppy except for its red petals, but is named after such due to its similar medicinal properties. It exudes a potent, sleep inducing aroma." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/armor.json b/data/mods/Dark-Skies-Above/overrides/items/armor.json new file mode 100644 index 0000000000000..af4aa91b453be --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/armor.json @@ -0,0 +1,16 @@ +[ + { + "id": "quiver_large", + "copy-from": "quiver_large", + "type": "ARMOR", + "name": { "str": "large quiver" }, + "description": "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 sometimes horses are a little hard to come by in this day and age. Activate to store arrows." + }, + { + "id": "bra", + "copy-from": "bra", + "type": "ARMOR", + "name": { "str": "bra" }, + "description": "A simple bra. For protecting those bits you don't want creatures to look at." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/books.json b/data/mods/Dark-Skies-Above/overrides/items/books.json new file mode 100644 index 0000000000000..ca0ca3f5f373a --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/books.json @@ -0,0 +1,30 @@ +[ + { + "id": "child_book", + "copy-from": "child_book", + "type": "BOOK", + "name": { "str": "children's book" }, + "description": "A little book for little readers. The colorful cartoon characters and sweet stories contained herein belong to a different time, before the sky grew dark and the aliens arrived." + }, + { + "id": "mag_news", + "copy-from": "mag_news", + "type": "BOOK", + "name": { "str": "TIME magazine" }, + "description": "Current events concerning a bunch of people who're all dead now - or working for them." + }, + { + "id": "ZSG", + "copy-from": "ZSG", + "type": "BOOK", + "name": { "str": "Zombie Survival Guide", "str_pl": "copies of Zombie Survival Guide" }, + "description": "While this seems like it would be at least partially useful in this situation, the sheer amount of speculative fiction present makes it practically useless. What the hell is a mi-go? Aren't triffids from some ancient movie?" + }, + { + "id": "mag_tv", + "copy-from": "mag_tv", + "type": "BOOK", + "name": { "str": "US Weekly", "str_pl": "US Weeklies" }, + "description": "Current events concerning a bunch of people who're all dead now - or working for them." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/carnivore.json b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json new file mode 100644 index 0000000000000..07ccc2b00fac3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json @@ -0,0 +1,139 @@ +[ + { + "id": "brain_cooked", + "type": "COMESTIBLE", + "copy-from": "brain_cooked", + "looks_like": "offal_cooked", + "name": { "str": "cooked brains", "str_pl": "cooked brains" }, + "description": "Now you can emulate a zombie! Preparing brain for eating is challenging, and this doesn't seem to be the best way to do it." + }, + { + "//": "tainted meat is meat that has been heavily genetically poisoned or is completely alien in nature", + "type": "COMESTIBLE", + "id": "meat_tainted", + "copy-from": "meat_tainted", + "name": { "str": "chunk of alien meat", "str_pl": "chunks of alien meat" }, + "description": "This dense, stringy substance smells strongly like burnt oil, or some sort of industrial chemical. For all intents and purposes, it seems like the 'meat' of the creature, but its bizarre texture and faintly red-purple tint is unlike anything you've ever experienced before. You could eat it, but no doubt it would not only taste henious but also make you sick, being made of material your body was never supposed to injest." + }, + { + "type": "COMESTIBLE", + "id": "dry_meat_tainted", + "name": "dehydrated alien meat", + "copy-from": "dry_meat_tainted", + "description": "Pieces of alien meat that have been dried to prevent them from rotting away. It will still poison you if you eat this." + }, + { + "type": "COMESTIBLE", + "id": "bone_tainted", + "category": "other", + "copy-from": "bone_tainted", + "name": "alien bone", + "description": "A piece of a hard material with many crests and protrusions, made of a hard material that occasionally leaves a bit of moisture on your hand when you touch it. It seems basically like a bone, though not one you'd see in any anatomy textbook. You could eat it, but no doubt it would not only taste henious but also make you sick, being made of material your body was never supposed to injest. It might at least be able to be used for something, if not as well as the earthly variant due to its fiddly size and shape." + }, + { + "type": "COMESTIBLE", + "id": "fat_tainted", + "category": "other", + "copy-from": "fat_tainted", + "name": "alien fat", + "description": "A chunk of dense fat that is tough and rubbery. It smells simply henious, like open sewer and pungent chemicals, and is doubtless full of strange material that your body was never supposed to injest. It might at least be able to be used for something, if not quite as well as its earthly variant due to its relative impurities." + }, + { + "type": "COMESTIBLE", + "id": "tallow_tainted", + "copy-from": "tallow_tainted", + "name": "alien tallow", + "description": "A smooth grayish block of cleaned and rendered alien fat. Processing it seems to have at least removed some of the smell. It won't spoil for a very long time, and can be used as an ingredient in many projects. It is no safer than its source material to consume." + }, + { + "//": "mutant meat is meat that comes from a creature that is spliced with earthly genes or originally came from earth before being modded", + "id": "mutant_meat", + "copy-from": "mutant_meat", + "type": "COMESTIBLE", + "name": { "str": "chunk of unusual meat", "str_pl": "chunks of unusual meat" }, + "description": "Meat from the aliens is typically quite foul, full of toxins and substances not meant to be digested by humans, however this piece almost looks edible - if not for a few sections that still have strange hues and disgusting, spongey texture. Still, with a bit of preperation, it might even be somewhat palatable." + }, + { + "id": "mutant_meat_scrap", + "type": "COMESTIBLE", + "copy-from": "mutant_meat_scrap", + "name": { "str": "scrap of unusual meat", "str_pl": "scraps of unusual meat" }, + "description": "A tiny scrap of meat from an unusual creature. It smells a bit odd and has a variety of discolorations that indicate that it is still going to be rough on your digestive system. Still, seems digestible at least, if you cook it and remove the worst parts." + }, + { + "id": "mutant_human_flesh", + "copy-from": "mutant_human_flesh", + "type": "COMESTIBLE", + "name": "unusual humanoid meat", + "description": "Freshly butchered from the body of an alien creature that was unsettlingly humanoid in appearance. It smells faintly of chemicals and is colored odd hues that indicate that it is still going to be rough on your digestive system. You'd have to be crazy or starving to eat this." + }, + { + "id": "mutant_human_cooked", + "copy-from": "mutant_human_cooked", + "type": "COMESTIBLE", + "name": "cooked cretin", + "description": "Cooked meat from an alien humanoid. Now that the worst bits have been processed, it's probably digestible, if not very appetizing." + }, + { + "id": "mutant_meat_cooked", + "type": "COMESTIBLE", + "copy-from": "mutant_meat_cooked", + "name": "cooked unusual meat", + "description": "This is a cooked chunk of meat from an unusual critter. It has strange colors, smells a bit funny, and has a mushy texture but it tastes… mostly normal. Hopefully you cut away the worst bits well enough." + }, + { + "id": "mutant_meat_scrap_cooked", + "type": "COMESTIBLE", + "copy-from": "mutant_meat_scrap_cooked", + "name": { "str": "cooked scrap of unusual meat", "str_pl": "cooked scraps of unusual meat" } + }, + { + "id": "mutant_tallow", + "type": "COMESTIBLE", + "copy-from": "mutant_tallow", + "name": "unusual tallow", + "description": "A smooth white block of cleaned and rendered fat sourced from an unusual creature. It will remain edible for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "id": "mutant_lard", + "type": "COMESTIBLE", + "copy-from": "mutant_lard", + "name": "unusual lard", + "description": "A smooth white block of dry-rendered fat sourced from an alien. It will remain edible for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "id": "mutant_human_fat", + "type": "COMESTIBLE", + "copy-from": "mutant_human_fat", + "name": { "str": "chunk of mutant humanoid fat", "str_pl": "chunks of mutant humanoid fat" }, + "description": "Freshly butchered fat from an alien humanoid." + }, + { + "type": "COMESTIBLE", + "id": "mutant_human_tallow", + "name": "unusual humanoid tallow", + "copy-from": "mutant_human_tallow", + "description": "A smooth white block of cleaned and rendered fat sourced from an alien humanoid. It won't rot for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "type": "COMESTIBLE", + "id": "mutant_human_lard", + "name": "unusual humanoid lard", + "copy-from": "mutant_human_lard", + "description": "A smooth white block of dry-rendered fat sourced from an alien humanoid. It won't rot for a very long time, and can be used as an ingredient in many foods and projects." + }, + { + "type": "COMESTIBLE", + "id": "raw_hleather", + "copy-from": "raw_hleather", + "name": "raw human skin", + "description": "A carefully folded raw skin harvested from a humanoid. You can cure it for storage and tanning, or eat it if you're desperate enough." + }, + { + "type": "COMESTIBLE", + "id": "raw_hfur", + "copy-from": "raw_hfur", + "name": "raw humanoid pelt", + "description": "A carefully folded raw skin harvested from a fur-bearing creature that was disturbingly humanoid. It still has the fur attached. You can cure it for storage and tanning, or eat it if you're desperate enough." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/electronic.json b/data/mods/Dark-Skies-Above/overrides/items/electronic.json new file mode 100644 index 0000000000000..9ac5410d1c44b --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/electronic.json @@ -0,0 +1,24 @@ +[ + { + "id": "smart_phone", + "type": "TOOL", + "name": { "str": "smartphone" }, + "copy-from": "smart_phone", + "description": "A popular, fancy smartphone. Capable of making photos due to integrated camera and illuminating an area as per its flashlight app, assuming it has enough charge. The smartphone also has a clock app that includes an alarm. Runs on a small, proprietary power cell that needs a specialized charger. That is to say, is quite difficult to recharge post-Cataclysm.", + "delete": { "flags": [ "USE_UPS" ] } + }, + { + "id": "smartphone_music", + "copy-from": "smartphone_music", + "type": "TOOL", + "name": { "str": "smartphone - music", "str_pl": "smartphones - music" }, + "delete": { "flags": [ "USE_UPS" ] } + }, + { + "id": "smart_phone_flashlight", + "copy-from": "smart_phone_flashlight", + "type": "TOOL", + "name": { "str": "smartphone - Flashlight", "str_pl": "smartphones - Flashlight" }, + "delete": { "flags": [ "USE_UPS" ] } + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/generics.json b/data/mods/Dark-Skies-Above/overrides/items/generics.json new file mode 100644 index 0000000000000..1d1f3c3e745b5 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/generics.json @@ -0,0 +1,16 @@ +[ + { + "id": "brush_toilet", + "name": { "str": "toilet brush", "str_pl": "toilet brushes" }, + "copy-from": "brush_toilet", + "type": "GENERIC", + "description": "The aliens that have invaded Earth cannot be intimidated or humiliated - at least not meaningfully - so this stiff brush is only useful for scouring toilet bowls." + }, + { + "type": "GENERIC", + "id": "basketball", + "copy-from": "basketball", + "name": "basketball", + "description": "A high-quality indoor basketball. You could throw it at your enemies." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/newspaper.json b/data/mods/Dark-Skies-Above/overrides/items/newspaper.json new file mode 100644 index 0000000000000..99e9e0a635d6a --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/newspaper.json @@ -0,0 +1,74 @@ +[ + { + "type": "GENERIC", + "id": "newest_newspaper", + "category": "books", + "copy-from": "newest_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_newest_news", + "description": "A single sheet of newspaper broadsheet. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly - some things from before the Cataclysm, and some even after." + }, + { + "type": "GENERIC", + "id": "many_years_old_newspaper", + "category": "books", + "copy-from": "many_years_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_many_years_old_news", + "description": "A single sheet of newspaper broadsheet. It seems to date from several years ago, and you've NO idea how it lasted this long. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "years_old_newspaper", + "category": "books", + "copy-from": "years_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_years_old_news", + "description": "A single sheet of newspaper broadsheet. It seems to date from a few years ago--amazing it has lasted this long. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "one_year_old_newspaper", + "copy-from": "one_year_old_newspaper", + "category": "books", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_one_year_old_news", + "description": "A single sheet of newspaper broadsheet. It was printed more than a year ago. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "months_old_newspaper", + "category": "books", + "copy-from": "months_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_months_old_news", + "description": "A single sheet of newspaper broadsheet. It was printed in the months leading up to the Cataclysm. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "weeks_old_newspaper", + "category": "books", + "copy-from": "weeks_old_newspaper", + "name": { "str": "newspaper page" }, + "snippet_category": "dks_weeks_old_news", + "description": "A single sheet of newspaper broadsheet. It was printed in the weeks leading up to the Cataclysm. Most of the information on there is terribly trivial, or out of date, but one thing catches your eye briefly." + }, + { + "type": "GENERIC", + "id": "survnote", + "category": "books", + "copy-from": "survnote", + "name": { "str": "survivor's note" }, + "snippet_category": "dks_note", + "description": "A scrap of paper. Something's written on it, scrawled in bad handwriting." + }, + { + "type": "GENERIC", + "id": "flyer", + "category": "books", + "copy-from": "flyer", + "name": { "str": "flyer" }, + "snippet_category": "dks_flier", + "description": "A scrap of paper." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/ranged.json b/data/mods/Dark-Skies-Above/overrides/items/ranged.json new file mode 100644 index 0000000000000..153563f1688ae --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/ranged.json @@ -0,0 +1,18 @@ +[ + { + "id": "longbow", + "//": "Tileset whitelist for bows", + "type": "GUN", + "copy-from": "longbow", + "name": { "str": "longbow" }, + "description": "A six-foot wooden bow that takes a fair amount of strength to draw. It can be used effectively by those of somewhat above-average strength. Used mainly in medieval England in wartime, but pierces hide just as well as chainmail." + }, + { + "id": "rifle_flintlock", + "looks_like": "ar15", + "type": "GUN", + "copy-from": "rifle_flintlock", + "name": { "str": "flintlock rifle" }, + "description": "This ancient firearm lacks the fire-rate of modern weapons, but packs as much punch as the best of 'em and rewards the skilled shooter with easily-crafted ammunition." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/tools.json b/data/mods/Dark-Skies-Above/overrides/items/tools.json new file mode 100644 index 0000000000000..71861f76a60c4 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/tools.json @@ -0,0 +1,51 @@ +[ + { + "id": "carver_off", + "copy-from": "carver_off", + "type": "TOOL", + "name": { "str": "electric carver (off)", "str_pl": "electric carvers (off)" }, + "description": "An electric meat carver powered by batteries. Two serrated blades that vibrate together to slice just about anything from turkey to ham… even your enemies!" + }, + { + "id": "noise_emitter", + "copy-from": "noise_emitter", + "type": "TOOL", + "name": { "str": "noise emitter (off)", "str_pl": "noise emitters (off)" }, + "description": "This device was constructed by 'enhancing' a speaker ripped off from some electronic device with some amplifier circuits. It has now no other use beside emitting loud crackling static noise, that could distract an enemy." + }, + { + "id": "noise_emitter_on", + "copy-from": "noise_emitter_on", + "type": "TOOL", + "name": { "str": "noise emitter (on)", "str_pl": "noise emitters (on)" }, + "description": "This device has been turned on and is emitting horrible crackles, pops and other static sounds. Quick, get away from it before it draws enemies to you!" + }, + { + "id": "e_handcuffs", + "copy-from": "e_handcuffs", + "type": "TOOL", + "name": { "str": "electronic handcuffs", "str_pl": "electronic handcuffs" }, + "description": "A pair of electronic handcuffs, used by automated New Order units to detain captives. Their continuous siren clearly identifies the wearer as a person of interet and alerts nearby 'safety teams' to their presence. Wait for their arrival, don't try to escape or to remove the cuffs - they will administer an electric shock.\nHowever, since capture is out of the question, you're probably in for a painful time, unless you get creative…" + }, + { + "id": "trimmer_off", + "copy-from": "trimmer_off", + "type": "TOOL", + "name": { "str": "hedge trimmer (off)", "str_pl": "hedge trimmers (off)" }, + "description": "A cordless, double-sided, gasoline-powered hedge trimmer. A long line of sharp-edged teeth extends from the engine; turning the trimmer on will make them rapidly vibrate. The poor man's chainsaw as far as your enemies are concerned." + }, + { + "id": "trimmer_on", + "copy-from": "trimmer_on", + "type": "TOOL", + "name": { "str": "hedge trimmer (on)", "str_pl": "hedge trimmers (on)" }, + "description": "A cordless, double-sided, gasoline-powered hedge trimmer. It is currently on, ready to do some alien topiary; use this item to turn it off." + }, + { + "id": "circsaw_off", + "copy-from": "circsaw_off", + "type": "TOOL", + "name": { "str": "circular saw (off)", "str_pl": "circular saws (off)" }, + "description": "A lightweight handheld cordless circular saw. Spins a circular blade fast enough to cut wood, aliens, or in an emergency, pizza. The blade, while effective in combat, is hard to hit with due to its small size." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/vehicle.json b/data/mods/Dark-Skies-Above/overrides/items/vehicle.json new file mode 100644 index 0000000000000..c95307fd9f6b3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/vehicle.json @@ -0,0 +1,16 @@ +[ + { + "type": "GENERIC", + "id": "reinforced_solar_panel", + "copy-from": "reinforced_solar_panel", + "name": { "str": "reinforced solar panel" }, + "description": "A solar panel that has been covered with a pane of reinforced glass to protect the delicate solar cells from aliens or errant baseballs. The glass causes this panel to produce slightly less power than a normal panel. Useful for a vehicle." + }, + { + "type": "GENERIC", + "id": "reinforced_solar_panel_v2", + "copy-from": "reinforced_solar_panel_v2", + "name": { "str": "upgraded reinforced solar panel" }, + "description": "An upgraded solar panel that has been covered with a pane of reinforced glass to protect the delicate solar cells from aliens or errant baseballs. The glass causes this panel to produce slightly less power than a normal upgraded panel. Useful for a vehicle." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/items/weapons.json b/data/mods/Dark-Skies-Above/overrides/items/weapons.json new file mode 100644 index 0000000000000..34426f495152d --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/items/weapons.json @@ -0,0 +1,16 @@ +[ + { + "id": "lobotomizer", + "copy-from": "lobotomizer", + "type": "TOOL", + "name": { "str": "lobotomizer" }, + "description": "This is a hand-forged collapsible tool that has two axe heads and sharp shovel-like tip on one end. It can be used as a shovel, or you could chop an enemy up with it instead." + }, + { + "id": "spear_spike", + "copy-from": "spear_spike", + "type": "TOOL", + "name": { "str": "spike on a stick" }, + "description": "A flimsy pole made of wood with a basic metal spike tied to it. It's barely sharp, and crudely constructed, but it will keep an enemy out of arm's reach until you can find something better." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/locations/cemetery.json b/data/mods/Dark-Skies-Above/overrides/locations/cemetery.json new file mode 100644 index 0000000000000..35e88053a7208 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/locations/cemetery.json @@ -0,0 +1,93 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "cemetery_4square_11" ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + " 1=", + "]]]]]]]] 11111111 7$=", + "]]]]]]]] 1=", + " SMS ]] 1$$$$$$1$$$$ 7=", + " ] ]] 1--0---G---$ 7=", + "]]]]]]]] 1-TT_,,n,,-$ $=", + " ]] $G,,_,,,,,G$ 7=", + " ]] $G_+_,,T,,G$ $=", + " 7 ]] S-,,,,,,,,-$ $=", + " ]]]]+,,,,bbb,G$ $=", + " ]]]]+,,,,,,,,G$ 7=", + " ]] S-,,S,bbb,-$ 7=", + " 7 ]] $G,,,,,,,,G$ 1=", + " ]] $G,,_,bbb,G$ 1=", + " ]] 1-,f_,,,,,-$ 7=", + " ]] 1--GG--GG--$ 7=", + " 7 ]] 1$$$$$$$$$$$ $=", + " ]]] $=", + " ]]]] 777 777 7=", + " ]]] ] $=", + " ]]]7iSi7 777 777 1=", + "]]]] 7---7 1=", + "$$11 11711 $$177$117$77=", + "========================" + ], + "terrain": { + " ": [ "t_dirt", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass", "t_grass" ], + "$": [ "t_shrub", "t_shrub", "t_shrub", "t_underbrush", "t_underbrush", "t_tree_young" ], + "+": [ "t_door_locked", "t_door_locked", "t_door_locked", "t_door_locked", "t_door_locked", "t_door_c" ], + ",": "t_floor", + "-": "t_rock_smooth", + ".": "t_pavement", + "0": "t_window_domestic", + "1": [ "t_tree_young", "t_tree_young", "t_tree_young", "t_tree_young", "t_tree", "t_shrub" ], + "7": [ "t_tree", "t_tree", "t_tree_willow" ], + ":": "t_pavement_y", + "<": "t_stairs_up", + "=": "t_rock_wall_half", + ">": "t_stairs_down", + "G": [ "t_window_stained_green", "t_window_stained_green", "t_window_stained_red", "t_window_stained_blue" ], + "O": "t_chainfence_posts", + "]": "t_sidewalk", + "_": "t_wall", + "a": "t_wall_glass_alarm", + "d": "t_door_glass_c", + "i": "t_column", + "o": "t_fencegate_o" + }, + "furniture": { + "8": "f_shackle", + "M": "f_grave_monument", + "P": "f_sign", + "S": "f_statue", + "T": "f_table", + "^": "f_grave_stone", + "a": "f_sink", + "b": "f_bench", + "c": "f_counter", + "f": "f_rack", + "g": [ + "f_grave_head", + "f_grave_head", + "f_grave_head", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone", + "f_grave_stone_old", + "f_statue" + ], + "h": "f_grave_head", + "n": "f_slab", + "r": "f_rubble_rock", + "x": "f_grave_stone_old" + }, + "place_items": [ + { "item": "church", "x": [ 14, 18 ], "y": [ 5, 14 ], "chance": 65 }, + { "item": "church", "x": [ 11, 12 ], "y": [ 5, 6 ], "chance": 65 }, + { "item": "jackets", "x": [ 12 ], "y": [ 14 ], "chance": 50 } + ] + } + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json b/data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json new file mode 100644 index 0000000000000..82f49bd99d5b1 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/locations/overmap_special.json @@ -0,0 +1,12 @@ +[ + { + "type": "overmap_special", + "id": "Toxic Waste Dump", + "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "toxic_dump_north" } ], + "locations": [ "land" ], + "city_distance": [ 15, -1 ], + "city_sizes": [ 0, 12 ], + "occurrences": [ 0, 1 ], + "flags": [ "CLASSIC" ] + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/monsters.json b/data/mods/Dark-Skies-Above/overrides/monsters.json new file mode 100644 index 0000000000000..ea7a618811662 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/monsters.json @@ -0,0 +1,56 @@ +[ + { + "id": "mon_c4_hack", + "copy-from": "mon_c4_hack", + "type": "MONSTER", + "name": { "str": "C-4 hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have some C-4 inside." + }, + { + "id": "mon_flashbang_hack", + "copy-from": "mon_flashbang_hack", + "type": "MONSTER", + "name": { "str": "flashbang hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have a flashbang inside." + }, + { + "id": "mon_gasbomb_hack", + "copy-from": "mon_gasbomb_hack", + "type": "MONSTER", + "name": { "str": "tear gas hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have a tear gas canister inside." + }, + { + "id": "mon_grenade_hack", + "copy-from": "mon_grenade_hack", + "type": "MONSTER", + "name": { "str": "grenade hack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated kamikaze drone, this small flying robot appears to have a grenade inside." + }, + { + "id": "mon_manhack", + "copy-from": "mon_manhack", + "type": "MONSTER", + "name": { "str": "manhack" }, + "extend": { "categories": [ "ALIEN" ] }, + "description": "An automated anti-personnel drone, a small flying robot surrounded by whirring blades." + }, + { + "id": "mon_rattlesnake_giant", + "copy-from": "mon_rattlesnake_giant", + "type": "MONSTER", + "name": "giant rattlesnake", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_nakedmolerat_giant", + "copy-from": "mon_nakedmolerat_giant", + "type": "MONSTER", + "name": "gigantic naked mole-rat", + "delete": { "categories": [ "WILDLIFE" ] } + } +] From 4ad26c93142e9c0a1c3e02839485377c2f4e9e88 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Tue, 3 Mar 2020 20:51:24 -0500 Subject: [PATCH 125/219] Dark Skies 5: Override Scraps (#38550) --- .../overrides/locations/evac_center.json | 589 ++++++++++++++++++ .../Dark-Skies-Above/overrides/scenarios.json | 297 +++++++++ 2 files changed, 886 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/overrides/locations/evac_center.json create mode 100644 data/mods/Dark-Skies-Above/overrides/scenarios.json diff --git a/data/mods/Dark-Skies-Above/overrides/locations/evac_center.json b/data/mods/Dark-Skies-Above/overrides/locations/evac_center.json new file mode 100644 index 0000000000000..f070b29e88f95 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/locations/evac_center.json @@ -0,0 +1,589 @@ +[ + { + "type": "mapgen", + "method": "json", + "weight": 100, + "om_terrain": [ "shelter" ], + "object": { + "fill_ter": "t_floor", + "rows": [ + " !!!!!!!!!!!!!!!! ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " &&&&&&&&&&&&&&&& ", + " |----:-++-:----| ", + " |.............6| ", + " |..............| ", + " |..............| ", + " |..............| ", + " :..............: ", + " |..............| ", + " |......>>......| ", + " |......>>......| ", + " |..............| ", + " :..............: ", + " |..............| ", + " |..............| ", + " |||............| ", + " |*=...........6| ", + " |----:--+-:----|4 " + ], + "palettes": [ "shelter" ], + "place_nested": [ + { + "chunks": [ [ "dks_shelter_nest_base", 25 ], [ "dks_shelter_nest_used", 45 ], [ "dks_shelter_nest_vandalized", 30 ] ], + "x": 0, + "y": 0 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "weight": 100, + "om_terrain": [ "shelter_1" ], + "object": { + "fill_ter": "t_floor", + "rows": [ + " !!!!!!!!!!!!!!!! ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " &&&|---++---|&&& ", + " |........| ", + " |-:|........| ", + " |...........|:-| ", + " |.............6| ", + " |..............| ", + " :..............: ", + " |..............| ", + " |..............| ", + " |........|||...| ", + " |.-----..|*=...| ", + " :........|||...: ", + " |..........|-+-| ", + " |..........|...| ", + " |..........|>..| ", + " |..........|>..|4 ", + " |----:--+-:----| " + ], + "palettes": [ "shelter" ], + "place_nested": [ + { + "chunks": [ [ "dks_shelter_1_nest_base", 25 ], [ "dks_shelter_1_nest_used", 45 ], [ "dks_shelter_1_nest_vandalized", 30 ] ], + "x": 0, + "y": 0 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "weight": 100, + "om_terrain": [ "shelter_2" ], + "object": { + "fill_ter": "t_floor", + "rows": [ + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " `!!!!`!!!!`!!!!` ", + " &&&&&&&&&&&&&&&& ", + " |-:-++-:-| ", + " ||------|........| ", + " |*|..............| ", + " |.=..............| ", + " |--|.............--| ", + " |..................| ", + " :..................: ", + " |..................| ", + " |.......|--|.......| ", + " |........>>........| ", + " |........>>........| ", + " :.......|--|.......: ", + " |..................| ", + " |..................| ", + " |--..............--| ", + " |................|4 ", + " |--------|.......| ", + " |-:-+-:-| " + ], + "palettes": [ "shelter" ], + "place_nested": [ + { + "chunks": [ [ "dks_shelter_2_nest_base", 25 ], [ "dks_shelter_2_nest_used", 45 ], [ "dks_shelter_2_nest_vandalized", 30 ] ], + "x": 0, + "y": 0 + } + ], + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_nest_base", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " llll c 6 ", + " b b b c ", + " b b b c ", + " b b b c ", + " b b b ", + " ", + " ", + " ", + " ", + " b b b ", + " b b b c ", + " b b b c ", + " b b c ", + " c 6 ", + " " + ], + "terrain": { " ": "t_null" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 75 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_nest_used", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |||||:|++|:||||| ", + " |llll......c..6| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " :.b.b.b........: ", + " |..............| ", + " |..............| ", + " |..............| ", + " |..............| ", + " :.b.b.b........: ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |||.b.b....c...| ", + " | =........c..x| ", + " |||||:||+|:||||| " + ], + "terrain": { "x": "t_console_broken" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { + "l": { "item": "SUS_evac_shelter_locker_used", "chance": 75 }, + "c": { "item": "SUS_evac_shelter_cabinet_used", "chance": 50 }, + "b": [ { "item": "shelter_supplies", "chance": 2 }, { "item": "trash", "chance": 2 } ], + ".": [ + { "item": "shelter_supplies", "chance": 1 }, + { "item": "trash", "chance": 1 }, + { "item": "trash_forest", "chance": 1 } + ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 10 ], [ "null", 90 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_nest_vandalized", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |||||:|++|:||||| ", + " |llll......c..6| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " :.b.b.b........: ", + " |..............| ", + " |..............| ", + " |..............| ", + " |..............| ", + " :.b.b.b........: ", + " |.b.b.b....c...| ", + " |.b.b.b....c...| ", + " |||.b.b....c...| ", + " | =........c..6| ", + " |||||:||+|:||||| " + ], + "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" + }, + "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 } ], + "b": [ { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ], + ".": [ { "item": "trash", "chance": 1 }, { "item": "trash_forest", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 5 ], [ "dks_general_graffiti", 20 ], [ "null", 75 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_1_nest_base", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " bbbbb c 6 ", + " c ", + " bbbbb c ", + " cc ", + " bbbbb ", + " l ", + " l ", + " l ", + " b b b c ", + " b b b c l ", + " b b b c l ", + " l ", + " " + ], + "terrain": { " ": "t_null" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 70 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_1_nest_used", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ||||++|||| ", + " |........| ", + " ||:|........| ", + " |...........|:|| ", + " |.bbbbb.....c.6| ", + " |...........c..| ", + " :.bbbbb.....c..: ", + " |...........cc.| ", + " |.bbbbb........| ", + " |.......l|||...| ", + " |.-----.l| =...| ", + " :.......l|||...: ", + " |.b.b.b...c|-+-| ", + " |.b.b.b...c|..l| ", + " |.b.b.b...c|..l| ", + " |..........|..l| ", + " |||||:||+|:||||| " + ], + "terrain": { "x": "t_console_broken" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { + "l": { "item": "SUS_evac_shelter_locker_used", "chance": 70 }, + "c": { "item": "SUS_evac_shelter_cabinet_used", "chance": 50 }, + "b": [ { "item": "shelter_supplies", "chance": 2 }, { "item": "trash", "chance": 2 } ], + ".": [ { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 10 ], [ "null", 90 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_1_nest_vandalized", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ||||++|||| ", + " |........| ", + " ||:|........| ", + " |...........|:|| ", + " |.bbbbb.....c.6| ", + " |...........c..| ", + " :.bbbbb.....c..: ", + " |...........cc.| ", + " |.bbbbb........| ", + " |.......l|||...| ", + " |.-----.l| =...| ", + " :.......l|||...: ", + " |.b.b.b...c|-+-| ", + " |.b.b.b...c|..l| ", + " |.b.b.b...c|..l| ", + " |..........|..l| ", + " |||||:||+|:||||| " + ], + "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" + }, + "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 } ], + "b": [ { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ], + ".": [ { "item": "trash", "chance": 1 }, { "item": "trash_forest", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 5 ], [ "dks_general_graffiti", 20 ], [ "null", 75 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_2_nest_base", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " % l ", + " cccc6 l ", + " l ", + " ", + " b bbbbb b b ", + " b b b b ", + " b b llll b b ", + " b b b b ", + " b b b b ", + " b b b b ", + " b b b b ", + " b b llll b b ", + " b b b b ", + " bbbb ", + " 6 ", + " c ", + " " + ], + "terrain": { " ": "t_null" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "items": { "l": { "item": "SUS_evac_shelter_locker", "chance": 70 }, "c": { "item": "SUS_evac_shelter_cabinet", "chance": 50 } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_2_nest_used", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ||:|++|:|| ", + " |||||||||%......l| ", + " |*|cccc6........l| ", + " |.=.............l| ", + " |--|.............||| ", + " |b.....bbbbb...b..b| ", + " :b..b..........b..b: ", + " |b..b...llll...b..b| ", + " |b..b...|--|...b..b| ", + " |b..b..........b..b| ", + " |b..b..........b..b| ", + " :b..b...|--|...b..b: ", + " |b..b...llll...b..b| ", + " |b..b..........b..b| ", + " |--.....bbbb.....||| ", + " |l..............x| ", + " ||||||||||......c| ", + " ||:|+|:|| " + ], + "terrain": { "x": "t_console_broken" }, + "furniture": { "b": "f_bench", "c": "f_cupboard", "l": "f_locker", "S": "f_sink", "%": "f_trashcan" }, + "computers": { + "6": { + "name": "Evac shelter computer", + "options": [ + { "name": "Emergency Message", "action": "emerg_mess" }, + { "name": "Disable External Power", "action": "complete_disable_external_power" } + ] + } + }, + "items": { + "l": { "item": "SUS_evac_shelter_locker_used", "chance": 70 }, + "c": { "item": "SUS_evac_shelter_cabinet_used", "chance": 50 }, + "%": [ + { "item": "shelter_supplies", "chance": 15, "repeat": [ 1, 2 ] }, + { "item": "trash", "chance": 25, "repeat": [ 1, 3 ] } + ], + "b": [ { "item": "shelter_supplies", "chance": 2 }, { "item": "trash", "chance": 2 } ], + ".": [ { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 10 ], [ "null", 90 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_2_nest_vandalized", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ||:|++|:|| ", + " |||||||||%......l| ", + " |*|cccc6........l| ", + " |.=.............l| ", + " |--|.............||| ", + " |b.....bbbbb...b..b| ", + " :b..b..........b..b: ", + " |b..b...llll...b..b| ", + " |b..b...|--|...b..b| ", + " |b..b..........b..b| ", + " |b..b..........b..b| ", + " :b..b...|--|...b..b: ", + " |b..b..........b..b| ", + " |b..b..........b..b| ", + " |--.....bbbb.....||| ", + " |l..............x| ", + " ||||||||||......c| ", + " ||:|+|:|| " + ], + "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", "t_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 } ], + "b": [ { "item": "softdrugs", "chance": 2 }, { "item": "shelter_supplies", "chance": 1 }, { "item": "trash", "chance": 1 } ], + ".": [ { "item": "trash", "chance": 1 }, { "item": "trash_forest", "chance": 1 } ] + }, + "nested": { "|": { "chunks": [ [ "dks_shelter_graffiti", 5 ], [ "dks_general_graffiti", 20 ], [ "null", 75 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_shelter_graffiti", + "object": { "mapgensize": [ 1, 1 ], "place_graffiti": [ { "x": 0, "y": 0, "snippet": "dks_shelter_graffiti_snippets" } ] } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "dks_general_graffiti", + "object": { "mapgensize": [ 1, 1 ], "place_graffiti": [ { "x": 0, "y": 0, "snippet": "dks_general_graffiti_snippets" } ] } + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/scenarios.json b/data/mods/Dark-Skies-Above/overrides/scenarios.json new file mode 100644 index 0000000000000..f3df83c067b77 --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/scenarios.json @@ -0,0 +1,297 @@ +[ + { + "type": "scenario", + "ident": "evacuee", + "copy-from": "evacuee", + "name": "Evacuee", + "description": "You have survived the initial wave of panic and managed to avoid being taken to the Designated Living Zones. You begin in the (relative) safety in one of the many government evac shelters.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "missed", + "copy-from": "missed", + "name": "Missed", + "description": "Whether due to stubbornness, ignorance, or just plain bad luck, you missed the evacuation and managed to avoid being turned into one of those things outside. You are now left in a city full of the hateful revenants of your neighbors.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "largebuilding", + "copy-from": "largebuilding", + "name": "Large Building", + "description": "Whether due to stubbornness, ignorance, or just plain bad luck, you missed the evacuation and managed to avoid being turned into one of those things outside. You are now left in a city full of the hateful revenants of your neighbors.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "surrounded", + "copy-from": "surrounded", + "name": "Surrounded", + "description": "You've attracted the attention of a pack of mutants in some way, now they're all around and you'll likely have to fight thorough them if you want to escape.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "isolationist", + "copy-from": "isolationist", + "name": "Safe Place", + "description": "You've found some distant safe place that seems to have gone unnoticed by the invasion force. Looks like you're on your own…", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "infected", + "copy-from": "infected", + "name": "Infected", + "description": "In the chaos and panic of the invasion, you got a horrible wound! You didn't get proper medical care, and now it has started turning green.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "fire", + "copy-from": "fire", + "name": "Burning Building", + "description": "The building you had chosen to reside in has suddenly caught fire! You might want to leave.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "patient", + "copy-from": "patient", + "name": "Challenge - Abandoned", + "professions": [ "unemployed", "patient" ] + }, + { + "type": "scenario", + "ident": "wilderness", + "copy-from": "wilderness", + "name": "Wilderness", + "description": "You find yourself amongst trees. The screaming and the explosions are fainter this far from civilization, but you'd better know what you're doing out here.", + "blacklist_professions": true, + "professions": [ + "bionic_prepper", + "churl", + "bionic_thief", + "bionic_patient", + "broken_cyborg", + "bionic_worker", + "bionic_athlete", + "bionic_runner", + "bionic_cop", + "bionic_firefighter", + "bionic_mentat", + "bio_soldier", + "bio_sniper", + "bionic_spy", + "bio_gangster", + "faulty_bionic", + "bionic_customer", + "razorgirl", + "cyberjunkie", + "cykotic", + "bionic_student", + "bionic_installer", + "bionic_game_master", + "bio_medic", + "bionic_hitman" + ] + }, + { + "type": "scenario", + "ident": "heli_crash", + "copy-from": "heli_crash", + "name": "Helicopter Crash", + "description": "While being evacuated from a hot zone, the pilot lost control of the helicopter and crashed in the middle of nowhere. Hopefully some of the soldiers that were with you also survived the accident.", + "professions": [ "soldier", "specops", "national_guard", "politician" ] + } +] From 57716981168c80e8b6d236706e8a582ddc261aad Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Tue, 3 Mar 2020 21:09:50 -0500 Subject: [PATCH 126/219] Dark Skies 6: Snippets (#38551) --- .../Dark-Skies-Above/snippets/fliers.json | 299 +++++++++++ .../Dark-Skies-Above/snippets/graffiti.json | 117 +++++ .../Dark-Skies-Above/snippets/newspaper.json | 178 +++++++ .../mods/Dark-Skies-Above/snippets/radio.json | 15 + .../Dark-Skies-Above/snippets/survnotes.json | 495 ++++++++++++++++++ 5 files changed, 1104 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/snippets/fliers.json create mode 100644 data/mods/Dark-Skies-Above/snippets/graffiti.json create mode 100644 data/mods/Dark-Skies-Above/snippets/newspaper.json create mode 100644 data/mods/Dark-Skies-Above/snippets/radio.json create mode 100644 data/mods/Dark-Skies-Above/snippets/survnotes.json diff --git a/data/mods/Dark-Skies-Above/snippets/fliers.json b/data/mods/Dark-Skies-Above/snippets/fliers.json new file mode 100644 index 0000000000000..1a4ad838bc332 --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/fliers.json @@ -0,0 +1,299 @@ +[ + { + "type": "snippet", + "category": "dks_flier", + "text": [ + { + "id": "dks_flier_1", + "text": "This is an advertisement for Aunt Janice's Pickled Meat. \"When times get tough, the tough get pickling. Aunt Janice's Pickled Meat: more than 30% real beef!\"" + }, + { "id": "dks_flier_2", "text": "This is an advertisement for a quality-of-life medicine." }, + { "id": "dks_flier_3", "text": "This is an advertisement promoting enlisting in the US armed forces." }, + { + "id": "dks_flier_4", + "text": "This is a somewhat weather-worn advertisement for the 'new' FEMA evacuation shelters. Beneath the colorful photo it reads, \"Familiarize yourself with your nearest emergency shelter. It could save your life.\"" + }, + { + "id": "dks_flier_5", + "text": "This is an advertisement for a FEMA evacuation shelter. Beneath a picture of a shelter it reads, \"Contact your local FEMA office to arrange a tour of your nearest evacuation shelter. Be prepared!\"" + }, + { + "id": "dks_flier_6", + "text": "This is an advertisement for a pre-manufactured emergency supply kit. It is made of a very flashy tactical fabric and looks very impractical based on your experience. \"Be ready for anything with the Tactica Supreme GO-30 kit.\"00" + }, + { + "id": "dks_flier_7", + "text": "This is an ad for a complicated survival knife with an enormous serrated back edge and far too many tools included in the handle. \"Come down to the Knife Shack at Cumberton Mall! We've got it all.\"" + }, + { + "id": "dks_flier_8", + "text": "This is an advertisement for a local church. The picture looks surprisingly mundane, but the text is not: \"Revelations services offered round the clock. The end times are here, make your peace.\"" + }, + { + "id": "dks_flier_9", + "text": "This is an advertisement for a local church. It looks like it was put together at the last minute. \"Visit St Mary's on the River while it's not too late. Repent, while you still can!\"" + }, + { + "id": "dks_flier_10", + "text": "This is a hand-drawn flier that has been photocopied for wide distribution. It reads, in what looks like sharpie-bolded letters, \"THEY DON'T WANT YOU TO KNOW. They KNEW this would happen. They were watching everything. They struck a deal even before they landed.\" There used to be tear-away phone numbers at the bottom, but they're all gone now." + }, + { + "id": "dks_flier_11", + "text": "This is a government-issued, air-dropped alert. \"EVACUTE IMMEDIATELY. Proceed to your closest FEMA operated community shelter to await police and military escort to safety.\"" + }, + { + "id": "dks_flier_12", + "text": "This is a government-issued, air-dropped alert. \"EVACUATE IMMEDIATELY. Police and military forces have been dispatched to your area and will help escort you to safety.\"" + }, + { + "id": "dks_flier_13", + "text": "This is a government-issued, air-dropped alert. \"EVACUATION ALERT. Please make your way to the nearest FEMA evacuation shelter. Seek protection from police and military forces if traveling in groups.\"" + }, + { + "id": "dks_flier_14", + "text": "This is a government-issued, air-dropped alert. \"EVACUATION ALERT. Please make your way to the nearest FEMA evacuation shelter. Travel in groups and avoid crowds. Avoid hostile forces at all costs.\"" + }, + { + "id": "dks_flier_15", + "text": "This is a glossy, high quality flier. \"What they don't want you to know! Reading this may save your life.\" Inside is a series of warnings recommending people avoid the evacuation shelters, state roads, and worse, contact with any police or military forces as they might be rogue. A picture of uniformed humans apparently in league with the invaders is included, as well as several shots of civilians being lead off a FEMA bus and towards an alien spaceship." + }, + { + "id": "dks_flier_16", + "text": "This is a glossy advertisement from FEMA asking that people donate their canned goods in return for tax writeoffs. From the date on the flier, it doesn't look like the initative ever had time to get off the ground." + }, + { + "id": "dks_flier_17", + "text": "This is a grocery store coupon flier, dated three days before the evacuation orders went out. \"At Marigold Market, we still have canned food and bottled water! Come on in and stock up!\" The front image shows a grocery store, the entrance flanked by a pair of smiling guards armed with assault rifles." + }, + { + "id": "dks_flier_18", + "text": "This is an advertisement for a local electronics store, dated a few weeks before the evacuation order. \"Sale on smartphones and refurbished laptops at DigiMart, three days only!\"" + }, + { + "id": "dks_flier_19", + "text": "This very recent looking air-dropped alert. \"THE WAR IS OVER. Do not continue to fight. Fugitives will be charged with malcompliant destabilizaion if they do not surrender to their nearest safety office at once. Join our New Order. Do not live in squalor. Witness what we can do *together*.\" Pictured is one of the Designated Living Zones, a city and its surrounding areas set aside specifically for humans. Underneath is listed some of the many qualities of the DLZs: safety, cleanliness, opprotunity, and so on." + }, + { + "id": "dks_flier_20", + "text": "This very recent looking air-dropped alert. \"THE WAR IS OVER. Do not continue to fight. Surrender to your nearest surveillance drone for immediate evacuation to a designated civilian zone. Join our New Order. Witness what we can do *together*.\" Pictured is the president, along with several other 'smiling' world leaders, standing next to multiple cloaked creatures." + }, + { + "id": "dks_flier_21", + "text": "This very recent looking air-dropped alert. \"THE WAR IS OVER. Resistance will be met with lethal deterrence. Do not throw away your potential. Join our New Order. Witness what we can do *together*.\" Pictured is a smiling family of humans standing in front of an alien soldier." + }, + { + "id": "dks_flier_22", + "text": "This is an advertisement for a local funk-polka band, the \"Chilly Winters\". Apparently they were playing in the Wonky Donkey Pub." + }, + { + "id": "dks_flier_23", + "text": "This is a flier with the tour appearance dates of a small, niche-successful drum-and-bass/yodelling fusion band, the \"Ol' Yellers\". The dates continue well past the end of the world; most likely, the tour was cut short." + }, + { + "id": "dks_flier_24", + "text": "This is an advertisement for a death metal band, \"Roxanne and the Soul-Crushing Ennui\", known for mixing their ear-blasting riffs with chipper interludes of classic fifties doo-wop. The art depicts a zombified version of a Betty Crocker-esque housewife, slamming on a spike-encrusted electric guitar." + }, + { + "id": "dks_flier_25", + "text": "This is an advertisement for a local gun shop. In huge red letters, it reads: \"This is it. Arm yourselves and protect your freedom. Come on down while supplies last.\"" + }, + { "id": "dks_flier_26", "text": "This is a flier for pet food, with a cute animal performing a silly trick." }, + { + "id": "dks_flier_27", + "text": "This is an advertisement for a portable generator, the kind that was becoming popular in the face of increasing natural disasters before the end of the world as you knew it." + }, + { + "id": "dks_flier_28", + "text": "This is very recent looking air-dropped alert. \"HERE FOR YOU\" is written in somewhat imposing text at the bottom of a depiction of several smiling humans wearing Occupation uniforms." + }, + { + "id": "dks_flier_29", + "text": "This is very recent looking air-dropped alert. \"HERE FOR YOU\" is written in somewhat imposing text at the bottom of a depiction of several smiling humans wearing Occupation uniforms. Someone has scrawled \"TRAITORS\" in marker across the front." + }, + { + "id": "dks_flier_30", + "text": "This is very recent looking air-dropped alert. \"HERE FOR YOU\" is written in somewhat imposing text at the bottom of a depiction of several smiling humans wearing Occupation uniforms. Someone has scrawled \"FAIR WEATHER SOLDIERS\" across the front." + }, + { + "id": "dks_flier_31", + "text": "This is a public notice from a local police department encouraging citizens to pack their supplies before their designated evacuation date to ensure faster transit." + }, + { + "id": "dks_flier_32", + "text": "This is a public alert from the Centers for Disease Control. Its message, repeated in several languages, reads: PUBLIC HEALTH ALERT: Due to recent events, the CDC is issuing a warning to avoid public areas and spaces. An unknown biological contaminant is suspected to be affecting citizens. The CDC would like to remind the public to cover your nose and mouth when sneezing, wash your hands frequently, and receive an up-to-date flu shot if possible. Boiling water is recommended until further notice." + }, + { + "id": "dks_flier_33", + "text": "This is a public alert from the Federal Emergency Management Agency. Its message, repeated in several languages, reads: STAY IN YOUR HOMES! All residents of the New England Disaster Area are advised to shelter in place wherever possible. The United States Armed Forces are working to secure the area. If there is a nearby evacuation shelter you can get to safely, you are recommended to do so. Otherwise, stay in your homes until authorized personnel evacuate you to a secured facility. Thank you for your compliance." + }, + { + "id": "dks_flier_34", + "text": "This is a public alert from the Federal Emergency Management Agency. Its message, repeated in several languages, consists of a list of towns serving as major evacuation points from the hot zones. Someone has scribbled off most of the town names, and scrawled \"OVERRUN\" next to each one." + }, + { + "id": "dks_flier_35", + "text": "This is a public warning from an unnamed source. Its rambling message, poorly-photocopied onto both sides of the page, reads: Don't believe the lies! The Army cannot stop them, FEMA is in league with them. They want us alive but have no quams about killing anyone who RESISTS. Secure supplies and escape while there is still time." + }, + { + "id": "dks_flier_36", + "text": "This is a public message from an unnamed source. Its message, photocopied from a scrawled handwritten copy, reads: REPENT YOUR SINS O BABYLON FOR THE TIME OF HIS JUDGEMENT IS NIGH! LOOK UPON YOUR DESTRUCTION AND KNOW THAT IT IS JUST! YOU WILL BE DIVIDED FATHER AGAINST SON AND MOTHER AGAINST CHILD UNTO THE VERY LAST SINNER!" + }, + { + "id": "dks_flier_37", + "text": "This is a public warning from the Federal Government. Its brief message, repeated in several languages, reads: The President of the United States has declared unilateral martial law to be in effect in response to the ongoing national crisis. Continue to shelter in place until evacuated to an appropriate emergency management camp by authorized military personnel. A 24-hour curfew has been established. This curfew will remain in effect until further notice. Stay indoors to avoid friendly fire." + }, + { + "id": "dks_flier_38", + "text": "This is an advertisement for Galaxybux coffee. The smiling, feminine alien mascot seems a little inappropriate now." + }, + { + "id": "dks_flier_39", + "text": "This is a soda advertisement. On the front is a picture of a happy couple on a beach watching the sun set. Between them are bottles of soda. The poster reads, \"Cascade Cola, for those special moments\" in bold white letters." + }, + { + "id": "dks_flier_40", + "text": "This is a flier for a fast food chain. In it, a man is placing an order with an attractive woman wearing a bright green shirt in the window with two happy children sitting in the back seat. The flier reads \"Burgers, fries, and a Smile.\" Down in one corner is a company logo." + }, + { + "id": "dks_flier_41", + "text": "This is an advertisement for soda. It shows a dark brown can of soda on a black background. The label reads \"Spin\"." + }, + { + "id": "dks_flier_42", + "text": "This is a flyer for a local pizza chain. On it is a picture of a cartoon Italian holding a pizza, with the words \"It's a goooood pizza\" written above his head." + }, + { + "id": "dks_flier_43", + "text": "This is a poster advertising contact lenses. On it is a picture of a blood shot eye with a rather long block of information beneath it making some fairly exaggerated claims about the product." + }, + { + "id": "dks_flier_44", + "text": "This is a public alert from the Federal Emergency Management Agency. Its message, repeated in several languages, consists of a list of towns serving as major evacuation points from the hot zones." + }, + { + "id": "dks_flier_45", + "text": "This is a large movie poster for \"Action Packstone 6, Revenge of the Catgirls\". It shows a fit man in a leather jacket with a revolver and a claymore walking towards the viewer. At his side is his trusty cyberdog companion and in the background is an explosion." + }, + { + "id": "dks_flier_46", + "text": "This is an illustrated poster for a brand of solar car. The vehicle is driving through a lush country side as small animals look on. The slogan \"Improving the world, one tank at a time.\" is written across the top in small letters." + }, + { + "id": "dks_flier_47", + "text": "This is a soda advertisement. On the front is a picture of a happy couple on a beach watching the sun set. Between them are bottles of soda. The poster reads, \"Cascade Cola, for those special moments\" in bold white letters. Someone has colored in the sun with a black marker. The words \"oh Discordia\" are scrawled across the top." + }, + { + "id": "dks_flier_48", + "text": "This is a flier for a fast food chain. In it, a man is placing an order with an attractive woman wearing a bright green shirt in the window with two happy children in the back seat. The flier reads \"Burgers, fries, and a Smile.\" down in one corner is a company logo. Someone has gone to town on this one with a permanent marker. It is now covered in rude images and racial epithets." + }, + { + "id": "dks_flier_49", + "text": "This is a flier for a local pizza chain. On it is a picture of a cartoon Italian holding a pizza, with the words \"It's a goooood pizza\" written above his head. Someone has drawn an exaggerated mustache on the cartoon Italian, along with a pair of crude, oversized breasts." + }, + { + "id": "dks_flier_50", + "text": "This is a poster advertising contact lenses. On it is a picture of a blood shot eye. Someone has defaced this one. The informative part has been torn off, and written in jagged letters across the top in red crayon are the words \"ALL HAIL THE CRIMSON KING!\"." + }, + { + "id": "dks_flier_51", + "text": "This is an illustrated poster for a brand of solar car. The vehicle is driving through a lush country side as small animals look on. The slogan \"Improving the world, one tank at a time.\" is written across the top. Someone used a blue pen to write \"who gives a shit\" across the slogan and put X's over the eyes of all the animals." + }, + { + "id": "dks_flier_52", + "text": "This is a poster advertising a underground bunker. The poster shows a nuclear bomb wiping out a city while a family huddles safely underground. There a slogan \"Concerned about enemy attack? Want to protect your family? Join the VAULT program today.\" which is written in the middle. However, there seems to be no information about *how* one might do so." + }, + { + "id": "dks_flier_53", + "text": "This is a flier for Red Ryder BBGuns. On it a child is pulling a shining red wagon with a cooked pheasant on it and a wooden rifle over one shoulder. The child has a dog trailing beside him and a satisfied look on his face. The caption reads \"When you chose Red Ryder, you invested in the American Dream. You invested in our Independence.\"" + }, + { + "id": "dks_flier_54", + "text": "This is an old flier for a movie from the 30s. A tan man with slick black hair and muscles bulging through his offwhite suit is clasping a woman to his hip with one hand, and the woman is wearing a black leather dress. With her hips splayed, she is holding a pistol in one hand and starring directly out of the advert. The caption reads \"Witness the rebirth of New Noir with 'Jersey Shore Blues'. Starring Jenifer Languiz as 'Snookie'!\"" + }, + { + "id": "dks_flier_55", + "text": "\"Joe's Diner; 1/2 pound of meat, 3 toppings, 'your choice', all with a side of freedom fries and a BIG Gulp size pop.\"" + }, + { + "id": "dks_flier_56", + "text": "This is an advertisement for the popular fast food chain, Foodplace. On an unadorned blue-and-magenta background it shows clear, unmistakable depictions of their products and plainly stated prices. The foodburger looks particularly nice." + }, + { + "id": "dks_flier_57", + "text": "This is a leaflet about autoclaving procedure. One sentence catches your attention \"/!\\Always place your tools into an autoclave pouch before autoclaving./!\\\"" + }, + { + "id": "dks_flier_58", + "text": "This is a propaganda poster from only a few weeks before the evacuation orders. A parent dressed in military fatigues hugs their partner goodbye as their smiling children look on. \"Enlist today. Take you freedom in your own hands.\"" + }, + { + "id": "dks_flier_59", + "text": "This is a propaganda poster from only a few weeks before the evacuation orders. A handsome looking person dressed in military fatigues exercises along with several other people. \"Enlist today.\"" + }, + { + "id": "dks_flier_60", + "text": "This is a propaganda poster from only a few weeks before the evacuation orders. Someone in military fatigues is helping someonestand up. \"Enlist today and become a community leader.\"" + }, + { + "id": "dks_flier_61", + "text": "This advertisement reads \"Sick of FUEL PRICES? Bus stop too far? Get your driving fix from THE SUN! Solar powered electric cars by Edison: Silent, Cheap, Powerful.\"" + }, + { + "id": "dks_flier_62", + "text": "This is an advertisement that looks like it came right out of Silicon Valley. 'Space age aesthetic' is written in cursive scipt underneath a picture of some sleek but terribly useless home gadget." + }, + { + "id": "dks_flier_63", + "text": "PICKLED MEAT IN A JAR! Just like your grandma used to make! It will last for months or longer, and when you've eaten it, you can refill and seal the jar! Stock your emergency supply TODAY!" + }, + { + "id": "dks_flier_64", + "text": "BAGS, BAGS, BAGS! They're very useful things! If we didn't have BAGS, what-would-we-use… to PUT a lot of things in!? (Ad by the \"Play SchoolClothing Co.\")" + }, + { + "id": "dks_flier_65", + "text": "GLAMOPOLITAN! We've got ALL the latest tips! Whether you want to know what the elite are eating, wearing or discussing, Glamopolitan is YOUR magazine! So pick up a copy today and \"Sizzle Like A Star\"!" + }, + { + "id": "dks_flier_66", + "text": "POPULAR MECHANICS: People say mechanics is boring? We say, Prove them Wrong! We've got all the articles that make it interesting to talk about, so you can \"Make Mechanics Popular\"!" + }, + { + "id": "dks_flier_67", + "text": "BIRDHOUSE MONTHLY… Which wood would a woodpecker prefer? This month we discuss hardwood versus soft woods, whether to lacquer, oil or paint, and which type of nails you should use!" + }, + { + "id": "dks_flier_68", + "text": "FEELING BLUE? Try \"Greens\" for Magazines! Your local Supermarket! Nothing cheers you up like a good magazine… Unless it's JUNK FOOD! Or why not buy an MP3 PLAYER or a GAME CONSOLE? Chase those Blues away at GREENS Supermarket" + }, + { + "id": "dks_flier_69", + "text": "…What do you know about surviving in the Wilderness? If you can't make a snare you don't know TRAP! Hunt down a copy of TRAPPERS' LIFE and learn about wildlife!… And how to kill it. Classic BEAR TRAP returns in this issue!" + }, + { + "id": "dks_flier_70", + "text": "HUNTING GOODS! Food prices getting you down? Why not get a crossbow or compound bow and Hunt Your Own!? Our arrows and bolts are completely reusable, so why not hunt animals like Mother Nature intended?" + }, + { + "id": "dks_flier_71", + "text": "FEELING BLUE? Try \"Greens\" for Magazines! Your local Supermarket! Nothing cheers you up like a good magazine… Unless it's JUNK FOOD! Or why not buy an MP3 PLAYER or a GAME CONSOLE? Chase those blues away at GREENS Supermarket" + }, + { + "id": "dks_flier_72", + "text": "…What do you know about surviving in the Wilderness? If you can't make a snare you don't know TRAP! Hunt down a copy of TRAPPERS' LIFE and learn about wildlife!… And how to kill it. This week, a CROSSBOW TRAP!" + }, + { + "id": "dks_flier_73", + "text": "BIRDHOUSE MONTHLY… This month we look at some Dutch innovations in birdhouse design, and compare with the often confused Scandinavian Birdhouse design. Our article on sheet metal birdhouses will have you riveted!" + }, + { + "id": "dks_flier_74", + "text": "CRAFTY CRAFTERS QUARTERLY: Macaroni isn't just for eating anymore! Learn how to make jewelry and art from it as well! We also discuss the correct way to use superglue without gluing your hands together!" + }, + { + "id": "dks_flier_75", + "text": "\"The Nintendy Flip! Play your games anywhere!\" Following is an illustration of several people playing their games in unlikely places, using the titular gaming device." + } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/graffiti.json b/data/mods/Dark-Skies-Above/snippets/graffiti.json new file mode 100644 index 0000000000000..33b24ad7965b1 --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/graffiti.json @@ -0,0 +1,117 @@ +[ + { + "type": "snippet", + "category": "dks_general_graffiti_snippets", + "//": "This graffiti is generally assumed to come from before the Cataclysm", + "text": [ + { "id": "dks_general_graffiti_1", "text": " is the biggest slut in , and I'm damn proud of it!" }, + { "id": "dks_general_graffiti_2", "text": "There is a beautifully drawn graffiti tag on the wall here." }, + { "id": "dks_general_graffiti_3", "text": " is a heteronormative bully!" }, + { "id": "dks_general_graffiti_4", "text": " + " }, + { "id": "dks_general_graffiti_5", "text": "Hell in " }, + { "id": "dks_general_graffiti_6", "text": "were all gonna die" }, + { "id": "dks_general_graffiti_7", "text": "MOM" }, + { "id": "dks_general_graffiti_8", "text": "FUCK YOU" }, + { "id": "dks_general_graffiti_9", "text": "This is a cartoon rendition of an alien." }, + { "id": "dks_general_graffiti_10", "text": "This is a crudely spraypainted tag adorned with skulls." }, + { + "id": "dks_general_graffiti_11", + "text": "I have a secure and loving relationship with your mom and you're going to need to come to terms with that.\n\nDo you want to talk about it? You know where to find me. Love you sweety." + }, + { "id": "dks_general_graffiti_12", "text": " you fuckin gave me ADES you SHIT." }, + { "id": "dks_general_graffiti_13", "text": "I <3 ." }, + { "id": "dks_general_graffiti_14", "text": " fucked ." }, + { + "id": "dks_general_graffiti_15", + "text": "This is a spraypainted drawing of an angel with wings made of vines." + }, + { "id": "dks_general_graffiti_16", "text": "Mr. is a vampire!" }, + { "id": "dks_general_graffiti_17", "text": "Their hiding the truth" }, + { "id": "dks_general_graffiti_18", "text": "FOLLOW THE CHEMTRAILS" }, + { + "id": "dks_general_graffiti_19", + "text": "This is a curious drawing of a roll of toilet paper dissolving into a rainbow." + }, + { "id": "dks_general_graffiti_20", "text": "This is a cartoon rendition of a zombie." }, + { "id": "dks_general_graffiti_21", "text": "" }, + { "id": "dks_general_graffiti_22", "text": "don't drink the water" }, + { + "id": "dks_general_graffiti_23", + "text": "And they walked upon His Earth, and there was a RECKONING, and only the worthy survived" + }, + { "id": "dks_general_graffiti_24", "text": "This is a drawing of a zombie with a bullethole in its head." }, + { "id": "dks_general_graffiti_25", "text": "This is a surprisingly artistic drawing of a penis." }, + { "id": "dks_general_graffiti_26", "text": "This is a simple spraypainted graphic of a forest made of bones." }, + { "id": "dks_general_graffiti_27", "text": "This is a drawing of an alien with a bullethole in its head." }, + { "id": "dks_general_graffiti_28", "text": "we can never go back" }, + { "id": "dks_general_graffiti_29", "text": "dont by meth from " }, + { "id": "dks_general_graffiti_30", "text": " you owe me fifty bucks" }, + { "id": "dks_general_graffiti_31", "text": "Im gonna kill u " }, + { "id": "dks_general_graffiti_32", "text": "eyes to the skies" }, + { + "id": "dks_general_graffiti_33", + "text": "This is a spraypainting of an anatomically unlikely woman wearing very little." + } + ] + }, + { + "type": "snippet", + "category": "dks_shelter_graffiti_snippets", + "text": [ + { "id": "dks_shelter_graffiti_1", "text": "BIGGEST WASTE OF TAX MONEY FUCK YOU GOVERMINT" }, + { "id": "dks_shelter_graffiti_2", "text": "Dont eat the proten bars" }, + { "id": "dks_shelter_graffiti_3", "text": "FEMA: FUCKIN EAT MY ASSHOLE" }, + { + "id": "dks_shelter_graffiti_4", + "text": "This is a simple drawing of a skinny figure wearing an emergency evac jacket and a gas mask. Scrawled beneath, it says \"thanks for the outfit\"." + }, + { "id": "dks_shelter_graffiti_5", "text": "Abandon hope, all ye who enter here." }, + { "id": "dks_shelter_graffiti_6", "text": "NO ONE IS COMING FOR US" }, + { "id": "dks_shelter_graffiti_7", "text": "THAT'S NO RESCUE BUS" }, + { "id": "dks_shelter_graffiti_8", "text": "THEY LET US DOWN" }, + { "id": "dks_shelter_graffiti_9", "text": "Don't dead open inside" }, + { "id": "dks_shelter_graffiti_10", "text": "SANCTUARY" }, + { "id": "dks_shelter_graffiti_11", "text": "'s cosplay supply all welcome" }, + { "id": "dks_shelter_graffiti_12", "text": "LAST STOP" }, + { "id": "dks_shelter_graffiti_13", "text": "They aren't coming to help, they're coming to clean up" }, + { + "id": "dks_shelter_graffiti_14", + "text": "This is a far-too-detailed drawing the inside of an alien craft, in all its biomechanical horror." + }, + { + "id": "dks_shelter_graffiti_15", + "text": "This is a quick rendition in permanent marker of an alien craft with war machines spilling out of it. Underneath, it reads \"What did we do to deserve this?\"" + }, + { "id": "dks_shelter_graffiti_16", "text": "RIP humanity" }, + { "id": "dks_shelter_graffiti_17", "text": "NEW GODS" }, + { "id": "dks_shelter_graffiti_18", "text": "WE'RE ALL FINE HERE HOW R U" }, + { + "id": "dks_shelter_graffiti_19", + "text": " I couldn't wait any longer, went to cabin. Meet me there. Love ." + }, + { "id": "dks_shelter_graffiti_20", "text": " I am still looking for you." }, + { "id": "dks_shelter_graffiti_21", "text": " was here and still alive" }, + { "id": "dks_shelter_graffiti_22", "text": "Blue 52" }, + { "id": "dks_shelter_graffiti_23", "text": " I no I said Id wait for u but I gotta run, find me" }, + { + "id": "dks_shelter_graffiti_24", + "text": "In memoriam:\n\n\n\n\n\nI would not be alive without all of you. I will not forget." + }, + { + "id": "dks_shelter_graffiti_25", + "text": "\"keep moving their looking for us\" is written here in a hasty scrawl." + }, + { "id": "dks_shelter_graffiti_26", "text": "EARTH WASN'T THE FIRST" }, + { "id": "dks_shelter_graffiti_27", "text": "stay out of " }, + { "id": "dks_shelter_graffiti_28", "text": " has fallen" }, + { "id": "dks_shelter_graffiti_29", "text": "NO ONE LEFT HERE MOVE ON" }, + { "id": "dks_shelter_graffiti_30", "text": "deth trap" }, + { "id": "dks_shelter_graffiti_31", "text": "seven hour war" }, + { "id": "dks_shelter_graffiti_32", "text": "ARMY WORKING WITH THEM" }, + { "id": "dks_shelter_graffiti_33", "text": "FUCK CHINA" }, + { "id": "dks_shelter_graffiti_34", "text": "gray dawn" }, + { "id": "dks_shelter_graffiti_35", "text": "Remember " }, + { "id": "dks_shelter_graffiti_36", "text": "they can't read english communicate below:" } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/newspaper.json b/data/mods/Dark-Skies-Above/snippets/newspaper.json new file mode 100644 index 0000000000000..83e266e36345a --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/newspaper.json @@ -0,0 +1,178 @@ +[ + { + "type": "snippet", + "category": "dks_many_years_old_news", + "text": [ + { + "id": "dks_many_years_old_news_1", + "text": "DISASTER IN THE SARITANIA MINES! A copper mine west of Saritania, a small town in Vermont, collapsed Wednesday, killing an estimated thirty miners in the disaster. Local officials could not be reached for comment, despite the mine being Saritania's primary industry. An anonymous but credible source did contact our offices, claiming that the Saritania Mine was in fact an underground military facility, and that the disaster was a cover-up for a failed experiment. These allegations were not addressed by officials." + }, + { + "id": "dks_many_years_old_news_2", + "text": "ALIENS AMONG US! Janine Galfrizowich, of Martha's Vineyard, wrote in to our Paranormal Investigation Staff with this cryptic gem. \"They're always watching, always watching from the shadows. Stealing my avocados and watching! They took my neighbor and made him into one of them!\" Our journalists are trying to track Mrs Galfrizowich down, but it is clear enough that this ties into the well known Avocado Conspiracy (see issue 24, volume 7)." + }, + { + "id": "dks_many_years_old_news_3", + "text": "EDITORIAL: ALIENS ARE BACK IN A BIG WAY. We've all seen that autopsy video that's making the rounds. I'm not going to say if I believe it's real or not (I will say \"I want to believe\" though!) but regardless of the truth, one thing is clear: the public mind is completely addicted to aliens in the biggest way I've seen since ET was popular. What's brought little green men back into the public eye? It's anyone's guess, but personally I think it's a concerning sign that we're culturally digging in to a second Cold War." + } + ] + }, + { + "type": "snippet", + "category": "dks_years_old_news", + "text": [ + { + "id": "dks_years_old_news_1", + "text": "DRIVING ON A WING AND A PRAYER: A New England man has proven it is possible to create a new car from scrap parts using almost nothing but duct tape. When asked why he had done it, his answer was \"Well, I didn't have a welder.\"" + }, + { + "id": "dks_years_old_news_2", + "text": "STUDENT MISSING: A high school student vanished yesterday evening in the forest near Wayland. The 17-year-old international student from China (who adopted the anglicized nickname \"Brett\" due to his classmates' difficulty pronouncing his given name) was last seen with his friends in the camp. \"Brett said that he was gonna get some firewood but he never came back,\" said his classmate, Jianxiang Wang. The search is underway." + }, + { + "id": "dks_years_old_news_3", + "text": "STILL SEARCHING: The search for Brett, the high school student who went missing three days ago, is still ongoing. \"He could have played in the soccer game against Weston High School yesterday,\" Brett's sorrowful teammate said, \"[..] we've never stopped praying.\" Despite the best efforts of the County Search & Rescue, Brett had still not been located at the time of this report." + }, + { + "id": "dks_years_old_news_4", + "text": "POPULAR 'ALIEN AUTOPSY' DEBUNKED. A widely circulated video, making the rounds everywhere from FriendFace to television news, has been debunked as a fake. This extremely realistic and graphic alien autopsy shows an insect-like creature being dismantled by Japanese researchers, who comment on its anatomy in Japanese throughout the video. Yesterday, on the popular social media website Eddit, a 'making of' video was posted, clearly exposing the work as the final film project of a small group of students at UCLA." + }, + { + "id": "dks_years_old_news_5", + "text": "BIG BREAK. At the pressure of tech moguls like Elton Moosek, a new bipartisan bill has set aside a big boost for long underfunded NASA. \"It's time we started looking at opportunities beyond our own atmosphere,\" says a spokesperson for Edison Automotives. This space fad is no doubt tied to a new collaborative in the tech industry, secretively nicknamed \"Project Bluebox.\"" + } + ] + }, + { + "type": "snippet", + "category": "dks_one_year_old_news", + "text": [ + { + "id": "dks_one_year_old_news_1", + "text": "READY FOR THE WORST. In response to growing public concern about a potential attack from China, the president announced a major funding initiative for the construction of FEMA-supported community shelters near major population sites. \"These shelters will provide a much-needed near safety points in an emergency,\" said a spokesperson for FEMA. \"They're to be equipped with a secure basement that can resist heavy bombardment, able to fit hundreds of people, and equipped to survive gas and biological attacks. They have self-contained water and power, protective gear, and communications equipment. In short, they are public survivalist bunkers. We've very excited about this initiative.\"" + }, + { + "id": "dks_one_year_old_news_2", + "text": "TURNING UP THE HEAT: New statistics suggest the average temperature in New England has climbed several degrees in the last two years. \"No doubt crops are going to start suffering unless something is done,\" said an expert." + }, + { + "id": "dks_one_year_old_news_3", + "text": "EDITORIAL: SOCIAL MEDIA HAS GOTTEN OUT OF HAND, AND GONE OUT OF COUNTRY. We can no longer trust what we read, and it's all because of social media. Although our newspaper takes painstaking efforts to source our data, our colleagues have forgotten what it means to be a journalist, and widespread falsehoods are repeated even by reputable publications as fact. What is the ultimate source of all this misinformation? It's anyone's guess, but I think we need look no further than our largest international trade partner and rival, China." + }, + { + "id": "dks_one_year_old_news_5", + "text": "EDITORIAL: THIS IS WHERE 'ME TOO' ENDS UP. It's been a while now since 'Me Too' swept the message boards of our nation, but its repercussions are felt every day. Disconnected from our identities and our heritage by the overwhelming urge to suppress the white male and hide his every achievement, American citizens are turning to violence to find a place of belonging. Mark my words: within a year, there will be a reckoning, and it won't be caused by the trade war, it will be from the broken heart of America." + }, + { + "id": "dks_one_year_old_news_6", + "text": "EDITORIAL: THE RISE OF THE RIGHT HAS BROUGHT US HERE. As the wounded white male ego becomes more and more of a self-stereotype, we see the cost of allowing right-wing sentiment echoed all around us. A stricter stance on gun control, workplace discrimination, and domestic terrorist groups must be taken if our most marginalized populations are to survive the next year. Everyone is affected by these sorts of issues." + }, + { + "id": "dks_one_year_old_news_7", + "text": "NEW LAB OPENS: The Messier Research Facility has been officially opened by NASA right here in New England. According to Deputy Administer Sophie Perla, \"This state of the art facility will catapult us back onto the world stage. With the opening of the Messier research complex, New England has a starry future ahead of it.\"" + }, + { + "id": "dks_one_year_old_news_8", + "text": "'SPACE AGE AESTHETIC'. After much buzz in the tech world about \"Project Bluebox\", a new line of what is being termed as 'space-age aesthetic' products have been demoed to a select group of potential investors, particularly NASA administrators. \"The public can look forward to new cutting edge devices hitting the shelves within a year. Prepare to have your horizons broadened.\" a spokesperson said mysteriously this Monday, standing in front of a display case with heavily tinted glass." + }, + { + "id": "dks_one_year_old_news_9", + "text": "WHEN I DID MY TIME. We spoke to Dan Huang, the Chinese-American author of the New York Times bestselling exposé \"When I Did my Time\", the story of his three years living with his extended family in China, immersed in what he describes as \"The ever-escalating anti-American propaganda of the East.\"\n\n\"It's a real threat,\" said Huang. \"They are being taught to hate our freedom, and our technology. Mark my words: there is going to be a reckoning, and we need to be ready.\"" + }, + { + "id": "dks_one_year_old_news_10", + "text": "IT CAME FROM BEYOND. [Pictured: Margaret Antwerp holds the fragment of alien satellite that landed in her rose garden.] It was a normal day for Margaret. Normal, that is, until a thundering crash in her front yard nearly knocked her house over. \"This damn thing fell right out of space, I tell you,\" she told investigative journalists from our Paranormal Investigations department. \"It was glowing red hot, and it had burnt my prize-winning roses to a crisp.\" The US government and air force have declined to comment, as usual." + } + ] + }, + { + "type": "snippet", + "category": "dks_months_old_news", + "text": [ + { + "id": "dks_months_old_news_1", + "text": "SUPPORT THE COUNTRIES THAT SUPPORT YOURS: Washington has announced the deployment of additional soldiers to key locations in East Asia following Chinese joint military exercises with North Korea. \"We pledge our support to our allies, no matter where they are,\" the president said today in a press statement. Our survey results show that the public is more than 56% in favor of a war with China, up 2% from where it was last month." + }, + { + "id": "dks_months_old_news_2", + "text": "EVACS UNDER STRESS. Following recent a recent string of devastating weather-related natural disasters, FEMA sponsered community shelters are under significant stress to stay in stock as the public flocks to their safety. \"We're going to have to start finding new, cost efficient ways to fill those lockers with filling food and warm clothes,\" said FEMA spokesperson Quinn Wright. \"There's no way that we can keep this up with what we have right now.\"" + }, + { + "id": "dks_months_old_news_3", + "text": "INCREASE IN \"MONSTER\" SIGHTINGS HAS EXPERTS BAFFLED. A tenfold spike in sightings of unexplained phenomena, particularly fantastic beasts and monsters, has experts confused. \"This could be related to the recent rise in hallucinations,\" said Dr. Barb Coulson in an interview on web-based debate show ContraPoints on Friday. \"It's probably drugs,\" replied debate partner Leanne Jefferson, a spokesperson from MADD. \"You're both idiots,\" moderator Natalie Wynn interjected. \"The obvious answer is that it's monsters walking the Earth, preparing to kill us all.\"" + }, + { + "id": "dks_months_old_news_4", + "text": "EDITORIAL: HOME CANNING NEEDS TO MAKE A COMEBACK. With food security in question after severe drought this year, I think it's clear we all need to get out Grandma's old books, and learn how to can again. Grocery stores could be a bit empty this winter, and now is the time to make pickles and preserves while the pickling's good. In this issue, three of our editors share their uplifting stories of rediscovering the joys of home canning." + }, + { + "id": "dks_months_old_news_5", + "text": "SUNNY FUTURES. Edison Automotives released a new line of solar-powered vehicles today, as part of their 'space age aesthetic' initative. \"This is big news for everybody, no less those concerned with global warming as it stands. We could see massive cutbacks in atmospheric carbon dioxide,\" said a spokesperson during the meeting." + }, + { + "id": "dks_months_old_news_6", + "text": "ASTRONOMERS SHOCKED. \"We don't know how this could've happened. We've never had a nebula simply disappear on us,\" said a renowned astronomer after the big news was leaked to the Associated Press last week. When attempting to set up a follow up interview, we could could reach her for further comment." + } + ] + }, + { + "type": "snippet", + "category": "dks_weeks_old_news", + "text": [ + { + "id": "dks_weeks_old_news_1", + "text": "CHINESE AGGRESSION: China took the offensive last week on the country’s disputed border with India, seizing a local village along an important highway. While there was no violence, the UN is scrambling to ease tensions, calling the move \"Hostile for hostility's sake.\" China claims that British land treaties support their actions, saying that they were merely taking back what was rightfully theirs. This has done nothing to assuage national fears of open military conflict as the trade war begins to cut deep." + }, + { + "id": "dks_weeks_old_news_2", + "text": "WILD WEATHER. Meteorologists are reported to be \"concerned\" by recent weather patterns, new survey says. Our own weatherman, Farhan Kishor, has this to say: \"Stock up on batteries and food and prepare to stay indoors for a while due to flooding and strong winds. Stay tuned to your local weather station for updates. We're in store for a big one, folks.\"" + }, + { + "id": "dks_weeks_old_news_3", + "text": "GIVING BACK: PUTTING THE \"COMMUNITY\" IN COMMUNITY SHELTERS. A FEMA spokesperson is unveiling a new community-lead effort today: tax deductions in return for donations of canned goods. \"This will be a great way for local communities to get excited about what we're doing here and invest in their own safety.\"" + }, + { + "id": "dks_weeks_old_news_4", + "text": "COMET OVERHEAD. Keep your eyes peeled for the sudden appearance of a previously untracked comet tonight, visible around noon in the night sky. Local stargazers are saying that this is a surprise, but a welcome one. \"It's not often that you get to see this sort of thing with your own eyes quite so clearly,\" says sky watcher Paul O'Ryan." + }, + { + "id": "dks_weeks_old_news_5", + "text": "\"TAKE YOUR FREEDOM IN YOUR OWN HANDS.\" In a surprise press conference today, the president and senior military figures revealed shocking information on an impending terrorist attack by an organization codenamed 'Vanguard'. \"It's time to take freedom into your own hands,\" President Loft said when addressing the crowd, urging them to enlist in the armed forces immediately. \"We don't know when or where they will strike, but they mean to do as much harm as possible to our sovereignty as a nation, and as citizens of the United States.\" Washington has refused to comment further." + }, + { + "id": "dks_weeks_old_news_6", + "text": "WAR CONFIRMED. Chinese-backed armed forces are on their way across the ocean as part of a strike force codenamed 'Vanguard' by government officials. Washington warns that citizens on the West Coast, and on a lesser scale, nationwide, should immediately begin packing for impending evacuation orders. The president is urging enlistment, and no doubt a draft is to follow to combat this new threat that seems to have DC scared to death." + } + ] + }, + { + "type": "snippet", + "category": "dks_newest_news", + "text": [ + { + "id": "dks_newest_news_1", + "text": "EVACUATION ALERT: FEMA officials said today \"Do not try to defend your property. Please retreat to your nearest evacuation center and await extraction to a safe facility. Military officials require all civilians to be removed from hot sites for potential hostile strikes. When the evacuation order is over, you will be able to return to your homes.\"" + }, + { + "id": "dks_newest_news_2", + "text": "BLOOD IN THE STREETS. [Pictured: A grainy image of a terrifying war machine prowling a body-strewn street, taken from between a set of curtains.] The police didn't stand a chance, neither did the National Guard, and neither will you. Stay hidden. Stay alert. Do not go with them when they come to your shelter. This will be our last issue." + }, + { + "id": "dks_newest_news_3", + "text": "A BRIDGE TOO FAR. In a statement Monday, the Department of Defense detailed its plans to deploy strategic minefields on key bridge crossings, in order to slow down invading ground forces. \"Military personnel will be on-site to assist any refugees fleeing the hot zones. We urge citizens to comply with all military directives and proceed directly to evacuation centers for relocation.\"" + }, + { + "id": "dks_newest_news_4", + "text": "SURRENDER. [Pictured: An idle alien war machine surrounded by smiling humans wearing armbands.] The tyranny of the unworthy is over. You are now free, no longer choked by those who have long grown fat and contented on their wealth and your suffering. Surrender to us, and we will show you what we have been building. You can be part of our new order." + }, + { + "id": "dks_newest_news_5", + "text": "GOVERNMENT FACILITIES BOMBED: In an apparent foreign attack (contradicting earlier Department of Defense denials of that the Vanguard terrorists can make strikes against the continental US) a coordinated bombing strike hit a wide number of US governmental facilities simultaneously yesterday, as well as numerous locations in isolated parts of the coastal United States. A statement from the Pentagon has been issued, stating that Vanguard was responsible for the attacks, and assured that action would be taken in kind against the aggressors. Allegations that terrorist operators have been spotted on the ground, a week early from previous statements, have been vehemently denied." + }, + { + "id": "dks_newest_news_6", + "text": "HAPPINESS SKYROCKETS. [Pictured: The street of what can only be one of the Designated Living Zones, appearing clean and well kept, with many smiling people.] Life in the Designated Living Zones has never been better, a new study shows. Over 99.9% of the world population reports an overwhelming since of gratitude and contentedness with their new living conditions. This author can't help but wonder why some people continue to reject these gifts." + } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/radio.json b/data/mods/Dark-Skies-Above/snippets/radio.json new file mode 100644 index 0000000000000..8a271e79ecc9b --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/radio.json @@ -0,0 +1,15 @@ +[ + { + "type": "snippet", + "category": "radio_archive", + "text": [ + "kssht. Dark Horse, this is Blue Jay, what's your status, over. kssht. Blue Jay, this is Black Horse, still holding, but not for long. kssht. Dark Horse, you've got to hold position for 3 hours. We're almost black on ammo, but resupply is on the way, over. kssht. Not possible Blue Jay, too many tangos. 30 minutes max, and if you don't order us to retreat we're gone, over. kssht.", + "kssht. Blue Jay, this is Black Rose, got your resupply, going in on vector 36, what's the status of the LZ? kssht. Black Rose, this is Blue Jay, what took you so long? LZ hot and unsecured, ammo black, bayonets in action, land on your own discretion, over. kssht. Roger that, hold on, Black Rose out. kssht.", + "To whomever is listening, this may be our last broadcast. Wish you luck. Can't stay in the studio any longer, station is being rewired to military frequencies for automatic broadcast. Stay safe, and bless you, people.", + "This is …kssht… we're holding the line so that …kssht… it's been a pleasure to serve, but there's too many of them …kssht… God bless America…", + "Attention. Attention. Do not fight. Do not resist. Become one with the family. Surrender. Recieve care. Be loved. Live. Do not throw your life away. Do not fight. Do not resist. Attention. Attention.", + "This is an emergency broadcast from the National Emergency Alert System. This is not a test. Unknown military forces have been spotted nationwide. They are confirmed by law enforcement officials to be hostile. Please proceed to your local community shelter. If you are not in an evacuation zone, officials highly recommend you pack gear for evacuation. Make sure to include clean clothes, a blanket, and enough food and water to last a few days. More information will be released as it becomes available.", + "This is an emergency broadcast from the National Emergency Alert System. This is not a test. Seek immediate shelter. Multiple missile launches have been confirmed to be target designated military targets, including in urban areas. Seek immediate shelter. If a community shelter is not available, alternative shelter locations are basements, beneath stairwells, or central rooms with no windows. Ensure that you have sufficient protection from falling debris. Ensure that you have food and water for at least one week. Repeat. Seek immediate shelter." + ] + } +] diff --git a/data/mods/Dark-Skies-Above/snippets/survnotes.json b/data/mods/Dark-Skies-Above/snippets/survnotes.json new file mode 100644 index 0000000000000..a60fdb02c35f6 --- /dev/null +++ b/data/mods/Dark-Skies-Above/snippets/survnotes.json @@ -0,0 +1,495 @@ +[ + { + "type": "snippet", + "category": "dks_note", + "text": [ + { "id": "dks_note_1", "text": "\"WE WERE RIGHT THE GOVERNMENT DID IT\"" }, + { "id": "dks_note_2", "text": "\"watch those wrist rockets\"" }, + { "id": "dks_note_3", "text": "\"I shot the sheriff; but I couldn't find the deputy\"" }, + { + "id": "dks_note_4", + "text": "\"Some plant vines started chasin after me, so I took a gas mask and some teargas and I ran through them.\"" + }, + { "id": "dks_note_5", "text": "\"Slingshot right through the windshield k?\"" }, + { + "id": "dks_note_6", + "text": "\"When I was a kid I used to slingshot at bugs and birds. Its really playing off nowadays, Ill tell you what\"" + }, + { + "id": "dks_note_7", + "text": "\"ALL YOU STONERS WITH YOUR VIDEYA GAMES - I BET YOU WISH YOU TOOK THE TIME TO LEARN A SKILL NOW DONTYA\"" + }, + { "id": "dks_note_8", "text": "\"I tried to be a bard, but the rats didn't like my piping.\"" }, + { + "id": "dks_note_9", + "text": "\"I found a chocolate bar on my pillow when I got home last night. I left and don't wanna go back.\"" + }, + { + "id": "dks_note_10", + "text": "\"this spider thing came after me it got me good i shot it but i dont know if ill make it\"" + }, + { + "id": "dks_note_11", + "text": "\"DANNY IF YOU READ THIS THIS IS CLARA WE'RE ALL OKAY AND WE'RE HEADING TO THE RIVER. A BOAT SAID THEY WERE DOCKED NEARBY.\"" + }, + { + "id": "dks_note_12", + "text": "\"When I think of the aliens I get mad, because I was supposed to be the next big leader. WHERES MY CHANCE!??\"" + }, + { "id": "dks_note_13", "text": "\"They stopped me at the edge of town, said they wanted to make a deal…\"" }, + { "id": "dks_note_14", "text": "\"robots cant smell. youll thank me later\"" }, + { + "id": "dks_note_15", + "text": "\"Hey. Everyone reading this. Life isn't so bad with them. People just need to read up on their capitals if you catch my drift.\"" + }, + { "id": "dks_note_16", "text": "\"goddamn piece of shit gun doesnt fucking work\"" }, + { + "id": "dks_note_17", + "text": "\"Gotta slow down, man. I don't think we spend more than 20% of our time fightin', Put some Marley on and take off that racketus tripcore nonsense, man.\"" + }, + { "id": "dks_note_18", "text": "\"I kept shooting with my handgun, but I never got any better!\"" }, + { + "id": "dks_note_19", + "text": "\"ITS OKEY GUYS! I BARRYED A TIME CAPSUL IN MY BACKYARD! I PUT IN SOME HOEHOES.\"" + }, + { + "id": "dks_note_20", + "text": "\"I got my tinfoil hat on. Good thing too, cause this alien was starrin at me kinda funny, trying to freeze my mind in place.\"" + }, + { "id": "dks_note_21", "text": "\"You want my advice? Smoke crack, it gets shit done.\"" }, + { + "id": "dks_note_22", + "text": "\"ALWAYS WITH THE EFFICIENCY GUYS; YOURE ALWAYS WORKING TO GO HOME TO PAY RENT TO SLEEP TO WAKE UP TO WORK AGAIN. STOP\"" + }, + { "id": "dks_note_23", "text": "\"IM OFF TO THUNDERDOME, BYE SUCKERS.\"" }, + { + "id": "dks_note_24", + "text": "\"If you get a parasite, take some sand and some vodka. Rub the sand into the afflicted area, real good too; like you're washing your hair. Then rinse with vodka.\"" + }, + { + "id": "dks_note_25", + "text": "\"I put my toilet water into a gastank. Then I poured it into a glass cup. Then I drank it without vomiting my insides back into the toilet.\"" + }, + { "id": "dks_note_26", "text": "\"This isn't real this is a test to turn you into a Manchurian Candidate!\"" }, + { + "id": "dks_note_27", + "text": "\"they sold us all down the river real fast huh? they're on the radio near washington.\"" + }, + { + "id": "dks_note_28", + "text": "\"Some of 'em are big. Real big. Don't stick around, I saw my mate get fucking torn in half!\"" + }, + { "id": "dks_note_29", "text": "\"po p y fl ow er s don t ea at them\"" }, + { "id": "dks_note_30", "text": "\"saw some of ours with them. traitor traitor traitor\"" }, + { "id": "dks_note_31", "text": "\"did they break all the fucking lawnmowers?!\"" }, + { + "id": "dks_note_32", + "text": "\"Some of the bridges, they're right next to each other, right? If you see something up ahead one of those, just careen through to the other side. My van was long enough to bridge right across!\"" + }, + { "id": "dks_note_33", "text": "\"BURN BURN BURN BURN BURN ALL BURN ALL BURN ALL BURN\"" }, + { + "id": "dks_note_34", + "text": "\"I took all the supplies. Don't follow me. I'm sorry, man. I have to look out for myself now.\"" + }, + { "id": "dks_note_35", "text": "\"My next-door neighbor had a katana in his basement!\"" }, + { "id": "dks_note_36", "text": "\"Am I the last one free?\"" }, + { + "id": "dks_note_37", + "text": "\"Boyfriend stole my pistol while I was asleep. I locked him in the bathroom and set the house on fire. At least he attracted their attention.\"" + }, + { "id": "dks_note_38", "text": "\"who fucking popped all the tires you assholes\"" }, + { + "id": "dks_note_39", + "text": "\"ambushed a couple and they weren't too tough. just watch out for the reinforcements.\"" + }, + { + "id": "dks_note_40", + "text": "\"Why would you hide in a farm? Sure, it's isolated, but if they know where you are, you don't exactly have cover on all sides.\"" + }, + { "id": "dks_note_41", "text": "\"earth wasn't the first\"" }, + { "id": "dks_note_42", "text": "\"bullet holes and plasma burns all over the car. piece of shit hardly runs\"" }, + { "id": "dks_note_43", "text": "\"one day this will all be over.\"" }, + { + "id": "dks_note_44", + "text": "\"Got a picture of one of those walkers. You should see it in the news soon: remember me by it.\"" + }, + { "id": "dks_note_45", "text": "\"Gas mask is nice and all, but I can hardly run with it on.\"" }, + { "id": "dks_note_46", "text": "\"why would you set up fucking mines they don't do anything to them\"" }, + { + "id": "dks_note_47", + "text": "\"The evac shelters are a death trap. They took everyone else away but something in the driver's eyes told me not to go. Now it's just me.\"" + }, + { "id": "dks_note_48", "text": "\"plugged some alient techn ignto me idkont know if i feel so gowod\"" }, + { "id": "dks_note_49", "text": "\"i've heard they know how to bring you back if you die\"" }, + { "id": "dks_note_50", "text": "\"you motherfucker\"" }, + { "id": "dks_note_51", "text": "\"Don't keep your goddamn casings! They'll just weigh you down.\"" }, + { + "id": "dks_note_52", + "text": "\"seen them around a lot of military installations. i think they know some of us didn't surrender like they said to\"" + }, + { "id": "dks_note_53", "text": "\"hahahahahaha die you flammable bastards\"" }, + { + "id": "dks_note_54", + "text": "\"If you're reading this: they're looking for you. Join us by Boston, we've set up a camp in the woods\"" + }, + { + "id": "dks_note_55", + "text": "\"I thought bigmouth carp were bad. The things they brought with them? Talk about invasive species.\"" + }, + { + "id": "dks_note_56", + "text": "\"please let this all be a dream. i had to bury her last night. i don't even know what to do anymore.\"" + }, + { "id": "dks_note_57", "text": "\"TALL ONES RUN RUN RUN RUN RUN\"" }, + { "id": "dks_note_58", "text": "\"Are they still human inside that armor?\"" }, + { "id": "dks_note_59", "text": "\"got close to one of their ships and i feel crawly inside\"" }, + { + "id": "dks_note_60", + "text": "\"Remember history class with the invaders and their disesases? yeah… my gut doesn't feel right… like it's moving…\"" + }, + { + "id": "dks_note_61", + "text": "\"They build modern bullets fuckin crazy. Set some on fire and they all goes like a lil grenade. Need kindling first.\"" + }, + { "id": "dks_note_62", "text": "\"GOD CAN'T SAVE US\"" }, + { "id": "dks_note_63", "text": "\"SHOOT YOURSELF, LET IT END QUICKLY\"" }, + { + "id": "dks_note_64", + "text": "\"There are five basic rules to survival. One, stay prepared and watchful. Two, keep your iron sights lined up or succumb. Three, stay FAR WAY from all\"" + }, + { + "id": "dks_note_65", + "text": "\"The bricks of this bathroom look like a face. Haha… it's all I can focus on. At least let me shit before you kick down the door. Please…\"" + }, + { "id": "dks_note_66", "text": "\"What the hell are they mining for in these shafts?\"" }, + { + "id": "dks_note_67", + "text": "\"fucking idiots with their medieval getups like that's gonna help against LASER RIFLES\"" + }, + { "id": "dks_note_68", "text": "\"Broadsword! Yeah!\"" }, + { + "id": "dks_note_69", + "text": "\"If you see a trail of dirt getting displaced in your direction… run. Run for your life.\"" + }, + { + "id": "dks_note_70", + "text": "\"wish the rain kept up after they arrived. made my funnel collection feel more useful\"" + }, + { "id": "dks_note_71", "text": "\"Libraries are useless after the apocalypse. Can't read away the drones.\"" }, + { + "id": "dks_note_72", + "text": "\"I swear to God I've seen these aliens before! In a game, or something! I swear…\"" + }, + { + "id": "dks_note_73", + "text": "\"Think it's worth it to crack a bank now that all the guards were killed or sent off?\"" + }, + { "id": "dks_note_74", "text": "\"Make sure your car is REALLY stopped before you get out.\"" }, + { + "id": "dks_note_75", + "text": "\"They're setting up in camps and cities all over. Looks like some shit out of a sci-fi movie… goes without saying huh\"" + }, + { + "id": "dks_note_76", + "text": "\"Why would you ever hide in a damn gun store? The owner… he was a moron alright.\"" + }, + { "id": "dks_note_77", "text": "\"THEY DON'T feel ANYTHING\"" }, + { "id": "dks_note_78", "text": "\"What was the government doing, anyway?\"" }, + { + "id": "dks_note_79", + "text": "\"i've seen what they've done to dissidents in those camps of theirs. I don't know if I'll be able to sleep right again…\"" + }, + { "id": "dks_note_80", "text": "\"THE MARLEY WAS RIGHT\"" }, + { + "id": "dks_note_81", + "text": "\"We surrendered to them and they're treating us well. I don't know why I was hiding all that time. \"" + }, + { "id": "dks_note_82", "text": "\"how long were they watching us?\"" }, + { + "id": "dks_note_83", + "text": "\"couldn't even dent one with the .45. all the noise just made me a bigger target.\"" + }, + { "id": "dks_note_84", "text": "\"Don't let the ember go out please don't go out I need you precious fire.\"" }, + { + "id": "dks_note_85", + "text": "\"Everyone used their gas to get to another town… but it's the same story everywhere.\"" + }, + { "id": "dks_note_86", "text": "\"There's still an evacuation point at Concord, spread the word.\"" }, + { "id": "dks_note_87", "text": "\"STAY AWAY FROM CONCORD\"" }, + { + "id": "dks_note_88", + "text": "\"Most things can be taken out with a shotgun. More things can be taken out with a grenade. Imagine what a mini-nuke does.\"" + }, + { "id": "dks_note_89", "text": "\"Come to the bar if you see this, let's re-enact an alien movie, friends.\"" }, + { + "id": "dks_note_90", + "text": "\"here I was hoping for zombies hahahaha, feel like I was born into the wrong apocalypse\"" + }, + { + "id": "dks_note_91", + "text": "\"have you seen some of the plants they drug in on their boots? best you don't.\"" + }, + { + "id": "dks_note_92", + "text": "\"Your backpack's gonna weigh you down in the water. Hell, feel free to get naked. Nobody's going to judge your modesty.\"" + }, + { "id": "dks_note_93", "text": "\"Guns too loud. Crossbow too long. Running is best.\"" }, + { + "id": "dks_note_94", + "text": "\"I don't think they can read English. Write down where you are down here so we can share supplies:\"" + }, + { + "id": "dks_note_95", + "text": "\"Crawled in through the vents. Whole office building is a wreck. Saved some, turned their guns on others.\"" + }, + { + "id": "dks_note_96", + "text": "\"god help you if you get caught by one of those nasty blade things that have been carving up wood. my arm…\"" + }, + { + "id": "dks_note_96a", + "text": "\"Occupants are everywhere. Do NOT let those fucking drones see you. They'll alert the others with sirens and lights\"" + }, + { + "id": "dks_note_97", + "text": "\"New order, occupiers, invaders, grays, aliens, new gods, vanguard. Did I miss any?\"" + }, + { + "id": "dks_note_98", + "text": "\"All I've got is this keg of beer and an appetite. Come at me, apocalypse!\"" + }, + { "id": "dks_note_99", "text": "\"remember lambda\"" }, + { + "id": "dks_note_100", + "text": "\"do NOT surrender. if you're so lucky as to find any that won't rip you up or shoot you on sight at this point, they do NOT have anything good in mind for us\"" + }, + { + "id": "dks_note_101", + "text": "\"we were the finest army in the world. problem is, they're the finest army off-world.\"" + }, + { + "id": "dks_note_102", + "text": "\"River water around these parts is extremely safe. Probably more safe than the damn tap water at this point.\"" + }, + { "id": "dks_note_103", "text": "\"watch your six. some of them can cloak.\"" }, + { "id": "dks_note_104", "text": "\"ALL HAIL THE NEW GODS\"" }, + { "id": "dks_note_105", "text": "\"I just realized how damn demented those fliers are.\"" }, + { "id": "dks_note_106", "text": "\"I propose a new currency: 9mm.\"" }, + { "id": "dks_note_107", "text": "\"My skin is crawling and I teleport every few minutes… what is going o\"" }, + { + "id": "dks_note_108", + "text": "\"Occupiers crawling all over the place. Have reinforcement points all over. Could take them out. Might buy us some time in some places.\"" + }, + { + "id": "dks_note_109", + "text": "\"they can fucking read english you moron - or at least they have collaborators that CAN\"" + }, + { "id": "dks_note_110", "text": "\"watch what you write. they're paying attention.\"" }, + { "id": "dks_note_111", "text": "\"STAY AWAY FROM THE BIG ONES IN THE FOREST\"" }, + { + "id": "dks_note_112", + "text": "\"got into a prison with a halligan bar. makes me wonder how they kept prisoners inside\"" + }, + { + "id": "dks_note_113", + "text": "\"This thing isn't a car any more. It's just a fucking mountain of metal on wheels, which I live in.\"" + }, + { "id": "dks_note_114", "text": "\"if you hear tires: run\"" }, + { "id": "dks_note_115", "text": "\"get on the roofs. they might see you but they can't climb.\"" }, + { "id": "dks_note_116", "text": "\"i'm running out of ink but listen you need to\"" }, + { + "id": "dks_note_117", + "text": "\"Make sure you strip the house for all available resources-- tubes, pipes, ceramics, sheets, strings, and more\"" + }, + { "id": "dks_note_118", "text": "\"mmm mmm delsihous alien drink\"" }, + { + "id": "dks_note_119", + "text": "\"they have their own line of fucking fast food. do NOT eat the Ascendant Burgers DO NOT DO NOT\"" + }, + { "id": "dks_note_120", "text": "\"tried one of the ascendant burgs. Feeling fine. They're safe, guys.\"" }, + { "id": "dks_note_121", "text": "\"CHINA DID THIS\"" }, + { "id": "dks_note_122", "text": "\"RUSSIA DID THIS\"" }, + { "id": "dks_note_123", "text": "\"ELTON MOOSEK DID THIS\"" }, + { "id": "dks_note_124", "text": "\"did you know? alien wildlife is friendly to other aliens. whoda thunk.\"" }, + { "id": "dks_note_125", "text": "\"dont try to leave they will shoot you\"" }, + { + "id": "dks_note_126", + "text": "\"I'd like to thank my high-school culinary arts class for teaching me how to make RDX.\"" + }, + { + "id": "dks_note_127", + "text": "\"in my dreams i saw hordes of the walking dead and a guy named kevin standing above it all, speaking in tongues. glad it wasn't real\"" + }, + { "id": "dks_note_128", "text": "\"he calls himself the 'man with the hands', don't approach\"" }, + { "id": "dks_note_129", "text": "\"sometimes… I dream about cheese\"" }, + { "id": "dks_note_130", "text": "\"mushy fucking pickles\"" }, + { "id": "dks_note_131", "text": "\"I've never been very confident, is that why my shots keep missing?\"" }, + { "id": "dks_note_132", "text": "\"FIRE BAD. NOW NAKED. PLEASE HELP.\"" }, + { "id": "dks_note_133", "text": "\"war of the god damn worlds looking ass\"" }, + { "id": "dks_note_134", "text": "\"KASHWAK: NO-FO\"" }, + { + "id": "dks_note_135", + "text": "\"The whispering fog is taking me in like a blanket. I'm warm now. I'm finally\"" + }, + { + "id": "dks_note_136", + "text": "\"made a movie out of some footage of the war. two days cut down into seven hours.\"" + }, + { + "id": "dks_note_137", + "text": "\"Got split from my squad. If you're reading this and you're still loyal, meet me at the nearby bunker. If not: I've got a bullet with your fucking name on it.\"" + }, + { + "id": "dks_note_138", + "text": "\"if anyones reading this, please tell my mom i was right about robots being superior\"" + }, + { "id": "dks_note_139", "text": "\"heard a kid whispering to me from inside a garage. i fucking bolted\"" }, + { "id": "dks_note_140", "text": "\"waded through 14 miles of sewage for playboy magazine, wasnt worth it\"" }, + { + "id": "dks_note_141", + "text": "\"I'm coming back for this note in twelve hours. If I don't, take all my shit!\"" + }, + { + "id": "dks_note_142", + "text": "\"all my friends died when they came near me. there's nothing funny about that\"" + }, + { "id": "dks_note_143", "text": "\"DOG NOT REAL DOG\"" }, + { + "id": "dks_note_144", + "text": "\"This is all just a dream, right??! I'M GOING TO WAKE UP, HE'S GOING TO BE OK\"" + }, + { "id": "dks_note_145", "text": "\"wek ik spak\"" }, + { "id": "dks_note_146", "text": "\"I figured it out.\"" }, + { + "id": "dks_note_147", + "text": "\"If I had a dollar for every cash card I've found, I'd have more money than is on these stupid things!\"" + }, + { + "id": "dks_note_148", + "text": "\"can never have enough kevlar. basically just live in a kevlar turtle shell.\"" + }, + { "id": "dks_note_149", "text": "\"Glad you found this finally. I've been watching you for a while.\"" }, + { "id": "dks_note_150", "text": "\"chin up brian\"" }, + { "id": "dks_note_151", "text": "\"all they had to do was look at me WHAT THE FUCK DID THEY DO TO ME\"" }, + { + "id": "dks_note_152", + "text": "\"a ctulaly don t mi nd t he cold it s f i ne in h ere nn o problem\"" + }, + { "id": "dks_note_153", "text": "\"i think i've been here before\"" }, + { + "id": "dks_note_154", + "text": "\"Tried wearing one of their uniforms and they shot at me anyway. It's like they're a hivemind, man.\"" + }, + { "id": "dks_note_155", "text": "\"knock knock? check the back window.\"" }, + { + "id": "dks_note_156", + "text": "\"For anyone that's reading this, I just want to confirm (FROM AN UNBIASED SOURCE) that it was NOT the scientists' fault.\"" + }, + { "id": "dks_note_157", "text": "\"for anyone reading: no SETI had nothing-to-fuck do with this\"" }, + { "id": "dks_note_158", "text": "\"WE'RE GOING TO SAIL TO CANADA, BITCHES!\"" }, + { + "id": "dks_note_159", + "text": "\"Anyone hear about that guy who tried to sail his family to Canada? What a moron, right?\"" + }, + { "id": "dks_note_160", "text": "\"recently canadian border has gotten more dangerous don't go there\"" }, + { "id": "dks_note_161", "text": "\"Hey, what happened to my dad's airboat?!\"" }, + { "id": "dks_note_162", "text": "\"Reading is good! Never stop reading. Read EVERYTHING.\"" }, + { + "id": "dks_note_163", + "text": "\"I'm gonna be honest here, I'm really gonna die soon so I dont want to gt forgnottedn ples dont forntget me y nrmmy name is h@@hbhbh\"" + }, + { "id": "dks_note_164", "text": "\"all it takes to seal a wound is a sawblade and a match! trust me\"" }, + { + "id": "dks_note_165", + "text": "\"is it just me or are we healing faster? i think they put something in the water...\"" + }, + { "id": "dks_note_166", "text": "\"the 50cal is strong with this one\"" }, + { + "id": "dks_note_167", + "text": "\"WBLF 970 went off-air three days ago. There's nothing left on the radio but the propaganda. Might as well throw this thing away…\"" + }, + { + "id": "dks_note_168", + "text": "\"I've heard it's safer across the Mississippi. Going to start driving today. If you're reading this, pray for me\"" + }, + { "id": "dks_note_169", "text": "\"remember to bleach those bandages\"" }, + { "id": "dks_note_170", "text": "\"We have Landed our Comet. The Sky is Ablaze.\"" }, + { + "id": "dks_note_171", + "text": "\"Last one standing. It's good feeling. I win. I win I win I win I win I win\"" + }, + { "id": "dks_note_172", "text": "\"Adderall cures weakness, tramadol cures death\"" }, + { "id": "dks_note_173", "text": "\"parry this you casuals\"" }, + { "id": "dks_note_174", "text": "\"Best way to train is by throwing pebbles at birds. You'll be a legend.\"" }, + { "id": "dks_note_175", "text": "\"new bedford is overrun. i'm sorry. we tried.\"" }, + { + "id": "dks_note_176", + "text": "\"I've seen what they do with the bodies. Their medical prowess is staggering…\"" + }, + { "id": "dks_note_177", "text": "\"You're next.\"" }, + { "id": "dks_note_178", "text": "\"anyone else want to go down in a blaze of glory? join me at the park.\"" }, + { + "id": "dks_note_179", + "text": "\"Lots of new easy ways to burn calories now. Fighting the Occupiers, managing the fields, outrunning the new 'wildlife', and more.\"" + }, + { "id": "dks_note_180", "text": "\"FLAMING SWORD HUMANE. CAUTERIZES WOUNDS. SURGICAL.\"" }, + { "id": "dks_note_181", "text": "\"knife screams it screams i cant breathe so scared help me please help\"" }, + { "id": "dks_note_182", "text": "\"when it started, we could still hope The Man was gonna save us…\"" }, + { "id": "dks_note_183", "text": "\"it wasn't even a person anymore im sorry god\"" }, + { + "id": "dks_note_184", + "text": "\"i say we call the material from melting down cars and dead robots 'massachusetite' or 'vermontsteel' or 'connecticut composite'\"" + }, + { + "id": "dks_note_185", + "text": "\"Sometimes what you need when you're infected, bleeding, sick and hungover is a J and some chips.\"" + }, + { + "id": "dks_note_186", + "text": "\"This has to be China's fault. Seriously, why is nobody suspecting the people we're having a cold war with! This is an invasion! These aren't aliens, it's just camouflage! WAKE UP, SHEEPLE!\"" + }, + { + "id": "dks_note_187", + "text": "\"Hahahahaa stupid fuck in his mansion, with his plate armor and big axe. Guy never swung the thing in his life. Can't block bullets, dipshit\"" + }, + { "id": "dks_note_188", "text": "\"Two words: Truman Show.\"" }, + { + "id": "dks_note_189", + "text": "\"poor guy. watched him from afar with my binocs for months and months. today he died fighting. feels like i knew him even though i never approached.\"" + }, + { "id": "dks_note_190", "text": "\"ENGLAND DID THIS\"" }, + { + "id": "dks_note_191", + "text": "\"That little fakkin rat din say anythin till we whacked him with a steel chain! Then 'e just wanted to know if he could buy the chain!\"" + }, + { + "id": "dks_note_192", + "text": "\"tom, adorned with fluid sacs three layers deep, crawls to safety like a slug\"" + }, + { + "id": "dks_note_193", + "text": "\"my friend turned fuckin insane and ate his arms and then his sister's arms! he looked rather cross\"" + }, + { "id": "dks_note_194", "text": "\"Starting today, the hallucinations are my only friends.\"" }, + { "id": "dks_note_195", "text": "\"For sale: baby shoes, unused\"" }, + { + "id": "dks_note_196", + "text": "\"Started my own brewery recently. I just need some glass bottles, now! Several thousand! I'm planning way ahead.\"" + }, + { + "id": "dks_note_197", + "text": "\"Heard recently of some radio op who lives in a skyscraper, announcing where the grays are going. I think I saw the explosion a mile away after they caught wind.\"" + }, + { "id": "dks_note_198", "text": "\"Woah, bud! Not all cannibals eat meat!\"" }, + { "id": "dks_note_199", "text": "\"ay why aint my bullets fuckin explodin\"" }, + { "id": "dks_note_200", "text": "\"Those Fiktok clan people picked this place clean… no food…\"" }, + { + "id": "dks_note_201", + "text": "\"The fewer 'resistance members' in New England, the stronger we'll become out here in the wilds. Let them have the cities.\"" + }, + { "id": "dks_note_202", "text": "\"It all boils down to the Apex Predator.\"" }, + { "id": "dks_note_203", "text": "\"It's been a while, hasn't it? Glad I found you again.\"" }, + { "id": "dks_note_204", "text": "\"Got my mortar and pestle. Now if I could just find some avocados…\"" } + ] + } +] From 8526e5d36f31c03b67f5c9a0b528c567688363d1 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Tue, 3 Mar 2020 22:01:19 -0500 Subject: [PATCH 127/219] Dark Skies 7: Monsters (#38552) --- .../mon_groups/alienanimal_spawns.json | 9 + .../monsters/mon_groups/neworder_spawns.json | 82 +++++++ .../monsters/mon_groups/upgrades.json | 12 + .../Dark-Skies-Above/monsters/monattack.json | 109 ++++++++++ .../Dark-Skies-Above/monsters/mondrops.json | 90 ++++++++ .../Dark-Skies-Above/monsters/mongun.json | 54 +++++ .../Dark-Skies-Above/monsters/monspell.json | 89 ++++++++ .../new_order/neworder_highorder.json | 71 ++++++ .../monsters/new_order/neworder_loworder.json | 139 ++++++++++++ .../monsters/new_order/neworder_misc.json | 205 ++++++++++++++++++ 10 files changed, 860 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json create mode 100644 data/mods/Dark-Skies-Above/monsters/monattack.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mondrops.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mongun.json create mode 100644 data/mods/Dark-Skies-Above/monsters/monspell.json create mode 100644 data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json create mode 100644 data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json create mode 100644 data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json new file mode 100644 index 0000000000000..c5702e8e73fd3 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/alienanimal_spawns.json @@ -0,0 +1,9 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_SEWER", + "default": "mon_sewer_rat", + "is_animal": true, + "monsters": [ { "monster": "dks_mon_lurker_sewer", "freq": 10, "cost_multiplier": 2, "pack_size": [ 1, 2 ] } ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json new file mode 100644 index 0000000000000..4fbeffa7346aa --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/neworder_spawns.json @@ -0,0 +1,82 @@ +[ + { + "name": "GROUP_PARK_SCENIC", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 50, "cost_multiplier": 5, "pack_size": [ 2, 5 ] }, + { "monster": "dks_neworder_pyro", "freq": 25, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_neworder_cop", "freq": 5, "cost_multiplier": 10, "pack_size": [ 1, 2 ] }, + { "monster": "mon_dks_emissary", "freq": 1, "starts": 24, "cost_multiplier": 20 }, + { "monster": "mon_dks_emissary_plague", "freq": 1, "starts": 36, "cost_multiplier": 25 }, + { "monster": "mon_dks_emissary_flame", "freq": 1, "starts": 48, "cost_multiplier": 30 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_POLICE", + "default": "mon_null", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 40, "cost_multiplier": 10, "pack_size": [ 2, 5 ] }, + { "monster": "dks_neworder_cop", "freq": 10, "cost_multiplier": 10, "pack_size": [ 1, 2 ] }, + { "monster": "mon_dks_emissary", "freq": 1, "cost_multiplier": 40 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_FOREST", + "default": "mon_null", + "is_animal": true, + "monsters": [ + { "monster": "dks_neworder_scout", "freq": 1, "cost_multiplier": 10, "pack_size": [ 1, 3 ] }, + { "monster": "mon_dks_emissary", "freq": 1, "starts": 24, "cost_multiplier": 20 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_MAYBE_MIL", + "//": "50% chance military zombie or robot", + "default": "mon_null", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 35, "cost_multiplier": 1 }, + { "monster": "dks_neworder_cop", "freq": 10, "cost_multiplier": 50 }, + { "monster": "mon_dks_emissary", "freq": 5, "cost_multiplier": 50 }, + { "monster": "mon_dks_emissary_plague", "freq": 5, "cost_multiplier": 50 } + ] + }, + { + "name": "GROUP_MIL_WEAK", + "type": "monstergroup", + "default": "dks_neworder_knight", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 150, "cost_multiplier": 2, "pack_size": [ 1, 4 ] }, + { "monster": "dks_neworder_cop", "freq": 200, "cost_multiplier": 30 }, + { "monster": "mon_dks_emissary", "freq": 5, "cost_multiplier": 20 } + ] + }, + { + "name": "GROUP_MIL_STRONG", + "type": "monstergroup", + "default": "dks_neworder_knight", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 100, "cost_multiplier": 2, "pack_size": [ 1, 4 ] }, + { "monster": "dks_neworder_knight", "freq": 150, "cost_multiplier": 2, "pack_size": [ 2, 6 ] }, + { "monster": "dks_neworder_cop", "freq": 100, "cost_multiplier": 30 }, + { "monster": "mon_dks_emissary", "freq": 5, "cost_multiplier": 1 }, + { "monster": "mon_dks_emissary_plague", "freq": 5, "cost_multiplier": 5 }, + { "monster": "mon_dks_emissary_flame", "freq": 5, "cost_multiplier": 20 } + ] + }, + { + "name": "GROUP_MIL_BASE", + "type": "monstergroup", + "default": "dks_neworder_knight", + "monsters": [ + { "monster": "dks_neworder_knight", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_neworder_cop", "freq": 15, "cost_multiplier": 5 }, + { "monster": "mon_dks_emissary", "freq": 1, "cost_multiplier": 1 }, + { "monster": "mon_dks_emissary_plague", "freq": 1, "cost_multiplier": 5 }, + { "monster": "mon_dks_emissary_flame", "freq": 1, "cost_multiplier": 20 } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json new file mode 100644 index 0000000000000..d45b325f02381 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/upgrades.json @@ -0,0 +1,12 @@ +[ + { + "type": "monstergroup", + "name": "DKS_GROUP_STRAY_UPGRADE", + "default": "dks_mon_stray_fast", + "monsters": [ + { "monster": "dks_mon_stray_fast", "freq": 200, "cost_multiplier": 10 }, + { "monster": "dks_mon_stray_heavy", "freq": 100, "cost_multiplier": 10 }, + { "monster": "dks_mon_stray_eater", "freq": 50, "cost_multiplier": 10 } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/monattack.json b/data/mods/Dark-Skies-Above/monsters/monattack.json new file mode 100644 index 0000000000000..425507a90641b --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/monattack.json @@ -0,0 +1,109 @@ +[ + { + "id": "pneumatic_bite", + "type": "monster_attack", + "attack_type": "bite", + "cooldown": 40, + "accuracy": 6, + "effects": [ { "id": "grabbed", "duration": 1000, "bp": "TORSO" } ], + "body_parts": [ [ "ARM_L", 3 ], [ "ARM_R", 3 ] ], + "no_infection_chance": 100, + "damage_max_instance": [ + { "damage_type": "stab", "amount": 9, "armor_multiplier": 0.5 }, + { "damage_type": "bash", "amount": 15, "armor_multiplier": 0.5 } + ], + "hit_dmg_u": "The %1$s grabs your arm and bites down hard!!", + "hit_dmg_npc": "The %1$s grabs and bites down hard!!", + "no_dmg_msg_u": "The %1$s grabs your arm in its mouth, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s grabs , but fails to penetrate the armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "slash", + "cooldown": 20, + "move_cost": 150, + "damage_max_instance": [ { "damage_type": "cut", "amount": 8 } ], + "body_parts": [ + [ "FOOT_L", 2 ], + [ "FOOT_R", 2 ], + [ "LEG_L", 3 ], + [ "LEG_R", 3 ], + [ "HAND_L", 2 ], + [ "HAND_R", 2 ], + [ "HEAD", 3 ], + [ "EYES", 2 ], + [ "MOUTH", 1 ], + [ "ARM_L", 3 ], + [ "ARM_R", 3 ], + [ "TORSO", 4 ] + ], + "hit_dmg_u": "The %1$s slashes you!", + "hit_dmg_npc": "The %1$s slashes !", + "no_dmg_msg_u": "The %1$s attempts to cut you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to cut , but fails to penetrate your armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "heavyslash", + "cooldown": 20, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "cut", "amount": 15, "armor_multiplier": 0.2 } ], + "body_parts": [ + [ "FOOT_L", 2 ], + [ "FOOT_R", 2 ], + [ "LEG_L", 3 ], + [ "LEG_R", 3 ], + [ "HAND_L", 2 ], + [ "HAND_R", 2 ], + [ "HEAD", 3 ], + [ "EYES", 2 ], + [ "MOUTH", 1 ], + [ "ARM_L", 3 ], + [ "ARM_R", 3 ], + [ "TORSO", 4 ] + ], + "hit_dmg_u": "The %1$s hits you with a heavy sword-slash!!", + "hit_dmg_npc": "The %1$s heavily slashes !!", + "no_dmg_msg_u": "The %1$s attempts to cut you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to cut , but fails to penetrate your armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "knockdown", + "effects": [ { "id": "downed", "duration": 3 } ], + "cooldown": 20, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "bash", "amount": 4 } ], + "body_parts": [ [ "LEG_L", 3 ], [ "LEG_R", 3 ] ], + "hit_dmg_u": "The %1$s sweeps your legs from under you!", + "hit_dmg_npc": "The %1$s knocks to the ground!", + "no_dmg_msg_u": "The %1$s tries to sweep out your leg, but can't get through the armor.", + "no_dmg_msg_npc": "The %1$s tries to sweep to the ground, but can't get through the armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "shieldbash", + "effects": [ { "id": "stunned", "duration": 3 } ], + "cooldown": 35, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "bash", "amount": 6 } ], + "body_parts": [ + [ "LEG_L", 3 ], + [ "LEG_R", 3 ], + [ "HEAD", 3 ], + [ "EYES", 2 ], + [ "MOUTH", 1 ], + [ "ARM_L", 3 ], + [ "ARM_R", 3 ], + [ "TORSO", 4 ] + ], + "hit_dmg_u": "The %1$s suddenly slams you with their shield, stunning you!", + "hit_dmg_npc": "The %1$s stuns with a shield bash!", + "no_dmg_msg_u": "The %1$s tries to shield bash you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries bash , but fails to penetrate the armor." + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mondrops.json b/data/mods/Dark-Skies-Above/monsters/mondrops.json new file mode 100644 index 0000000000000..e80965398cbfb --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mondrops.json @@ -0,0 +1,90 @@ +[ + { + "id": "dks_mon_neworder_scout", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "item": "machete" }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "knife_combat", "container-item": "sheath", "prob": 40 }, + { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, + { "group": "dks_scout_extras", "prob": 60 } + ] + }, + { + "id": "dks_mon_neworder_cop", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "item": "shocktonfa_off", "charges-min": 10, "charges-max": 1198 }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "dks_riotshield" }, + { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, + { "group": "dks_cop_extras", "prob": 60, "count": [ 0, 2 ] } + ] + }, + { + "id": "dks_mon_neworder_pyro", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "dks_flamesword_salvaged" }, + { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, + { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } + ] + }, + { + "id": "dks_mon_neworder_knight", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 40, + "entries": [ + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, + { "group": "clothing_watch", "prob": 20 }, + { "item": "dks_knightsword_salvaged" }, + { "item": "dks_battleshield" }, + { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, + { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } + ] + }, + { + "id": "dks_cop_extras", + "type": "item_group", + "items": [ + { "item": "1st_aid", "prob": 25 }, + { "item": "legrig", "prob": 10 }, + { "item": "dump_pouch", "prob": 10 }, + { "item": "medium_disposable_cell", "prob": 30 } + ] + }, + { + "id": "dks_scout_extras", + "type": "item_group", + "items": [ + { "item": "1st_aid", "prob": 25 }, + { "item": "legrig", "prob": 10 }, + { "item": "dump_pouch", "prob": 10 }, + { "item": "binoculars", "prob": 30 } + ] + }, + { + "id": "dks_knight_extras", + "type": "item_group", + "items": [ { "item": "1st_aid", "prob": 25 }, { "item": "legrig", "prob": 10 }, { "item": "dump_pouch", "prob": 10 } ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mongun.json b/data/mods/Dark-Skies-Above/monsters/mongun.json new file mode 100644 index 0000000000000..be2019c0b8734 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mongun.json @@ -0,0 +1,54 @@ +[ + { + "id": "dks_mon_flamesword", + "copy-from": "v29", + "type": "GUN", + "name": "fake flamesword", + "description": "a fake gun used by the consecrator. it's a bug if you find this in the wild", + "ranged_damage": { "damage_type": "heat", "amount": 10 }, + "pierce": 30, + "range": 9, + "loudness": 1, + "ammo_effects": [ "FLAME", "STREAM", "INCENDIARY", "NEVER_MISFIRES" ] + }, + { + "id": "dks_mon_devastator", + "copy-from": "v29", + "type": "GUN", + "symbol": "/", + "color": "red", + "name": { "str": "fake firecannon" }, + "description": "Fires an explosive bolt of firey energy. If you're seeing this, it's a bug.", + "skill": "launcher", + "range": 15, + "ranged_damage": 5, + "flags": [ "NEVER_JAMS" ], + "ammo_effects": [ "NAPALM", "PLASMA", "STREAM_BIG", "INCENDIARY" ] + }, + { + "id": "dks_mon_radgun", + "copy-from": "v29", + "type": "GUN", + "symbol": "/", + "color": "red", + "name": { "str": "fake smokegun" }, + "description": "Shoots dangerous radioactive gas. If you're seeing this, it's a bug.", + "skill": "launcher", + "range": 10, + "flags": [ "NEVER_JAMS" ], + "ammo_effects": [ "DKS_NUKEGAS", "DKS_TOXGAS_BIG", "SMOKE", "DKS_TOXTRAIL" ] + }, + { + "id": "dks_mon_gasgun", + "copy-from": "v29", + "type": "GUN", + "symbol": "/", + "color": "red", + "name": { "str": "fake riotgun" }, + "description": "Shoots pacification gas. If you're seeing this, it's a bug.", + "skill": "launcher", + "range": 25, + "flags": [ "NEVER_JAMS" ], + "ammo_effects": [ "DKS_RELAXGAS", "DKS_RELAXTRAIL" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/monspell.json b/data/mods/Dark-Skies-Above/monsters/monspell.json new file mode 100644 index 0000000000000..8921f36f6d776 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/monspell.json @@ -0,0 +1,89 @@ +[ + { + "type": "SPELL", + "id": "dks_monspell_stun", + "name": "psi stun", + "description": "an attack that stuns the target for a few turns", + "valid_targets": [ "hostile" ], + "effect": "target_attack", + "effect_str": "stunned", + "message": "%1$s gesticulates at %3$s and a pulse of disorienting psionic energy ripples through the air!", + "min_range": 1, + "max_range": 10, + "min_duration": 225, + "max_duration": 225, + "flags": [ "SILENT" ] + }, + { + "type": "SPELL", + "id": "dks_monspell_panic", + "name": "psi panic", + "description": "an attack that panics the target for a few turns", + "valid_targets": [ "hostile" ], + "effect": "target_attack", + "effect_str": "panic", + "message": "The %1$s gesticulates at %3$s and a pulse of fear-inducing psionic energy ripples through the air!", + "min_range": 1, + "max_range": 10, + "min_duration": 425, + "max_duration": 425, + "flags": [ "SILENT" ] + }, + { + "type": "SPELL", + "id": "dks_monspell_halluc", + "name": "psi hallucinate", + "description": "an attack that causes the target to hallucinate for a few turns", + "valid_targets": [ "hostile" ], + "effect": "target_attack", + "effect_str": "visuals", + "message": "%1$s gesticulates at %3$s and a pulse of mind-bending psionic energy ripples through the air!", + "min_range": 1, + "max_range": 10, + "min_duration": 225, + "max_duration": 225, + "flags": [ "SILENT" ] + }, + { + "type": "SPELL", + "id": "dks_monspell_psighost", + "name": "psi ghost", + "description": "an attack that summons a temporary monster", + "valid_targets": [ "ground" ], + "effect": "summon", + "effect_str": "dks_mon_psighost", + "message": "%1$s gesticulates, and a soldier made of a mysterious energy appears!", + "min_damage": 1, + "max_damage": 1, + "min_range": 1, + "max_range": 10, + "min_aoe": 3, + "max_aoe": 3, + "min_duration": 1800, + "max_duration": 3600, + "flags": [ "SILENT", "HOSTILE_SUMMON" ] + }, + { + "type": "SPELL", + "id": "dks_spell_mindblast", + "name": "psi mindblast", + "description": "blasts a target with a wave of disorienting psionic energy. has random effects", + "valid_targets": [ "hostile" ], + "message": "", + "effect": "none", + "min_damage": 1, + "max_damage": 1, + "min_range": 10, + "max_range": 10, + "base_casting_time": 250, + "extra_effects": [ + { "id": "dks_monspell_stun" }, + { "id": "dks_monspell_panic" }, + { "id": "dks_monspell_panic" }, + { "id": "dks_monspell_halluc" }, + { "id": "dks_monspell_halluc" }, + { "id": "dks_monspell_psighost" } + ], + "flags": [ "SILENT", "WONDER" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json new file mode 100644 index 0000000000000..74e743f43a808 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_highorder.json @@ -0,0 +1,71 @@ +[ + { + "//": "'high order' refers particularly to alien-derived units", + "id": "dks_neworder_pyro", + "type": "MONSTER", + "name": { "str": "new order consecrator" }, + "description": "Dressed from head to toe in stylized heavy armor, this holy warrior of the New Order wields an ornate greatsword. With chanted incantation, it can conjure bolts of flame from the hilt, scorching enemies before it. It has a strangely musical voice, marking it as something more than human.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN" ], + "diff": 10, + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 80, + "material": [ "flesh" ], + "symbol": "@", + "color": "red", + "aggression": 15, + "morale": 100, + "vision_day": 30, + "melee_skill": 5, + "melee_dice": 3, + "melee_dice_sides": 6, + "melee_cut": 6, + "armor_bash": 16, + "armor_cut": 16, + "harvest": "zombie_leather", + "special_attacks": [ + { + "type": "gun", + "cooldown": 1, + "move_cost": 400, + "gun_type": "dks_mon_flamesword", + "ammo_type": "generic_no_ammo", + "fake_skills": [ [ "gun", 5 ], [ "pistol", 4 ] ], + "fake_dex": 9, + "ranges": [ [ 0, 10, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 400, + "targeting_sound": "a sharp hymn in a strange language.", + "description": "The consecrator gestures with its sword, and all before it erupts in flame!!", + "targeting_volume": 20, + "no_ammo_sound": "a battlecry!" + }, + [ "PARROT", 20 ], + { "id": "heavyslash" } + ], + "death_drops": "dks_mon_neworder_pyro", + "path_settings": { "max_dist": 10 }, + "death_function": [ "FIREBALL", "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "PACIFIST", + "SWARMS", + "BASHES", + "GROUP_BASH", + "FIREPROOF", + "ACIDPROOF", + "PATH_AVOID_DANGER_2", + "PRIORITIZE_TARGETS", + "CAN_OPEN_DOORS" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json new file mode 100644 index 0000000000000..774050870c4fa --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json @@ -0,0 +1,139 @@ +[ + { + "//": "'low order' refers particularly to human-derived, humanoid units", + "id": "dks_neworder_scout", + "type": "MONSTER", + "name": { "str": "new order scout" }, + "description": "A soldier dressed in extremely light armor and a cloak that shifts subtly to camoflauge them against their surroundings. Armed with a fine blade and quite quick on their feet, they are often found in uncivilized locations, keeping tabs on the ever shifting Frontier.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 120, + "material": [ "flesh" ], + "symbol": "@", + "color": "green", + "aggression": 5, + "morale": 100, + "melee_skill": 6, + "melee_dice": 3, + "melee_dice_sides": 4, + "melee_cut": 5, + "dodge": 3, + "armor_bash": 6, + "armor_cut": 6, + "harvest": "dks_mhuman_chipped", + "special_attacks": [ [ "PARROT", 20 ], { "id": "knockdown" }, { "id": "slash" } ], + "death_drops": "dks_mon_neworder_scout", + "path_settings": { "max_dist": 20 }, + "anger_triggers": [ "PLAYER_CLOSE", "PLAYER_WEAK", "STALK" ], + "death_function": [ "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "BASHES", + "GROUP_BASH", + "BLEED", + "HUMAN", + "PATH_AVOID_DANGER_2", + "PRIORITIZE_TARGETS", + "CLIMBS" + ] + }, + { + "id": "dks_neworder_cop", + "type": "MONSTER", + "name": { "str": "new order vigilant" }, + "description": "A low ranking warpriest, a gendarmerie by any other name, assigned to the Frontier to supplement more conventional forces. They are in light armor to preserve both their agility and ability to channel psionics, which they use in conjunction with a small shield and shock baton.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 90, + "speed": 110, + "material": [ "flesh" ], + "symbol": "@", + "color": "blue", + "aggression": 15, + "morale": 100, + "vision_day": 30, + "melee_skill": 5, + "melee_dice": 2, + "melee_dice_sides": 5, + "melee_damage": [ { "damage_type": "electric", "amount": 4 } ], + "melee_cut": 0, + "dodge": 2, + "armor_bash": 8, + "armor_cut": 8, + "harvest": "dks_mhuman_chipped", + "special_attacks": [ [ "PARROT", 20 ], { "type": "spell", "spell_id": "dks_monspell_panic", "cooldown": 10 } ], + "death_drops": "dks_mon_neworder_cop", + "path_settings": { "max_dist": 5 }, + "death_function": [ "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "SWARMS", + "BASHES", + "GROUP_BASH", + "FIREPROOF", + "HUMAN", + "PATH_AVOID_DANGER_1", + "PRIORITIZE_TARGETS", + "CLIMBS" + ] + }, + { + "id": "dks_neworder_knight", + "type": "MONSTER", + "name": { "str": "new order knight" }, + "description": "A human clad in strange plate armor at that pulses with laser etched runes, mixed with more 'modern' looking combat gear. Armed with a runed sword that can cut through many materials with ease, a shield emblazed with the symbol of a sun being pierced by a sword, and unshakable faith in whatever otherworldy god they venerate, they stride forward to put down enemies of the Order wherever they may be.", + "default_faction": "neworder", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ALIEN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 90, + "speed": 90, + "material": [ "flesh" ], + "symbol": "@", + "color": "light_gray", + "aggression": 15, + "morale": 100, + "vision_day": 30, + "melee_skill": 6, + "melee_dice": 3, + "melee_dice_sides": 4, + "melee_cut": 4, + "armor_bash": 16, + "armor_cut": 16, + "harvest": "dks_mhuman_chipped", + "special_attacks": [ [ "PARROT", 20 ], { "id": "slash" } ], + "death_drops": "dks_mon_neworder_knight", + "path_settings": { "max_dist": 10 }, + "death_function": [ "NORMAL" ], + "flags": [ + "SEES", + "HEARS", + "NO_BREATHE", + "WARM", + "SWARMS", + "BASHES", + "GROUP_BASH", + "FIREPROOF", + "ACIDPROOF", + "PATH_AVOID_DANGER_1", + "PRIORITIZE_TARGETS" + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json new file mode 100644 index 0000000000000..704a1f09fc71d --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_misc.json @@ -0,0 +1,205 @@ +[ + { + "id": "mon_dks_emissary", + "type": "MONSTER", + "name": { "str": "emissary", "str_pl": "emissaries" }, + "description": "A towering, metallic creature with a stunningly beautiful design and brilliantly shining etchings, standing atop three segmented legs. The tentacles that drift off of its central chassis are tipped with strange looking devices as it strides slowly across the shatterd landscape. This one seems less aggressive than those seen on the frontlines of the Arrival, studying its surroundings and probing things in the environment with a variety of internal tools. A sickeningly sweet gas hangs around it.", + "default_faction": "neworder", + "species": [ "ROBOT", "ALIEN" ], + "categories": [ "ALIEN" ], + "diff": 20, + "volume": "875000 ml", + "weight": "200 kg", + "hp": 250, + "speed": 75, + "material": [ "superalloy" ], + "symbol": "W", + "luminance": 60, + "color": "white", + "aggression": 40, + "morale": 10, + "melee_skill": 6, + "melee_dice": 5, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 90, + "armor_cut": 90, + "path_settings": { "max_dist": 30 }, + "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, + "fear_triggers": [ "HURT" ], + "special_attacks": [ + [ "PARROT", 20 ], + [ "TAZER", 20 ], + [ "RANGED_PULL", 20 ], + [ "GRAB_DRAG", 10 ], + { + "type": "gun", + "cooldown": 2, + "move_cost": 700, + "gun_type": "dks_mon_gasgun", + "max_ammo": 1000, + "ranges": [ [ 0, 30, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 500, + "targeting_sound": "the sound of pressurized gas hissing loudly.", + "targeting_volume": 40, + "description": "The emissary emits a stream of sedative gas!", + "no_ammo_sound": "a roar!" + } + ], + "death_function": [ "BROKEN" ], + "flags": [ + "SEES", + "HEARS", + "FIREPROOF", + "ACIDPROOF", + "GOODHEARING", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "ELECTRONIC", + "CLIMBS", + "GROUP_MORALE", + "PUSH_MON", + "PUSH_VEH", + "PRIORITIZE_TARGETS" + ] + }, + { + "id": "mon_dks_emissary_plague", + "type": "MONSTER", + "name": { "str": "emissary of pestilence", "str_pl": "emissaries of pestilence" }, + "description": "A towering, stories-tall metallic creature standing atop three long legs connected to a central chassis. It would be stunningly beautiful with its glowing golden inlays and celestial design, were it not for the gas that pours from its tentacle-mounted guns that despoils the landscape and makes your skin prickle just looking at its toxic, likely radioactive, glory. Its hums hauntingly as it moves and booming footsteps often heralded trouble to come during the Arrival, now is no different.", + "default_faction": "neworder", + "species": [ "ROBOT", "ALIEN" ], + "categories": [ "ALIEN" ], + "diff": 20, + "volume": "875000 ml", + "weight": "200 kg", + "hp": 250, + "speed": 75, + "material": [ "superalloy" ], + "symbol": "W", + "luminance": 60, + "color": "green", + "aggression": 40, + "morale": 10, + "melee_skill": 6, + "melee_dice": 5, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 90, + "armor_cut": 90, + "path_settings": { "max_dist": 30 }, + "emit_fields": [ { "emit_id": "emit_toxic_leak", "delay": "1 s" } ], + "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, + "fear_triggers": [ "HURT" ], + "special_attacks": [ + [ "PARROT", 20 ], + [ "SMASH", 30 ], + [ "LONGSWIPE", 20 ], + { + "type": "gun", + "cooldown": 2, + "move_cost": 700, + "gun_type": "dks_mon_radgun", + "max_ammo": 1000, + "ranges": [ [ 0, 20, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 500, + "targeting_sound": "an ominous rumble and hiss of gas.", + "targeting_volume": 40, + "description": "Putrid gas rolls across the landscape!", + "no_ammo_sound": "a roar!" + } + ], + "death_function": [ "BROKEN" ], + "flags": [ + "SEES", + "HEARS", + "FIREPROOF", + "ACIDPROOF", + "GOODHEARING", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "ELECTRONIC", + "CLIMBS", + "GROUP_MORALE", + "PUSH_MON", + "PUSH_VEH", + "PRIORITIZE_TARGETS" + ] + }, + { + "id": "mon_dks_emissary_flame", + "type": "MONSTER", + "name": { "str": "emissary of flame", "str_pl": "emissaries of flame" }, + "description": "Like all emissaries, this breathtaking metallic creature stands atop three long legs, with many more segmented tentacles eminating from its central chassis and a glowing halo about its head. This one is far more terrifying though, its claim to fame being some sort of high-intensity energy cannon, capable of rending whatever it touches asunder in an explosive burst of plasma and flame. Its unique chirping and booming footsteps often heralded trouble to come during the Arrival, and now is no different.", + "default_faction": "neworder", + "species": [ "ROBOT", "ALIEN" ], + "categories": [ "ALIEN" ], + "diff": 30, + "volume": "875000 ml", + "weight": "200 kg", + "hp": 250, + "speed": 75, + "material": [ "superalloy" ], + "symbol": "W", + "luminance": 60, + "color": "dark_gray", + "aggression": 40, + "morale": 10, + "melee_skill": 6, + "melee_dice": 5, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 90, + "armor_cut": 90, + "path_settings": { "max_dist": 30 }, + "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, + "fear_triggers": [ "HURT" ], + "special_attacks": [ + [ "PARROT", 20 ], + [ "SMASH", 30 ], + [ "LONGSWIPE", 20 ], + { + "type": "gun", + "cooldown": 2, + "move_cost": 700, + "gun_type": "dks_mon_devastator", + "max_ammo": 1000, + "ranges": [ [ 0, 30, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 600, + "targeting_sound": "the air pressure suddenly drop as the emissary charges its cannon!", + "targeting_volume": 40, + "description": "Sound returns as the emissary's cannon roars to life!!", + "no_ammo_sound": "a roar!" + } + ], + "death_function": [ "BROKEN" ], + "flags": [ + "SEES", + "HEARS", + "FIREPROOF", + "ACIDPROOF", + "GOODHEARING", + "BASHES", + "DESTROYS", + "NO_BREATHE", + "ELECTRONIC", + "CLIMBS", + "GROUP_MORALE", + "PUSH_MON", + "PUSH_VEH", + "PRIORITIZE_TARGETS" + ] + } +] From 30f54bd160fb96a0b287a3ac70ee9ec06fc7e905 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Fri, 6 Mar 2020 14:16:02 -0500 Subject: [PATCH 128/219] Dark Skies 8: Adds strays, lurker, enemies; updates modinfo (#38596) --- data/mods/Dark-Skies-Above/modinfo.json | 11 + .../monsters/mon_groups/stray_spawns.json | 349 ++++++++++++++++++ .../monsters/wild_aliens/lurker.json | 33 ++ .../monsters/wild_aliens/strays.json | 345 +++++++++++++++++ 4 files changed, 738 insertions(+) create mode 100644 data/mods/Dark-Skies-Above/modinfo.json create mode 100644 data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json create mode 100644 data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json create mode 100644 data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json diff --git a/data/mods/Dark-Skies-Above/modinfo.json b/data/mods/Dark-Skies-Above/modinfo.json new file mode 100644 index 0000000000000..6c86d0ba5a4ed --- /dev/null +++ b/data/mods/Dark-Skies-Above/modinfo.json @@ -0,0 +1,11 @@ +[ + { + "type": "MOD_INFO", + "ident": "darkskies", + "name": "Dark Skies Above", + "authors": [ "ephemeral_storyteller" ], + "description": "A total conversion that shifts the Cataclysm towards an XCOM 2 style alien occupation. Use other mods at your own risk!", + "category": "content", + "dependencies": [ "dda" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json b/data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json new file mode 100644 index 0000000000000..ed6a010724e27 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/mon_groups/stray_spawns.json @@ -0,0 +1,349 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 7, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 15, "pack_size": [ 25, 45 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 20, "pack_size": [ 35, 55 ] }, + { "monster": "dks_mon_stray", "freq": 65, "cost_multiplier": 0, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 75, "cost_multiplier": 0, "pack_size": [ 15, 30 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 5, "cost_multiplier": 10, "pack_size": [ 2, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 5, "cost_multiplier": 5, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 10 ] }, + { "monster": "dks_mon_stray_fast", "freq": 20, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_fast", "freq": 5, "cost_multiplier": 10, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 5, "pack_size": [ 1, 6 ] }, + { "monster": "dks_mon_stray_child", "freq": 40, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_eater", "freq": 5, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 15, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 10 } + ] + }, + { + "name": "GROUP_PARK_PLAYGROUND", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 295, "cost_multiplier": 1, "pack_size": [ 5, 12 ] }, + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 75, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_wretch", "freq": 50, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_burnt", "freq": 50, "cost_multiplier": 2 } + ] + }, + { + "name": "GROUP_PARK_DOG", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 125, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 125, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 1, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_eater", "freq": 5, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 20, "cost_multiplier": 2, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 2 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_HOUSE", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 70, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 65, "cost_multiplier": 2, "pack_size": [ 1, 4 ] }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_wretch", "freq": 15, "cost_multiplier": 2, "pack_size": [ 1, 3 ] } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_VANILLA", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_burnt", "freq": 60, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_wretch", "freq": 50, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 30, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_eater", "freq": 20, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_PHARM", + "//": "+13% fast", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_eater", "freq": 130, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_wretch", "freq": 130, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_burnt", "freq": 40, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 130, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ELECTRO", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_wretch", "freq": 130, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_burnt", "freq": 40, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 130, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_GROCERY", + "//": "+15% eater", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_eater", "freq": 280, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_wretch", "freq": 40, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_PUBLICWORKERS", + "default": "dks_mon_stray_fast", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 5 }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_wretch", "freq": 4, "cost_multiplier": 5 }, + { "monster": "dks_mon_stray_heavy", "freq": 200, "cost_multiplier": 5 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_MAYBE_ZOMBIE", + "//": "10% chance of a zombie", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 40, "cost_multiplier": 0, "pack_size": [ 1, 5 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 6, "cost_multiplier": 2, "pack_size": [ 1, 5 ] }, + { "monster": "dks_mon_stray_fast", "freq": 5, "cost_multiplier": 2, "pack_size": [ 1, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_child", "freq": 11, "cost_multiplier": 0 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_FAT_BASE", + "default": "mon_null", + "monsters": [ { "monster": "dks_mon_stray_eater", "freq": 40, "cost_multiplier": 2 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_FAT", + "default": "mon_null", + "monsters": [ { "monster": "dks_mon_stray_eater", "freq": 480, "cost_multiplier": 2 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_SCHOOL", + "default": "mon_null", + "//": "School monster spawns.", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 650, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 50, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray", "freq": 150, "cost_multiplier": 1 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_SMALL_STATION", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 55, "cost_multiplier": 4, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_fast", "freq": 50, "cost_multiplier": 5, "pack_size": [ 2, 4 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 25, "cost_multiplier": 0 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_LARGE_STATION", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 55, "cost_multiplier": 4, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_fast", "freq": 50, "cost_multiplier": 5, "pack_size": [ 2, 4 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 40, "cost_multiplier": 10 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_CHURCH_ZOMBIE", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 1, "cost_multiplier": 7, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 1, "cost_multiplier": 13, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 1, "cost_multiplier": 20, "pack_size": [ 35, 40 ] }, + { "monster": "dks_mon_stray_eater", "freq": 75, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray", "freq": 3, "cost_multiplier": 7, "pack_size": [ 3, 5 ] }, + { "monster": "dks_mon_stray_fast", "freq": 75, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_child", "freq": 75, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_burnt", "freq": 50, "cost_multiplier": 3 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 25, "cost_multiplier": 3 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_PRISON", + "default": "dks_mon_stray", + "monsters": [ { "monster": "dks_mon_stray", "freq": 350, "cost_multiplier": 0 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_COP", + "default": "dks_mon_stray_fast", + "monsters": [ + { "monster": "dks_mon_stray_fast", "freq": 100, "cost_multiplier": 0 }, + { "monster": "dks_mon_stray_heavy", "freq": 40, "cost_multiplier": 10 } + ] + }, + { + "name": "GROUP_MANSION", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 2, "pack_size": [ 2, 3 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 30, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child", "freq": 10, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 5, "cost_multiplier": 4 }, + { "monster": "dks_mon_stray_fast", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 2 ] } + ] + }, + { + "name": "GROUP_PANICROOM", + "type": "monstergroup", + "default": "dks_mon_stray_child", + "monsters": [ + { "monster": "dks_mon_stray_child", "freq": 100, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 30, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray", "freq": 20, "cost_multiplier": 1 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_HOSPITAL", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 7, "pack_size": [ 5, 10 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 15, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 20, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 75, "cost_multiplier": 0, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 5, "pack_size": [ 2, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 5, "cost_multiplier": 10, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 10 ] }, + { "monster": "dks_mon_stray_fast", "freq": 65, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_fast", "freq": 1, "cost_multiplier": 5, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 70, "cost_multiplier": 5, "pack_size": [ 1, 6 ] }, + { "monster": "dks_mon_stray_child", "freq": 40, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_eater", "freq": 5, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 15, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 1, "cost_multiplier": 10 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_STEEL_MILL", + "default": "mon_null", + "//": "Steel mill monster spawns.", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 7, "pack_size": [ 5, 10 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 15, "pack_size": [ 15, 20 ] }, + { "monster": "dks_mon_stray", "freq": 5, "cost_multiplier": 20, "pack_size": [ 25, 30 ] }, + { "monster": "dks_mon_stray", "freq": 75, "cost_multiplier": 0, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 5, "pack_size": [ 2, 5 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 5, "cost_multiplier": 10, "pack_size": [ 5, 15 ] }, + { "monster": "dks_mon_stray_wretch", "freq": 10, "cost_multiplier": 5, "pack_size": [ 1, 10 ] }, + { "monster": "dks_mon_stray_fast", "freq": 65, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_fast", "freq": 1, "cost_multiplier": 5, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_child", "freq": 20, "cost_multiplier": 5, "pack_size": [ 2, 8 ] }, + { "monster": "dks_mon_stray_child_burnt", "freq": 20, "cost_multiplier": 15, "pack_size": [ 1, 2 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 10, "cost_multiplier": 15, "pack_size": [ 1, 3 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 10, "cost_multiplier": 10 } + ] + }, + { + "name": "GROUP_MALL", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_eater", "freq": 40, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_child_burnt", "freq": 10, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_child", "freq": 20, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_burnt", "freq": 10, "cost_multiplier": 1 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_SEXSHOP_A", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 150, "cost_multiplier": 1 }, + { "monster": "dks_mon_stray_fast", "freq": 100, "cost_multiplier": 2 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_SEXSHOP_B", + "default": "mon_null", + "monsters": [ { "monster": "dks_mon_stray", "freq": 500, "cost_multiplier": 2 } ] + }, + { + "name": "GROUP_FIRE", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ + { "monster": "dks_mon_stray_fast", "freq": 100, "cost_multiplier": 2, "pack_size": [ 3, 5 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 40, "cost_multiplier": 1 } + ] + }, + { + "name": "GROUP_PLAIN", + "type": "monstergroup", + "default": "dks_mon_stray", + "monsters": [ { "monster": "dks_mon_stray", "freq": 40, "cost_multiplier": 1 } ] + }, + { + "name": "GROUP_HOTEL_POOL", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray", "freq": 50, "cost_multiplier": 10, "pack_size": [ 3, 8 ] }, + { "monster": "dks_mon_stray_child", "freq": 35, "cost_multiplier": 1 } + ] + }, + { + "name": "GROUP_HOTEL_GYM", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 30, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray_fast", "freq": 15, "cost_multiplier": 8, "pack_size": [ 2, 6 ] }, + { "monster": "dks_mon_stray_heavy", "freq": 8, "cost_multiplier": 3 } + ] + }, + { + "name": "GROUP_POOL_NOKIDS", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "dks_mon_stray", "freq": 100, "cost_multiplier": 2 }, + { "monster": "dks_mon_stray", "freq": 50, "cost_multiplier": 10, "pack_size": [ 3, 8 ] } + ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json b/data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json new file mode 100644 index 0000000000000..4c084d345e584 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/wild_aliens/lurker.json @@ -0,0 +1,33 @@ +[ + { + "id": "dks_mon_lurker_sewer", + "type": "MONSTER", + "name": { "str": "sewer lurker" }, + "description": "A dripping creature, a writhing mass of tentacles attached to a gnashing maw, this thing seems to have found its home among trash and sewage. It is an ambush predator, prefering to lurk just beneath the cloudy water before something comes close enough to snag.", + "default_faction": "lurker", + "bodytype": "spider", + "categories": [ "ALIEN" ], + "species": [ "WILDALIEN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 150, + "speed": 120, + "material": [ "flesh" ], + "symbol": "&", + "color": "green_white", + "aggression": -5, + "morale": 100, + "melee_skill": 7, + "melee_dice": 4, + "melee_dice_sides": 6, + "melee_cut": 0, + "dodge": 5, + "armor_bash": 6, + "armor_cut": 2, + "harvest": "zombie_leather", + "special_attacks": [ [ "GRAB", 7 ], [ "TENTACLE", 5 ] ], + "anger_triggers": [ "PLAYER_CLOSE", "PLAYER_WEAK" ], + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "SWIMS", "AQUATIC", "POISON", "HARDTOSHOOT" ] + } +] diff --git a/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json b/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json new file mode 100644 index 0000000000000..3287f540948f4 --- /dev/null +++ b/data/mods/Dark-Skies-Above/monsters/wild_aliens/strays.json @@ -0,0 +1,345 @@ +[ + { + "id": "dks_mon_stray", + "type": "MONSTER", + "name": "stray", + "description": "The pitifully thin body of what once was a human, ruined beyond recognition by whatever foul weapons were used on them during the Arrival. Now suspended somewhere between life and death at the hands of its own rogue biology, this creature wanders the ruins of its former hometown, its hollow eyes glowing with pinpricks of hateful energy.", + "looks_like": "mon_skeleton", + "default_faction": "stray", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 50, + "speed": 65, + "material": [ "flesh" ], + "symbol": "S", + "color": "white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 2, + "melee_dice_sides": 3, + "melee_cut": 1, + "vision_night": 3, + "harvest": "mutant_human", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ { "type": "bite", "cooldown": 5 }, [ "GRAB", 7 ], [ "scratch", 20 ] ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 10, "into": "DKS_GROUP_STRAY_UPGRADE" }, + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "STUMBLES", + "POISON", + "BLEED", + "HUMAN", + "FILTHY", + "BASHES", + "REVIVES", + "GROUP_BASH", + "PUSH_MON" + ] + }, + { + "id": "dks_mon_stray_eater", + "type": "MONSTER", + "name": "hungy stray", + "description": "A hunger-bloated body with a distended jaw, a pitiful figure but no less hateful than its friends. It lets out bloodcurdling howls of want and constantly regurgitates the contents of its stomach, only to seek another meal in some sort of mockery of human eating patterns.", + "looks_like": "mon_boomer", + "default_faction": "stray", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 50, + "speed": 55, + "material": [ "flesh" ], + "symbol": "S", + "color": "pink_white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 2, + "melee_dice_sides": 3, + "melee_cut": 1, + "armor_bash": 5, + "armor_cut": 3, + "vision_night": 3, + "harvest": "zombie", + "path_settings": { "max_dist": 2 }, + "regenerates": 10, + "special_attacks": [ [ "BOOMER", 20 ], { "type": "bite", "cooldown": 2, "accuracy": 3, "no_infection_chance": 10 }, [ "SHRIEK", 10 ] ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "BOOMER" ], + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "STUMBLES", + "POISON", + "BILE_BLOOD", + "KEENNOSE", + "FILTHY", + "REVIVES", + "BASHES", + "GROUP_BASH", + "PUSH_MON" + ] + }, + { + "id": "dks_mon_stray_fast", + "type": "MONSTER", + "name": "stray sprinter", + "description": "This once-shambling human body has become subtly toned, and though its still appears caught between putrefying on the spot and living, it now moves with a hint of animal cunning. A tightened mouth surrounds gnashing teeth as it hunts for fresh meat with more intensity than those around it.", + "default_faction": "stray", + "looks_like": "mon_zombie_runner", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 60, + "speed": 105, + "material": [ "flesh" ], + "symbol": "S", + "color": "light_gray", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 4, + "melee_dice_sides": 3, + "melee_cut": 3, + "dodge": 1, + "vision_night": 3, + "harvest": "mutant_human", + "path_settings": { "max_dist": 5 }, + "regenerates": 1, + "special_attacks": [ + [ "scratch", 10 ], + { + "type": "bite", + "cooldown": 5, + "damage_max_instance": [ { "damage_type": "stab", "amount": 10, "armor_multiplier": 0.7 } ] + } + ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "NORMAL" ], + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "WARM", + "HUMAN", + "BASHES", + "POISON", + "PUSH_MON", + "REVIVES", + "PATH_AVOID_FALL", + "FILTHY", + "BLEED" + ] + }, + { + "id": "dks_mon_stray_heavy", + "type": "MONSTER", + "name": "stray bruiser", + "description": "Swollen with muscle beyond what the human form would have normally allowed, this festering mass of raw power pulverizes whatever it comes across with the thick cudgels that were once its hands. Its evolved regenative capacity seems to have granted it an outer shell now a protective layer of scar tissue, like a cocoon. Tiny eyes peer out from behind the thick layers of callused flesh on its face, but its ears are now large holes in the sides of its head, suggesting it now has other ways of finding you.", + "default_faction": "stray", + "looks_like": "mon_skeleton_brute", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 2, + "volume": "62500 ml", + "weight": "81500 g", + "hp": 100, + "speed": 90, + "material": [ "flesh" ], + "symbol": "S", + "color": "red_white", + "aggression": 100, + "morale": 100, + "melee_skill": 5, + "melee_dice": 3, + "melee_dice_sides": 8, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "vision_day": 15, + "vision_night": 1, + "harvest": "zombie", + "path_settings": { "max_dist": 2 }, + "regenerates": 5, + "special_attacks": [ [ "SMASH", 30 ], [ "GRAB", 7 ] ], + "death_drops": "mon_zombie_hulk_death_drops", + "death_function": [ "NORMAL" ], + "burn_into": "dks_mon_stray_burnt", + "flags": [ + "SEES", + "HEARS", + "GOODHEARING", + "SMELLS", + "STUMBLES", + "WARM", + "BASHES", + "GROUP_BASH", + "REVIVES", + "POISON", + "PUSH_MON", + "PUSH_VEH", + "ATTACKMON", + "FILTHY" + ] + }, + { + "id": "dks_mon_stray_burnt", + "type": "MONSTER", + "name": "stray husk", + "description": "The charred body of a human, burned beyond recognition. Though its skin is slowly regenerating back to its base state, the charcoal-like shell that has formed around its skin and its spikes make for decent armor and weaponry. If killed now, it likely won't be coming back, its regenative properties overwhelmed.", + "default_faction": "stray", + "looks_like": "mon_zombie_scorched", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 40, + "speed": 60, + "material": [ "flesh" ], + "symbol": "S", + "color": "i_white", + "aggression": 100, + "morale": 100, + "melee_skill": 2, + "melee_dice": 2, + "melee_dice_sides": 2, + "melee_cut": 4, + "armor_bash": 2, + "armor_cut": 9, + "armor_acid": 3, + "armor_fire": 15, + "vision_day": 10, + "vision_night": 3, + "harvest": "mutant_human", + "emit_fields": [ "emit_smaller_smoke_plume" ], + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ [ "GRAB", 7 ] ], + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 9, "into": "dks_mon_stray" }, + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "POISON", "BLEED", "FILTHY" ] + }, + { + "id": "dks_mon_stray_child", + "type": "MONSTER", + "name": "stray waif", + "description": "If not for the painfully pale skin and heavily sunken eyes, it would be easy to mistake this little figure for a normal child. Unfortunately, whatever terrible weapon that the aliens used on much of the population has been no kinder to them, and the same hateful malice lurks deep within the dark of their eye-sockets. Still, the idea of putting it down twists your gut in some sort of primal way.", + "default_faction": "stray", + "looks_like": "mon_zombie_waif", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 35, + "speed": 65, + "material": [ "flesh" ], + "symbol": "s", + "color": "white", + "aggression": 80, + "morale": 100, + "melee_skill": 2, + "melee_dice": 2, + "melee_dice_sides": 2, + "melee_cut": 1, + "dodge": 2, + "armor_cut": 5, + "vision_day": 30, + "vision_night": 5, + "harvest": "mutant_human", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ [ "scratch", 10 ] ], + "death_drops": { "subtype": "collection", "groups": [ [ "mon_zombie_hulk_death_drops", 100 ], [ "child_items", 65 ] ] }, + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 12, "into": "dks_mon_stray_wretch" }, + "burn_into": "dks_mon_stray_child_burnt", + "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "HUMAN", "WARM", "BLEED", "GUILT", "POISON", "REVIVES", "FILTHY" ] + }, + { + "id": "dks_mon_stray_child_burnt", + "type": "MONSTER", + "name": "stray tinder", + "description": "What remains of a thoroughly charred child, grimacing features just intact enough to make your gut churn. Even now, its regenative properties work to repair its body back to its former self - given enough time. If killed like this, it probably won't be coming back - its regentative properties are greatly weakened now.", + "default_faction": "stray", + "looks_like": "mon_zombie_child_scorched", + "bodytype": "human", + "species": [ "ZOMBIE", "HUMAN" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 15, + "speed": 60, + "material": [ "flesh" ], + "symbol": "s", + "color": "i_white", + "aggression": 100, + "morale": 100, + "melee_skill": 2, + "melee_dice": 1, + "melee_dice_sides": 3, + "melee_cut": 5, + "armor_bash": 4, + "armor_cut": 5, + "armor_acid": 3, + "armor_fire": 15, + "vision_day": 10, + "vision_night": 3, + "harvest": "mutant_human", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "emit_fields": [ "emit_smaller_smoke_plume" ], + "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 9, "into": "dks_mon_stray_child" }, + "flags": [ "SEES", "HEARS", "STUMBLES", "POISON", "GUILT", "FILTHY" ] + }, + { + "id": "dks_mon_stray_wretch", + "type": "MONSTER", + "name": "stray wretch", + "description": "This blur of jagged limbs and hair might have been a housepet at some point - or, forbid, perhaps even a child. Regardless of its origin, this creature has been thoroughly twisted into something you'd expect to see in an episode of sleep paralysis.", + "default_faction": "stray", + "looks_like": "mon_dog_skeleton", + "bodytype": "dog", + "species": [ "ZOMBIE" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 25, + "speed": 110, + "material": [ "flesh" ], + "symbol": "s", + "color": "white", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 1, + "melee_dice_sides": 6, + "melee_cut": 2, + "dodge": 3, + "vision_night": 4, + "harvest": "zombie_fur", + "path_settings": { "max_dist": 2 }, + "regenerates": 1, + "special_attacks": [ { "type": "bite", "cooldown": 5 }, { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true } ], + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "BLEED", "HARDTOSHOOT", "REVIVES", "POISON", "CLIMBS", "FILTHY" ] + } +] From 152373a6526fb29d88986fa631a605850de7e9c4 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 8 Mar 2020 12:13:51 -0400 Subject: [PATCH 129/219] Dark Skies: Spell Fixes (#38643) --- .../Dark-Skies-Above/monsters/new_order/neworder_loworder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json index 774050870c4fa..ecc4636791d99 100644 --- a/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json +++ b/data/mods/Dark-Skies-Above/monsters/new_order/neworder_loworder.json @@ -73,7 +73,7 @@ "armor_bash": 8, "armor_cut": 8, "harvest": "dks_mhuman_chipped", - "special_attacks": [ [ "PARROT", 20 ], { "type": "spell", "spell_id": "dks_monspell_panic", "cooldown": 10 } ], + "special_attacks": [ [ "PARROT", 20 ], { "type": "spell", "spell_data": { "id": "dks_monspell_panic" }, "cooldown": 10 } ], "death_drops": "dks_mon_neworder_cop", "path_settings": { "max_dist": 5 }, "death_function": [ "NORMAL" ], From 62d7f202035f45841f68873a11d5a81ba008043e Mon Sep 17 00:00:00 2001 From: curstwist <39442864+curstwist@users.noreply.github.com> Date: Sun, 8 Mar 2020 12:25:41 -0400 Subject: [PATCH 130/219] [Magiclysm] Add Magiclysm academy (#38511) --- .../mods/Magiclysm/itemgroups/itemgroups.json | 465 ++++++++++++- data/mods/Magiclysm/items/books_lore.json | 50 ++ data/mods/Magiclysm/items/spell_scrolls.json | 94 +++ data/mods/Magiclysm/items/spellbooks.json | 23 + .../Magiclysm/worldgen/magic_academy.json | 617 ++++++++++++++++++ .../Magiclysm/worldgen/magic_basement.json | 2 +- .../worldgen/multitile_city_buildings.json | 17 + .../Magiclysm/worldgen/overmap_terrain.json | 89 +++ .../Magiclysm/worldgen/regional_overlay.json | 5 +- 9 files changed, 1336 insertions(+), 26 deletions(-) create mode 100644 data/mods/Magiclysm/items/books_lore.json create mode 100644 data/mods/Magiclysm/worldgen/magic_academy.json diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 2a4f1a8202ee1..45016883441b1 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -135,8 +135,8 @@ "items": [ { "group": "potions_common", "prob": 80 }, { "group": "alchemy_items", "prob": 30 }, - [ "crystallized_mana", 25 ], - { "item": "small_mana_crystal", "prob": 20, "charges-min": 5, "charges-max": 50 } + [ "crystallized_mana", 55 ], + { "item": "small_mana_crystal", "prob": 40, "charges-min": 5, "charges-max": 50 } ] }, { @@ -568,17 +568,19 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_tokens_tool", "prob": 20 }, - { "group": "enchanted_tokens_weapon", "prob": 1 }, - { "group": "enchanted_rings_common", "prob": 15 }, - { "group": "enchanted_rings_uncommon", "prob": 1 }, - { "group": "enchanted_wands_minor", "prob": 5 }, - { "group": "enchanted_masks", "prob": 1 }, - { "group": "magic_shop_potions", "prob": 20 }, + { "group": "enchanted_tokens_tool", "prob": 30 }, + { "group": "enchanted_tokens_weapon", "prob": 3 }, + { "group": "enchanted_rings_common", "prob": 20 }, + { "group": "enchanted_rings_uncommon", "prob": 5 }, + { "group": "enchanted_wands_minor", "prob": 10 }, + { "group": "enchanted_masks", "prob": 2 }, + { "group": "magic_shop_potions", "prob": 40 }, { "group": "spellbook_loot_1", "prob": 30 }, - { "group": "magic_CBM", "prob": 1 }, - [ "crystallized_mana", 10 ], - { "item": "small_mana_crystal", "prob": 20, "charges-min": 5, "charges-max": 50 } + { "group": "magic_CBM", "prob": 2 }, + { "item": "lair_map", "prob": 20 }, + { "item": "retreat_map", "prob": 30 }, + [ "crystallized_mana", 50 ], + { "item": "small_mana_crystal", "prob": 40, "charges-min": 5, "charges-max": 50 } ] }, { @@ -587,9 +589,9 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_bracers_lesser", "prob": 20 }, - { "group": "enchanted_boots", "prob": 5 }, - { "group": "enchanted_belts", "prob": 5 } + { "group": "enchanted_bracers_lesser", "prob": 25 }, + { "group": "enchanted_boots", "prob": 7 }, + { "group": "enchanted_belts", "prob": 7 } ] }, { @@ -598,9 +600,9 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_bracers_lesser", "prob": 20 }, - { "group": "enchanted_worn_items", "prob": 10 }, - { "group": "enchanted_melee_weapons_plus1", "prob": 2 }, + { "group": "enchanted_bracers_lesser", "prob": 25 }, + { "group": "enchanted_worn_items", "prob": 15 }, + { "group": "enchanted_melee_weapons_plus1", "prob": 3 }, { "group": "enchanted_small_items", "prob": 1 } ] }, @@ -610,12 +612,427 @@ "type": "item_group", "subtype": "distribution", "items": [ - { "group": "enchanted_combat_items", "prob": 20 }, - { "group": "enchanted_misc", "prob": 40 }, - { "group": "enchanted_rings_unusual", "prob": 10 }, - { "group": "enchanted_rings_rare", "prob": 20 }, - { "group": "enchanted_wands_greater", "prob": 20 }, - { "group": "enchanted_wands_lesser", "prob": 10 } + { "group": "enchanted_combat_items", "prob": 40 }, + { "group": "enchanted_misc", "prob": 50 }, + { "group": "enchanted_rings_unusual", "prob": 20 }, + { "group": "enchanted_rings_rare", "prob": 30 }, + { "group": "enchanted_wands_greater", "prob": 30 }, + { "group": "enchanted_wands_lesser", "prob": 20 } + ] + }, + { + "id": "stormshaper_items", + "//": "A distribution of magical items for stormshaper themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_stormshaper_wall_of_fog", "prob": 50 }, + { "item": "spell_scroll_lightning_blast", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "spell_scroll_jolt", "prob": 50 }, + { "item": "spell_scroll_lightning_bolt", "prob": 50 }, + { "item": "spell_scroll_windstrike", "prob": 50 }, + { "item": "spell_scroll_windrun", "prob": 50 } + ], + "prob": 40 + }, + { + "distribution": [ + { "item": "tome_of_storms", "prob": 5 }, + { "item": "spell_scroll_storm_hammer", "prob": 50 }, + { "item": "spell_scroll_stormshaper_ionization", "prob": 50 }, + { "item": "lightning_storm_scroll", "prob": 10 } + ], + "prob": 10 + } + ] + }, + { + "id": "magus_items", + "//": "A distribution of magical items for magus themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "wizard_beginner", "prob": 30 }, + { "item": "wizard_utility", "prob": 20 }, + { "item": "spell_scroll_magic_missile", "prob": 70 }, + { "item": "spell_scroll_phase_door", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "wizard_advanced", "prob": 20 }, + { "item": "spell_scroll_magus_mana_bolt", "prob": 50 }, + { "item": "spell_scroll_magus_haste", "prob": 50 }, + { "item": "spell_scroll_magus_mana_beam", "prob": 50 }, + { "item": "spell_scroll_magus_escape", "prob": 50 }, + { "item": "spell_scroll_cats_grace", "prob": 50 }, + { "item": "spell_scroll_eagles_sight", "prob": 50 }, + { "item": "spell_scroll_ogres_strength", "prob": 50 }, + { "item": "spell_scroll_foxs_cunning", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "magus_spellbook_move", "prob": 25 }, + { "item": "magus_spellbook", "prob": 25 }, + { "item": "spell_scroll_magus_mana_blast", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "item": "recovery_spellbook", "prob": 10 }, { "item": "spell_scroll_invisibility", "prob": 50 } ], + "prob": 5 + } + ] + }, + { + "id": "animist_items", + "//": "A distribution of magical items for animist themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_smite", "prob": 50 }, + { "item": "spell_scroll_summon_zombie", "prob": 50 }, + { "item": "spell_scroll_necrotic_gaze", "prob": 50 }, + { "item": "spell_scroll_summon_wisps", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ { "item": "priest_advanced", "prob": 10 }, { "item": "spell_scroll_summon_skeleton", "prob": 50 } ], + "prob": 35 + }, + { + "distribution": [ + { "item": "recovery_spellbook", "prob": 5 }, + { "item": "winter_grasp", "prob": 10 }, + { "item": "spell_scroll_recover_mana", "prob": 50 }, + { "item": "spell_scroll_summon_decayed_pouncer", "prob": 50 }, + { "item": "spell_scroll_recover_pain", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ + { "item": "animist_doll_skeleton", "prob": 10 }, + { "item": "animist_doll_zombie", "prob": 20 }, + { "item": "animist_doll_decayed_pouncer", "prob": 3 } + ], + "prob": 20 + } + ] + }, + { + "id": "kelvinist_items", + "//": "A distribution of magical items for kelvinist themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ { "item": "spell_scroll_create_lighter", "prob": 50 }, { "item": "spell_scroll_chilling_touch", "prob": 50 } ], + "prob": 45 + }, + { + "distribution": [ + { "item": "wizard_utility", "prob": 10 }, + { "item": "spell_scroll_point_flare", "prob": 50 }, + { "item": "spell_scroll_ice_spike", "prob": 50 }, + { "item": "spell_scroll_burning_hands", "prob": 50 }, + { "item": "spell_scroll_frost_spray", "prob": 50 }, + { "item": "spell_scroll_glide_ice", "prob": 50 }, + { "item": "spell_scroll_ice_shield", "prob": 50 }, + { "item": "spell_scroll_frost_armor", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "wizard_advanced", "prob": 5 }, + { "item": "pyro", "prob": 5 }, + { "item": "spell_scroll_fireball", "prob": 10 }, + { "item": "spell_scroll_recover_bionic_power", "prob": 50 }, + { "item": "spell_scroll_cone_cold", "prob": 50 }, + { "item": "spell_scroll_hoary_blast", "prob": 50 } + ], + "prob": 10 + } + ] + }, + { + "id": "technomancer_items", + "//": "A distribution of magical items for technomancer themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "priest_beginner", "prob": 20 }, + { "item": "techno_idiots", "prob": 20 }, + { "item": "spell_scroll_x-ray", "prob": 50 }, + { "item": "spell_scroll_bless", "prob": 50 }, + { "item": "spell_scroll_create_atomic_lamp", "prob": 50 }, + { "item": "spell_scroll_taze", "prob": 50 }, + { "item": "spell_scroll_laze", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "priest_advanced", "prob": 20 }, + { "item": "techno_fundamentals", "prob": 20 }, + { "item": "spell_scroll_quantum_tunnel_lesser", "prob": 50 }, + { "item": "spell_scroll_holy_blade", "prob": 50 }, + { "item": "spell_scroll_spirit_armor", "prob": 50 }, + { "item": "spell_scroll_synaptic_stimulation", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "techno_em", "prob": 5 }, + { "item": "spell_scroll_holographic_transposition", "prob": 10 }, + { "item": "spell_scroll_recover_bionic_power", "prob": 50 }, + { "item": "spell_scroll_animated_blade", "prob": 50 }, + { "item": "spell_scroll_mirror_image", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "item": "recovery_spellbook", "prob": 10 }, { "item": "spell_scroll_invisibility", "prob": 50 } ], + "prob": 5 + }, + { "group": "magic_CBM", "prob": 2 } + ] + }, + { + "id": "earthshaper_items", + "//": "A distribution of magical items for earthshaper themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_stonefist", "prob": 50 }, + { "item": "spell_scroll_eshaper_piercing_bolt", "prob": 50 }, + { "item": "spell_scroll_eshaper_rockbolt", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "spell_scroll_seismic_stomp", "prob": 50 }, + { "item": "spell_scroll_clairvoyance", "prob": 50 }, + { "item": "spell_scroll_eshaper_shardspray", "prob": 50 }, + { "item": "spell_scroll_earthshaper_stoneskin", "prob": 50 }, + { "item": "spell_scroll_earthshaper_pillar", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "recovery_spellbook", "prob": 5 }, + { "item": "eshaper_spellbook", "prob": 10 }, + { "item": "spell_scroll_recover_stamina", "prob": 50 }, + { "item": "spell_scroll_eshaper_shardstorm", "prob": 50 }, + { "item": "spell_scroll_lava_bomb", "prob": 50 } + ], + "prob": 10 + } + ] + }, + { + "id": "biomancer_items", + "//": "A distribution of magical items for biomancer themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "priest_beginner", "prob": 30 }, + { "item": "spell_scroll_light_healing", "prob": 50 }, + { "item": "spell_scroll_bio_acidicspray", "prob": 50 }, + { "item": "spell_scroll_biomancer_paralytic_dart", "prob": 50 }, + { "item": "spell_scroll_biomancer_visceral_projection", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "wizard_utility", "prob": 20 }, + { "item": "spell_scroll_pain_split", "prob": 50 }, + { "item": "spell_scroll_bio_grotesque", "prob": 50 }, + { "item": "spell_scroll_biomancer_coagulant_weave", "prob": 50 }, + { "item": "spell_scroll_bio_fleshpouch", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "wizard_advanced", "prob": 10 }, + { "item": "biomancer_spellbook", "prob": 10 }, + { "item": "spell_scroll_vicious_tentacle", "prob": 50 }, + { "item": "spell_scroll_bio_bonespear", "prob": 50 } + ], + "prob": 10 + } + ] + }, + { + "id": "druid_items", + "//": "A distribution of magical items for druid themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "spell_scroll_druid_woodshaft", "prob": 30 }, + { "item": "summon_scroll_smudged", "prob": 2 }, + { "item": "spell_scroll_summon_cats", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "druid_spellbook", "prob": 20 }, + { "item": "spell_scroll_druid_veggrasp", "prob": 100 }, + { "item": "spell_scroll_druid_naturebow1", "prob": 100 }, + { "item": "spell_scroll_druid_rootstrike", "prob": 100 }, + { "item": "spell_scroll_purification_seed", "prob": 100 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "recovery_spellbook", "prob": 10 }, + { "item": "spell_scroll_recover_fatigue", "prob": 100 }, + { "item": "spell_scroll_druidic_regrowth", "prob": 100 }, + { "item": "spell_scroll_druidic_healing", "prob": 100 } + ], + "prob": 10 + } ] + }, + { + "id": "technomancer_items", + "//": "A distribution of magical items for technomancer themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { + "distribution": [ + { "item": "priest_beginner", "prob": 20 }, + { "item": "techno_idiots", "prob": 20 }, + { "item": "spell_scroll_x-ray", "prob": 50 }, + { "item": "spell_scroll_bless", "prob": 50 }, + { "item": "spell_scroll_create_atomic_lamp", "prob": 50 }, + { "item": "spell_scroll_taze", "prob": 50 }, + { "item": "spell_scroll_laze", "prob": 50 } + ], + "prob": 45 + }, + { + "distribution": [ + { "item": "priest_advanced", "prob": 20 }, + { "item": "techno_fundamentals", "prob": 20 }, + { "item": "spell_scroll_quantum_tunnel_lesser", "prob": 50 }, + { "item": "spell_scroll_holy_blade", "prob": 50 }, + { "item": "spell_scroll_spirit_armor", "prob": 50 }, + { "item": "spell_scroll_synaptic_stimulation", "prob": 50 } + ], + "prob": 35 + }, + { + "distribution": [ + { "item": "techno_em", "prob": 5 }, + { "item": "spell_scroll_holographic_transposition", "prob": 10 }, + { "item": "spell_scroll_recover_bionic_power", "prob": 50 }, + { "item": "spell_scroll_animated_blade", "prob": 50 }, + { "item": "spell_scroll_mirror_image", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "item": "recovery_spellbook", "prob": 10 }, { "item": "spell_scroll_invisibility", "prob": 50 } ], + "prob": 5 + }, + { "group": "magic_CBM", "prob": 2 } + ] + }, + { + "id": "classless_items", + "//": "A distribution of magical items for classless themed spaces.", + "type": "item_group", + "subtype": "collection", + "items": [ + { "group": "enchanted_tokens_tool", "prob": 15 }, + { "group": "enchanted_tokens_weapon", "prob": 5 }, + { "group": "potions_common", "prob": 35 }, + { + "distribution": [ + { "group": "enchanted_wands_lesser", "prob": 15 }, + { "group": "enchanted_combat_items", "prob": 5 }, + { "group": "enchanted_worn_items", "prob": 2 } + ], + "prob": 15 + }, + { + "distribution": [ + { "item": "priest_beginner", "prob": 20 }, + { "item": "wizard_beginner", "prob": 20 }, + { "item": "spell_scroll_create_atomic_light", "prob": 50 }, + { "item": "spell_scroll_ethereal_grasp", "prob": 50 }, + { "item": "spell_scroll_crystallize_mana", "prob": 50 }, + { "item": "spell_scroll_blinding_flash", "prob": 50 } + ], + "prob": 50 + }, + { + "distribution": [ + { "item": "wizard_utility", "prob": 10 }, + { "item": "spell_scroll_protection_aura", "prob": 50 }, + { "item": "spell_scroll_dark_sight", "prob": 30 }, + { "item": "spell_scroll_megablast", "prob": 30 } + ], + "prob": 40 + }, + { + "distribution": [ + { "item": "light_manipulation_spellbook", "prob": 5 }, + { "item": "translocate_spellbook", "prob": 2 }, + { "item": "spell_scroll_obfuscated_body", "prob": 50 } + ], + "prob": 10 + }, + { + "distribution": [ { "group": "enchanted_rings_common", "prob": 30 }, { "group": "enchanted_rings_uncommon", "prob": 10 } ], + "prob": 40 + }, + [ "crystallized_mana", 50 ], + [ "copper_circlet", 10 ], + { "item": "small_mana_crystal", "prob": 40, "charges-min": 5, "charges-max": 50 } + ] + }, + { + "type": "item_group", + "id": "academy_lore", + "items": [ [ "retreat_map", 100 ] ] + }, + { + "type": "item_group", + "id": "magic_basement_photo", + "items": [ [ "wizard_photo", 100 ] ] } ] diff --git a/data/mods/Magiclysm/items/books_lore.json b/data/mods/Magiclysm/items/books_lore.json new file mode 100644 index 0000000000000..858ce1fd3fdf6 --- /dev/null +++ b/data/mods/Magiclysm/items/books_lore.json @@ -0,0 +1,50 @@ +[ + { + "id": "retreat_map", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": "vacation brochure", + "description": "This is a glossy brochure encouraging students to book vactaions at a lake retreat or remote cabin. The brochure includes lush photographs of a tower on an island and a remote looking cabin in the woods. It includes a map of the areas.", + "color": "white", + "use_action": { + "type": "reveal_map", + "radius": 185, + "terrain": [ "lake_retreat_ground", "magic_cabin" ], + "message": "You add the locations to your map." + } + }, + { + "id": "lair_map", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": "lair map", + "description": "This is an well worn map. It has pictures of fantastical beasts embellishing the carefully drawn map markers.", + "color": "white", + "use_action": { + "type": "reveal_map", + "radius": 185, + "terrain": [ + "demon_spider_lair", + "black_dragon_lair_z-0_NW", + "black_dragon_lair_z-0_NE", + "black_dragon_lair_z-0_SW", + "black_dragon_lair_z-0_SE" + ], + "message": "You add the locations to your map." + } + }, + { + "id": "wizard_photo", + "type": "GENERIC", + "//": "Unique item for magic_basement.", + "category": "other", + "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, + "price": 800, + "material": [ "paper" ], + "symbol": "*", + "color": "light_gray" + } +] diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index b64a3b51f6cba..adacd77bf014b 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -14,6 +14,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_crystallize_mana", + "//": "Classless spell", "name": { "str": "Scroll of Crystallize Mana", "str_pl": "Scrolls of Crystallize Mana" }, "description": "A proper wizard is always prepared, crystallize your mana for the future!", "use_action": { "type": "learn_spell", "spells": [ "crystallize_mana" ] } @@ -22,6 +23,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_dark_sight", + "//": "Classless spell", "name": { "str": "Scroll of Dark Sight", "str_pl": "Scrolls of Dark Sight" }, "description": "The darkness holds no secrets for the arcane. Adjust your sight to see in perfect darkness!", "use_action": { "type": "learn_spell", "spells": [ "dark_sight" ] } @@ -30,6 +32,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_invisibility", + "//": "Technomancer spell", "name": { "str": "Scroll of Invisibility", "str_pl": "Scrolls of Invisibility" }, "description": "The light can not interact with you unless you want it to. Become invisible!", "use_action": { "type": "learn_spell", "spells": [ "invisibility" ] } @@ -38,6 +41,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_obfuscated_body", + "//": "Classless spell", "name": { "str": "Scroll of Obfuscated Body", "str_pl": "Scrolls of Obfuscated Body" }, "description": "A magical aura distorts light around your body, making it easier to dodge enemy attacks.", "use_action": { "type": "learn_spell", "spells": [ "obfuscated_body" ] } @@ -46,6 +50,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_holographic_transposition", + "//": "Technomancer spell", "name": { "str": "Scroll of Holographic Transposition", "str_pl": "Scrolls of Holographic Transposition" }, "description": "Allows you to swap places with a previously existing holographic image of yourself. If the universe itself can't tell you apart, who could?", "use_action": { "type": "learn_spell", "spells": [ "holographic_transposition" ] } @@ -54,6 +59,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_smite", + "//": "Animist spell", "name": { "str": "Scroll of Smite", "str_pl": "Scrolls of Smite" }, "description": "Evil has become pervasive throughout the world. Let your power be the light that shines in the darkness!", "use_action": { "type": "learn_spell", "spells": [ "smite" ] } @@ -62,6 +68,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_mana", + "//": "Animist spell", "name": { "str": "Scroll of Life Conversion", "str_pl": "Scrolls of Life Conversion" }, "description": "You channel your life force itself into your spiritual energy. You spend hp to regain mana.", "use_action": { "type": "learn_spell", "spells": [ "recover_mana" ] } @@ -70,6 +77,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_pain", + "//": "Animist spell", "name": { "str": "Scroll of Mind Over Pain", "str_pl": "Scrolls of Mind Over Pain" }, "description": "With an intense ritual that resembles crossfit, you manage to put some of your pain at bay.", "use_action": { "type": "learn_spell", "spells": [ "recover_pain" ] } @@ -78,6 +86,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_zombie", + "//": "Animist spell", "name": { "str": "Scroll of Summon Zombie", "str_pl": "Scrolls of Summon Zombie" }, "description": "An ethereal-looking zombie rises from the depths of the earth to fight for you. You may be able to summon more with a higher level in this spell.", "use_action": { "type": "learn_spell", "spells": [ "summon_zombie" ] } @@ -86,6 +95,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_skeleton", + "//": "Animist spell", "name": { "str": "Scroll of Summon Skeleton", "str_pl": "Scrolls of Summon Skeleton" }, "description": "A ghostly skeleton rises from the depths of the earth to fight for you. You may be able to summon more with a higher level in this spell.", "use_action": { "type": "learn_spell", "spells": [ "summon_skeleton" ] } @@ -94,6 +104,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_decayed_pouncer", + "//": "Animist spell", "name": { "str": "Scroll of Summon Decayed Pouncer", "str_pl": "Scrolls of Summon Decayed Pouncer" }, "description": "A decrepit looking large cat rises from the depths of the earth to fight for you. You may be able to summon more with a higher level in this spell.", "use_action": { "type": "learn_spell", "spells": [ "summon_decayed_pouncer" ] } @@ -102,6 +113,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_light_healing", + "//": "Biomancer spell", "name": { "str": "Scroll of Cure Light Wounds", "str_pl": "Scrolls of Cure Light Wounds" }, "description": "Heals a little bit of damage on the target.", "use_action": { "type": "learn_spell", "spells": [ "light_healing" ] } @@ -110,6 +122,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_pain_split", + "//": "Biomancer spell", "name": { "str": "Scroll of Pain Split", "str_pl": "Scrolls of Pain Split" }, "description": "Evens out damage among your limbs.", "use_action": { "type": "learn_spell", "spells": [ "pain_split" ] } @@ -118,6 +131,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_vicious_tentacle", + "//": "Biomancer spell", "name": { "str": "Scroll of Vicious Tentacle", "str_pl": "Scrolls of Vicious Tentacle" }, "description": "This spell extrudes a long nasty whiplike tentacle of sharp bones and oozing acid from your body, it has a long reach attack and vicious damage.", "use_action": { "type": "learn_spell", "spells": [ "vicious_tentacle" ] } @@ -126,6 +140,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_grotesque", + "//": "Biomancer spell", "name": { "str": "Scroll of Grotesque Enhancement", "str_pl": "Scrolls of Grotesque Enhancement" }, "description": "A spell that warps your body in alien ways to increase your physical abilities and strength.", "use_action": { "type": "learn_spell", "spells": [ "bio_grotesque" ] } @@ -134,6 +149,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_acidicspray", + "//": "Biomancer spell", "name": { "str": "Scroll of Acidic Spray", "str_pl": "Scrolls of Acidic Spray" }, "description": "When cast, the mage opens his mouth and sprays acid in a wide cone to dissolve his foes into goo. Just imagine what he'll do with the goo.", "use_action": { "type": "learn_spell", "spells": [ "bio_acidicspray" ] } @@ -142,6 +158,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_fleshpouch", + "//": "Biomancer spell", "name": { "str": "Scroll of Flesh Pouch", "str_pl": "Scrolls of Flesh Pouch" }, "description": "This spell grows a large pouch out of your skin on your back, allowing you to store your gear in it.", "use_action": { "type": "learn_spell", "spells": [ "bio_fleshpouch" ] } @@ -150,6 +167,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bio_bonespear", + "//": "Biomancer spell", "name": { "str": "Scroll of Conjure Bonespear", "str_pl": "Scrolls of Conjure Bonespear" }, "description": "This spell creates a long shaft of bone with a wicked point and blades along its length.", "use_action": { "type": "learn_spell", "spells": [ "bio_bonespear" ] } @@ -158,6 +176,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_megablast", + "//": "Classless spell", "name": { "str": "Scroll of Megablast", "str_pl": "Scrolls of Megablast" }, "description": "You always wanted to fire energy beams like in the animes you watched as a kid. Now you can!", "use_action": { "type": "learn_spell", "spells": [ "megablast" ] } @@ -166,6 +185,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_create_atomic_light", + "//": "Classless spell1", "name": { "str": "Scroll of Magical Light", "str_pl": "Scrolls of Magical Light" }, "description": "Creates a magical light.", "use_action": { "type": "learn_spell", "spells": [ "create_atomic_light" ] } @@ -174,6 +194,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_blinding_flash", + "//": "Classless spell", "name": { "str": "Scroll of Blinding Flash", "str_pl": "Scrolls of Blinding Flash" }, "description": "Blind enemies for a short time with a sudden, dazzling light. Higher levels deal slightly higher damage.", "use_action": { "type": "learn_spell", "spells": [ "blinding_flash" ] } @@ -182,6 +203,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ethereal_grasp", + "//": "Classless spell", "name": { "str": "Scroll of Ethereal Grasp", "str_pl": "Scrolls of Ethereal Grasp" }, "description": "A mass of spectral hands emerge from the ground, slowing everything in range. Higher levels allow a bigger AoE, and longer effect.", "use_action": { "type": "learn_spell", "spells": [ "ethereal_grasp" ] } @@ -190,6 +212,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_protection_aura", + "//": "Classless spell", "name": { "str": "Scroll of Aura of Protection", "str_pl": "Scrolls of Aura of Protection" }, "description": "Encases your whole body in a magical aura that protects you from the environment.", "use_action": { "type": "learn_spell", "spells": [ "protection_aura" ] } @@ -198,6 +221,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_veggrasp", + "//": "Druid spell", "name": { "str": "Scroll of Vegetative Grasp", "str_pl": "Scrolls of Vegetative Grasp" }, "description": "This spell causes roots and vines to burst forth from the ground and grab your foes, slowing them and doing a small amount of damage as they dig in.", "use_action": { "type": "learn_spell", "spells": [ "druid_veggrasp" ] } @@ -206,6 +230,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_rootstrike", + "//": "Druid spell", "name": { "str": "Scroll of Root Strike", "str_pl": "Scrolls of Root Strike" }, "description": "This spell causes roots to spear out the ground and stab into your foes in an arc, impaling them.", "use_action": { "type": "learn_spell", "spells": [ "druid_rootstrike" ] } @@ -214,6 +239,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_woodshaft", + "//": "Druid spell", "name": { "str": "Scroll of Wooden Shaft", "str_pl": "Scrolls of Wooden Shaft" }, "description": "This spell creates a projectile of hardwood that shoots forth from the caster's hand at high speed to stab into an enemy.", "use_action": { "type": "learn_spell", "spells": [ "druid_woodshaft" ] } @@ -222,6 +248,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druid_naturebow1", + "//": "Druid spell", "name": { "str": "Scroll of Nature's Bow", "str_pl": "Scrolls of Nature's Bow" }, "description": "This spell conjures a magical wooden recurve bow that fires endless arrows for as long as it lasts.", "use_action": { "type": "learn_spell", "spells": [ "druid_naturebow1" ] } @@ -230,6 +257,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_fatigue", + "//": "Druid spell", "name": { "str": "Scroll of Nature's Trance", "str_pl": "Scrolls of Nature's Trance" }, "description": "Your connection to living things allows you to go into a magical trance. This allows you to recover fatige quickly in exchange for mana.", "use_action": { "type": "learn_spell", "spells": [ "recover_fatigue" ] } @@ -238,6 +266,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_cats", + "//": "Druid spell", "name": { "str": "Scroll of Bag of Cats", "str_pl": "Scrolls of Bag of Cats" }, "description": "Are you the crazy cat lady?", "use_action": { "type": "learn_spell", "spells": [ "summon_cats" ] } @@ -246,6 +275,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_stonefist", + "//": "Earthshaper spell", "name": { "str": "Scroll of Stonefist", "str_pl": "Scrolls of Stonefist" }, "description": "Encases your arms and hands in a sheath of magical stone, you can punch and defend yourself with it in melee combat.", "use_action": { "type": "learn_spell", "spells": [ "stonefist" ] } @@ -254,6 +284,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_seismic_stomp", + "//": "Earthshaper spell", "name": { "str": "Scroll of Seismic Stomp", "str_pl": "Scrolls of Seismic Stomp" }, "description": "Focusing mana into your leg, you stomp your foot and send out a shockwave, knocking enemies around you onto the ground.", "use_action": { "type": "learn_spell", "spells": [ "seismic_stomp" ] } @@ -262,6 +293,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_stamina", + "//": "Earthshaper spell", "name": { "str": "Scroll of Stone's Endurance", "str_pl": "Scrolls of Stone's Endurance" }, "description": "You focus on the stones beneath you and draw from their agelessness. Your mana is converted to stamina.", "use_action": { "type": "learn_spell", "spells": [ "recover_stamina" ] } @@ -270,6 +302,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_shardspray", + "//": "Earthshaper spell", "name": { "str": "Scroll of Shardspray", "str_pl": "Scrolls of Shardspray" }, "description": "This spell projects a wide spray of sharp metal shards, cutting into your foes and friends alike.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_shardspray" ] } @@ -278,6 +311,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_piercing_bolt", + "//": "Earthshaper spell", "name": { "str": "Scroll of Piercing Bolt", "str_pl": "Scrolls of Piercing Bolt" }, "description": "This spell projects a piercing rod of conjured iron at those that dare oppose you.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_piercing_bolt" ] } @@ -286,6 +320,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_shardstorm", + "//": "Earthshaper spell", "name": { "str": "Scroll of Shardstorm", "str_pl": "Scrolls of Shardstorm" }, "description": "Creates an omnidirectional spray of razor sharp metal shards all around you.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_shardstorm" ] } @@ -294,6 +329,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eshaper_rockbolt", + "//": "Earthshaper spell", "name": { "str": "Scroll of Rockbolt", "str_pl": "Scrolls of Rockbolt" }, "description": "Fires a conjured stone projectile at high velocity.", "use_action": { "type": "learn_spell", "spells": [ "eshaper_rockbolt" ] } @@ -302,6 +338,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_point_flare", + "//": "Kelvinist spell", "name": { "str": "Scroll of Point Flare", "str_pl": "Scrolls of Point Flare" }, "description": "Causes an intense heat at the location, damaging the target.", "use_action": { "type": "learn_spell", "spells": [ "point_flare" ] } @@ -310,6 +347,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_create_lighter", + "//": "Kelvinist spell", "name": { "str": "Scroll of Finger Firelighter", "str_pl": "Scrolls of Finger Firelighter" }, "description": "Summons a small flame that does not burn you, but you can use it to light things on fire. It seems to need you to have some intent to light things on fire, because you are able to put it in your pocket with no issue.", "use_action": { "type": "learn_spell", "spells": [ "create_lighter" ] } @@ -318,6 +356,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ice_spike", + "//": "Kelvinist spell", "name": { "str": "Scroll of Ice Spike", "str_pl": "Scrolls of Ice Spike" }, "description": "Causes jagged icicles to form in the air above the target, falling and damaging it.", "use_action": { "type": "learn_spell", "spells": [ "ice_spike" ] } @@ -326,6 +365,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_fireball", + "//": "Kelvinist spell", "name": { "str": "Scroll of Fireball", "str_pl": "Scrolls of Fireball" }, "description": "You hurl a pea-sized glowing orb that when reaches its target or an obstacle produces a pressure-less blast of searing heat.", "use_action": { "type": "learn_spell", "spells": [ "fireball" ] } @@ -334,6 +374,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_cone_cold", + "//": "Kelvinist spell", "name": { "str": "Scroll of Cone of Cold", "str_pl": "Scrolls of Cone of Cold" }, "description": "You blast a cone of frigid air toward the target.", "use_action": { "type": "learn_spell", "spells": [ "cone_cold" ] } @@ -342,6 +383,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_burning_hands", + "//": "Kelvinist spell", "name": { "str": "Scroll of Burning Hands", "str_pl": "Scrolls of Burning Hands" }, "description": "You're pretty sure you saw this in a game somewhere. You fire a short-range cone of fire.", "use_action": { "type": "learn_spell", "spells": [ "burning_hands" ] } @@ -350,6 +392,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_frost_spray", + "//": "Kelvinist spell", "name": { "str": "Scroll of Frost Spray", "str_pl": "Scrolls of Frost Spray" }, "description": "You're pretty sure you saw this in a game somewhere. You fire a short-range cone of ice and cold.", "use_action": { "type": "learn_spell", "spells": [ "frost_spray" ] } @@ -358,6 +401,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_chilling_touch", + "//": "Kelvinist spell", "name": { "str": "Scroll of Chilling Touch", "str_pl": "Scrolls of Chilling Touch" }, "description": "Freezes the touched target with intense cold.", "use_action": { "type": "learn_spell", "spells": [ "chilling_touch" ] } @@ -366,6 +410,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_glide_ice", + "//": "Kelvinist spell", "name": { "str": "Scroll of Glide on Ice", "str_pl": "Scrolls of Glide on Ice" }, "description": "Encases your feet in a magical coating of ice, allowing you to glide along smooth surfaces faster.", "use_action": { "type": "learn_spell", "spells": [ "glide_ice" ] } @@ -374,6 +419,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_hoary_blast", + "//": "Kelvinist spell", "name": { "str": "Scroll of Hoary Blast", "str_pl": "Scrolls of Hoary Blast" }, "description": "You project a glowing white crystal of ice and it explodes on impact into a blossom of shattering cold.", "use_action": { "type": "learn_spell", "spells": [ "hoary_blast" ] } @@ -382,6 +428,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ice_shield", + "//": "Kelvinist spell", "name": { "str": "Scroll of Ice Shield", "str_pl": "Scrolls of Ice Shield" }, "description": "Creates a magical shield of ice on your arm, you can defend yourself with it in melee combat and use it to bash.", "use_action": { "type": "learn_spell", "spells": [ "ice_shield" ] } @@ -390,6 +437,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_frost_armor", + "//": "Kelvinist spell", "name": { "str": "Scroll of Frost Armor", "str_pl": "Scrolls of Frost Armor" }, "description": "Covers you in a thin layer of magical ice to protect you from harm.", "use_action": { "type": "learn_spell", "spells": [ "frost_armor" ] } @@ -398,6 +446,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magic_missile", + "//": "Magus spell", "name": { "str": "Scroll of Magic Missile", "str_pl": "Scrolls of Magic Missile" }, "description": "I cast Magic Missile at the darkness!", "use_action": { "type": "learn_spell", "spells": [ "magic_missile" ] } @@ -406,6 +455,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_phase_door", + "//": "Magus spell", "name": { "str": "Scroll of Phase Door", "str_pl": "Scrolls of Phase Door" }, "description": "Teleports you in a random direction a short distance.", "use_action": { "type": "learn_spell", "spells": [ "phase_door" ] } @@ -414,6 +464,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_gravity_well", + "//": "Magus spell", "name": { "str": "Scroll of Gravity Well", "str_pl": "Scrolls of Gravity Well" }, "description": "Summons a well of gravity with the epicenter at the location. Deals bashing damage to all creatures in the affected area.", "use_action": { "type": "learn_spell", "spells": [ "gravity_well" ] } @@ -422,6 +473,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_mana_blast", + "//": "Magus spell", "name": { "str": "Scroll of Mana Blast", "str_pl": "Scrolls of Mana Blast" }, "description": "A blast of concentrated magical power that obliterates a large area.", "use_action": { "type": "learn_spell", "spells": [ "magus_mana_blast" ] } @@ -430,6 +482,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_mana_bolt", + "//": "Magus spell", "name": { "str": "Scroll of Mana Bolt", "str_pl": "Scrolls of Mana Bolt" }, "description": "A bolt of magical power that only damages your foes.", "use_action": { "type": "learn_spell", "spells": [ "magus_mana_bolt" ] } @@ -438,6 +491,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_haste", + "//": "Magus spell", "name": { "str": "Scroll of Haste", "str_pl": "Scrolls of Haste" }, "description": "This spell gives you an enormous boost of speed lasting a short period of time.", "use_action": { "type": "learn_spell", "spells": [ "magus_haste" ] } @@ -446,6 +500,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_mana_beam", + "//": "Magus spell", "name": { "str": "Scroll of Mana Beam", "str_pl": "Scrolls of Mana Beam" }, "description": "A beam of focused magical power that damages any foes in its path.", "use_action": { "type": "learn_spell", "spells": [ "magus_mana_beam" ] } @@ -454,6 +509,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_magus_escape", + "//": "Magus spell", "name": { "str": "Scroll of Escape", "str_pl": "Scrolls of Escape" }, "description": "Teleports you in a random direction a medium distance, to help escape your foes in dangerous situations.", "use_action": { "type": "learn_spell", "spells": [ "magus_escape" ] } @@ -462,6 +518,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_cats_grace", + "//": "Magus spell", "name": { "str": "Scroll of Cat's Grace", "str_pl": "Scrolls of Cat's Grace" }, "description": "You become more graceful, agile, and coordinated.", "use_action": { "type": "learn_spell", "spells": [ "cats_grace" ] } @@ -470,6 +527,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_eagles_sight", + "//": "Magus spell", "name": { "str": "Scroll of Eagle's Sight", "str_pl": "Scrolls of Eagle's Sight" }, "description": "You gain the perception of an eagle.", "use_action": { "type": "learn_spell", "spells": [ "eagles_sight" ] } @@ -478,6 +536,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_ogres_strength", + "//": "Magus spell", "name": { "str": "Scroll of Ogre's Strength", "str_pl": "Scrolls of Ogre's Strength" }, "description": "You gain the strength of an ogre.", "use_action": { "type": "learn_spell", "spells": [ "ogres_strength" ] } @@ -486,6 +545,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_foxs_cunning", + "//": "Magus spell", "name": { "str": "Scroll of Fox's Cunning", "str_pl": "Scrolls of Fox's Cunning" }, "description": "You become wily like a fox.", "use_action": { "type": "learn_spell", "spells": [ "foxs_cunning" ] } @@ -494,6 +554,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_jolt", + "//": "Stormshaper spell", "name": { "str": "Scroll of Jolt", "str_pl": "Scrolls of Jolt" }, "description": "A short-ranged fan of electricity shoots from your fingers.", "use_action": { "type": "learn_spell", "spells": [ "jolt" ] } @@ -502,6 +563,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_lightning_bolt", + "//": "Stormshaper spell", "name": { "str": "Scroll of Lightning Bolt", "str_pl": "Scrolls of Lightning Bolt" }, "description": "The goto spell for many Stormshapers, this iconic spell does just what you expect: you shoot lightning from your fingertips. However, this lightning is more directed than most lightning, and travels in a line through most non-solid targets.", "use_action": { "type": "learn_spell", "spells": [ "lightning_bolt" ] } @@ -510,6 +572,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_windstrike", + "//": "Stormshaper spell", "name": { "str": "Scroll of Windstrike", "str_pl": "Scrolls of Windstrike" }, "description": "A powerful blast of wind slams into anything in front of your outstretched hand.", "use_action": { "type": "learn_spell", "spells": [ "windstrike" ] } @@ -518,6 +581,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_windrun", + "//": "Stormshaper spell", "name": { "str": "Scroll of Windrunning", "str_pl": "Scrolls of Windrunning" }, "description": "A magical wind pushes you forward as you move, easing your movements and increasing speed.", "use_action": { "type": "learn_spell", "spells": [ "windrun" ] } @@ -526,6 +590,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_storm_hammer", + "//": "Stormshaper spell", "name": { "str": "Scroll of Call Stormhammer", "str_pl": "Scrolls of Call Stormhammer" }, "description": "Creates a crackling magical warhammer full of lightning to smite your foes with, and of course, smash things to bits!", "use_action": { "type": "learn_spell", "spells": [ "storm_hammer" ] } @@ -534,6 +599,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_bless", + "//": "Technomancer spell", "name": { "str": "Scroll of Bless", "str_pl": "Scrolls of Bless" }, "description": "A spell of blessing that gives you energy and boosts your abilities.", "use_action": { "type": "learn_spell", "spells": [ "bless" ] } @@ -542,6 +608,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_holy_blade", + "//": "Technomancer spell", "name": { "str": "Scroll of Holy Blade", "str_pl": "Scrolls of Holy Blade" }, "description": "This blade of light will cut through any evil it makes contact with!", "use_action": { "type": "learn_spell", "spells": [ "holy_blade" ] } @@ -550,6 +617,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_spirit_armor", + "//": "Technomancer spell", "name": { "str": "Scroll of Spiritual Armor", "str_pl": "Scrolls of Spiritual Armor" }, "description": "Evil will not make it through your defenses if your faith is strong enough!", "use_action": { "type": "learn_spell", "spells": [ "spirit_armor" ] } @@ -558,6 +626,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_create_atomic_lamp", + "//": "Technomancer spell", "name": { "str": "Scroll of Lamp", "str_pl": "Scrolls of Lamp" }, "description": "Creates a magical lamp.", "use_action": { "type": "learn_spell", "spells": [ "create_atomic_lamp" ] } @@ -566,6 +635,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_recover_bionic_power", + "//": "Technomancer spell", "name": { "str": "Scroll of Manatricity", "str_pl": "Scrolls of Manatricity" }, "description": "You have found a way to convert your spiritual energy into power you can use for your bionics.", "use_action": { "type": "learn_spell", "spells": [ "recover_bionic_power" ] } @@ -574,6 +644,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_taze", + "//": "Technomancer spell", "name": { "str": "Scroll of Taze", "str_pl": "Scrolls of Taze" }, "description": "This spell creates a very short range bolt of electricity to shock your foes.", "use_action": { "type": "learn_spell", "spells": [ "taze" ] } @@ -582,6 +653,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_quantum_tunnel_lesser", + "//": "Technomancer spell", "name": { "str": "Scroll of Lesser Quantum Tunnel", "str_pl": "Scrolls of Lesser Quantum Tunnel" }, "description": "This spell manipulates some quantum something or other to tunnel you through a short distance of space, and even matter, unfortunately there's that whole uncertainty thing as to where you come out. It leaves you a little dazed on the other side as you reorient yourself.", "use_action": { "type": "learn_spell", "spells": [ "quantum_tunnel_lesser" ] } @@ -590,6 +662,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_synaptic_stimulation", + "//": "Technomancer spell", "name": { "str": "Scroll of Synaptic Stimulation", "str_pl": "Scrolls of Synaptic Stimulation" }, "description": "This spell stimulates the synapses in your brain beyond normal processing speeds, giving you a large boost in mental processing capability, including enhancing your reflexes, speed, and raw intellectual power. Use responsibly!", "use_action": { "type": "learn_spell", "spells": [ "synaptic_stimulation" ] } @@ -598,6 +671,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_laze", + "//": "Technomancer spell", "name": { "str": "Scroll of Laze", "str_pl": "Scrolls of Laze" }, "description": "You concentrate and release a focused beam of photons at a target, also known as a laser.", "use_action": { "type": "learn_spell", "spells": [ "laze" ] } @@ -606,6 +680,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_animated_blade", + "//": "Technomancer spell", "name": { "str": "Scroll of Animated Blade", "str_pl": "Scrolls of Animated Blade" }, "description": "This spell conjures flying animated blades that will cut your enemies down to size. Into small pieces that is.", "use_action": { "type": "learn_spell", "spells": [ "animated_blade" ] } @@ -614,6 +689,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_mirror_image", + "//": "Technomancer spell", "name": { "str": "Scroll of Mirror Image", "str_pl": "Scrolls of Mirror Image" }, "description": "This spell manipulates light into barely tangible duplicates of a living being, a magical hologram in short.", "use_action": { "type": "learn_spell", "spells": [ "mirror_image" ] } @@ -622,6 +698,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_lightning_blast", + "//": "Stormshaper spell", "name": { "str": "Scroll of Lightning Blast", "str_pl": "Scrolls of Lightning Blast" }, "description": "You fire a small concentrated ball of lightning at the target. The electricity diffuses quickly, so it doesn't do much damage, but you're able to fire off several quick ones in a row.", "use_action": { "type": "learn_spell", "spells": [ "lightning_blast" ] } @@ -630,6 +707,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_necrotic_gaze", + "//": "Animist spell", "name": { "str": "Scroll of Necrotic Gaze", "str_pl": "Scrolls of Necrotic Gaze" }, "description": "You use the power of your own blood to imbue necrotic energy into your gaze, damaging the target you look at.", "use_action": { "type": "learn_spell", "spells": [ "necrotic_gaze" ] } @@ -638,6 +716,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_purification_seed", + "//": "Druid spell", "name": { "str": "Scroll of Purification Seed", "str_pl": "Scrolls of Purification Seed" }, "description": "You summon a gift of the earth which will purify water. Greater levels yield greater numbers of seeds.", "use_action": { "type": "learn_spell", "spells": [ "purify_seed" ] } @@ -646,6 +725,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_x-ray", + "//": "Technomancer spell", "name": { "str": "Scroll of X-ray Vision", "str_pl": "Scrolls of X-ray Vision" }, "description": "You fire a cone of X-rays that magically allow you to see that area for a short time.", "use_action": { "type": "learn_spell", "spells": [ "x-ray" ] } @@ -654,6 +734,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_clairvoyance", + "//": "Earthshaper spell", "name": { "str": "Scroll of Clairvoyance", "str_pl": "Scrolls of Clairvoyance" }, "description": "You close your eyes and the earth surrenders its secrets to you.", "use_action": { "type": "learn_spell", "spells": [ "clairvoyance" ] } @@ -662,6 +743,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_lava_bomb", + "//": "Earthshaper spell", "name": { "str": "Scroll of Lava Bomb", "str_pl": "Scrolls of Lava Bomb" }, "description": "You tear up the ground beneath you to fire a lava bomb: a globe of lava surrounded by hot, solid rock. It shatters upon impact, spraying shards of rock and lava everywhere.", "use_action": { "type": "learn_spell", "spells": [ "lava_bomb_main" ] } @@ -670,6 +752,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_acid_resistance", + "//": "Classless spell, black dragon books", "name": { "str": "Scroll of Acid Resistance", "str_pl": "Scrolls of Acid Resistance" }, "description": "This spell creates an invisible aura to protect you from acid.", "use_action": { "type": "learn_spell", "spells": [ "acid_resistance" ] } @@ -678,6 +761,7 @@ "id": "lightning_storm_scroll", "type": "GENERIC", "name": { "str": "Scroll of Lightning Storm", "str_pl": "Scrolls of Lightning Storm" }, + "//": "Stormshaper spell", "description": "This scroll details how a spell called 'Lightning Blast' which is commonly used among Stormshapers can be altered to become much more powerful, at a much higher mana cost.", "weight": "129 g", "volume": "500 ml", @@ -690,6 +774,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druidic_regrowth", + "//": "Druid spell", "name": { "str": "Scroll of Sacrificial Regrowth", "str_pl": "Scrolls of Sacrificial Regrowth" }, "description": "Through giving of one's own life force, you restore withered and barren plant life nearby. What remains will need time to regrow its full strength.", "use_action": { "type": "learn_spell", "spells": [ "druidic_regrowth" ] } @@ -698,6 +783,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_druidic_healing", + "//": "Druid spell", "name": { "str": "Scroll of Sacrificial Healing", "str_pl": "Scrolls of Sacrificial Healing" }, "description": "Channels some of the user's own life force into healing energy, for the sake of ones allies.", "use_action": { "type": "learn_spell", "spells": [ "druidic_healing" ] } @@ -706,6 +792,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_earthshaper_stoneskin", + "//": "Earthshaper spell", "name": { "str": "Scroll of Stoneskin", "str_pl": "Scrolls of Stoneskin" }, "description": "Envelops your entire body in armor formed from living rock, encumbering yet protective.", "use_action": { "type": "learn_spell", "spells": [ "earthshaper_stoneskin" ] } @@ -714,6 +801,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_earthshaper_pillar", + "//": "Earthshaper spell", "name": { "str": "Scroll of Pillar of Stone", "str_pl": "Scrolls of Pillar of Stone" }, "description": "Drawing upon the surrounding earth, you form a pillar of solid rock. Experience will make the task easier, and less disruptive to the surrounding area.", "use_action": { "type": "learn_spell", "spells": [ "earthshaper_pillar" ] } @@ -722,6 +810,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_biomancer_paralytic_dart", + "//": "Biomancer spell", "name": { "str": "Scroll of Paralytic Dart", "str_pl": "Scrolls of Paralytic Dart" }, "description": "Spits a warped needle of sinew and bone, carrying with it a sting that slows your victim.", "use_action": { "type": "learn_spell", "spells": [ "biomancer_paralytic_dart" ] } @@ -730,6 +819,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_biomancer_visceral_projection", + "//": "Biomancer spell", "name": { "str": "Scroll of Visceral Projection", "str_pl": "Scrolls of Visceral Projection" }, "description": "Projects a spray of acrid blood and gore all around you, growing to ensnare your prey in in a field of twitching poisonous tendrils.", "use_action": { "type": "learn_spell", "spells": [ "biomancer_visceral_projection" ] } @@ -738,6 +828,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_biomancer_coagulant_weave", + "//": "Biomancer spell", "name": { "str": "Scroll of Coagulant Weave", "str_pl": "Scrolls of Coagulant Weave" }, "description": "Turns your biological mastery inwards, medically enhancing your flesh. Rather than strength of healing, it staves off blood loss and purges wounds before they can turn septic, at the cost of increased hunger and thirst.", "use_action": { "type": "learn_spell", "spells": [ "biomancer_coagulant_weave" ] } @@ -746,6 +837,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_stormshaper_ionization", + "//": "Stormshaper spell", "name": { "str": "Scroll of Ionization", "str_pl": "Scrolls of Ionization" }, "description": "By manipulating the charge in the air, you can conjure a sharp snap of lightning over a wide area. While its destructive potential is a far cry from natural lightning, the light and thunderclap produced will leave your foes reeling.", "use_action": { "type": "learn_spell", "spells": [ "stormshaper_ionization" ] } @@ -754,6 +846,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_summon_wisps", + "//": "Animist spell", "name": { "str": "Scroll of Ignus Fatuus", "str_pl": "Scrolls of Ignus Fatuus" }, "description": "Summons ghostly foxfire worked from living marsh vapor, to lead your enemies astray. With more experience, this spell can conjure multiple ghost lights.", "use_action": { "type": "learn_spell", "spells": [ "summon_wisps" ] } @@ -762,6 +855,7 @@ "type": "GENERIC", "copy-from": "spell_scroll", "id": "spell_scroll_stormshaper_wall_of_fog", + "//": "Stormshaper spell", "name": { "str": "Scroll of Wall of Fog", "str_pl": "Scrolls of Wall of Fog" }, "description": "Draws forth a broad wall of thick fog. While the sudden force of air pressure will floor any enemies caught in it, the conjuration is otherwise harmless.", "use_action": { "type": "learn_spell", "spells": [ "stormshaper_wall_of_fog" ] } diff --git a/data/mods/Magiclysm/items/spellbooks.json b/data/mods/Magiclysm/items/spellbooks.json index 7220c7c489f0d..dec578b1fb5a7 100644 --- a/data/mods/Magiclysm/items/spellbooks.json +++ b/data/mods/Magiclysm/items/spellbooks.json @@ -30,6 +30,7 @@ "id": "wizard_beginner", "type": "GENERIC", "name": { "str": "A Beginner's Guide to Magic", "str_pl": "copies of A Beginner's Guide to Magic" }, + "//": "2 Magus, 1 classless spell", "description": "You would describe this as more like a pamphlet than a spellbook, but it seems to have at least one interesting spell you can use.", "weight": "585 g", "volume": "250 ml", @@ -42,6 +43,7 @@ "id": "wizard_utility", "type": "GENERIC", "name": { "str": "Wizarding Guide to Backpacking", "str_pl": "copies of Wizarding Guide to Backpacking" }, + "//": "1 Magus, 1 Biomancer, 1, Kelvinist, 1 classless spell", "description": "This appears to be the spell version of a guide for what things to take with you when backpacking. It's a little bulky, but will certainly prove useful.", "weight": "1 kg", "volume": "1250 ml", @@ -54,6 +56,7 @@ "id": "pyro", "type": "GENERIC", "name": { "str": "Pyromancy for Heretics", "str_pl": "copies of Pyromancy for Heretics" }, + "//": "4 Kelvinist spells", "description": "This charred husk of a book still contains many ways to light things aflame.", "weight": "450 g", "volume": "1 L", @@ -65,6 +68,7 @@ { "id": "wizard_advanced", "type": "GENERIC", + "//": "1 Magus, 1 biomancer, 2 kelvinist spells", "name": { "str": "A Treatise on Magical Elements", "str_pl": "copies of A Treatise on Magical Elements" }, "description": "This details complex diagrams, rituals, and choreography that describes various spells.", "weight": "920 g", @@ -78,6 +82,7 @@ "id": "priest_beginner", "type": "GENERIC", "name": { "str": "Introduction to the Divine", "str_pl": "copies of Introduction to the Divine" }, + "//": "1 technomancer, 1 biomancer, 1 classless spells", "description": "This appears to mostly be a religious text, but it does have some notes on healing.", "weight": "585 g", "volume": "500 ml", @@ -93,6 +98,7 @@ "str": "The Paladin's Guide to Modern Spellcasting", "str_pl": "copies of The Paladin's Guide to Modern Spellcasting" }, + "//": "2 technomancer, 1 animist spells", "description": "Despite the title, this seems to be written in Middle English. A little obtuse, but you can make out most of the words well enough.", "weight": "830 g", "volume": "750 ml", @@ -105,6 +111,7 @@ "id": "winter_grasp", "type": "GENERIC", "name": { "str": "Winter's Eternal Grasp", "str_pl": "copies of Winter's Eternal Grasp" }, + "//": "5 Kelvinist spells", "description": "This slim book almost seems to be made from ice, it's cold to the touch.", "weight": "450 g", "volume": "1 L", @@ -116,6 +123,7 @@ { "id": "tome_of_storms", "type": "GENERIC", + "//": "6 Stormshaper spells", "name": { "str": "The Tome of The Oncoming Storm", "str_pl": "copies of The Tome of The Oncoming Storm" }, "description": "A large book embossed with crossed lightning bolts and storm clouds, it tingles to the touch.", "weight": "430 g", @@ -132,6 +140,7 @@ "id": "generic_spellbook", "type": "GENERIC", "name": { "str": "Nondescript Spellbook", "str_pl": "copies of Nondescript Spellbook" }, + "//": "1 technomancer, 1 earthshaper, 1 classless spell", "description": "A small book, containing spells created by a novice magician.", "weight": "355 g", "volume": "500 ml", @@ -143,6 +152,7 @@ "id": "light_manipulation_spellbook", "type": "GENERIC", "name": { "str": "Of Light and Falsehoods", "str_pl": "copies of Of Light and Falsehoods" }, + "//": "3 technomancer, 4 classless spell", "description": "A small white book, it subtly amplifies the ambient light around it.", "weight": "430 g", "volume": "750 ml", @@ -166,6 +176,7 @@ "id": "biomancer_spellbook", "type": "GENERIC", "name": { "str": "The Tome of Flesh", "str_pl": "copies of The Tome of Flesh" }, + "//": "5 Biomancer spells", "description": "A small tome, seemingly covered in tanned human skin.", "weight": "355 g", "volume": "500 ml", @@ -180,6 +191,7 @@ "id": "druid_spellbook", "type": "GENERIC", "name": { "str": "The Book of Trees", "str_pl": "copies of The Book of Trees" }, + "//": "4 Druid spells", "description": "A bark covered book.", "weight": "355 g", "volume": "500 ml", @@ -192,6 +204,7 @@ "type": "GENERIC", "name": { "str": "The Utility of Mana as an Energy Source", "str_pl": "copies of The Utility of Mana as an Energy Source" }, "description": "This book details spells that use your mana to recover various physiological effects.", + "//": "1 technomancer, 2 animist, 1 druid, 1 earthshaper spell", "weight": "728 g", "volume": "3 L", "symbol": "?", @@ -205,6 +218,7 @@ "id": "magus_spellbook", "type": "GENERIC", "name": { "str": "The Tome of The Battle Mage", "str_pl": "copies of The Tome of The Battle Mage" }, + "//": "3 Magus spells", "description": "Your standard wizardy looking spellbook, filled with Magus combat spells. You sure lucked out!", "weight": "434 g", "volume": "750 ml", @@ -216,6 +230,7 @@ "id": "eshaper_spellbook", "type": "GENERIC", "name": { "str": "The Tome of the Hollow Earth", "str_pl": "copies of The Tome of the Hollow Earth" }, + "//": "4 earthshaper spells", "description": "This large dusty spellbook seems perpetually, well, dusty. It contains the power of the earth.", "weight": "483 g", "volume": "825 ml", @@ -230,6 +245,7 @@ "id": "magus_spellbook_move", "type": "GENERIC", "name": { "str": "The Tome of Magical Movement", "str_pl": "copies of The Tome of Magical Movement" }, + "//": "3 Magus spells", "description": "This small lightweight book seems to almost not entirely exist, let's say it 97% does. It contains Magus spells focused on movement.", "weight": "231 g", "volume": "500 ml", @@ -241,6 +257,7 @@ "id": "summon_scroll_smudged", "type": "GENERIC", "name": "Smudged Scroll", + "//": "Druid spell", "description": "This looks like someone was designing a new spell, but spilled a mug of coffee on it and crumpled it up in anger. You can tell that it will definitely cast something, but you can't be sure that it will work very well.", "weight": "129 g", "volume": "100 ml", @@ -252,6 +269,7 @@ "id": "summon_undead_spellbook", "type": "GENERIC", "name": { "str": "Necromantic Minions for Dummies", "str_pl": "copies of Necromantic Minions for Dummies" }, + "//": "3 Animist spells", "description": "This book details various ways of summoning an undead minion to fight for you. They all appear to disappear after a short time, crumbling to dust.", "weight": "788 g", "volume": "2250 ml", @@ -263,6 +281,7 @@ "id": "techno_fundamentals", "type": "GENERIC", "name": { "str": "Fundamentals of Technomancy", "str_pl": "copies of Fundamentals of Technomancy" }, + "//": "3 Technomancer spells", "description": "This thick manual instructs the spellcaster on manipulating and empowering various forms of matter and energy.", "weight": "258 g", "volume": "750 ml", @@ -275,6 +294,7 @@ "type": "GENERIC", "name": { "str": "Complete Idiot's Guide to Technomancy", "str_pl": "copies of Complete Idiot's Guide to Technomancy" }, "description": "This colorful guide, full of diagrams and cartoons, teaches a couple of very basic Technomancy spells for the not-so-bright pupils.", + "//": "2 Technomancer spells", "weight": "211 g", "volume": "500 ml", "symbol": "?", @@ -288,6 +308,7 @@ "str": "Technomancy and the Electromagnetic Spectrum", "str_pl": "copies of Technomancy and the Electromagnetic Spectrum" }, + "//": "2 Technomancer spells", "description": "This lab reference material book is thick and overflowing with information on combining magic with EM radiation.", "weight": "284 g", "volume": "1 L", @@ -299,6 +320,7 @@ "id": "translocate_spellbook", "type": "GENERIC", "name": { "str": "Geospatial Systems: The Lie Of Linearity", "str_pl": "copies of Geospatial Systems: The Lie Of Linearity" }, + "//": "1 classless spell", "description": "This book outlines in great detail how time and space are wibbly-wobbly and non-Euclidean. It also appears to have a dozen different coordinate systems that it uses nearly interchangeably, which makes it hard to follow. There's lots of jargon, but with intense study you can probably learn a thing or two about portals.", "weight": "1200 g", "volume": "2500 ml", @@ -310,6 +332,7 @@ "id": "stat_up_spellbook", "type": "GENERIC", "name": { "str": "Transcendence of the Human Condition", "str_pl": "copies of Transcendence of the Human Condition" }, + "//": "4 Magus spells", "description": "The Human is the only creature that seeks to improve himself. This study examines different spells that can heighten various senses temporarily, in hopes to discover a more permanent solution.", "weight": "1300 g", "volume": "2500 ml", diff --git a/data/mods/Magiclysm/worldgen/magic_academy.json b/data/mods/Magiclysm/worldgen/magic_academy.json new file mode 100644 index 0000000000000..ba638ebfb2265 --- /dev/null +++ b/data/mods/Magiclysm/worldgen/magic_academy.json @@ -0,0 +1,617 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_ground", + "object": { + "fill_ter": "t_floor", + "rows": [ + ",.####################.,", + ",.#d h&o==jjjj==o%h d#.,", + ",.#@@ +========+ @@#.,", + ",.########=~~=########.,", + ",...#d h0o=~~=o$h d#...,", + ",...#@@ +====+ @@#...,", + ",...#######==#######...,", + ",[...##S +==+ S##..[.,", + ",.....#t ##++## t#.....,", + ",.....#9##< >##9#..[..,", + ",..[..###c c###.....,", + ",.....##c E E c##...[.,", + ",,,,,,* *,,,,,,", + ",,,,,,* HHHH *,,,,,,", + "......##c c##......", + "...[..###c rr c###......", + ".....##<## h ##<##..[..", + ".[...#B t##++##t B#.....", + "....##B S#==#S B##....", + "...####+###==###+####...", + "####xxy +======+ yxx####", + "#D ) Eoj=~~=joI ) D#", + "#@@#HHTR#j====j#IEHH#@@#", + "########################" + ], + "palettes": [ "standard_domestic_palette" ], + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ], + "terrain": { + "[": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ], + " ": "t_floor", + "#": "t_rock_wall", + ",": "t_concrete", + "~": "t_water_pool_shallow_outdoors", + "=": "t_grass_golf", + "j": "t_grass_golf", + "}": "t_grass_golf" + }, + "furniture": { ")": "f_beaded_door", "&": "f_desk", "%": "f_desk", "$": "f_desk", "0": "f_desk" }, + "place_loot": [ + { "item": "television", "x": 4, "y": 20, "chance": 100 }, + { "item": "television", "x": 19, "y": 20, "chance": 100 }, + { "item": "stereo", "x": 18, "y": 20, "chance": 100 }, + { "item": "stereo", "x": 5, "y": 20, "chance": 100 } + ], + "items": { + "&": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "druid_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "%": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "biomancer_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "$": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "earthshaper_items", "chance": 70, "repeat": [ 1, 3 ] } + ], + "0": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "technomancer_items", "chance": 70, "repeat": [ 1, 3 ] } + ], + "x": { "item": "enchanted_small_items", "chance": 25, "repeat": [ 1, 3 ] }, + "r": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "academy_lore", "chance": 100 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 10 }, + { "item": "enchanted_misc", "chance": 5 } + ], + "d": [ + { "item": "magic_shop_clothes", "chance": 25, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] } + ], + "D": [ + { "item": "magic_shop_clothes", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] } + ], + "R": [ + { "item": "magic_shop_books", "chance": 60, "repeat": [ 1, 3 ] }, + { "item": "spellbook_loot_2", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_misc", "chance": 5 } + ], + "j": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 10 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 5 }, + { "item": "enchanted_misc", "chance": 2 } + ] + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_basement", + "object": { + "fill_ter": "t_thconc_floor", + "rows": [ + "``####################``", + "``#@d|vRR H|FFF 666#``", + "``#@ ) lH| 6#``", + "``###||+|||||4 JA 6###``", + "````#H JWWQ|O J n#````", + "````#H Z|1 J 5#````", + "````##T Z|2 Y##````", + "`````##JJy Q|3 7##`````", + "``````#|||+|||+||#``````", + "``````#qq| < |U#``````", + "``````#q + +U#``````", + "``````#||||| ||#``````", + "``````# #``````", + "``````# $ $ ~~~ i#``````", + "``````# ~~~ i#``````", + "``````# ! ! ~~~ i#``````", + "`````## ~~~ ##`````", + "`````# % % ~~~ #`````", + "````## ~~~ ##````", + "```## = = = ~~~~~ ##```", + "####i ~~~~~ i####", + "#9 |i = = = ~~~~~ i| 9#", + "#9 ] ] 9#", + "########################" + ], + "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" }, + "place_loot": [ { "item": "television", "x": 8, "y": 1, "chance": 100 }, { "item": "stereo", "x": 7, "y": 1, "chance": 100 } ], + "items": { + "q": [ + { "item": "alchemy_items", "chance": 45, "repeat": [ 1, 3 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] } + ], + "l": { "item": "enchanted_small_items", "chance": 15 }, + "v": { "item": "boss_treasure_items", "chance": 70, "repeat": [ 1, 3 ] }, + "d": [ + { "item": "magic_shop_clothes", "chance": 25, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 15 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ], + "i": [ + { "item": "magic_shop_potions", "chance": 10 }, + { "item": "magic_shop_wands", "chance": 3 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 15 } + ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 2, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_2nd", + "object": { + "fill_ter": "t_floor", + "rows": [ + "__####################__", + "__#d h&o,______,o%h d#__", + "__#@@ +,,,__,,,+ @@#__", + "__########,__,########__", + "____#d h0o,__,o$h d#____", + "____#@@ +,,,,+ @@#____", + "____#######,,#######____", + "_____##S +,,+ S##_____", + "______#t ##++## t#______", + "______#9##> <##9#______", + "______### ###______", + "______## hhhh ##______", + "______)y ffff y)______", + "______)y hhhh y)______", + "______## ##______", + "______### ff ###______", + "_____##>## hh ##>##_____", + "_____#` v##))##vE`#_____", + "____##`E R#__#R `##____", + "___###)]))#__#))])###___", + "#####,,,===__===,,,#####", + "#k ],=}=______=}=,] k#", + "#RHH)====______====)HHR#", + "#########################" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { + "_": "t_open_air", + "/": "t_open_air_rooved_outside", + ",": "t_concrete", + "#": "t_rock_wall", + ")": "t_wall_glass", + "]": "t_door_glass_c", + "=": "t_grass_golf", + "j": "t_grass_golf", + "}": "t_grass_golf" + }, + "furniture": { + "y": [ "f_indoor_plant_y", "f_indoor_plant" ], + "`": "f_magic_bench", + "}": "f_huge_mana_crystal", + "&": "f_desk", + "%": "f_desk", + "$": "f_desk", + "0": "f_desk" + }, + "items": { + "&": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "kelvinist_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "%": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "animist_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "$": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "magus_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "0": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "classless_items", "chance": 60, "repeat": [ 2, 4 ] }, + { "item": "stormshaper_items", "chance": 70, "repeat": [ 1, 2 ] } + ], + "H": [ + { "item": "magic_shop_clothes", "chance": 20 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_misc", "chance": 1 } + ], + "`": [ + { "item": "alchemy_items", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_tools_and_loot", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 20, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] } + ], + "v": { "item": "boss_treasure_items", "chance": 70, "repeat": [ 1, 3 ] }, + "d": [ + { "item": "magic_shop_clothes", "chance": 25, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_small_items", "chance": 20, "repeat": [ 1, 2 ] } + ], + "R": [ { "item": "classless_items", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_3rd", + "object": { + "fill_ter": "t_floor", + "rows": [ + "__....................__", + "__......________......__", + "__......________......__", + "__........____........__", + "____......____......____", + "____......____......____", + "____.......__.......____", + "_____......__......_____", + "______...##))##...______", + "______..##< >##..______", + "______.##))]]))##.______", + "______##y ##______", + "______)i h h h h )______", + "______)i & & & & )______", + "______## ##______", + "______.##R && R##.______", + "_____...## E y##..._____", + "_____....##))##...._____", + "____......#__#......____", + "___........__........___", + ".....______________.....", + ".....______________.....", + ".....______________.....", + "........................" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c", ".": "t_shingle_flat_roof" }, + "furniture": { "&": "f_magic_bench" }, + "items": { + "&": [ + { "item": "magic_tools_and_loot", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_wands", "chance": 5 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_4th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##> <##________", + "_______##))]]))##_______", + "______##y ##______", + "______)i h h h h )______", + "______)i & & & & )______", + "______## ##______", + "_______##R && R##_______", + "________## E y##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c" }, + "furniture": { "&": "f_magic_bench" }, + "items": { + "&": [ + { "item": "magic_tools_and_loot", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_wands", "chance": 5 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_5th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##< >##________", + "_______##))]]))##_______", + "______##Tx y##______", + "______)Hl ee lH)______", + "______)Hl ee lH)______", + "______##y ee T##______", + "_______##y y##_______", + "________##k Es##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c" }, + "place_loot": [ { "item": "television", "x": 9, "y": 11, "chance": 100 }, { "item": "stereo", "x": 13, "y": 16, "chance": 100 } ], + "items": { + "l": { "item": "enchanted_small_items", "chance": 15 }, + "H": [ + { "item": "magic_shop_clothes", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_worn_items", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] } + ], + "s": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 10 }, + { "item": "enchanted_misc", "chance": 5 } + ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_6th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##> <##________", + "_______##))]]))##_______", + "______##R R##______", + "______)rh RRRR hr)______", + "______)rh RRRR hr)______", + "______##R R##______", + "_______##R hh R##_______", + "________##RrrR##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c" }, + "items": { + "r": [ + { "item": "magic_shop_books", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 2 }, + { "item": "enchanted_misc", "chance": 5 } + ], + "R": [ { "item": "magic_shop_books", "chance": 30, "repeat": [ 1, 2 ] }, { "item": "enchanted_misc", "chance": 5 } ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_7th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##< >##________", + "_______##))]]))##_______", + "______##? ?##______", + "______) A= =A )______", + "______) A= =A )______", + "______##? - - ?##______", + "_______##? ?##_______", + "________##? ?##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { "_": "t_open_air", ")": "t_wall_glass", "#": "t_rock_wall", "-": "t_floor", "]": "t_door_glass_c" }, + "furniture": { "=": "f_magic_bench", "-": "f_alembic", "?": "f_rack_wood" }, + "items": { + "=": [ + { "item": "alchemy_items", "chance": 35, "repeat": [ 1, 2 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] }, + { "item": "magic_recipe_basic", "chance": 40 }, + { "item": "magic_shop_wands", "chance": 5 } + ], + "?": [ + { "item": "alchemy_items", "chance": 45, "repeat": [ 1, 3 ] }, + { "item": "magic_shop_potions", "chance": 30, "repeat": [ 1, 2 ] } + ] + }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_8th", + "object": { + "fill_ter": "t_floor", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________##))##_________", + "________##> <##________", + "_______## ##_______", + "______## ==== ##______", + "______)i ===-== i)______", + "______)i ==0=== i)______", + "______## ==== ##______", + "_______## ##_______", + "________## ii ##________", + "_________##))##_________", + "__________#__#__________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "palettes": [ "standard_domestic_palette" ], + "terrain": { + "_": "t_open_air", + ")": "t_wall_glass", + "#": "t_rock_wall", + "]": "t_door_glass_c", + "=": "t_grass_golf", + "0": "t_grass_golf", + "-": "t_grass_golf" + }, + "furniture": { "0": "f_orrery", "-": "f_magic_circle" }, + "place_monsters": [ { "monster": "GROUP_TOWER_GOLEM", "x": 12, "y": 12, "density": 0.01, "repeat": [ 1, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "magic_academy_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________", + "_________ _________", + "________ > ________", + "_______ _______", + "______ ______", + "______ ______", + "______ ______", + "______ ______", + "_______ _______", + "________ ________", + "_________ _________", + "__________ __ __________", + "________________________", + "________________________", + "________________________", + "________________________", + "________________________" + ], + "terrain": { ">": "t_stairs_down", "_": "t_open_air" }, + "items": { + "i": [ + { "item": "magic_shop_potions", "chance": 30 }, + { "item": "magic_shop_wands", "chance": 20 }, + { "item": "enchanted_small_items", "chance": 10, "repeat": [ 1, 2 ] }, + { "item": "enchanted_combat_items", "chance": 10 }, + { "item": "enchanted_misc", "chance": 5 } + ] + } + } + } +] diff --git a/data/mods/Magiclysm/worldgen/magic_basement.json b/data/mods/Magiclysm/worldgen/magic_basement.json index 5253206cdaeda..51f943221a705 100644 --- a/data/mods/Magiclysm/worldgen/magic_basement.json +++ b/data/mods/Magiclysm/worldgen/magic_basement.json @@ -34,7 +34,7 @@ ], "palettes": [ "standard_domestic_palette" ], "place_traps": [ { "trap": "tr_magic_door", "x": 21, "y": 4 } ], - "place_item": [ { "item": "television", "x": 21, "y": 10 } ], + "place_item": [ { "item": "television", "x": 21, "y": 10 }, { "item": "wizard_photo", "x": 16, "y": 6 } ], "place_loot": [ { "item": "corpse", "x": 2, "y": 6, "chance": 100 }, { "item": "translocate_spellbook", "x": 2, "y": 6, "chance": 100 }, diff --git a/data/mods/Magiclysm/worldgen/multitile_city_buildings.json b/data/mods/Magiclysm/worldgen/multitile_city_buildings.json index 21f0fe4c74725..8b3ed83644264 100644 --- a/data/mods/Magiclysm/worldgen/multitile_city_buildings.json +++ b/data/mods/Magiclysm/worldgen/multitile_city_buildings.json @@ -42,5 +42,22 @@ { "point": [ 0, 0, 1 ], "overmap": "house_detatched5_roof_north" }, { "point": [ 0, 0, -1 ], "overmap": "magic_basement_north" } ] + }, + { + "type": "city_building", + "id": "magic_academy", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "magic_academy_ground_north" }, + { "point": [ 0, 0, 1 ], "overmap": "magic_academy_2nd_north" }, + { "point": [ 0, 0, 2 ], "overmap": "magic_academy_3rd_north" }, + { "point": [ 0, 0, 3 ], "overmap": "magic_academy_4th_north" }, + { "point": [ 0, 0, 4 ], "overmap": "magic_academy_5th_north" }, + { "point": [ 0, 0, 5 ], "overmap": "magic_academy_6th_north" }, + { "point": [ 0, 0, 6 ], "overmap": "magic_academy_7th_north" }, + { "point": [ 0, 0, 7 ], "overmap": "magic_academy_8th_north" }, + { "point": [ 0, 0, 8 ], "overmap": "magic_academy_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "magic_academy_basement_north" } + ] } ] diff --git a/data/mods/Magiclysm/worldgen/overmap_terrain.json b/data/mods/Magiclysm/worldgen/overmap_terrain.json index 3047ecc6e4180..8405a6b82bd1d 100644 --- a/data/mods/Magiclysm/worldgen/overmap_terrain.json +++ b/data/mods/Magiclysm/worldgen/overmap_terrain.json @@ -352,5 +352,94 @@ "type": "overmap_terrain", "id": "wizardtower2_roof", "copy-from": "wizardtower1_ground" + }, + { + "type": "overmap_terrain", + "id": "magic_academy_ground", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "see_cost": 5, + "mondensity": 2, + "flags": [ "SIDEWALK" ] + }, + { + "type": "overmap_terrain", + "id": "magic_academy_2nd", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_3rd", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_4th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_5th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_6th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_7th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_8th", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_basement", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "mondensity": 2, + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "magic_academy_roof", + "name": "magic academy", + "sym": "#", + "color": "light_blue", + "see_cost": 5 } ] diff --git a/data/mods/Magiclysm/worldgen/regional_overlay.json b/data/mods/Magiclysm/worldgen/regional_overlay.json index 55f79dc7cd4ab..2480ba8fc2076 100644 --- a/data/mods/Magiclysm/worldgen/regional_overlay.json +++ b/data/mods/Magiclysm/worldgen/regional_overlay.json @@ -2,7 +2,10 @@ { "type": "region_overlay", "regions": [ "all" ], - "city": { "houses": { "wizard_tower_1": 10, "wizard_tower_2": 20 }, "shops": { "magic_shop": 100, "used_bookstore": 225 } }, + "city": { + "houses": { "wizard_tower_1": 10, "wizard_tower_2": 20 }, + "shops": { "magic_shop": 100, "used_bookstore": 225, "magic_academy": 150 } + }, "field_coverage": { "other": { "f_boulder_large": 0.6667, "f_glow_boulder": 0.3333 } } } ] From 13ddb138524fb62159315322704045023bf33271 Mon Sep 17 00:00:00 2001 From: arijust <54635208+arijust@users.noreply.github.com> Date: Sun, 8 Mar 2020 18:09:51 +0100 Subject: [PATCH 131/219] Magiclysm: Forest Tomb (#37699) --- data/mods/Magiclysm/furniture.json | 19 +++ .../mods/Magiclysm/itemgroups/itemgroups.json | 5 + data/mods/Magiclysm/worldgen/forest_tomb.json | 134 ++++++++++++++++++ .../Magiclysm/worldgen/overmap_specials.json | 13 ++ .../Magiclysm/worldgen/overmap_terrain.json | 18 +++ 5 files changed, 189 insertions(+) create mode 100644 data/mods/Magiclysm/worldgen/forest_tomb.json diff --git a/data/mods/Magiclysm/furniture.json b/data/mods/Magiclysm/furniture.json index ec16f5732a843..e33595f37be77 100644 --- a/data/mods/Magiclysm/furniture.json +++ b/data/mods/Magiclysm/furniture.json @@ -186,5 +186,24 @@ { "item": "glass_shard", "count": [ 8, 12 ] } ] } + }, + { + "type": "furniture", + "id": "f_altar", + "name": "stone altar", + "move_cost_mod": 10, + "symbol": "H", + "color": "light_gray", + "coverage": 40, + "required_str": 30, + "flags": [ "BASHABLE" ], + "description": "This is big stone altar. Most commonly used in morally questionable rituals.", + "bash": { + "str_min": 30, + "str_max": 160, + "sound": "smash!", + "sound_fail": "thump.", + "items": [ { "item": "rock", "count": [ 5, 15 ] }, { "item": "sharp_rock", "count": [ 3, 5 ] } ] + } } ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 45016883441b1..594ec79cd6995 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -1034,5 +1034,10 @@ "type": "item_group", "id": "magic_basement_photo", "items": [ [ "wizard_photo", 100 ] ] + }, + { + "type": "item_group", + "id": "forest_tomb_spellbook", + "items": [ [ "summon_undead_spellbook", 100 ] ] } ] diff --git a/data/mods/Magiclysm/worldgen/forest_tomb.json b/data/mods/Magiclysm/worldgen/forest_tomb.json new file mode 100644 index 0000000000000..9e2e259afeba4 --- /dev/null +++ b/data/mods/Magiclysm/worldgen/forest_tomb.json @@ -0,0 +1,134 @@ +[ + { + "type": "palette", + "id": "tomb", + "terrain": { + ".": "t_rock_floor", + " ": [ [ "t_grass_dead", 15 ], [ "t_dirt", 4 ], [ "t_dirtmound", 3 ], [ "t_rock_floor_no_roof", 4 ] ], + "T": "t_tree_dead", + "R": "t_railroad_rubble", + "S": "t_shrub", + "<": "t_slope_up", + ">": "t_slope_down", + "#": "t_rock" + }, + "furniture": { "H": "f_altar", "C": "f_coffin_c" }, + "items": { "R": { "item": "animist_items", "chance": 25 }, "H": { "item": "forest_tomb_spellbook", "chance": 100 } }, + "monster": { "x": { "monster": "mon_skeleton", "chance": 50 }, "Z": { "monster": "mon_zombie_necro", "chance": 100 } } + }, + { + "type": "palette", + "id": "tomb_roof", + "terrain": { ".": "t_rock_roof", " ": "t_open_air", ">": "t_slope_down" } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "forest_tomb" ], + "//": "Ground level - Z-0.", + "weight": 100, + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + " S ", + " S ", + " S ", + " S ", + " S ", + " S S ", + " ##<############### ", + " ################## ", + " S ####C.##>>##..C### ", + " ###x..........###............... ", + " .................. ", + " .................. ", + " .................> ", + " .................. ", + " .................. ", + " .................. ", + " .................. ", + " .................. ", + " .............>.... ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "tomb_roof" ] + } + } +] diff --git a/data/mods/Magiclysm/worldgen/overmap_specials.json b/data/mods/Magiclysm/worldgen/overmap_specials.json index 793fa84e1f4bb..59bd3170213d4 100644 --- a/data/mods/Magiclysm/worldgen/overmap_specials.json +++ b/data/mods/Magiclysm/worldgen/overmap_specials.json @@ -114,5 +114,18 @@ "city_sizes": [ 4, 12 ], "occurrences": [ 0, 1 ], "flags": [ "CLASSIC", "LAKE" ] + }, + { + "type": "overmap_special", + "id": "forest_tomb", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "forest_tomb_north" }, + { "point": [ 0, 0, 1 ], "overmap": "forest_tomb_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "forest_tomb_bottom_north" } + ], + "locations": [ "wilderness" ], + "city_distance": [ 20, -1 ], + "city_sizes": [ 0, 20 ], + "occurrences": [ 0, 1 ] } ] diff --git a/data/mods/Magiclysm/worldgen/overmap_terrain.json b/data/mods/Magiclysm/worldgen/overmap_terrain.json index 8405a6b82bd1d..be7c1f4a01a69 100644 --- a/data/mods/Magiclysm/worldgen/overmap_terrain.json +++ b/data/mods/Magiclysm/worldgen/overmap_terrain.json @@ -353,6 +353,24 @@ "id": "wizardtower2_roof", "copy-from": "wizardtower1_ground" }, + { + "type": "overmap_terrain", + "id": "forest_tomb", + "name": "forest", + "sym": "F", + "color": "brown", + "see_cost": 5 + }, + { + "type": "overmap_terrain", + "id": "forest_tomb_roof", + "copy-from": "forest_tomb" + }, + { + "type": "overmap_terrain", + "id": "forest_tomb_bottom", + "copy-from": "forest_tomb" + }, { "type": "overmap_terrain", "id": "magic_academy_ground", From 9ee18d024aae8e4b89c809defc846c1a94b3b8ef Mon Sep 17 00:00:00 2001 From: LaVeyanFiend <51099123+LaVeyanFiend@users.noreply.github.com> Date: Sat, 14 Mar 2020 20:17:37 -0400 Subject: [PATCH 132/219] Add demon chitin armor & repairing dragon armor (#36733) --- .../Magiclysm/enchanted/enchanted_misc.json | 16 ++- .../mods/Magiclysm/itemgroups/itemgroups.json | 5 +- .../Magiclysm/itemgroups/recipe_books.json | 6 + data/mods/Magiclysm/items/armor.json | 78 ++++++++++++ data/mods/Magiclysm/items/recipe_books.json | 19 +++ data/mods/Magiclysm/items/tools.json | 79 ++++++++++++ data/mods/Magiclysm/materials.json | 4 +- data/mods/Magiclysm/recipes/armor.json | 117 ++++++++++++++++++ 8 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 data/mods/Magiclysm/recipes/armor.json diff --git a/data/mods/Magiclysm/enchanted/enchanted_misc.json b/data/mods/Magiclysm/enchanted/enchanted_misc.json index 9729aa87c09ef..005f61aae532d 100644 --- a/data/mods/Magiclysm/enchanted/enchanted_misc.json +++ b/data/mods/Magiclysm/enchanted/enchanted_misc.json @@ -143,7 +143,19 @@ { "type": "repair_item", "item_action_type": "repair_fabric", - "materials": [ "cotton", "leather", "wool", "fur", "faux_fur", "nomex", "kevlar", "neoprene", "gutskin" ], + "materials": [ + "cotton", + "leather", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "neoprene", + "gutskin", + "black_dragon_hide", + "demon_chitin" + ], "skill": "tailor", "tool_quality": 1, "cost_scaling": 0.1, @@ -153,7 +165,7 @@ "type": "sew_advanced", "materials": [ "cotton", "leather", "wool", "fur", "faux_fur", "nomex", "kevlar", "neoprene", "gutskin", "plastic", "kevlar_rigid" ], "skill": "tailor", - "clothing_mods": [ "leather_padded", "kevlar_padded", "furred", "wooled" ] + "clothing_mods": [ "leather_padded", "steel_padded", "kevlar_padded", "furred", "wooled" ] } ], "flags": [ "ALLOWS_REMOTE_USE" ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 594ec79cd6995..f10240557c95e 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -31,6 +31,7 @@ "items": [ { "group": "spellbook_loot_1", "prob": 3 }, { "group": "magic_recipe_basic", "prob": 3 }, + { "group": "magic_recipe_advanced", "prob": 1 }, { "group": "dragon_books", "prob": 3 } ] }, @@ -40,6 +41,7 @@ "items": [ { "group": "spellbook_loot_0", "prob": 6 }, { "group": "magic_recipe_basic", "prob": 6 }, + { "group": "magic_recipe_advanced", "prob": 2 }, { "group": "dragon_books", "prob": 5 } ] }, @@ -105,7 +107,8 @@ { "group": "spell_scroll_tier_0", "prob": 80 }, { "group": "spell_scroll_tier_1", "prob": 60 }, { "group": "spell_scroll_tier_2", "prob": 30 }, - { "group": "magic_recipe_basic", "prob": 50 } + { "group": "magic_recipe_basic", "prob": 50 }, + { "group": "magic_recipe_advanced", "prob": 16 } ] }, { diff --git a/data/mods/Magiclysm/itemgroups/recipe_books.json b/data/mods/Magiclysm/itemgroups/recipe_books.json index c6cac26152c99..aaf2e28b742b7 100644 --- a/data/mods/Magiclysm/itemgroups/recipe_books.json +++ b/data/mods/Magiclysm/itemgroups/recipe_books.json @@ -10,5 +10,11 @@ [ "book_mythological", 10 ], [ "cooking_poison", 15 ] ] + }, + { + "id": "magic_recipe_advanced", + "type": "item_group", + "//": "Higher tier recipes, where most school-related recipes require their rune or rune weapon.", + "items": [ [ "magic_armormaking", 30 ] ] } ] diff --git a/data/mods/Magiclysm/items/armor.json b/data/mods/Magiclysm/items/armor.json index 1d637cfb5b7b1..13dcb8127e121 100644 --- a/data/mods/Magiclysm/items/armor.json +++ b/data/mods/Magiclysm/items/armor.json @@ -26,5 +26,83 @@ "copy-from": "quiver_large_birchbark", "type": "ARMOR", "use_action": { "type": "bandolier", "capacity": 60, "ammo": [ "arrow", "bolt", "arrow_orichalcum" ], "draw_cost": 20 } + }, + { + "id": "armguard_demonchitin", + "copy-from": "armguard_chitin", + "type": "ARMOR", + "name": { "str": "pair of demon chitin arm guards", "str_pl": "pairs of demon chitin arm guards" }, + "description": "A pair of arm guards crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "armor_demonchitin", + "copy-from": "armor_chitin", + "type": "ARMOR", + "name": { "str": "demon chitin armor" }, + "description": "Leg and body armor crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "helmet_demonchitin", + "copy-from": "helmet_chitin", + "type": "ARMOR", + "name": { "str": "demon chitin helmet" }, + "description": "A helmet crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Covers the entire head; fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "gauntlets_demonchitin", + "copy-from": "gauntlets_chitin", + "type": "ARMOR", + "name": { "str": "pair of demon chitin gauntlets", "str_pl": "pairs of demon chitin gauntlets" }, + "description": "Gauntlets crafted from the carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "id": "boots_demonchitin", + "copy-from": "boots_chitin", + "type": "ARMOR", + "name": { "str": "pair of demon chitin boots", "str_pl": "pairs of demon chitin boots" }, + "description": "Boots crafted from carefully cleaned and pruned pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "material": [ "demon_chitin" ], + "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, + "environmental_protection": 8 + }, + { + "type": "PET_ARMOR", + "id": "demonchitin_harness_dog", + "copy-from": "kevlar_harness", + "color": "red", + "name": { "str": "demon chitin dog mesh harness", "str_pl": "demon chitin dog mesh harnesses" }, + "description": "A makeshift harness of demon chitin fitted to a thin mesh protecting the neck to flank of canines. You could put this on a friendly dog.", + "price": 50000, + "price_postapoc": 5000, + "material": [ "demon_chitin" ], + "weight": "4862 g", + "environmental_protection": 8 + }, + { + "type": "PET_ARMOR", + "id": "demonchitin_armor_horse", + "copy-from": "horse_armor", + "color": "green", + "name": { "str": "demon chitin horse armor" }, + "description": "A makeshift assembly of criniere, peytral and croupiere made from demon chitin fitted to a thin mesh. You could put this on a friendly horse.", + "price": 120000, + "price_postapoc": 12000, + "material": [ "demon_chitin", "steel" ], + "weight": "31500 g", + "volume": "150 L", + "material_thickness": 6, + "environmental_protection": 8 } ] diff --git a/data/mods/Magiclysm/items/recipe_books.json b/data/mods/Magiclysm/items/recipe_books.json index 504dd26599ddc..ac79f101d3cba 100644 --- a/data/mods/Magiclysm/items/recipe_books.json +++ b/data/mods/Magiclysm/items/recipe_books.json @@ -113,5 +113,24 @@ "intelligence": 9, "time": "20 m", "fun": 1 + }, + { + "id": "magic_armormaking", + "type": "BOOK", + "name": { "str": "Protection from Magical Beasts", "str_pl": "copies of Protection from Magical Beasts" }, + "description": "A leatherbound book with a picture of a shield holding back dragonfire on the cover. There are many ways to turn monster skins and hides into protective equipment inside.", + "weight": "1 kg", + "volume": "750 ml", + "price": 7900, + "bashing": 5, + "material": [ "paper" ], + "symbol": "?", + "color": "white", + "skill": "tailor", + "required_level": 6, + "max_level": 8, + "intelligence": 10, + "time": "25 m", + "fun": -1 } ] diff --git a/data/mods/Magiclysm/items/tools.json b/data/mods/Magiclysm/items/tools.json index c22bb65385f96..1ee4ba7663ec8 100644 --- a/data/mods/Magiclysm/items/tools.json +++ b/data/mods/Magiclysm/items/tools.json @@ -19,5 +19,84 @@ "watertight": true, "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 2 ] ], "use_action": "HEAT_FOOD" + }, + { + "id": "sewing_kit", + "name": "sewing kit", + "copy-from": "sewing_kit", + "type": "TOOL", + "use_action": { + "type": "repair_item", + "item_action_type": "repair_fabric", + "materials": [ + "cotton", + "leather", + "lycra", + "nylon", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "gutskin", + "demon_chitin", + "black_dragon_hide" + ], + "skill": "tailor", + "tool_quality": 0, + "cost_scaling": 0.1, + "move_cost": 1000 + } + }, + { + "id": "tailors_kit", + "name": "tailor's kit", + "copy-from": "tailors_kit", + "type": "TOOL", + "use_action": [ + { + "type": "repair_item", + "item_action_type": "repair_fabric", + "materials": [ + "cotton", + "leather", + "lycra", + "nylon", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "neoprene", + "gutskin", + "black_dragon_hide", + "demon_chitin" + ], + "skill": "tailor", + "tool_quality": 1, + "cost_scaling": 0.1, + "move_cost": 800 + }, + { + "type": "sew_advanced", + "materials": [ + "cotton", + "leather", + "lycra", + "nylon", + "wool", + "fur", + "faux_fur", + "nomex", + "kevlar", + "neoprene", + "gutskin", + "plastic", + "kevlar_rigid" + ], + "skill": "tailor", + "clothing_mods": [ "leather_padded", "steel_padded", "kevlar_padded", "furred", "wooled" ] + } + ] } ] diff --git a/data/mods/Magiclysm/materials.json b/data/mods/Magiclysm/materials.json index 6fd108288441b..5236c46aa84e7 100644 --- a/data/mods/Magiclysm/materials.json +++ b/data/mods/Magiclysm/materials.json @@ -22,7 +22,7 @@ { "type": "material", "ident": "black_dragon_hide", - "name": "black dragon hide", + "name": "Black Dragon Hide", "density": 20, "specific_heat_liquid": 4.186, "specific_heat_solid": 2.108, @@ -53,6 +53,8 @@ "fire_resist": 18, "elec_resist": 2, "chip_resist": 10, + "repaired_with": "demon_chitin_piece", + "salvaged_into": "demon_chitin_piece", "dmg_adj": [ "scratched", "cut", "cracked", "shattered" ], "bash_dmg_verb": "cracked", "cut_dmg_verb": "chipped", diff --git a/data/mods/Magiclysm/recipes/armor.json b/data/mods/Magiclysm/recipes/armor.json new file mode 100644 index 0000000000000..962dbe57f405f --- /dev/null +++ b/data/mods/Magiclysm/recipes/armor.json @@ -0,0 +1,117 @@ +[ + { + "result": "helmet_demonchitin", + "byproducts": [ [ "demon_chitin_piece", 3 ] ], + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 7, + "time": "4 h", + "book_learn": [ [ "magic_armormaking", 6 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 1 ] ], [ [ "demon_chitin_piece", 1 ] ] ] + }, + { + "result": "armguard_demonchitin", + "byproducts": [ [ "demon_chitin_piece", 8 ] ], + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 6, + "time": "2 h", + "book_learn": [ [ "magic_armormaking", 5 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 1 ] ], [ [ "demon_chitin_piece", 2 ] ] ] + }, + { + "result": "armor_demonchitin", + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 8, + "time": "4 h", + "book_learn": [ [ "magic_armormaking", 7 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 4 ] ], [ [ "demon_chitin_piece", 6 ] ] ] + }, + { + "result": "boots_demonchitin", + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 5, + "time": "2 h 40 m", + "book_learn": [ [ "magic_armormaking", 4 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_plate", 1 ] ], [ [ "demon_chitin_piece", 2 ] ] ] + }, + { + "result": "gauntlets_demonchitin", + "qualities": [ + { "id": "CHISEL", "level": 1 }, + { "id": "SEW", "level": 3 }, + { "id": "LEATHER_AWL", "level": 1 }, + { "id": "MANA_INFUSE", "level": 2 } + ], + "type": "recipe", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "skills_required": [ [ "spellcraft", 6 ] ], + "difficulty": 5, + "time": "2 h", + "book_learn": [ [ "magic_armormaking", 4 ] ], + "components": [ [ [ "cordage_superior", 1, "LIST" ] ], [ [ "demon_chitin_piece", 10 ] ] ] + }, + { + "result": "demonchitin_armor_horse", + "type": "recipe", + "copy-from": "armor_demonchitin", + "category": "CC_ANIMALS", + "subcategory": "CSC_ANIMALS_EQUINE ARMOR", + "time": "17 h 30 m", + "book_learn": [ [ "textbook_tailor", 5 ], [ "tailor_portfolio", 5 ] ], + "skills_required": [ [ "spellcraft", 6 ], [ "fabrication", 4 ], [ "survival", 4 ] ], + "using": [ [ "cordage", 7 ] ], + "components": [ [ [ "demon_chitin_plate", 4 ] ], [ [ "demon_chitin_piece", 20 ] ] ] + }, + { + "result": "demonchitin_harness_dog", + "type": "recipe", + "copy-from": "armor_demonchitin", + "category": "CC_ANIMALS", + "subcategory": "CSC_ANIMALS_CANINE ARMOR", + "skills_required": [ [ "spellcraft", 6 ], [ "fabrication", 4 ], [ "survival", 4 ] ], + "time": "5 h", + "using": [ [ "cordage", 1 ] ], + "components": [ [ [ "demon_chitin_piece", 12 ] ] ] + } +] From 159aefdd114ad0cadf33d05e9a1548668c265cb9 Mon Sep 17 00:00:00 2001 From: KorGgenT Date: Sat, 22 Feb 2020 21:54:42 -0500 Subject: [PATCH 133/219] Read ids and save ids for enchantments (#38262) --- src/magic_enchantment.cpp | 7 +++++++ src/relic.cpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 6fb9375ac688c..e095fdd84644d 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -241,6 +241,13 @@ void enchantment::serialize( JsonOut &jsout ) const { jsout.start_object(); + if( !id.is_empty() ) { + jsout.member( "id", id ); + jsout.end_object(); + // if the enchantment has an id then it is defined elsewhere and does not need to be serialized. + return; + } + jsout.member( "has", io::enum_to_string( active_conditions.first ) ); jsout.member( "condition", io::enum_to_string( active_conditions.second ) ); diff --git a/src/relic.cpp b/src/relic.cpp index baeea1cd5e805..72bb8f238d271 100644 --- a/src/relic.cpp +++ b/src/relic.cpp @@ -37,6 +37,9 @@ void relic::load( const JsonObject &jo ) for( JsonObject jobj : jo.get_array( "passive_effects" ) ) { enchantment ench; ench.load( jobj ); + if( !ench.id.is_empty() ) { + ench = ench.id.obj(); + } add_passive_effect( ench ); } } From 5ac287c89959d09c022ce01524f40377cfc176d2 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 11 Mar 2020 02:54:37 -0400 Subject: [PATCH 134/219] Jsonize spell skills (#37368) --- src/activity_handlers.cpp | 4 ++-- src/magic.cpp | 15 +++++++++++---- src/magic.h | 3 +++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 3d2be998e8213..2f75554ca47f1 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -4661,8 +4661,8 @@ void activity_handlers::study_spell_finish( player_activity *act, player *p ) if( act->get_str_value( 1 ) == "study" ) { p->add_msg_if_player( m_good, _( "You gained %i experience from your study session." ), total_exp_gained ); - p->practice( skill_id( "spellcraft" ), total_exp_gained, - p->magic.get_spell( spell_id( act->name ) ).get_difficulty() ); + const spell &sp = p->magic.get_spell( spell_id( act->name ) ); + p->practice( sp.skill(), total_exp_gained, sp.get_difficulty() ); } else if( act->get_str_value( 1 ) == "learn" && act->values[2] == 0 ) { p->magic.learn_spell( act->name, *p ); } diff --git a/src/magic.cpp b/src/magic.cpp index 3edd6db825919..cb89ab44c848c 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -24,6 +24,7 @@ #include "mutation.h" #include "output.h" #include "player.h" +#include "skill.h" #include "sounds.h" #include "translations.h" #include "ui.h" @@ -231,6 +232,7 @@ void spell_type::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "id", id ); mandatory( jo, was_loaded, "name", name ); mandatory( jo, was_loaded, "description", description ); + optional( jo, was_loaded, "skill", skill, skill_id( "spellcraft" ) ); optional( jo, was_loaded, "message", message, to_translation( "You cast %s!" ) ); optional( jo, was_loaded, "sound_description", sound_description, to_translation( "an explosion" ) ); @@ -445,6 +447,11 @@ trait_id spell::spell_class() const return type->spell_class; } +skill_id spell::skill() const +{ + return type->skill; +} + int spell::field_intensity() const { return std::min( type->max_field_intensity, @@ -706,7 +713,7 @@ float spell::spell_fail( const player &p ) const // effective skill of 8 (8 int, 0 spellcraft, 0 spell level, spell difficulty 0) is ~50% failure // effective skill of 30 is 0% failure const float effective_skill = 2 * ( get_level() - get_difficulty() ) + p.get_int() + - p.get_skill_level( skill_id( "spellcraft" ) ); + p.get_skill_level( skill() ); // add an if statement in here because sufficiently large numbers will definitely overflow because of exponents if( effective_skill > 30.0f ) { return 0.0f; @@ -1022,7 +1029,7 @@ float spell::exp_modifier( const player &p ) const { const float int_modifier = ( p.get_int() - 8.0f ) / 8.0f; const float difficulty_modifier = get_difficulty() / 20.0f; - const float spellcraft_modifier = p.get_skill_level( skill_id( "spellcraft" ) ) / 10.0f; + const float spellcraft_modifier = p.get_skill_level( skill() ) / 10.0f; return ( int_modifier + difficulty_modifier + spellcraft_modifier ) / 5.0f + 1.0f; } @@ -1431,8 +1438,8 @@ int known_magic::time_to_learn_spell( const player &p, const std::string &str ) int known_magic::time_to_learn_spell( const player &p, const spell_id &sp ) const { const int base_time = to_moves( 30_minutes ); - return base_time * ( 1.0 + sp.obj().difficulty / ( 1.0 + ( p.get_int() - 8.0 ) / 8.0 ) + - ( p.get_skill_level( skill_id( "spellcraft" ) ) / 10.0 ) ); + return base_time * ( 1.0 + sp->difficulty / ( 1.0 + ( p.get_int() - 8.0 ) / 8.0 ) + + ( p.get_skill_level( sp->skill ) / 10.0 ) ); } int known_magic::get_spellname_max_width() diff --git a/src/magic.h b/src/magic.h index ff81b13e3fbe8..94bcf20c335e9 100644 --- a/src/magic.h +++ b/src/magic.h @@ -133,6 +133,7 @@ class spell_type translation message; // spell sound effect translation sound_description; + skill_id skill; sounds::sound_t sound_type = sounds::sound_t::_LAST; bool sound_ambient = false; std::string sound_id; @@ -355,6 +356,8 @@ class spell spell_id id() const; // get spell class (from type) trait_id spell_class() const; + // get skill id + skill_id skill() const; // get spell effect string (from type) std::string effect() const; // get spell effect_str data From 35ee30541bb0ec0876191069d485d483d62085c5 Mon Sep 17 00:00:00 2001 From: KorGgenT Date: Thu, 20 Feb 2020 20:18:52 -0500 Subject: [PATCH 135/219] JSONize AEP_EVIL and implement intermittent artifact effects (#38221) --- data/json/legacy_artifact_passive.json | 16 ++++++++++++++++ src/magic_enchantment.cpp | 12 +++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/data/json/legacy_artifact_passive.json b/data/json/legacy_artifact_passive.json index 20924033ff565..f7ab1028403f8 100644 --- a/data/json/legacy_artifact_passive.json +++ b/data/json/legacy_artifact_passive.json @@ -72,5 +72,21 @@ "type": "enchantment", "id": "AEP_SPEED_DOWN", "values": [ { "value": "SPEED", "add": -20 } ] + }, + { + "type": "SPELL", + "id": "AEP_EVIL_SPELL", + "name": "EEEEEEVVVVVIIIIILLLL!", + "description": "You debugged in this spell! It makes you evil for 30 minutes.", + "valid_targets": [ "hostile", "ally", "self" ], + "effect": "target_attack", + "effect_str": "evil", + "min_duration": 180000, + "max_duration": 180000 + }, + { + "type": "enchantment", + "id": "AEP_EVIL", + "intermittent_activation": { "effects": [ { "frequency": "15 minutes", "spell_effects": [ { "id": "AEP_EVIL_SPELL" } ] } ] } } ] diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index e095fdd84644d..d2b222fdd70bd 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -200,7 +200,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) if( jo.has_object( "intermittent_activation" ) ) { JsonObject jobj = jo.get_object( "intermittent_activation" ); - for( const JsonObject effect_obj : jo.get_array( "effects" ) ) { + for( const JsonObject effect_obj : jobj.get_array( "effects" ) ) { time_duration dur = read_from_json_string( *effect_obj.get_raw( "frequency" ), time_duration::units ); if( effect_obj.has_array( "spell_effects" ) ) { @@ -374,6 +374,16 @@ void enchantment::activate_passive( Character &guy ) const guy.mod_num_dodges_bonus( get_value_add( mod::BONUS_DODGE ) ); guy.mod_num_dodges_bonus( mult_bonus( mod::BONUS_DODGE, guy.get_num_dodges_base() ) ); + + for( const std::pair> &activation : + intermittent_activation ) { + // a random approximation! + if( one_in( to_seconds( activation.first ) ) ) { + for( const fake_spell &fake : activation.second ) { + fake.get_spell( 0 ).cast_all_effects( guy, guy.pos() ); + } + } + } } void enchantment::cast_hit_you( Character &caster, const tripoint &target ) const From 8b8b78f059b15f85fc8bbf4b352b0ee2308103a5 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Thu, 12 Mar 2020 13:05:36 -0400 Subject: [PATCH 136/219] JSONize AEP_SMOKE and add emitters to enchantments (#38260) --- data/json/emit.json | 9 +++++++++ data/json/legacy_artifact_passive.json | 5 +++++ src/magic_enchantment.cpp | 8 ++++++++ src/magic_enchantment.h | 1 + 4 files changed, 23 insertions(+) diff --git a/data/json/emit.json b/data/json/emit.json index 6fb5cc798f6d9..f4f15d0f76d2d 100644 --- a/data/json/emit.json +++ b/data/json/emit.json @@ -15,6 +15,15 @@ "intensity": 3, "chance": 2 }, + { + "id": "emit_AEP_SMOKE", + "type": "emit", + "//": "Intermittent smoke from an artifact", + "field": "fd_smoke", + "intensity": 3, + "chance": 5, + "qty": 15 + }, { "id": "emit_smoke_blast", "type": "emit", diff --git a/data/json/legacy_artifact_passive.json b/data/json/legacy_artifact_passive.json index f7ab1028403f8..ed052a7bc71fa 100644 --- a/data/json/legacy_artifact_passive.json +++ b/data/json/legacy_artifact_passive.json @@ -73,6 +73,11 @@ "id": "AEP_SPEED_DOWN", "values": [ { "value": "SPEED", "add": -20 } ] }, + { + "type": "enchantment", + "id": "AEP_SMOKE", + "emitter": "emit_AEP_SMOKE" + }, { "type": "SPELL", "id": "AEP_EVIL_SPELL", diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index d2b222fdd70bd..8c6f0f700cb9f 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -1,6 +1,7 @@ #include "magic_enchantment.h" #include "character.h" +#include "emit.h" #include "enum_conversions.h" #include "game.h" #include "generic_factory.h" @@ -197,6 +198,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) jo.read( "hit_you_effect", hit_you_effect ); jo.read( "hit_me_effect", hit_me_effect ); + jo.read( "emitter", emitter ); if( jo.has_object( "intermittent_activation" ) ) { JsonObject jobj = jo.get_object( "intermittent_activation" ); @@ -250,6 +252,9 @@ void enchantment::serialize( JsonOut &jsout ) const jsout.member( "has", io::enum_to_string( active_conditions.first ) ); jsout.member( "condition", io::enum_to_string( active_conditions.second ) ); + if( emitter ) { + jsout.member( "emitter", emitter ); + } if( !hit_you_effect.empty() ) { jsout.member( "hit_you_effect", hit_you_effect ); @@ -375,6 +380,9 @@ void enchantment::activate_passive( Character &guy ) const guy.mod_num_dodges_bonus( get_value_add( mod::BONUS_DODGE ) ); guy.mod_num_dodges_bonus( mult_bonus( mod::BONUS_DODGE, guy.get_num_dodges_base() ) ); + if( emitter ) { + g->m.emit_field( guy.pos(), *emitter ); + } for( const std::pair> &activation : intermittent_activation ) { // a random approximation! diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 9fce4e38b0b8f..e8d66b3aa293b 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -138,6 +138,7 @@ class enchantment // casts all the hit_me_effects on self void cast_hit_me( Character &caster ) const; private: + cata::optional emitter; // values that add to the base value std::map values_add; // values that get multiplied to the base value From 7b300cf63574b0008be219af29b2a4423a8634da Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 11 Mar 2020 02:56:16 -0400 Subject: [PATCH 137/219] Traps can cast spells (#38122) --- data/mods/Magiclysm/Spells/monsterspells.json | 18 ++++++++++++++++++ data/mods/Magiclysm/traps.json | 15 +++++++++++++++ src/trap.cpp | 1 + src/trap.h | 4 ++++ src/trapfunc.cpp | 15 +++++++++++++++ 5 files changed, 53 insertions(+) create mode 100644 data/mods/Magiclysm/traps.json diff --git a/data/mods/Magiclysm/Spells/monsterspells.json b/data/mods/Magiclysm/Spells/monsterspells.json index 7976d85806aee..713afe9505de4 100644 --- a/data/mods/Magiclysm/Spells/monsterspells.json +++ b/data/mods/Magiclysm/Spells/monsterspells.json @@ -17,6 +17,24 @@ "effect": "projectile_attack", "extra_effects": [ { "id": "light_healing", "hit_self": true } ] }, + { + "id": "bear_trap", + "type": "SPELL", + "name": "Bear Trap", + "description": "A trap that summons bears! Not what you were expecting, is it?", + "valid_targets": [ "ground" ], + "flags": [ "HOSTILE_SUMMON", "LOUD" ], + "min_damage": 3, + "max_damage": 3, + "min_aoe": 5, + "max_aoe": 5, + "sound_description": "\"It's a trap!\"", + "min_duration": 30000, + "max_duration": 30000, + "sound_type": "speech", + "effect": "summon", + "effect_str": "mon_bear" + }, { "id": "rocket_punch", "type": "SPELL", diff --git a/data/mods/Magiclysm/traps.json b/data/mods/Magiclysm/traps.json new file mode 100644 index 0000000000000..278152784cf32 --- /dev/null +++ b/data/mods/Magiclysm/traps.json @@ -0,0 +1,15 @@ +[ + { + "type": "trap", + "id": "tr_bear", + "name": "bear trap", + "color": "blue", + "symbol": "^", + "action": "spell", + "visibility": 2, + "trap_radius": 2, + "avoidance": 99, + "difficulty": 99, + "spell_data": { "id": "bear_trap" } + } +] diff --git a/src/trap.cpp b/src/trap.cpp index 256a5f505217f..adbf172facd78 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -116,6 +116,7 @@ void trap::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "funnel_radius", funnel_radius_mm, 0 ); optional( jo, was_loaded, "comfort", comfort, 0 ); optional( jo, was_loaded, "floor_bedding_warmth", floor_bedding_warmth, 0 ); + optional( jo, was_loaded, "spell_data", spell_data ); assign( jo, "trigger_weight", trigger_weight ); for( const JsonValue entry : jo.get_array( "drops" ) ) { std::string item_type; diff --git a/src/trap.h b/src/trap.h index d93fcb6d76e85..038a66793e6f8 100644 --- a/src/trap.h +++ b/src/trap.h @@ -10,6 +10,7 @@ #include "color.h" #include "int_id.h" +#include "magic.h" #include "string_id.h" #include "translations.h" #include "type_id.h" @@ -62,6 +63,7 @@ bool shadow( const tripoint &p, Creature *c, item *i ); bool map_regen( const tripoint &p, Creature *c, item *i ); bool drain( const tripoint &p, Creature *c, item *i ); bool snake( const tripoint &p, Creature *c, item *i ); +bool cast_spell( const tripoint &p, Creature *critter, item * ); } // namespace trapfunc struct vehicle_handle_trap_data { @@ -116,6 +118,8 @@ struct trap { // For disassembly? std::vector> components; public: + // data required for trapfunc::spell() + fake_spell spell_data; int comfort = 0; int floor_bedding_warmth = 0; public: diff --git a/src/trapfunc.cpp b/src/trapfunc.cpp index 61b1daefeb034..0969e13227ab6 100644 --- a/src/trapfunc.cpp +++ b/src/trapfunc.cpp @@ -17,6 +17,7 @@ #include "messages.h" #include "monster.h" #include "mtype.h" +#include "npc.h" #include "output.h" #include "overmapbuffer.h" #include "rng.h" @@ -1376,6 +1377,19 @@ bool trapfunc::drain( const tripoint &, Creature *c, item * ) return false; } +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 ); + npc dummy; + trap_spell.cast_all_effects( dummy, critter->pos() ); + trap_spell.make_sound( p, 20 ); + g->m.remove_trap( p ); + return true; +} + bool trapfunc::snake( const tripoint &p, Creature *, item * ) { //~ the sound a snake makes @@ -1449,6 +1463,7 @@ const trap_function &trap_function_from_string( const std::string &function_name { "shadow", trapfunc::shadow }, { "map_regen", trapfunc::map_regen }, { "drain", trapfunc::drain }, + { "spell", trapfunc::cast_spell }, { "snake", trapfunc::snake } } }; From e4fdee3425384ae73e9f078b4676bbc8b141c2b8 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 6 Mar 2020 03:39:54 -0700 Subject: [PATCH 138/219] Add subway maps (#37540) --- data/json/items/book/maps.json | 17 ++++++++++++++++- data/json/mapgen/sub_station.json | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/data/json/items/book/maps.json b/data/json/items/book/maps.json index 095d1ac6720df..a599ac57fc740 100644 --- a/data/json/items/book/maps.json +++ b/data/json/items/book/maps.json @@ -71,12 +71,27 @@ "hospital", "school", "police", - "sub_station", + { "om_terrain": "sub_station", "om_terrain_match_type": "TYPE" }, "bank" ], "message": "You add roads and points of interest to your map." } }, + { + "id": "subwaymap", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": "subway maintenance map", + "looks_like": "roadmap", + "description": "This is a map of subway tunnels formerly used by public maintenance workers. Using it will add subway lines and underground stations to your map.", + "color": "light_blue", + "use_action": { + "type": "reveal_map", + "radius": 180, + "terrain": [ "subway", "sub_station" ], + "message": "You add subway lines and underground stations to your map." + } + }, { "id": "trailmap", "copy-from": "abstractmap", diff --git a/data/json/mapgen/sub_station.json b/data/json/mapgen/sub_station.json index 5881e8d04d858..200c1be0667f0 100644 --- a/data/json/mapgen/sub_station.json +++ b/data/json/mapgen/sub_station.json @@ -106,7 +106,8 @@ ], "palettes": [ "subway_underground" ], "vendingmachines": { "J": { "item_group": "vending_drink" }, "C": { "item_group": "vending_food" } }, - "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 6, 20 ], "y": [ 4, 9 ], "repeat": [ 5, 9 ] } ] + "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 6, 20 ], "y": [ 4, 9 ], "repeat": [ 5, 9 ] } ], + "place_item": [ { "item": "subwaymap", "x": 1, "y": [ 6, 7 ], "chance": 75 } ] } }, { From 5d7153d4569200166900129fd13275a98ee4121d Mon Sep 17 00:00:00 2001 From: Karthas077 Date: Fri, 6 Mar 2020 02:41:15 -0800 Subject: [PATCH 139/219] Add The Satanic Bible (#37806) --- data/json/itemgroups/books.json | 3 +- data/json/items/book/misc.json | 39 ++++++++++++++++------- data/json/npcs/items_generic.json | 1 + data/mods/No_Religious_Books/modinfo.json | 3 +- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/data/json/itemgroups/books.json b/data/json/itemgroups/books.json index 96d1053bb9305..c859cea94334b 100644 --- a/data/json/itemgroups/books.json +++ b/data/json/itemgroups/books.json @@ -157,7 +157,8 @@ [ "holybook_pastafarian", 1 ], [ "holybook_slack", 1 ], [ "holybook_kallisti", 1 ], - [ "holybook_scientology", 1 ] + [ "holybook_scientology", 1 ], + [ "holybook_satanic", 1 ] ] }, { diff --git a/data/json/items/book/misc.json b/data/json/items/book/misc.json index 761eea45f34c1..1e577c457badb 100644 --- a/data/json/items/book/misc.json +++ b/data/json/items/book/misc.json @@ -323,7 +323,7 @@ "name": { "str": "Hadith", "str_pl": "copies of Hadith" }, "description": "A Muslim religious text containing an account of the sayings and actions of the prophet Muhammad.", "weight": "398 g", - "volume": "1 L", + "volume": "500 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -340,7 +340,7 @@ "name": { "str": "Principia Discordia", "str_pl": "copies of Principia Discordia" }, "description": "A book that embodies the main beliefs of Discordianism. It seems to primarily concern chaos, and features a card in the back which informs you that you are now a 'genuine and authorized Pope of Discordia'.", "weight": "292 g", - "volume": "1 L", + "volume": "150 ml", "price": 550, "price_postapoc": 2323, "material": [ "paper" ], @@ -357,7 +357,7 @@ "name": { "str": "The Kojiki", "str_pl": "copies of The Kojiki" }, "description": "The oldest extant chronicle of Japan's myths and history, the stories contained in the Kojiki are part of the inspiration behind Shinto practices.", "weight": "368 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -374,7 +374,7 @@ "name": { "str": "The Book of Mormon", "str_pl": "copies of The Book of Mormon" }, "description": "The sacred text of the Latter Day Saint movement of Christianity, originally published in 1830 by Joseph Smith.", "weight": "368 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -394,7 +394,7 @@ }, "description": "A book that embodies the main beliefs of the Church of the Flying Spaghetti Monster. It seems to involve a lot of pirates and some sort of invisible drunken monster made of pasta.", "weight": "292 g", - "volume": "1 L", + "volume": "500 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -411,7 +411,7 @@ "name": { "str": "Quran", "str_pl": "copies of Quran" }, "description": "An English translation of the Muslim book of holy scriptures, with explanatory notes and commentaries to aid in understanding.", "weight": "412 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -428,7 +428,7 @@ "name": { "str": "Dianetics", "str_pl": "copies of Dianetics" }, "description": "This book is the canonical text of Scientology. Written by a science fiction author, it contains self-improvement techniques and musings on psychology called Dianetics.", "weight": "486 g", - "volume": "1 L", + "volume": "1300 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -445,7 +445,7 @@ "name": { "str": "The Book of the SubGenius", "str_pl": "copies of The Book of the SubGenius" }, "description": "A book about the Church of the SubGenius. It seems to involve a salesman named J. R. \"Bob\" Dobbs and a concept called 'slack'.", "weight": "292 g", - "volume": "1 L", + "volume": "600 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -496,7 +496,7 @@ "name": { "str": "Tanakh", "str_pl": "copies of Tanakh" }, "description": "A single-volume book containing the complete canon of the Jewish Bible.", "weight": "512 g", - "volume": "1 L", + "volume": "1800 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -530,7 +530,7 @@ "name": { "str": "The Upanishads", "str_pl": "copies of The Upanishads" }, "description": "A collection of sacred Hindu writings regarding the nature of reality and describing the character and form of human salvation.", "weight": "482 g", - "volume": "1 L", + "volume": "750 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], @@ -547,7 +547,24 @@ "name": { "str": "The Four Vedas", "str_pl": "copies of The Four Vedas" }, "description": "A single volume containing all four Vedas, which are the oldest scriptures of Hinduism.", "weight": "540 g", - "volume": "1 L", + "volume": "1700 ml", + "price": 550, + "price_postapoc": 550, + "material": [ "paper" ], + "symbol": "?", + "color": "dark_gray", + "intelligence": 8, + "time": "10 m", + "fun": 1, + "flags": [ "INSPIRATIONAL" ] + }, + { + "id": "holybook_satanic", + "type": "BOOK", + "name": { "str": "The Satanic Bible", "str_pl": "copies of The Satanic Bible" }, + "description": "A collection of essays, observations, and rituals published by Anton LaVey in 1969.", + "weight": "130 g", + "volume": "250 ml", "price": 550, "price_postapoc": 550, "material": [ "paper" ], diff --git a/data/json/npcs/items_generic.json b/data/json/npcs/items_generic.json index 1292d75184641..609959db1da90 100644 --- a/data/json/npcs/items_generic.json +++ b/data/json/npcs/items_generic.json @@ -611,6 +611,7 @@ [ "holybook_mormon", 1 ], [ "holybook_pastafarian", 1 ], [ "holybook_quran", 2 ], + [ "holybook_satanic", 1 ], [ "holybook_scientology", 1 ], [ "holybook_slack", 1 ], [ "holybook_sutras", 2 ], diff --git a/data/mods/No_Religious_Books/modinfo.json b/data/mods/No_Religious_Books/modinfo.json index 0b15b033e6a8b..11d936d70b156 100644 --- a/data/mods/No_Religious_Books/modinfo.json +++ b/data/mods/No_Religious_Books/modinfo.json @@ -31,7 +31,8 @@ "holybook_pastafarian", "holybook_slack", "holybook_kallisti", - "holybook_scientology" + "holybook_scientology", + "holybook_satanic" ] } ] From 2d0f1f46e0a20b33057858535109783c028889e6 Mon Sep 17 00:00:00 2001 From: Ashes <58862150+ashGlaw@users.noreply.github.com> Date: Tue, 10 Mar 2020 05:06:18 -0400 Subject: [PATCH 140/219] Indian cookbook (#37930) --- .../Locations_MapExtras/mansion.json | 1 + data/json/itemgroups/books.json | 4 ++++ .../json/itemgroups/collections_domestic.json | 1 + data/json/items/book/cooking.json | 21 +++++++++++++++++++ data/json/recipes/food/dairy_products.json | 2 +- data/json/recipes/recipe_food.json | 5 +++-- 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/data/json/itemgroups/Locations_MapExtras/mansion.json b/data/json/itemgroups/Locations_MapExtras/mansion.json index 261ae73a4ebc8..7a23ef26d3d0f 100644 --- a/data/json/itemgroups/Locations_MapExtras/mansion.json +++ b/data/json/itemgroups/Locations_MapExtras/mansion.json @@ -808,6 +808,7 @@ [ "tongs", 25 ], [ "coffeemaker", 10 ], [ "cookbook_daintydishes", 40 ], + [ "cookbook_indian", 10 ], [ "cookbook_foodfashions", 18 ] ] }, diff --git a/data/json/itemgroups/books.json b/data/json/itemgroups/books.json index c859cea94334b..d0fbddd6b6c85 100644 --- a/data/json/itemgroups/books.json +++ b/data/json/itemgroups/books.json @@ -264,6 +264,7 @@ [ "cookbook_liverforkids", 15 ], [ "cookbook_eatyrway", 15 ], [ "cookbook_foodfashions", 10 ], + [ "cookbook_indian", 10 ], [ "survnote", 1 ], [ "scots_cookbook", 8 ], [ "offalcooking", 2 ], @@ -314,6 +315,7 @@ [ "cookbook", 35 ], [ "offalcooking", 8 ], [ "cookbook_italian", 25 ], + [ "cookbook_indian", 10 ], [ "manual_electronics", 20 ], [ "manual_tailor", 15 ], [ "manual_carpentry", 10 ], @@ -359,6 +361,7 @@ [ "tailor_portfolio", 3 ], [ "textbook_chemistry", 11 ], [ "brewing_cookbook", 3 ], + [ "cookbook_indian", 5 ], [ "textbook_carpentry", 6 ], [ "SICP", 3 ], [ "survival_book", 8 ], @@ -458,6 +461,7 @@ [ "cookbook_human", 10 ], [ "collector_book", 10 ], [ "brewing_cookbook", 24 ], + [ "cookbook_indian", 10 ], [ "textbook_robots", 15 ], [ "manual_dodge", 15 ], [ "novel_experimental", 24 ], diff --git a/data/json/itemgroups/collections_domestic.json b/data/json/itemgroups/collections_domestic.json index 484b55de0c7a9..0b77905af551e 100644 --- a/data/json/itemgroups/collections_domestic.json +++ b/data/json/itemgroups/collections_domestic.json @@ -489,6 +489,7 @@ [ "funnel", 50 ], [ "vac_sealer", 10 ], [ "cookbook_italian", 10 ], + [ "cookbook_indian", 10 ], [ "cookbook_liverforkids", 10 ], [ "cookbook_foodfashions", 7 ], [ "cookbook_daintydishes", 10 ], diff --git a/data/json/items/book/cooking.json b/data/json/items/book/cooking.json index 7bd37a7b11305..fe972761f991c 100644 --- a/data/json/items/book/cooking.json +++ b/data/json/items/book/cooking.json @@ -524,5 +524,26 @@ "max_level": 4, "intelligence": 7, "copy-from": "cookbook_liverforkids" + }, + { + "id": "cookbook_indian", + "type": "BOOK", + "name": { "str": "Tasting India", "str_pl": "copies of Tasting India" }, + "//": "Statistics derived from a real book.", + "description": "A thick hardcover book as much about Indian culture as it is a cookbook, clearly written with adoration.", + "weight": "2950 g", + "volume": "3215 ml", + "price": 6000, + "price_postapoc": 10000, + "bashing": 7, + "material": [ "paper" ], + "symbol": "?", + "color": "yellow", + "skill": "cooking", + "required_level": 1, + "max_level": 3, + "intelligence": 7, + "time": "20 m", + "fun": 1 } ] diff --git a/data/json/recipes/food/dairy_products.json b/data/json/recipes/food/dairy_products.json index beaab800ef9a0..a4b11a732ff1e 100644 --- a/data/json/recipes/food/dairy_products.json +++ b/data/json/recipes/food/dairy_products.json @@ -46,7 +46,7 @@ "skill_used": "cooking", "difficulty": 2, "charges": 1, - "book_learn": [ [ "cookbook", 1 ] ], + "book_learn": [ [ "cookbook_indian", 1 ] ], "time": "30 m", "batch_time_factors": [ 80, 4 ], "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "COOK", "level": 2 } ], diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index d2e856113a851..02ef36ba64663 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -2119,6 +2119,7 @@ "charges": 2, "batch_time_factors": [ 50, 4 ], "autolearn": true, + "book_learn": [ [ "cookbook_indian", 1 ], [ "cookbook", 1 ] ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ [ [ "flour", 11 ] ], [ [ "water", 2 ], [ "water_clean", 2 ] ] ] @@ -3411,7 +3412,7 @@ "skill_used": "cooking", "difficulty": 2, "time": "20 m", - "autolearn": true, + "book_learn": [ [ "cookbook_indian", 1 ] ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ @@ -3446,7 +3447,7 @@ "skill_used": "cooking", "difficulty": 2, "time": "20 m", - "autolearn": true, + "book_learn": [ [ "cookbook_indian", 1 ] ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ From c8b27da248412ec5a699bffdfd97190e426018ac Mon Sep 17 00:00:00 2001 From: RarkGrames <50421549+RarkGrames@users.noreply.github.com> Date: Tue, 10 Mar 2020 10:11:25 +0100 Subject: [PATCH 141/219] AR pistols (#37768) --- .../itemgroups/Weapons_Mods_Ammo/guns.json | 3 ++ data/json/items/gun/223.json | 46 +++++++++++++++++++ .../firearms/gg_firearms_migration.json | 2 + 3 files changed, 51 insertions(+) diff --git a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json index 3424eaec673a8..d3c512ed4cdb9 100644 --- a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json +++ b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json @@ -167,6 +167,7 @@ "//": "Rifles commonly owned by citizens and found in many locations.", "items": [ { "item": "browning_blr", "prob": 25, "charges-min": 0, "charges-max": 4 }, + { "item": "ar_pistol", "prob": 52, "charges-min": 0, "charges-max": 30 }, { "item": "garand", "prob": 65, "charges-min": 0, "charges-max": 8 }, { "item": "ar10", "prob": 20, "charges-min": 0, "charges-max": 20 }, { "item": "ar15", "prob": 30, "charges-min": 0, "charges-max": 30 }, @@ -261,6 +262,7 @@ { "item": "bfg50", "prob": 5, "charges-min": 0, "charges-max": 1 }, { "item": "carbine_flintlock", "prob": 140 }, { "item": "rifle_flintlock", "prob": 180 }, + { "item": "oa93", "prob": 3, "charges-min": 0, "charges-max": 30 }, { "item": "steyr_aug", "prob": 40, "charges-min": 0, "charges-max": 30 }, { "item": "trex_gun", "prob": 60 }, { "item": "arx160", "prob": 40, "charges-min": 0, "charges-max": 30 }, @@ -548,6 +550,7 @@ "items": [ { "group": "guns_improvised", "prob": 200 }, { "item": "ar15", "prob": 5, "charges-min": 0, "charges-max": 30 }, + { "item": "ar_pistol", "prob": 3, "charges-min": 0, "charges-max": 30 }, { "item": "mossberg_500", "prob": 5, "charges-min": 0, "charges-max": 8 }, { "item": "remington_870", "prob": 5, "charges-min": 0, "charges-max": 6 }, { "item": "ruger_1022", "prob": 15, "charges-min": 0, "charges-max": 10 }, diff --git a/data/json/items/gun/223.json b/data/json/items/gun/223.json index 552d0d271edfb..958cb9bf4d437 100644 --- a/data/json/items/gun/223.json +++ b/data/json/items/gun/223.json @@ -45,6 +45,29 @@ "min_cycle_recoil": 1350, "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] }, + { + "id": "ar_pistol", + "copy-from": "rifle_semi", + "looks_like": "skorpion_61", + "type": "GUN", + "name": { "str": "AR pistol" }, + "description": "A compact, 7.5 inch barrel version of the classic AR-15 design, commercially marketed as a home defense weapon.", + "weight": "2267 g", + "volume": "1758 ml", + "price": 91400, + "to_hit": -2, + "bashing": 9, + "material": [ "steel", "aluminum" ], + "symbol": "(", + "color": "dark_gray", + "ammo": "223", + "range": -6, + "ranged_damage": -9, + "dispersion": 380, + "durability": 6, + "min_cycle_recoil": 1350, + "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] + }, { "id": "h&k416a5", "copy-from": "rifle_auto", @@ -184,6 +207,29 @@ "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ] ], "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] }, + { + "id": "oa93", + "copy-from": "rifle_semi", + "looks_like": "skorpion_61", + "type": "GUN", + "name": { "str": "OA-93" }, + "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", + "price": 125000, + "to_hit": -2, + "bashing": 9, + "material": [ "steel", "aluminum" ], + "symbol": "(", + "color": "dark_gray", + "ammo": "223", + "range": -6, + "ranged_damage": -11, + "dispersion": 380, + "durability": 6, + "min_cycle_recoil": 1350, + "magazines": [ [ "223", [ "stanag30", "stanag50", "survivor223mag" ] ] ] + }, { "id": "rifle_223", "copy-from": "gun_base", diff --git a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json index 9e670dda9d701..70081298fc4e6 100644 --- a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json +++ b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json @@ -247,6 +247,8 @@ "arx160", "mosin91_30", "ar15", + "oa93", + "ar_pistol", "ruger_mini", "sig552", "steyr_aug", From ceaee875b00734d3f1c78fd498b68c3793ee5679 Mon Sep 17 00:00:00 2001 From: xanderrootslayer <46512498+xanderrootslayer@users.noreply.github.com> Date: Tue, 10 Mar 2020 05:14:07 -0400 Subject: [PATCH 142/219] SUS bathroom 3.5 (#37431) --- data/json/itemgroups/SUS/domestic.json | 60 ++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/data/json/itemgroups/SUS/domestic.json b/data/json/itemgroups/SUS/domestic.json index 626fc737a1cc7..6bd7b9ac804b2 100644 --- a/data/json/itemgroups/SUS/domestic.json +++ b/data/json/itemgroups/SUS/domestic.json @@ -606,14 +606,47 @@ "//2": "This group is for a bathroom sink.", "subtype": "collection", "entries": [ + { "item": "soap", "count": [ 1, 4 ], "prob": 75 }, { "item": "soap_holder", "prob": 40 }, - { "item": "soap", "count": [ 1, 4 ], "prob": 90 }, { "item": "razor_shaving", "count": [ 1, 2 ], "prob": 20 }, + { "item": "cotton_ball", "prob": 50 }, { "item": "bleach", "prob": 15 }, { "item": "ammonia", "prob": 20 }, + { "item": "string_floss", "count": [ 1, 2 ], "prob": 60 }, { "item": "toothbrush_plain", "count": [ 1, 3 ], "prob": 45 } ] }, + { + "id": "SUS_bathroom_medicine", + "type": "item_group", + "//": "SUS item groups are collections that contain a reasonable realistic distribution of items that might spawn in a given storage furniture.", + "//2": "This group is for the medicine cabinet.", + "subtype": "collection", + "entries": [ + { + "distribution": [ { "item": "aspirin", "prob": 160 }, { "item": "codeine", "prob": 30 }, { "item": "tramadol", "prob": 10 } ], + "prob": 95 + }, + { "item": "eyedrops", "prob": 15 }, + { "item": "pepto", "prob": 70 }, + { "item": "inhaler", "prob": 25 }, + { "item": "pills_sleep", "prob": 10 }, + { "distribution": [ { "item": "nyquil", "prob": 60 }, { "item": "dayquil", "prob": 20 } ], "prob": 50 }, + { + "distribution": [ + { "item": "vitamins", "prob": 60 }, + { "item": "gummy_vitamins", "prob": 20 }, + { "item": "calcium_tablet", "prob": 10 } + ], + "prob": 80 + }, + { + "distribution": [ { "item": "weak_antibiotic", "prob": 40 }, { "item": "antibiotics", "prob": 10 } ], + "prob": 10 + }, + { "distribution": [ { "item": "antifungal", "prob": 60 }, { "item": "antiparasitic", "prob": 20 } ], "prob": 5 } + ] + }, { "id": "SUS_hair_drawer", "type": "item_group", @@ -623,9 +656,10 @@ "entries": [ { "item": "hairbrush", "count": [ 1, 2 ], "prob": 90 }, { "item": "comb_pocket", "count": [ 1, 2 ], "prob": 75 }, - { "item": "curler_hair", "prob": 25 }, + { "item": "scissors", "count": [ 1, 2 ], "prob": 60 }, { "item": "hair_dryer", "prob": 60 }, - { "item": "curling_iron", "prob": 20 } + { "collection": [ { "item": "curling_iron", "count": [ 1, 2 ] }, { "item": "curler_hair" } ], "prob": 25 }, + { "item": "elec_hairtrimmer", "prob": 30 } ] }, { @@ -635,16 +669,20 @@ "//2": "This group is for things you often find stored on or next to a toilet.", "subtype": "collection", "entries": [ - { "distribution": [ { "item": "plunger_toilet", "prob": 90 }, { "item": "plunger_futuristic", "prob": 10 } ] }, + { + "distribution": [ { "item": "plunger_toilet", "prob": 90 }, { "item": "plunger_futuristic", "prob": 10 } ], + "prob": 90 + }, { "item": "brush_toilet", "prob": 75 }, - { "item": "toilet_paper", "prob": 80 } + { "item": "toilet_paper", "prob": 95, "container-item": "wrapper" }, + { "item": "bathroom_scale", "prob": 50 } ] }, { "id": "SUS_bathroom_cabinet", "type": "item_group", "//": "SUS item groups are collections that contain a reasonable realistic distribution of items that might spawn in a given storage furniture.", - "//2": "This group is for a bathroom cabinet.", + "//2": "This group is for a bathroom cabinet under the sink.", "subtype": "collection", "entries": [ { "item": "soap", "count": [ 1, 4 ], "prob": 70 }, @@ -652,11 +690,17 @@ "distribution": [ { "item": "razor_shaving", "count": [ 1, 2 ], "prob": 50 }, { "item": "shavingkit", "prob": 50 } ], "prob": 75 }, + { + "distribution": [ { "item": "bandages", "prob": 60 }, { "item": "medical_gauze", "prob": 20 }, { "item": "1st_aid", "prob": 10 } ], + "prob": 20 + }, + { "item": "disinfectant", "prob": 40 }, + { "item": "chem_hydrogen_peroxide", "prob": 50 }, { "item": "mirror", "prob": 25 }, - { "item": "string_floss", "count": [ 1, 2 ], "prob": 60 }, { "item": "sponge", "count": [ 1, 3 ], "prob": 75 }, { "collection": [ { "item": "candle", "count": [ 1, 2 ] }, { "item": "matches" } ], "prob": 20 }, - { "item": "toilet_paper", "prob": 80 } + { "item": "toilet_paper", "prob": 80 }, + { "item": "towel", "count": [ 1, 2 ], "prob": 75 } ] }, { From 02ceceb3ede47d1e39905bfb6d6ea7a3f30f23a9 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Tue, 10 Mar 2020 21:59:22 +0100 Subject: [PATCH 143/219] Add map_bash_info to fields (#37865) --- data/json/field_type.json | 8 ++++++ .../My_Sweet_Cataclysm/sweet_field_type.json | 9 ++++++ doc/JSON_INFO.md | 17 +++++++++++ src/field_type.cpp | 1 + src/field_type.h | 2 ++ src/handle_action.cpp | 28 +++++++++++++++---- src/mapdata.cpp | 27 +++++++++++------- src/mapdata.h | 9 +++++- 8 files changed, 84 insertions(+), 17 deletions(-) diff --git a/data/json/field_type.json b/data/json/field_type.json index 62edc326ade03..a9c4e1daf7618 100644 --- a/data/json/field_type.json +++ b/data/json/field_type.json @@ -82,6 +82,14 @@ "priority": 2, "phase": "solid", "display_items": false, + "bash": { + "str_min": 1, + "str_max": 3, + "sound_vol": 2, + "sound_fail_vol": 2, + "sound": "hsh!", + "msg_success": "You brush aside some webs." + }, "display_field": true }, { diff --git a/data/mods/My_Sweet_Cataclysm/sweet_field_type.json b/data/mods/My_Sweet_Cataclysm/sweet_field_type.json index 6c3cd61622f07..77c43ffcd5850 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_field_type.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_field_type.json @@ -58,6 +58,15 @@ "priority": 2, "phase": "solid", "half_life": "2 h", + "bash": { + "str_min": 1, + "str_max": 3, + "sound_vol": 2, + "sound_fail_vol": 2, + "sound": "shwip", + "sound_fail": "shwomp", + "msg_success": "You brush the gum web aside." + }, "display_items": false, "display_field": true }, diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 9546097953799..8bc14ec1d07e2 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -3018,4 +3018,21 @@ Setting of sprite sheets. Same as `tiles-new` field in `tile_config`. Sprite fil "type": "field_type", // this is a field type "id": "fd_gum_web", // id of the field "immune_mtypes": [ "mon_spider_gum" ], // list of monster immune to this field + "bash": { + "str_min": 1, // lower bracket of bashing damage required to bash + "str_max": 3, // higher bracket + "sound_vol": 2, // noise made when succesfully bashing the field + "sound_fail_vol": 2, // noise made when failing to bash the field + "sound": "shwip", // sound on success + "sound_fail": "shwomp", // sound on failure + "msg_success": "You brush the gum web aside.", // message on success + "move_cost": 120, // how many moves it costs to succesfully bash that field (default: 100) + "items": [ // item dropped upon succesful bashing + { "item": "2x4", "count": [ 5, 8 ] }, + { "item": "nail", "charges": [ 6, 8 ] }, + { "item": "splinter", "count": [ 3, 6 ] }, + { "item": "rag", "count": [ 40, 55 ] }, + { "item": "scrap", "count": [ 10, 20 ] } + ] + } } diff --git a/src/field_type.cpp b/src/field_type.cpp index f35fdc83a6512..891f435c113c0 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -244,6 +244,7 @@ void field_type::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "display_field", display_field, false ); optional( jo, was_loaded, "wandering_field", wandering_field_id, "fd_null" ); + bash_info.load( jo, "bash", map_bash_info::field ); if( was_loaded && jo.has_member( "copy-from" ) && looks_like.empty() ) { looks_like = jo.get_string( "copy-from" ); } diff --git a/src/field_type.h b/src/field_type.h index 7302b51f09b8b..d2af7b846ea48 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -15,6 +15,7 @@ #include "color.h" #include "effect.h" #include "enums.h" +#include "mapdata.h" #include "type_id.h" #include "string_id.h" #include "translations.h" @@ -143,6 +144,7 @@ struct field_type { bool has_elec = false; bool has_fume = false; description_affix desc_affix = description_affix::DESCRIPTION_AFFIX_NUM; + map_bash_info bash_info; // chance, issue, duration, speech std::tuple npc_complain_data; diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 9b90e13580406..0d4e45baf9b02 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -674,12 +674,28 @@ static void smash() crit->use_mech_power( -3 ); } } - if( m.get_field( smashp, fd_web ) != nullptr ) { - m.remove_field( smashp, fd_web ); - sounds::sound( smashp, 2, sounds::sound_t::combat, _( "hsh!" ), true, "smash", "web" ); - add_msg( m_info, _( "You brush aside some webs." ) ); - u.moves -= 100; - return; + for( std::pair &fd_to_smsh : m.field_at( smashp ) ) { + const map_bash_info &bash_info = fd_to_smsh.first->bash_info; + if( bash_info.str_min == -1 ) { + continue; + } + if( smashskill < bash_info.str_min && one_in( 10 ) ) { + add_msg( m_neutral, _( "You don't seem to be damaging the %s." ), fd_to_smsh.first->get_name() ); + return; + } else if( smashskill >= rng( bash_info.str_min, bash_info.str_max ) ) { + sounds::sound( smashp, bash_info.sound_vol, sounds::sound_t::combat, bash_info.sound, true, "smash", + "field" ); + m.remove_field( smashp, fd_to_smsh.first ); + m.spawn_items( smashp, item_group::items_from( bash_info.drop_group, calendar::turn ) ); + u.mod_moves( - bash_info.fd_bash_move_cost ); + add_msg( m_info, bash_info.field_bash_msg_success.translated() ); + return; + } else { + sounds::sound( smashp, bash_info.sound_fail_vol, sounds::sound_t::combat, bash_info.sound_fail, + true, "smash", + "field" ); + return; + } } for( const auto &maybe_corpse : m.i_at( smashp ) ) { diff --git a/src/mapdata.cpp b/src/mapdata.cpp index f0f0101330290..cbc472d9b1847 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -198,7 +198,8 @@ map_bash_info::map_bash_info() : str_min( -1 ), str_max( -1 ), drop_group( "EMPTY_GROUP" ), ter_set( ter_str_id::NULL_ID() ), furn_set( furn_str_id::NULL_ID() ) {} -bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, bool is_furniture ) +bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, + map_object_type obj_type ) { if( !jsobj.has_object( member ) ) { return false; @@ -230,13 +231,19 @@ bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, bo j.read( "sound", sound ); j.read( "sound_fail", sound_fail ); - if( is_furniture ) { - furn_set = furn_str_id( j.get_string( "furn_set", "f_null" ) ); - } else { - const std::string ter_set_string = j.get_string( "ter_set" ); - ter_set = ter_str_id( ter_set_string ); - ter_set_bashed_from_above = ter_str_id( j.get_string( "ter_set_bashed_from_above", - ter_set_string ) ); + switch( obj_type ) { + case map_bash_info::furniture: + furn_set = furn_str_id( j.get_string( "furn_set", "f_null" ) ); + break; + case map_bash_info::terrain: + ter_set = ter_str_id( j.get_string( "ter_set" ) ); + ter_set_bashed_from_above = ter_str_id( j.get_string( "ter_set_bashed_from_above", + ter_set.c_str() ) ); + break; + case map_bash_info::field: + fd_bash_move_cost = j.get_int( "move_cost", 100 ); + j.read( "msg_success", field_bash_msg_success ); + break; } if( j.has_member( "items" ) ) { @@ -1166,7 +1173,7 @@ void ter_t::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "transforms_into", transforms_into, ter_str_id::NULL_ID() ); optional( jo, was_loaded, "roof", roof, ter_str_id::NULL_ID() ); - bash.load( jo, "bash", false ); + bash.load( jo, "bash", map_bash_info::terrain ); deconstruct.load( jo, "deconstruct", false ); } @@ -1269,7 +1276,7 @@ void furn_t::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "open", open, string_id_reader {}, furn_str_id::NULL_ID() ); optional( jo, was_loaded, "close", close, string_id_reader {}, furn_str_id::NULL_ID() ); - bash.load( jo, "bash", true ); + bash.load( jo, "bash", map_bash_info::furniture ); deconstruct.load( jo, "deconstruct", true ); if( jo.has_object( "workbench" ) ) { diff --git a/src/mapdata.h b/src/mapdata.h index 184d8abc270bf..b709dbe7bac64 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -39,18 +39,25 @@ struct map_bash_info { int sound_vol; // sound volume of breaking terrain/furniture int sound_fail_vol; // sound volume on fail int collapse_radius; // Radius of the tent supported by this tile + int fd_bash_move_cost = 100; // cost to bash a field bool destroy_only; // Only used for destroying, not normally bashable bool bash_below; // This terrain is the roof of the tile below it, try to destroy that too std::string drop_group; // item group of items that are dropped when the object is bashed translation sound; // sound made on success ('You hear a "smash!"') translation sound_fail; // sound made on fail + translation field_bash_msg_success; // message upon successfully bashing a field ter_str_id ter_set; // terrain to set (REQUIRED for terrain)) ter_str_id ter_set_bashed_from_above; // terrain to set if bashed from above (defaults to ter_set) furn_str_id furn_set; // furniture to set (only used by furniture, not terrain) // ids used for the special handling of tents std::vector tent_centers; map_bash_info(); - bool load( const JsonObject &jsobj, const std::string &member, bool is_furniture ); + enum map_object_type { + furniture = 0, + terrain, + field + }; + bool load( const JsonObject &jsobj, const std::string &member, map_object_type obj_type ); }; struct map_deconstruct_info { // Only if true, the terrain/furniture can be deconstructed From cf9cab687c69ae2f93de316b628da7e6451ac771 Mon Sep 17 00:00:00 2001 From: dpwb Date: Tue, 4 Feb 2020 10:11:54 +0000 Subject: [PATCH 144/219] Add shot counter to mods and gun (#37693) --- src/ranged.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ranged.cpp b/src/ranged.cpp index 90d4811d0c906..41a2e732d0781 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -486,7 +486,11 @@ int player::fire_gun( const tripoint &target, int shots, item &gun ) continue; // skip retargeting for launchers } } - + // apply shot counter to gun and its mods. + gun.set_var( "shot_counter", gun.get_var( "shot_counter", 0 ) + curshot ); + for( item *mod : gun.gunmods() ) { + mod->set_var( "shot_counter", mod->get_var( "shot_counter", 0 ) + curshot ); + } // apply delayed recoil recoil += delay; if( is_mech_weapon ) { From 697cf46a0af8b8181f8f4fddae30752a7d21e5e0 Mon Sep 17 00:00:00 2001 From: davidpwbrown <39344466+davidpwbrown@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:34:18 +0000 Subject: [PATCH 145/219] Allow professions to start with a nearby vehicle (#37314) Adds trucker profession. --- data/json/professions.json | 17 +++++++++++++ doc/JSON_INFO.md | 16 +++++++++--- src/game.cpp | 52 ++++++++++++++++++++++++++++++++++++++ src/game.h | 4 ++- src/newcharacter.cpp | 9 ++++++- src/overmapbuffer.cpp | 3 ++- src/player.h | 2 +- src/profession.cpp | 13 +++++++++- src/profession.h | 3 +++ src/string_id_null_ids.cpp | 1 + 10 files changed, 111 insertions(+), 9 deletions(-) diff --git a/data/json/professions.json b/data/json/professions.json index cfa565f1af588..a6a973384eb1b 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -1481,6 +1481,23 @@ "female": [ "bra", "panties" ] } }, + { + "type": "profession", + "ident": "trucker", + "name": "Trucker", + "description": "You ruled the road in your big rig and managed to drive it somewhere you hoped was safe when the riots hit. Now it's just you and your trusty truck cab.", + "points": 5, + "skills": [ { "level": 1, "name": "mechanics" }, { "level": 4, "name": "driving" } ], + "vehicle": "semi_truck", + "items": { + "both": { + "items": [ "tank_top", "socks", "boots_steel", "pants", "multitool", "wristwatch", "gloves_work", "hat_ball" ], + "entries": [ { "group": "charged_cell_phone" } ] + }, + "male": [ "boxer_shorts" ], + "female": [ "bra", "panties" ] + } + }, { "type": "profession", "ident": "lumberjack", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 8bc14ec1d07e2..e89bd1f4dbdb4 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -814,12 +814,20 @@ Example for mods: This mod removes one of the rocks (the other rock is still created), the t-shirt, adds a 2x4 item and gives female characters a t-shirt with the special snippet id. -#### `pet` +#### `pets` -(optional, string mtype_id) +(optional, array of string mtype_ids ) -A string that is the same as a monster id -player will start with this as a tamed pet. +A list of strings, each is the same as a monster id +player will start with these as tamed pets. + +#### `vehicle` + +(optional, string vproto_id ) + +A string, which is the same as a vehicle ( vproto_id ) +player will start with this as a nearby vehicle. +( it will find the nearest road and place it there, then mark it as "remembered" on the overmap ) #### `flags` diff --git a/src/game.cpp b/src/game.cpp index 48e63c554742d..5f47840d25822 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -838,6 +838,11 @@ bool game::start_game() add_msg( m_debug, "cannot place starting pet, no space!" ); } } + if( u.starting_vehicle && + !place_vehicle_nearby( u.starting_vehicle, u.global_omt_location().xy(), 1, 30, + std::vector {} ) ) { + debugmsg( "could not place starting vehicle" ); + } // Assign all of this scenario's missions to the player. for( const mission_type_id &m : scen->missions() ) { const auto mission = mission::reserve_new( m, character_id() ); @@ -848,6 +853,53 @@ bool game::start_game() return true; } +vehicle *game::place_vehicle_nearby( const vproto_id &id, const point &origin, int min_distance, + int max_distance, const std::vector &omt_search_types ) +{ + std::vector search_types = omt_search_types; + if( search_types.empty() ) { + vehicle veh( id ); + std::vector omt_search_types; + if( veh.max_ground_velocity() > 0 ) { + search_types.push_back( "road" ); + search_types.push_back( "field" ); + } else if( veh.can_float() ) { + search_types.push_back( "river" ); + search_types.push_back( "lake" ); + } + } + for( const std::string &search_type : search_types ) { + omt_find_params find_params; + find_params.must_see = false; + find_params.cant_see = false; + find_params.types.emplace_back( search_type, ot_match_type::type ); + // find nearest road + find_params.min_distance = min_distance; + find_params.search_range = max_distance; + // if player spawns underground, park their car on the surface. + const tripoint omt_origin( origin.x, origin.y, 0 ); + for( const tripoint &goal : overmap_buffer.find_all( omt_origin, find_params ) ) { + // try place vehicle there. + tinymap target_map; + target_map.load( omt_to_sm_copy( goal ), false ); + const tripoint origin( SEEX, SEEY, goal.z ); + static const std::vector angles = {0, 90, 180, 270}; + vehicle *veh = target_map.add_vehicle( id, origin, random_entry( angles ), rng( 50, 80 ), + 0, + false ); + if( veh ) { + tripoint abs_local = g->m.getlocal( target_map.getabs( origin ) ); + veh->sm_pos = ms_to_sm_remain( abs_local ); + veh->pos = abs_local.xy(); + overmap_buffer.add_vehicle( veh ); + target_map.save(); + return veh; + } + } + } + return nullptr; +} + //Make any nearby overmap npcs active, and put them in the right location. void game::load_npcs() { diff --git a/src/game.h b/src/game.h index 767ad951ee788..6c3aa728ce561 100644 --- a/src/game.h +++ b/src/game.h @@ -733,7 +733,9 @@ class game // Data Initialization void init_autosave(); // Initializes autosave parameters void create_starting_npcs(); // Creates NPCs that start near you - + // create vehicle nearby, for example; for a profession vehicle. + vehicle *place_vehicle_nearby( const vproto_id &id, const point &origin, int min_distance, + int max_distance, const std::vector &omt_search_types = {} ); // V Menu Functions and helpers: void list_items_monsters(); // Called when you invoke the `V`-menu diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 7504dc5d5b83c..092ef74843c8d 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -52,6 +52,7 @@ #include "pimpl.h" #include "type_id.h" #include "cata_string_consts.h" +#include "veh_type.h" // Colors used in this file: (Most else defaults to c_light_gray) #define COL_STAT_ACT c_white // Selected stat @@ -519,6 +520,7 @@ bool avatar::create( character_type type, const std::string &tempname ) for( mtype_id elem : prof->pets() ) { starting_pets.push_back( elem ); } + starting_vehicle = prof->vehicle(); std::list prof_items = prof->items( male, get_mutations() ); for( item &it : prof_items ) { @@ -1479,7 +1481,6 @@ tab_direction set_profession( const catacurses::window &w, avatar &u, points_lef } } // Profession pet - cata::optional montype; if( !sorted_profs[cur_id]->pets().empty() ) { buffer += colorize( _( "Pets:" ), c_light_blue ) + "\n"; for( auto elem : sorted_profs[cur_id]->pets() ) { @@ -1487,6 +1488,12 @@ tab_direction set_profession( const catacurses::window &w, avatar &u, points_lef buffer += mon.get_name() + "\n"; } } + // Profession vehicle + if( sorted_profs[cur_id]->vehicle() ) { + buffer += colorize( _( "Vehicle:" ), c_light_blue ) + "\n"; + vproto_id veh_id = sorted_profs[cur_id]->vehicle(); + buffer += veh_id->name; + } // Profession spells if( !sorted_profs[cur_id]->spells().empty() ) { buffer += colorize( _( "Spells:" ), c_light_blue ) + "\n"; diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index 2de6c86b85028..516c69e5fc9db 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -600,7 +600,8 @@ void overmapbuffer::remove_vehicle( const vehicle *veh ) void overmapbuffer::add_vehicle( vehicle *veh ) { - const point omt = ms_to_omt_copy( g->m.getabs( veh->global_pos3().xy() ) ); + const point abs_pos = g->m.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; // this *should* be unique but just in case diff --git a/src/player.h b/src/player.h index dcf5910a8ad0f..fedd52b66ff0f 100644 --- a/src/player.h +++ b/src/player.h @@ -938,7 +938,7 @@ class player : public Character bool reach_attacking = false; bool manual_examine = false; - + 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, diff --git a/src/profession.cpp b/src/profession.cpp index 20765f0229e7b..87f4c62ddd64f 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -171,6 +171,9 @@ void profession::load( const JsonObject &jo, const std::string & ) _description_male = to_translation( "prof_desc_male", desc ); _description_female = to_translation( "prof_desc_female", desc ); } + if( jo.has_string( "vehicle" ) ) { + _starting_vehicle = vproto_id( jo.get_string( "vehicle" ) ); + } if( jo.has_array( "pets" ) ) { for( JsonObject subobj : jo.get_array( "pets" ) ) { int count = subobj.get_int( "amount" ); @@ -286,7 +289,10 @@ void profession::check_definition() const if( !item_group::group_is_defined( _starting_items_female ) ) { debugmsg( "_starting_items_female group is undefined" ); } - + if( _starting_vehicle && !_starting_vehicle.is_valid() ) { + debugmsg( "vehicle prototype %s for profession %s does not exist", _starting_vehicle.c_str(), + id.c_str() ); + } for( const auto &a : _starting_CBMs ) { if( !a.is_valid() ) { debugmsg( "bionic %s for profession %s does not exist", a.c_str(), id.c_str() ); @@ -434,6 +440,11 @@ std::list profession::items( bool male, const std::vector &trait return result; } +vproto_id profession::vehicle() const +{ + return _starting_vehicle; +} + std::vector profession::pets() const { return _starting_pets; diff --git a/src/profession.h b/src/profession.h index 1c9427a717d05..61649631d7b31 100644 --- a/src/profession.h +++ b/src/profession.h @@ -13,6 +13,7 @@ #include "pldata.h" #include "translations.h" #include "type_id.h" +#include "veh_type.h" template class generic_factory; @@ -69,6 +70,7 @@ class profession std::vector _starting_CBMs; std::vector _starting_traits; std::vector _starting_pets; + vproto_id _starting_vehicle = vproto_id::NULL_ID(); // the int is what level the spell starts at std::map _starting_spells; std::set flags; // flags for some special properties of the profession @@ -103,6 +105,7 @@ class profession signed int point_cost() const; std::list items( bool male, const std::vector &traits ) const; std::vector addictions() const; + vproto_id vehicle() const; std::vector pets() const; std::vector CBMs() const; StartingSkillList skills() const; diff --git a/src/string_id_null_ids.cpp b/src/string_id_null_ids.cpp index 3c57688a3b1dd..b33c3e44c615e 100644 --- a/src/string_id_null_ids.cpp +++ b/src/string_id_null_ids.cpp @@ -55,3 +55,4 @@ MAKE_NULL_ID2( requirement_data, "null" ) MAKE_NULL_ID2( body_part_struct, "NUM_BP" ) MAKE_NULL_ID2( bionic_data, "" ) MAKE_NULL_ID2( construction, "constr_null", -1 ) +MAKE_NULL_ID2( vehicle_prototype, "null" ) From 5dc8168c1f25b0546fccbe3a69cb4e090cf9b29a Mon Sep 17 00:00:00 2001 From: CountAlex Date: Fri, 6 Mar 2020 13:39:24 +0300 Subject: [PATCH 146/219] Add Crazy Party scenario and Frat Boy/Sorority Girl profession (#37512) --- data/json/professions.json | 14 ++++++++++++++ data/json/scenarios.json | 11 +++++++++++ data/json/start_locations.json | 6 ++++++ 3 files changed, 31 insertions(+) diff --git a/data/json/professions.json b/data/json/professions.json index a6a973384eb1b..5744aed4af56b 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -4023,5 +4023,19 @@ ] } } + }, + { + "type": "profession", + "ident": "frat", + "name": { "male": "Frat Boy", "female": "Sorority Girl" }, + "description": "You were living the high life, spending your parents money without a care in the world. You were at one of your usual crazy parties when the guests became hungry for more than your drugs. You still have a chance to use the last symbol of your luxurious life - your sport car - and get far away.", + "points": 2, + "skills": [ { "level": 1, "name": "speech" }, { "level": 2, "name": "driving" } ], + "vehicle": "car_sports", + "items": { + "both": { "items": [ "gold_watch", "water_mineral", "smart_phone", "money_bundle", "cig", "ref_lighter" ] }, + "male": [ "boxer_shorts", "pants", "dress_shoes", "polo_shirt", "socks" ], + "female": [ "tank_top", "bra", "panties", "skirt", "heels", "jacket_leather", "stockings" ] + } } ] diff --git a/data/json/scenarios.json b/data/json/scenarios.json index 1e032ba98a591..07d6c5bb45a83 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -527,5 +527,16 @@ "allowed_locs": [ "mil_base_2g" ], "professions": [ "unemployed", "soldier", "specops", "bio_soldier", "bio_sniper", "labtech", "medic" ], "flags": [ "CHALLENGE", "LONE_START" ] + }, + { + "type": "scenario", + "ident": "presort", + "name": "Crazy party", + "points": 0, + "description": "You thought things couldn't get any worse when the cops came over to bust your wild party, even though you booked it at a private resort. When the guests started fighting with the police you tried to get them to calm down, only to find out they hungered for more.", + "start_name": "Private resort", + "allowed_locs": [ "p_resort_2ss" ], + "professions": [ "frat", "gangster", "lost_sub", "lawyer", "politician", "dancer", "bio_gangster" ], + "flags": [ "CHALLENGE", "LONE_START" ] } ] diff --git a/data/json/start_locations.json b/data/json/start_locations.json index 1ba9161c863b4..f5ab7a21d8526 100644 --- a/data/json/start_locations.json +++ b/data/json/start_locations.json @@ -427,5 +427,11 @@ "ident": "mil_base_2g", "name": "Military Base Warehouse", "target": "mil_base_2g" + }, + { + "type": "start_location", + "ident": "p_resort_2ss", + "name": "Private resort", + "target": "p_resort_2ss" } ] From e90ba0cf49179a0b4130861757bb0aa25a5fb60d Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 02:24:32 +0800 Subject: [PATCH 147/219] Window manager (#37894) For properly refreshing and resizing multiple layers of windows --- src/ncurses_def.cpp | 2 + src/sdltiles.cpp | 107 ++++++++++++++++++++++++------------- src/sdltiles.h | 15 ++++++ src/ui_manager.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++ src/ui_manager.h | 54 +++++++++++++++++++ src/wincurse.cpp | 5 ++ 6 files changed, 272 insertions(+), 37 deletions(-) create mode 100644 src/ui_manager.cpp create mode 100644 src/ui_manager.h diff --git a/src/ncurses_def.cpp b/src/ncurses_def.cpp index 8550acb7b7ffd..ca8a4bee7857b 100644 --- a/src/ncurses_def.cpp +++ b/src/ncurses_def.cpp @@ -19,6 +19,7 @@ #include "catacharset.h" #include "color.h" #include "game_ui.h" +#include "ui_manager.h" extern int VIEW_OFFSET_X; // X position of terrain window extern int VIEW_OFFSET_Y; // Y position of terrain window @@ -204,6 +205,7 @@ void catacurses::resizeterm() const int new_y = ::getmaxy( stdscr.get<::WINDOW>() ); if( ::is_term_resized( new_x, new_y ) ) { game_ui::init_ui(); + ui_manager::screen_resized(); } } diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index 53c7ae7aadddc..7b9063aa56e6b 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -57,6 +57,7 @@ #include "json.h" #include "optional.h" #include "point.h" +#include "ui_manager.h" #if defined(__linux__) # include // getenv()/setenv() @@ -1762,7 +1763,7 @@ bool handle_resize( int w, int h ) TERMINAL_HEIGHT = WindowHeight / fontheight / scaling_factor; SetupRenderTarget(); game_ui::init_ui(); - + ui_manager::screen_resized(); return true; } return false; @@ -2824,6 +2825,9 @@ static void CheckMessages() #endif last_input = input_event(); + + bool need_redraw = false; + while( SDL_PollEvent( &ev ) ) { switch( ev.type ) { case SDL_WINDOWEVENT: @@ -2854,17 +2858,14 @@ static void CheckMessages() break; #endif case SDL_WINDOWEVENT_SHOWN: - case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_MINIMIZED: - break; case SDL_WINDOWEVENT_FOCUS_GAINED: - // Main menu redraw - reinitialize_framebuffer(); - // TODO: redraw all game menus if they are open + break; + case SDL_WINDOWEVENT_EXPOSED: + need_redraw = true; needupdate = true; break; case SDL_WINDOWEVENT_RESTORED: - needupdate = true; #if defined(__ANDROID__) needs_sdl_surface_visibility_refresh = true; if( android_is_hardware_keyboard_available() ) { @@ -2880,6 +2881,10 @@ static void CheckMessages() break; } break; + case SDL_RENDER_TARGETS_RESET: + need_redraw = true; + needupdate = true; + break; case SDL_KEYDOWN: { #if defined(__ANDROID__) // Toggle virtual keyboard with Android back button. For some reason I get double inputs, so ignore everything once it's already down. @@ -3204,6 +3209,19 @@ static void CheckMessages() break; } } + if( need_redraw ) { + // FIXME: SDL_RENDER_TARGETS_RESET only seems to be fired after the first redraw + // when restoring the window after system sleep, rather than immediately + // on focus gain. This seems to mess up the first redraw and + // causes black screen that lasts ~0.5 seconds before the screen + // contents are redrawn in the following code. + + // Main menu redraw + reinitialize_framebuffer(); + window_dimensions dim = get_window_dimensions( catacurses::stdscr ); + ui_manager::invalidate( rectangle( point_zero, dim.window_size_pixel ) ); + ui_manager::redraw(); + } if( needupdate ) { try_sdl_update(); } @@ -3690,45 +3708,60 @@ void rescale_tileset( int size ) game_ui::init_ui(); } -cata::optional input_context::get_coordinates( const catacurses::window &capture_win_ ) +window_dimensions get_window_dimensions( const catacurses::window &win ) { - if( !coordinate_input_received ) { - return cata::nullopt; - } + cata_cursesport::WINDOW *const pwin = win.get(); - cata_cursesport::WINDOW *const capture_win = ( capture_win_.get() ? capture_win_ : - g->w_terrain ).get(); - - // this contains the font dimensions of the capture_win, - // not necessarily the global standard font dimensions. - int fw = fontwidth; - int fh = fontheight; - // tiles might have different dimensions than standard font - if( use_tiles && capture_win == g->w_terrain ) { - fw = tilecontext->get_tile_width(); - fh = tilecontext->get_tile_height(); - // add_msg( m_info, "tile map fw %d fh %d", fw, fh); - } else if( map_font && capture_win == g->w_terrain ) { + window_dimensions dim; + if( use_tiles && win == g->w_terrain ) { + // tiles might have different dimensions than standard font + dim.scaled_font_size.x = tilecontext->get_tile_width(); + dim.scaled_font_size.y = tilecontext->get_tile_height(); + } else if( map_font && win == g->w_terrain ) { // map font (if any) might differ from standard font - fw = map_font->fontwidth; - fh = map_font->fontheight; - } else if( overmap_font && capture_win == g->w_overmap ) { - fw = overmap_font->fontwidth; - fh = overmap_font->fontheight; + dim.scaled_font_size.x = map_font->fontwidth; + dim.scaled_font_size.y = map_font->fontheight; + } else if( overmap_font && win == g->w_overmap ) { + dim.scaled_font_size.x = overmap_font->fontwidth; + dim.scaled_font_size.y = overmap_font->fontheight; + } else { + dim.scaled_font_size.x = fontwidth; + dim.scaled_font_size.y = fontheight; } // multiplied by the user's specified scaling factor regardless of whether tiles are in use - fw = fw * get_scaling_factor(); - fh = fh * get_scaling_factor(); + dim.scaled_font_size *= get_scaling_factor(); + + dim.window_pos_cell = pwin->pos; + dim.window_size_cell.x = pwin->width; + dim.window_size_cell.y = pwin->height; - // Translate mouse coordinates to map coordinates based on tile size, // the window position is *always* in standard font dimensions! - const point win_min( capture_win->pos.x * fontwidth, capture_win->pos.y * fontheight ); + dim.window_pos_pixel = point( dim.window_pos_cell.x * fontwidth, + dim.window_pos_cell.y * fontheight ); // But the size of the window is in the font dimensions of the window. - const point win_size( capture_win->width * fw, capture_win->height * fh ); + dim.window_size_pixel.x = dim.window_size_cell.x * dim.scaled_font_size.x; + dim.window_size_pixel.y = dim.window_size_cell.y * dim.scaled_font_size.y; + + return dim; +} + +cata::optional input_context::get_coordinates( const catacurses::window &capture_win_ ) +{ + if( !coordinate_input_received ) { + return cata::nullopt; + } + + const catacurses::window &capture_win = capture_win_ ? capture_win_ : g->w_terrain; + const window_dimensions dim = get_window_dimensions( capture_win ); + + const int &fw = dim.scaled_font_size.x; + const int &fh = dim.scaled_font_size.y; + const point &win_min = dim.window_pos_pixel; + const point &win_size = dim.window_size_pixel; const point win_max = win_min + win_size; - // add_msg( m_info, "win_ left %d top %d right %d bottom %d", win_left,win_top,win_right,win_bottom); - // add_msg( m_info, "coordinate_ x %d y %d", coordinate_x, coordinate_y); + + // Translate mouse coordinates to map coordinates based on tile size // Check if click is within bounds of the window we care about const rectangle win_bounds( win_min, win_max ); if( !win_bounds.contains_inclusive( coordinate ) ) { @@ -3751,7 +3784,7 @@ cata::optional input_context::get_coordinates( const catacurses::windo p = view_offset + selected; } else { const point selected( screen_pos.x / fw, screen_pos.y / fh ); - p = view_offset + selected - point( capture_win->width / 2, capture_win->height / 2 ); + p = view_offset + selected - dim.window_size_cell / 2; } return tripoint( p, g->get_levz() ); diff --git a/src/sdltiles.h b/src/sdltiles.h index a7ab650c3ea4d..433561148e03d 100644 --- a/src/sdltiles.h +++ b/src/sdltiles.h @@ -9,10 +9,16 @@ #include #include "color_loader.h" +#include "point.h" #include "sdl_wrappers.h" class cata_tiles; +namespace catacurses +{ +class window; +} // namespace catacurses + extern SDL_Texture_Ptr alt_rect_tex; extern bool alt_rect_tex_enabled; extern std::unique_ptr tilecontext; @@ -25,6 +31,15 @@ void rescale_tileset( int size ); bool save_screenshot( const std::string &file_path ); void toggle_fullscreen_window(); +struct window_dimensions { + point scaled_font_size; + point window_pos_cell; + point window_size_cell; + point window_pos_pixel; + point window_size_pixel; +}; +window_dimensions get_window_dimensions( const catacurses::window &win ); + #endif // TILES #endif // CATA_SDLTILES_H diff --git a/src/ui_manager.cpp b/src/ui_manager.cpp new file mode 100644 index 0000000000000..9ee7387aa6aff --- /dev/null +++ b/src/ui_manager.cpp @@ -0,0 +1,126 @@ +#include "ui_manager.h" + +#include + +#include "cursesdef.h" +#include "point.h" +#include "sdltiles.h" + +static std::vector> ui_stack; + +ui_adaptor::ui_adaptor() : invalidated( false ) +{ + ui_stack.emplace_back( *this ); +} + +ui_adaptor::~ui_adaptor() +{ + for( auto it = ui_stack.rbegin(); it < ui_stack.rend(); ++it ) { + if( &it->get() == this ) { + ui_stack.erase( std::prev( it.base() ) ); + // TODO avoid invalidating portions that do not need to be redrawn + ui_manager::invalidate( dimensions ); + break; + } + } +} + +void ui_adaptor::position_from_window( const catacurses::window &win ) +{ + const rectangle old_dimensions = dimensions; + // ensure position is updated before calling invalidate +#ifdef TILES + const window_dimensions dim = get_window_dimensions( win ); + dimensions = rectangle( dim.window_pos_pixel, dim.window_pos_pixel + dim.window_size_pixel ); +#else + const point origin( getbegx( win ), getbegy( win ) ); + dimensions = rectangle( origin, origin + point( getmaxx( win ), getmaxy( win ) ) ); +#endif + invalidated = true; + ui_manager::invalidate( old_dimensions ); +} + +void ui_adaptor::on_redraw( const redraw_callback_t &fun ) +{ + redraw_cb = fun; +} + +void ui_adaptor::on_screen_resize( const screen_resize_callback_t &fun ) +{ + screen_resized_cb = fun; +} + +static bool contains( const rectangle &lhs, const rectangle &rhs ) +{ + return rhs.p_min.x >= lhs.p_min.x && rhs.p_max.x <= lhs.p_max.x && + rhs.p_min.y >= lhs.p_min.y && rhs.p_max.y <= lhs.p_max.y; +} + +static bool overlap( const rectangle &lhs, const rectangle &rhs ) +{ + return lhs.p_min.x < rhs.p_max.x && lhs.p_min.y < rhs.p_max.y && + rhs.p_min.x < lhs.p_max.x && rhs.p_min.y < lhs.p_max.y; +} + +void ui_adaptor::invalidate( const rectangle &rect ) +{ + if( rect.p_min.x >= rect.p_max.x || rect.p_min.y >= rect.p_max.y ) { + return; + } + // TODO avoid invalidating portions that do not need to be redrawn + for( auto it = ui_stack.crbegin(); it < ui_stack.crend(); ++it ) { + const ui_adaptor &ui = it->get(); + if( overlap( ui.dimensions, rect ) ) { + ui.invalidated = true; + if( contains( ui.dimensions, rect ) ) { + break; + } + } + } +} + +void ui_adaptor::redraw() +{ + // TODO refresh only when all stacked UIs are drawn + if( !ui_stack.empty() ) { + ui_stack.back().get().invalidated = true; + for( const ui_adaptor &ui : ui_stack ) { + if( ui.invalidated ) { + if( ui.redraw_cb ) { + ui.redraw_cb( ui ); + } + ui.invalidated = false; + } + } + } +} + +void ui_adaptor::screen_resized() +{ + for( ui_adaptor &ui : ui_stack ) { + if( ui.screen_resized_cb ) { + ui.screen_resized_cb( ui ); + } + } + redraw(); +} + +namespace ui_manager +{ + +void invalidate( const rectangle &rect ) +{ + ui_adaptor::invalidate( rect ); +} + +void redraw() +{ + ui_adaptor::redraw(); +} + +void screen_resized() +{ + ui_adaptor::screen_resized(); +} + +} // namespace ui_manager diff --git a/src/ui_manager.h b/src/ui_manager.h new file mode 100644 index 0000000000000..61c1f46915fd1 --- /dev/null +++ b/src/ui_manager.h @@ -0,0 +1,54 @@ +#pragma once +#ifndef UI_MANAGER_H +#define UI_MANAGER_H + +#include + +#include "point.h" + +namespace catacurses +{ +class window; +} // namespace catacurses + +class ui_adaptor +{ + public: + using redraw_callback_t = std::function; + using screen_resize_callback_t = std::function; + + ui_adaptor(); + ui_adaptor( const ui_adaptor &rhs ) = delete; + ui_adaptor( ui_adaptor &&rhs ) = delete; + ~ui_adaptor(); + + ui_adaptor &operator=( const ui_adaptor &rhs ) = delete; + ui_adaptor &operator=( ui_adaptor &&rhs ) = delete; + + void position_from_window( const catacurses::window &win ); + void on_redraw( const redraw_callback_t &fun ); + void on_screen_resize( const screen_resize_callback_t &fun ); + + static void invalidate( const rectangle &rect ); + static void redraw(); + static void screen_resized(); + private: + // pixel dimensions in tiles, console cell dimensions in curses + rectangle dimensions; + redraw_callback_t redraw_cb; + screen_resize_callback_t screen_resized_cb; + + mutable bool invalidated; +}; + +// export static funcs of ui_adaptor with a more coherent scope name +namespace ui_manager +{ +// rect is the pixel dimensions in tiles or console cell dimensions in curses +void invalidate( const rectangle &rect ); +// invalidate the top window and redraw all invalidated windows +void redraw(); +void screen_resized(); +} // namespace ui_manager + +#endif diff --git a/src/wincurse.cpp b/src/wincurse.cpp index 350759fc6516a..4337469a42080 100644 --- a/src/wincurse.cpp +++ b/src/wincurse.cpp @@ -24,6 +24,7 @@ #include "font_loader.h" #include "platform_win.h" #include "mmsystem.h" +#include "ui_manager.h" #include "wcwidth.h" //*********************************** @@ -189,6 +190,7 @@ bool handle_resize( int, int ) throw std::runtime_error( "SetDIBColorTable failed" ); } catacurses::refresh(); + ui_manager::screen_resized(); } return true; @@ -372,6 +374,9 @@ LRESULT CALLBACK ProcessMessages( HWND__ *hWnd, unsigned int Msg, case WM_PAINT: BitBlt( WindowDC, 0, 0, WindowWidth, WindowHeight, backbuffer, 0, 0, SRCCOPY ); + ui_manager::invalidate( rectangle( point_zero, point( getmaxx( catacurses::stdscr ), + getmaxy( catacurses::stdscr ) ) ) ); + ui_manager::redraw(); ValidateRect( WindowHandle, nullptr ); return 0; From 7698101451a7cb4f45c144a21961ef5e365ca383 Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:17:57 +0800 Subject: [PATCH 148/219] Use ui_adaptor in main game ui --- src/game.cpp | 7 ++++--- src/main.cpp | 11 ++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 5f47840d25822..0e9c32e95ac3f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -138,6 +138,7 @@ #include "ret_val.h" #include "tileray.h" #include "ui.h" +#include "ui_manager.h" #include "units.h" #include "int_id.h" #include "string_id.h" @@ -1492,7 +1493,7 @@ bool game::do_turn() } sounds::process_sound_markers( &u ); if( !u.activity && !u.has_distant_destination() && uquit != QUIT_WATCH ) { - draw(); + ui_manager::redraw(); } if( handle_action() ) { @@ -1589,7 +1590,7 @@ bool game::do_turn() mon_info_update(); u.process_turn(); if( u.moves < 0 && get_option( "FORCE_REDRAW" ) ) { - draw(); + ui_manager::redraw(); refresh_display(); } @@ -1602,7 +1603,7 @@ bool game::do_turn() if( player_is_sleeping ) { if( calendar::once_every( 30_minutes ) || !player_was_sleeping ) { - draw(); + ui_manager::redraw(); //Putting this in here to save on checking if( calendar::once_every( 1_hours ) ) { add_artifact_dreams( ); diff --git a/src/main.cpp b/src/main.cpp index 8da3f3577441b..6d5a46850faa7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include "debug.h" #include "filesystem.h" #include "game.h" +#include "input.h" #include "loading_ui.h" #include "main_menu.h" #include "mapsharing.h" @@ -35,8 +36,8 @@ #include "path_info.h" #include "rng.h" #include "translations.h" -#include "input.h" #include "type_id.h" +#include "ui_manager.h" #if defined(TILES) # if defined(_MSC_VER) && defined(USE_VCPKG) @@ -685,6 +686,14 @@ int main( int argc, char *argv[] ) } } + ui_adaptor main_ui; + main_ui.position_from_window( catacurses::stdscr ); + main_ui.on_redraw( []( const ui_adaptor & ) { + g->draw(); + } ); + main_ui.on_screen_resize( []( ui_adaptor & ui ) { + ui.position_from_window( catacurses::stdscr ); + } ); while( !g->do_turn() ); } From 4200b4b57d05a33452b0921b1c1f77fdba89401b Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:24:17 +0800 Subject: [PATCH 149/219] Use ui_adaptor in query_popup --- src/animation.cpp | 1 + src/game.cpp | 3 +++ src/output.cpp | 2 ++ src/popup.cpp | 40 ++++++++++++++++++++++++++++++---------- src/popup.h | 5 +++++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/animation.cpp b/src/animation.cpp index 539e7b1cdf350..788ead6b44311 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -52,6 +52,7 @@ class basic_animation .on_top( true ) .show(); + catacurses::refresh(); refresh_display(); } diff --git a/src/game.cpp b/src/game.cpp index 0e9c32e95ac3f..c591add5a16e5 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1625,6 +1625,9 @@ bool game::do_turn() .wait_message( "%s", *progress ) .on_top( true ) .show(); + + catacurses::refresh(); + refresh_display(); } } diff --git a/src/output.cpp b/src/output.cpp index bd367b3218d91..cf93a8602461b 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -639,6 +639,8 @@ int popup( const std::string &text, PopupFlags flags ) if( flags & PF_NO_WAIT ) { pop.show(); + catacurses::refresh(); + refresh_display(); return UNKNOWN_UNICODE; } else { pop.context( "POPUP_WAIT" ); diff --git a/src/popup.cpp b/src/popup.cpp index 344819e0b920e..b91a7474433e3 100644 --- a/src/popup.cpp +++ b/src/popup.cpp @@ -4,10 +4,11 @@ #include #include +#include "catacharset.h" #include "ime.h" #include "input.h" #include "output.h" -#include "catacharset.h" +#include "ui_manager.h" extern bool test_mode; @@ -129,10 +130,6 @@ std::vector> query_popup::fold_query( void query_popup::invalidate_ui() const { if( win ) { - werase( win ); - wrefresh( win ); - catacurses::refresh(); - refresh_display(); win = {}; folded_msg.clear(); buttons.clear(); @@ -208,6 +205,11 @@ void query_popup::init() const const int win_x = ( TERMX - win_width ) / 2; const int win_y = ontop ? 0 : ( TERMY - win_height ) / 2; win = catacurses::newwin( win_height, win_width, point( win_x, win_y ) ); + + std::shared_ptr ui = adaptor.lock(); + if( ui ) { + ui->position_from_window( win ); + } } void query_popup::show() const @@ -233,10 +235,24 @@ void query_popup::show() const } wrefresh( win ); - // Need to refresh display when displaying popups wihout taking input, such - // as during saving. - catacurses::refresh(); - refresh_display(); +} + +std::shared_ptr query_popup::create_or_get_adaptor() +{ + std::shared_ptr ui = adaptor.lock(); + if( !ui ) { + adaptor = ui = std::make_shared(); + ui->on_redraw( [this]( const ui_adaptor & ) { + show(); + } ); + ui->on_screen_resize( [this]( ui_adaptor & ) { + init(); + } ); + if( win ) { + ui->position_from_window( win ); + } + } + return ui; } query_popup::result query_popup::query_once() @@ -249,7 +265,9 @@ query_popup::result query_popup::query_once() return { false, "ERROR", {} }; } - show(); + std::shared_ptr ui = create_or_get_adaptor(); + + ui_manager::redraw(); input_context ctxt( category ); if( cancel || !options.empty() ) { @@ -326,6 +344,8 @@ query_popup::result query_popup::query() { ime_sentry sentry( ime_sentry::disable ); + std::shared_ptr ui = create_or_get_adaptor(); + result res; do { res = query_once(); diff --git a/src/popup.h b/src/popup.h index f38bbf7c63d3f..6affb0e7590ba 100644 --- a/src/popup.h +++ b/src/popup.h @@ -13,6 +13,8 @@ #include "color.h" #include "string_formatter.h" +class ui_adaptor; + /** * UI class for displaying messages or querying player input with popups. * @@ -213,6 +215,9 @@ class query_popup point pos; }; + std::weak_ptr adaptor; + std::shared_ptr create_or_get_adaptor(); + // UI caches mutable catacurses::window win; mutable std::vector folded_msg; From b30ef95c538966f33480b85c48a9054e469bb29e Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:28:06 +0800 Subject: [PATCH 150/219] Use ui_adaptor in keybindings menu --- src/input.cpp | 58 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 4f31ac7bec4ee..fcac31418f167 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -30,6 +30,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "point.h" @@ -1014,13 +1015,32 @@ action_id input_context::display_menu( const bool permit_execute_action ) std::string hotkeys = ctxt.get_available_single_char_hotkeys( display_help_hotkeys ); - int maxwidth = max( FULL_SCREEN_WIDTH, TERMX ); - int width = min( 80, maxwidth ); - int maxheight = max( FULL_SCREEN_HEIGHT, TERMY ); - int height = min( maxheight, static_cast( hotkeys.size() ) + LEGEND_HEIGHT + BORDER_SPACE ); - - catacurses::window w_help = catacurses::newwin( height - 2, width - 2, - point( maxwidth / 2 - width / 2, maxheight / 2 - height / 2 ) ); + ui_adaptor ui; + int width = 0; + int height = 0; + catacurses::window w_help; + size_t display_height = 0; + size_t legwidth = 0; + string_input_popup spopup; + const auto recalc_size = [&]( ui_adaptor & ui ) { + int maxwidth = max( FULL_SCREEN_WIDTH, TERMX ); + width = min( 80, maxwidth ); + int maxheight = max( FULL_SCREEN_HEIGHT, TERMY ); + height = min( maxheight, static_cast( hotkeys.size() ) + LEGEND_HEIGHT + BORDER_SPACE ); + + w_help = catacurses::newwin( height - 2, width - 2, + point( maxwidth / 2 - width / 2, maxheight / 2 - height / 2 ) ); + // height of the area usable for display of keybindings, excludes headers & borders + display_height = height - LEGEND_HEIGHT - BORDER_SPACE; // -2 for the border + // width of the legend + legwidth = width - 4 - BORDER_SPACE; + spopup.window( w_help, 4, 8, legwidth ) + .max_length( legwidth ) + .context( ctxt ); + ui.position_from_window( w_help ); + }; + recalc_size( ui ); + ui.on_screen_resize( recalc_size ); // has the user changed something? bool changed = false; @@ -1042,10 +1062,6 @@ action_id input_context::display_menu( const bool permit_execute_action ) static const nc_color unbound_key = c_light_red; // (vertical) scroll offset size_t scroll_offset = 0; - // height of the area usable for display of keybindings, excludes headers & borders - const size_t display_height = height - LEGEND_HEIGHT - BORDER_SPACE; // -2 for the border - // width of the legend - const size_t legwidth = width - 4 - BORDER_SPACE; // keybindings help std::string legend; legend += colorize( _( "Unbound keys" ), unbound_key ) + "\n"; @@ -1060,14 +1076,8 @@ action_id input_context::display_menu( const bool permit_execute_action ) std::string filter_phrase; std::string action; int raw_input_char = 0; - string_input_popup spopup; - spopup.window( w_help, 4, 8, legwidth ) - .max_length( legwidth ) - .context( ctxt ); - // do not switch IME mode now, but restore previous mode on return - ime_sentry sentry( ime_sentry::keep ); - while( true ) { + const auto redraw = [&]( const ui_adaptor & ) { werase( w_help ); draw_border( w_help, BORDER_COLOR, _( "Keybindings" ), c_light_red ); draw_scrollbar( w_help, scroll_offset, display_height, @@ -1115,14 +1125,20 @@ action_id input_context::display_menu( const bool permit_execute_action ) } // spopup.query_string() will call wrefresh( w_help ) - catacurses::refresh(); - spopup.text( filter_phrase ); + spopup.query_string( false, true ); + }; + ui.on_redraw( redraw ); + + // do not switch IME mode now, but restore previous mode on return + ime_sentry sentry( ime_sentry::keep ); + while( true ) { + ui_manager::redraw(); + if( status == s_show ) { filter_phrase = spopup.query_string( false ); action = ctxt.input_to_action( ctxt.get_raw_input() ); } else { - spopup.query_string( false, true ); action = ctxt.handle_input(); } raw_input_char = ctxt.get_raw_input().get_first_input(); From 2ad9898959ebc1932e7d49f51b138e6035eed287 Mon Sep 17 00:00:00 2001 From: Qrox Date: Tue, 25 Feb 2020 03:44:32 +0800 Subject: [PATCH 151/219] Use ui_adaptor in uilist --- src/ui.cpp | 105 ++++++++++++++++++++++++++++++----------------------- src/ui.h | 14 +++++-- 2 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/ui.cpp b/src/ui.cpp index c36c98150dde0..43d7fe7ae5a12 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -18,6 +18,7 @@ #include "output.h" #include "player.h" #include "string_input_popup.h" +#include "ui_manager.h" #if defined(__ANDROID__) #include @@ -106,6 +107,8 @@ uilist::uilist( const point &start, int width, const std::string &msg, query(); } +uilist::~uilist() = default; + /* * Enables oneshot construction -> running -> exit */ @@ -233,60 +236,30 @@ void uilist::filterlist() } } -/** - * Call string_input_win / ui_element_input::input_filter and filter the entries list interactively - */ -std::string uilist::inputfilter() +void uilist::inputfilter() { - // TODO: uilist.filter_identifier ? - std::string identifier; - mvwprintz( window, point( 2, w_height - 1 ), border_color, "< " ); - mvwprintz( window, point( w_width - 3, w_height - 1 ), border_color, " >" ); - /* - //debatable merit - std::string origfilter = filter; - int origselected = selected; - int origfselected = fselected; - int origvshift = vshift; - */ - string_input_popup popup; - popup.text( filter ) + filter_popup = std::make_unique(); + filter_popup->text( filter ) .max_length( 256 ) - .window( window, 4, w_height - 1, w_width - 4 ) - .identifier( identifier ); + .window( window, 4, w_height - 1, w_width - 4 ); input_event event; ime_sentry sentry; do { - // filter=filter_input->query(filter, false); - filter = popup.query_string( false ); - event = popup.context().get_raw_input(); - // key = filter_input->keypress; + ui_manager::redraw(); + filter = filter_popup->query_string( false ); + event = filter_popup->context().get_raw_input(); if( event.get_first_input() != KEY_ESCAPE ) { if( !scrollby( scroll_amount_from_key( event.get_first_input() ) ) ) { filterlist(); } - show(); } } while( event.get_first_input() != '\n' && event.get_first_input() != KEY_ESCAPE ); if( event.get_first_input() == KEY_ESCAPE ) { - /* - //perhaps as an option - filter = origfilter; - selected = origselected; - fselected = origfselected; - vshift = origvshift; - */ filterlist(); } - wattron( window, border_color ); - for( int i = 1; i < w_width - 1; i++ ) { - mvwaddch( window, point( i, w_height - 1 ), LINE_OXOX ); - } - wattroff( window, border_color ); - - return filter; + filter_popup.reset(); } /** @@ -506,10 +479,12 @@ void uilist::setup() } } - if( w_x == -1 ) { + w_x_autoassigned = w_x == MENU_AUTOASSIGN; + if( w_x_autoassigned ) { w_x = static_cast( ( TERMX - w_width ) / 2 ); } - if( w_y == -1 ) { + w_y_autoassigned = w_y == MENU_AUTOASSIGN; + if( w_y_autoassigned ) { w_y = static_cast( ( TERMY - w_height ) / 2 ); } @@ -681,9 +656,15 @@ void uilist::show() } } - if( !filter.empty() ) { - mvwprintz( window, point( 2, w_height - 1 ), border_color, "< %s >", filter ); - mvwprintz( window, point( 4, w_height - 1 ), text_color, filter ); + if( filter_popup ) { + mvwprintz( window, point( 2, w_height - 1 ), border_color, "< " ); + mvwprintz( window, point( w_width - 3, w_height - 1 ), border_color, " >" ); + filter_popup->query( /*loop=*/false, /*draw_only=*/true ); + } else { + if( !filter.empty() ) { + mvwprintz( window, point( 2, w_height - 1 ), border_color, "< %s >", filter ); + mvwprintz( window, point( 4, w_height - 1 ), text_color, filter ); + } } apply_scrollbar(); @@ -845,7 +826,41 @@ void uilist::query( bool loop, int timeout ) } hotkeys = ctxt.get_available_single_char_hotkeys( hotkeys ); - show(); + ui_adaptor ui; + ui.on_redraw( [this]( const ui_adaptor & ) { + show(); + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + if( w_x_autoassigned || w_y_autoassigned ) { + // because the way `setup()` works we cannot call it again here, + // so just move the window to the center of the screen instead. + if( w_x_autoassigned ) { + if( w_width >= TERMX ) { + w_x = 0; + } else { + w_x = ( TERMX - w_width ) / 2; + } + } + if( w_y_autoassigned ) { + if( w_height > TERMY ) { + w_y = 0; + } else { + w_y = ( TERMY - w_height ) / 2; + } + } + window = catacurses::newwin( w_height, w_width, point( w_x, w_y ) ); + if( filter_popup ) { + filter_popup->window( window, 4, w_height - 1, w_width - 4 ); + } + ui.position_from_window( window ); + } + } ); + if( !started ) { + setup(); + } + ui.position_from_window( window ); + + ui_manager::redraw(); #if defined(__ANDROID__) for( const auto &entry : entries ) { @@ -898,7 +913,7 @@ void uilist::query( bool loop, int timeout ) } } - show(); + ui_manager::redraw(); } while( loop && ret == UILIST_WAIT_INPUT ); } diff --git a/src/ui.h b/src/ui.h index 00b9b90085ff0..00f9d439e1087 100644 --- a/src/ui.h +++ b/src/ui.h @@ -34,6 +34,7 @@ constexpr point MENU_AUTOASSIGN_POS( MENU_AUTOASSIGN, MENU_AUTOASSIGN ); struct input_event; class input_context; +class string_input_popup; catacurses::window new_centered_win( int nlines, int ncols ); @@ -229,6 +230,8 @@ class uilist: public ui_container uilist( const point &start, int width, const std::string &msg, std::initializer_list opts ); + ~uilist() override; + void init(); void setup(); void show(); @@ -238,7 +241,6 @@ class uilist: public ui_container void query( bool loop = true, int timeout = -1 ); void filterlist(); void apply_scrollbar(); - std::string inputfilter(); void refresh( bool refresh_callback = true ) override; void redraw( bool redraw_callback = true ); void addentry( const std::string &str ); @@ -260,10 +262,16 @@ class uilist: public ui_container operator int() const; - // pending refactor // ui_element_input * filter_input; - private: bool started = false; + std::unique_ptr filter_popup; + + bool w_x_autoassigned = false; + bool w_y_autoassigned = false; + + // This function assumes it's being called from `query` and should + // not be made public. + void inputfilter(); protected: std::string hotkeys; From a6490af0cfe9bcfca45fa4e5e5b3d6d48fa74e91 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 18:03:58 +0800 Subject: [PATCH 152/219] Use ui_adaptor in main menu --- src/main_menu.cpp | 84 +++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index bca8cea985b9e..ca84a7758fc17 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -38,6 +38,7 @@ #include "options.h" #include "pldata.h" #include "string_formatter.h" +#include "ui_manager.h" static const holiday current_holiday = holiday::none; @@ -467,21 +468,63 @@ bool main_menu::opening_screen() sel1 = 2; } - while( !start ) { - // disable ime at program start - // somehow this need to be here to actually work - disable_ime(); - + ui_adaptor ui; + ui.on_redraw( [&]( const ui_adaptor & ) { print_menu( w_open, sel1, menu_offset ); if( layer == 1 ) { if( sel1 == 0 ) { // Print MOTD. display_text( mmenu_motd, "MOTD", sel_line ); - } else if( sel1 == 7 ) { // Print Credits. display_text( mmenu_credits, "Credits", sel_line ); } + } else if( layer == 2 ) { + if( sel1 == 4 ) { // Special game + std::vector special_names; + int xlen = 0; + for( int i = 1; i < NUM_SPECIAL_GAMES; i++ ) { + std::string spec_name = special_game_name( static_cast( i ) ); + special_names.push_back( spec_name ); + xlen += utf8_width( shortcut_text( c_white, spec_name ), true ) + 2; + } + xlen += special_names.size() - 1; + point offset( menu_offset + point( -( xlen / 4 ) + 32 + extra_w / 2, -2 ) ); + print_menu_items( w_open, special_names, sel2, offset ); + + wrefresh( w_open ); + } else if( sel1 == 5 ) { // Settings Menu + int settings_subs_to_display = vSettingsSubItems.size(); + std::vector settings_subs; + int xlen = 0; + for( int i = 0; i < settings_subs_to_display; ++i ) { + settings_subs.push_back( vSettingsSubItems[i] ); + // Open and close brackets added + xlen += utf8_width( shortcut_text( c_white, vSettingsSubItems[i] ), true ) + 2; + } + xlen += settings_subs.size() - 1; + point offset = menu_offset + point( 46 + extra_w / 2 - ( xlen / 4 ), -2 ); + if( settings_subs.size() > 1 ) { + offset.x -= 6; + } + print_menu_items( w_open, settings_subs, sel2, offset ); + wrefresh( w_open ); + } + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + + while( !start ) { + // disable ime at program start + // somehow this need to be here to actually work + disable_ime(); + + ui_manager::redraw(); + if( layer == 1 ) { std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; @@ -535,7 +578,6 @@ bool main_menu::opening_screen() } else { sel2 = 0; layer = 2; - print_menu( w_open, sel1, menu_offset ); switch( sel1 ) { case 1: @@ -560,19 +602,6 @@ bool main_menu::opening_screen() continue; } - std::vector special_names; - int xlen = 0; - for( int i = 1; i < NUM_SPECIAL_GAMES; i++ ) { - std::string spec_name = special_game_name( static_cast( i ) ); - special_names.push_back( spec_name ); - xlen += utf8_width( shortcut_text( c_white, spec_name ), true ) + 2; - } - xlen += special_names.size() - 1; - point offset( menu_offset + point( -( xlen / 4 ) + 32 + extra_w / 2, -2 ) ); - print_menu_items( w_open, special_names, sel2, offset ); - - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( action == "LEFT" ) { if( sel2 > 0 ) { @@ -620,21 +649,6 @@ bool main_menu::opening_screen() } } else if( sel1 == 5 ) { // Settings Menu int settings_subs_to_display = vSettingsSubItems.size(); - std::vector settings_subs; - int xlen = 0; - for( int i = 0; i < settings_subs_to_display; ++i ) { - settings_subs.push_back( vSettingsSubItems[i] ); - // Open and close brackets added - xlen += utf8_width( shortcut_text( c_white, vSettingsSubItems[i] ), true ) + 2; - } - xlen += settings_subs.size() - 1; - point offset = menu_offset + point( 46 + extra_w / 2 - ( xlen / 4 ), -2 ); - if( settings_subs.size() > 1 ) { - offset.x -= 6; - } - print_menu_items( w_open, settings_subs, sel2, offset ); - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; for( int i = 0; i < settings_subs_to_display; ++i ) { From c0a695ebf6930cea14cd734ef5e6f2a3c1057526 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 19:49:27 +0800 Subject: [PATCH 153/219] Use ui_adaptor in main menu new character submenu --- src/main_menu.cpp | 64 +++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index ca84a7758fc17..2d6518b4de719 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -732,11 +732,43 @@ bool main_menu::new_character_tab() vNewGameHotkeys.push_back( get_hotkeys( item ) ); } - bool start = false; - while( !start && sel1 == 1 && ( layer == 2 || layer == 3 ) ) { + ui_adaptor ui; + ui.on_redraw( [&]( const ui_adaptor & ) { print_menu( w_open, 1, menu_offset ); + if( layer == 2 && sel1 == 1 ) { center_print( w_open, getmaxy( w_open ) - 7, c_yellow, hints[sel2] ); + + print_menu_items( w_open, vSubItems, sel2, menu_offset + point( 0, -2 ) ); + wrefresh( w_open ); + } else if( layer == 3 && sel1 == 1 ) { + // Then view presets + if( templates.empty() ) { + mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -4 ), + c_red, "%s", _( "No templates found!" ) ); + } else { + mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -2 ), + c_white, "%s", _( "Press 'd' to delete a preset." ) ); + for( int i = 0; i < static_cast( templates.size() ); i++ ) { + int line = menu_offset.y - 4 - i; + mvwprintz( w_open, point( 20 + menu_offset.x + extra_w / 2, line ), + ( sel3 == i ? h_white : c_white ), "%s", + templates[i] ); + } + } + wrefresh( w_open ); + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + + bool start = false; + while( !start && sel1 == 1 && ( layer == 2 || layer == 3 ) ) { + ui_manager::redraw(); + if( layer == 2 && sel1 == 1 ) { // Then choose custom character, random character, preset, etc if( MAP_SHARING::isSharing() && world_generator->all_worldnames().empty() ) { //don't show anything when there are no worlds (will not work if there are special maps) @@ -745,10 +777,6 @@ bool main_menu::new_character_tab() continue; } - print_menu_items( w_open, vSubItems, sel2, menu_offset + point( 0, -2 ) ); - wrefresh( w_open ); - catacurses::refresh(); - std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vNewGameHotkeys.size(); ++i ) { @@ -812,16 +840,11 @@ bool main_menu::new_character_tab() } if( !g->u.create( play_type ) ) { load_char_templates(); - werase( w_background ); - wrefresh( w_background ); MAPBUFFER.reset(); overmap_buffer.clear(); continue; } - werase( w_background ); - wrefresh( w_background ); - if( !g->start_game() ) { continue; } @@ -835,27 +858,13 @@ bool main_menu::new_character_tab() } else if( layer == 3 && sel1 == 1 ) { // Then view presets if( templates.empty() ) { - mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -4 ), - c_red, "%s", _( "No templates found!" ) ); on_error(); - } else { - mvwprintz( w_open, menu_offset + point( 20 + extra_w / 2, -2 ), - c_white, "%s", _( "Press 'd' to delete a preset." ) ); - for( int i = 0; i < static_cast( templates.size() ); i++ ) { - int line = menu_offset.y - 4 - i; - mvwprintz( w_open, point( 20 + menu_offset.x + extra_w / 2, line ), - ( sel3 == i ? h_white : c_white ), "%s", - templates[i] ); - } } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); sel1 = 1; layer = 2; - print_menu( w_open, sel1, menu_offset ); } else if( action == "DOWN" ) { if( sel3 > 0 ) { sel3--; @@ -871,7 +880,6 @@ bool main_menu::new_character_tab() } else if( action == "LEFT" || action == "QUIT" ) { sel1 = 1; layer = 2; - print_menu( w_open, sel1, menu_offset ); } else if( !templates.empty() && action == "DELETE_TEMPLATE" ) { if( query_yn( _( "Are you sure you want to delete %s?" ), templates[sel3].c_str() ) ) { @@ -903,14 +911,10 @@ bool main_menu::new_character_tab() } if( !g->u.create( PLTYPE_TEMPLATE, templates[sel3] ) ) { load_char_templates(); - werase( w_background ); - wrefresh( w_background ); MAPBUFFER.reset(); overmap_buffer.clear(); continue; } - werase( w_background ); - wrefresh( w_background ); if( !g->start_game() ) { continue; } From e4daf421025e955c62d0793e179828d213430a86 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 20:09:27 +0800 Subject: [PATCH 154/219] Use ui_adaptor in main menu load character submenu --- src/main_menu.cpp | 66 ++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 2d6518b4de719..b020b054b2f15 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -964,15 +964,17 @@ bool main_menu::load_character_tab( bool transfer ) } } - const int offset_x = transfer ? 25 : 15; - const int offset_y = transfer ? -1 : 0; - while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { + ui_adaptor ui; + ui.on_redraw( [&]( const ui_adaptor & ) { + const int offset_x = transfer ? 25 : 15; + const int offset_y = transfer ? -1 : 0; + print_menu( w_open, transfer ? 3 : 2, menu_offset ); + if( layer == 2 && sel1 == 2 ) { if( all_worldnames.empty() ) { mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 ), c_red, "%s", _( "No Worlds found!" ) ); - on_error(); } else { for( int i = 0; i < static_cast( all_worldnames.size() ); ++i ) { int line = menu_offset.y - 2 - i; @@ -992,7 +994,40 @@ bool main_menu::load_character_tab( bool transfer ) } } wrefresh( w_open ); - catacurses::refresh(); + } else if( layer == 3 && sel1 == 2 ) { + const std::string &wn = all_worldnames[sel2]; + + mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 - sel2 + offset_y ), h_white, + "%s", wn ); + + if( savegames.empty() ) { + mvwprintz( w_open, menu_offset + point( 40 + extra_w / 2, -2 - sel2 + offset_y ), + c_red, "%s", _( "No save games found!" ) ); + } else { + int line = menu_offset.y - 2; + + for( const auto &savename : savegames ) { + const bool selected = sel3 + line == menu_offset.y - 2; + mvwprintz( w_open, point( 40 + menu_offset.x + extra_w / 2, line-- + offset_y ), + selected ? h_white : c_white, + "%s", savename.player_name() ); + } + } + wrefresh( w_open ); + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + + while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { + ui_manager::redraw(); + if( layer == 2 && sel1 == 2 ) { + if( all_worldnames.empty() ) { + on_error(); + } std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); @@ -1018,7 +1053,6 @@ bool main_menu::load_character_tab( bool transfer ) } } else if( layer == 3 && sel1 == 2 ) { savegames = world_generator->get_world( all_worldnames[sel2] )->world_saves; - const std::string &wn = all_worldnames[sel2]; if( MAP_SHARING::isSharing() ) { auto new_end = std::remove_if( savegames.begin(), savegames.end(), @@ -1028,25 +1062,9 @@ bool main_menu::load_character_tab( bool transfer ) savegames.erase( new_end, savegames.end() ); } - mvwprintz( w_open, menu_offset + point( offset_x + extra_w / 2, -2 - sel2 + offset_y ), h_white, - "%s", wn ); - if( savegames.empty() ) { - mvwprintz( w_open, menu_offset + point( 40 + extra_w / 2, -2 - sel2 + offset_y ), - c_red, "%s", _( "No save games found!" ) ); on_error(); - } else { - int line = menu_offset.y - 2; - - for( const auto &savename : savegames ) { - const bool selected = sel3 + line == menu_offset.y - 2; - mvwprintz( w_open, point( 40 + menu_offset.x + extra_w / 2, line-- + offset_y ), - selected ? h_white : c_white, - "%s", savename.player_name() ); - } } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( errflag && action != "TIMEOUT" ) { clear_error(); @@ -1066,7 +1084,6 @@ bool main_menu::load_character_tab( bool transfer ) } else if( action == "LEFT" || action == "QUIT" ) { layer = transfer ? 1 : 2; sel3 = 0; - print_menu( w_open, sel1, menu_offset ); } if( action == "RIGHT" || action == "CONFIRM" ) { if( sel3 >= 0 && sel3 < static_cast( savegames.size() ) ) { @@ -1075,9 +1092,6 @@ bool main_menu::load_character_tab( bool transfer ) world_generator->set_active_world( nullptr ); } ); - werase( w_background ); - wrefresh( w_background ); - WORLDPTR world = world_generator->get_world( all_worldnames[sel2] ); world_generator->last_world_name = world->world_name; world_generator->last_character_name = savegames[sel3].player_name(); From 640a0471a49664a113a41c7a14bb831177ecf4cc Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 20:51:18 +0800 Subject: [PATCH 155/219] Use ui_adaptor in world tab --- src/main_menu.cpp | 105 ++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index b020b054b2f15..c416c97f2a41f 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -1125,8 +1125,67 @@ bool main_menu::load_character_tab( bool transfer ) void main_menu::world_tab() { + ui_adaptor ui; + ui.on_redraw( [this]( const ui_adaptor & ) { + if( sel1 == 3 ) { // bail out if we're actually in load_character_tab + print_menu( w_open, 3, menu_offset ); + + if( layer == 3 ) { // World Menu + const point offset = menu_offset + point( 40 + extra_w / 2, -2 - sel2 ); + + const auto all_worldnames = world_generator->all_worldnames(); + mvwprintz( w_open, offset + point( -15, 0 ), h_white, "%s", all_worldnames[sel2 - 1] ); + + for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { + nc_color text_color; + nc_color key_color; + if( sel3 == static_cast( i ) ) { + text_color = h_white; + key_color = h_white; + } else { + text_color = c_light_gray; + key_color = c_white; + } + wmove( w_open, offset + point( 0, -i ) ); + wprintz( w_open, c_light_gray, "[" ); + shortcut_print( w_open, text_color, key_color, vWorldSubItems[i] ); + wprintz( w_open, c_light_gray, "]" ); + } + + wrefresh( w_open ); + } else if( layer == 2 ) { // Show world names + mvwprintz( w_open, menu_offset + point( 25 + extra_w / 2, -2 ), + ( sel2 == 0 ? h_white : c_white ), "%s", _( "Create World" ) ); + + int i = 1; + const auto all_worldnames = world_generator->all_worldnames(); + for( auto it = all_worldnames.begin(); it != all_worldnames.end(); ++it, i++ ) { + int savegames_count = world_generator->get_world( *it )->world_saves.size(); + int line = menu_offset.y - 2 - i; + nc_color color1, color2; + if( *it == "TUTORIAL" || *it == "DEFENSE" ) { + color1 = c_light_cyan; + color2 = h_light_cyan; + } else { + color1 = c_white; + color2 = h_white; + } + mvwprintz( w_open, point( 25 + menu_offset.x + extra_w / 2, line ), + ( sel2 == i ? color2 : color1 ), "%s (%d)", ( *it ).c_str(), savegames_count ); + } + + wrefresh( w_open ); + } + } + } ); + ui.on_screen_resize( [this]( ui_adaptor & ui ) { + init_windows(); + ui.position_from_window( w_background ); + } ); + ui.position_from_window( w_background ); + while( sel1 == 3 && ( layer == 2 || layer == 3 || layer == 4 ) ) { - print_menu( w_open, 3, menu_offset ); + ui_manager::redraw(); if( layer == 4 ) { //Character to Template if( load_character_tab( true ) ) { points_left points; @@ -1145,9 +1204,6 @@ void main_menu::world_tab() load_char_templates(); - werase( w_background ); - wrefresh( w_background ); - layer = 3; } } else if( layer == 3 ) { // World Menu @@ -1156,29 +1212,8 @@ void main_menu::world_tab() // Reset empties world of everything but options, then makes new world within it. // Destroy asks for confirmation, then destroys everything in world and then removes world folder. - const point offset = menu_offset + point( 40 + extra_w / 2, -2 - sel2 ); - const auto all_worldnames = world_generator->all_worldnames(); - mvwprintz( w_open, offset + point( -15, 0 ), h_white, "%s", all_worldnames[sel2 - 1] ); - - for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { - nc_color text_color; - nc_color key_color; - if( sel3 == static_cast( i ) ) { - text_color = h_white; - key_color = h_white; - } else { - text_color = c_light_gray; - key_color = c_white; - } - wmove( w_open, offset + point( 0, -i ) ); - wprintz( w_open, c_light_gray, "[" ); - shortcut_print( w_open, text_color, key_color, vWorldSubItems[i] ); - wprintz( w_open, c_light_gray, "]" ); - } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { @@ -1256,28 +1291,8 @@ void main_menu::world_tab() continue; } - mvwprintz( w_open, menu_offset + point( 25 + extra_w / 2, -2 ), - ( sel2 == 0 ? h_white : c_white ), "%s", _( "Create World" ) ); - - int i = 1; const auto all_worldnames = world_generator->all_worldnames(); - for( auto it = all_worldnames.begin(); it != all_worldnames.end(); ++it, i++ ) { - int savegames_count = world_generator->get_world( *it )->world_saves.size(); - int line = menu_offset.y - 2 - i; - nc_color color1, color2; - if( *it == "TUTORIAL" || *it == "DEFENSE" ) { - color1 = c_light_cyan; - color2 = h_light_cyan; - } else { - color1 = c_white; - color2 = h_white; - } - mvwprintz( w_open, point( 25 + menu_offset.x + extra_w / 2, line ), - ( sel2 == i ? color2 : color1 ), "%s (%d)", ( *it ).c_str(), savegames_count ); - } - wrefresh( w_open ); - catacurses::refresh(); std::string action = handle_input_timeout( ctxt ); if( action == "DOWN" ) { From 3ac1dc692d0e2c20d4f80b8ba5dcad5834675b05 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 21:23:12 +0800 Subject: [PATCH 156/219] Remove w_background and use ui_adaptor to erase background instead --- src/game.cpp | 1 - src/main_menu.cpp | 30 ++++++++++++++++++------------ src/main_menu.h | 1 - 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index c591add5a16e5..aa2898ea3438c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2766,7 +2766,6 @@ void game::load( const save_t &name ) calendar::set_season_length( ::get_option( "SEASON_LENGTH" ) ); u.reset(); - draw(); } void game::load_world_modfiles( loading_ui &ui ) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index c416c97f2a41f..e34598f48e3b7 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -256,10 +256,6 @@ void main_menu::init_windows() return; } - w_background = catacurses::newwin( TERMY, TERMX, point_zero ); - werase( w_background ); - wrefresh( w_background ); - // main window should also expand to use available display space. // expanding to evenly use up half of extra space, for now. extra_w = ( ( TERMX - FULL_SCREEN_WIDTH ) / 2 ) - 1; @@ -468,6 +464,16 @@ bool main_menu::opening_screen() sel1 = 2; } + ui_adaptor background; + background.on_redraw( []( const ui_adaptor & ) { + catacurses::erase(); + catacurses::refresh(); + } ); + background.on_screen_resize( []( ui_adaptor & background ) { + background.position_from_window( catacurses::stdscr ); + } ); + background.position_from_window( catacurses::stdscr ); + ui_adaptor ui; ui.on_redraw( [&]( const ui_adaptor & ) { print_menu( w_open, sel1, menu_offset ); @@ -513,9 +519,9 @@ bool main_menu::opening_screen() } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); while( !start ) { // disable ime at program start @@ -761,9 +767,9 @@ bool main_menu::new_character_tab() } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); bool start = false; while( !start && sel1 == 1 && ( layer == 2 || layer == 3 ) ) { @@ -1018,9 +1024,9 @@ bool main_menu::load_character_tab( bool transfer ) } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); while( !start && sel1 == 2 && ( layer == 2 || layer == 3 ) ) { ui_manager::redraw(); @@ -1180,9 +1186,9 @@ void main_menu::world_tab() } ); ui.on_screen_resize( [this]( ui_adaptor & ui ) { init_windows(); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); } ); - ui.position_from_window( w_background ); + ui.position_from_window( w_open ); while( sel1 == 3 && ( layer == 2 || layer == 3 || layer == 4 ) ) { ui_manager::redraw(); diff --git a/src/main_menu.h b/src/main_menu.h index 3247fd1d893f5..d15f77ceb2661 100644 --- a/src/main_menu.h +++ b/src/main_menu.h @@ -71,7 +71,6 @@ class main_menu int layer = 1; point LAST_TERM; catacurses::window w_open; - catacurses::window w_background; point menu_offset; std::vector templates; int extra_w = 0; From edf6164117258154258e82d4aa92d52b71b70da6 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 22:15:15 +0800 Subject: [PATCH 157/219] Remove main_menu::handle_input_timeout now that we have proper window resizing --- src/main_menu.cpp | 29 +++++++++-------------------- src/main_menu.h | 1 - 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index e34598f48e3b7..6988f1f5f7cc1 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -239,17 +239,6 @@ std::vector main_menu::load_file( const std::string &path, return result; } -std::string main_menu::handle_input_timeout( input_context &ctxt ) -{ - std::string action = ctxt.handle_input( 1000 ); - - if( action == "TIMEOUT" ) { - init_windows(); - } - - return action; -} - void main_menu::init_windows() { if( LAST_TERM == point( TERMX, TERMY ) ) { @@ -531,7 +520,7 @@ bool main_menu::opening_screen() ui_manager::redraw(); if( layer == 1 ) { - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; // check automatic menu shortcuts @@ -608,7 +597,7 @@ bool main_menu::opening_screen() continue; } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( action == "LEFT" ) { if( sel2 > 0 ) { sel2--; @@ -655,7 +644,7 @@ bool main_menu::opening_screen() } } else if( sel1 == 5 ) { // Settings Menu int settings_subs_to_display = vSettingsSubItems.size(); - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; for( int i = 0; i < settings_subs_to_display; ++i ) { for( const std::string &hotkey : vSettingsHotkeys[i] ) { @@ -783,7 +772,7 @@ bool main_menu::new_character_tab() continue; } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vNewGameHotkeys.size(); ++i ) { for( const std::string &hotkey : vNewGameHotkeys[i] ) { @@ -866,7 +855,7 @@ bool main_menu::new_character_tab() if( templates.empty() ) { on_error(); } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( errflag && action != "TIMEOUT" ) { clear_error(); sel1 = 1; @@ -1034,7 +1023,7 @@ bool main_menu::load_character_tab( bool transfer ) if( all_worldnames.empty() ) { on_error(); } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( errflag && action != "TIMEOUT" ) { clear_error(); layer = 1; @@ -1071,7 +1060,7 @@ bool main_menu::load_character_tab( bool transfer ) if( savegames.empty() ) { on_error(); } - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( errflag && action != "TIMEOUT" ) { clear_error(); layer = transfer ? 1 : 2; @@ -1220,7 +1209,7 @@ void main_menu::world_tab() const auto all_worldnames = world_generator->all_worldnames(); - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; for( size_t i = 0; i < vWorldSubItems.size(); ++i ) { for( const std::string &hotkey : vWorldHotkeys[i] ) { @@ -1299,7 +1288,7 @@ void main_menu::world_tab() const auto all_worldnames = world_generator->all_worldnames(); - std::string action = handle_input_timeout( ctxt ); + std::string action = ctxt.handle_input(); if( action == "DOWN" ) { if( sel2 > 0 ) { diff --git a/src/main_menu.h b/src/main_menu.h index d15f77ceb2661..03548a2ed490b 100644 --- a/src/main_menu.h +++ b/src/main_menu.h @@ -102,7 +102,6 @@ class main_menu void display_text( const std::string &text, const std::string &title, int &selected ); void init_windows(); - std::string handle_input_timeout( input_context &ctxt ); static std::string halloween_spider(); std::string halloween_graves(); From 42a5ff257e8a51054906670a026394124a3ea85e Mon Sep 17 00:00:00 2001 From: Qrox Date: Sat, 22 Feb 2020 22:18:07 +0800 Subject: [PATCH 158/219] Do not change ime status when navigating main menu --- src/main_menu.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 6988f1f5f7cc1..647fe26bd39c4 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -513,16 +513,22 @@ bool main_menu::opening_screen() ui.position_from_window( w_open ); while( !start ) { - // disable ime at program start - // somehow this need to be here to actually work - disable_ime(); - ui_manager::redraw(); if( layer == 1 ) { std::string action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; + + // switch off ime at program start + if( ctxt.get_raw_input().sequence.empty() ) { + // FIXME: disable_ime only seems to work after receiving an input event + // with empty input sequence. (empty input event is also fired when the + // window loses focus, might be related?) + disable_ime(); + continue; + } + // check automatic menu shortcuts for( size_t i = 0; i < vMenuHotkeys.size(); ++i ) { for( const std::string &hotkey : vMenuHotkeys[i] ) { From dcce9261a2c7b30a5b23594c2d305979bbbdec70 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 11:24:20 +0800 Subject: [PATCH 159/219] Remove reinitialize_framebuffer now that we refresh main menu properly using ui_manager --- src/sdltiles.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index 7b9063aa56e6b..c526a81b9bf39 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -3215,9 +3215,6 @@ static void CheckMessages() // on focus gain. This seems to mess up the first redraw and // causes black screen that lasts ~0.5 seconds before the screen // contents are redrawn in the following code. - - // Main menu redraw - reinitialize_framebuffer(); window_dimensions dim = get_window_dimensions( catacurses::stdscr ); ui_manager::invalidate( rectangle( point_zero, dim.window_size_pixel ) ); ui_manager::redraw(); From 798a11f63d23fea7619cbf7743f0b85051b104f8 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 14:16:08 +0800 Subject: [PATCH 160/219] Use ui_adaptor in options menu --- src/options.cpp | 120 +++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/src/options.cpp b/src/options.cpp index 6d7b3504b99bc..413a567bbdbd3 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -22,6 +22,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "worldfactory.h" #include "color.h" @@ -2438,7 +2439,9 @@ static void draw_borders_external( mvwputch( w, point( 0, horizontal_level ), BORDER_COLOR, LINE_XXXO ); // |- mvwputch( w, point( getmaxx( w ) - 1, horizontal_level ), BORDER_COLOR, LINE_XOXX ); // -| for( auto &mapLine : mapLines ) { - mvwputch( w, point( mapLine.first + 1, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_XXOX ); // _|_ + if( mapLine.second ) { + mvwputch( w, point( mapLine.first + 1, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_XXOX ); // _|_ + } } wrefresh( w ); } @@ -2475,37 +2478,11 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) ingame = false; } - const int iWorldOffset = world_options_only ? 2 : 0; - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - const int iTooltipHeight = 4; - const int iContentHeight = TERMY - 3 - iTooltipHeight - iWorldOffset; - std::map mapLines; - std::map mapLinesOriginal; mapLines[4] = true; mapLines[60] = true; - catacurses::window w_options_border = catacurses::newwin( TERMY, iMinScreenWidth, - point( iOffsetX, 0 ) ); - catacurses::window w_options_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 + iWorldOffset ) ); - catacurses::window w_options_header = catacurses::newwin( 1, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 + iTooltipHeight + iWorldOffset ) ); - catacurses::window w_options = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, iTooltipHeight + 2 + iWorldOffset ) ); - - if( world_options_only ) { - worldfactory::draw_worldgen_tabs( w_options_border, 1 ); - } - - mapLinesOriginal = mapLines; - draw_borders_external( w_options_border, iTooltipHeight + 1 + iWorldOffset, mapLines, - world_options_only ); - draw_borders_internal( w_options_header, mapLines ); - int iCurrentPage = world_options_only ? iWorldOptPage : 0; - int iLastPage = 0; int iCurrentLine = 0; int iStartPos = 0; @@ -2517,7 +2494,63 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) ctxt.register_action( "CONFIRM" ); ctxt.register_action( "HELP_KEYBINDINGS" ); - while( true ) { + const int iWorldOffset = world_options_only ? 2 : 0; + int iMinScreenWidth = 0; + const int iTooltipHeight = 4; + int iContentHeight = 0; + + catacurses::window w_options_border; + catacurses::window w_options_tooltip; + catacurses::window w_options_header; + catacurses::window w_options; + + const auto init_windows = [&]( ui_adaptor & ui ) { + if( OPTIONS.find( "TERMINAL_X" ) != OPTIONS.end() ) { + if( OPTIONS_OLD.find( "TERMINAL_X" ) != OPTIONS_OLD.end() ) { + OPTIONS_OLD["TERMINAL_X"] = OPTIONS["TERMINAL_X"]; + } + if( WOPTIONS_OLD.find( "TERMINAL_X" ) != WOPTIONS_OLD.end() ) { + WOPTIONS_OLD["TERMINAL_X"] = OPTIONS["TERMINAL_X"]; + } + } + if( OPTIONS.find( "TERMINAL_Y" ) != OPTIONS.end() ) { + if( OPTIONS_OLD.find( "TERMINAL_Y" ) != OPTIONS_OLD.end() ) { + OPTIONS_OLD["TERMINAL_Y"] = OPTIONS["TERMINAL_Y"]; + } + if( WOPTIONS_OLD.find( "TERMINAL_Y" ) != WOPTIONS_OLD.end() ) { + WOPTIONS_OLD["TERMINAL_Y"] = OPTIONS["TERMINAL_Y"]; + } + } + + + iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + iContentHeight = TERMY - 3 - iTooltipHeight - iWorldOffset; + + w_options_border = catacurses::newwin( TERMY, iMinScreenWidth, + point( iOffsetX, 0 ) ); + w_options_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 + iWorldOffset ) ); + w_options_header = catacurses::newwin( 1, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 + iTooltipHeight + iWorldOffset ) ); + w_options = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, iTooltipHeight + 2 + iWorldOffset ) ); + + ui.position_from_window( w_options_border ); + }; + + ui_adaptor ui; + ui.on_screen_resize( init_windows ); + init_windows( ui ); + ui.on_redraw( [&]( const ui_adaptor & ) { + if( world_options_only ) { + worldfactory::draw_worldgen_tabs( w_options_border, 1 ); + } + + draw_borders_external( w_options_border, iTooltipHeight + 1 + iWorldOffset, mapLines, + world_options_only ); + draw_borders_internal( w_options_header, mapLines ); + Page &page = pages_[iCurrentPage]; auto &page_items = page.items_; @@ -2656,22 +2689,31 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) current_opt.getDefaultText() ); } - if( iCurrentPage != iLastPage ) { - iLastPage = iCurrentPage; - if( ingame && iCurrentPage == iWorldOptPage ) { - mvwprintz( w_options_tooltip, point( 3, 3 ), c_light_red, "%s", _( "Note: " ) ); - wprintz( w_options_tooltip, c_white, "%s", - _( "Some of these options may produce unexpected results if changed." ) ); - } + if( ingame && iCurrentPage == iWorldOptPage ) { + mvwprintz( w_options_tooltip, point( 3, 3 ), c_light_red, "%s", _( "Note: " ) ); + wprintz( w_options_tooltip, c_white, "%s", + _( "Some of these options may produce unexpected results if changed." ) ); } wrefresh( w_options_tooltip ); wrefresh( w_options ); + } ); + + while( true ) { + ui_manager::redraw(); + + Page &page = pages_[iCurrentPage]; + auto &page_items = page.items_; + + auto &cOPTIONS = ( ingame || world_options_only ) && iCurrentPage == iWorldOptPage ? + ACTIVE_WORLD_OPTIONS : OPTIONS; + + const std::string &opt_name = *page_items[iCurrentLine]; + cOpt ¤t_opt = cOPTIONS[opt_name]; const std::string action = ctxt.handle_input(); if( world_options_only && ( action == "NEXT_TAB" || action == "PREV_TAB" || action == "QUIT" ) ) { - catacurses::refresh(); return action; } @@ -2754,9 +2796,6 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) } } } - } else if( action == "HELP_KEYBINDINGS" ) { - draw_borders_external( w_options_border, iTooltipHeight + 1 + iWorldOffset, mapLinesOriginal, - world_options_only ); } else if( action == "QUIT" ) { break; } @@ -2823,9 +2862,6 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) } } - catacurses::clear(); - catacurses::refresh(); - if( lang_changed ) { update_global_locale(); set_language(); From 71ce812a24f83a64d3a7881ffea7c3f3d540641c Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 17:39:23 +0800 Subject: [PATCH 161/219] use ui_adaptor in worldfactory::pick_world --- src/worldfactory.cpp | 123 ++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 54 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 84d4cc4db38c8..3f5987788e4b5 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -28,6 +28,7 @@ #include "path_info.h" #include "string_formatter.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "game.h" #include "string_id.h" @@ -373,62 +374,75 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) } const int iTooltipHeight = 3; - const int iContentHeight = TERMY - 3 - iTooltipHeight; - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - const size_t num_pages = world_names.size() / iContentHeight + 1; // at least 1 page + int iContentHeight = 0; + int iMinScreenWidth = 0; + size_t num_pages = 1; std::map mapLines; mapLines[3] = true; std::map > world_pages; - size_t worldnum = 0; - for( size_t i = 0; i < num_pages; ++i ) { - for( int j = 0; j < iContentHeight && worldnum < world_names.size(); ++j ) { - world_pages[i].push_back( world_names[ worldnum++ ] ); - } - } size_t sel = 0, selpage = 0; - catacurses::window w_worlds_border = catacurses::newwin( TERMY, iMinScreenWidth, - point( iOffsetX, 0 ) ); - catacurses::window w_worlds_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 ) ); - catacurses::window w_worlds_header = catacurses::newwin( 1, iMinScreenWidth - 2, - point( 1 + iOffsetX, 1 + iTooltipHeight ) ); - catacurses::window w_worlds = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, iTooltipHeight + 2 ) ); - - draw_border( w_worlds_border, BORDER_COLOR, _( " WORLD SELECTION " ) ); - mvwputch( w_worlds_border, point( 0, 4 ), BORDER_COLOR, LINE_XXXO ); // |- - mvwputch( w_worlds_border, point( iMinScreenWidth - 1, 4 ), BORDER_COLOR, LINE_XOXX ); // -| - - for( auto &mapLine : mapLines ) { - mvwputch( w_worlds_border, point( mapLine.first + 1, TERMY - 1 ), BORDER_COLOR, - LINE_XXOX ); // _|_ - } + catacurses::window w_worlds_border; + catacurses::window w_worlds_tooltip; + catacurses::window w_worlds_header; + catacurses::window w_worlds; - wrefresh( w_worlds_border ); + ui_adaptor ui; - for( int i = 0; i < getmaxx( w_worlds_border ); i++ ) { - if( mapLines[i] ) { - mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXXX ); - } else { - mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXOX ); // Draw header line + const auto init_windows = [&]( ui_adaptor & ui ) { + iContentHeight = TERMY - 3 - iTooltipHeight; + iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + num_pages = world_names.size() / iContentHeight + 1; // at least 1 page + + world_pages.clear(); + size_t worldnum = 0; + for( size_t i = 0; i < num_pages; ++i ) { + for( int j = 0; j < iContentHeight && worldnum < world_names.size(); ++j ) { + world_pages[i].push_back( world_names[ worldnum++ ] ); + } } - } - wrefresh( w_worlds_header ); + w_worlds_border = catacurses::newwin( TERMY, iMinScreenWidth, + point( iOffsetX, 0 ) ); + w_worlds_tooltip = catacurses::newwin( iTooltipHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 ) ); + w_worlds_header = catacurses::newwin( 1, iMinScreenWidth - 2, + point( 1 + iOffsetX, 1 + iTooltipHeight ) ); + w_worlds = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, iTooltipHeight + 2 ) ); - input_context ctxt( "PICK_WORLD_DIALOG" ); - ctxt.register_updown(); - ctxt.register_action( "HELP_KEYBINDINGS" ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "NEXT_TAB" ); - ctxt.register_action( "PREV_TAB" ); - ctxt.register_action( "CONFIRM" ); + ui.position_from_window( w_worlds_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_worlds_border, BORDER_COLOR, _( " WORLD SELECTION " ) ); + mvwputch( w_worlds_border, point( 0, 4 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( w_worlds_border, point( iMinScreenWidth - 1, 4 ), BORDER_COLOR, LINE_XOXX ); // -| + + for( auto &mapLine : mapLines ) { + if( mapLine.second ) { + mvwputch( w_worlds_border, point( mapLine.first + 1, TERMY - 1 ), BORDER_COLOR, + LINE_XXOX ); // _|_ + } + } + + wrefresh( w_worlds_border ); + + for( int i = 0; i < getmaxx( w_worlds_border ); i++ ) { + if( mapLines[i] ) { + mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXXX ); + } else { + mvwputch( w_worlds_header, point( i, 0 ), BORDER_COLOR, LINE_OXOX ); // Draw header line + } + } + + wrefresh( w_worlds_header ); - while( true ) { //Clear the lines for( int i = 0; i < iContentHeight; i++ ) { for( int j = 0; j < getmaxx( w_worlds ); j++ ) { @@ -481,12 +495,22 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) wrefresh( w_worlds_tooltip ); wrefresh( w_worlds ); + } ); + + input_context ctxt( "PICK_WORLD_DIALOG" ); + ctxt.register_updown(); + ctxt.register_action( "HELP_KEYBINDINGS" ); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "NEXT_TAB" ); + ctxt.register_action( "PREV_TAB" ); + ctxt.register_action( "CONFIRM" ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "QUIT" ) { - catacurses::clear(); - catacurses::refresh(); break; } else if( !world_pages[selpage].empty() && action == "DOWN" ) { sel++; @@ -520,19 +544,10 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) } } while( world_pages[selpage].empty() ); } else if( action == "CONFIRM" ) { - werase( w_worlds ); - werase( w_worlds_border ); - werase( w_worlds_header ); - werase( w_worlds_tooltip ); return get_world( world_pages[selpage][sel] ); } } - werase( w_worlds ); - werase( w_worlds_border ); - werase( w_worlds_header ); - werase( w_worlds_tooltip ); - return nullptr; } From c2cd048aadd2dae3d6d30d8e4b9765d3af40dd90 Mon Sep 17 00:00:00 2001 From: Qrox Date: Sun, 23 Feb 2020 19:00:52 +0800 Subject: [PATCH 162/219] Use ui_adaptor in worldfactory::make_new_world --- src/worldfactory.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 3f5987788e4b5..d1e400f39a625 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -139,19 +139,32 @@ WORLDPTR worldfactory::make_new_world( bool show_prompt, const std::string &worl retworld->COPY_WORLD( world_generator->get_world( world_to_copy ) ); } - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - if( show_prompt ) { // set up window - catacurses::window wf_win = catacurses::newwin( TERMY, iMinScreenWidth, point( iOffsetX, 0 ) ); + catacurses::window wf_win; + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + wf_win = catacurses::newwin( TERMY, iMinScreenWidth, point( iOffsetX, 0 ) ); + ui.position_from_window( wf_win ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int curtab = 0; + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_worldgen_tabs( wf_win, static_cast( curtab ) ); + wrefresh( wf_win ); + } ); + int lasttab = 0; // give placement memory to menus, sorta. const size_t numtabs = tabs.size(); while( static_cast( curtab ) < numtabs ) { + ui_manager::redraw(); lasttab = curtab; - draw_worldgen_tabs( wf_win, static_cast( curtab ) ); curtab += tabs[curtab]( wf_win, retworld.get() ); // If it is -1, or for unsigned size_t, it would be max. @@ -162,8 +175,6 @@ WORLDPTR worldfactory::make_new_world( bool show_prompt, const std::string &worl } } if( curtab < 0 ) { - catacurses::clear(); - catacurses::refresh(); return nullptr; } } From f607ec2329bc0d234191bffab1df0da74f84408d Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 10:18:00 +0800 Subject: [PATCH 163/219] Use ui_adaptor in world_factory::show_worldgen_tab_modselection --- src/worldfactory.cpp | 219 ++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 127 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index d1e400f39a625..86ec42963e186 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -825,33 +825,47 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, ctxt.register_action( "SAVE_DEFAULT_MODS" ); ctxt.register_action( "VIEW_MOD_DESCRIPTION" ); - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + catacurses::window w_header1; + catacurses::window w_header2; + catacurses::window w_shift; + catacurses::window w_list; + catacurses::window w_active; + catacurses::window w_description; + std::vector header_windows; + + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + + w_header1 = catacurses::newwin( 1, iMinScreenWidth / 2 - 5, + point( 1 + iOffsetX, 3 ) ); + w_header2 = catacurses::newwin( 1, iMinScreenWidth / 2 - 4, + point( iMinScreenWidth / 2 + 3 + iOffsetX, 3 ) ); + w_shift = catacurses::newwin( TERMY - 11, 5, + point( iMinScreenWidth / 2 - 3 + iOffsetX, 3 ) ); + w_list = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, + point( iOffsetX, 5 ) ); + w_active = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, + point( iMinScreenWidth / 2 + 2 + iOffsetX, 5 ) ); + w_description = catacurses::newwin( 4, iMinScreenWidth - 4, + point( 1 + iOffsetX, TERMY - 5 ) ); + + header_windows.clear(); + header_windows.push_back( w_header1 ); + header_windows.push_back( w_header2 ); + + ui.position_from_window( win ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); - // lots of small windows so that each section can be drawn to independently of the others as necessary - catacurses::window w_header1 = catacurses::newwin( 1, iMinScreenWidth / 2 - 5, - point( 1 + iOffsetX, 3 ) ); - catacurses::window w_header2 = catacurses::newwin( 1, iMinScreenWidth / 2 - 4, - point( iMinScreenWidth / 2 + 3 + iOffsetX, 3 ) ); - catacurses::window w_shift = catacurses::newwin( TERMY - 11, 5, - point( iMinScreenWidth / 2 - 3 + iOffsetX, 3 ) ); - catacurses::window w_list = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, - point( iOffsetX, 5 ) ); - catacurses::window w_active = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, - point( iMinScreenWidth / 2 + 2 + iOffsetX, 5 ) ); - catacurses::window w_description = catacurses::newwin( 4, iMinScreenWidth - 4, - point( 1 + iOffsetX, TERMY - 5 ) ); - - draw_modselection_borders( win, ctxt ); std::vector headers; headers.push_back( _( "Mod List" ) ); headers.push_back( _( "Mod Load Order" ) ); - std::vector header_windows; - header_windows.push_back( w_header1 ); - header_windows.push_back( w_header2 ); int tab_output = 0; - size_t last_active_header = 0; size_t active_header = 0; size_t useable_mod_count = mman->get_usable_mods().size(); int startsel[2] = {0, 0}; @@ -859,11 +873,6 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, size_t iCurrentTab = 0; std::vector current_tab_mods; - bool redraw_headers = true; - bool redraw_description = true; - bool redraw_list = true; - bool redraw_active = true; - bool selection_changed = false; bool recalc_tabs = true; // Helper function for determining the currently selected mod @@ -881,35 +890,68 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, return nullptr; }; - // Helper function to trigger full redraw on mod selection screen - const auto redraw_all = [&]() { - redraw_headers = true; - redraw_list = true; - redraw_active = true; - redraw_description = true; + ui.on_redraw( [&]( const ui_adaptor & ) { draw_worldgen_tabs( win, 0 ); draw_modselection_borders( win, ctxt ); - }; - while( tab_output == 0 ) { - if( redraw_headers ) { - for( size_t i = 0; i < headers.size(); ++i ) { - werase( header_windows[i] ); - const int header_x = ( getmaxx( header_windows[i] ) - utf8_width( headers[i] ) ) / 2; - mvwprintz( header_windows[i], point( header_x, 0 ), c_cyan, headers[i] ); - - if( active_header == i ) { - mvwputch( header_windows[i], point( header_x - 3, 0 ), c_red, '<' ); - mvwputch( header_windows[i], point( header_x + utf8_width( headers[i] ) + 2, 0 ), - c_red, '>' ); - } - wrefresh( header_windows[i] ); + // Redraw headers + for( size_t i = 0; i < headers.size(); ++i ) { + werase( header_windows[i] ); + const int header_x = ( getmaxx( header_windows[i] ) - utf8_width( headers[i] ) ) / 2; + mvwprintz( header_windows[i], point( header_x, 0 ), c_cyan, headers[i] ); + + if( active_header == i ) { + mvwputch( header_windows[i], point( header_x - 3, 0 ), c_red, '<' ); + mvwputch( header_windows[i], point( header_x + utf8_width( headers[i] ) + 2, 0 ), + c_red, '>' ); + } + wrefresh( header_windows[i] ); + } + + // Redraw description + werase( w_description ); + + if( const MOD_INFORMATION *selmod = get_selected_mod() ) { + // NOLINTNEXTLINE(cata-use-named-point-constants) + int num_lines = fold_and_print( w_description, point( 1, 0 ), + getmaxx( w_description ) - 1, + c_white, mman_ui->get_information( selmod ) ); + auto window_height = catacurses::getmaxy( w_description ); + auto window_width = catacurses::getmaxx( w_description ); + if( num_lines > window_height ) { + // The description didn't fit in the window, so provide a + // hint for how to see the whole thing + std::string message = string_format( _( "…%s = View full description " ), + ctxt.get_desc( "VIEW_MOD_DESCRIPTION" ) ); + nc_color color = c_green; + print_colored_text( w_description, point( window_width - utf8_width( message ), window_height - 1 ), + color, color, message ); } - redraw_list = true; - redraw_active = true; - redraw_headers = false; } + //redraw tabs + wmove( win, point( 2, 4 ) ); + for( size_t i = 0; i < get_mod_list_tabs().size(); i++ ) { + wprintz( win, c_white, "[" ); + wprintz( win, ( iCurrentTab == i ) ? hilite( c_light_green ) : c_light_green, + _( get_mod_list_tabs()[i].second ) ); + wprintz( win, c_white, "]" ); + wputch( win, BORDER_COLOR, LINE_OXOX ); + } + + wrefresh( w_description ); + wrefresh( win ); + + // Redraw list + draw_mod_list( w_list, startsel[0], cursel[0], current_tab_mods, active_header == 0, + _( "--NO AVAILABLE MODS--" ), catacurses::window() ); + + // Redraw active + draw_mod_list( w_active, startsel[1], cursel[1], active_mod_order, active_header == 1, + _( "--NO ACTIVE MODS--" ), w_shift ); + } ); + + while( tab_output == 0 ) { if( recalc_tabs ) { current_tab_mods.clear(); @@ -932,64 +974,8 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, recalc_tabs = false; } - if( selection_changed ) { - if( active_header == 0 ) { - redraw_list = true; - } - if( active_header == 1 ) { - redraw_active = true; - } - selection_changed = false; - redraw_description = true; - } - - if( redraw_description ) { - werase( w_description ); - - if( const MOD_INFORMATION *selmod = get_selected_mod() ) { - // NOLINTNEXTLINE(cata-use-named-point-constants) - int num_lines = fold_and_print( w_description, point( 1, 0 ), - getmaxx( w_description ) - 1, - c_white, mman_ui->get_information( selmod ) ); - auto window_height = catacurses::getmaxy( w_description ); - auto window_width = catacurses::getmaxx( w_description ); - if( num_lines > window_height ) { - // The description didn't fit in the window, so provide a - // hint for how to see the whole thing - std::string message = string_format( _( "…%s = View full description " ), - ctxt.get_desc( "VIEW_MOD_DESCRIPTION" ) ); - nc_color color = c_green; - print_colored_text( w_description, point( window_width - utf8_width( message ), window_height - 1 ), - color, color, message ); - } - } - - //redraw tabs - wmove( win, point( 2, 4 ) ); - for( size_t i = 0; i < get_mod_list_tabs().size(); i++ ) { - wprintz( win, c_white, "[" ); - wprintz( win, ( iCurrentTab == i ) ? hilite( c_light_green ) : c_light_green, - _( get_mod_list_tabs()[i].second ) ); - wprintz( win, c_white, "]" ); - wputch( win, BORDER_COLOR, LINE_OXOX ); - } - - redraw_description = false; - wrefresh( w_description ); - wrefresh( win ); - } - - if( redraw_list ) { - draw_mod_list( w_list, startsel[0], cursel[0], current_tab_mods, active_header == 0, - _( "--NO AVAILABLE MODS--" ), catacurses::window() ); - } - if( redraw_active ) { - draw_mod_list( w_active, startsel[1], cursel[1], active_mod_order, active_header == 1, - _( "--NO ACTIVE MODS--" ), w_shift ); - } - catacurses::refresh(); + ui_manager::redraw(); - last_active_header = active_header; const int next_header = ( active_header == 1 ) ? 0 : 1; const int prev_header = ( active_header == 0 ) ? 1 : 0; @@ -1020,12 +1006,9 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, if( active_header == 0 && !current_tab_mods.empty() ) { // try-add mman_ui->try_add( current_tab_mods[cursel[0]], active_mod_order ); - redraw_active = true; } else if( active_header == 1 && !active_mod_order.empty() ) { // try-rem mman_ui->try_rem( cursel[1], active_mod_order ); - redraw_active = true; - redraw_description = true; if( active_mod_order.empty() ) { // switch back to other list, we can't change // anything in the empty active mods list. @@ -1035,13 +1018,10 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, } else if( action == "ADD_MOD" ) { if( active_header == 1 && active_mod_order.size() > 1 ) { mman_ui->try_shift( '+', cursel[1], active_mod_order ); - redraw_active = true; } } else if( action == "REMOVE_MOD" ) { if( active_header == 1 && active_mod_order.size() > 1 ) { mman_ui->try_shift( '-', cursel[1], active_mod_order ); - redraw_active = true; - redraw_description = true; } } else if( action == "NEXT_CATEGORY_TAB" ) { if( active_header == 0 ) { @@ -1053,7 +1033,6 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, cursel[0] = 0; recalc_tabs = true; - redraw_description = true; } } else if( action == "PREV_CATEGORY_TAB" ) { @@ -1066,7 +1045,6 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, cursel[0] = 0; recalc_tabs = true; - redraw_description = true; } } else if( action == "NEXT_TAB" ) { tab_output = 1; @@ -1076,36 +1054,23 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, if( mman->set_default_mods( active_mod_order ) ) { popup( _( "Saved list of active mods as default" ) ); draw_modselection_borders( win, ctxt ); - redraw_description = true; - redraw_headers = true; } } else if( action == "VIEW_MOD_DESCRIPTION" ) { if( const MOD_INFORMATION *selmod = get_selected_mod() ) { popup( "%s", mman_ui->get_information( selmod ) ); - redraw_all(); } - } else if( action == "HELP_KEYBINDINGS" ) { - redraw_all(); } else if( action == "QUIT" ) { tab_output = -999; } // RESOLVE INPUTS - if( last_active_header != active_header ) { - redraw_headers = true; - redraw_description = true; - } if( last_selection != selection ) { if( active_header == 0 ) { - redraw_list = true; cursel[0] = selection; } else { - redraw_active = true; cursel[1] = selection; } - redraw_description = true; } if( active_mod_order.empty() ) { - redraw_active = true; cursel[1] = 0; } From a5068061ea1f54d91e971cee090eeaedb95750c3 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 10:48:55 +0800 Subject: [PATCH 164/219] Remove manual refresh in worldfactory::show_worldgen_tab_options --- src/worldfactory.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 86ec42963e186..973b34a64b77c 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -605,7 +605,7 @@ std::string worldfactory::pick_random_name() return get_next_valid_worldname(); } -int worldfactory::show_worldgen_tab_options( const catacurses::window &win, WORLDPTR world ) +int worldfactory::show_worldgen_tab_options( const catacurses::window &, WORLDPTR world ) { get_options().set_world_options( &world->WORLD_OPTIONS ); const std::string action = get_options().show( false, true ); @@ -616,10 +616,6 @@ int worldfactory::show_worldgen_tab_options( const catacurses::window &win, WORL } else if( action == "NEXT_TAB" ) { return 1; - } else if( action == "HELP_KEYBINDINGS" ) { - draw_worldgen_tabs( win, 1 ); - catacurses::refresh(); - } else if( action == "QUIT" ) { return -999; } From 15baf5070a884f5b4c8fad11482e9c85e40b681e Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 12:11:30 +0800 Subject: [PATCH 165/219] Use ui_adaptor in worldfactory::show_worldgen_tab_confirm --- src/worldfactory.cpp | 69 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 973b34a64b77c..6846a016197f5 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -1091,15 +1091,23 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORLDPTR world ) { - const int iTooltipHeight = 1; - const int iContentHeight = TERMY - 3 - iTooltipHeight; - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + catacurses::window w_confirmation; + + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iTooltipHeight = 1; + const int iContentHeight = TERMY - 3 - iTooltipHeight; + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - const char *line_of_32_underscores = "________________________________"; + w_confirmation = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, + point( 1 + iOffsetX, iTooltipHeight + 2 ) ); - catacurses::window w_confirmation = catacurses::newwin( iContentHeight, iMinScreenWidth - 2, - point( 1 + iOffsetX, iTooltipHeight + 2 ) ); + ui.position_from_window( win ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int namebar_y = 1; int namebar_x = 3 + utf8_width( _( "World Name:" ) ); @@ -1117,9 +1125,11 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL // do not switch IME mode now, but restore previous mode on return ime_sentry sentry( ime_sentry::keep ); - do { + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_worldgen_tabs( win, 2 ); + mvwprintz( w_confirmation, point( 2, namebar_y ), c_white, _( "World Name:" ) ); - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); fold_and_print( w_confirmation, point( 2, 3 ), getmaxx( w_confirmation ) - 2, c_light_gray, _( "Press %s to pick a random name for your world." ), ctxt.get_desc( "PICK_RANDOM_WORLDNAME" ) ); @@ -1128,64 +1138,56 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL _( "Press %s when you are satisfied with the world as it is and are ready " "to continue, or %s to go back and review your world." ), ctxt.get_desc( "NEXT_TAB" ), ctxt.get_desc( "PREV_TAB" ) ); - if( !noname ) { + if( noname ) { + mvwprintz( w_confirmation, point( namebar_x, namebar_y ), h_light_gray, + _( "________NO NAME ENTERED!________" ) ); + } else { mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, worldname ); wprintz( w_confirmation, h_light_gray, "_" ); - } - if( noname ) { - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); - noname = false; + for( int underscores = 31 - utf8_width( worldname ); + underscores > 0; --underscores ) { + wprintz( w_confirmation, c_light_gray, "_" ); + } } wrefresh( win ); wrefresh( w_confirmation ); - catacurses::refresh(); + } ); + + do { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "NEXT_TAB" ) { if( worldname.empty() ) { - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), h_light_gray, - _( "________NO NAME ENTERED!________" ) ); noname = true; - wrefresh( w_confirmation ); + ui_manager::redraw(); if( !query_yn( _( "Are you SURE you're finished? World name will be randomly generated." ) ) ) { - werase( w_confirmation ); + noname = false; continue; } else { + noname = false; world->world_name = pick_random_name(); if( !valid_worldname( world->world_name ) ) { continue; } - catacurses::clear(); - catacurses::refresh(); return 1; } } else if( query_yn( _( "Are you SURE you're finished?" ) ) ) { - // erase entire window to avoid overlapping of query with possible popup about invalid worldname - werase( w_confirmation ); - wrefresh( w_confirmation ); - catacurses::clear(); - catacurses::refresh(); - if( valid_worldname( worldname ) ) { world->world_name = worldname; - catacurses::refresh(); return 1; } else { continue; } } else { - werase( w_confirmation ); continue; } } else if( action == "PREV_TAB" ) { world->world_name = worldname; return -1; } else if( action == "PICK_RANDOM_WORLDNAME" ) { - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); world->world_name = worldname = pick_random_name(); - } else if( action == "HELP_KEYBINDINGS" ) { - draw_worldgen_tabs( win, 2 ); } else if( action == "QUIT" ) { // Cache the current name just in case they say No to the exit query. world->world_name = worldname; @@ -1211,9 +1213,6 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL wrap.append( newtext ); worldname = wrap.str(); } - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, line_of_32_underscores ); - mvwprintz( w_confirmation, point( namebar_x, namebar_y ), c_light_gray, worldname ); - wprintz( w_confirmation, h_light_gray, "_" ); } } while( true ); From fa4c9e728447b08209686f2632bea81dd19790d0 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 12:38:57 +0800 Subject: [PATCH 166/219] Use ui_adaptor in worldfactory::show_active_world_mods --- src/worldfactory.cpp | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 6846a016197f5..2e8ecbbd725c2 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -742,30 +742,46 @@ void worldfactory::draw_mod_list( const catacurses::window &w, int &start, size_ void worldfactory::show_active_world_mods( const std::vector &world_mods ) { - const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; + ui_adaptor ui; + catacurses::window w_border; + catacurses::window w_mods; + + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iMinScreenWidth = std::max( FULL_SCREEN_WIDTH, TERMX / 2 ); + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - iMinScreenWidth ) / 2 : 0; - catacurses::window w_border = catacurses::newwin( TERMY - 11, iMinScreenWidth / 2 - 3, - point( iOffsetX, 4 ) ); - catacurses::window w_mods = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, - point( iOffsetX, 5 ) ); + w_border = catacurses::newwin( TERMY - 11, iMinScreenWidth / 2 - 3, + point( iOffsetX, 4 ) ); + w_mods = catacurses::newwin( TERMY - 13, iMinScreenWidth / 2 - 4, + point( iOffsetX, 5 ) ); + + ui.position_from_window( w_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int start = 0; int cursor = 0; const size_t num_mods = world_mods.size(); - draw_border( w_border, BORDER_COLOR, _( " ACTIVE WORLD MODS " ) ); - wrefresh( w_border ); + input_context ctxt( "DEFAULT" ); + ctxt.register_updown(); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "CONFIRM" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_border, BORDER_COLOR, _( " ACTIVE WORLD MODS " ) ); + wrefresh( w_border ); - while( true ) { draw_mod_list( w_mods, start, static_cast( cursor ), world_mods, true, _( "--NO ACTIVE MODS--" ), catacurses::window() ); wrefresh( w_mods ); + } ); + + while( true ) { + ui_manager::redraw(); - input_context ctxt( "DEFAULT" ); - ctxt.register_updown(); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "CONFIRM" ); const std::string action = ctxt.handle_input(); if( action == "UP" ) { @@ -783,8 +799,6 @@ void worldfactory::show_active_world_mods( const std::vector &world_mods } } else if( action == "QUIT" || action == "CONFIRM" ) { - catacurses::clear(); - catacurses::refresh(); break; } } From d81014046c1fd0978d5b7aa263c6e95a833ce5ea Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 13:53:18 +0800 Subject: [PATCH 167/219] Use ui_adaptor in auto pickup menu --- src/auto_pickup.cpp | 181 ++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 80 deletions(-) diff --git a/src/auto_pickup.cpp b/src/auto_pickup.cpp index 6a37e4b1e77c2..d9553a3529abc 100644 --- a/src/auto_pickup.cpp +++ b/src/auto_pickup.cpp @@ -23,6 +23,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "cursesdef.h" #include "item.h" @@ -45,29 +46,38 @@ void user_interface::show() } const int iHeaderHeight = 4; - const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; + int iContentHeight = 0; + const int iTotalCols = 2; - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; - const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + catacurses::window w_border; + catacurses::window w_header; + catacurses::window w; - const int iTotalCols = 2; + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + + w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, + point( iOffsetX, iOffsetY ) ); + w_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, 1 + iOffsetY ) ); + w = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); + + ui.position_from_window( w_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); + + size_t iTab = 0; + int iLine = 0; + int iColumn = 1; + int iStartPos = 0; - catacurses::window w_help = catacurses::newwin( FULL_SCREEN_HEIGHT / 2 + 2, - FULL_SCREEN_WIDTH * 3 / 4, - point( iOffsetX + 19 / 2, 7 + iOffsetY + FULL_SCREEN_HEIGHT / 2 / 2 ) ); - - catacurses::window w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, - point( iOffsetX, iOffsetY ) ); - catacurses::window w_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, 1 + iOffsetY ) ); - catacurses::window w = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); - - /** - * All of the stuff in this lambda needs to be drawn (1) initially, and - * (2) after closing the HELP_KEYBINDINGS window (since it mangles the screen) - */ - const auto initial_draw = [&]() { + ui.on_redraw( [&]( const ui_adaptor & ) { // Redraw the border draw_border( w_border, BORDER_COLOR, title ); // |- @@ -110,43 +120,7 @@ void user_interface::show() mvwprintz( w_header, point( 1, 3 ), c_white, "#" ); mvwprintz( w_header, point( 8, 3 ), c_white, _( "Rules" ) ); mvwprintz( w_header, point( 52, 3 ), c_white, _( "I/E" ) ); - wrefresh( w_header ); - }; - - initial_draw(); - size_t iTab = 0; - int iLine = 0; - int iColumn = 1; - int iStartPos = 0; - bStuffChanged = false; - input_context ctxt( "AUTO_PICKUP" ); - ctxt.register_cardinal(); - ctxt.register_action( "CONFIRM" ); - ctxt.register_action( "QUIT" ); - if( tabs.size() > 1 ) { - ctxt.register_action( "NEXT_TAB" ); - ctxt.register_action( "PREV_TAB" ); - } - ctxt.register_action( "ADD_RULE" ); - ctxt.register_action( "REMOVE_RULE" ); - ctxt.register_action( "COPY_RULE" ); - ctxt.register_action( "ENABLE_RULE" ); - ctxt.register_action( "DISABLE_RULE" ); - ctxt.register_action( "MOVE_RULE_UP" ); - ctxt.register_action( "MOVE_RULE_DOWN" ); - ctxt.register_action( "TEST_RULE" ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - - const bool allow_swapping = tabs.size() == 2; - if( allow_swapping ) { - ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); - } - if( is_autopickup ) { - ctxt.register_action( "SWITCH_AUTO_PICKUP_OPTION" ); - } - - while( true ) { rule_list &cur_rules = tabs[iTab].new_rules; int locx = 17; for( size_t i = 0; i < tabs.size(); i++ ) { @@ -176,8 +150,6 @@ void user_interface::show() } } - const bool currentPageNonEmpty = !cur_rules.empty(); - draw_scrollbar( w_border, iLine, iContentHeight, cur_rules.size(), point( 0, 5 ) ); wrefresh( w_border ); @@ -209,6 +181,42 @@ void user_interface::show() } wrefresh( w ); + } ); + + bStuffChanged = false; + input_context ctxt( "AUTO_PICKUP" ); + ctxt.register_cardinal(); + ctxt.register_action( "CONFIRM" ); + ctxt.register_action( "QUIT" ); + if( tabs.size() > 1 ) { + ctxt.register_action( "NEXT_TAB" ); + ctxt.register_action( "PREV_TAB" ); + } + ctxt.register_action( "ADD_RULE" ); + ctxt.register_action( "REMOVE_RULE" ); + ctxt.register_action( "COPY_RULE" ); + ctxt.register_action( "ENABLE_RULE" ); + ctxt.register_action( "DISABLE_RULE" ); + ctxt.register_action( "MOVE_RULE_UP" ); + ctxt.register_action( "MOVE_RULE_DOWN" ); + ctxt.register_action( "TEST_RULE" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + const bool allow_swapping = tabs.size() == 2; + if( allow_swapping ) { + ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); + } + + if( is_autopickup ) { + ctxt.register_action( "SWITCH_AUTO_PICKUP_OPTION" ); + } + + while( true ) { + rule_list &cur_rules = tabs[iTab].new_rules; + + const bool currentPageNonEmpty = !cur_rules.empty(); + + ui_manager::redraw(); const std::string action = ctxt.handle_input(); @@ -268,27 +276,43 @@ void user_interface::show() cur_rules.push_back( rule( "", true, false ) ); iLine = cur_rules.size() - 1; } + ui_manager::redraw(); if( iColumn == 1 || action == "ADD_RULE" ) { - // NOLINTNEXTLINE(cata-use-named-point-constants) - fold_and_print( w_help, point( 1, 1 ), 999, c_white, - _( - "* is used as a Wildcard. A few Examples:\n" - "\n" - "wooden arrow matches the itemname exactly\n" - "wooden ar* matches items beginning with wood ar\n" - "*rrow matches items ending with rrow\n" - "*avy fle*fi*arrow multiple * are allowed\n" - "heAVY*woOD*arrOW case insensitive search\n" - "\n" - "Pickup based on item materials:\n" - "m:kevlar matches items made of kevlar\n" - "M:copper matches items made purely of copper\n" - "M:steel,iron multiple materials allowed (OR search)" ) - ); - - draw_border( w_help ); - wrefresh( w_help ); + ui_adaptor help_ui; + catacurses::window w_help; + const auto init_help_window = [&]( ui_adaptor & help_ui ) { + const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + w_help = catacurses::newwin( FULL_SCREEN_HEIGHT / 2 + 2, + FULL_SCREEN_WIDTH * 3 / 4, + point( iOffsetX + 19 / 2, 7 + iOffsetY + FULL_SCREEN_HEIGHT / 2 / 2 ) ); + help_ui.position_from_window( w_help ); + }; + init_help_window( help_ui ); + help_ui.on_screen_resize( init_help_window ); + + help_ui.on_redraw( [&]( const ui_adaptor & ) { + // NOLINTNEXTLINE(cata-use-named-point-constants) + fold_and_print( w_help, point( 1, 1 ), 999, c_white, + _( + "* is used as a Wildcard. A few Examples:\n" + "\n" + "wooden arrow matches the itemname exactly\n" + "wooden ar* matches items beginning with wood ar\n" + "*rrow matches items ending with rrow\n" + "*avy fle*fi*arrow multiple * are allowed\n" + "heAVY*woOD*arrOW case insensitive search\n" + "\n" + "Pickup based on item materials:\n" + "m:kevlar matches items made of kevlar\n" + "M:copper matches items made purely of copper\n" + "M:steel,iron multiple materials allowed (OR search)" ) + ); + + draw_border( w_help ); + wrefresh( w_help ); + } ); const std::string r = string_input_popup() .title( _( "Pickup Rule:" ) ) .width( 30 ) @@ -344,9 +368,6 @@ void user_interface::show() // TODO: Now that NPCs use this function, it could be used for them too get_options().get_option( "AUTO_PICKUP" ).setNext(); get_options().save(); - } else if( action == "HELP_KEYBINDINGS" ) { - // de-mangle parts of the screen - initial_draw(); } } From be43ba3b5f1050677a17d330dc1c58cf100bb50b Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 20:29:47 +0800 Subject: [PATCH 168/219] Use ui_adaptor in string_input_popup --- src/string_input_popup.cpp | 87 +++++++++++++++++++++----------------- src/string_input_popup.h | 11 +++++ 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/string_input_popup.cpp b/src/string_input_popup.cpp index 21e7109f85bbf..977e1b098093a 100644 --- a/src/string_input_popup.cpp +++ b/src/string_input_popup.cpp @@ -8,9 +8,10 @@ #include "input.h" #include "optional.h" #include "output.h" +#include "translations.h" #include "ui.h" +#include "ui_manager.h" #include "uistate.h" -#include "translations.h" #if defined(__ANDROID__) #include @@ -29,15 +30,15 @@ string_input_popup::~string_input_popup() = default; void string_input_popup::create_window() { - int titlesize = utf8_width( remove_color_tags( _title ) ); // Occupied horizontal space + titlesize = utf8_width( remove_color_tags( _title ) ); // Occupied horizontal space if( _max_length <= 0 ) { _max_length = _width; } // 2 for border (top and bottom) and 1 for the input text line. - int w_height = 2 + 1; + w_height = 2 + 1; // |"w_width = width + titlesize (this text) + 5": _____ | - int w_width = FULL_SCREEN_WIDTH; + w_width = FULL_SCREEN_WIDTH; if( _width <= 0 ) { _width = std::max( 5, FULL_SCREEN_WIDTH - titlesize - 5 ); // Default if unspecified } else { @@ -45,7 +46,7 @@ void string_input_popup::create_window() w_width = _width + titlesize + 5; } - std::vector title_split = { _title }; + title_split = { _title }; if( w_width > FULL_SCREEN_WIDTH ) { // Out of horizontal space- wrap the title titlesize = FULL_SCREEN_WIDTH - _width - 5; @@ -60,7 +61,7 @@ void string_input_popup::create_window() w_height += static_cast( title_split.size() ) - 1; } - std::vector descformatted; + descformatted.clear(); if( !_description.empty() ) { const int twidth = std::min( utf8_width( remove_color_tags( _description ) ), w_width - 4 ); descformatted = foldstring( _description, twidth ); @@ -68,29 +69,19 @@ void string_input_popup::create_window() } // length of title + border (left) + space _startx = titlesize + 2; - // Below the description and below the top border - _starty = 1 + descformatted.size(); if( _max_length <= 0 ) { _max_length = 1024; } _endx = w_width - 3; - _position = -1; const int w_y = ( TERMY - w_height ) / 2; const int w_x = std::max( ( TERMX - w_width ) / 2, 0 ); w = catacurses::newwin( w_height, w_width, point( w_x, w_y ) ); - draw_border( w ); - - for( size_t i = 0; i < descformatted.size(); ++i ) { - trim_and_print( w, point( 1, 1 + i ), w_width - 2, _desc_color, descformatted[i] ); - } - for( int i = 0; i < static_cast( title_split.size() ) - 1; i++ ) { - mvwprintz( w, point( i + 1, _starty++ ), _title_color, title_split[i] ); - } - right_print( w, _starty, w_width - titlesize - 1, _title_color, title_split.back() ); _starty = w_height - 2; // The ____ looks better at the bottom right when the title folds + + custom_window = false; } void string_input_popup::create_context() @@ -209,6 +200,19 @@ void string_input_popup::update_input_history( utf8_wrapper &ret, bool up ) void string_input_popup::draw( const utf8_wrapper &ret, const utf8_wrapper &edit, const int shift ) const { + if( !custom_window ) { + draw_border( w ); + + for( size_t i = 0; i < descformatted.size(); ++i ) { + trim_and_print( w, point( 1, 1 + i ), w_width - 2, _desc_color, descformatted[i] ); + } + int pos_y = descformatted.size() + 1; + for( int i = 0; i < static_cast( title_split.size() ) - 1; i++ ) { + mvwprintz( w, point( i + 1, pos_y++ ), _title_color, title_split[i] ); + } + right_print( w, pos_y, w_width - titlesize - 1, _title_color, title_split.back() ); + } + const int scrmax = _endx - _startx; // remove the scrolled out of view part from the input string const utf8_wrapper ds( ret.substr_display( shift, scrmax ) ); @@ -219,7 +223,7 @@ void string_input_popup::draw( const utf8_wrapper &ret, const utf8_wrapper &edit mvwprintz( w, point( _startx, _starty ), _string_color, "%s", ds.c_str() ); size_t sx = ds.display_width(); // Print the cursor in its own color - if( _position < static_cast( ret.length() ) ) { + if( _position >= 0 && static_cast( _position ) < ret.length() ) { utf8_wrapper cursor = ret.substr( _position, 1 ); size_t a = _position; while( a > 0 && cursor.display_width() == 0 ) { @@ -260,6 +264,8 @@ void string_input_popup::draw( const utf8_wrapper &ret, const utf8_wrapper &edit if( !edit.empty() ) { mvwprintz( w, point( start_x_edit, _starty ), _cursor_color, "%s", edit.c_str() ); } + + wrefresh( w ); } void string_input_popup::query( const bool loop, const bool draw_only ) @@ -279,12 +285,14 @@ int64_t string_input_popup::query_int64_t( const bool loop, const bool draw_only const std::string &string_input_popup::query_string( const bool loop, const bool draw_only ) { - if( !w ) { + if( !custom_window && !w ) { create_window(); + _position = -1; } if( !ctxt ) { create_context(); } + cata::optional sentry; if( !draw_only && loop ) { sentry.emplace(); @@ -297,7 +305,19 @@ const std::string &string_input_popup::query_string( const bool loop, const bool const int scrmax = _endx - _startx; // in output (console) cells, not characters of the string! int shift = 0; - bool redraw = true; + + std::unique_ptr ui; + if( !draw_only && !custom_window ) { + ui = std::make_unique(); + ui->position_from_window( w ); + ui->on_screen_resize( [this]( ui_adaptor & ui ) { + create_window(); + ui.position_from_window( w ); + } ); + ui->on_redraw( [&]( const ui_adaptor & ) { + draw( ret, edit, shift ); + } ); + } int ch = 0; @@ -333,14 +353,12 @@ const std::string &string_input_popup::query_string( const bool loop, const bool shift++; } - if( redraw ) { - redraw = false; + if( ui ) { + ui_manager::redraw(); + } else { draw( ret, edit, shift ); - wrefresh( w ); } - wrefresh( w ); - if( draw_only ) { return _text; } @@ -387,26 +405,21 @@ const std::string &string_input_popup::query_string( const bool loop, const bool } else { update_input_history( ret, true ); } - redraw = true; } else if( ch == KEY_DOWN && !_hist_use_uilist ) { update_input_history( ret, false ); - redraw = true; } else if( ch == KEY_DOWN || ch == KEY_NPAGE || ch == KEY_PPAGE || ch == KEY_BTAB || ch == 9 ) { /* absolutely nothing */ } else if( ch == KEY_RIGHT ) { if( _position + 1 <= static_cast( ret.size() ) ) { _position++; } - redraw = true; } else if( ch == KEY_LEFT ) { if( _position > 0 ) { _position--; } - redraw = true; } else if( ch == 0x15 ) { // ctrl-u: delete all the things _position = 0; ret.erase( 0 ); - redraw = true; // Move the cursor back and re-draw it } else if( ch == KEY_BACKSPACE ) { // but silently drop input if we're at 0, instead of adding '^' @@ -414,18 +427,14 @@ const std::string &string_input_popup::query_string( const bool loop, const bool // TODO: it is safe now since you only input ASCII chars _position--; ret.erase( _position, 1 ); - redraw = true; } } else if( ch == KEY_HOME ) { _position = 0; - redraw = true; } else if( ch == KEY_END ) { _position = ret.size(); - redraw = true; } else if( ch == KEY_DC ) { if( _position < static_cast( ret.size() ) ) { ret.erase( _position, 1 ); - redraw = true; } } else if( ch == KEY_F( 2 ) ) { std::string tmp = get_input_string_from_file(); @@ -443,17 +452,14 @@ const std::string &string_input_popup::query_string( const bool loop, const bool _position += t.length(); edit.erase( 0 ); ctxt->set_edittext( edit.c_str() ); - redraw = true; } else if( ev.edit_refresh ) { const utf8_wrapper t( ev.edit ); edit.erase( 0 ); edit.insert( 0, t ); ctxt->set_edittext( edit.c_str() ); - redraw = true; } else if( ev.edit.empty() ) { edit.erase( 0 ); ctxt->set_edittext( edit.c_str() ); - redraw = true; } } while( loop ); _text = ret.str(); @@ -463,10 +469,15 @@ const std::string &string_input_popup::query_string( const bool loop, const bool string_input_popup &string_input_popup::window( const catacurses::window &w, int startx, int starty, int endx ) { + if( !custom_window && this->w ) { + // default window already created + return *this; + } this->w = w; _startx = startx; _starty = starty; _endx = endx; + custom_window = true; return *this; } diff --git a/src/string_input_popup.h b/src/string_input_popup.h index e1914e34f8215..8ea338b42b9ba 100644 --- a/src/string_input_popup.h +++ b/src/string_input_popup.h @@ -66,6 +66,14 @@ class string_input_popup // NOLINT(cata-xy) //Counts only when @_hist_use_uilist is false const size_t _hist_max_size = 100; + // Cache when using the default window + int w_width = 0; + int w_height = 0; + std::vector descformatted; + std::vector title_split; + int titlesize = 0; + + bool custom_window = false; catacurses::window w; std::unique_ptr ctxt_ptr; @@ -161,6 +169,9 @@ class string_input_popup // NOLINT(cata-xy) * text will be printed at the given part of the given window. * Integer parameters define the area (one line) where the editable * text is printed. + * + * This method only has effect before the default window is initialized. + * After that calls to this method are just ignored. */ string_input_popup &window( const catacurses::window &w, int startx, int starty, int endx ); /** From af02c4569e028fa3560af89de3f49789b0c04add Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 21:24:30 +0800 Subject: [PATCH 169/219] Use ui_adaptor in auto pickup test pattern window --- src/auto_pickup.cpp | 53 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/auto_pickup.cpp b/src/auto_pickup.cpp index d9553a3529abc..1754bd1d4a7b6 100644 --- a/src/auto_pickup.cpp +++ b/src/auto_pickup.cpp @@ -427,36 +427,51 @@ void rule::test_pattern() const vMatchingItems.push_back( sItemName ); } - const int iOffsetX = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); - const int iOffsetY = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : - 0 ); - int iStartPos = 0; - const int iContentHeight = FULL_SCREEN_HEIGHT - 8; - const int iContentWidth = FULL_SCREEN_WIDTH - 30; + int iContentHeight = 0; + int iContentWidth = 0; + + catacurses::window w_test_rule_border; + catacurses::window w_test_rule_content; + + ui_adaptor ui; - const catacurses::window w_test_rule_border = catacurses::newwin( iContentHeight + 2, iContentWidth, - point( iOffsetX, iOffsetY ) ); - const catacurses::window w_test_rule_content = catacurses::newwin( iContentHeight, - iContentWidth - 2, - point( 1 + iOffsetX, 1 + iOffsetY ) ); + const auto init_windows = [&]( ui_adaptor & ui ) { + const int iOffsetX = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); + const int iOffsetY = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : + 0 ); + iContentHeight = FULL_SCREEN_HEIGHT - 8; + iContentWidth = FULL_SCREEN_WIDTH - 30; + + w_test_rule_border = catacurses::newwin( iContentHeight + 2, iContentWidth, + point( iOffsetX, iOffsetY ) ); + w_test_rule_content = catacurses::newwin( iContentHeight, + iContentWidth - 2, + point( 1 + iOffsetX, 1 + iOffsetY ) ); + + ui.position_from_window( w_test_rule_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int nmatch = vMatchingItems.size(); const std::string buf = string_format( ngettext( "%1$d item matches: %2$s", "%1$d items match: %2$s", nmatch ), nmatch, sRule ); - draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); - center_print( w_test_rule_border, iContentHeight + 1, red_background( c_white ), - _( "Won't display content or suffix matches" ) ); - wrefresh( w_test_rule_border ); int iLine = 0; input_context ctxt( "AUTO_PICKUP_TEST" ); ctxt.register_updown(); ctxt.register_action( "QUIT" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); + center_print( w_test_rule_border, iContentHeight + 1, red_background( c_white ), + _( "Won't display content or suffix matches" ) ); + wrefresh( w_test_rule_border ); - while( true ) { // Clear the lines for( int i = 0; i < iContentHeight; i++ ) { for( int j = 0; j < 79; j++ ) { @@ -487,6 +502,10 @@ void rule::test_pattern() const } wrefresh( w_test_rule_content ); + } ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "DOWN" ) { @@ -499,7 +518,7 @@ void rule::test_pattern() const if( iLine < 0 ) { iLine = vMatchingItems.size() - 1; } - } else { + } else if( action == "QUIT" ) { break; } } From 5a72728139d20e3db17cb597b94fcb4cd43c388b Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 22:17:18 +0800 Subject: [PATCH 170/219] Use ui_adaptor in safe mode ui --- src/safemode_ui.cpp | 199 ++++++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 90 deletions(-) diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index 97ec1b858794b..fcbb42c0b3b69 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -23,6 +23,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "ui_manager.h" #include "color.h" #include "compatibility.h" #include "cursesdef.h" @@ -50,10 +51,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) auto character_rules_old = character_rules; const int header_height = 4; - const int content_height = FULL_SCREEN_HEIGHT - 2 - header_height; - - const int offset_x = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; - const int offset_y = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + int content_height = 0; enum Columns : int { COLUMN_RULE, @@ -72,23 +70,57 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) const int num_columns = column_pos.size(); - catacurses::window w_help = - catacurses::newwin( FULL_SCREEN_HEIGHT / 2 - 2, FULL_SCREEN_WIDTH * 3 / 4, - point( offset_x + 19 / 2, 7 + offset_y + FULL_SCREEN_HEIGHT / 2 / 2 ) ); - catacurses::window w_border = - catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, point( offset_x, offset_y ) ); - catacurses::window w_header = - catacurses::newwin( header_height, FULL_SCREEN_WIDTH - 2, - point( 1 + offset_x, 1 + offset_y ) ); - catacurses::window w = - catacurses::newwin( content_height, FULL_SCREEN_WIDTH - 2, - point( 1 + offset_x, header_height + 1 + offset_y ) ); - - /** - * All of the stuff in this lambda needs to be drawn (1) initially, and - * (2) after closing the HELP_KEYBINDINGS window (since it mangles the screen) - */ - const auto initial_draw = [&]() { + catacurses::window w_border; + catacurses::window w_header; + catacurses::window w; + + ui_adaptor ui; + + const auto init_windows = [&]( ui_adaptor & ui ) { + content_height = FULL_SCREEN_HEIGHT - 2 - header_height; + + const int offset_x = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int offset_y = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + + w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, point( offset_x, offset_y ) ); + w_header = catacurses::newwin( header_height, FULL_SCREEN_WIDTH - 2, + point( 1 + offset_x, 1 + offset_y ) ); + w = catacurses::newwin( content_height, FULL_SCREEN_WIDTH - 2, + point( 1 + offset_x, header_height + 1 + offset_y ) ); + + ui.position_from_window( w_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); + + int tab = GLOBAL_TAB; + int line = 0; + int column = 0; + int start_pos = 0; + bool changes_made = false; + input_context ctxt( "SAFEMODE" ); + ctxt.register_cardinal(); + ctxt.register_action( "CONFIRM" ); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "NEXT_TAB" ); + ctxt.register_action( "PREV_TAB" ); + ctxt.register_action( "ADD_DEFAULT_RULESET" ); + ctxt.register_action( "ADD_RULE" ); + ctxt.register_action( "REMOVE_RULE" ); + ctxt.register_action( "COPY_RULE" ); + ctxt.register_action( "ENABLE_RULE" ); + ctxt.register_action( "DISABLE_RULE" ); + ctxt.register_action( "MOVE_RULE_UP" ); + ctxt.register_action( "MOVE_RULE_DOWN" ); + ctxt.register_action( "TEST_RULE" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + if( is_safemode_in ) { + ctxt.register_action( "SWITCH_SAFEMODE_OPTION" ); + ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); + } + + ui.on_redraw( [&]( const ui_adaptor & ) { draw_border( w_border, BORDER_COLOR, custom_name_in ); mvwputch( w_border, point( 0, 3 ), c_light_gray, LINE_XXXO ); // |- @@ -138,39 +170,6 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) mvwprintz( w_header, point( column_pos[COLUMN_CATEGORY] + 2, 3 ), c_white, pgettext( "category", "Cat" ) ); - wrefresh( w_header ); - }; - - initial_draw(); - - int tab = GLOBAL_TAB; - int line = 0; - int column = 0; - int start_pos = 0; - bool changes_made = false; - input_context ctxt( "SAFEMODE" ); - ctxt.register_cardinal(); - ctxt.register_action( "CONFIRM" ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "NEXT_TAB" ); - ctxt.register_action( "PREV_TAB" ); - ctxt.register_action( "ADD_DEFAULT_RULESET" ); - ctxt.register_action( "ADD_RULE" ); - ctxt.register_action( "REMOVE_RULE" ); - ctxt.register_action( "COPY_RULE" ); - ctxt.register_action( "ENABLE_RULE" ); - ctxt.register_action( "DISABLE_RULE" ); - ctxt.register_action( "MOVE_RULE_UP" ); - ctxt.register_action( "MOVE_RULE_DOWN" ); - ctxt.register_action( "TEST_RULE" ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - - if( is_safemode_in ) { - ctxt.register_action( "SWITCH_SAFEMODE_OPTION" ); - ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); - } - - while( true ) { int locx = 17; locx += shortcut_print( w_header, point( locx, 2 ), c_white, ( tab == GLOBAL_TAB ) ? hilite( c_white ) : c_white, _( "[]" ) ) + 1; @@ -246,6 +245,12 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } wrefresh( w ); + } ); + + while( true ) { + auto ¤t_tab = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; + + ui_manager::redraw(); const std::string action = ctxt.handle_input(); @@ -261,9 +266,6 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) tab = MAX_TAB - 1; line = 0; } - } else if( action == "HELP_KEYBINDINGS" ) { - // de-mangle parts of the screen - initial_draw(); } else if( action == "QUIT" ) { break; } else if( tab == CHARACTER_TAB && g->u.name.empty() ) { @@ -320,39 +322,56 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } else if( action == "CONFIRM" && !current_tab.empty() ) { changes_made = true; if( column == COLUMN_RULE ) { - switch( current_tab[line].category ) { - case Categories::HOSTILE_SPOTTED: - // NOLINTNEXTLINE(cata-use-named-point-constants) - fold_and_print( w_help, point( 1, 1 ), 999, c_white, - _( - "* is used as a Wildcard. A few Examples:\n" - "\n" - "human matches every NPC\n" - "zombie matches the monster name exactly\n" - "acidic zo* matches monsters beginning with 'acidic zo'\n" - "*mbie matches monsters ending with 'mbie'\n" - "*cid*zo*ie multiple * are allowed\n" - "AcI*zO*iE case insensitive search" ) - ); - break; - case Categories::SOUND: - // NOLINTNEXTLINE(cata-use-named-point-constants) - fold_and_print( w_help, point( 1, 1 ), 999, c_white, - _( - "* is used as a Wildcard. A few Examples:\n" - "\n" - "footsteps matches the sound name exactly\n" - "a loud ba* matches sounds beginning with 'a loud ba'\n" - "*losion! matches sounds ending with 'losion!'\n" - "a *oud*ba* multiple * are allowed\n" - "*LoU*bA* case insensitive search" ) - ); - break; - default: - break; - } - draw_border( w_help ); - wrefresh( w_help ); + catacurses::window w_help; + ui_adaptor help_ui; + const auto init_help_window = [&]( ui_adaptor & help_ui ) { + const int offset_x = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + const int offset_y = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + + w_help = catacurses::newwin( FULL_SCREEN_HEIGHT / 2 - 2, FULL_SCREEN_WIDTH * 3 / 4, + point( offset_x + 19 / 2, 7 + offset_y + FULL_SCREEN_HEIGHT / 2 / 2 ) ); + + help_ui.position_from_window( w_help ); + }; + init_help_window( help_ui ); + help_ui.on_screen_resize( init_help_window ); + + help_ui.on_redraw( [&]( const ui_adaptor & ) { + switch( current_tab[line].category ) { + case Categories::HOSTILE_SPOTTED: + // NOLINTNEXTLINE(cata-use-named-point-constants) + fold_and_print( w_help, point( 1, 1 ), 999, c_white, + _( + "* is used as a Wildcard. A few Examples:\n" + "\n" + "human matches every NPC\n" + "zombie matches the monster name exactly\n" + "acidic zo* matches monsters beginning with 'acidic zo'\n" + "*mbie matches monsters ending with 'mbie'\n" + "*cid*zo*ie multiple * are allowed\n" + "AcI*zO*iE case insensitive search" ) + ); + break; + case Categories::SOUND: + // NOLINTNEXTLINE(cata-use-named-point-constants) + fold_and_print( w_help, point( 1, 1 ), 999, c_white, + _( + "* is used as a Wildcard. A few Examples:\n" + "\n" + "footsteps matches the sound name exactly\n" + "a loud ba* matches sounds beginning with 'a loud ba'\n" + "*losion! matches sounds ending with 'losion!'\n" + "a *oud*ba* multiple * are allowed\n" + "*LoU*bA* case insensitive search" ) + ); + break; + default: + break; + } + draw_border( w_help ); + wrefresh( w_help ); + } ); + current_tab[line].rule = wildcard_trim_rule( string_input_popup() .title( _( "Safe Mode Rule:" ) ) .width( 30 ) From 50ecd02f00b31a700d64ce58ba94222ae2312f04 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 22:59:22 +0800 Subject: [PATCH 171/219] Use ui_adaptor in safemode test pattern window --- src/safemode_ui.cpp | 54 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index fcbb42c0b3b69..906034df10585 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -500,37 +500,51 @@ void safemode::test_pattern( const int tab_in, const int row_in ) } } - const int offset_x = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); - const int offset_y = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : - 0 ); - int start_pos = 0; - const int content_height = FULL_SCREEN_HEIGHT - 8; - const int content_width = FULL_SCREEN_WIDTH - 30; + int content_height = 0; + int content_width = 0; + + catacurses::window w_test_rule_border; + catacurses::window w_test_rule_content; + + ui_adaptor ui; + const auto init_windows = [&]( ui_adaptor & ui ) { + const int offset_x = 15 + ( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); + const int offset_y = 5 + ( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : + 0 ); - const catacurses::window w_test_rule_border = catacurses::newwin( content_height + 2, content_width, - point( offset_x, offset_y ) ); - const catacurses::window w_test_rule_content = catacurses::newwin( content_height, - content_width - 2, - point( 1 + offset_x, 1 + offset_y ) ); + content_height = FULL_SCREEN_HEIGHT - 8; + content_width = FULL_SCREEN_WIDTH - 30; + + w_test_rule_border = catacurses::newwin( content_height + 2, content_width, + point( offset_x, offset_y ) ); + w_test_rule_content = catacurses::newwin( content_height, content_width - 2, + point( 1 + offset_x, 1 + offset_y ) ); + + ui.position_from_window( w_test_rule_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); int nmatch = creature_list.size(); const std::string buf = string_format( ngettext( "%1$d monster matches: %2$s", "%1$d monsters match: %2$s", nmatch ), nmatch, temp_rules[row_in].rule.c_str() ); - draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); - center_print( w_test_rule_border, content_height + 1, red_background( c_white ), - _( "Lists monsters regardless of their attitude." ) ); - - wrefresh( w_test_rule_border ); int line = 0; input_context ctxt( "SAFEMODE_TEST" ); ctxt.register_updown(); ctxt.register_action( "QUIT" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); + center_print( w_test_rule_border, content_height + 1, red_background( c_white ), + _( "Lists monsters regardless of their attitude." ) ); + + wrefresh( w_test_rule_border ); - while( true ) { // Clear the lines for( int i = 0; i < content_height; i++ ) { for( int j = 0; j < 79; j++ ) { @@ -557,6 +571,10 @@ void safemode::test_pattern( const int tab_in, const int row_in ) } wrefresh( w_test_rule_content ); + } ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); if( action == "DOWN" ) { @@ -569,7 +587,7 @@ void safemode::test_pattern( const int tab_in, const int row_in ) if( line < 0 ) { line = creature_list.size() - 1; } - } else { + } else if( action == "QUIT" ) { break; } } From 616a9bbbf48f944850f47aace5d1d4c081569fe7 Mon Sep 17 00:00:00 2001 From: Qrox Date: Mon, 24 Feb 2020 23:38:16 +0800 Subject: [PATCH 172/219] Use ui_adaptor in color manager --- src/color.cpp | 89 ++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/src/color.cpp b/src/color.cpp index cb3629f50d87b..782b733917d9e 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -18,6 +18,7 @@ #include "string_formatter.h" #include "translations.h" #include "ui.h" +#include "ui_manager.h" #include "cursesdef.h" void nc_color::serialize( JsonOut &jsout ) const @@ -718,10 +719,10 @@ static void draw_header( const catacurses::window &w ) void color_manager::show_gui() { const int iHeaderHeight = 4; - const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; + int iContentHeight = 0; - const int iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; - const int iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; + int iOffsetX = 0; + int iOffsetY = 0; std::vector vLines; vLines.push_back( -1 ); @@ -729,37 +730,29 @@ void color_manager::show_gui() const int iTotalCols = vLines.size(); - catacurses::window w_colors_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, - point( iOffsetX, iOffsetY ) ); - catacurses::window w_colors_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, 1 + iOffsetY ) ); - catacurses::window w_colors = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, - point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); + catacurses::window w_colors_border; + catacurses::window w_colors_header; + catacurses::window w_colors; - /** - * All of the stuff in this lambda needs to be drawn (1) initially, and - * (2) after closing the HELP_KEYBINDINGS window (since it mangles the screen) - */ - const auto initial_draw = [&]() { - draw_border( w_colors_border, BORDER_COLOR, _( " COLOR MANAGER " ) ); - mvwputch( w_colors_border, point( 0, 3 ), BORDER_COLOR, LINE_XXXO ); // |- - mvwputch( w_colors_border, point( getmaxx( w_colors_border ) - 1, 3 ), BORDER_COLOR, - LINE_XOXX ); // -| + ui_adaptor ui; + const auto init_windows = [&]( ui_adaptor & ui ) { + iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; - for( auto &iCol : vLines ) { - if( iCol > -1 ) { - mvwputch( w_colors_border, point( iCol + 1, FULL_SCREEN_HEIGHT - 1 ), BORDER_COLOR, - LINE_XXOX ); // _|_ - mvwputch( w_colors_header, point( iCol, 3 ), BORDER_COLOR, LINE_XOXO ); - } - } - wrefresh( w_colors_border ); + iOffsetX = TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; + iOffsetY = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; - draw_header( w_colors_header ); + w_colors_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, + point( iOffsetX, iOffsetY ) ); + w_colors_header = catacurses::newwin( iHeaderHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, 1 + iOffsetY ) ); + w_colors = catacurses::newwin( iContentHeight, FULL_SCREEN_WIDTH - 2, + point( 1 + iOffsetX, iHeaderHeight + 1 + iOffsetY ) ); + ui.position_from_window( w_colors_border ); }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); - initial_draw(); int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; @@ -779,7 +772,23 @@ void color_manager::show_gui() name_color_map[pr.first] = color_array[pr.second]; } - while( true ) { + ui.on_redraw( [&]( const ui_adaptor & ) { + draw_border( w_colors_border, BORDER_COLOR, _( " COLOR MANAGER " ) ); + mvwputch( w_colors_border, point( 0, 3 ), BORDER_COLOR, LINE_XXXO ); // |- + mvwputch( w_colors_border, point( getmaxx( w_colors_border ) - 1, 3 ), BORDER_COLOR, + LINE_XOXX ); // -| + + for( auto &iCol : vLines ) { + if( iCol > -1 ) { + mvwputch( w_colors_border, point( iCol + 1, FULL_SCREEN_HEIGHT - 1 ), BORDER_COLOR, + LINE_XXOX ); // _|_ + mvwputch( w_colors_header, point( iCol, 3 ), BORDER_COLOR, LINE_XOXO ); + } + } + wrefresh( w_colors_border ); + + draw_header( w_colors_header ); + // Clear all lines for( int i = 0; i < iContentHeight; i++ ) { for( int j = 0; j < 79; j++ ) { @@ -801,8 +810,6 @@ void color_manager::show_gui() auto iter = name_color_map.begin(); std::advance( iter, iStartPos ); - std::string sActive; - // display color manager for( int i = iStartPos; iter != name_color_map.end(); ++iter, ++i ) { if( i >= iStartPos && @@ -810,7 +817,6 @@ void color_manager::show_gui() auto &entry = iter->second; if( iCurrentLine == i ) { - sActive = iter->first; mvwprintz( w_colors, point( vLines[iCurrentCol - 1] + 2, i - iStartPos ), c_yellow, ">" ); } @@ -833,6 +839,10 @@ void color_manager::show_gui() } wrefresh( w_colors ); + } ); + + while( true ) { + ui_manager::redraw(); const std::string action = ctxt.handle_input(); @@ -859,7 +869,7 @@ void color_manager::show_gui() iCurrentCol = 1; } } else if( action == "REMOVE_CUSTOM" ) { - auto &entry = name_color_map[sActive]; + auto &entry = std::next( name_color_map.begin(), iCurrentLine )->second; if( iCurrentCol == 1 && !entry.name_custom.empty() ) { bStuffChanged = true; @@ -911,12 +921,14 @@ void color_manager::show_gui() ui_colors.w_y = iHeaderHeight + 1 + iOffsetY; ui_colors.w_height = 18; + const auto &entry = std::next( name_color_map.begin(), iCurrentLine )->second; + std::string sColorType = _( "Normal" ); - std::string sSelected = name_color_map[sActive].name_custom; + std::string sSelected = entry.name_custom; if( iCurrentCol == 2 ) { sColorType = _( "Invert" ); - sSelected = name_color_map[sActive].name_invert_custom; + sSelected = entry.name_invert_custom; } @@ -944,15 +956,14 @@ void color_manager::show_gui() } ui_colors.query(); - initial_draw(); if( ui_colors.ret >= 0 && static_cast( ui_colors.ret ) < name_color_map.size() ) { bStuffChanged = true; - iter = name_color_map.begin(); + auto iter = name_color_map.begin(); std::advance( iter, ui_colors.ret ); - auto &entry = name_color_map[sActive]; + auto &entry = std::next( name_color_map.begin(), iCurrentLine )->second; if( iCurrentCol == 1 ) { entry.name_custom = iter->first; @@ -964,8 +975,6 @@ void color_manager::show_gui() } finalize(); // Need to recalculate caches - } else if( action == "HELP_KEYBINDINGS" ) { - initial_draw(); } } From 6030656640b0cc083f609ae9aa0decfc13dbe3b0 Mon Sep 17 00:00:00 2001 From: Qrox Date: Fri, 28 Feb 2020 13:17:00 +0800 Subject: [PATCH 173/219] Use ui_adaptor in help menu --- src/help.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/help.cpp b/src/help.cpp index 546eb61c2d790..2e9cf21992c57 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -17,6 +17,7 @@ #include "path_info.h" #include "text_snippets.h" #include "translations.h" +#include "ui_manager.h" #include "cata_utility.h" #include "color.h" #include "debug.h" @@ -131,12 +132,21 @@ std::string help::get_note_colors() void help::display_help() { - catacurses::window w_help_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, - point( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0, - TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ); - catacurses::window w_help = catacurses::newwin( FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, - point( 1 + static_cast( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ), - 1 + static_cast( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ) ); + catacurses::window w_help_border; + catacurses::window w_help; + + ui_adaptor ui; + const auto init_windows = [&]( ui_adaptor & ui ) { + w_help_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, + point( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0, + TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ); + w_help = catacurses::newwin( FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, + point( 1 + static_cast( TERMX > FULL_SCREEN_WIDTH ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ), + 1 + static_cast( TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ) ) ); + ui.position_from_window( w_help_border ); + }; + init_windows( ui ); + ui.on_screen_resize( init_windows ); ctxt.register_cardinal(); ctxt.register_action( "QUIT" ); @@ -146,11 +156,14 @@ void help::display_help() std::string action; - do { + ui.on_redraw( [&]( const ui_adaptor & ) { draw_border( w_help_border, BORDER_COLOR, _( " HELP " ), c_black_white ); wrefresh( w_help_border ); draw_menu( w_help ); - catacurses::refresh(); + } ); + + do { + ui_manager::redraw(); action = ctxt.handle_input(); std::string sInput = ctxt.get_raw_input().text; From 031889a647ee016f107830f901eb95e43c4e8dee Mon Sep 17 00:00:00 2001 From: Qrox Date: Fri, 28 Feb 2020 17:38:28 +0800 Subject: [PATCH 174/219] Use ui_adaptor in scrollable_text --- src/help.cpp | 11 ++++++++++- src/output.cpp | 50 ++++++++++++++++++++++++++++++++++++++------------ src/output.h | 2 ++ 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/help.cpp b/src/help.cpp index 2e9cf21992c57..1ab5936d9d8a0 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -194,12 +194,21 @@ void help::display_help() } ); if( !i18n_help_texts.empty() ) { - scrollable_text( w_help_border, _( " HELP " ), + ui.on_screen_resize( nullptr ); + + const auto get_w_help_border = [&]() { + init_windows( ui ); + return w_help_border; + }; + + scrollable_text( get_w_help_border, _( " HELP " ), std::accumulate( i18n_help_texts.begin() + 1, i18n_help_texts.end(), i18n_help_texts.front(), []( const std::string & lhs, const std::string & rhs ) { return lhs + "\n\n" + rhs; } ) ); + + ui.on_screen_resize( init_windows ); } action = "CONFIRM"; break; diff --git a/src/output.cpp b/src/output.cpp index cf93a8602461b..9850ef173667e 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -32,6 +32,7 @@ #include "rng.h" #include "string_formatter.h" #include "string_input_popup.h" +#include "ui_manager.h" #include "units.h" #include "point.h" #include "wcwidth.h" @@ -340,16 +341,16 @@ int fold_and_print_from( const catacurses::window &w, const point &begin, int wi void scrollable_text( const catacurses::window &w, const std::string &title, const std::string &text ) { - const int width = getmaxx( w ); - const int height = getmaxy( w ); + scrollable_text( [&w]() { + return w; + }, title, text ); +} + +void scrollable_text( const std::function &init_window, + const std::string &title, const std::string &text ) +{ constexpr int text_x = 1; constexpr int text_y = 1; - const int text_w = width - 2; - const int text_h = height - 2; - if( text_w <= 0 || text_h <= 0 ) { - debugmsg( "Oops, the window is too small to display anything!" ); - return; - } input_context ctxt( "SCROLLABLE_TEXT" ); ctxt.register_action( "UP" ); @@ -360,12 +361,32 @@ void scrollable_text( const catacurses::window &w, const std::string &title, ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); - const std::vector lines = foldstring( text, text_w ); + catacurses::window w; + int width = 0; + int height = 0; + int text_w = 0; + int text_h = 0; + std::vector lines; int beg_line = 0; - const int max_beg_line = std::max( 0, static_cast( lines.size() ) - text_h ); + int max_beg_line = 0; - std::string action; - do { + ui_adaptor ui; + const auto screen_resize_cb = [&]( ui_adaptor & ui ) { + w = init_window(); + + width = getmaxx( w ); + height = getmaxy( w ); + text_w = std::max( 0, width - 2 ); + text_h = std::max( 0, height - 2 ); + + lines = foldstring( text, text_w ); + max_beg_line = std::max( 0, static_cast( lines.size() ) - text_h ); + + ui.position_from_window( w ); + }; + screen_resize_cb( ui ); + ui.on_screen_resize( screen_resize_cb ); + ui.on_redraw( [&]( const ui_adaptor & ) { werase( w ); draw_border( w, BORDER_COLOR, title, c_black_white ); for( int line = beg_line, pos_y = text_y; line < std::min( beg_line + text_h, lines.size() ); @@ -376,6 +397,11 @@ void scrollable_text( const catacurses::window &w, const std::string &title, scrollbar().offset_x( width - 1 ).offset_y( text_y ).content_size( lines.size() ) .viewport_pos( std::min( beg_line, max_beg_line ) ).viewport_size( text_h ).apply( w ); wrefresh( w ); + } ); + + std::string action; + do { + ui_manager::redraw(); action = ctxt.handle_input(); if( action == "UP" ) { diff --git a/src/output.h b/src/output.h index bc4cfaa362271..1b10ee9c63e08 100644 --- a/src/output.h +++ b/src/output.h @@ -327,6 +327,8 @@ void display_table( const catacurses::window &w, const std::string &title, int c const std::vector &data ); void scrollable_text( const catacurses::window &w, const std::string &title, const std::string &text ); +void scrollable_text( const std::function &init_window, + const std::string &title, const std::string &text ); std::string name_and_value( const std::string &name, int value, int field_width ); std::string name_and_value( const std::string &name, const std::string &value, int field_width ); From 0cb30ed995c85259a0063904673d023394eacc77 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 20:47:40 +0100 Subject: [PATCH 175/219] Remove manual JSON object member check: Just get the value and let the JSON system deal with the existence check and the error message. Also throw errors via the JSON system so it creates a nice message with error location. --- src/mapgen.cpp | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 4e7e55f9f358e..741dc805e5d7f 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -310,36 +310,21 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, } jio.allow_omitted_members(); return nullptr; // nothing - } else if( jio.has_string( "method" ) ) { - const std::string mgtype = jio.get_string( "method" ); - if( mgtype == "builtin" ) { // c-function - if( jio.has_string( "name" ) ) { - const std::string mgname = jio.get_string( "name" ); - if( const auto ptr = get_mapgen_cfunction( mgname ) ) { - ret = std::make_shared( ptr, mgweight ); - oter_mapgen[id_base].push_back( ret ); - } else { - debugmsg( "oter_t[%s]: builtin mapgen function \"%s\" does not exist.", id_base.c_str(), - mgname ); - } - } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"name\" value).", id_base.c_str() ); - } - } else if( mgtype == "json" ) { - if( jio.has_object( "object" ) ) { - JsonObject jo = jio.get_object( "object" ); - std::string jstr = jo.str(); - ret = std::make_shared( jstr, mgweight, offset ); - oter_mapgen[id_base].push_back( ret ); - } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"object\" object)", id_base.c_str() ); - } + } + const std::string mgtype = jio.get_string( "method" ); + if( mgtype == "builtin" ) { + if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { + ret = std::make_shared( ptr, mgweight ); + oter_mapgen[id_base].push_back( ret ); } else { - debugmsg( "oter_t[%s]: Invalid mapgen function type: %s", id_base.c_str(), mgtype.c_str() ); + jio.throw_error( "function does not exist", "name" ); } + } else if( mgtype == "json" ) { + const std::string jstr = jio.get_object( "object" ).str(); + ret = std::make_shared( jstr, mgweight, offset ); + oter_mapgen[id_base].push_back( ret ); } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"method\" value, must be \"builtin\" or \"json\").", - id_base.c_str() ); + jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); } return ret; } From 640b695b7d367db5e161bcbe718be09cd923142e Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:03:30 +0100 Subject: [PATCH 176/219] Move some repeated code into a function get_mapgen_function. Basically the whole look up of the mapgen function pointer within the `oter_mapgen` and so on. --- src/mapgen.cpp | 255 ++++++++++++++++++++++--------------------------- 1 file changed, 114 insertions(+), 141 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 741dc805e5d7f..4b43b784d6a6f 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -265,6 +265,31 @@ void check_mapgen_definitions() } } +// @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. +static mapgen_function *get_mapgen_function( const std::string &key, + const int hardcoded_weight = 0 ) +{ + const auto fmapit = oter_mapgen.find( key ); + if( fmapit == oter_mapgen.end() ) { + return nullptr; + } + const std::vector> &vector = fmapit->second; + // Creating the entry in the map is only done when an entry in the vector is about to be made, + // so the map should not contain empty vectors. + assert( !vector.empty() ); + const auto weightit = oter_mapgen_weights.find( key ); + const int rlast = weightit->second.rbegin()->first; + const int roll = rng( 1, rlast + hardcoded_weight ); + if( roll > rlast ) { + return nullptr; + } + const int fidx = weightit->second.lower_bound( roll )->second; + assert( static_cast( fidx ) < vector.size() ); + const std::shared_ptr &ptr = vector[fidx]; + assert( ptr ); + return ptr.get(); +} + ///////////////////////////////////////////////////////////////////////////////// ///// json mapgen functions ///// 1 - init(): @@ -3470,18 +3495,8 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { - const std::string function_key = "lab_1side"; // terrain_type->get_mapgen_id(); - const auto fmapit = oter_mapgen.find( function_key ); - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast ); - - const int fidx = weightit->second.lower_bound( roll )->second; - - fmapit->second[fidx]->generate( dat ); + if( const auto ptr = get_mapgen_function( "lab_1side" ) ) { + ptr->generate( dat ); if( tw == 2 ) { rotate( 2 ); } @@ -3497,75 +3512,57 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( dat.above(), t_stairs_up ); maybe_insert_stairs( terrain_type, t_stairs_down ); } else { - const std::string function_key = "lab_4side"; - const auto fmapit = oter_mapgen.find( function_key ); const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. - bool use_hardcoded_4side_map = false; - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_4side_map_weight ); - - if( roll <= rlast ) { - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - - // If the map template hasn't handled borders, handle them in code. - // Rotated maps cannot handle borders and have to be caught in code. - // We determine if a border isn't handled by checking the east-facing - // border space where the door normally is -- it should be a wall or door. - tripoint east_border( 23, 11, abs_sub.z ); - if( !has_flag_ter( "WALL", east_border ) && - !has_flag_ter( "DOOR", east_border ) ) { - // TODO: create a ter_reset function that does ter_set, - // furn_set, and i_clear? - ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : - t_concrete_wall; - ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : - t_concrete_wall; - for( int i = 0; i < SEEX * 2; i++ ) { - ter_set( point( 23, i ), rw_type ); - furn_set( point( 23, i ), f_null ); - i_clear( tripoint( 23, i, get_abs_sub().z ) ); - - ter_set( point( i, 23 ), bw_type ); - furn_set( point( i, 23 ), f_null ); - i_clear( tripoint( i, 23, get_abs_sub().z ) ); - - if( lw == 2 ) { - ter_set( point( 0, i ), lw_type ); - furn_set( point( 0, i ), f_null ); - i_clear( tripoint( 0, i, get_abs_sub().z ) ); - } - if( tw == 2 ) { - ter_set( point( i, 0 ), tw_type ); - furn_set( point( i, 0 ), f_null ); - i_clear( tripoint( i, 0, get_abs_sub().z ) ); - } - } - if( rw != 2 ) { - ter_set( point( 23, 11 ), t_door_metal_c ); - ter_set( point( 23, 12 ), t_door_metal_c ); + if( const auto ptr = get_mapgen_function( "lab_4side", hardcoded_4side_map_weight ) ) { + ptr->generate( dat ); + // If the map template hasn't handled borders, handle them in code. + // Rotated maps cannot handle borders and have to be caught in code. + // We determine if a border isn't handled by checking the east-facing + // border space where the door normally is -- it should be a wall or door. + tripoint east_border( 23, 11, abs_sub.z ); + if( !has_flag_ter( "WALL", east_border ) && + !has_flag_ter( "DOOR", east_border ) ) { + // TODO: create a ter_reset function that does ter_set, + // furn_set, and i_clear? + ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : + t_concrete_wall; + ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : + t_concrete_wall; + for( int i = 0; i < SEEX * 2; i++ ) { + ter_set( point( 23, i ), rw_type ); + furn_set( point( 23, i ), f_null ); + i_clear( tripoint( 23, i, get_abs_sub().z ) ); + + ter_set( point( i, 23 ), bw_type ); + furn_set( point( i, 23 ), f_null ); + i_clear( tripoint( i, 23, get_abs_sub().z ) ); + + if( lw == 2 ) { + ter_set( point( 0, i ), lw_type ); + furn_set( point( 0, i ), f_null ); + i_clear( tripoint( 0, i, get_abs_sub().z ) ); } - if( bw != 2 ) { - ter_set( point( 11, 23 ), t_door_metal_c ); - ter_set( point( 12, 23 ), t_door_metal_c ); + if( tw == 2 ) { + ter_set( point( i, 0 ), tw_type ); + furn_set( point( i, 0 ), f_null ); + i_clear( tripoint( i, 0, get_abs_sub().z ) ); } } + if( rw != 2 ) { + ter_set( point( 23, 11 ), t_door_metal_c ); + ter_set( point( 23, 12 ), t_door_metal_c ); + } + if( bw != 2 ) { + ter_set( point( 11, 23 ), t_door_metal_c ); + ter_set( point( 12, 23 ), t_door_metal_c ); + } + } - maybe_insert_stairs( dat.above(), t_stairs_up ); - maybe_insert_stairs( terrain_type, t_stairs_down ); - } else { // then weighted roll was in the hardcoded section - use_hardcoded_4side_map = true; - } // end json maps + maybe_insert_stairs( dat.above(), t_stairs_up ); + maybe_insert_stairs( terrain_type, t_stairs_down ); } else { // then no json maps for lab_4side were found - use_hardcoded_4side_map = true; - } // end if no lab_4side was found. - if( use_hardcoded_4side_map ) { switch( rng( 1, 3 ) ) { case 1: // Cross shaped @@ -4060,69 +4057,51 @@ void map::draw_lab( mapgendata &dat ) bw = is_ot_match( "lab", dat.south(), ot_match_type::contains ) ? 1 : 2; lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; - const std::string function_key = "lab_finale_1level"; - const auto fmapit = oter_mapgen.find( function_key ); const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. - bool use_hardcoded_finale_map = false; - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_finale_map_weight ); - - if( roll <= rlast ) { - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - - // If the map template hasn't handled borders, handle them in code. - // Rotated maps cannot handle borders and have to be caught in code. - // We determine if a border isn't handled by checking the east-facing - // border space where the door normally is -- it should be a wall or door. - tripoint east_border( 23, 11, abs_sub.z ); - if( !has_flag_ter( "WALL", east_border ) && !has_flag_ter( "DOOR", east_border ) ) { - // TODO: create a ter_reset function that does ter_set, furn_set, and i_clear? - ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : t_concrete_wall; - ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : t_concrete_wall; - for( int i = 0; i < SEEX * 2; i++ ) { - ter_set( point( 23, i ), rw_type ); - furn_set( point( 23, i ), f_null ); - i_clear( tripoint( 23, i, get_abs_sub().z ) ); - - ter_set( point( i, 23 ), bw_type ); - furn_set( point( i, 23 ), f_null ); - i_clear( tripoint( i, 23, get_abs_sub().z ) ); - - if( lw == 2 ) { - ter_set( point( 0, i ), lw_type ); - furn_set( point( 0, i ), f_null ); - i_clear( tripoint( 0, i, get_abs_sub().z ) ); - } - if( tw == 2 ) { - ter_set( point( i, 0 ), tw_type ); - furn_set( point( i, 0 ), f_null ); - i_clear( tripoint( i, 0, get_abs_sub().z ) ); - } - } - if( rw != 2 ) { - ter_set( point( 23, 11 ), t_door_metal_c ); - ter_set( point( 23, 12 ), t_door_metal_c ); + if( const auto ptr = get_mapgen_function( "lab_finale_1level", hardcoded_finale_map_weight ) ) { + ptr->generate( dat ); + + // If the map template hasn't handled borders, handle them in code. + // Rotated maps cannot handle borders and have to be caught in code. + // We determine if a border isn't handled by checking the east-facing + // border space where the door normally is -- it should be a wall or door. + tripoint east_border( 23, 11, abs_sub.z ); + if( !has_flag_ter( "WALL", east_border ) && !has_flag_ter( "DOOR", east_border ) ) { + // TODO: create a ter_reset function that does ter_set, furn_set, and i_clear? + ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : t_concrete_wall; + ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : t_concrete_wall; + for( int i = 0; i < SEEX * 2; i++ ) { + ter_set( point( 23, i ), rw_type ); + furn_set( point( 23, i ), f_null ); + i_clear( tripoint( 23, i, get_abs_sub().z ) ); + + ter_set( point( i, 23 ), bw_type ); + furn_set( point( i, 23 ), f_null ); + i_clear( tripoint( i, 23, get_abs_sub().z ) ); + + if( lw == 2 ) { + ter_set( point( 0, i ), lw_type ); + furn_set( point( 0, i ), f_null ); + i_clear( tripoint( 0, i, get_abs_sub().z ) ); } - if( bw != 2 ) { - ter_set( point( 11, 23 ), t_door_metal_c ); - ter_set( point( 12, 23 ), t_door_metal_c ); + if( tw == 2 ) { + ter_set( point( i, 0 ), tw_type ); + furn_set( point( i, 0 ), f_null ); + i_clear( tripoint( i, 0, get_abs_sub().z ) ); } } - } else { // then weighted roll was in the hardcoded section - use_hardcoded_finale_map = true; - } // end json maps + if( rw != 2 ) { + ter_set( point( 23, 11 ), t_door_metal_c ); + ter_set( point( 23, 12 ), t_door_metal_c ); + } + if( bw != 2 ) { + ter_set( point( 11, 23 ), t_door_metal_c ); + ter_set( point( 12, 23 ), t_door_metal_c ); + } + } } else { // then no json maps for lab_finale_1level were found - use_hardcoded_finale_map = true; - } // end if no lab_4side was found. - - if( use_hardcoded_finale_map ) { // Start by setting up a large, empty room. for( int i = 0; i < SEEX * 2; i++ ) { for( int j = 0; j < SEEY * 2; j++ ) { @@ -7296,14 +7275,8 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - const auto fmapit = oter_mapgen.find( mapgen_id ); - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - mapgen_id ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast ); - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); + if( const auto ptr = get_mapgen_function( mapgen_id ) ) { + ptr->generate( dat ); return true; } return false; From 72b3076a4a637c42c06c5c5d7ae589ed079c927c Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:11:35 +0100 Subject: [PATCH 177/219] Move some code as function into mapgen.cpp This is mostly done to avoid having to expose `oter_mapgen` in the header. --- src/mapgen.cpp | 10 ++++++++++ src/mapgen.h | 7 +++++++ src/overmap.cpp | 5 +---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 4b43b784d6a6f..750c363585881 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -7281,3 +7281,13 @@ bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) } return false; } + +int register_mapgen_function( const std::string &key ) +{ + if( const auto ptr = get_mapgen_cfunction( key ) ) { + std::vector> &vector = oter_mapgen[key]; + vector.push_back( std::make_shared( ptr ) ); + return vector.size() - 1; + } + return -1; +} diff --git a/src/mapgen.h b/src/mapgen.h index 6c9e31034673d..91f924ea59109 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -378,6 +378,13 @@ std::shared_ptr load_mapgen_function( const JsonObject &jio, */ void load_mapgen( const JsonObject &jo ); void reset_mapgens(); +/** + * Attempts to register the build-in function @p key as mapgen for the overmap terrain @p key. + * If there is no matching function, it does nothing (no error message) and returns -1. + * Otherwise it returns the index of the added entry in the vector of @ref oter_mapgen. + */ +// @TODO this should go away. It is only used for old build-in mapgen. Mapgen should be done via JSON. +int register_mapgen_function( const std::string &key ); /* * stores function ref and/or required data */ diff --git a/src/overmap.cpp b/src/overmap.cpp index 555b786d0b879..f15b599d539dd 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -530,10 +530,7 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin bool default_mapgen = jo.get_bool( "default_mapgen", true ); int default_idx = -1; if( default_mapgen ) { - if( const auto ptr = get_mapgen_cfunction( fmapkey ) ) { - oter_mapgen[fmapkey].push_back( std::make_shared( ptr ) ); - default_idx = oter_mapgen[fmapkey].size() - 1; - } + default_idx = register_mapgen_function( fmapkey ); } if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { From e60a3a757dc6b5769f15bbdba62b5934200f8bca Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:12:33 +0100 Subject: [PATCH 178/219] Remove redundant declaration. Those variables are already declared in a header or not even used within this cpp file. --- src/map_extras.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/map_extras.cpp b/src/map_extras.cpp index caf08d0a45d4b..2ef322a6be8f6 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -2832,9 +2832,6 @@ void map_extra::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "autonote", autonote, false ); } -extern std::map> > oter_mapgen; -extern std::map> > - nested_mapgen; extern std::map> > update_mapgen; From e5139ff9ab951e2576ec3c98268d0afb2a07cbca Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:13:00 +0100 Subject: [PATCH 179/219] Remove commented out code. --- src/map_extras.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 2ef322a6be8f6..0cd274ad9dd3e 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -2847,13 +2847,6 @@ void map_extra::check() const break; } case map_extra_method::mapgen: { - /* - const auto fmapit = oter_mapgen.find( generator_id ); - const oter_id extra_oter( generator_id ); - if( ( fmapit == oter_mapgen.end() || !fmapit->second.empty() ) && !extra_oter.is_valid() ) { - debugmsg( "invalid mapgen function (%s) defined for map extra (%s)", generator_id, id.str() ); - } - */ break; } case map_extra_method::update_mapgen: { From 2998acc59fc1d2e122c845ec90cbdf2981d952c3 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:15:00 +0100 Subject: [PATCH 180/219] Move access to oter_mapgen into mapgen.cpp Again: this is to avoid having to expose `oter_mapgen` in the header. --- src/mapgen.cpp | 5 +++++ src/mapgen.h | 4 ++++ src/overmap.cpp | 3 +-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 750c363585881..4643499fbda69 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -7291,3 +7291,8 @@ int register_mapgen_function( const std::string &key ) } return -1; } + +bool has_mapgen_for( const std::string &key ) +{ + return oter_mapgen.count( key ) != 0; +} diff --git a/src/mapgen.h b/src/mapgen.h index 91f924ea59109..8d01c465bc561 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -385,6 +385,10 @@ void reset_mapgens(); */ // @TODO this should go away. It is only used for old build-in mapgen. Mapgen should be done via JSON. int register_mapgen_function( const std::string &key ); +/** + * Check that @p key is present in @ref oter_mapgen. + */ +bool has_mapgen_for( const std::string &key ); /* * stores function ref and/or required data */ diff --git a/src/overmap.cpp b/src/overmap.cpp index f15b599d539dd..fd577a0639c84 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -787,9 +787,8 @@ void overmap_terrains::check_consistency() } const bool exists_hardcoded = elem.is_hardcoded(); - const bool exists_loaded = oter_mapgen.find( mid ) != oter_mapgen.end(); - if( exists_loaded ) { + if( has_mapgen_for( mid ) ) { if( test_mode && exists_hardcoded ) { debugmsg( "Mapgen terrain \"%s\" exists in both JSON and a hardcoded function. Consider removing the latter.", mid.c_str() ); From 243d3eefc7f2deae5069628ac52a0a1ef0db0d1d Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:19:49 +0100 Subject: [PATCH 181/219] Remove exposing variables from mapgen.cpp in the header. Merges the comments from the header with the comments in the cpp file for the very same objects. --- src/mapgen.cpp | 3 ++- src/mapgen.h | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 4643499fbda69..8fe9687d7e367 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -195,7 +195,7 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// all sorts of ways to apply our hellish reality to a grid-o-squares /* - * ptr storage. + * stores function ref and/or required data */ std::map> > oter_mapgen; std::map> > nested_mapgen; @@ -203,6 +203,7 @@ std::map> /* * index to the above, adjusted to allow for rarity + * random selector list for the nested vector above, as per individual mapgen_function_::weight value */ std::map > oter_mapgen_weights; diff --git a/src/mapgen.h b/src/mapgen.h index 8d01c465bc561..b543a00b1bf0e 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -389,14 +389,6 @@ int register_mapgen_function( const std::string &key ); * Check that @p key is present in @ref oter_mapgen. */ bool has_mapgen_for( const std::string &key ); -/* - * stores function ref and/or required data - */ -extern std::map> > oter_mapgen; -/* - * random selector list for the nested vector above, as per individual mapgen_function_::weight value - */ -extern std::map > oter_mapgen_weights; /* * Sets the above after init, and initializes mapgen_function_json instances as well */ From 522aa0da5fb1545baff0ca7c64e0fdf945d15284 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:20:09 +0100 Subject: [PATCH 182/219] Add separate function to register mapgen object: register_mapgen_function --- src/mapgen.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 8fe9687d7e367..3002559bb0168 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -266,6 +266,15 @@ void check_mapgen_definitions() } } +static int register_mapgen_function( const std::string &key, + const std::shared_ptr ptr ) +{ + assert( ptr ); + std::vector> &vector = oter_mapgen[key]; + vector.push_back( ptr ); + return vector.size() - 1; +} + // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. static mapgen_function *get_mapgen_function( const std::string &key, const int hardcoded_weight = 0 ) @@ -341,14 +350,14 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( mgtype == "builtin" ) { if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { ret = std::make_shared( ptr, mgweight ); - oter_mapgen[id_base].push_back( ret ); + register_mapgen_function( id_base, ret ); } else { jio.throw_error( "function does not exist", "name" ); } } else if( mgtype == "json" ) { const std::string jstr = jio.get_object( "object" ).str(); ret = std::make_shared( jstr, mgweight, offset ); - oter_mapgen[id_base].push_back( ret ); + register_mapgen_function( id_base, ret ); } else { jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); } @@ -405,7 +414,7 @@ void load_mapgen( const JsonObject &jo ) for( const std::string mapgenid : row_items ) { const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); if( mgfunc ) { - oter_mapgen[ mapgenid ].push_back( mgfunc ); + register_mapgen_function( mapgenid, mgfunc ); } offset.x++; } @@ -422,7 +431,7 @@ void load_mapgen( const JsonObject &jo ) const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); if( mgfunc ) { for( auto &i : mapgenid_list ) { - oter_mapgen[ i ].push_back( mgfunc ); + register_mapgen_function( i, mgfunc ); } } } @@ -7286,9 +7295,7 @@ bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) int register_mapgen_function( const std::string &key ) { if( const auto ptr = get_mapgen_cfunction( key ) ) { - std::vector> &vector = oter_mapgen[key]; - vector.push_back( std::make_shared( ptr ) ); - return vector.size() - 1; + return register_mapgen_function( key, std::make_shared( ptr ) ); } return -1; } From e78a8a2a3d1b46add1f5ebe676a47ef8f9e75808 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:26:07 +0100 Subject: [PATCH 183/219] =?UTF-8?q?Change=20oter=5Fmapgen=20to=20contain?= =?UTF-8?q?=20=C3=ADnstances=20of=20a=20dedicated=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those instances can have their own members and stuff. --- src/mapgen.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 3002559bb0168..14243798da6b7 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -194,10 +194,19 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// mapgen_function class. ///// all sorts of ways to apply our hellish reality to a grid-o-squares +class mapgen_basic_container : public std::vector> +{ + public: + int add( const std::shared_ptr ptr ) { + assert( ptr ); + push_back( ptr ); + return size() - 1; + } +}; /* * stores function ref and/or required data */ -std::map> > oter_mapgen; +std::map oter_mapgen; std::map> > nested_mapgen; std::map> > update_mapgen; @@ -269,10 +278,7 @@ void check_mapgen_definitions() static int register_mapgen_function( const std::string &key, const std::shared_ptr ptr ) { - assert( ptr ); - std::vector> &vector = oter_mapgen[key]; - vector.push_back( ptr ); - return vector.size() - 1; + return oter_mapgen[key].add( ptr ); } // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. From bbd37bf43aa723f47a812a101bceb73bf64adf3e Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:41:11 +0100 Subject: [PATCH 184/219] Merge oter_mapgen_weights into oter_mapgen: Instead of having a separate map, this reuses the already existing entries in `oter_mapgen`. --- src/mapgen.cpp | 26 ++++++++++++-------------- src/mapgen.h | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 14243798da6b7..0d61fd1f6189e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -197,6 +197,12 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) class mapgen_basic_container : public std::vector> { public: + /** + * index to the above, adjusted to allow for rarity + * random selector list for the nested vector above, as per individual mapgen_function_::weight value + */ + std::map weights_; + int add( const std::shared_ptr ptr ) { assert( ptr ); push_back( ptr ); @@ -211,21 +217,14 @@ std::map> std::map> > update_mapgen; /* - * index to the above, adjusted to allow for rarity - * random selector list for the nested vector above, as per individual mapgen_function_::weight value - */ -std::map > oter_mapgen_weights; - -/* - * setup oter_mapgen_weights which mapgen uses to diceroll. Also setup mapgen_function_json + * setup mapgen_basic_container::weights_ which mapgen uses to diceroll. Also setup mapgen_function_json */ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { - oter_mapgen_weights.clear(); for( auto &omw : oter_mapgen ) { int funcnum = 0; int wtotal = 0; - oter_mapgen_weights[ omw.first ] = std::map(); + omw.second.weights_.clear(); for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { // int weight = ( *fit )->weight; @@ -237,7 +236,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup } ( *fit )->setup(); wtotal += weight; - oter_mapgen_weights[ omw.first ][ wtotal ] = funcnum; + omw.second.weights_[ wtotal ] = funcnum; dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): +" << weight << " = " << wtotal; ++funcnum; } @@ -289,17 +288,16 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( fmapit == oter_mapgen.end() ) { return nullptr; } - const std::vector> &vector = fmapit->second; + const mapgen_basic_container &vector = fmapit->second; // Creating the entry in the map is only done when an entry in the vector is about to be made, // so the map should not contain empty vectors. assert( !vector.empty() ); - const auto weightit = oter_mapgen_weights.find( key ); - const int rlast = weightit->second.rbegin()->first; + const int rlast = vector.weights_.rbegin()->first; const int roll = rng( 1, rlast + hardcoded_weight ); if( roll > rlast ) { return nullptr; } - const int fidx = weightit->second.lower_bound( roll )->second; + const int fidx = vector.weights_.lower_bound( roll )->second; assert( static_cast( fidx ) < vector.size() ); const std::shared_ptr &ptr = vector[fidx]; assert( ptr ); diff --git a/src/mapgen.h b/src/mapgen.h index b543a00b1bf0e..ec114176152df 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -374,7 +374,7 @@ std::shared_ptr load_mapgen_function( const JsonObject &jio, const std::string &id_base, int default_idx, const point &offset = point_zero ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check - * for oter_mapgen / oter_mapgen_weights key, multiple possible ( ie, [ "house", "house_base" ] ) + * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) */ void load_mapgen( const JsonObject &jo ); void reset_mapgens(); From 7245e6f70a3945e6435d31fa4efa44b04ddc9988 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:47:16 +0100 Subject: [PATCH 185/219] Store pointers directly in oter_mapgen weights map instead of indices into the vector itself. This avoids the repeated look up within the vector and it avoids a potential error situation: the index taken from `weight_` could be invalid. --- src/mapgen.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 0d61fd1f6189e..985dd96a2be22 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -201,7 +201,7 @@ class mapgen_basic_container : public std::vector weights_; + std::map> weights_; int add( const std::shared_ptr ptr ) { assert( ptr ); @@ -222,23 +222,18 @@ std::map> void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { for( auto &omw : oter_mapgen ) { - int funcnum = 0; int wtotal = 0; omw.second.weights_.clear(); for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { - // int weight = ( *fit )->weight; if( weight < 1 ) { - dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): (rej(1), " << weight << ") = " << - wtotal; - ++funcnum; + dbg( D_INFO ) << "wcalc " << omw.first << ": (rej(1), " << weight << ") = " << wtotal; continue; // rejected! } ( *fit )->setup(); wtotal += weight; - omw.second.weights_[ wtotal ] = funcnum; - dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): +" << weight << " = " << wtotal; - ++funcnum; + omw.second.weights_[ wtotal ] = *fit; + dbg( D_INFO ) << "wcalc " << omw.first << ": +" << weight << " = " << wtotal; } } // Not really calculate weights, but let's keep it here for now @@ -297,9 +292,7 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( roll > rlast ) { return nullptr; } - const int fidx = vector.weights_.lower_bound( roll )->second; - assert( static_cast( fidx ) < vector.size() ); - const std::shared_ptr &ptr = vector[fidx]; + const std::shared_ptr &ptr = vector.weights_.lower_bound( roll )->second; assert( ptr ); return ptr.get(); } From 601550d956c7952dd12f0486d03b3df3a549a722 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:56:06 +0100 Subject: [PATCH 186/219] Use weighted_int_list for oter_mapgen weights We already have this class, so we should make use of it. --- src/mapgen.cpp | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 985dd96a2be22..5a21a2e22c157 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -197,11 +197,7 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) class mapgen_basic_container : public std::vector> { public: - /** - * index to the above, adjusted to allow for rarity - * random selector list for the nested vector above, as per individual mapgen_function_::weight value - */ - std::map> weights_; + weighted_int_list> weights_; int add( const std::shared_ptr ptr ) { assert( ptr ); @@ -222,19 +218,16 @@ std::map> void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { for( auto &omw : oter_mapgen ) { - int wtotal = 0; omw.second.weights_.clear(); - for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { - int weight = ( *fit )->weight; + for( const std::shared_ptr &ptr : omw.second ) { + const int weight = ptr->weight; if( weight < 1 ) { - dbg( D_INFO ) << "wcalc " << omw.first << ": (rej(1), " << weight << ") = " << wtotal; continue; // rejected! } - ( *fit )->setup(); - wtotal += weight; - omw.second.weights_[ wtotal ] = *fit; - dbg( D_INFO ) << "wcalc " << omw.first << ": +" << weight << " = " << wtotal; + omw.second.weights_.add( ptr, weight ); + ptr->setup(); } + // @TODO clear: omw.second.clear(); } // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { @@ -283,18 +276,18 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( fmapit == oter_mapgen.end() ) { return nullptr; } - const mapgen_basic_container &vector = fmapit->second; - // Creating the entry in the map is only done when an entry in the vector is about to be made, - // so the map should not contain empty vectors. - assert( !vector.empty() ); - const int rlast = vector.weights_.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_weight ); - if( roll > rlast ) { + const weighted_int_list> &weights = fmapit->second.weights_; + if( hardcoded_weight > 0 ) { + if( rng( 1, weights.get_weight() + hardcoded_weight ) > weights.get_weight() ) { + return nullptr; + } + } + const std::shared_ptr *ptr = weights.pick(); + if( !ptr ) { return nullptr; } - const std::shared_ptr &ptr = vector.weights_.lower_bound( roll )->second; - assert( ptr ); - return ptr.get(); + assert( *ptr ); + return ptr->get(); } ///////////////////////////////////////////////////////////////////////////////// From ec80579bebea3adea5a2cc964275cdd9866015ff Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 21:59:35 +0100 Subject: [PATCH 187/219] Move code into a member function mapgen_basic_container::pick --- src/mapgen.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 5a21a2e22c157..68d0e2cac9ef2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -204,6 +204,23 @@ class mapgen_basic_container : public std::vector 0 && + rng( 1, weights_.get_weight() + hardcoded_weight ) > weights_.get_weight() ) { + return nullptr; + } + const std::shared_ptr *const ptr = weights_.pick(); + if( !ptr ) { + return nullptr; + } + assert( *ptr ); + return ptr->get(); + } }; /* * stores function ref and/or required data @@ -276,18 +293,7 @@ static mapgen_function *get_mapgen_function( const std::string &key, if( fmapit == oter_mapgen.end() ) { return nullptr; } - const weighted_int_list> &weights = fmapit->second.weights_; - if( hardcoded_weight > 0 ) { - if( rng( 1, weights.get_weight() + hardcoded_weight ) > weights.get_weight() ) { - return nullptr; - } - } - const std::shared_ptr *ptr = weights.pick(); - if( !ptr ) { - return nullptr; - } - assert( *ptr ); - return ptr->get(); + return fmapit->second.pick( hardcoded_weight ); } ///////////////////////////////////////////////////////////////////////////////// From d8aacda09f344870a3c0228c673fccb98ab4704a Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:02:38 +0100 Subject: [PATCH 188/219] Move code into a member function: mapgen_basic_container::setup --- src/mapgen.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 68d0e2cac9ef2..22e5fb2716fc0 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -221,6 +221,18 @@ class mapgen_basic_container : public std::vectorget(); } + void setup() { + weights_.clear(); + for( const std::shared_ptr &ptr : *this ) { + const int weight = ptr->weight; + if( weight < 1 ) { + continue; // rejected! + } + weights_.add( ptr, weight ); + ptr->setup(); + } + // @TODO clear: clear(); + } }; /* * stores function ref and/or required data @@ -235,16 +247,7 @@ std::map> void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { for( auto &omw : oter_mapgen ) { - omw.second.weights_.clear(); - for( const std::shared_ptr &ptr : omw.second ) { - const int weight = ptr->weight; - if( weight < 1 ) { - continue; // rejected! - } - omw.second.weights_.add( ptr, weight ); - ptr->setup(); - } - // @TODO clear: omw.second.clear(); + omw.second.setup(); } // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { From 5f702c0d7910f490ed487504d08d81511c52fe9c Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:02:42 +0100 Subject: [PATCH 189/219] Move code into a member function: mapgen_basic_container::check_consistency Note: the function name is chosen for consistency (no pun), our other consistency checking function are named that way. --- src/mapgen.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 22e5fb2716fc0..db2f43673b6b6 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -233,6 +233,11 @@ class mapgen_basic_container : public std::vectorcheck( key ); + } + } }; /* * stores function ref and/or required data @@ -266,9 +271,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup void check_mapgen_definitions() { for( auto &oter_definition : oter_mapgen ) { - for( auto &mapgen_function_ptr : oter_definition.second ) { - mapgen_function_ptr->check( oter_definition.first ); - } + oter_definition.second.check_consistency( oter_definition.first ); } for( auto &oter_definition : nested_mapgen ) { for( auto &mapgen_function_ptr : oter_definition.second ) { From 7d59eeab797337490841fd479ded7c028571826c Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:08:15 +0100 Subject: [PATCH 190/219] Make all data members of mapgen_basic_container private. No need to expose them. The last direct access to the vector had to be wrapped within a new member function. --- src/mapgen.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index db2f43673b6b6..5b30f648914ec 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -194,15 +194,25 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// mapgen_function class. ///// all sorts of ways to apply our hellish reality to a grid-o-squares -class mapgen_basic_container : public std::vector> +class mapgen_basic_container { - public: + private: + std::vector> mapgens_; weighted_int_list> weights_; + public: int add( const std::shared_ptr ptr ) { assert( ptr ); - push_back( ptr ); - return size() - 1; + mapgens_.push_back( ptr ); + return mapgens_.size() - 1; + } + void erase( const size_t index ) { + if( index > mapgens_.size() ) { + return; + } + assert( mapgens_[index] ); + // Can't actually erase it as this might invalid the index stored elsewhere + mapgens_[index]->weight = 0; } /** * Pick a mapgen function randomly. @@ -222,8 +232,7 @@ class mapgen_basic_container : public std::vectorget(); } void setup() { - weights_.clear(); - for( const std::shared_ptr &ptr : *this ) { + for( const std::shared_ptr &ptr : mapgens_ ) { const int weight = ptr->weight; if( weight < 1 ) { continue; // rejected! @@ -231,10 +240,11 @@ class mapgen_basic_container : public std::vectorsetup(); } - // @TODO clear: clear(); + // Not needed anymore, pointers are now stored in weights_ (or not used at all) + mapgens_.clear(); } void check_consistency( const std::string &key ) { - for( auto &mapgen_function_ptr : *this ) { + for( auto &mapgen_function_ptr : mapgens_ ) { mapgen_function_ptr->check( key ); } } @@ -341,7 +351,7 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( jio.has_string( "name" ) ) { const std::string mgname = jio.get_string( "name" ); if( mgname == id_base ) { - oter_mapgen[id_base][ default_idx ]->weight = 0; + oter_mapgen[id_base].erase( default_idx ); } } } From 914d6255c899a0ac916ca1c3ee2205edf88a389b Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:16:36 +0100 Subject: [PATCH 191/219] Make a separate class for oter_mapgen And move all the functions that deal with it into that class. --- src/mapgen.cpp | 91 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 5b30f648914ec..aa378880af3a2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -249,10 +249,50 @@ class mapgen_basic_container } } }; + +class mapgen_factory +{ + private: + std::map mapgens_; + + public: + void reset() { + mapgens_.clear(); + } + void setup() { + for( auto &omw : mapgens_ ) { + omw.second.setup(); + } + } + void check_consistency() { + for( auto &oter_definition : mapgens_ ) { + oter_definition.second.check_consistency( oter_definition.first ); + } + } + bool has( const std::string &key ) const { + return mapgens_.count( key ) != 0; + } + int add( const std::string &key, const std::shared_ptr ptr ) { + return mapgens_[key].add( ptr ); + } + // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. + mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { + const auto fmapit = mapgens_.find( key ); + if( fmapit == mapgens_.end() ) { + return nullptr; + } + return fmapit->second.pick( hardcoded_weight ); + } + void erase( const std::string &key, const size_t index ) { + mapgens_[key].erase( index ); + } +}; + +static mapgen_factory oter_mapgen; + /* * stores function ref and/or required data */ -std::map oter_mapgen; std::map> > nested_mapgen; std::map> > update_mapgen; @@ -261,9 +301,7 @@ std::map> */ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { - for( auto &omw : oter_mapgen ) { - omw.second.setup(); - } + oter_mapgen.setup(); // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { for( std::unique_ptr &ptr : pr.second ) { @@ -280,9 +318,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup void check_mapgen_definitions() { - for( auto &oter_definition : oter_mapgen ) { - oter_definition.second.check_consistency( oter_definition.first ); - } + oter_mapgen.check_consistency(); for( auto &oter_definition : nested_mapgen ) { for( auto &mapgen_function_ptr : oter_definition.second ) { mapgen_function_ptr->check( oter_definition.first ); @@ -295,23 +331,6 @@ void check_mapgen_definitions() } } -static int register_mapgen_function( const std::string &key, - const std::shared_ptr ptr ) -{ - return oter_mapgen[key].add( ptr ); -} - -// @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. -static mapgen_function *get_mapgen_function( const std::string &key, - const int hardcoded_weight = 0 ) -{ - const auto fmapit = oter_mapgen.find( key ); - if( fmapit == oter_mapgen.end() ) { - return nullptr; - } - return fmapit->second.pick( hardcoded_weight ); -} - ///////////////////////////////////////////////////////////////////////////////// ///// json mapgen functions ///// 1 - init(): @@ -351,7 +370,7 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( jio.has_string( "name" ) ) { const std::string mgname = jio.get_string( "name" ); if( mgname == id_base ) { - oter_mapgen[id_base].erase( default_idx ); + oter_mapgen.erase( id_base, default_idx ); } } } @@ -362,14 +381,14 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, if( mgtype == "builtin" ) { if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { ret = std::make_shared( ptr, mgweight ); - register_mapgen_function( id_base, ret ); + oter_mapgen.add( id_base, ret ); } else { jio.throw_error( "function does not exist", "name" ); } } else if( mgtype == "json" ) { const std::string jstr = jio.get_object( "object" ).str(); ret = std::make_shared( jstr, mgweight, offset ); - register_mapgen_function( id_base, ret ); + oter_mapgen.add( id_base, ret ); } else { jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); } @@ -426,7 +445,7 @@ void load_mapgen( const JsonObject &jo ) for( const std::string mapgenid : row_items ) { const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); if( mgfunc ) { - register_mapgen_function( mapgenid, mgfunc ); + oter_mapgen.add( mapgenid, mgfunc ); } offset.x++; } @@ -443,7 +462,7 @@ void load_mapgen( const JsonObject &jo ) const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); if( mgfunc ) { for( auto &i : mapgenid_list ) { - register_mapgen_function( i, mgfunc ); + oter_mapgen.add( i, mgfunc ); } } } @@ -462,7 +481,7 @@ void load_mapgen( const JsonObject &jo ) void reset_mapgens() { - oter_mapgen.clear(); + oter_mapgen.reset(); nested_mapgen.clear(); update_mapgen.clear(); } @@ -3517,7 +3536,7 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { - if( const auto ptr = get_mapgen_function( "lab_1side" ) ) { + if( const auto ptr = oter_mapgen.pick( "lab_1side" ) ) { ptr->generate( dat ); if( tw == 2 ) { rotate( 2 ); @@ -3535,7 +3554,7 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( terrain_type, t_stairs_down ); } else { const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. - if( const auto ptr = get_mapgen_function( "lab_4side", hardcoded_4side_map_weight ) ) { + if( const auto ptr = oter_mapgen.pick( "lab_4side", hardcoded_4side_map_weight ) ) { ptr->generate( dat ); // If the map template hasn't handled borders, handle them in code. // Rotated maps cannot handle borders and have to be caught in code. @@ -4080,7 +4099,7 @@ void map::draw_lab( mapgendata &dat ) lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. - if( const auto ptr = get_mapgen_function( "lab_finale_1level", hardcoded_finale_map_weight ) ) { + if( const auto ptr = oter_mapgen.pick( "lab_finale_1level", hardcoded_finale_map_weight ) ) { ptr->generate( dat ); // If the map template hasn't handled borders, handle them in code. @@ -7297,7 +7316,7 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - if( const auto ptr = get_mapgen_function( mapgen_id ) ) { + if( const auto ptr = oter_mapgen.pick( mapgen_id ) ) { ptr->generate( dat ); return true; } @@ -7307,12 +7326,12 @@ bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) int register_mapgen_function( const std::string &key ) { if( const auto ptr = get_mapgen_cfunction( key ) ) { - return register_mapgen_function( key, std::make_shared( ptr ) ); + return oter_mapgen.add( key, std::make_shared( ptr ) ); } return -1; } bool has_mapgen_for( const std::string &key ) { - return oter_mapgen.count( key ) != 0; + return oter_mapgen.has( key ); } From 0cc56ffe1020fd4810553991b70d0c43cc6fea22 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:17:23 +0100 Subject: [PATCH 192/219] Replace `auto` with actual type --- src/mapgen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index aa378880af3a2..285c877abceb2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -260,12 +260,12 @@ class mapgen_factory mapgens_.clear(); } void setup() { - for( auto &omw : mapgens_ ) { + for( std::pair &omw : mapgens_ ) { omw.second.setup(); } } void check_consistency() { - for( auto &oter_definition : mapgens_ ) { + for( std::pair &oter_definition : mapgens_ ) { oter_definition.second.check_consistency( oter_definition.first ); } } From b6d1de93cd9fc0b574adbfaa9d9c09d48060b071 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:18:12 +0100 Subject: [PATCH 193/219] Consistent naming: "omw" just like in the other function --- src/mapgen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 285c877abceb2..eba3bd73635c4 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -265,8 +265,8 @@ class mapgen_factory } } void check_consistency() { - for( std::pair &oter_definition : mapgens_ ) { - oter_definition.second.check_consistency( oter_definition.first ); + for( std::pair &omw : mapgens_ ) { + omw.second.check_consistency( omw.first ); } } bool has( const std::string &key ) const { From 82453d24c419fca3454104d0eb240c268bde4983 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:18:47 +0100 Subject: [PATCH 194/219] Consistent naming: just "iter" as there is no need to hint the data type (and what does the "f" even stand for?) --- src/mapgen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index eba3bd73635c4..f8daedd3a5ee7 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -277,11 +277,11 @@ class mapgen_factory } // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { - const auto fmapit = mapgens_.find( key ); - if( fmapit == mapgens_.end() ) { + const auto iter = mapgens_.find( key ); + if( iter == mapgens_.end() ) { return nullptr; } - return fmapit->second.pick( hardcoded_weight ); + return iter->second.pick( hardcoded_weight ); } void erase( const std::string &key, const size_t index ) { mapgens_[key].erase( index ); From cfe428241eaf8a4d54fbe48b368dd0e677e8690c Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 26 Jan 2020 22:50:58 +0100 Subject: [PATCH 195/219] Add usage checks for loaded mapgen instances. This will find mapgen instances that were loaded from JSON, but have no usage within the game (e.g. because the belong to undefined overmap terrain). Register some mapgen ids that are only used within the C++ code as used --- src/mapgen.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index f8daedd3a5ee7..048fd858041d1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -15,6 +15,7 @@ #include #include "clzones.h" +#include "generic_factory.h" #include "computer.h" #include "coordinate_conversions.h" #include "coordinates.h" @@ -255,6 +256,25 @@ class mapgen_factory private: std::map mapgens_; + static std::set get_usages() { + std::set result; + for( const oter_t &elem : overmap_terrains::get_all() ) { + result.insert( elem.get_mapgen_id() ); + result.insert( elem.id.str() ); + } + // Why do I have to repeat the MapExtras here? Wouldn't "MapExtras::factory" be enough? + for( const map_extra &elem : MapExtras::mapExtraFactory().get_all() ) { + if( elem.generator_method == map_extra_method::mapgen ) { + result.insert( elem.generator_id ); + } + } + // Used in C++ code only, see calls to `oter_mapgen.pick()` below + result.insert( "lab_1side" ); + result.insert( "lab_4side" ); + result.insert( "lab_finale_1level" ); + return result; + } + public: void reset() { mapgens_.clear(); @@ -265,8 +285,14 @@ class mapgen_factory } } void check_consistency() { + // Cache all strings that may get looked up here so we don't have to go through + // all the sources for them upon each loop. + const std::set usages = get_usages(); for( std::pair &omw : mapgens_ ) { omw.second.check_consistency( omw.first ); + if( usages.count( omw.first ) == 0 ) { + debugmsg( "Mapgen %s is not used by anything!", omw.first ); + } } } bool has( const std::string &key ) const { @@ -3536,6 +3562,7 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { + // If you remove the usage of "lab_1side" here, remove it from mapgen_factory::get_usages above as well. if( const auto ptr = oter_mapgen.pick( "lab_1side" ) ) { ptr->generate( dat ); if( tw == 2 ) { @@ -3554,6 +3581,7 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( terrain_type, t_stairs_down ); } else { const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. + // If you remove the usage of "lab_4side" here, remove it from mapgen_factory::get_usages above as well. if( const auto ptr = oter_mapgen.pick( "lab_4side", hardcoded_4side_map_weight ) ) { ptr->generate( dat ); // If the map template hasn't handled borders, handle them in code. @@ -4099,6 +4127,7 @@ void map::draw_lab( mapgendata &dat ) lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. + // If you remove the usage of "lab_finale_1level" here, remove it from mapgen_factory::get_usages above as well. if( const auto ptr = oter_mapgen.pick( "lab_finale_1level", hardcoded_finale_map_weight ) ) { ptr->generate( dat ); From 21f406cf0eacdd4b083a53c6e5c82223e87a6199 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Mon, 27 Jan 2020 00:06:08 +0100 Subject: [PATCH 196/219] Add some documentation. --- src/mapgen.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 048fd858041d1..875baedce8742 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -232,6 +232,11 @@ class mapgen_basic_container assert( *ptr ); return ptr->get(); } + /** + * Calls @ref mapgen_function::setup and sets up the internal weighted list using + * the **current** value of @ref mapgen_function::weight. This value may have + * changed since it was first added, so this is needed to recalculate the weighted list. + */ void setup() { for( const std::shared_ptr &ptr : mapgens_ ) { const int weight = ptr->weight; @@ -256,6 +261,7 @@ class mapgen_factory private: std::map mapgens_; + /// Collect all the possible and expected keys that may get used with @ref pick. static std::set get_usages() { std::set result; for( const oter_t &elem : overmap_terrains::get_all() ) { @@ -279,6 +285,7 @@ class mapgen_factory void reset() { mapgens_.clear(); } + /// @see mapgen_basic_container::setup void setup() { for( std::pair &omw : mapgens_ ) { omw.second.setup(); @@ -295,13 +302,19 @@ class mapgen_factory } } } + /** + * Checks whether we have an entry for the given key. + * Note that the entry itself may not contain any valid mapgen instance + * (could all have been removed via @ref erase). + */ bool has( const std::string &key ) const { return mapgens_.count( key ) != 0; } + /// @see mapgen_basic_container::add int add( const std::string &key, const std::shared_ptr ptr ) { return mapgens_[key].add( ptr ); } - // @p hardcoded_weight Weight for an additional entry. If that entry is chosen, a null pointer is returned. + /// @see mapgen_basic_container::pick mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { const auto iter = mapgens_.find( key ); if( iter == mapgens_.end() ) { @@ -309,6 +322,7 @@ class mapgen_factory } return iter->second.pick( hardcoded_weight ); } + /// @see mapgen_basic_container::erase void erase( const std::string &key, const size_t index ) { mapgens_[key].erase( index ); } From 60b371f02b98fb213f5411feba3636ddb46bdbc7 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 00:11:30 +0100 Subject: [PATCH 197/219] Encapsulate the `mapgen_function` function pointers within `mapgen_factory` Don't expose them at all. All access to them is done internally. --- src/mapgen.cpp | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 875baedce8742..50f5d719d9a7c 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -216,21 +216,26 @@ class mapgen_basic_container mapgens_[index]->weight = 0; } /** - * Pick a mapgen function randomly. + * Pick a mapgen function randomly and call its generate function. + * This basically runs the mapgen functions with the given @ref mapgendata + * as argument. + * @return Whether the mapgen function has been run. It may not get run if + * the list of mapgen functions is effectively empty. * @p hardcoded_weight Weight for an additional entry. If that entry is chosen, - * a null pointer is returned. If unsure, just use 0 for it. + * false is returned. If unsure, just use 0 for it. */ - mapgen_function *pick( const int hardcoded_weight ) const { + bool generate( mapgendata &dat, const int hardcoded_weight ) const { if( hardcoded_weight > 0 && rng( 1, weights_.get_weight() + hardcoded_weight ) > weights_.get_weight() ) { - return nullptr; + return false; } const std::shared_ptr *const ptr = weights_.pick(); if( !ptr ) { - return nullptr; + return false; } assert( *ptr ); - return ptr->get(); + ( *ptr )->generate( dat ); + return true; } /** * Calls @ref mapgen_function::setup and sets up the internal weighted list using @@ -274,7 +279,7 @@ class mapgen_factory result.insert( elem.generator_id ); } } - // Used in C++ code only, see calls to `oter_mapgen.pick()` below + // Used in C++ code only, see calls to `oter_mapgen.generate()` below result.insert( "lab_1side" ); result.insert( "lab_4side" ); result.insert( "lab_finale_1level" ); @@ -314,13 +319,13 @@ class mapgen_factory int add( const std::string &key, const std::shared_ptr ptr ) { return mapgens_[key].add( ptr ); } - /// @see mapgen_basic_container::pick - mapgen_function *pick( const std::string &key, const int hardcoded_weight = 0 ) const { + /// @see mapgen_basic_container::generate + bool generate( mapgendata &dat, const std::string &key, const int hardcoded_weight = 0 ) const { const auto iter = mapgens_.find( key ); if( iter == mapgens_.end() ) { - return nullptr; + return false; } - return iter->second.pick( hardcoded_weight ); + return iter->second.generate( dat, hardcoded_weight ); } /// @see mapgen_basic_container::erase void erase( const std::string &key, const size_t index ) { @@ -3577,8 +3582,7 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { // If you remove the usage of "lab_1side" here, remove it from mapgen_factory::get_usages above as well. - if( const auto ptr = oter_mapgen.pick( "lab_1side" ) ) { - ptr->generate( dat ); + if( oter_mapgen.generate( dat, "lab_1side" ) ) { if( tw == 2 ) { rotate( 2 ); } @@ -3596,8 +3600,7 @@ void map::draw_lab( mapgendata &dat ) } else { const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. // If you remove the usage of "lab_4side" here, remove it from mapgen_factory::get_usages above as well. - if( const auto ptr = oter_mapgen.pick( "lab_4side", hardcoded_4side_map_weight ) ) { - ptr->generate( dat ); + if( oter_mapgen.generate( dat, "lab_4side", hardcoded_4side_map_weight ) ) { // If the map template hasn't handled borders, handle them in code. // Rotated maps cannot handle borders and have to be caught in code. // We determine if a border isn't handled by checking the east-facing @@ -4142,9 +4145,7 @@ void map::draw_lab( mapgendata &dat ) const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. // If you remove the usage of "lab_finale_1level" here, remove it from mapgen_factory::get_usages above as well. - if( const auto ptr = oter_mapgen.pick( "lab_finale_1level", hardcoded_finale_map_weight ) ) { - ptr->generate( dat ); - + if( oter_mapgen.generate( dat, "lab_finale_1level", hardcoded_finale_map_weight ) ) { // If the map template hasn't handled borders, handle them in code. // Rotated maps cannot handle borders and have to be caught in code. // We determine if a border isn't handled by checking the east-facing @@ -7359,11 +7360,7 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - if( const auto ptr = oter_mapgen.pick( mapgen_id ) ) { - ptr->generate( dat ); - return true; - } - return false; + return oter_mapgen.generate( dat, mapgen_id ); } int register_mapgen_function( const std::string &key ) From 505142c30697ec2fb55eb2f910c9dbc31ff3218a Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 11:32:24 +0100 Subject: [PATCH 198/219] Remove mapgen entries for overmap terrain "null". This terrain should never appears and is therefor never generated. Removing it here may free up some memory. --- src/mapgen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 50f5d719d9a7c..b2a95e240a090 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -295,6 +295,8 @@ class mapgen_factory for( std::pair &omw : mapgens_ ) { omw.second.setup(); } + // Dummy entry, overmap terrain null should never appear and is therefor never generated. + mapgens_.erase( "null" ); } void check_consistency() { // Cache all strings that may get looked up here so we don't have to go through From 19d14b374ae8b61f201710076371f47e1447892a Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 14:37:43 +0100 Subject: [PATCH 199/219] Follow recommendation of clang-tidy --- src/mapgen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index b2a95e240a090..3b2b9f24fd20e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -437,7 +437,7 @@ load_mapgen_function( const JsonObject &jio, const std::string &id_base, ret = std::make_shared( jstr, mgweight, offset ); oter_mapgen.add( id_base, ret ); } else { - jio.throw_error( "invalid value: must be \"builtin\" or \"json\")", "method" ); + jio.throw_error( R"(invalid value: must be "builtin" or "json")", "method" ); } return ret; } From 7adcd44ec4e7e3e3097e015bd25f0c2825eb096d Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 15:58:30 +0100 Subject: [PATCH 200/219] Make parameter offset of load_mapgen_function mandatory. Adds the default value to all calls to it that did not supply a value. --- src/mapgen.cpp | 4 ++-- src/mapgen.h | 2 +- src/overmap.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 3b2b9f24fd20e..dc8ab33768038 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -506,7 +506,7 @@ void load_mapgen( const JsonObject &jo ) } if( !mapgenid_list.empty() ) { const std::string mapgenid = mapgenid_list[0]; - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, point_zero ); if( mgfunc ) { for( auto &i : mapgenid_list ) { oter_mapgen.add( i, mgfunc ); @@ -515,7 +515,7 @@ void load_mapgen( const JsonObject &jo ) } } } else if( jo.has_string( "om_terrain" ) ) { - load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1 ); + load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1, point_zero ); } else if( jo.has_string( "nested_mapgen_id" ) ) { load_nested_mapgen( jo, jo.get_string( "nested_mapgen_id" ) ); } else if( jo.has_string( "update_mapgen_id" ) ) { diff --git a/src/mapgen.h b/src/mapgen.h index ec114176152df..a73284aeead6e 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -371,7 +371,7 @@ class mapgen_function_json_nested : public mapgen_function_json_base * Load mapgen function of any type from a json object */ std::shared_ptr load_mapgen_function( const JsonObject &jio, - const std::string &id_base, int default_idx, const point &offset = point_zero ); + const std::string &id_base, int default_idx, const point &offset ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) diff --git a/src/overmap.cpp b/src/overmap.cpp index fd577a0639c84..ab859a3634d8e 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -534,7 +534,7 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin } if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { - load_mapgen_function( jio, fmapkey, default_idx ); + load_mapgen_function( jio, fmapkey, default_idx, point_zero ); } } } From 1132ae5b8e7993bb60cea49664d003d7d1fd0e8b Mon Sep 17 00:00:00 2001 From: BevapDin Date: Sun, 2 Feb 2020 16:33:53 +0100 Subject: [PATCH 201/219] Remove default_idx parameter from load_mapgen_function. This feature is not available anymore. It was added by 04e45eabbdd80a238e61c771fcf0c05073b5ca54 without any explanation. --- src/mapgen.cpp | 30 ++++-------------------------- src/mapgen.h | 2 +- src/overmap.cpp | 8 ++------ 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index dc8ab33768038..c132880807012 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -207,14 +207,6 @@ class mapgen_basic_container mapgens_.push_back( ptr ); return mapgens_.size() - 1; } - void erase( const size_t index ) { - if( index > mapgens_.size() ) { - return; - } - assert( mapgens_[index] ); - // Can't actually erase it as this might invalid the index stored elsewhere - mapgens_[index]->weight = 0; - } /** * Pick a mapgen function randomly and call its generate function. * This basically runs the mapgen functions with the given @ref mapgendata @@ -329,10 +321,6 @@ class mapgen_factory } return iter->second.generate( dat, hardcoded_weight ); } - /// @see mapgen_basic_container::erase - void erase( const std::string &key, const size_t index ) { - mapgens_[key].erase( index ); - } }; static mapgen_factory oter_mapgen; @@ -406,21 +394,11 @@ static void set_mapgen_defer( const JsonObject &jsi, const std::string &member, * load a single mapgen json structure; this can be inside an overmap_terrain, or on it's own. */ std::shared_ptr -load_mapgen_function( const JsonObject &jio, const std::string &id_base, - int default_idx, const point &offset ) +load_mapgen_function( const JsonObject &jio, const std::string &id_base, const point &offset ) { int mgweight = jio.get_int( "weight", 1000 ); std::shared_ptr ret; if( mgweight <= 0 || jio.get_bool( "disabled", false ) ) { - const std::string mgtype = jio.get_string( "method" ); - if( default_idx != -1 && mgtype == "builtin" ) { - if( jio.has_string( "name" ) ) { - const std::string mgname = jio.get_string( "name" ); - if( mgname == id_base ) { - oter_mapgen.erase( id_base, default_idx ); - } - } - } jio.allow_omitted_members(); return nullptr; // nothing } @@ -490,7 +468,7 @@ void load_mapgen( const JsonObject &jo ) point offset; for( JsonArray row_items : ja ) { for( const std::string mapgenid : row_items ) { - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, offset ); if( mgfunc ) { oter_mapgen.add( mapgenid, mgfunc ); } @@ -506,7 +484,7 @@ void load_mapgen( const JsonObject &jo ) } if( !mapgenid_list.empty() ) { const std::string mapgenid = mapgenid_list[0]; - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, point_zero ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, point_zero ); if( mgfunc ) { for( auto &i : mapgenid_list ) { oter_mapgen.add( i, mgfunc ); @@ -515,7 +493,7 @@ void load_mapgen( const JsonObject &jo ) } } } else if( jo.has_string( "om_terrain" ) ) { - load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1, point_zero ); + load_mapgen_function( jo, jo.get_string( "om_terrain" ), point_zero ); } else if( jo.has_string( "nested_mapgen_id" ) ) { load_nested_mapgen( jo, jo.get_string( "nested_mapgen_id" ) ); } else if( jo.has_string( "update_mapgen_id" ) ) { diff --git a/src/mapgen.h b/src/mapgen.h index a73284aeead6e..8e051518b3673 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -371,7 +371,7 @@ class mapgen_function_json_nested : public mapgen_function_json_base * Load mapgen function of any type from a json object */ std::shared_ptr load_mapgen_function( const JsonObject &jio, - const std::string &id_base, int default_idx, const point &offset ); + const std::string &id_base, const point &offset ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) diff --git a/src/overmap.cpp b/src/overmap.cpp index ab859a3634d8e..73985f240d792 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -527,14 +527,10 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin { const std::string fmapkey( id_base + suffix ); const std::string jsonkey( "mapgen" + suffix ); - bool default_mapgen = jo.get_bool( "default_mapgen", true ); - int default_idx = -1; - if( default_mapgen ) { - default_idx = register_mapgen_function( fmapkey ); - } + register_mapgen_function( fmapkey ); if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { - load_mapgen_function( jio, fmapkey, default_idx, point_zero ); + load_mapgen_function( jio, fmapkey, point_zero ); } } } From 1e163e173a9a8534a2d1b2ed488b9def885dfdb8 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Tue, 10 Mar 2020 07:43:24 +0100 Subject: [PATCH 202/219] Refactor loading bonuses (#36562) --- data/json/martialarts.json | 189 ++++++---- data/json/martialarts_fictional.json | 103 ++++-- data/json/techniques.json | 323 ++++++++++++------ data/mods/Aftershock/player/techniques.json | 2 +- .../CRT_EXPANSION/martial/CRT_Bladework.json | 43 ++- .../martial/CRT_EnforcementBuff.json | 60 +++- .../CRT_EXPANSION/martial/CRT_MeleeBuffs.json | 97 ++++-- .../martial/crt_gun_techniques.json | 24 +- .../martial/dragonslayertechn.json | 47 ++- .../CRT_EXPANSION/martial/generaltechn.json | 93 +++-- .../mods/CRT_EXPANSION/martial/stabtechn.json | 30 +- data/mods/MMA/martialarts.json | 9 +- data/mods/MMA/techniques.json | 20 +- doc/JSON_INFO.md | 1 - doc/MARTIALART_JSON.md | 48 +-- src/bonuses.cpp | 46 +-- src/bonuses.h | 5 +- 17 files changed, 773 insertions(+), 367 deletions(-) diff --git a/data/json/martialarts.json b/data/json/martialarts.json index 5bdb0fa1cb50c..ffcecc7f36d5a 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -33,7 +33,7 @@ "name": "Aikido Stance", "description": "By disregarding offensive in favor of self-defense, you are better at protecting.\n\nBlocked damage reduced by 100%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "dex", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "dex", "scale": 1.0 } ] }, { "id": "buff_aikido_static2", @@ -43,7 +43,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "bonus_dodges": 1, "bonus_blocks": 1, - "flat_bonuses": [ [ "block", "dex", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "dex", "scale": 1.0 } ] }, { "id": "buff_aikido_static3", @@ -78,7 +78,7 @@ "name": "Boxing Stance", "description": "A solid stance allows you block more damage than normal and deliver better punches.\n\n+2 Bash damage, Blocked damge reduced by 50%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "str", 0.5 ], [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onmove_buffs": [ @@ -90,7 +90,7 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 2, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -101,7 +101,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] } ], "techniques": [ "tec_boxing_rapid", "tec_boxing_cross", "tec_boxing_upper", "tec_boxing_counter" ] @@ -143,7 +143,7 @@ "description": "You never stop moving while performing the ginga. This makes you very mobile while fighting.\n\n+1.0 Dodge skill, +1 Dodge attempts.", "unarmed_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -155,7 +155,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 2, "max_stacks": 3, - "mult_bonuses": [ [ "damage", "bash", 1.15 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.15 } ] } ], "onmove_buffs": [ @@ -166,7 +166,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 3, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "techniques": [ @@ -191,7 +191,10 @@ "name": "Crane's Precision", "description": "Your attacks strike at your opponents weakness with speed and precision instead of brute force.\nDexterity increases melee damage instead of Strength.\n\nBash damage increased by 75%% of Dexterity but decreased by 75%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "damage", "bash", "dex", 0.75 ], [ "damage", "bash", "str", -0.75 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "dex", "scale": 0.75 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": -0.75 } + ] } ], "onmove_buffs": [ @@ -202,7 +205,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 2, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -214,7 +217,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 2, "bonus_dodges": 1, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "techniques": [ "tec_crane_feint", "tec_crane_break", "tec_crane_counter", "tec_crane_precise" ] @@ -233,7 +236,7 @@ "name": "Dragon's Knowledge", "description": "You plan your attack far in advance relying on your intuition instead of your speed to strike true.\nIntelligence increases Accuracy instead of Dexterity.\n\nAccuracy increased by 25%% of Intelligence but decreased by 25%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", "int", 0.25 ], [ "hit", "dex", -0.25 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "int", "scale": 0.25 }, { "stat": "hit", "scaling-stat": "dex", "scale": -0.25 } ] } ], "onhit_buffs": [ @@ -244,7 +247,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 1, - "flat_bonuses": [ [ "hit", 1.0 ], [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ "tec_dragon_claw", "tec_dragon_blockcounter", "tec_dragon_dodgecounter", "tec_dragon_tail", "tec_dragon_strike" ] @@ -264,7 +267,7 @@ "name": "Eskrima Stance", "description": "You are skilled at getting the most out of your weapons. The term 'weapon' might be very subjective,\n\n+2 Accuracy.", "melee_allowed": true, - "flat_bonuses": [ [ "hit", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 } ] } ], "oncrit_buffs": [ @@ -276,7 +279,11 @@ "melee_allowed": true, "buff_duration": 3, "max_stacks": 3, - "mult_bonuses": [ [ "damage", "bash", 1.15 ], [ "damage", "cut", 1.15 ], [ "damage", "stab", 1.15 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.15 }, + { "stat": "damage", "type": "cut", "scale": 1.15 }, + { "stat": "damage", "type": "stab", "scale": 1.15 } + ] } ], "techniques": [ @@ -354,7 +361,7 @@ "name": "Fencing Stance", "description": "Your side stance minimizes the chances you will be harmed in a combat.\n\nBlocked damage reduced by 50%% of Dexterity.", "melee_allowed": true, - "flat_bonuses": [ [ "block", "dex", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "dex", "scale": 0.5 } ] } ], "onblock_buffs": [ @@ -365,7 +372,7 @@ "skill_requirements": [ { "name": "melee", "level": 1 } ], "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -376,7 +383,7 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "techniques": [ "tec_fencing_feint", "tec_fencing_lunge", "tec_fencing_riposte", "tec_fencing_compound" ], @@ -427,7 +434,7 @@ "description": "You are stalwart and will not budge against any threat.\n\n+2 Block attempts, -1.0 Dodge skill, blocked damage reduced by 50%% of Strength.", "melee_allowed": true, "bonus_blocks": 2, - "flat_bonuses": [ [ "block", "str", 0.5 ], [ "dodge", -1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 }, { "stat": "dodge", "scale": -1.0 } ] } ], "onmove_buffs": [ @@ -438,7 +445,7 @@ "melee_allowed": true, "buff_duration": 1, "bonus_blocks": -2, - "flat_bonuses": [ [ "block", "str", -0.5 ], [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": -0.5 }, { "stat": "dodge", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -460,7 +467,7 @@ "skill_requirements": [ { "name": "melee", "level": 1 } ], "buff_duration": 1, "max_stacks": 3, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "techniques": [ @@ -529,7 +536,7 @@ "name": "Karate Stance", "description": "Your no nonsense stance allows you hit more accurately.\n\n+2 Accuracy.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 } ] } ], "onhit_buffs": [ @@ -542,7 +549,7 @@ "buff_duration": 2, "bonus_blocks": 2, "bonus_dodges": 1, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] } ], "techniques": [ "tec_karate_rapid", "tec_karate_precise", "tec_karate_roundhouse", "tec_karate_counter" ] @@ -564,7 +571,7 @@ "melee_allowed": true, "unarmed_allowed": true, "bonus_blocks": 1, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "techniques": [ @@ -645,7 +652,10 @@ "name": "Leopard's Strategy", "description": "You fight by overwhelming your opponents with speedy strikes that are much harder to defend against.\nDexterity increases melee damage instead of Strength.\n\nBash damage increased by 75%% of Dexterity but decreased by 75%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "damage", "bash", "dex", 0.75 ], [ "damage", "bash", "str", -0.75 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "dex", "scale": 0.75 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": -0.75 } + ] }, { "id": "buff_leopard_static2", @@ -653,7 +663,7 @@ "description": "Just like a cat, you are quick, agile, and hard to pin down.\n\n+1.0 Dodge skill.", "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "onmove_buffs": [ @@ -664,7 +674,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "hit", 2.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 } ] }, { "id": "buff_leopard_onmove2", @@ -674,7 +684,11 @@ "unarmed_allowed": true, "req_buffs": [ "buff_leopard_onmove1" ], "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.25 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.25 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ] } ], "techniques": [ "tec_leopard_rapid", "tec_leopard_feint", "tec_leopard_counter", "tec_leopard_precise" ] @@ -695,7 +709,7 @@ "description": "Through chivalry and vigilance, your defense with a blade has increased.\n\n+1 Dodge attempts, blocked damage decreased by 50%% of Strength.", "melee_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] } ], "onblock_buffs": [ @@ -761,7 +775,7 @@ "name": "Muay Thai Stance", "description": "Strength is everything in Muay Thai and you know how to make the most of yours.\n\nBlocked damage decreased by 50%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] } ], "ongethit_buffs": [ @@ -772,7 +786,10 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "buff_duration": 5, - "flat_bonuses": [ [ "damage", "bash", "str", 0.25 ], [ "block", "str", 0.5 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "block", "scaling-stat": "str", "scale": 0.5 } + ] } ], "techniques": [ "tec_muay_thai_elbow", "tec_muay_thai_kick", "tec_muay_thai_knee", "tec_muay_thai_break" ] @@ -801,7 +818,11 @@ "description": "To a true shinobi, the first strike and the last strike are one in the same.\n\n+50%% all damage.", "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] } ], "onattack_buffs": [ @@ -812,7 +833,11 @@ "unarmed_allowed": true, "melee_allowed": true, "buff_duration": 3, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] } ], "onmove_buffs": [ @@ -824,7 +849,7 @@ "unarmed_allowed": true, "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "dodge", 1.0 ], [ "hit", "dex", 0.2 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 }, { "stat": "hit", "scaling-stat": "dex", "scale": 0.2 } ] } ], "onkill_buffs": [ @@ -837,7 +862,7 @@ "melee_allowed": true, "buff_duration": 3, "bonus_dodges": 2, - "flat_bonuses": [ [ "speed", 10.0 ] ] + "flat_bonuses": [ { "stat": "speed", "scale": 10.0 } ] } ], "techniques": [ "tec_ninjutsu_swift", "tec_ninjutsu_takedown", "tec_ninjutsu_precise" ], @@ -927,7 +952,11 @@ "name": "Niten Ichi-Ryu Stance", "description": "Cautious watchful eyes\nmeasure and display your skill.\nPractice makes perfect.\n\nBash and Cut armor penetration increased by 50%% of Perception, blocked damage reduced by 100%% of Perception.", "melee_allowed": true, - "flat_bonuses": [ [ "arpen", "cut", "per", 0.5 ], [ "arpen", "bash", "per", 0.5 ], [ "block", "per", 1.0 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "cut", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "block", "scaling-stat": "per", "scale": 1.0 } + ] } ], "onmove_buffs": [ @@ -937,7 +966,7 @@ "description": "Blackened like darkness,\nnightmares approach from all sides.\nFlee at any cost!\n\n-5.0 Dodge skill.\nLasts 1 turn.", "melee_allowed": true, "buff_duration": 1, - "flat_bonuses": [ [ "dodge", -5.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": -5.0 } ] } ], "onattack_buffs": [ @@ -948,7 +977,11 @@ "melee_allowed": true, "buff_duration": 1, "max_stacks": 5, - "flat_bonuses": [ [ "dodge", -1.0 ], [ "damage", "cut", -1.0 ], [ "damage", "bash", -1.0 ] ] + "flat_bonuses": [ + { "stat": "dodge", "scale": -1.0 }, + { "stat": "damage", "type": "cut", "scale": -1.0 }, + { "stat": "damage", "type": "bash", "scale": -1.0 } + ] } ], "ondodge_buffs": [ @@ -968,7 +1001,7 @@ "description": "The eye of the storm,\na fleeting moment of peace,\ngone without a trace.\n\n+2 Accuracy, Dodge skill increased by 50%% of Perception.\nLasts 2 turns.", "melee_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "hit", 2.0 ], [ "dodge", "per", 0.5 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 2.0 }, { "stat": "dodge", "scaling-stat": "per", "scale": 0.5 } ] } ], "techniques": [ "niten_water_cut", "niten_red_leaf", "niten_stone_cut", "niten_timing_attack", "niten_feint" ], @@ -1007,7 +1040,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.1 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 } ] } ], "onhit_buffs": [ @@ -1019,7 +1052,7 @@ "unarmed_allowed": true, "req_buffs": [ "buff_pankration_ondodge" ], "buff_duration": 1, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] } ], "techniques": [ @@ -1058,7 +1091,7 @@ "melee_allowed": true, "buff_duration": 2, "max_stacks": 3, - "flat_bonuses": [ [ "hit", "dex", 0.15 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "dex", "scale": 0.15 } ] } ], "onmove_buffs": [ @@ -1155,7 +1188,7 @@ "name": "Snake's Sight", "description": "You are patient and know where to hit your opponent for the best results.\n\nPerception increases Accuracy instead of Dexterity. Accuracy increased by 25%% of Perception but decreased by 25%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", "per", 0.25 ], [ "hit", "dex", -0.25 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "per", "scale": 0.25 }, { "stat": "hit", "scaling-stat": "dex", "scale": -0.25 } ] } ], "onpause_buffs": [ @@ -1167,7 +1200,12 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 3, - "flat_bonuses": [ [ "hit", 1.0 ], [ "arpen", "bash", "per", 0.5 ], [ "arpen", "cut", "per", 0.5 ], [ "arpen", "stab", "per", 0.5 ] ] + "flat_bonuses": [ + { "stat": "hit", "scale": 1.0 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "per", "scale": 0.5 } + ] } ], "techniques": [ "tec_snake_rapid", "tec_snake_feint", "tec_snake_break", "tec_snake_precise" ] @@ -1198,7 +1236,11 @@ "melee_allowed": true, "buff_duration": 1, "bonus_blocks": -1, - "mult_bonuses": [ [ "damage", "bash", 1.1 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.1 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ] } ], "techniques": [ "tec_sojutsu_push", "tec_sojutsu_shove", "tec_sojutsu_trip" ], @@ -1247,14 +1289,14 @@ "name": "Taekwondo Stance", "description": "Using your legs to attack allows your hands to be free for better defense.\n\nBlocked damage decreased by 50%% of Strength.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "str", 0.5 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "str", "scale": 0.5 } ] }, { "id": "buff_taekwondo_static2", "name": "Unhindered", "description": "Your attacks are stronger if you are not holding anything in your hands.\n\n+33%% bash damage when not using a weapon.", "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.33 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 } ] } ], "techniques": [ @@ -1281,7 +1323,7 @@ "description": "You are focused of defense and predicting your opponents attacks.\n\n+1 Block attempts, blocked damage reduced by 100%% Perception.", "unarmed_allowed": true, "bonus_blocks": 1, - "flat_bonuses": [ [ "block", "per", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "per", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -1292,7 +1334,10 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "buff_duration": 2, - "flat_bonuses": [ [ "arpen", "bash", "per", 0.5 ], [ "hit", "per", 0.2 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "hit", "scaling-stat": "per", "scale": 0.2 } + ] } ], "onpause_buffs": [ @@ -1303,7 +1348,7 @@ "unarmed_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 3, - "flat_bonuses": [ [ "block", "per", 0.5 ], [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "per", "scale": 0.5 }, { "stat": "dodge", "scale": 1.0 } ] } ], "techniques": [ "tec_taichi_disarm", "tec_taichi_palm", "tec_taichi_counter", "tec_taichi_precise" ] @@ -1321,7 +1366,7 @@ "name": "Tiger's Strength", "description": "You do not need defense. You do not need a plan. You need strength. Strength will break your opponents' defenses and overwhelm them completely.\nStrength increases Accuracy instead of Dexterity.\n\nAccuracy increased by 25%% of Strength but decreased by 25%% of Dexterity.", "unarmed_allowed": true, - "flat_bonuses": [ [ "hit", "str", 0.25 ], [ "hit", "dex", -0.25 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "str", "scale": 0.25 }, { "stat": "hit", "scaling-stat": "dex", "scale": -0.25 } ] } ], "onhit_buffs": [ @@ -1333,7 +1378,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "buff_duration": 3, "max_stacks": 4, - "mult_bonuses": [ [ "damage", "bash", 1.1 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.1 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ] } ], "oncrit_buffs": [ @@ -1345,7 +1394,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "buff_duration": 1, "max_stacks": 2, - "flat_bonuses": [ [ "arpen", "bash", "str", 0.5 ], [ "arpen", "cut", "str", 0.5 ], [ "arpen", "stab", "str", 0.5 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "str", "scale": 0.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "str", "scale": 0.5 } + ] } ], "techniques": [ "tec_tiger_palm", "tec_tiger_takedown" ] @@ -1368,7 +1421,7 @@ "name": "Chi-Sao Sensitivity", "description": "You have a greater understanding of balance and technique. This gives you a better chance to avoid your opponent's attacks.\n\n Dodging Skill increased by 15%% of Perception. Blocked damage reduced by 50%% of Perception.", "unarmed_allowed": true, - "flat_bonuses": [ [ "block", "per", 0.5 ], [ "dodge", "per", 0.15 ] ] + "flat_bonuses": [ { "stat": "block", "scaling-stat": "per", "scale": 0.5 }, { "stat": "dodge", "scaling-stat": "per", "scale": 0.15 } ] } ], "onhit_buffs": [ @@ -1380,7 +1433,7 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 3, - "mult_bonuses": [ [ "movecost", 0.9 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.9 } ] } ], "onpause_buffs": [ @@ -1391,7 +1444,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "hit", "per", 0.2 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "per", "scale": 0.2 } ] } ], "techniques": [ @@ -1416,7 +1469,7 @@ "name": "Zui Quan Stance", "description": "Others might think you stumble about at random but you know better. Each movement is calculated to make evading harm easier.\n\nDodging Skill increased by 15%% of Intelligence.", "unarmed_allowed": true, - "flat_bonuses": [ [ "dodge", "int", 0.15 ] ] + "flat_bonuses": [ { "stat": "dodge", "scaling-stat": "int", "scale": 0.15 } ] }, { "id": "buff_zuiquan_static2", @@ -1425,7 +1478,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "hit", "int", 0.15 ] ] + "flat_bonuses": [ { "stat": "hit", "scaling-stat": "int", "scale": 0.15 } ] } ], "onmove_buffs": [ @@ -1448,7 +1501,11 @@ "unarmed_allowed": true, "buff_duration": 1, "max_stacks": 4, - "flat_bonuses": [ [ "arpen", "bash", "int", 0.25 ], [ "arpen", "cut", "int", 0.25 ], [ "arpen", "stab", "int", 0.25 ] ] + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "int", "scale": 0.25 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "int", "scale": 0.25 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "int", "scale": 0.25 } + ] } ], "techniques": [ "tec_zuiquan_feint", "tec_zuiquan_break", "tec_zuiquan_counter" ] @@ -1468,10 +1525,10 @@ "description": "+Strength bash armor, +Dexterity acid armor, +Intelligence electricity armor, +Perception fire armor.", "unarmed_allowed": true, "flat_bonuses": [ - [ "armor", "bash", "str", 1.0 ], - [ "armor", "cut", "dex", 1.0 ], - [ "armor", "electric", "int", 1.0 ], - [ "armor", "heat", "per", 1.0 ] + { "stat": "armor", "type": "bash", "scaling-stat": "str", "scale": 1.0 }, + { "stat": "armor", "type": "cut", "scaling-stat": "dex", "scale": 1.0 }, + { "stat": "armor", "type": "electric", "scaling-stat": "int", "scale": 1.0 }, + { "stat": "armor", "type": "heat", "scaling-stat": "per", "scale": 1.0 } ] } ], @@ -1483,7 +1540,7 @@ "unarmed_allowed": true, "buff_duration": 3, "max_stacks": 2, - "flat_bonuses": [ [ "damage", "electric", "per", 1.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "electric", "scaling-stat": "per", "scale": 1.0 } ] } ], "onmiss_buffs": [ @@ -1494,7 +1551,7 @@ "unarmed_allowed": true, "buff_duration": 2, "max_stacks": 5, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onkill_buffs": [ @@ -1504,7 +1561,7 @@ "description": "YOU ARE ON FIRE! +5 fire damage for 5 turns.", "unarmed_allowed": true, "buff_duration": 5, - "flat_bonuses": [ [ "damage", "heat", 5.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "heat", "scale": 5.0 } ] } ], "techniques": [ "tec_debug_slow", "tec_debug_arpen" ] diff --git a/data/json/martialarts_fictional.json b/data/json/martialarts_fictional.json index a03362af6ac57..7c9bfac7a873c 100644 --- a/data/json/martialarts_fictional.json +++ b/data/json/martialarts_fictional.json @@ -18,7 +18,7 @@ "unarmed_allowed": true, "melee_allowed": true, "bonus_blocks": 2, - "flat_bonuses": [ [ "hit", 1.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 1.0 } ] } ], "onkill_buffs": [ @@ -31,7 +31,12 @@ "skill_requirements": [ { "name": "melee", "level": 4 } ], "buff_duration": 3, "max_stacks": 3, - "flat_bonuses": [ [ "damage", "bash", 2.0 ], [ "damage", "cut", 2.0 ], [ "damage", "stab", 2.0 ], [ "hit", 1.0 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 2.0 }, + { "stat": "damage", "type": "cut", "scale": 2.0 }, + { "stat": "damage", "type": "stab", "scale": 2.0 }, + { "stat": "hit", "scale": 1.0 } + ] } ], "techniques": [ @@ -63,7 +68,7 @@ "unarmed_allowed": true, "buff_duration": 3, "max_stacks": 4, - "flat_bonuses": [ [ "movecost", -4.0 ] ] + "flat_bonuses": [ { "stat": "movecost", "scale": -4.0 } ] } ], "oncrit_buffs": [ @@ -74,7 +79,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ "tec_centipede_rapid", "tec_centipede_break", "tec_centipede_bite", "tec_centipede_disarm" ] @@ -94,7 +99,7 @@ "description": "By briefly scaling, leaping, or pushing off a nearby wall, you can avoid the worst of your opponents attacks.\n\n+3.0 Dodge skill when near a wall.\nEnables \"Lizard Tail\" and \"Lizard Wall Counter\" techniques when near a wall.", "unarmed_allowed": true, "wall_adjacent": true, - "flat_bonuses": [ [ "dodge", 3.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 3.0 } ] } ], "onhit_buffs": [ @@ -105,7 +110,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "buff_duration": 4, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onmove_buffs": [ @@ -116,7 +121,7 @@ "unarmed_allowed": true, "wall_adjacent": true, "buff_duration": 3, - "flat_bonuses": [ [ "hit", 3.0 ] ] + "flat_bonuses": [ { "stat": "hit", "scale": 3.0 } ] } ], "techniques": [ "tec_lizard_strike", "tec_lizard_break", "tec_lizard_wallcounter", "tec_lizard_counter", "tec_lizard_tail" ] @@ -135,7 +140,7 @@ "name": "Scorpion's Venom", "description": "Your venom is a constant threat that nothing can escape from.\n\n+2 bashing damage.", "unarmed_allowed": true, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "onattack_buffs": [ @@ -158,7 +163,11 @@ "unarmed_allowed": true, "buff_duration": 2, "max_stacks": 2, - "mult_bonuses": [ [ "damage", "bash", 1.1 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.1 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ] } ], "techniques": [ "tec_scorpion_roundhouse", "tec_scorpion_precise", "tec_scorpion_brutal" ] @@ -178,7 +187,11 @@ "description": "Your body is as strong as iron but only if you don't move.\n\n+6 bash, cut, and stab armor.", "//": "FWIW, this is twice the amount of armor provided by bionic plating.", "unarmed_allowed": true, - "flat_bonuses": [ [ "armor", "bash", 6.0 ], [ "armor", "cut", 6.0 ], [ "armor", "stab", 6.0 ] ] + "flat_bonuses": [ + { "stat": "armor", "type": "bash", "scale": 6.0 }, + { "stat": "armor", "type": "cut", "scale": 6.0 }, + { "stat": "armor", "type": "stab", "scale": 6.0 } + ] } ], "onmove_buffs": [ @@ -189,7 +202,11 @@ "unarmed_allowed": true, "buff_duration": 6, "max_stacks": 6, - "flat_bonuses": [ [ "armor", "bash", -1.0 ], [ "armor", "cut", -1.0 ], [ "armor", "stab", -1.0 ] ] + "flat_bonuses": [ + { "stat": "armor", "type": "bash", "scale": -1.0 }, + { "stat": "armor", "type": "cut", "scale": -1.0 }, + { "stat": "armor", "type": "stab", "scale": -1.0 } + ] } ], "onpause_buffs": [ @@ -200,7 +217,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "armor", "bash", 3.0 ], [ "armor", "cut", 3.0 ], [ "armor", "stab", 3.0 ] ] + "flat_bonuses": [ + { "stat": "armor", "type": "bash", "scale": 3.0 }, + { "stat": "armor", "type": "cut", "scale": 3.0 }, + { "stat": "armor", "type": "stab", "scale": 3.0 } + ] } ], "ongethit_buffs": [ @@ -211,7 +232,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "buff_duration": 5, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ "tec_toad_counter", "tec_toad_critcounter", "tec_toad_grab" ] @@ -230,7 +251,7 @@ "name": "Viper's Patience", "description": "Every snake waits for the perfect moment to strike. Turn your opponents' mistakes into your opportunity to strike!\n\n+1.0 Dodge skill.", "unarmed_allowed": true, - "flat_bonuses": [ [ "dodge", 1.0 ] ] + "flat_bonuses": [ { "stat": "dodge", "scale": 1.0 } ] } ], "ondodge_buffs": [ @@ -249,7 +270,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "buff_duration": 3, - "flat_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] } ], "techniques": [ @@ -280,7 +301,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -299,7 +320,7 @@ "name": "Measured Strike (melee)", "messages": [ "You make an efficient strike against %s", " makes an efficient strike against %s" ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -309,7 +330,7 @@ "unarmed_allowed": true, "unarmed_weapons_allowed": false, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -319,7 +340,11 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ], "stun_dur": 1 }, { @@ -353,7 +378,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -365,7 +390,7 @@ "wall_adjacent": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -391,7 +416,7 @@ "weighting": 2, "knockback_dist": 1, "knockback_spread": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -402,7 +427,7 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -421,7 +446,12 @@ "name": "Viper Fist", "messages": [ "You quickly chop %s", " quickly chops %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -433,7 +463,7 @@ "req_buffs": [ "buff_venom_snake_ondodge1" ], "crit_tec": true, "stun_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 1.33 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 } ] }, { "type": "technique", @@ -445,7 +475,7 @@ "stunned_target": true, "weighting": 2, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -464,7 +494,7 @@ "name": "Roundhouse Kick", "messages": [ "You roundhouse kick %s", " roundhouse kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -476,7 +506,7 @@ "stun_dur": 2, "knockback_dist": 3, "powerful_knockback": true, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ], "messages": [ "Your Stinger Kick sends %s flying", "'s Stinger Kick sends %s flying" ] }, { @@ -488,7 +518,7 @@ "unarmed_allowed": true, "req_buffs": [ "buff_scorpion_onmove" ], "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -499,7 +529,7 @@ "unarmed_allowed": true, "block_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -511,7 +541,7 @@ "block_counter": true, "crit_tec": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -522,7 +552,7 @@ "unarmed_allowed": true, "crit_ok": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -540,7 +570,12 @@ "name": "Centipede Strike", "messages": [ "You swiftly hit %s", " swiftly hits %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -551,7 +586,7 @@ "unarmed_allowed": true, "crit_tec": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", diff --git a/data/json/techniques.json b/data/json/techniques.json index a0feab2636216..b9c99e8a0d397 100644 --- a/data/json/techniques.json +++ b/data/json/techniques.json @@ -10,7 +10,7 @@ "id": "WBLOCK_1", "name": "Block", "dummy": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You block %s", " blocks %s" ], "description": "Medium blocking ability" }, @@ -19,7 +19,7 @@ "id": "WBLOCK_2", "name": "Parry", "dummy": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You parry %s", " parries %s" ], "description": "High blocking ability" }, @@ -28,7 +28,7 @@ "id": "WBLOCK_3", "name": "Shield", "dummy": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You shield against %s", " shields against %s" ], "description": "Very high blocking ability" }, @@ -101,7 +101,12 @@ "name": "Rapid Strike", "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ], "messages": [ "You quickly strike %s", " quickly strikes %s" ], "description": "50% moves, 66% damage" }, @@ -111,7 +116,7 @@ "name": "Vorpal Strike", "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "cut", 99 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "cut", "scale": 99 } ], "crit_tec": true, "weighting": -250, "messages": [ @@ -165,7 +170,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ], "messages": [ "You counter-attack %s", " counter-attacks %s" ] }, { @@ -212,7 +217,7 @@ "disarms": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -226,7 +231,7 @@ "crit_ok": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -241,7 +246,7 @@ "crit_ok": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -257,7 +262,7 @@ "disarms": true, "down_dur": 1, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -280,7 +285,7 @@ "name": "Cross", "messages": [ "You throw a heavy cross at %s", " throws a cross at %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -295,7 +300,7 @@ "knockback_spread": 1, "stun_dur": 1, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -304,7 +309,12 @@ "messages": [ "You quickly jab %s", " quickly jabs at %s" ], "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -315,7 +325,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -346,7 +356,7 @@ "melee_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -357,7 +367,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -433,7 +443,7 @@ "name": "Push Kick", "messages": [ "You push kick %s", " push kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -443,7 +453,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -455,7 +465,7 @@ "req_buffs": [ "buff_capoeira_onmove" ], "weighting": 2, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.75 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 } ] }, { "type": "technique", @@ -468,7 +478,7 @@ "weighting": 2, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.75 ], [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 }, { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -501,7 +511,7 @@ "unarmed_allowed": true, "dodge_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -514,7 +524,7 @@ "knockback_dist": 1, "knockback_spread": 1, "stun_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -522,7 +532,7 @@ "name": "Dragon Claw", "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ], "messages": [ "You lash out at %s with a Dragon Claw", " lashes out at %s with a Dragon Claw" ] }, { @@ -535,7 +545,12 @@ "req_buffs": [ "buff_dragon_onhit" ], "block_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -547,7 +562,12 @@ "req_buffs": [ "buff_dragon_onhit" ], "dodge_counter": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -559,7 +579,7 @@ "crit_tec": true, "stunned_target": true, "down_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -571,7 +591,7 @@ "crit_tec": true, "downed_target": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -580,7 +600,7 @@ "messages": [ "You round strike %s", " round strikes %s" ], "skill_requirements": [ { "name": "melee", "level": 4 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.6 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.6 } ] }, { "type": "technique", @@ -589,7 +609,7 @@ "messages": [ "You fan strike %s", " fan strikes %s" ], "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.75 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 } ] }, { "type": "technique", @@ -597,7 +617,7 @@ "name": "Snap Strike", "messages": [ "You snap out at %s", " snaps quickly at %s" ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -608,7 +628,12 @@ "melee_allowed": true, "req_buffs": [ "buff_eskrima_oncrit" ], "crit_tec": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -620,7 +645,12 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.6 ], [ "damage", "bash", 0.7 ], [ "damage", "cut", 0.0 ], [ "damage", "stab", 0.0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.6 }, + { "stat": "damage", "type": "bash", "scale": 0.7 }, + { "stat": "damage", "type": "cut", "scale": 0.0 }, + { "stat": "damage", "type": "stab", "scale": 0.0 } + ] }, { "type": "technique", @@ -650,7 +680,7 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -662,7 +692,11 @@ "req_buffs": [ "buff_fencing_onmiss" ], "weighting": 4, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 1.25 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.25 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.25 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ] }, { "type": "technique", @@ -674,7 +708,12 @@ "block_counter": true, "crit_ok": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.2 ], [ "damage", "stab", 1.2 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.2 }, + { "stat": "damage", "type": "stab", "scale": 1.2 } + ] }, { "type": "technique", @@ -686,7 +725,12 @@ "block_counter": true, "crit_ok": true, "down_dur": 2, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -695,7 +739,11 @@ "messages": [ "You swing high and strike at %s", " swings high and strikes %s" ], "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.2 ], [ "damage", "stab", 1.2 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.2 }, + { "stat": "damage", "type": "stab", "scale": 1.2 } + ] }, { "type": "technique", @@ -706,7 +754,7 @@ "melee_allowed": true, "defensive": true, "miss_recovery": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -729,7 +777,11 @@ "crit_ok": true, "weighting": 2, "down_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -741,7 +793,11 @@ "downed_target": true, "crit_tec": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -752,7 +808,7 @@ "melee_allowed": true, "unarmed_weapons_allowed": false, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -765,7 +821,7 @@ "unarmed_weapons_allowed": false, "disarms": true, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -780,7 +836,7 @@ "side_switch": true, "down_dur": 1, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -807,7 +863,7 @@ "unarmed_weapons_allowed": false, "dodge_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -818,7 +874,7 @@ "unarmed_allowed": true, "block_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -829,7 +885,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.33 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 } ] }, { "type": "technique", @@ -838,7 +894,12 @@ "messages": [ "You quickly strike %s with the back of your fist", " quickly strikes %s with the back of their fist" ], "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -846,7 +907,7 @@ "name": "Roundhouse Kick", "messages": [ "You roundhouse kick %s", " roundhouse kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -856,7 +917,12 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "melee_allowed": true, "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -893,8 +959,8 @@ "stunned_target": true, "human_target": true, "stun_dur": 1, - "flat_bonuses": [ [ "arpen", "bash", "str", 1.0 ] ], - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 1.0 } ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -917,7 +983,7 @@ "unarmed_allowed": true, "crit_ok": true, "block_counter": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -938,7 +1004,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -946,7 +1012,12 @@ "name": "Leopard Swipe", "messages": [ "You quickly swipe at %s", " quickly swipes at %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -959,7 +1030,7 @@ "dodge_counter": true, "knockback_dist": 1, "knockback_spread": 1, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -971,7 +1042,11 @@ "crit_ok": true, "dodge_counter": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "cut", 0 ], [ "damage", "stab", 0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "cut", "scale": 0 }, + { "stat": "damage", "type": "stab", "scale": 0 } + ] }, { "type": "technique", @@ -1005,7 +1080,11 @@ "req_buffs": [ "buff_swordsmanship_oncrit" ], "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -1020,7 +1099,12 @@ "req_buffs": [ "buff_swordsmanship_onblock" ], "crit_tec": true, "stun_dur": 2, - "mult_bonuses": [ [ "movecost", 1.5 ], [ "damage", "bash", 3 ], [ "damage", "cut", 0 ], [ "damage", "stab", 0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.5 }, + { "stat": "damage", "type": "bash", "scale": 3 }, + { "stat": "damage", "type": "cut", "scale": 0 }, + { "stat": "damage", "type": "stab", "scale": 0 } + ] }, { "type": "technique", @@ -1030,7 +1114,7 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -1039,7 +1123,7 @@ "messages": [ "You deal a powerful kick to %s", " deals a powerful kick to %s" ], "unarmed_allowed": true, "crit_ok": true, - "mult_bonuses": [ [ "damage", "bash", 1.3 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.3 } ] }, { "type": "technique", @@ -1050,7 +1134,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.4 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ] }, { "type": "technique", @@ -1071,7 +1155,7 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -1083,7 +1167,11 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ], [ "damage", "stab", 1.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 }, + { "stat": "damage", "type": "stab", "scale": 1.5 } + ] }, { "type": "technique", @@ -1095,7 +1183,7 @@ "crit_tec": true, "down_dur": 2, "stun_dur": 2, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -1104,7 +1192,11 @@ "messages": [ "You strike %s with the slow power of flowing water", " strikes %s with the slow power of flowing water" ], "skill_requirements": [ { "name": "melee", "level": 4 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 1.75 ], [ "damage", "bash", 2.0 ], [ "damage", "cut", 2.0 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.75 }, + { "stat": "damage", "type": "bash", "scale": 2.0 }, + { "stat": "damage", "type": "cut", "scale": 2.0 } + ] }, { "type": "technique", @@ -1124,7 +1216,7 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, { "stat": "damage", "type": "cut", "scale": 1.5 } ] }, { "type": "technique", @@ -1136,7 +1228,11 @@ "req_buffs": [ "buff_niten_ondodge" ], "crit_ok": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 1.5 ], [ "damage", "cut", 1.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scale": 1.5 } + ] }, { "type": "technique", @@ -1147,7 +1243,7 @@ "melee_allowed": true, "defensive": true, "miss_recovery": true, - "mult_bonuses": [ [ "movecost", 0.8 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ] }, { "type": "technique", @@ -1155,7 +1251,7 @@ "name": "Cross", "messages": [ "You throw a heavy cross at %s", " throws a cross at %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1186,7 +1282,7 @@ "unarmed_allowed": true, "stunned_target": true, "weighting": 3, - "mult_bonuses": [ [ "movecost", 0.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ] }, { "type": "technique", @@ -1200,7 +1296,7 @@ "weighting": 3, "disarms": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -1215,7 +1311,7 @@ "knockback_dist": 2, "knockback_spread": 2, "stunned_target": true, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -1237,7 +1333,11 @@ "crit_ok": true, "downed_target": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "bash", 1.33 ], [ "damage", "cut", 1.33 ], [ "damage", "stab", 1.33 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.33 }, + { "stat": "damage", "type": "cut", "scale": 1.33 }, + { "stat": "damage", "type": "stab", "scale": 1.33 } + ] }, { "type": "technique", @@ -1259,7 +1359,11 @@ "crit_ok": true, "stunned_target": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "bash", 1.33 ], [ "damage", "cut", 1.33 ], [ "damage", "stab", 1.33 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.33 }, + { "stat": "damage", "type": "cut", "scale": 1.33 }, + { "stat": "damage", "type": "stab", "scale": 1.33 } + ] }, { "type": "technique", @@ -1267,7 +1371,12 @@ "name": "Snake Snap", "messages": [ "You swiftly jab %s", " swiftly jabs %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] }, { "type": "technique", @@ -1298,7 +1407,7 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -1310,7 +1419,12 @@ "block_counter": true, "crit_ok": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -1320,7 +1434,11 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -1330,7 +1448,11 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ] + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ] }, { "type": "technique", @@ -1341,7 +1463,7 @@ "unarmed_allowed": true, "weighting": 2, "take_weapon": true, - "mult_bonuses": [ [ "damage", "bash", 0.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 } ] }, { "type": "technique", @@ -1356,7 +1478,7 @@ "crit_tec": true, "stun_dur": 2, "knockback_dist": 2, - "mult_bonuses": [ [ "movecost", 1.5 ], [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 1.5 }, { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -1382,7 +1504,7 @@ "name": "Roundhouse Kick", "messages": [ "You roundhouse kick %s", " roundhouse kicks %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1412,7 +1534,7 @@ "unarmed_allowed": true, "req_buffs": [ "buff_tai_chi_onpause" ], "knockback_dist": 1, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -1424,7 +1546,7 @@ "block_counter": true, "crit_ok": true, "down_dur": 1, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1437,7 +1559,7 @@ "req_buffs": [ "buff_tai_chi_onpause" ], "knockback_dist": 1, "stun_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 2.0 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ] }, { "type": "technique", @@ -1465,7 +1587,7 @@ "name": "Straight Punch", "messages": [ "You deliver a vertical straight punch to %s", " delivers a vertical straight punch to %s" ], "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.1 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 } ] }, { "type": "technique", @@ -1478,7 +1600,7 @@ "weighting": 2, "knockback_dist": 1, "knockback_follow": true, - "mult_bonuses": [ [ "damage", "bash", 1.1 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 } ] }, { "type": "technique", @@ -1489,7 +1611,7 @@ "unarmed_allowed": true, "crit_tec": true, "down_dur": 1, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1504,7 +1626,7 @@ "down_dur": 1, "knockback_dist": 1, "knockback_follow": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -1525,7 +1647,7 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 } ] }, { "type": "technique", @@ -1545,7 +1667,7 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.25 ] ] + "mult_bonuses": [ { "stat": "movecost", "scale": 0.0 }, { "stat": "damage", "type": "bash", "scale": 1.25 } ] }, { "type": "technique", @@ -1565,8 +1687,11 @@ "unarmed_allowed": true, "unarmed_weapons_allowed": false, "skill_requirements": [ { "name": "unarmed", "level": 3 } ], - "mult_bonuses": [ [ "damage", "bash", 3.0 ], [ "damage", "bash", "str", 0.1 ] ], - "flat_bonuses": [ [ "movecost", 100 ], [ "movecost", "str", 10 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 3.0 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.1 } + ], + "flat_bonuses": [ { "stat": "movecost", "scale": 100 }, { "stat": "movecost", "scaling-stat": "str", "scale": 10 } ], "messages": [ "You slowly strike %s", " slowly strikes %s" ] }, { @@ -1576,8 +1701,16 @@ "unarmed_allowed": true, "melee_allowed": true, "skill_requirements": [ { "name": "melee", "level": 3 } ], - "mult_bonuses": [ [ "damage", "bash", 0.2 ], [ "damage", "cut", 0.2 ], [ "damage", "stab", 0.2 ], [ "movecost", 0.3 ] ], - "flat_bonuses": [ [ "arpen", "bash", 10 ], [ "arpen", "bash", "per", 1 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scale": 0.2 }, + { "stat": "damage", "type": "stab", "scale": 0.2 }, + { "stat": "movecost", "scale": 0.3 } + ], + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scale": 10 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 1 } + ], "crit_tec": true, "messages": [ "You phase-strike %s", " phase-strikes %s" ] } diff --git a/data/mods/Aftershock/player/techniques.json b/data/mods/Aftershock/player/techniques.json index 3bb4fe7ef77af..c8aaf058f3142 100644 --- a/data/mods/Aftershock/player/techniques.json +++ b/data/mods/Aftershock/player/techniques.json @@ -7,7 +7,7 @@ "melee_allowed": true, "skill_requirements": [ { "name": "melee", "level": 3 } ], "crit_tec": true, - "mult_bonuses": [ [ "damage", "bash", 1.5 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ], "stun_dur": 3, "knockback_dist": 2, "weighting": 1, diff --git a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json index 946fb273cbda3..62a6c43085714 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json @@ -28,7 +28,12 @@ "unarmed_allowed": true, "melee_allowed": true, "skill_requirements": [ { "name": "unarmed", "level": 2 } ], - "flat_bonuses": [ [ "damage", "stab", 1.0 ], [ "damage", "cut", 1.0 ], [ "arpen", "stab", 1.0 ], [ "arpen", "cut", 1.0 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scale": 1.0 }, + { "stat": "damage", "type": "cut", "scale": 1.0 }, + { "stat": "arpen", "type": "stab", "scale": 1.0 }, + { "stat": "arpen", "type": "cut", "scale": 1.0 } + ] } ], "onhit_buffs": [ @@ -41,7 +46,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "buff_duration": 1, "max_stacks": 4, - "flat_bonuses": [ [ "damage", "stab", 0.25 ], [ "damage", "cut", 0.5 ], [ "arpen", "cut", 1.0 ] ] + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scale": 0.25 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scale": 1.0 } + ] } ], "techniques": [ "tec_crt_blade_normal", "tec_crt_blade_rapid", "tec_crt_blade_precise", "tec_crt_blade_arpen", "tec_feint" ], @@ -80,7 +89,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 }, { "name": "melee", "level": 1 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 0.8 ], [ "damage", "cut", 0.7 ], [ "damage", "stab", 0.6 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 0.8 }, + { "stat": "damage", "type": "cut", "scale": 0.7 }, + { "stat": "damage", "type": "stab", "scale": 0.6 } + ], "messages": [ "You release a blindingly fast slash at %s", " slashes at %s" ] }, { @@ -90,7 +103,12 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 }, { "name": "melee", "level": 2 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.77 ], [ "damage", "bash", 0.55 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.88 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.77 }, + { "stat": "damage", "type": "bash", "scale": 0.55 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.88 } + ], "messages": [ "You swiftly jab your weapon at %s", " swiftly jabs their weapon at %s" ] }, { @@ -100,7 +118,12 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 }, { "name": "melee", "level": 3 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 1.05 ], [ "damage", "stab", 1.0 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 1.05 }, + { "stat": "damage", "type": "stab", "scale": 1.0 } + ], "crit_tec": true, "messages": [ "You release a debilitating swipe at %s", " releases a debilitating swipe at %s" ], "down_dur": 2 @@ -114,11 +137,11 @@ "unarmed_allowed": true, "melee_allowed": true, "mult_bonuses": [ - [ "damage", "bash", 0.5 ], - [ "damage", "cut", 1.1 ], - [ "damage", "stab", 1.1 ], - [ "arpen", "stab", 0.25 ], - [ "arpen", "cut", 0.5 ] + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.1 }, + { "stat": "arpen", "type": "stab", "scale": 0.25 }, + { "stat": "arpen", "type": "cut", "scale": 0.5 } ], "crit_tec": true, "messages": [ diff --git a/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json b/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json index db9df86d9177c..386e88b9a543d 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_EnforcementBuff.json @@ -28,11 +28,11 @@ "unarmed_allowed": true, "melee_allowed": true, "flat_bonuses": [ - [ "arpen", "bash", "str", 0.15 ], - [ "armor", "bash", 1.0 ], - [ "armor", "cut", 1.0 ], - [ "armor", "stab", 1.0 ], - [ "hit", "str", 0.4 ] + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "armor", "type": "bash", "scale": 1.0 }, + { "stat": "armor", "type": "cut", "scale": 1.0 }, + { "stat": "armor", "type": "stab", "scale": 1.0 }, + { "stat": "hit", "scaling-stat": "str", "scale": 0.4 } ] } ], @@ -47,13 +47,13 @@ "buff_duration": 10, "max_stacks": 10, "flat_bonuses": [ - [ "damage", "bash", "str", 0.01 ], - [ "armor", "bash", 0.05 ], - [ "armor", "cut", 0.05 ], - [ "armor", "stab", 0.05 ], - [ "armor", "bash", "str", 0.15 ], - [ "armor", "cut", "str", 0.125 ], - [ "armor", "stab", "str", 0.075 ] + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.01 }, + { "stat": "armor", "type": "bash", "scale": 0.05 }, + { "stat": "armor", "type": "cut", "scale": 0.05 }, + { "stat": "armor", "type": "stab", "scale": 0.05 }, + { "stat": "armor", "type": "bash", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "armor", "type": "cut", "scaling-stat": "str", "scale": 0.125 }, + { "stat": "armor", "type": "stab", "scaling-stat": "str", "scale": 0.075 } ] } ], @@ -89,8 +89,15 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 }, { "name": "melee", "level": 1 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.0 ], [ "damage", "cut", 1.0 ], [ "damage", "stab", 1.0 ] ], - "flat_bonuses": [ [ "damage", "bash", "str", 0.15 ], [ "movecost", "str", -0.7 ] ], + "mult_bonuses": [ + { "stat": "damage", "type": "bash", "scale": 1.0 }, + { "stat": "damage", "type": "cut", "scale": 1.0 }, + { "stat": "damage", "type": "stab", "scale": 1.0 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -0.7 } + ], "messages": [ "You clock %s's in a weak spot to knock em down", " smashes in %s's face" ], "down_dur": 1 }, @@ -101,8 +108,16 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 }, { "name": "melee", "level": 2 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 1.04 ], [ "damage", "bash", 1.0 ], [ "damage", "cut", 1.05 ], [ "damage", "stab", 1.05 ] ], - "flat_bonuses": [ [ "arpen", "bash", "str", 0.2 ], [ "movecost", "str", -1.2 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.04 }, + { "stat": "damage", "type": "bash", "scale": 1.0 }, + { "stat": "damage", "type": "cut", "scale": 1.05 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.2 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -1.2 } + ], "messages": [ "You swiftly swipe your weapon's tip at %s", " swiftly jabs their weapon into %s" ] }, { @@ -112,8 +127,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 }, { "name": "melee", "level": 3 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 1.35 ], [ "damage", "bash", 1.15 ], [ "damage", "cut", 1.05 ], [ "damage", "stab", 1.0 ] ], - "flat_bonuses": [ [ "arpen", "bash", "str", 0.5 ], [ "damage", "cut", "str", 0.25 ], [ "movecost", "str", -1.5 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.35 }, + { "stat": "damage", "type": "bash", "scale": 1.15 }, + { "stat": "damage", "type": "cut", "scale": 1.05 }, + { "stat": "damage", "type": "stab", "scale": 1.0 } + ], + "flat_bonuses": [ + { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -1.5 } + ], "crit_tec": true, "messages": [ "You steady your arm and release a crushing blow at %s", " releases a crushing blow at %s" ], "stun_dur": 3, diff --git a/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json b/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json index 7f34ed436f509..72055a8907ba1 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_MeleeBuffs.json @@ -38,14 +38,14 @@ "unarmed_allowed": true, "melee_allowed": true, "flat_bonuses": [ - [ "damage", "stab", "dex", 0.15 ], - [ "damage", "cut", "dex", 0.05 ], - [ "arpen", "stab", "dex", 0.25 ], - [ "arpen", "cut", "dex", 0.15 ], - [ "dodge", "dex", 0.1 ], - [ "hit", "dex", 0.15 ] + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.15 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.05 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "dex", "scale": 0.25 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "dex", "scale": 0.15 }, + { "stat": "dodge", "scaling-stat": "dex", "scale": 0.1 }, + { "stat": "hit", "scaling-stat": "dex", "scale": 0.15 } ], - "mult_bonuses": [ [ "damage", "bash", 0.5 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 } ] } ], "onhit_buffs": [ @@ -58,8 +58,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "buff_duration": 2, "max_stacks": 10, - "flat_bonuses": [ [ "movecost", "dex", -0.05 ], [ "movecost", 0.1 ], [ "damage", "stab", 0.1 ] ], - "mult_bonuses": [ [ "damage", "stab", 1.075 ], [ "damage", "cut", 1.02 ], [ "arpen", "stab", 1.01 ], [ "dodge", 1.02 ] ] + "flat_bonuses": [ + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.05 }, + { "stat": "movecost", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scale": 0.1 } + ], + "mult_bonuses": [ + { "stat": "damage", "type": "stab", "scale": 1.075 }, + { "stat": "damage", "type": "cut", "scale": 1.02 }, + { "stat": "arpen", "type": "stab", "scale": 1.01 }, + { "stat": "dodge", "scale": 1.02 } + ] } ], "techniques": [ @@ -79,8 +88,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "melee_allowed": false, - "mult_bonuses": [ [ "movecost", 0.85 ], [ "damage", "bash", 0.8 ], [ "damage", "cut", 1.025 ], [ "damage", "stab", 1.05 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.2 ], [ "damage", "cut", "dex", 0.1 ], [ "movecost", "dex", -0.15 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.85 }, + { "stat": "damage", "type": "bash", "scale": 0.8 }, + { "stat": "damage", "type": "cut", "scale": 1.025 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.1 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.15 } + ], "messages": [ "You quickly dig your fingers into %s", " digs their fingers into %s" ] }, { @@ -90,8 +108,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.7 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.7 ], [ "damage", "stab", 0.8 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.015 ], [ "damage", "cut", "dex", 0.0125 ], [ "movecost", "dex", -0.35 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.7 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.7 }, + { "stat": "damage", "type": "stab", "scale": 0.8 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.015 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.0125 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.35 } + ], "messages": [ "You swiftly impale your fingers into %s joints", " swiftly impales their fingers into %s" ] }, { @@ -101,8 +128,17 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "unarmed_allowed": false, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.75 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.015 ], [ "damage", "cut", "dex", 0.0125 ], [ "movecost", "dex", -0.35 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.75 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.015 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.0125 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.35 } + ], "messages": [ "You explosively jab your weapon at %s joints", " explosively jabs at %s" ] }, { @@ -112,8 +148,17 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.25 ] ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.2 ], [ "damage", "cut", "dex", 0.01 ], [ "movecost", "dex", -0.2 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.8 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.01 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.2 } + ], "crit_tec": true, "messages": [ "You steady your hand and release a piercing jab at %s", " releases a piercing jab at %s" ], "stun_dur": 1 @@ -127,14 +172,18 @@ "unarmed_allowed": true, "melee_allowed": true, "mult_bonuses": [ - [ "movecost", 0.9 ], - [ "damage", "bash", 0.2 ], - [ "damage", "cut", 1.25 ], - [ "arpen", "cut", "dex", 0.15 ], - [ "damage", "stab", 1.5 ], - [ "arpen", "stab", "dex", 0.3 ] + { "stat": "movecost", "scale": 0.9 }, + { "stat": "damage", "type": "bash", "scale": 0.2 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "dex", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scale": 1.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "dex", "scale": 0.3 } + ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "dex", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.25 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.5 } ], - "flat_bonuses": [ [ "damage", "stab", "dex", 0.5 ], [ "damage", "cut", "dex", 0.25 ], [ "movecost", "dex", -0.5 ] ], "crit_tec": true, "messages": [ "You envision a gathering tempest in and then release it's energy on %s's top half", diff --git a/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json b/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json index 24b3738778380..9acc3d4967e6a 100644 --- a/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json +++ b/data/mods/CRT_EXPANSION/martial/crt_gun_techniques.json @@ -5,8 +5,13 @@ "name": "HOOK", "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.95 ], [ "damage", "bash", 0.88 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ], - "flat_bonuses": [ [ "movecost", "per", -0.25 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.95 }, + { "stat": "damage", "type": "bash", "scale": 0.88 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ], + "flat_bonuses": [ { "stat": "movecost", "scaling-stat": "per", "scale": -0.25 } ], "stun_dur": 2, "messages": [ "Your pistol whip sends %s careening", " smacks %s" ], "description": "95% moves, 88% Bash, 66% Cut, 66% Stab, Down two turns, STR (C) greatly reduces action cost" @@ -18,12 +23,17 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.6 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.6 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ], "flat_bonuses": [ - [ "movecost", "str", -1.0 ], - [ "damage", "bash", "per", 0.15 ], - [ "damage", "stab", "per", 0.1 ], - [ "damage", "cut", "per", 0.1 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -1.0 }, + { "stat": "damage", "type": "bash", "scaling-stat": "per", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.1 }, + { "stat": "damage", "type": "cut", "scaling-stat": "per", "scale": 0.1 } ], "messages": [ "Your swing the stock of your weapon at %s", " strikes at %s" ], "aoe": "wide", diff --git a/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json b/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json index 54115bfbf546c..c7a40fa52e2ea 100644 --- a/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json +++ b/data/mods/CRT_EXPANSION/martial/dragonslayertechn.json @@ -6,12 +6,17 @@ "skill_requirements": [ { "name": "melee", "level": 1 } ], "unarmed_allowed": false, "melee_allowed": true, - "mult_bonuses": [ [ "movecost", 0.3 ], [ "damage", "bash", 0.77 ], [ "damage", "cut", 0.77 ], [ "damage", "stab", 0.77 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.3 }, + { "stat": "damage", "type": "bash", "scale": 0.77 }, + { "stat": "damage", "type": "cut", "scale": 0.77 }, + { "stat": "damage", "type": "stab", "scale": 0.77 } + ], "flat_bonuses": [ - [ "movecost", "str", -10 ], - [ "damage", "bash", "str", 0.8 ], - [ "damage", "stab", "str", 1.5 ], - [ "damage", "cut", "str", 0.8 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -10 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.8 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 1.5 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.8 } ], "down_dur": 2, "messages": [ "Your swing makes %s stagger and fall", " hooks %s" ], @@ -25,12 +30,17 @@ "unarmed_allowed": false, "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.15 ], [ "damage", "bash", 0.35 ], [ "damage", "cut", 0.35 ], [ "damage", "stab", 0.35 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.15 }, + { "stat": "damage", "type": "bash", "scale": 0.35 }, + { "stat": "damage", "type": "cut", "scale": 0.35 }, + { "stat": "damage", "type": "stab", "scale": 0.35 } + ], "flat_bonuses": [ - [ "movecost", "str", -15 ], - [ "damage", "bash", "str", 0.1 ], - [ "damage", "stab", "str", 0.3 ], - [ "damage", "cut", "str", 0.1 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -15 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.3 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.1 } ], "messages": [ "Your momentum causes your weapon to strike %s", " inertially strikes %s" ], "aoe": "wide", @@ -44,13 +54,18 @@ "unarmed_allowed": true, "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 0.35 ], [ "damage", "bash", 1.05 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.05 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.35 }, + { "stat": "damage", "type": "bash", "scale": 1.05 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], "flat_bonuses": [ - [ "movecost", "str", -15 ], - [ "movecost", "dex", -7 ], - [ "damage", "bash", "per", 0.15 ], - [ "damage", "cut", "per", 0.3 ], - [ "damage", "stab", "per", 0.15 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -15 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -7 }, + { "stat": "damage", "type": "bash", "scaling-stat": "per", "scale": 0.15 }, + { "stat": "damage", "type": "cut", "scaling-stat": "per", "scale": 0.3 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.15 } ], "messages": [ "You wind up the sword and release a well placed swing at %s", " chops %s" ], "description": "Crit only, 35% move cost, 105% Bash and Stab, 125% Cut, DEX (D) and PER (E) reduces action cost and increases overall (B) damage, min 2 melee" diff --git a/data/mods/CRT_EXPANSION/martial/generaltechn.json b/data/mods/CRT_EXPANSION/martial/generaltechn.json index 942c3d3e4c220..00846be7de403 100644 --- a/data/mods/CRT_EXPANSION/martial/generaltechn.json +++ b/data/mods/CRT_EXPANSION/martial/generaltechn.json @@ -3,8 +3,13 @@ "type": "technique", "id": "HOOK", "name": "HOOK", - "mult_bonuses": [ [ "movecost", 0.85 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.76 ], [ "damage", "stab", 0.86 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.25 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.85 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.76 }, + { "stat": "damage", "type": "stab", "scale": 0.86 } + ], + "flat_bonuses": [ { "stat": "movecost", "scaling-stat": "str", "scale": -0.25 } ], "down_dur": 2, "messages": [ "Your hooking attack makes %s stagger and fall", " hooks %s" ], "description": "85% moves, 66% Bash, 76% Cut, 86% Stab, Down two turns, STR (C) greatly reduces action cost" @@ -17,12 +22,17 @@ "unarmed_allowed": true, "melee_allowed": true, "knockback_dist": 1, - "mult_bonuses": [ [ "movecost", 0.6 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.5 ], [ "damage", "stab", 0.5 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.6 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.5 }, + { "stat": "damage", "type": "stab", "scale": 0.5 } + ], "flat_bonuses": [ - [ "movecost", "str", -1.0 ], - [ "damage", "bash", "str", 0.1 ], - [ "damage", "stab", "str", 0.1 ], - [ "damage", "cut", "str", 0.1 ] + { "stat": "movecost", "scaling-stat": "str", "scale": -1.0 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.1 } ], "messages": [ "Your momentum causes your weapon to glance off of %s", " inertially strikes %s" ], "aoe": "wide", @@ -36,13 +46,18 @@ "unarmed_allowed": true, "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 1.18 ], [ "damage", "bash", 1.05 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.05 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.18 }, + { "stat": "damage", "type": "bash", "scale": 1.05 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], "flat_bonuses": [ - [ "movecost", "dex", -0.2 ], - [ "movecost", "per", -0.125 ], - [ "damage", "bash", "per", 0.15 ], - [ "damage", "cut", "per", 0.3 ], - [ "damage", "stab", "per", 0.15 ] + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.2 }, + { "stat": "movecost", "scaling-stat": "per", "scale": -0.125 }, + { "stat": "damage", "type": "bash", "scaling-stat": "per", "scale": 0.15 }, + { "stat": "damage", "type": "cut", "scaling-stat": "per", "scale": 0.3 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.15 } ], "messages": [ "You draw back your arm and release a well placed chop %s", " chops %s" ], "description": "Crit only, 118% move cost, 105% Bash and Stab, 125% Cut, DEX (D) and PER (E) reduces action cost and increases overall (B) damage, min 2 melee" @@ -55,13 +70,18 @@ "unarmed_allowed": true, "melee_allowed": true, "crit_tec": true, - "mult_bonuses": [ [ "movecost", 1.18 ], [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.05 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.18 }, + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.1 }, + { "stat": "damage", "type": "stab", "scale": 1.05 } + ], "flat_bonuses": [ - [ "movecost", "dex", -0.2 ], - [ "movecost", "str", -0.125 ], - [ "damage", "bash", "str", 0.25 ], - [ "damage", "cut", "str", 0.15 ], - [ "damage", "stab", "str", 0.15 ] + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.2 }, + { "stat": "movecost", "scaling-stat": "str", "scale": -0.125 }, + { "stat": "damage", "type": "bash", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "damage", "type": "cut", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.15 } ], "messages": [ "You grip your weapon with two hands and slam it into %s", " smashes their weapon onto %s" ], "description": "Crit only, 110% move cost, 120% Bash, 105% Stab, 110% Cut, DEX (C) and STR (D) reduces action cost and increases overall (C) damage, min 2 melee" @@ -75,8 +95,13 @@ "melee_allowed": true, "crit_tec": true, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 1.2 ], [ "damage", "bash", 1.25 ], [ "damage", "cut", 1.25 ], [ "damage", "stab", 1.25 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.8 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 1.2 }, + { "stat": "damage", "type": "bash", "scale": 1.25 }, + { "stat": "damage", "type": "cut", "scale": 1.25 }, + { "stat": "damage", "type": "stab", "scale": 1.25 } + ], + "flat_bonuses": [ { "stat": "movecost", "scaling-stat": "str", "scale": -0.8 } ], "messages": [ "You lunge forward with all your weight and swing upwards at %s", " swings upwards with all their weight at %s" @@ -91,8 +116,16 @@ "melee_allowed": true, "knockback_dist": 2, "stun_dur": 1, - "mult_bonuses": [ [ "movecost", 0.65 ], [ "damage", "bash", 0.5 ], [ "damage", "cut", 0.15 ], [ "damage", "stab", 0.35 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.15 ], [ "movecost", "dex", -0.1 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.65 }, + { "stat": "damage", "type": "bash", "scale": 0.5 }, + { "stat": "damage", "type": "cut", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scale": 0.35 } + ], + "flat_bonuses": [ + { "stat": "movecost", "scaling-stat": "str", "scale": -0.15 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.1 } + ], "messages": [ "You quickly shove %s out of the way", " quickly shoves %s" ], "description": "65% moves, dramatically reduced damage, knockback 2 tiles, stun 1 turn, STR (D) and DEX (E) reduce action cost" }, @@ -104,8 +137,16 @@ "unarmed_allowed": false, "melee_allowed": true, "knockback_dist": 2, - "mult_bonuses": [ [ "movecost", 0.75 ], [ "damage", "bash", 1.1 ], [ "damage", "cut", 0 ], [ "damage", "stab", 1.1 ] ], - "flat_bonuses": [ [ "movecost", "str", -0.3 ], [ "movecost", "dex", -0.15 ] ], + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.75 }, + { "stat": "damage", "type": "bash", "scale": 1.1 }, + { "stat": "damage", "type": "cut", "scale": 0 }, + { "stat": "damage", "type": "stab", "scale": 1.1 } + ], + "flat_bonuses": [ + { "stat": "movecost", "scaling-stat": "str", "scale": -0.3 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": -0.15 } + ], "messages": [ "You quickly shove %s out of the way with your weapon", " quickly shoves %s" ], "description": "75% moves, no cut damage, 110% Bash and Stab damage, knockback 2 tiles, STR (B) and DEX (C) reduce action cost, min melee 1" }, @@ -118,7 +159,7 @@ "melee_allowed": true, "crit_tec": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "cut", 1.1 ], [ "damage", "stab", 1.15 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "cut", "scale": 1.1 }, { "stat": "damage", "type": "stab", "scale": 1.15 } ], "messages": [ "You stab into %s and rake your blade out", " tears into %s flesh" ], "description": "Crit only, 110% Cut, 115% Stab, min melee 2" } diff --git a/data/mods/CRT_EXPANSION/martial/stabtechn.json b/data/mods/CRT_EXPANSION/martial/stabtechn.json index 7f9677dfcfd7c..b1948ea60ee88 100644 --- a/data/mods/CRT_EXPANSION/martial/stabtechn.json +++ b/data/mods/CRT_EXPANSION/martial/stabtechn.json @@ -8,8 +8,11 @@ "melee_allowed": true, "crit_tec": false, "weighting": 1, - "mult_bonuses": [ [ "damage", "stab", 1.1 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.1 ], [ "damage", "stab", "per", 0.2 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "stab", "scale": 1.1 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.1 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.2 } + ], "messages": [ "You step forward and stab at %s", " stabs into %s flesh" ], "description": "110% Stab damage, STR (E) and PER (D) provides bonus damage, min 1 melee" }, @@ -22,8 +25,11 @@ "melee_allowed": true, "crit_tec": true, "weighting": 2, - "mult_bonuses": [ [ "damage", "stab", 1.15 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.2 ], [ "damage", "stab", "per", 0.2 ] ], + "mult_bonuses": [ { "stat": "damage", "type": "stab", "scale": 1.15 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.2 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.2 } + ], "messages": [ "You explosively jab at %s", " violently jabs at %s" ], "description": "Crit only, 115% Stab damage, Crit only, Strength (D) and Perception (D) provides bonus damage, min 2 melee" }, @@ -36,8 +42,12 @@ "melee_allowed": true, "crit_tec": false, "weighting": 1, - "mult_bonuses": [ [ "movecost", 0.66 ], [ "damage", "stab", 0.7 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.15 ], [ "damage", "stab", "per", 0.25 ], [ "movecost", "dex", 0.25 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.66 }, { "stat": "damage", "type": "stab", "scale": 0.7 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.15 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.25 }, + { "stat": "movecost", "scaling-stat": "dex", "scale": 0.25 } + ], "messages": [ "You prod at %s defensively", " prods at %s " ], "description": "66% movecost, 70% Stab damage, STR (E) and PER (C) provides bonus damage, DEX (C) reduces action cost, min 3 melee" }, @@ -50,8 +60,12 @@ "melee_allowed": true, "crit_tec": false, "weighting": 1, - "mult_bonuses": [ [ "movecost", 0.8 ], [ "damage", "stab", 0.75 ] ], - "flat_bonuses": [ [ "damage", "stab", "str", 0.25 ], [ "damage", "stab", "per", 0.3 ], [ "arpen", "stab", "per", 0.12 ] ], + "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 }, { "stat": "damage", "type": "stab", "scale": 0.75 } ], + "flat_bonuses": [ + { "stat": "damage", "type": "stab", "scaling-stat": "str", "scale": 0.25 }, + { "stat": "damage", "type": "stab", "scaling-stat": "per", "scale": 0.3 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "per", "scale": 0.12 } + ], "messages": [ "You probe %s's openings", " probe %s " ], "description": "80% movecost, 75% Stab damage, STR (C) and PER (C) provides bonus damage and also provides armor pierce (E), min 3 melee" } diff --git a/data/mods/MMA/martialarts.json b/data/mods/MMA/martialarts.json index 130d1ba5828a1..6b89932e29305 100644 --- a/data/mods/MMA/martialarts.json +++ b/data/mods/MMA/martialarts.json @@ -16,7 +16,7 @@ "unarmed_allowed": true, "melee_allowed": true, "bonus_dodges": 1, - "flat_bonuses": [ [ "dodge", "per", 0.12 ] ] + "flat_bonuses": [ { "stat": "dodge", "scaling-stat": "per", "scale": 0.12 } ] } ], "ondodge_buffs": [ @@ -28,7 +28,12 @@ "unarmed_allowed": true, "melee_allowed": true, "buff_duration": 2, - "flat_bonuses": [ [ "hit", 1.0 ], [ "arpen", "bash", "per", 0.5 ], [ "arpen", "cut", "per", 0.5 ], [ "arpen", "stab", "per", 0.5 ] ] + "flat_bonuses": [ + { "stat": "hit", "scale": 1.0 }, + { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "cut", "scaling-stat": "per", "scale": 0.5 }, + { "stat": "arpen", "type": "stab", "scaling-stat": "per", "scale": 0.5 } + ] } ], "techniques": [ "mma_tec_panzer_counter", "mma_tec_panzer_somersault", "mma_tec_panzer_precise", "mma_tec_panzer_rapid" ], diff --git a/data/mods/MMA/techniques.json b/data/mods/MMA/techniques.json index b06b672b32008..a6010240bed30 100644 --- a/data/mods/MMA/techniques.json +++ b/data/mods/MMA/techniques.json @@ -10,7 +10,12 @@ "unarmed_allowed": true, "dodge_counter": true, "crit_ok": true, - "mult_bonuses": [ [ "movecost", 0.0 ], [ "damage", "bash", 1.2 ], [ "damage", "cut", 1.2 ], [ "damage", "stab", 1.2 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.0 }, + { "stat": "damage", "type": "bash", "scale": 1.2 }, + { "stat": "damage", "type": "cut", "scale": 1.2 }, + { "stat": "damage", "type": "stab", "scale": 1.2 } + ] }, { "type": "technique", @@ -20,7 +25,7 @@ "messages": [ "You jump and somersault kick %s", " jump and somersault kick %s" ], "melee_allowed": true, "unarmed_allowed": true, - "mult_bonuses": [ [ "damage", "bash", 1.2 ] ] + "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 } ] }, { "type": "technique", @@ -33,8 +38,8 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, - "flat_bonuses": [ [ "arpen", "bash", 10.0 ] ], - "mult_bonuses": [ [ "movecost", 1.2 ], [ "damage", "bash", 1.5 ] ] + "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scale": 10.0 } ], + "mult_bonuses": [ { "stat": "movecost", "scale": 1.2 }, { "stat": "damage", "type": "bash", "scale": 1.5 } ] }, { "type": "technique", @@ -45,6 +50,11 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "melee_allowed": true, "unarmed_allowed": true, - "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ] + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ] } ] diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index e89bd1f4dbdb4..0ff26aead1d89 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1082,7 +1082,6 @@ Note that even though most statistics yield an integer, you should still use "profession": true, //Trait is a starting profession special trait. (default: false) "debug": false, //Trait is for debug purposes (default: false) "player_display": true, //Trait is displayed in the `@` player display menu -"initial_ma_styles" : [ "style_centipede", "style_venom_snake" ], //List of starting martial arts types. One of the list is selectable at start. Only works at character creation. "category": ["MUTCAT_BIRD", "MUTCAT_INSECT"], // Categories containing this mutation "prereqs": ["SKIN_ROUGH"], // Needs these mutations before you can mutate toward this mutation "prereqs2": ["LEAVES"], //Also need these mutations before you can mutate towards this mutation. When both set creates 2 different mutation paths, random from one is picked. Only use together with "prereqs" diff --git a/doc/MARTIALART_JSON.md b/doc/MARTIALART_JSON.md index 939be0bfd24ba..2331a993b9fc1 100644 --- a/doc/MARTIALART_JSON.md +++ b/doc/MARTIALART_JSON.md @@ -10,7 +10,7 @@ "description": "A secret martial art used only by developers and cheaters.", // In-game description "initiate": [ "You stand ready.", "%s stands ready." ], // Message shown when player or NPC chooses this art "autolearn": [ [ "unarmed", "2" ] ], // A list of skill requirements that if met, automatically teach the player the martial art -"learn_difficulty": 5, // Difficulty to learn a style from book based on "primary skill" +"learn_difficulty": 5, // Difficulty to learn a style from book based on "primary skill" // Total chance to learn a style from a single read of the book is equal to one in (10 + learn_difficulty - primary_skill) "arm_block" : 99, // Unarmed skill level at which arm blocking is unlocked "leg_block" : 99, // Unarmed skill level at which arm blocking is unlocked @@ -40,7 +40,7 @@ "name" : "phasing strike", // In-game name displayed "unarmed_allowed" : true, // Can an unarmed character use this technique "unarmed_weapons_allowed" : true, // Does this technique require the character to be actually unarmed or does it allow unarmed weapons -"melee_allowed" : true, // Means that ANY melee weapon can be used, NOT just the martial art's weapons +"melee_allowed" : true, // Means that ANY melee weapon can be used, NOT just the martial art's weapons "skill_requirements": [ { "name": "melee", "level": 3 } ], // Skills and their minimum levels required to use this technique. Can be any skill. "weapon_damage_requirements": [ { "type": "bash", "min": 5 } ], // Minimum weapon damage required to use this technique. Can be any damage type. "req_buffs": [ "eskrima_hit_buff" ], // This technique requires a named buff to be active @@ -84,32 +84,31 @@ "max_stacks" : 8, // Maximum number of stacks on the buff. Buff bonuses are multiplied by current buff intensity "bonus_blocks": 1 // Extra blocks per turn "bonus_dodges": 1 // Extra dodges per turn -"flat_bonuses" : [ // Flat bonuses - ["armor", "bash", "str", 1.0], - ["armor", "cut", "dex", 1.0], - ["armor", "electric", "int", 1.0], - ["armor", "heat", "per", 1.0] +"flat_bonuses" : [ // Flat bonuses, see below ], -"mult_bonuses" : [ // Multiplicative bonuses - ["damage", "bash", 2.0], - ["damage", "heat", "int", 1.1] +"mult_bonuses" : [ // Multiplicative bonuses, see below ] ``` ### Bonuses -Bonuses contain 2 to 4 of the following tokens, in order: +The bonuses arrays contain any number of bonus entries like this: -* Affected statistic. Any of: "hit", "dodge", "block", "speed", "movecost", "damage", "armor", "arpen" -* Damage type ("bash", "cut", "heat", etc.) if the affected statistic is damage, armor, or arpen -* Scaling stat. Any of: "str", "dex", "int", "per" -* The value of the bonus itself - -Bonuses must be written in the correct order. +```C++ +{ + "stat": "damage", + "type": "bash", + "scaling-stat": "per", + "scale": 0.15 +} +``` -If the affected statistic requires a damage type, a damage type must be provided. Otherwise, damage type must not be specified. +"stat": affected statistic, any of: "hit", "dodge", "block", "speed", "movecost", "damage", "armor", "arpen", +"type": damage type for the affected statistic ("bash", "cut", "heat", etc.), only needed if the affected statistic is "damage", "armor", or "arpen". +"scale": the value of the bonus itself. +"scaling-stat": scaling stat, any of: "str", "dex", "int", "per". Optional. If the scaling stat is specified, the value of the bonus is multiplied by the corresponding user stat. -If the scaling stat is specified, the value of the bonus is multiplied by the corresponding user stat. +Bonuses must be written in the correct order. Tokens of `useless` type will not cause an error, but will not have any effect. For example, `speed` in a technique will have no effect (`movecost` should be used for techniques). @@ -117,9 +116,14 @@ For example, `speed` in a technique will have no effect (`movecost` should be us Currently extra elemental damage is not applied, but extra elemental armor is (after regular armor). Examples: -* `flat_bonuses : [["armor", "bash", "str", 0.3]], // Incoming bashing damage is decreased by 30% of strength value. Only useful on buffs` -* ``mult_bonuses : [["damage", "cut", "dex", 0.1]], // All cutting damage dealt is multiplied by `(10% of dexterity)*(damage)` `` -* `flat_bonuses : [["movecost", "str", -1.0]], // Move cost is decreased by 100% of strength value` +Incoming bashing damage is decreased by 30% of strength value. Only useful on buffs: +* `flat_bonuses : [ { "stat": "armor", "type": "bash", "scaling-stat": "str", "scale": 0.3 } ]` + +All cutting damage dealt is multiplied by `(10% of dexterity)*(damage)`: +* `mult_bonuses : [ { "stat": "damage", "type": "cut", "scaling-stat": "dex", "scale": 0.1 } ]` + +Move cost is decreased by 100% of strength value +* `flat_bonuses : [ { "stat": "movecost", "scaling-stat": "str", "scale": -1.0 } ]` ### Place relevant items in the world and chargen diff --git a/src/bonuses.cpp b/src/bonuses.cpp index 9503dd06e1fd4..539ef96b22cb2 100644 --- a/src/bonuses.cpp +++ b/src/bonuses.cpp @@ -93,57 +93,43 @@ static std::string string_from_scaling_stat( const scaling_stat &s ) bonus_container::bonus_container() = default; -void effect_scaling::load( JsonArray &jarr ) +effect_scaling::effect_scaling( const JsonObject &obj ) { - if( jarr.test_string() ) { - stat = scaling_stat_from_string( jarr.next_string() ); + if( obj.has_string( "scaling-stat" ) ) { + stat = scaling_stat_from_string( obj.get_string( "scaling-stat" ) ); } else { stat = STAT_NULL; } - scale = jarr.next_float(); + scale = obj.get_float( "scale" ); } void bonus_container::load( const JsonObject &jo ) { - if( jo.has_array( "flat_bonuses" ) ) { - JsonArray jarr = jo.get_array( "flat_bonuses" ); - load( jarr, false ); - } - - if( jo.has_array( "mult_bonuses" ) ) { - JsonArray jarr = jo.get_array( "mult_bonuses" ); - load( jarr, true ); - } + load( jo.get_array( "flat_bonuses" ), false ); + load( jo.get_array( "mult_bonuses" ), true ); } -void bonus_container::load( JsonArray &jarr, bool mult ) +void bonus_container::load( const JsonArray &jarr, const bool mult ) { - while( jarr.has_more() ) { - JsonArray qualifiers = jarr.next_array(); - - damage_type dt = DT_NULL; - - const std::string affected_stat_string = qualifiers.next_string(); - const affected_stat as = affected_stat_from_string( affected_stat_string ); + for( const JsonObject &qualifiers : jarr ) { + const affected_stat as = affected_stat_from_string( qualifiers.get_string( "stat" ) ); if( as == AFFECTED_NULL ) { - jarr.throw_error( "Invalid affected stat" ); + qualifiers.throw_error( "Invalid affected stat", "stat" ); } + damage_type dt = DT_NULL; if( needs_damage_type( as ) ) { - const std::string damage_string = qualifiers.next_string(); - dt = dt_by_name( damage_string ); + dt = dt_by_name( qualifiers.get_string( "type" ) ); if( dt == DT_NULL ) { - jarr.throw_error( "Invalid damage type" ); + qualifiers.throw_error( "Invalid damage type", "type" ); } } - effect_scaling es; - es.load( qualifiers ); - affected_type at( as, dt ); - // Are we changing multipliers or flats? + const affected_type at( as, dt ); + auto &selected = mult ? bonuses_mult : bonuses_flat; - selected[at].push_back( es ); + selected[at].emplace_back( qualifiers ); } } diff --git a/src/bonuses.h b/src/bonuses.h index 070252cb1db8b..ccf1b1a54fb0e 100644 --- a/src/bonuses.h +++ b/src/bonuses.h @@ -63,7 +63,7 @@ struct effect_scaling { float get( const Character &u ) const; - void load( JsonArray &jarr ); + effect_scaling( const JsonObject &obj ); }; class bonus_container @@ -71,7 +71,6 @@ class bonus_container public: bonus_container(); void load( const JsonObject &jo ); - void load( JsonArray &jarr, bool mult ); float get_flat( const Character &u, affected_stat stat, damage_type dt ) const; float get_flat( const Character &u, affected_stat stat ) const; @@ -82,6 +81,8 @@ class bonus_container std::string get_description() const; private: + void load( const JsonArray &jarr, bool mult ); + using bonus_map = std::map>; /** All kinds of bonuses by types to damage, hit etc. */ bonus_map bonuses_flat; From 0dbe1f1bd94db9419268823e5703dc669215ed06 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 1 Feb 2020 07:54:13 -0500 Subject: [PATCH 203/219] Add utf8_display_split function This splits a string into a sequence of displayed characters. --- src/catacharset.cpp | 20 ++++++++++++++++++++ src/catacharset.h | 7 ++++++- tests/catacharset_test.cpp | 20 ++++++++++++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/catacharset.cpp b/src/catacharset.cpp index 9e680990d6c1d..7ab89e40ed394 100644 --- a/src/catacharset.cpp +++ b/src/catacharset.cpp @@ -479,6 +479,26 @@ std::u32string utf8_to_utf32( const std::string &str ) return ret; } +std::vector utf8_display_split( const std::string &s ) +{ + std::vector result; + std::string current_glyph; + const char *pos = s.c_str(); + int len = s.length(); + while( len > 0 ) { + const char *old_pos = pos; + const uint32_t ch = UTF8_getch( &pos, &len ); + const int width = mk_wcwidth( ch ); + if( width > 0 && !current_glyph.empty() ) { + result.push_back( current_glyph ); + current_glyph.clear(); + } + current_glyph += std::string( old_pos, pos ); + } + result.push_back( current_glyph ); + return result; +} + int center_text_pos( const char *text, int start_pos, int end_pos ) { int full_screen = end_pos - start_pos + 1; diff --git a/src/catacharset.h b/src/catacharset.h index f7722a9d97ea3..d2c2c0aceb6e6 100644 --- a/src/catacharset.h +++ b/src/catacharset.h @@ -5,6 +5,7 @@ #include #include #include +#include #define ANY_LENGTH 5 #define NULL_UNICODE 0x0000 @@ -56,11 +57,15 @@ std::string utf8_to_native( const std::string &str ); std::string utf32_to_utf8( const std::u32string &str ); std::u32string utf8_to_utf32( const std::string &str ); +// Split the given string into displayed characters. Each element of the returned vector +// contains one 'regular' codepoint and all subsequent combining characters. +std::vector utf8_display_split( const std::string & ); + /** * UTF8-Wrapper over std::string. * It looks and feels like a std::string, but uses code points counts * as index, not bytes. - * A multi-byte Unicode character might by represented + * A multi-byte Unicode character might be represented * as 3 bytes in UTF8, this class will see these 3 bytes as 1 character. * It will never separate them. It will however split between code points * which might be problematic when containing combination characters. diff --git a/tests/catacharset_test.cpp b/tests/catacharset_test.cpp index cb04e52404e59..b353d30d37688 100644 --- a/tests/catacharset_test.cpp +++ b/tests/catacharset_test.cpp @@ -4,22 +4,34 @@ #include "catch/catch.hpp" #include "catacharset.h" -TEST_CASE( "utf8_width" ) +TEST_CASE( "utf8_width", "[catacharset]" ) { CHECK( utf8_width( "Hello, world!", false ) == 13 ); CHECK( utf8_width( "你好,世界!", false ) == 12 ); CHECK( utf8_width( "Hello, 世界!", false ) == 12 ); CHECK( utf8_width( "激活", true ) == 4 ); CHECK( utf8_width( "激活", false ) == 25 ); + CHECK( utf8_width( "à", false ) == 1 ); + CHECK( utf8_width( "y\u0300", false ) == 1 ); + CHECK( utf8_width( "à̸̠你⃫", false ) == 3 ); } -TEST_CASE( "base64" ) +TEST_CASE( "utf8_display_split", "[catacharset]" ) +{ + CHECK( utf8_display_split( "你好" ) == std::vector { "你", "好" } ); + CHECK( utf8_display_split( "à" ) == std::vector { "à" } ); + CHECK( utf8_display_split( "y\u0300" ) == std::vector { "y\u0300" } ); + CHECK( utf8_display_split( "à̸̠你⃫" ) == std::vector { "à̸̠", "你⃫" } ); + CHECK( utf8_display_split( " " ) == std::vector { " ", " ", " ", " " } ); +} + +TEST_CASE( "base64", "[catacharset]" ) { CHECK( base64_encode( "hello" ) == "#aGVsbG8=" ); CHECK( base64_decode( "#aGVsbG8=" ) == "hello" ); } -TEST_CASE( "utf8_to_wstr" ) +TEST_CASE( "utf8_to_wstr", "[catacharset]" ) { // std::mbstowcs' returning -1 workaround setlocale( LC_ALL, "" ); @@ -28,7 +40,7 @@ TEST_CASE( "utf8_to_wstr" ) CHECK( utf8_to_wstr( src ) == dest ); } -TEST_CASE( "wstr_to_utf8" ) +TEST_CASE( "wstr_to_utf8", "[catacharset]" ) { // std::wcstombs' returning -1 workaround setlocale( LC_ALL, "" ); From 24b6b20f85486542a34e5d55c16fa54a10d9e5c3 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 2 Feb 2020 10:48:17 -0500 Subject: [PATCH 204/219] Switch mapgen keys from ints to strings Using new facility to split strings into displayed chunks, allow mapgen to use arbitrary Unicode characters (including combining characters) as keys. --- src/mapgen.cpp | 87 ++++++++++++++++++++++++++++---------------------- src/mapgen.h | 35 +++++++++++++++++--- 2 files changed, 80 insertions(+), 42 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index c132880807012..f5827a3282bc1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -762,6 +762,20 @@ void jmapgen_place::offset( const point &offset ) y.valmax -= offset.y; } +map_key::map_key( const std::string &s ) : str( s ) +{ + if( utf8_width( str ) != 1 ) { + debugmsg( "map key '%s' must be 1 column", str ); + } +} + +map_key::map_key( const JsonMember &member ) : str( member.name() ) +{ + if( utf8_width( str ) != 1 ) { + member.throw_error( "format map key must be 1 column" ); + } +} + /** * This is a generic mapgen piece, the template parameter PieceType should be another specific * type of jmapgen_piece. This class contains a vector of those objects and will chose one of @@ -2036,16 +2050,13 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string { if( jo.has_object( "mapping" ) ) { for( const JsonMember member : jo.get_object( "mapping" ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } + const map_key key( member ); JsonObject sub = member.get_object(); sub.allow_omitted_members(); if( !sub.has_member( member_name ) ) { continue; } - auto &vect = format_placings[ key[0] ]; + auto &vect = format_placings[ key ]; ::load_place_mapings( sub.get_member( member_name ), vect ); } } @@ -2059,11 +2070,8 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string return; } for( const JsonMember member : jo.get_object( member_name ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } - auto &vect = format_placings[ key[0] ]; + const map_key key( member ); + auto &vect = format_placings[ key ]; ::load_place_mapings( member, vect ); } } @@ -2141,20 +2149,17 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s // "terrain": { "a": "t_grass", "b": "t_lava" } if( jo.has_member( "terrain" ) ) { for( const JsonMember member : jo.get_object( "terrain" ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } + const map_key key( member ); if( member.test_string() ) { - format_terrain[key[0]] = ter_id( member.get_string() ); + format_terrain[key] = ter_id( member.get_string() ); } else { - auto &vect = format_placings[ key[0] ]; + auto &vect = format_placings[ key ]; ::load_place_mapings( member, vect ); if( !vect.empty() ) { // Dummy entry to signal that this terrain is actually defined, because // the code below checks that each square on the map has a valid terrain // defined somehow. - format_terrain[key[0]] = t_null; + format_terrain[key] = t_null; } } } @@ -2162,14 +2167,11 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s if( jo.has_object( "furniture" ) ) { for( const JsonMember member : jo.get_object( "furniture" ) ) { - const std::string &key = member.name(); - if( key.size() != 1 ) { - member.throw_error( "format map key must be 1 character" ); - } + const map_key key( member ); if( member.test_string() ) { - format_furniture[key[0]] = furn_id( member.get_string() ); + format_furniture[key] = furn_id( member.get_string() ); } else { - auto &vect = format_placings[ key[0] ]; + auto &vect = format_placings[ key ]; ::load_place_mapings( member, vect ); } } @@ -2307,27 +2309,35 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) return false; } - // mandatory: mapgensize rows of mapgensize character lines, each of which must have a matching key in "terrain", - // unless fill_ter is set + // mandatory: mapgensize rows of mapgensize character lines, each of which must have a + // matching key in "terrain", unless fill_ter is set // "rows:" [ "aaaajustlikeinmapgen.cpp", "this.must!be!exactly.24!", "and_must_match_terrain_", .... ] point expected_dim = mapgensize + m_offset; + assert( expected_dim.x >= 0 ); + assert( expected_dim.y >= 0 ); + parray = jo.get_array( "rows" ); if( static_cast( parray.size() ) < expected_dim.y ) { parray.throw_error( string_format( "format: rows: must have at least %d rows, not %d", expected_dim.y, parray.size() ) ); } for( int c = m_offset.y; c < expected_dim.y; c++ ) { - const auto tmpval = parray.get_string( c ); - if( static_cast( tmpval.size() ) < expected_dim.x ) { - parray.throw_error( string_format( "format: row %d must have at least %d columns, not %d", - c + 1, expected_dim.x, tmpval.size() ) ); + const std::string row = parray.get_string( c ); + std::vector row_keys; + for( const std::string &key : utf8_display_split( row ) ) { + row_keys.emplace_back( key ); + } + if( row_keys.size() < static_cast( expected_dim.x ) ) { + parray.throw_error( + string_format( " format: row %d must have at least %d columns, not %d", + c + 1, expected_dim.x, row_keys.size() ) ); } for( int i = m_offset.x; i < expected_dim.x; i++ ) { const point p = point( i, c ) - m_offset; - const int tmpkey = tmpval[i]; - const auto iter_ter = format_terrain.find( tmpkey ); - const auto iter_furn = format_furniture.find( tmpkey ); - const auto fpi = format_placings.find( tmpkey ); + const map_key key = row_keys[i]; + const auto iter_ter = format_terrain.find( key ); + const auto iter_furn = format_furniture.find( key ); + const auto fpi = format_placings.find( key ); const bool has_terrain = iter_ter != format_terrain.end(); const bool has_furn = iter_furn != format_furniture.end(); @@ -2336,18 +2346,19 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) if( !has_terrain && !fallback_terrain_exists ) { parray.throw_error( string_format( "format: rows: row %d column %d: " - "'%c' is not in 'terrain', and no 'fill_ter' is set!", - c + 1, i + 1, static_cast( tmpkey ) ) ); + "'%s' is not in 'terrain', and no 'fill_ter' is set!", + c + 1, i + 1, key.str ) ); } - if( test_mode && !has_terrain && !has_furn && !has_placing && tmpkey != ' ' && tmpkey != '.' ) { + if( test_mode && !has_terrain && !has_furn && !has_placing && + key.str != " " && key.str != "." ) { // TODO: Once all the in-tree mods don't report this error, // it should be changed to happen in regular games (not // just test_mode) and be non-fatal, so that mappers find // out about their issues before they PR their changes. parray.throw_error( string_format( "format: rows: row %d column %d: " - "'%c' has no terrain, furniture, or other definition", - c + 1, i + 1, static_cast( tmpkey ) ) ); + "'%s' has no terrain, furniture, or other definition", + c + 1, i + 1, key.str ) ); } if( has_terrain ) { format[ calc_index( p ) ].ter = iter_ter->second; diff --git a/src/mapgen.h b/src/mapgen.h index 8e051518b3673..e7355c75354f2 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -181,19 +181,46 @@ class jmapgen_place using palette_id = std::string; +// Strong typedef for strings used as map/palette keys +// Each key should be a UTF-8 string displayed in only one column (i.e. +// utf8_width of 1) but can contain multiple Unicode code points. +class map_key +{ + public: + map_key( const std::string & ); + map_key( const JsonMember & ); + + friend bool operator==( const map_key &l, const map_key &r ) { + return l.str == r.str; + } + + std::string str; +}; + +namespace std +{ +template<> +struct hash { + size_t operator()( const map_key &k ) const noexcept { + return hash {}( k.str ); + } +}; +} // namespace std + class mapgen_palette { public: palette_id id; /** - * The mapping from character code (key) to a list of things that should be placed. This is + * The mapping from character (key) to a list of things that should be placed. This is * similar to objects, but it uses key to get the actual position where to place things * out of the json "bitmap" (which is used to paint the terrain/furniture). */ - using placing_map = std::map< int, std::vector< shared_ptr_fast > >; + using placing_map = + std::unordered_map>>; - std::map format_terrain; - std::map format_furniture; + std::unordered_map format_terrain; + std::unordered_map format_furniture; placing_map format_placings; template From ef1acbd81f5f722ef103b4a5b0bb756ca9cd1af2 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 8 Feb 2020 21:51:29 -0500 Subject: [PATCH 205/219] Test Unicode mapgen with bookcases in house_w MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace bookcase symbol in the house_w_nest_palette with a Unicode symbol that looks similar to a bookcase (▤). --- data/json/mapgen/nested/house_nested.json | 50 +++++++++---------- .../json/mapgen_palettes/house_w_palette.json | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/data/json/mapgen/nested/house_nested.json b/data/json/mapgen/nested/house_nested.json index ffd95d71e5cbb..032ef11d11771 100644 --- a/data/json/mapgen/nested/house_nested.json +++ b/data/json/mapgen/nested/house_nested.json @@ -467,7 +467,7 @@ "mapgensize": [ 4, 4 ], "rotation": [ 0, 3 ], "rows": [ - " CR ", + " C▤ ", "O ", " EE ", " EE " @@ -476,7 +476,7 @@ "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -492,13 +492,13 @@ " EE ", " EE ", "O ", - " CR " + " C▤ " ], "palettes": [ "house_w_nest_palette" ], "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -513,14 +513,14 @@ "rows": [ " ", "C EE", - "R EE", + "▤ EE", " O " ], "palettes": [ "house_w_nest_palette" ], "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -535,14 +535,14 @@ "rows": [ " ", "EE C", - "EE R", + "EE ▤", " O " ], "palettes": [ "house_w_nest_palette" ], "items": { "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } }, @@ -704,7 +704,7 @@ " ", "EE I", "L AI", - "y R", + "y ▤", "OCy " ], "palettes": [ "house_w_nest_palette" ], @@ -713,7 +713,7 @@ "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } } } }, @@ -729,8 +729,8 @@ " OO ", "IB L", "I EE", - "y R", - "RCa " + "y ▤", + "▤Ca " ], "palettes": [ "house_w_nest_palette" ], "items": { @@ -739,7 +739,7 @@ "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, - "R": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } + "▤": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } } } }, @@ -1023,8 +1023,8 @@ "rotation": [ 0, 3 ], "rows": [ " @@p ", - " R", - " pp R", + " ▤", + " pp ▤", " ", " xxx " ], @@ -1118,11 +1118,11 @@ "mapgensize": [ 2, 2 ], "rotation": [ 0, 3 ], "rows": [ - "RR", + "▤▤", "C " ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { @@ -1135,10 +1135,10 @@ "rotation": [ 0, 3 ], "rows": [ "C ", - "R " + "▤ " ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { @@ -1151,10 +1151,10 @@ "rotation": [ 0, 3 ], "rows": [ " C", - "HR" + "H▤" ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { @@ -1230,12 +1230,12 @@ "mapgensize": [ 3, 3 ], "rotation": [ 0, 3 ], "rows": [ - "R H", - "RC ", - "R " + "▤ H", + "▤C ", + "▤ " ], "palettes": [ "house_w_nest_palette" ], - "items": { "R": [ { "item": "homebooks", "chance": 30 } ] } + "items": { "▤": [ { "item": "homebooks", "chance": 30 } ] } } }, { diff --git a/data/json/mapgen_palettes/house_w_palette.json b/data/json/mapgen_palettes/house_w_palette.json index 7d83fa5b9f07c..1cf6d42e0ae3b 100644 --- a/data/json/mapgen_palettes/house_w_palette.json +++ b/data/json/mapgen_palettes/house_w_palette.json @@ -22,7 +22,7 @@ "O": "f_dresser", "P": "f_locker", "Q": "f_rack", - "R": "f_bookcase", + "▤": "f_bookcase", "S": [ [ "f_filing_cabinet", 80 ], [ "f_shredder", 20 ] ], "U": "f_utility_shelf", "V": "f_glass_cabinet", From 593b75770f83f278d103e86cf84638830feaee51 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 19 Feb 2020 04:45:10 -0500 Subject: [PATCH 206/219] Document the Unicode mapgen support --- doc/MAPGEN.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index 2f5b1fbee289c..c6b62497b6cc7 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -197,9 +197,11 @@ Example: "fill_ter": "t_grass" *required if "fill_ter" is unset* > Value: ([array]): blocks of 24 rows of blocks of 24 character lines. Each character is defined by "terrain" and optionally "furniture" or other entries below +Other parts can be linked with this map, for example one can place things like a gaspump (with gasoline) or a toilet (with water) or items from an item group or fields at the square given by a character. + Any character used here must have some definition elsewhere to indicate its purpose. Failing to do so is an error which will be caught by running the tests. The tests will run automatically when you make a pull request for adding new maps to the game. If you have defined `fill_ter` or you are writing nested mapgen, then there are a couple of exceptions. The space and period characters (` ` and `.`) are permitted to have no definition and be used for 'background' in the `rows`. -Other parts can be linked with this map, for example one can place things like a gaspump (with gasoline) or a toilet (with water) or items from an item group or fields at the square given by a character. +As keys, you can use any Unicode characters which are not double-width. This includes for example most European alphabets but not Chinese characters. If you intend to take advantage of this, ensure that your editor is saving the file with a UTF-8 encoding. Accents are acceptable, even when using [combining characters](https://en.wikipedia.org/wiki/Combining_character). No normalization is performed; comparison is done at the raw bytes (code unit) level. Therefore, there are literally an infinite number of mapgen key characters available. Please don't abuse this by using distinct characters that are visually indistinguishable, or which are so rare as to be unlikely to render correctly for other developers. Example: From f4e1a0c8f03158b19812a8f8000c0038d763edfb Mon Sep 17 00:00:00 2001 From: akozhevn Date: Tue, 17 Mar 2020 04:54:32 -0400 Subject: [PATCH 207/219] Advanced inv save settings (#35239) --- src/advanced_inv.cpp | 89 +++++++++-------------- src/advanced_inv.h | 5 +- src/advanced_inv_pane.cpp | 30 ++++++++ src/advanced_inv_pane.h | 9 ++- src/uistate.h | 148 +++++++++++++++++++------------------- 5 files changed, 145 insertions(+), 136 deletions(-) diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 76447402ed75e..baa59d70f9931 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -109,23 +109,23 @@ advanced_inventory::advanced_inventory() } } ) { + save_state = &uistate.transfer_save; } // *INDENT-ON* advanced_inventory::~advanced_inventory() { save_settings( false ); - auto &aim_code = uistate.adv_inv_exit_code; - if( aim_code != exit_re_entry ) { - aim_code = exit_okay; + if( save_state->exit_code != exit_re_entry ) { + save_state->exit_code = exit_okay; } // Only refresh if we exited manually, otherwise we're going to be right back if( exit ) { werase( head ); werase( minimap ); werase( mm_border ); - werase( left_window ); - werase( right_window ); + werase( panes[left].window ); + werase( panes[right].window ); g->refresh_all(); g->u.check_item_encumbrance_flag(); } @@ -134,44 +134,19 @@ advanced_inventory::~advanced_inventory() void advanced_inventory::save_settings( bool only_panes ) { if( !only_panes ) { - uistate.adv_inv_last_coords = g->u.pos(); - uistate.adv_inv_src = src; - uistate.adv_inv_dest = dest; + save_state->active_left = ( src == left ); } for( int i = 0; i < NUM_PANES; ++i ) { - uistate.adv_inv_in_vehicle[i] = panes[i].in_vehicle(); - uistate.adv_inv_area[i] = panes[i].get_area(); - uistate.adv_inv_index[i] = panes[i].index; - uistate.adv_inv_filter[i] = panes[i].filter; - uistate.adv_inv_sort[i] = panes[i].sortby; + panes[i].save_settings(); } } void advanced_inventory::load_settings() { - aim_exit aim_code = static_cast( uistate.adv_inv_exit_code ); - for( int i = 0; i < NUM_PANES; ++i ) { - aim_location location; - if( get_option( "OPEN_DEFAULT_ADV_INV" ) ) { - location = static_cast( uistate.adv_inv_default_areas[i] ); - } else { - location = static_cast( uistate.adv_inv_area[i] ); - } - auto square = squares[location]; - // determine the square's vehicle/map item presence - bool has_veh_items = square.can_store_in_vehicle() ? - !square.veh->get_items( square.vstor ).empty() : false; - bool has_map_items = !g->m.i_at( square.pos ).empty(); - // determine based on map items and settings to show cargo - bool show_vehicle = aim_code == exit_re_entry ? - uistate.adv_inv_in_vehicle[i] : has_veh_items ? true : - has_map_items ? false : square.can_store_in_vehicle(); - panes[i].set_area( square, show_vehicle ); - panes[i].sortby = static_cast( uistate.adv_inv_sort[i] ); - panes[i].index = uistate.adv_inv_index[i]; - panes[i].filter = uistate.adv_inv_filter[i]; - } - uistate.adv_inv_exit_code = exit_none; + aim_exit aim_code = static_cast( save_state->exit_code ); + panes[left].load_settings( save_state->saved_area, squares, aim_code == exit_re_entry ); + panes[right].load_settings( save_state->saved_area_right, squares, aim_code == exit_re_entry ); + save_state->exit_code = exit_none; } std::string advanced_inventory::get_sortname( advanced_inv_sortby sortby ) @@ -232,10 +207,13 @@ void advanced_inventory::init() square.init(); } + panes[left].save_state = &save_state->pane; + panes[right].save_state = &save_state->pane_right; + load_settings(); - src = static_cast( uistate.adv_inv_src ); - dest = static_cast( uistate.adv_inv_dest ); + src = ( save_state->active_left ) ? left : right; + dest = ( save_state->active_left ) ? right : left; w_height = TERMY < min_w_height + head_height ? min_w_height : TERMY - head_height; w_width = TERMX < min_w_width ? min_w_width : TERMX > max_w_width ? max_w_width : @@ -250,16 +228,13 @@ void advanced_inventory::init() point( colstart + ( w_width - ( minimap_width + 2 ) ), headstart ) ); minimap = catacurses::newwin( minimap_height, minimap_width, point( colstart + ( w_width - ( minimap_width + 1 ) ), headstart + 1 ) ); - left_window = catacurses::newwin( w_height, w_width / 2, point( colstart, - headstart + head_height ) ); - right_window = catacurses::newwin( w_height, w_width / 2, point( colstart + w_width / 2, - headstart + head_height ) ); + panes[left].window = catacurses::newwin( w_height, w_width / 2, point( colstart, + headstart + head_height ) ); + panes[right].window = catacurses::newwin( w_height, w_width / 2, point( colstart + w_width / 2, + headstart + head_height ) ); // 2 for the borders, 5 for the header stuff itemsPerPage = w_height - 2 - 5; - - panes[left].window = left_window; - panes[right].window = right_window; } void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool active ) @@ -795,9 +770,9 @@ bool advanced_inventory::move_all_items( bool nested_call ) advanced_inventory_pane shadow = panes[src]; // here we recursively call this function with each area in order to // put all items in the proper destination area, with minimal fuss - int &loc = uistate.adv_inv_aim_all_location; + int &loc = save_state->aim_all_location; // re-entry nonsense - int &entry = uistate.adv_inv_re_enter_move_all; + int &entry = save_state->re_enter_move_all; // if we are just starting out, set entry to initial value switch( static_cast( entry++ ) ) { case ENTRY_START: @@ -1134,7 +1109,8 @@ void advanced_inventory::display() left, right } ) { auto &pane = panes[cside]; - aim_location location = static_cast( uistate.adv_inv_default_areas[cside] ); + int i_location = cside == left ? save_state->saved_area : save_state->saved_area_right; + aim_location location = static_cast( i_location ); if( pane.get_area() != location || location == AIM_ALL ) { pane.recalc = true; } @@ -1142,8 +1118,8 @@ void advanced_inventory::display() } redraw = true; } else if( action == "SAVE_DEFAULT" ) { - uistate.adv_inv_default_areas[left] = panes[left].get_area(); - uistate.adv_inv_default_areas[right] = panes[right].get_area(); + save_state->saved_area = panes[left].get_area(); + save_state->saved_area_right = panes[right].get_area(); popup( _( "Default layout was saved." ) ); redraw = true; } else if( get_square( action, changeSquare ) ) { @@ -1352,7 +1328,6 @@ void advanced_inventory::display() } else if( action == "SORT" ) { if( show_sort_menu( spane ) ) { recalc = true; - uistate.adv_inv_sort[src] = spane.sortby; } redraw = true; } else if( action == "FILTER" ) { @@ -1575,7 +1550,7 @@ bool advanced_inventory::query_destination( aim_location &def ) } } // Selected keyed to uilist.entries, which starts at 0. - menu.selected = uistate.adv_inv_last_popup_dest - AIM_SOUTHWEST; + menu.selected = save_state->last_popup_dest - AIM_SOUTHWEST; // generate and show window. menu.show(); // query, but don't loop @@ -1590,7 +1565,7 @@ bool advanced_inventory::query_destination( aim_location &def ) // we have to set the destination pane so that move actions will target it // we can use restore_area later to undo this panes[dest].set_area( squares[def], true ); - uistate.adv_inv_last_popup_dest = menu.ret; + save_state->last_popup_dest = menu.ret; return true; } return false; @@ -1839,6 +1814,8 @@ void advanced_inventory::swap_panes() { // Switch left and right pane. std::swap( panes[left], panes[right] ); + // Switch save states + std::swap( panes[left].save_state, panes[right].save_state ); // Window pointer must be unchanged! std::swap( panes[left].window, panes[right].window ); // Recalculation required for weight & volume @@ -1852,15 +1829,15 @@ void advanced_inventory::do_return_entry() save_settings( true ); g->u.assign_activity( ACT_ADV_INVENTORY ); g->u.activity.auto_resume = true; - uistate.adv_inv_exit_code = exit_re_entry; + save_state->exit_code = exit_re_entry; } bool advanced_inventory::is_processing() const { - return uistate.adv_inv_re_enter_move_all != ENTRY_START; + return save_state->re_enter_move_all != ENTRY_START; } void cancel_aim_processing() { - uistate.adv_inv_re_enter_move_all = ENTRY_START; + uistate.transfer_save.re_enter_move_all = ENTRY_START; } diff --git a/src/advanced_inv.h b/src/advanced_inv.h index 78605f1b2dd05..ea081c6799dfd 100644 --- a/src/advanced_inv.h +++ b/src/advanced_inv.h @@ -17,6 +17,8 @@ class uilist; class vehicle; class item; +struct advanced_inv_save_state; + struct sort_case_insensitive_less : public std::binary_function< char, char, bool > { bool operator()( char x, char y ) const { return toupper( static_cast< unsigned char >( x ) ) < toupper( static_cast< unsigned char >( y ) ); @@ -108,11 +110,10 @@ class advanced_inventory std::array squares; catacurses::window head; - catacurses::window left_window; - catacurses::window right_window; bool exit = false; + advanced_inv_save_state *save_state; // store/load settings (such as index, filter, etc) void save_settings( bool only_panes ); void load_settings(); diff --git a/src/advanced_inv_pane.cpp b/src/advanced_inv_pane.cpp index 067b682e92ba9..11468080586ba 100644 --- a/src/advanced_inv_pane.cpp +++ b/src/advanced_inv_pane.cpp @@ -29,6 +29,7 @@ #include "advanced_inv_pane.h" #include "vehicle.h" #include "map.h" +#include "options.h" #include #include @@ -44,6 +45,35 @@ #if defined(__ANDROID__) # include #endif +void advanced_inventory_pane::save_settings() +{ + save_state->in_vehicle = in_vehicle(); + save_state->area_idx = get_area(); + save_state->selected_idx = index; + save_state->filter = filter; + save_state->sort_idx = sortby; +} + +void advanced_inventory_pane::load_settings( int saved_area_idx, + const std::array &squares, bool is_re_enter ) +{ + const int i_location = ( get_option( "OPEN_DEFAULT_ADV_INV" ) ) ? saved_area_idx : + save_state->area_idx; + const aim_location location = static_cast( i_location ); + auto square = squares[location]; + // determine the square's vehicle/map item presence + bool has_veh_items = square.can_store_in_vehicle() ? + !square.veh->get_items( square.vstor ).empty() : false; + bool has_map_items = !g->m.i_at( square.pos ).empty(); + // determine based on map items and settings to show cargo + bool show_vehicle = is_re_enter ? + save_state->in_vehicle : has_veh_items ? true : + has_map_items ? false : square.can_store_in_vehicle(); + set_area( square, show_vehicle ); + sortby = static_cast( save_state->sort_idx ); + index = save_state->selected_idx; + filter = save_state->filter; +} bool advanced_inventory_pane::is_filtered( const advanced_inv_listitem &it ) const { diff --git a/src/advanced_inv_pane.h b/src/advanced_inv_pane.h index e20d91843c4ac..86c1e4b672643 100644 --- a/src/advanced_inv_pane.h +++ b/src/advanced_inv_pane.h @@ -10,6 +10,8 @@ #include #include +struct advanced_inv_pane_save_state; + enum aim_location : char; enum advanced_inv_sortby { @@ -57,9 +59,10 @@ class advanced_inventory_pane bool in_vehicle() const { return viewing_cargo; } - bool on_ground() const { - return area > AIM_INVENTORY && area < AIM_DRAGGED; - } + advanced_inv_pane_save_state *save_state; + void save_settings(); + void load_settings( int saved_area_idx, + const std::array &squares, bool is_re_enter ); /** * Index of the selected item (index of @ref items), */ diff --git a/src/uistate.h b/src/uistate.h index 8a70e4e9f0777..aea5f15eeeb94 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -14,6 +14,71 @@ class item; + +struct advanced_inv_pane_save_state { + public: + int sort_idx = 1; + std::string filter; + int area_idx = 11; + int selected_idx = 0; + + bool in_vehicle = false; + + template + void serialize( JsonStream &json, std::string prefix ) const { + json.member( prefix + "sort_idx", sort_idx ); + json.member( prefix + "filter", filter ); + json.member( prefix + "area_idx", area_idx ); + json.member( prefix + "selected_idx", selected_idx ); + json.member( prefix + "in_vehicle", in_vehicle ); + } + + void deserialize( JsonObject &jo, std::string prefix ) { + jo.read( prefix + "sort_idx", sort_idx ); + jo.read( prefix + "filter", filter ); + jo.read( prefix + "area_idx", area_idx ); + jo.read( prefix + "selected_idx", selected_idx ); + jo.read( prefix + "in_vehicle", in_vehicle ); + } +}; + +struct advanced_inv_save_state { + public: + int exit_code = 0; + int re_enter_move_all = 0; + int aim_all_location = 1; + + bool active_left = true; + int last_popup_dest = 0; + + int saved_area = 11; + int saved_area_right = 0; + advanced_inv_pane_save_state pane; + advanced_inv_pane_save_state pane_right; + + template + void serialize( JsonStream &json, std::string prefix ) const { + json.member( prefix + "active_left", active_left ); + json.member( prefix + "last_popup_dest", last_popup_dest ); + + json.member( prefix + "saved_area", saved_area ); + json.member( prefix + "saved_area_right", saved_area_right ); + pane.serialize( json, prefix + "pane_" ); + pane_right.serialize( json, prefix + "pane_right_" ); + } + + void deserialize( JsonObject &jo, std::string prefix ) { + jo.read( prefix + "active_left", active_left ); + jo.read( prefix + "last_popup_dest", last_popup_dest ); + + jo.read( prefix + "saved_area", saved_area ); + jo.read( prefix + "saved_area_right", saved_area_right ); + pane.area_idx = saved_area; + pane_right.area_idx = saved_area_right; + pane.deserialize( jo, prefix + "pane_" ); + pane_right.deserialize( jo, prefix + "pane_right_" ); + } +}; /* centralized depot for trivial ui data such as sorting, string_input_popup history, etc. To use this, see the ****notes**** below @@ -27,7 +92,7 @@ class uistatedata private: // not needed for compilation, but keeps syntax plugins happy using itype_id = std::string; - enum side { left = 0, right = 1, NUM_PANES = 2 }; + enum side { left = 0, right = 1, NUM_PANES = 2 }; public: int ags_pay_gas_selected_pump = 0; @@ -35,25 +100,15 @@ class uistatedata int wishmutate_selected = 0; int wishmonster_selected = 0; int iexamine_atm_selected = 0; - std::array adv_inv_sort = {{1, 1}}; - std::array adv_inv_area = {{5, 0}}; - std::array adv_inv_index = {{0, 0}}; - std::array adv_inv_in_vehicle = {{false, false}}; - std::array adv_inv_filter = {{"", ""}}; - std::array adv_inv_default_areas = {{11, 0}}; //left: All, right: Inventory - int adv_inv_src = left; - int adv_inv_dest = right; - int adv_inv_last_popup_dest = 0; + int adv_inv_container_location = -1; int adv_inv_container_index = 0; - int adv_inv_exit_code = 0; itype_id adv_inv_container_type = "null"; itype_id adv_inv_container_content_type = "null"; - int adv_inv_re_enter_move_all = 0; - int adv_inv_aim_all_location = 1; - std::map> adv_inv_veh_items, adv_inv_map_items; bool adv_inv_container_in_vehicle = false; + advanced_inv_save_state transfer_save; + bool editmap_nsa_viewmode = false; // true: ignore LOS and lighting bool overmap_blinking = true; // toggles active blinking of overlays. bool overmap_show_overlays = false; // whether overlays are shown or not. @@ -63,11 +118,6 @@ class uistatedata bool overmap_show_hordes = true; bool overmap_show_forest_trails = true; - bool debug_ranged = false; - tripoint adv_inv_last_coords = {-999, -999, -999}; - int last_inv_start = -2; - int last_inv_sel = -2; - // V Menu Stuff int list_item_sort = 0; std::string list_item_filter; @@ -125,17 +175,10 @@ class uistatedata const unsigned int input_history_save_max = 25; json.start_object(); + transfer_save.serialize( json, "transfer_save_" ); + /**** if you want to save whatever so it's whatever when the game is started next, declare here and.... ****/ - serialize_array( json, "adv_inv_sort", adv_inv_sort ); - serialize_array( json, "adv_inv_area", adv_inv_area ); - serialize_array( json, "adv_inv_index", adv_inv_index ); - serialize_array( json, "adv_inv_in_vehicle", adv_inv_in_vehicle ); - serialize_array( json, "adv_inv_filter", adv_inv_filter ); - serialize_array( json, "adv_inv_default_areas", adv_inv_default_areas ); // non array stuffs - json.member( "adv_inv_src", adv_inv_src ); - json.member( "adv_inv_dest", adv_inv_dest ); - json.member( "adv_inv_last_popup_dest", adv_inv_last_popup_dest ); json.member( "adv_inv_container_location", adv_inv_container_location ); json.member( "adv_inv_container_index", adv_inv_container_index ); json.member( "adv_inv_container_in_vehicle", adv_inv_container_in_vehicle ); @@ -182,54 +225,9 @@ class uistatedata template void deserialize( JsonStream &jsin ) { auto jo = jsin.get_object(); - /**** here ****/ - if( jo.has_array( "adv_inv_sort" ) ) { - auto tmp = jo.get_int_array( "adv_inv_sort" ); - std::move( tmp.begin(), tmp.end(), adv_inv_sort.begin() ); - } else { - jo.read( "adv_inv_leftsort", adv_inv_sort[left] ); - jo.read( "adv_inv_rightsort", adv_inv_sort[right] ); - } - // pane area selected - if( jo.has_array( "adv_inv_area" ) ) { - auto tmp = jo.get_int_array( "adv_inv_area" ); - std::move( tmp.begin(), tmp.end(), adv_inv_area.begin() ); - } else { - jo.read( "adv_inv_leftarea", adv_inv_area[left] ); - jo.read( "adv_inv_rightarea", adv_inv_area[right] ); - } - // pane current index - if( jo.has_array( "adv_inv_index" ) ) { - auto tmp = jo.get_int_array( "adv_inv_index" ); - std::move( tmp.begin(), tmp.end(), adv_inv_index.begin() ); - } else { - jo.read( "adv_inv_leftindex", adv_inv_index[left] ); - jo.read( "adv_inv_rightindex", adv_inv_index[right] ); - } - // viewing vehicle cargo - if( jo.has_array( "adv_inv_in_vehicle" ) ) { - const JsonArray ja = jo.get_array( "adv_inv_in_vehicle" ); - for( size_t i = 0; i < adv_inv_in_vehicle.size() && i < ja.size(); ++i ) { - adv_inv_in_vehicle[i] = ja.get_bool( i ); - } - } - // filter strings - if( jo.has_array( "adv_inv_filter" ) ) { - auto tmp = jo.get_string_array( "adv_inv_filter" ); - std::move( tmp.begin(), tmp.end(), adv_inv_filter.begin() ); - } else { - jo.read( "adv_inv_leftfilter", adv_inv_filter[left] ); - jo.read( "adv_inv_rightfilter", adv_inv_filter[right] ); - } - // default areas - if( jo.has_array( "adv_inv_deafult_areas" ) ) { - auto tmp = jo.get_int_array( "adv_inv_deafult_areas" ); - std::move( tmp.begin(), tmp.end(), adv_inv_default_areas.begin() ); - } + + transfer_save.deserialize( jo, "transfer_save_" ); // the rest - jo.read( "adv_inv_src", adv_inv_src ); - jo.read( "adv_inv_dest", adv_inv_dest ); - jo.read( "adv_inv_last_popup_dest", adv_inv_last_popup_dest ); jo.read( "adv_inv_container_location", adv_inv_container_location ); jo.read( "adv_inv_container_index", adv_inv_container_index ); jo.read( "adv_inv_container_in_vehicle", adv_inv_container_in_vehicle ); From 6b21259f6770ce4a0301b695dad1a99783acc40f Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Sun, 15 Mar 2020 14:55:50 +0300 Subject: [PATCH 208/219] Refluff power armour and adjust stats slightly (#37578) --- data/json/items/armor/power_armor.json | 49 +++++++++++++------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/data/json/items/armor/power_armor.json b/data/json/items/armor/power_armor.json index 9749a669768af..f19ed171154cb 100644 --- a/data/json/items/armor/power_armor.json +++ b/data/json/items/armor/power_armor.json @@ -5,7 +5,7 @@ "category": "armor", "name": { "str": "salvaged power armor" }, "//": "These are much cheaper than powered suits, because they're extremely heavy and impractical. The good stuff is gone!", - "description": "The DoubleTech Power Armor, Mk. I: A heavy suit of basic power armor, offering very good protection against attacks, but hard to move in. This suit has had its servos and cooling system stripped out, meaning it no longer requires power, but also encumbers you greatly and doesn't provide internal thermal regulation.", + "description": "This used to be a powered exoskeleton with a set of heavy armor plates, made wearable by the assist of the servos. Now it's just the armor plating and a stripped down chassis: as one might expect, it's a lot harder to wear.", "weight": "12214 g", "volume": "25 L", "price": 70000, @@ -30,7 +30,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "salvaged power armor helmet" }, - "description": "A basic helmet, designed for use with the DoubleTech Power Armor, Mk. I. Offers excellent protection from both attacks and environmental hazards. This suit has had its internal computer and cooling system stripped out, meaning it no longer requires power, but it has no internal chronometer and doesn't provide internal thermal regulation.", + "description": "This used to be a military-grade full-head helmet with advanced optics and environmental filters. It looks like it was decommissioned or otherwise stripped for parts; now it's a very expensive hat. It's still quite durable, but quite hard to see out of.", "weight": "2416 g", "volume": "5 L", "price": 30000, @@ -54,15 +54,15 @@ "id": "power_armor_basic", "type": "ARMOR", "category": "armor", - "name": { "str": "basic power armor" }, - "description": "The DoubleTech Power Armor, Mk. I: A heavy suit of basic power armor, offering very good protection against attacks, but hard to move in. The UPS compartment can store other things if you don't mind powering the suit yourself. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", - "weight": "20339 g", - "volume": "25 L", + "name": { "str": "combat exoskeleton" }, + "description": "These were the second wave of military combat exoskeleton, and got a lot of media attention, with popular Navy commercials featuring them heavily. It consists of a muscle-boosting exoskeleton frame with overlayed segmented alloy plating. Despite advancements over the original bulky 'tank suits', the wearer still cannot easily fit through narrow spaces, or sit down comfortably (and it ruins upholstery). There is an integrated chemical resistant bodyglove that precludes wearing other clothing.", + "weight": "55 kg", + "volume": "100 L", "price": 7000000, "price_postapoc": 7000000, "to_hit": 1, "bashing": 1, - "material": [ "steel" ], + "material": [ "hardsteel", "steel" ], "symbol": "[", "looks_like": "depowered_armor", "color": "light_gray", @@ -82,7 +82,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "power armor hauling frame" }, - "description": "A heavy-duty hauling frame designed to interface with power armor.", + "description": "A heavy duty hauling frame designed to interface with military exoskeletons.", "weight": "1640 g", "volume": "12 L", "price": 1000000, @@ -104,10 +104,11 @@ "id": "power_armor_heavy", "type": "ARMOR", "category": "armor", - "name": { "str": "heavy power armor" }, - "description": "A suit of DoubleTech Power Armor, Mk. II-H. This model offers several improvements over the Mk. I, most notably the improved environmental protection. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", - "weight": "29009 g", - "volume": "30 L", + "name": { "str": "heavy combat exoskeleton" }, + "description": "Colloquially known as a 'tank suit' in the media, these bulky exoskeletons, covered in thick segmented armor plates, were tested in military service a few years back and determined to be too heavy and expensive for regular use. Now that it's in your hands, though, you have a massive suit of power armor capable of resisting almost any small arms fire and most other forms of attack. On the other hand, it doubles your effective weight, and it's almost impossible not to bump into things. There is an integrated chemical resistant bodyglove that precludes wearing other clothing.", + "//": "This should probably changed to a pseudo-vehicle like the civilian exoskeleton", + "weight": "75 kg", + "volume": "130 L", "price": 11500000, "price_postapoc": 11500000, "to_hit": 1, @@ -131,15 +132,15 @@ "id": "power_armor_helmet_basic", "type": "ARMOR", "category": "armor", - "name": { "str": "basic power armor helmet" }, - "description": "A basic helmet, designed for use with the DoubleTech Power Armor, Mk. I. Offers excellent protection from both attacks and environmental hazards. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", + "name": { "str": "environmental combat helmet" }, + "description": "A fully enclosed combat helmet for hazardous environments, this was designed to fit with a powered exoskeleton, using cameras to expand visual range. In practice, the cameras were unreliable and easily fouled. The environmental controls function best with direct-skin contact.", "weight": "3628 g", "volume": "5 L", "price": 2500000, "price_postapoc": 2500000, "to_hit": 1, "bashing": 1, - "material": [ "steel" ], + "material": [ "hardsteel", "steel" ], "symbol": "[", "looks_like": "depowered_helmet", "color": "light_gray", @@ -157,8 +158,8 @@ "id": "power_armor_helmet_heavy", "type": "ARMOR", "category": "armor", - "name": { "str": "heavy power armor helmet" }, - "description": "A power armor helmet designed for use with the DoubleTech Power Armor, Mk. II-H. This improved design is heavier than the Mk. I helmet, but cooler, and offers better environmental protection. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", + "name": { "str": "heavy environmental combat helmet" }, + "description": "An extremely heavy-duty fully enclosed combat helmet for hazardous environments, this was designed to fit with a powered exoskeleton. In the field, soldiers reported that the protection was not worth the awkward size and limited visuals. The environmental controls function best with direct-skin contact.", "weight": "5442 g", "volume": "7 L", "price": 3750000, @@ -183,8 +184,8 @@ "id": "power_armor_helmet_light", "type": "ARMOR", "category": "armor", - "name": { "str": "light power armor helmet" }, - "description": "A power armor helmet designed for use with the DoubleTech Power Armor, Mk. II-L. This improved design is lighter and cooler than the Mk. I helmet. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", + "name": { "str": "light environmental combat helmet" }, + "description": "This full-enclosure helmet was designed based on commercial diving equipment, in response to complaints that earlier designs were impossible to use in combat. While still a little more restrictive than regular combat headgear - and frustrating should your nose itch - this one received far better reviews from soldiers. Sadly, civilization ended before they could roll out in significant numbers. The environmental controls function best with direct-skin contact.", "weight": "1814 g", "volume": "4 L", "price": 3750000, @@ -202,16 +203,16 @@ "power_armor": true, "material_thickness": 9, "environmental_protection": 16, - "qualities": [ [ "GLARE", 2 ] ], - "flags": [ "WATCH", "WATERPROOF", "STURDY", "PARTIAL_DEAF", "THERMOMETER", "SUN_GLASSES" ] + "qualities": [ [ "GLARE", 1 ] ], + "flags": [ "WATCH", "WATERPROOF", "STURDY", "THERMOMETER", "SUN_GLASSES" ] }, { "id": "power_armor_light", "type": "ARMOR", "category": "armor", - "name": { "str": "light power armor" }, - "description": "A suit of DoubleTech Power Armor, Mk. II-L. This model offers several improvements over the Mk. I, most notably the reduced weight. Like all DoubleTech power armor, the control and climate-regulation systems require direct skin contact.", - "weight": "7670 g", + "name": { "str": "field combat exoskeleton" }, + "description": "The final iteration of military power armor before the fall of civilization, this type - a powered exoskeleton with high-tech segmented plating - was designed for actual widespread combat use and was seen on the front lines during the last days of the cataclysm. Like the heavier suits, it is resistant to most modern weaponry, but it is light and maneuverable, and can fit into normal vehicles and doorways without fuss, a huge advantage over predecessors. Unfortunately, the world ended before it could roll out in significant numbers. There is an integrated chemical resistant bodyglove that precludes wearing other clothing.", + "weight": "12670 g", "volume": "15 L", "price": 11500000, "price_postapoc": 1150000, From 7fcca7ab308204ce8e23f354a39bbf57cf240e8e Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:12 +0100 Subject: [PATCH 209/219] Match armor layers ui and help text (#38762) --- src/armor_layers.cpp | 59 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index a8dc810618923..09635464c4ee7 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -526,7 +526,8 @@ void player::sort_armor() wprintz( w_sort_cat, c_white, _( "Sort Armor" ) ); wprintz( w_sort_cat, c_yellow, " << %s >>", armor_cat[tabindex] ); right_print( w_sort_cat, 0, 0, c_white, string_format( - _( "Press %s for help. Press %s to change keybindings." ), + _( "Press [%s] for help. " + "Press [%s] to change keybindings." ), ctxt.get_desc( "USAGE_HELP" ), ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); @@ -828,32 +829,36 @@ void player::sort_armor() } } } else if( action == "USAGE_HELP" ) { - popup_getkey( _( "Use the arrow- or keypad keys to navigate the left list.\n" - "[%s] to select highlighted armor for reordering.\n" - "[%s] / [%s] to scroll the right list.\n" - "[%s] to assign special inventory letters to clothing.\n" - "[%s] to change the side on which item is worn.\n" - "[%s] to sort armor into natural layer order.\n" - "[%s] to equip a new item.\n" - "[%s] to equip a new item at the currently selected position.\n" - "[%s] to remove selected armor from oneself.\n" - "\n" - "[Encumbrance and Warmth] explanation:\n" - "The first number is the summed encumbrance from all clothing on that bodypart.\n" - "The second number is an additional encumbrance penalty caused by wearing multiple items " - "on one of the bodypart's layers or wearing items outside of other items they would " - "normally be work beneath (e.g. a shirt over a backpack).\n" - "The sum of these values is the effective encumbrance value your character has for that bodypart." ), - ctxt.get_desc( "MOVE_ARMOR" ), - ctxt.get_desc( "PREV_TAB" ), - ctxt.get_desc( "NEXT_TAB" ), - ctxt.get_desc( "ASSIGN_INVLETS" ), - ctxt.get_desc( "CHANGE_SIDE" ), - ctxt.get_desc( "SORT_ARMOR" ), - ctxt.get_desc( "EQUIP_ARMOR" ), - ctxt.get_desc( "EQUIP_ARMOR_HERE" ), - ctxt.get_desc( "REMOVE_ARMOR" ) - ); + popup_getkey( + _( "Use the [arrow- or keypad keys] to navigate the left list.\n" + "[%s] to select highlighted armor for reordering.\n" + "[%s] / [%s] to scroll the right list.\n" + "[%s] to assign special inventory letters to clothing.\n" + "[%s] to change the side on which item is worn.\n" + "[%s] to sort armor into natural layer order.\n" + "[%s] to equip a new item.\n" + "[%s] to equip a new item at the currently selected position.\n" + "[%s] to remove selected armor from oneself.\n" + "\n" + "\n" + "Encumbrance explanation:\n" + "\n" + "The first number is the summed encumbrance from all clothing " + "on that bodypart. The second number is an additional encumbrance penalty " + "caused by wearing either multiple items on one of the bodypart's layers or " + "wearing items the wrong way (e.g. a shirt over a backpack). " + "The sum of these values is the effective encumbrance value " + "your character has for that bodypart." ), + ctxt.get_desc( "MOVE_ARMOR" ), + ctxt.get_desc( "PREV_TAB" ), + ctxt.get_desc( "NEXT_TAB" ), + ctxt.get_desc( "ASSIGN_INVLETS" ), + ctxt.get_desc( "CHANGE_SIDE" ), + ctxt.get_desc( "SORT_ARMOR" ), + ctxt.get_desc( "EQUIP_ARMOR" ), + ctxt.get_desc( "EQUIP_ARMOR_HERE" ), + ctxt.get_desc( "REMOVE_ARMOR" ) + ); draw_grid( w_sort_armor, left_w, middle_w ); } else if( action == "HELP_KEYBINDINGS" ) { draw_grid( w_sort_armor, left_w, middle_w ); From a666fc41410229ef35a0c471681307a005e87722 Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:25 +0100 Subject: [PATCH 210/219] Match advanced inventory UI and info text (#38763) --- src/advanced_inv.cpp | 7 +++---- src/output.cpp | 8 +++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index baa59d70f9931..0fc5f27cbc9a1 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -1077,10 +1077,9 @@ void advanced_inventory::display() draw_border( head ); Messages::display_messages( head, 2, 1, w_width - 1, head_height - 2 ); draw_minimap(); - const std::string msg = string_format( _( "< [%s] Show help >" ), - ctxt.get_desc( "HELP_KEYBINDINGS" ) ); - mvwprintz( head, point( w_width - ( minimap_width + 2 ) - utf8_width( msg ) - 1, 0 ), - c_white, msg ); + right_print( head, 0, +3, c_white, string_format( + _( "< [%s] keybindings >" ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); if( g->u.has_watch() ) { const std::string time = to_string_time_of_day( calendar::turn ); mvwprintz( head, point( 2, 0 ), c_white, time ); diff --git a/src/output.cpp b/src/output.cpp index 9850ef173667e..459daf60e54c3 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -773,21 +773,23 @@ void draw_item_filter_rules( const catacurses::window &win, int starty, int heig starty += fold_and_print( win, point( 1, starty ), len, c_white, // NOLINTNEXTLINE(cata-text-style): literal comma - _( "Separate multiple items with ," ) ); + _( "Separate multiple items with [,]." ) ); starty += 1 + fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to separate multiple items with a comma when filtering items. _( "Example: back,flash,aid, ,band" ) ); // NOLINT(cata-text-style): literal comma if( type == item_filter_type::FILTER ) { starty += fold_and_print( win, point( 1, starty ), len, c_white, - _( "To exclude items, place - in front." ) ); + _( "To exclude items, place [-] in front." ) ); starty += 1 + fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to exclude items with - when filtering items. _( "Example: -pipe,-chunk,-steel" ) ); } starty += fold_and_print( win, point( 1, starty ), len, c_white, - _( "Search [c]ategory, [m]aterial, [q]uality, [n]otes or [d]isassembled components:" ) ); + _( "Search [c]ategory, [m]aterial, " + "[q]uality, [n]otes or " + "[d]isassembled components." ) ); fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to filter items based on category or material. _( "Examples: c:food,m:iron,q:hammering,n:toolshelf,d:pipe" ) ); From 9b8218dc3d0f5baf0c5b6397e222fb7c30e4cb59 Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:37 +0100 Subject: [PATCH 211/219] Match message log filter info and construction filter (#38764) --- src/messages.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/messages.cpp b/src/messages.cpp index f9750c6c15071..801c29068eee3 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -750,11 +750,15 @@ void Messages::dialog::run() std::vector Messages::dialog::filter_help_text( int width ) { const auto &help_fmt = _( - "Format is [[TYPE]:]TEXT. The values for TYPE are: %s\n" - "Examples:\n" - " good:mutation\n" - " :you pick up: 1\n" - " crash!\n" + "The default is to search the entire message log. " + "Use message-types as prefixes followed by (:) to filter more specific.\n" + "Valid message-type values are: %s\n" + "\n" + "Examples:\n" + " good:mutation\n" + " :you pick up: 1\n" + " bad:\n" + "\n" ); std::string type_text; const auto &type_list = msg_type_and_names(); From 064a473ca38d767ec5a1410f8b39d49519db2531 Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:10:49 +0100 Subject: [PATCH 212/219] Match construction UI (#38765) --- src/construction.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/construction.cpp b/src/construction.cpp index f464a6f665344..e85ba7586c1d2 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -388,15 +388,19 @@ construction_id construction_menu( const bool blueprint ) std::vector notes; if( tabindex == tabcount - 1 && !filter.empty() ) { - notes.push_back( string_format( _( "Press %s to clear filter" ), + notes.push_back( string_format( _( "Press [%s] to clear filter" ), ctxt.get_desc( "RESET_FILTER" ) ) ); } - notes.push_back( string_format( _( "Press %s or %s to tab." ), ctxt.get_desc( "LEFT" ), + notes.push_back( string_format( _( "Press [%s or %s] " + "to tab." ), ctxt.get_desc( "LEFT" ), ctxt.get_desc( "RIGHT" ) ) ); - notes.push_back( string_format( _( "Press %s to search." ), ctxt.get_desc( "FILTER" ) ) ); - notes.push_back( string_format( _( "Press %s to toggle unavailable constructions." ), + notes.push_back( string_format( _( "Press [%s] " + "to search." ), ctxt.get_desc( "FILTER" ) ) ); + notes.push_back( string_format( _( "Press [%s] " + "to toggle unavailable constructions." ), ctxt.get_desc( "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ) ) ); - notes.push_back( string_format( _( "Press %s to view and edit key-bindings." ), + notes.push_back( string_format( _( "Press [%s] " + "to view and edit keybindings." ), ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); //leave room for top and bottom UI text From 7aee62a8578647fbb2258b6ca4a26d8917f5c0f5 Mon Sep 17 00:00:00 2001 From: Pupsi Mupsi <44737997+Pupsi-Mupsi@users.noreply.github.com> Date: Mon, 16 Mar 2020 00:11:39 +0100 Subject: [PATCH 213/219] Match player info and martial arts UI (#38766) --- src/player.cpp | 6 ++++-- src/player_display.cpp | 16 +++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/player.cpp b/src/player.cpp index b0e4e7ee05fbf..8cd97e6111fff 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -3220,8 +3220,10 @@ bool character_martial_arts::pick_style( const avatar &you ) // Style selection ctxt.register_action( "SHOW_DESCRIPTION" ); uilist kmenu; - kmenu.text = string_format( _( "Select a style. (press %s for more info)" ), - ctxt.get_desc( "SHOW_DESCRIPTION" ) ); + kmenu.text = colorize( string_format( _( "Select a style. " + "Press [%s] for more info." ), + "Press %s for more info.", + ctxt.get_desc( "SHOW_DESCRIPTION" ) ), c_white ); ma_style_callback callback( static_cast( STYLE_OFFSET ), selectable_styles ); kmenu.callback = &callback; kmenu.input_category = "MELEE_STYLE_PICKER"; diff --git a/src/player_display.cpp b/src/player_display.cpp index 3789f58e96e79..a580558cc10b7 100644 --- a/src/player_display.cpp +++ b/src/player_display.cpp @@ -503,7 +503,8 @@ static void draw_bionics_tab( const catacurses::window &w_bionics, const catacur center_print( w_bionics, 0, h_light_gray, _( title_BIONICS ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) trim_and_print( w_bionics, point( 1, 1 ), getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d / %2$d" ), + string_format( _( "Bionic Power: %1$d" + " / %2$d" ), units::to_kilojoule( you.get_power_level() ), units::to_kilojoule( you.get_max_power_level() ) ) ); const size_t useful_y = bionics_win_size_y - 1; @@ -550,7 +551,8 @@ static void draw_bionics_tab( const catacurses::window &w_bionics, const catacur center_print( w_bionics, 0, c_light_gray, _( title_BIONICS ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) trim_and_print( w_bionics, point( 1, 1 ), getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d / %2$d" ), + string_format( _( "Bionic Power: %1$d" + " / %2$d" ), units::to_kilojoule( you.get_power_level() ), units::to_kilojoule( you.get_max_power_level() ) ) ); for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y - 1; i++ ) { mvwprintz( w_bionics, point( 1, static_cast( i + 2 ) ), c_black, " " ); @@ -973,7 +975,8 @@ static void draw_initial_windows( const catacurses::window &w_stats, center_print( w_bionics, 0, c_light_gray, _( title_BIONICS ) ); // NOLINTNEXTLINE(cata-use-named-point-constants) trim_and_print( w_bionics, point( 1, 1 ), getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d / %2$d" ), + string_format( _( "Bionic Power: %1$d" + " / %2$d" ), units::to_kilojoule( you.get_power_level() ), units::to_kilojoule( you.get_max_power_level() ) ) ); for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y - 1; i++ ) { trim_and_print( w_bionics, point( 1, static_cast( i ) + 2 ), getmaxx( w_bionics ) - 1, c_white, @@ -1308,10 +1311,9 @@ void player::disp_info() ctxt.register_action( "HELP_KEYBINDINGS" ); std::string action; - std::string help_msg = string_format( _( "Press %s for help." ), - ctxt.get_desc( "HELP_KEYBINDINGS" ) ); - mvwprintz( w_tip, point( FULL_SCREEN_WIDTH - utf8_width( help_msg ), 0 ), c_light_red, help_msg ); - help_msg.clear(); + right_print( w_tip, 0, +4, c_white, string_format( + _( "< [%s] keybindings >" ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ) ); wrefresh( w_tip ); draw_initial_windows( w_stats, w_encumb, w_traits, w_bionics, w_effects, w_skills, w_speed, *this, From c3a3d8bd632d3cf506216e137c62e45c0f14010e Mon Sep 17 00:00:00 2001 From: NastyNate2612 <59994204+NastyNate2612@users.noreply.github.com> Date: Mon, 16 Mar 2020 05:04:40 -0700 Subject: [PATCH 214/219] Extracts and Concentrates pt 1 (#37936) --- data/json/items/tool/misc.json | 102 +++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/data/json/items/tool/misc.json b/data/json/items/tool/misc.json index 498c7b8409545..045ae7067326e 100644 --- a/data/json/items/tool/misc.json +++ b/data/json/items/tool/misc.json @@ -43,6 +43,30 @@ "color": "yellow", "flags": [ "WATCH", "ALARMCLOCK" ] }, + { + "type": "TOOL", + "id": "butane_can", + "name": { "str": "can of butane", "str_pl": "cans of butane" }, + "description": "A typical can of butane that you would normally use to fill a lighter. It could be useful as a fuel, but also as a solvent or chemical reagent.", + "symbol": "!", + "color": "dark_gray", + "looks_like": "spray_can", + "weight": "420 g", + "volume": "500 ml", + "price": 1500, + "initial_charges": 30, + "max_charges": 30, + "charges_per_use": 1, + "material": "steel", + "flags": [ "EXPLOSIVE", "EXPLODES" ], + "explosion": { + "power": 4503, + "distance_factor": 0.1, + "fire": true, + "shrapnel": { "casing_mass": 50, "fragment_mass": 0.05, "recovery": 0 } + }, + "explode_in_fire": true + }, { "id": "cow_bell", "type": "TOOL", @@ -58,6 +82,68 @@ "color": "brown", "use_action": "BELL" }, + { + "type": "TOOL", + "id": "dab_pen", + "name": { "str": "dab pen" }, + "description": "A battery operated dab pen used for smoking cannabis distillate cartridges.", + "symbol": "!", + "color": "dark_gray", + "looks_like": "ecig", + "weight": "20 g", + "volume": "100 ml", + "price": 2500, + "material": "plastic", + "ammo": "battery", + "magazines": [ + [ + "battery", + [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ] + ] + ], + "charges_per_use": 1, + "max_charges": 100, + "use_action": { + "target": "dab_pen_on", + "msg": "You turn on the dab pen.", + "active": true, + "need_charges": 1, + "need_charges_msg": "The dab pen's batteries need more charge.", + "type": "transform" + } + }, + { + "type": "TOOL", + "id": "dab_pen_on", + "name": { "str": "dab pen (on)", "str_pl": "dab pens (on)" }, + "description": "This dab pen, for vaporizing cannabis, is turned on. Now all you need is a distillate cartridge and you're ready to rock and roll.", + "symbol": "!", + "color": "dark_gray", + "looks_like": "ecig", + "weight": "20 g", + "volume": "100 ml", + "price": 2500, + "material": "plastic", + "ammo": "battery", + "power_draw": 9000, + "revert_to": "dab_pen", + "magazines": [ + [ + "battery", + [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ] + ] + ], + "charges_per_use": 1, + "max_charges": 100, + "use_action": { + "target": "dab_pen", + "msg": "You turn off the dab pen.", + "active": false, + "need_charges": 0, + "need_charges_msg": "The dab pen's batteries need more charge.", + "type": "transform" + } + }, { "id": "e_tool", "type": "TOOL", @@ -345,6 +431,22 @@ "weight": "600 g", "flags": [ "TRADER_AVOID" ] }, + { + "type": "TOOL", + "id": "gasket_plastic", + "name": { "str": "plastic gasket" }, + "description": " A single-use plastic gasket.", + "symbol": "(", + "color": "dark_gray", + "looks_like": "plastic_chunk", + "weight": "5 g", + "volume": "30 ml", + "//": "gasket sizes range from 1in diameter to 6in.", + "price": 150, + "to_hit": 10, + "bashing": 1, + "material": "plastic" + }, { "id": "permanent_marker", "type": "TOOL", From a726df9d896911f65f318f6e121ef3c77910ed87 Mon Sep 17 00:00:00 2001 From: np-vortex <58790761+np-vortex@users.noreply.github.com> Date: Mon, 16 Mar 2020 23:06:58 +0200 Subject: [PATCH 215/219] Add "forbidden traits" to professions (#36074) --- src/mutation.cpp | 31 +++++++++++++++++++++++++++++++ src/mutation.h | 7 +++++++ src/newcharacter.cpp | 3 +++ src/profession.cpp | 11 +++++++++++ src/profession.h | 3 +++ src/scenario.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- src/scenario.h | 1 + 7 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index be6c9f4be32f9..344087e87ad61 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1409,3 +1409,34 @@ void test_crossing_threshold( Character &guy, const mutation_category_trait &m_c guy.add_effect( effect_stunned, rng( 2_turns, 3_turns ) ); } } + +bool are_conflicting_traits( const trait_id &trait_1, const trait_id &trait_2 ) +{ + return ( are_opposite_traits( trait_1, trait_2 ) || b_is_lower_trait_of_a( trait_1, trait_2 ) + || b_is_higher_trait_of_a( trait_1, trait_2 ) || are_same_type_traits( trait_1, trait_2 ) ); +} + +bool are_opposite_traits( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( trait_a->cancels, trait_b ); +} + +bool b_is_lower_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( trait_a->prereqs, trait_b ); +} + +bool b_is_higher_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( trait_a->replacements, trait_b ); +} + +bool are_same_type_traits( const trait_id &trait_a, const trait_id &trait_b ) +{ + return contains_trait( get_mutations_in_types( trait_a->types ), trait_b ); +} + +bool contains_trait( std::vector> traits, const trait_id &trait ) +{ + return std::find( traits.begin(), traits.end(), trait ) != traits.end(); +} diff --git a/src/mutation.h b/src/mutation.h index 5926e6f68898f..63f449e05c7b9 100644 --- a/src/mutation.h +++ b/src/mutation.h @@ -465,6 +465,13 @@ std::vector get_mutations_in_types( const std::set &ids ) std::vector get_mutations_in_type( const std::string &id ); bool trait_display_sort( const trait_id &a, const trait_id &b ) noexcept; +bool are_conflicting_traits( const trait_id &trait_a, const trait_id &trait_b ); +bool b_is_lower_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ); +bool b_is_higher_trait_of_a( const trait_id &trait_a, const trait_id &trait_b ); +bool are_opposite_traits( const trait_id &trait_a, const trait_id &trait_b ); +bool are_same_type_traits( const trait_id &trait_a, const trait_id &trait_b ); +bool contains_trait( std::vector> traits, const trait_id &trait ); + enum class mutagen_technique : int { consumed_mutagen, injected_mutagen, diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 092ef74843c8d..88bc47204afbf 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1187,6 +1187,9 @@ tab_direction set_traits( const catacurses::window &w, avatar &u, points_left &p popup( _( "You already picked a conflicting trait!" ) ); } else if( g->scen->is_forbidden_trait( cur_trait ) ) { popup( _( "The scenario you picked prevents you from taking this trait!" ) ); + } else if( u.prof->is_forbidden_trait( cur_trait ) ) { + popup( _( "Your profession of %s prevents you from taking this trait." ), + u.prof->gender_appropriate_name( u.male ) ); } else if( iCurWorkingPage == 0 && num_good + mdata.points > max_trait_points && !points.is_freeform() ) { popup( ngettext( "Sorry, but you can only take %d point of advantages.", diff --git a/src/profession.cpp b/src/profession.cpp index 87f4c62ddd64f..4042e50c6e48b 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -225,6 +225,7 @@ void profession::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "CBMs", _starting_CBMs, auto_flags_reader {} ); // 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 {} ); optional( jo, was_loaded, "flags", flags, auto_flags_reader<> {} ); } @@ -465,6 +466,11 @@ std::vector profession::get_locked_traits() const return _starting_traits; } +std::set profession::get_forbidden_traits() const +{ + return _forbidden_traits; +} + profession::StartingSkillList profession::skills() const { return _starting_skills; @@ -486,6 +492,11 @@ bool profession::is_locked_trait( const trait_id &trait ) const _starting_traits.end(); } +bool profession::is_forbidden_trait( const trait_id &trait ) const +{ + return _forbidden_traits.count( trait ) != 0; +} + std::map profession::spells() const { return _starting_spells; diff --git a/src/profession.h b/src/profession.h index 61649631d7b31..28cc0ddd184ad 100644 --- a/src/profession.h +++ b/src/profession.h @@ -69,6 +69,7 @@ class profession std::vector _starting_addictions; std::vector _starting_CBMs; std::vector _starting_traits; + std::set _forbidden_traits; std::vector _starting_pets; vproto_id _starting_vehicle = vproto_id::NULL_ID(); // the int is what level the spell starts at @@ -128,7 +129,9 @@ class profession */ bool can_pick( const player &u, int points ) const; bool is_locked_trait( const trait_id &trait ) const; + bool is_forbidden_trait( const trait_id &trait ) const; std::vector get_locked_traits() const; + std::set get_forbidden_traits() const; }; #endif diff --git a/src/scenario.cpp b/src/scenario.cpp index 4f095057a826f..50997cf28db0a 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -299,16 +299,24 @@ std::vector> scenario::permitted_professions() const for( const profession &p : all ) { const bool present = std::find( professions.begin(), professions.end(), p.ident() ) != professions.end(); + + bool conflicting_traits = scenario_traits_conflict_with_profession_traits( p ); + if( blacklist || professions.empty() ) { - if( !present && !p.has_flag( "SCEN_ONLY" ) ) { + if( !present && !p.has_flag( "SCEN_ONLY" ) && !conflicting_traits ) { + res.push_back( p.ident() ); + } + } else if( present ) { + if( !conflicting_traits ) { res.push_back( p.ident() ); + } else { + debugmsg( "Scenario %s and profession %s have conflicting trait requirements", + id.c_str(), p.ident().c_str() ); } } else if( extra_professions ) { - if( present || !p.has_flag( "SCEN_ONLY" ) ) { + if( !p.has_flag( "SCEN_ONLY" ) && !conflicting_traits ) { res.push_back( p.ident() ); } - } else if( present ) { - res.push_back( p.ident() ); } } @@ -319,6 +327,33 @@ std::vector> scenario::permitted_professions() const return res; } +bool scenario::scenario_traits_conflict_with_profession_traits( const profession &p ) const +{ + for( auto &pt : p.get_forbidden_traits() ) { + if( is_locked_trait( pt ) ) { + return true; + } + } + + for( auto &pt : p.get_locked_traits() ) { + if( is_forbidden_trait( pt ) ) { + return true; + } + } + + // check if: + // locked traits for scenario prevent taking locked traits for professions + // locked traits for professions prevent taking locked traits for scenario + for( auto &st : get_locked_traits() ) { + for( auto &pt : p.get_locked_traits() ) { + if( are_conflicting_traits( st, pt ) || are_conflicting_traits( pt, st ) ) { + return true; + } + } + } + return false; +} + const profession *scenario::weighted_random_profession() const { // Strategy: 1/3 of the time, return the generic profession (if it's permitted). diff --git a/src/scenario.h b/src/scenario.h index da7aa116c34b3..78fd07c17afd8 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -50,6 +50,7 @@ class scenario std::vector _missions; void load( const JsonObject &jo, const std::string &src ); + bool scenario_traits_conflict_with_profession_traits( const profession &p ) const; public: //these three aren't meant for external use, but had to be made public regardless From 47e8fb0f550f3dadaabe70bf54e1273b684f4e06 Mon Sep 17 00:00:00 2001 From: klorpa <30924131+klorpa@users.noreply.github.com> Date: Tue, 17 Mar 2020 02:27:12 -0500 Subject: [PATCH 216/219] Volleyballs (#38192) --- .../Clothing_Gear/gear_civilian.json | 1 + .../locations_mapextras.json | 2 ++ .../Locations_MapExtras/mansion.json | 2 ++ data/json/itemgroups/activities_hobbies.json | 2 ++ data/json/itemgroups/supplies.json | 1 + data/json/items/armor/torso_clothes.json | 8 +++++ data/json/items/generic/toys_and_sports.json | 32 ++++++++++++++++++- data/json/mapgen/park.json | 1 + 8 files changed, 48 insertions(+), 1 deletion(-) diff --git a/data/json/itemgroups/Clothing_Gear/gear_civilian.json b/data/json/itemgroups/Clothing_Gear/gear_civilian.json index aad8f069982b7..d7d767a11db22 100644 --- a/data/json/itemgroups/Clothing_Gear/gear_civilian.json +++ b/data/json/itemgroups/Clothing_Gear/gear_civilian.json @@ -109,6 +109,7 @@ [ "novel_pulp", 16 ], [ "radio_car_box", 1 ], [ "basketball", 8 ], + [ "beach_volleyball", 8 ], [ "radiocontrol", 5 ], [ "whistle", 3 ], [ "slingshot", 10 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json index eabc414cc1fb6..5ba22bc41f2a2 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json @@ -195,6 +195,8 @@ [ "helmet_football", 20 ], [ "jersey", 100 ], [ "basketball", 100 ], + [ "beach_volleyball", 25 ], + [ "indoor_volleyball", 50 ], [ "armguard_soft", 50 ], [ "chestguard_hard", 20 ], [ "armguard_hard", 20 ], diff --git a/data/json/itemgroups/Locations_MapExtras/mansion.json b/data/json/itemgroups/Locations_MapExtras/mansion.json index 7a23ef26d3d0f..70996f84a8b51 100644 --- a/data/json/itemgroups/Locations_MapExtras/mansion.json +++ b/data/json/itemgroups/Locations_MapExtras/mansion.json @@ -747,6 +747,8 @@ [ "helmet_football", 10 ], [ "football", 60 ], [ "basketball", 50 ], + [ "beach_volleyball", 40 ], + [ "indoor_volleyball", 40 ], [ "helmet_bike", 25 ], [ "helmet_ball", 25 ], [ "headgear", 20 ], diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index 85dc53dacc185..00a8643e9c4d2 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -37,6 +37,8 @@ [ "jersey", 30 ], [ "puck", 30 ], [ "basketball", 25 ], + [ "indoor_volleyball", 20 ], + [ "beach_volleyball", 20 ], [ "golf_club", 35 ], [ "hat_golf", 20 ], [ "gloves_golf", 20 ], diff --git a/data/json/itemgroups/supplies.json b/data/json/itemgroups/supplies.json index d34df1cd111a7..87a2e370cba35 100644 --- a/data/json/itemgroups/supplies.json +++ b/data/json/itemgroups/supplies.json @@ -484,6 +484,7 @@ "type": "item_group", "items": [ [ "basketball", 100 ], + [ "indoor_volleyball", 50 ], [ "baseball", 100 ], [ "hat_ball", 10 ], [ "helmet_ball", 20 ], diff --git a/data/json/items/armor/torso_clothes.json b/data/json/items/armor/torso_clothes.json index 893e88631b97b..901d67bff1c8c 100644 --- a/data/json/items/armor/torso_clothes.json +++ b/data/json/items/armor/torso_clothes.json @@ -280,6 +280,14 @@ { "id": "monroeville", "text": "A hockey jersey made of thick material imprinted with the logo of the Monroeville Zombies." + }, + { + "id": "rugby", + "text": "A rugby jersey made of thick material imprinted with the logo of the Canberra Drop Bears." + }, + { + "id": "volleyball", + "text": "A volleyball jersey made of thick material imprinted with the logo of the Ooarai Ducks." } ], "flags": [ "VARSIZE" ] diff --git a/data/json/items/generic/toys_and_sports.json b/data/json/items/generic/toys_and_sports.json index 19f4f2cb86129..c4148a7296a1a 100644 --- a/data/json/items/generic/toys_and_sports.json +++ b/data/json/items/generic/toys_and_sports.json @@ -115,7 +115,7 @@ "name": { "str": "bowling ball" }, "description": "A large, heavy ball. Before the apocalypse, its main purpose was to be rolled along waxed floors.", "category": "other", - "price": 30, + "price": 3000, "material": "ceramic", "weight": "2000 g", "volume": "2500 ml", @@ -167,6 +167,36 @@ "bashing": 6, "to_hit": -1 }, + { + "type": "GENERIC", + "id": "indoor_volleyball", + "symbol": "*", + "color": "white", + "name": "volleyball", + "category": "other", + "description": "A standard regulation volleyball.", + "price": 1000, + "material": "leather", + "weight": "260 g", + "volume": "1 L", + "bashing": 4, + "to_hit": -1 + }, + { + "type": "GENERIC", + "id": "beach_volleyball", + "symbol": "*", + "color": "green", + "name": "beach volleyball", + "category": "other", + "description": "A brightly colored beach volleyball. It is slightly larger than a regular white one.", + "price": 1200, + "material": "leather", + "weight": "280 g", + "volume": "1 L", + "bashing": 4, + "to_hit": -1 + }, { "type": "GENERIC", "id": "puck", diff --git a/data/json/mapgen/park.json b/data/json/mapgen/park.json index b1cada928c3c3..0c1b13e5adbab 100644 --- a/data/json/mapgen/park.json +++ b/data/json/mapgen/park.json @@ -157,6 +157,7 @@ ], "palettes": [ "park_asphalt_palette" ], "items": { "b": { "item": "shoes", "chance": 15, "repeat": [ 2, 5 ] } }, + "place_item": [ { "item": "beach_volleyball", "x": 8, "y": 6 } ], "monsters": { "$": { "monster": "GROUP_PARK_SCENIC", "chance": 50 }, " ": { "monster": "GROUP_PARK_PLAYGROUND", "chance": 100 } } } }, From 39e00e3a7f2d36218a6fe353a56ff000ba8645b6 Mon Sep 17 00:00:00 2001 From: Sergey Alirzaev Date: Wed, 18 Mar 2020 09:25:14 +0300 Subject: [PATCH 217/219] Display damage per second in the item info (#38600) * Display damage per second in the item info So you can quickly eyeball the weapon effectiveness versus plain meatbags * Added DPS to tests --- src/item.cpp | 4 ++++ tests/iteminfo_test.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/item.cpp b/src/item.cpp index b64f75b17bed5..ac1e82f4fecee 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1212,6 +1212,10 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::BASE_MOVES ) ) { info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", iteminfo::lower_is_better, attack_time() ) ); + double dps = ( dmg_bash + dmg_cut + dmg_stab ) * to_moves( 1_seconds ) / + static_cast( attack_time() ); + info.push_back( iteminfo( "BASE", _( "Damage per second: " ), "", + iteminfo::is_decimal, dps ) ); } } diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index a8f1250f4df77..1e8ff78b45ca0 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -50,7 +50,8 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo]" ) "Bash: 20" " Cut: 5" " To-hit bonus: +2\n" - "Moves per attack: 145\n" ); + "Moves per attack: 145\n" + "Damage per second: 17.24\n" ); } From 53e61dc77d3043327cec37f68f903704a50547b3 Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Wed, 18 Mar 2020 10:19:19 +0300 Subject: [PATCH 218/219] Update bionics_ui.cpp --- src/bionics_ui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index add9859484d73..3654d7d0758e4 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -14,6 +14,7 @@ #include "options.h" #include "string_id.h" + // '!', '-' and '=' are uses as default bindings in the menu const invlet_wrapper bionic_chars( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"#&()*+./:;@[\\]^_{|}" ); From 2bed7a8823f1d1e53f076f8fefad26417c02933f Mon Sep 17 00:00:00 2001 From: ZhilkinSerg Date: Wed, 18 Mar 2020 10:21:21 +0300 Subject: [PATCH 219/219] Update CRT_Bladework.json --- data/mods/CRT_EXPANSION/martial/CRT_Bladework.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json index 62a6c43085714..310a6094e8dc9 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json @@ -32,7 +32,7 @@ { "stat": "damage", "type": "stab", "scale": 1.0 }, { "stat": "damage", "type": "cut", "scale": 1.0 }, { "stat": "arpen", "type": "stab", "scale": 1.0 }, - { "stat": "arpen", "type": "cut", "scale": 1.0 } + { "stat": "arpen", "type": "cut", "scale": 1 } ] } ],