diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c6951bb7..880470360 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required ( VERSION 3.1 ) +cmake_minimum_required ( VERSION 3.25 ) project ( OpenXcom ) @@ -47,7 +47,10 @@ if ( APPLE ) endif () # C++ version check -if ( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) +# Both flag checks fail on clang-cl, no idea why. +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_SIMULATE_ID MATCHES "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") +elseif ( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17) CHECK_CXX_COMPILER_FLAG("-std=c++1z" COMPILER_SUPPORTS_CXX1Z) diff --git a/bin/common/Language/OXCE/en-GB.yml b/bin/common/Language/OXCE/en-GB.yml index 05e2e7414..8e517ea52 100644 --- a/bin/common/Language/OXCE/en-GB.yml +++ b/bin/common/Language/OXCE/en-GB.yml @@ -286,6 +286,9 @@ en-GB: STR_LOAD_PERSONAL_EQUIPMENT: "Load Personal Equipment" STR_PERSONAL_EQUIPMENT_SAVED: "Personal equipment saved." STR_SLOT: "Slot>{ALT}{0}" + #=== Kaizoku ==================== + STR_SOLDIER_NOT_ALLOWED_IN_MISSION: "Soldier not allowed in mission>{ALT} {0}{ALT}" + STR_ITEMS_NOT_ALLOWED_IN_MISSION: "Items not allowed in {0}>{ALT} {1}{ALT}" #Map.cpp STR_THINKING: "Thinking..." #NextTurnState.cpp @@ -382,6 +385,19 @@ en-GB: STR_AUTOMATICPROMOTIONS_DESC: "If enabled, soldiers are automatically promoted after a mission." STR_OFF_CENTRE_SHOOTING: "Off-centre shooting" STR_OFF_CENTRE_SHOOTING_DESC: "Soldiers will automatically try to adjust the firing angle slightly in case there is no line of fire." +#=== Kaizoku ==================== + STR_NEW_BASE_HOVER_AREA_INFO: "Display area when placing new base" + STR_NEW_BASE_HOVER_AREA_INFO_DESC: "Show the country and region under the cursor when placing a new base. 0: Off 1: Top 2: Bottom" + STR_LISTS_SCREEN_HEIGHT_PERCENTAGE: "Lists screen height percentage" + STR_LISTS_SCREEN_HEIGHT_PERCENTAGE_DESC: "Changes the height of most list screens to a percentage of the game's vertical resolution. Set to 0 to disable." + STR_SYSTEM_CURSOR: "Show system cursor" + STR_SYSTEM_CURSOR_DESC: "Jank double cursor mode (hiding game cursor breaks battlescape)" + STR_STRICT_INVENTORY_WEAPON_CATEGORY_SEARCH: "Strict weapon category matching" + STR_STRICT_INVENTORY_WEAPON_CATEGORY_SEARCH_DESC: "Ignores ammo categories for weapons in inventory search (useful for X-Piratez infiltration and similar missions)" + STR_INVENTORY_SEARCH_IGNORE_RESEARCHED: "Inventory search ignore researched" + STR_INVENTORY_SEARCH_IGNORE_RESEARCHED_DESC: "Ignore researched status when matching categories" + STR_INVENTORY_FORBIDDEN_ITEMS: "Show forbidden items in inventory" + STR_INVENTORY_FORBIDDEN_ITEMS_DESC: "Shows items, armors and soldiers not allowed in certain geoscape missions on the inventory screen. Might not display correctly on low resolutions." #=================== STR_GRAPHS_ZOOM_IN: "Zoom In (Graphs)" STR_GRAPHS_ZOOM_OUT: "Zoom Out (Graphs)" @@ -511,7 +527,7 @@ en-GB: #OptionsAdvancedState.cpp STR_ENGINE_OXC: "OXC" STR_ENGINE_OXCE: "OXCE" - STR_ENGINE_OTHER: "OTHER" + STR_ENGINE_OTHER: "Kaizoku" STR_BASESCAPE: "Basescape" STR_AI: "AI" #OptionsBattlescapeState.cpp diff --git a/bin/common/Language/OXCE/en-US.yml b/bin/common/Language/OXCE/en-US.yml index 60db1a0aa..f51558d30 100644 --- a/bin/common/Language/OXCE/en-US.yml +++ b/bin/common/Language/OXCE/en-US.yml @@ -286,6 +286,9 @@ en-US: STR_LOAD_PERSONAL_EQUIPMENT: "Load Personal Equipment" STR_PERSONAL_EQUIPMENT_SAVED: "Personal equipment saved." STR_SLOT: "Slot>{ALT}{0}" + #=== Kaizoku ==================== + STR_SOLDIER_NOT_ALLOWED_IN_MISSION: "Soldier not allowed in mission>{ALT} {0}{ALT}" + STR_ITEMS_NOT_ALLOWED_IN_MISSION: "Items not allowed in {0}>{ALT} {1}{ALT}" #Map.cpp STR_THINKING: "Thinking..." #NextTurnState.cpp @@ -382,6 +385,19 @@ en-US: STR_AUTOMATICPROMOTIONS_DESC: "If enabled, soldiers are automatically promoted after a mission." STR_OFF_CENTRE_SHOOTING: "Off-center shooting" STR_OFF_CENTRE_SHOOTING_DESC: "Soldiers will automatically try to adjust the firing angle slightly in case there is no line of fire." +#=== Kaizoku ==================== + STR_NEW_BASE_HOVER_AREA_INFO: "Display area when placing new base" + STR_NEW_BASE_HOVER_AREA_INFO_DESC: "Show the country and region under the cursor when placing a new base. 0: Off 1: Top 2: Bottom" + STR_LISTS_SCREEN_HEIGHT_PERCENTAGE: "Lists screen height percentage" + STR_LISTS_SCREEN_HEIGHT_PERCENTAGE_DESC: "Changes the height of most list screens to a percentage of the game's vertical resolution. Set to 0 to disable." + STR_SYSTEM_CURSOR: "Show system cursor" + STR_SYSTEM_CURSOR_DESC: "Jank double cursor mode (hiding game cursor breaks battlescape)" + STR_STRICT_INVENTORY_WEAPON_CATEGORY_SEARCH: "Strict weapon category matching" + STR_STRICT_INVENTORY_WEAPON_CATEGORY_SEARCH_DESC: "Ignores ammo categories for weapons in inventory search (useful for X-Piratez infiltration and similar missions)" + STR_INVENTORY_SEARCH_IGNORE_RESEARCHED: "Inventory search ignore researched" + STR_INVENTORY_SEARCH_IGNORE_RESEARCHED_DESC: "Ignore researched status when matching categories" + STR_INVENTORY_FORBIDDEN_ITEMS: "Show forbidden items in inventory" + STR_INVENTORY_FORBIDDEN_ITEMS_DESC: "Shows items, armors and soldiers not allowed in certain geoscape missions on the inventory screen. Might not display correctly on low resolutions." #=================== STR_GRAPHS_ZOOM_IN: "Zoom In (Graphs)" STR_GRAPHS_ZOOM_OUT: "Zoom Out (Graphs)" @@ -511,7 +527,7 @@ en-US: #OptionsAdvancedState.cpp STR_ENGINE_OXC: "OXC" STR_ENGINE_OXCE: "OXCE" - STR_ENGINE_OTHER: "OTHER" + STR_ENGINE_OTHER: "Kaizoku" STR_BASESCAPE: "Basescape" STR_AI: "AI" #OptionsBattlescapeState.cpp diff --git a/src/Basescape/CraftArmorState.h b/src/Basescape/CraftArmorState.h index dcb2d6c2e..6637f06a2 100644 --- a/src/Basescape/CraftArmorState.h +++ b/src/Basescape/CraftArmorState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include "SoldierSortUtil.h" @@ -37,7 +37,7 @@ struct SortFunctor; * Select Armor screen that lets the player * pick armor for the soldiers on the craft. */ -class CraftArmorState : public State +class CraftArmorState : public ListState { private: TextButton *_btnOk; diff --git a/src/Basescape/CraftEquipmentLoadState.h b/src/Basescape/CraftEquipmentLoadState.h index 921159ed9..e6b7fcf2e 100644 --- a/src/Basescape/CraftEquipmentLoadState.h +++ b/src/Basescape/CraftEquipmentLoadState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class CraftEquipmentState; /** * Craft Loadout Load window that allows changing of the equipment onboard. */ -class CraftEquipmentLoadState : public State +class CraftEquipmentLoadState : public ListState { private: CraftEquipmentState *_parent; diff --git a/src/Basescape/CraftEquipmentSaveState.h b/src/Basescape/CraftEquipmentSaveState.h index 13784d215..970621132 100644 --- a/src/Basescape/CraftEquipmentSaveState.h +++ b/src/Basescape/CraftEquipmentSaveState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -33,7 +33,7 @@ class CraftEquipmentState; /** * Craft Loadout Save window that allows saving of the equipment onboard to a global template. */ -class CraftEquipmentSaveState : public State +class CraftEquipmentSaveState : public ListState { private: CraftEquipmentState *_parent; diff --git a/src/Basescape/CraftEquipmentState.cpp b/src/Basescape/CraftEquipmentState.cpp index b3635f8d4..03f1e33e0 100644 --- a/src/Basescape/CraftEquipmentState.cpp +++ b/src/Basescape/CraftEquipmentState.cpp @@ -43,6 +43,7 @@ #include "../Savegame/Craft.h" #include "../Mod/RuleCraft.h" #include "../Savegame/ItemContainer.h" +#include "../Savegame/Soldier.h" #include "../Mod/RuleItemCategory.h" #include "../Mod/RuleItem.h" #include "../Savegame/Vehicle.h" @@ -78,7 +79,9 @@ CraftEquipmentState::CraftEquipmentState(Base *base, size_t craft) : _btnQuickSearch = new TextEdit(this, 48, 9, 264, 12); _btnOk = new TextButton((craftHasACrew || _isNewBattle)?30:140, 16, (craftHasACrew || _isNewBattle)?274:164, 176); _btnClear = new TextButton(102, 16, 164, 176); - _btnInventory = new TextButton(102, 16, 164, 176); + _btnInventory = new TextButton(70, 16, 196, 176); + _btnInventoryPlus = new TextButton(16, 16, 164, 176); + _btnInventoryMinus = new TextButton(16, 16, 180, 176); _txtTitle = new Text(300, 17, 16, 7); _txtItem = new Text(144, 9, 16, 32); _txtStores = new Text(150, 9, 160, 32); @@ -98,6 +101,8 @@ CraftEquipmentState::CraftEquipmentState(Base *base, size_t craft) : add(_btnOk, "button", "craftEquipment"); add(_btnClear, "button", "craftEquipment"); add(_btnInventory, "button", "craftEquipment"); + add(_btnInventoryPlus, "button", "craftEquipment"); + add(_btnInventoryMinus, "button", "craftEquipment"); add(_txtTitle, "text", "craftEquipment"); add(_txtItem, "text", "craftEquipment"); add(_txtStores, "text", "craftEquipment"); @@ -128,6 +133,14 @@ CraftEquipmentState::CraftEquipmentState(Base *base, size_t craft) : _btnInventory->setVisible(craftHasACrew && !_isNewBattle); _btnInventory->onKeyboardPress((ActionHandler)&CraftEquipmentState::btnInventoryClick, Options::keyBattleInventory); + _btnInventoryPlus->setText("+"); + _btnInventoryPlus->onMouseClick((ActionHandler)&CraftEquipmentState::btnInventoryClick); + _btnInventoryPlus->setVisible(craftHasACrew && !_isNewBattle); + + _btnInventoryMinus->setText("-"); + _btnInventoryMinus->onMouseClick((ActionHandler)&CraftEquipmentState::btnInventoryClick); + _btnInventoryMinus->setVisible(craftHasACrew && !_isNewBattle); + _txtTitle->setBig(); _txtTitle->setText(tr("STR_EQUIPMENT_FOR_CRAFT").arg(c->getName(_game->getLanguage()))); @@ -268,6 +281,7 @@ void CraftEquipmentState::init() } initList(); } + _reload = true; _returningFromGlobalTemplates = false; _returningFromInventory = false; @@ -942,13 +956,50 @@ void CraftEquipmentState::btnClearClick(Action *) * inside the craft. * @param action Pointer to an action. */ -void CraftEquipmentState::btnInventoryClick(Action *) +void CraftEquipmentState::btnInventoryClick(Action *action) { Craft *craft = _base->getCrafts()->at(_craft); if (craft->getNumTotalSoldiers() > 0) { - if (Options::oxceAlternateCraftEquipmentManagement && !_isNewBattle) + bool apocInventory = (action->getSender() == _btnInventoryMinus) || (Options::oxceAlternateCraftEquipmentManagement && !action->isMouseAction()) || _game->isAltPressed(); + bool fullInventory = (action->getSender() == _btnInventoryPlus) || _game->isCtrlPressed(); + if ((apocInventory || fullInventory) && !_isNewBattle) { + // Find all equipped items in the base so that we can filter these "reserved" items out when using Apocalypse style inventory management. Adapted from Craft::calculateTotalSoldierEquipment() + ItemContainer tempBaseSoldierEquipmentItems; + if (apocInventory && !fullInventory) + { + for (auto *soldier : *_base->getSoldiers()) + { + Craft *soldier_craft = soldier->getCraft(); + if (soldier_craft != 0) + { + if (soldier_craft->getStatus() == "STR_OUT") + continue; + } + if (soldier_craft != craft) + { + for (auto *invItem : *soldier->getEquipmentLayout()) + { + // ignore fixed weapons... + if (!invItem->isFixed()) + { + tempBaseSoldierEquipmentItems.addItem(invItem->getItemType()); + } + // ...but not their ammo + for (int slot = 0; slot < RuleItem::AmmoSlotMax; ++slot) + { + const RuleItem* invItemAmmo = invItem->getAmmoItemForSlot(slot); + if (invItemAmmo != nullptr) + { + tempBaseSoldierEquipmentItems.addItem(invItemAmmo); + } + } + } + } + } + } + // This is a bit tricky... here's what we're doing: // * Remember the extra craft items (i.e. items that are on the craft, but not equipped by soldiers) // * Move all equipment from the base into the craft. @@ -970,7 +1021,14 @@ void CraftEquipmentState::btnInventoryClick(Action *) } if (!rule->getVehicleUnit() && rule->canBeEquippedBeforeBaseDefense()) { - moveRightByValue(INT_MAX, true); + if (apocInventory && !fullInventory) + { + moveRightByValue(_base->getStorageItems()->getItem(rule) - tempBaseSoldierEquipmentItems.getItem(rule), true); + } + else + { + moveRightByValue(INT_MAX, true); + } } } } diff --git a/src/Basescape/CraftEquipmentState.h b/src/Basescape/CraftEquipmentState.h index a6066676c..c4d47997e 100644 --- a/src/Basescape/CraftEquipmentState.h +++ b/src/Basescape/CraftEquipmentState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include #include @@ -38,10 +38,10 @@ class Base; * Equipment screen that lets the player * pick the equipment to carry on a craft. */ -class CraftEquipmentState : public State +class CraftEquipmentState : public ListState { private: - TextButton *_btnOk, *_btnClear, *_btnInventory; + TextButton *_btnOk, *_btnClear, *_btnInventory, *_btnInventoryPlus, *_btnInventoryMinus; TextEdit *_btnQuickSearch; Window *_window; Text *_txtTitle, *_txtItem, *_txtStores, *_txtAvailable, *_txtUsed, *_txtCrew; diff --git a/src/Basescape/CraftPilotSelectState.h b/src/Basescape/CraftPilotSelectState.h index 1a574acb8..a94e3baa9 100644 --- a/src/Basescape/CraftPilotSelectState.h +++ b/src/Basescape/CraftPilotSelectState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -33,7 +33,7 @@ class TextList; /** * Select Pilot window that allows assigning a pilot to a craft. */ -class CraftPilotSelectState : public State +class CraftPilotSelectState : public ListState { private: Base *_base; diff --git a/src/Basescape/CraftPilotsState.h b/src/Basescape/CraftPilotsState.h index e8e067e45..e836366d2 100644 --- a/src/Basescape/CraftPilotsState.h +++ b/src/Basescape/CraftPilotsState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -31,7 +31,7 @@ class TextList; /** * Displays info about craft pilot(s). */ -class CraftPilotsState : public State +class CraftPilotsState : public ListState { private: Base *_base; diff --git a/src/Basescape/CraftSoldiersState.h b/src/Basescape/CraftSoldiersState.h index 4498ae2de..fef9e4b16 100644 --- a/src/Basescape/CraftSoldiersState.h +++ b/src/Basescape/CraftSoldiersState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include "SoldierSortUtil.h" @@ -37,7 +37,7 @@ struct SortFunctor; * Select Squad screen that lets the player * pick the soldiers to assign to a craft. */ -class CraftSoldiersState : public State +class CraftSoldiersState : public ListState { private: TextButton *_btnOk; diff --git a/src/Basescape/CraftWeaponsState.h b/src/Basescape/CraftWeaponsState.h index fed72f138..366e82ce1 100644 --- a/src/Basescape/CraftWeaponsState.h +++ b/src/Basescape/CraftWeaponsState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -35,7 +35,7 @@ class RuleCraftWeapon; * Select Armament window for * changing the weapon equipped on a craft. */ -class CraftWeaponsState : public State +class CraftWeaponsState : public ListState { private: Base *_base; diff --git a/src/Basescape/GlobalManufactureState.h b/src/Basescape/GlobalManufactureState.h index 7dbb0b0d0..b2f08d2aa 100644 --- a/src/Basescape/GlobalManufactureState.h +++ b/src/Basescape/GlobalManufactureState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -33,7 +33,7 @@ class RuleManufacture; * Global Manufacture screen that provides overview * of the ongoing manufacturing operations in all the bases. */ -class GlobalManufactureState : public State +class GlobalManufactureState : public ListState { private: TextButton *_btnOk; diff --git a/src/Basescape/GlobalResearchState.h b/src/Basescape/GlobalResearchState.h index fbcb87ad6..c2c11ef1a 100644 --- a/src/Basescape/GlobalResearchState.h +++ b/src/Basescape/GlobalResearchState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -33,7 +33,7 @@ class RuleResearch; * Global Research screen that provides overview * of the ongoing research operations in all the bases. */ -class GlobalResearchState : public State +class GlobalResearchState : public ListState { private: TextButton *_btnOk; diff --git a/src/Basescape/ManageAlienContainmentState.h b/src/Basescape/ManageAlienContainmentState.h index 1dc09fcbd..8fdadf1e8 100644 --- a/src/Basescape/ManageAlienContainmentState.h +++ b/src/Basescape/ManageAlienContainmentState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Menu/OptionsBaseState.h" #include #include @@ -36,7 +36,7 @@ class Base; * ManageAlienContainment screen that lets the player manage * alien numbers in a particular base. */ -class ManageAlienContainmentState : public State +class ManageAlienContainmentState : public ListState { private: Base *_base; diff --git a/src/Basescape/ManufactureDependenciesTreeState.h b/src/Basescape/ManufactureDependenciesTreeState.h index 6f39486bd..04a476026 100644 --- a/src/Basescape/ManufactureDependenciesTreeState.h +++ b/src/Basescape/ManufactureDependenciesTreeState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -30,7 +30,7 @@ class TextList; /** * Window which displays manufacture dependencies tree. */ -class ManufactureDependenciesTreeState : public State +class ManufactureDependenciesTreeState : public ListState { private: Window *_window; diff --git a/src/Basescape/ManufactureState.h b/src/Basescape/ManufactureState.h index 5880c3712..006afa07f 100644 --- a/src/Basescape/ManufactureState.h +++ b/src/Basescape/ManufactureState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class Base; * Manufacture screen that lets the player manage * all the manufacturing operations of a base. */ -class ManufactureState : public State +class ManufactureState : public ListState { private: Base *_base; diff --git a/src/Basescape/NewManufactureListState.h b/src/Basescape/NewManufactureListState.h index 3d4b6c192..935d62e02 100644 --- a/src/Basescape/NewManufactureListState.h +++ b/src/Basescape/NewManufactureListState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -36,7 +36,7 @@ class ComboBox; /** * Screen which list possible productions. */ -class NewManufactureListState : public State +class NewManufactureListState : public ListState { private: Base *_base; diff --git a/src/Basescape/NewResearchListState.h b/src/Basescape/NewResearchListState.h index 04f2e81e1..60a841de1 100644 --- a/src/Basescape/NewResearchListState.h +++ b/src/Basescape/NewResearchListState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -36,7 +36,7 @@ class ComboBox; /** * Window which displays possible research projects. */ -class NewResearchListState : public State +class NewResearchListState : public ListState { private: Base *_base; diff --git a/src/Basescape/PurchaseState.cpp b/src/Basescape/PurchaseState.cpp index fd867a1c2..443add44d 100644 --- a/src/Basescape/PurchaseState.cpp +++ b/src/Basescape/PurchaseState.cpp @@ -653,7 +653,16 @@ void PurchaseState::updateList() { std::string projectName = _items[i].name; Unicode::upperCase(projectName); - if (projectName.find(searchString) == std::string::npos) + + bool noBattleTypeMatch = true; + if (_items[i].type == TRANSFER_ITEM) + { + std::string battleTypeLocalName = _game->getLanguage()->getBattleTypeString(((RuleItem *)_items[i].rule)->getBattleType()); + Unicode::upperCase(battleTypeLocalName); + noBattleTypeMatch = (battleTypeLocalName.find(searchString) == std::string::npos); + } + + if (projectName.find(searchString) == std::string::npos && noBattleTypeMatch) { continue; } diff --git a/src/Basescape/PurchaseState.h b/src/Basescape/PurchaseState.h index 6f030009e..c299f14bd 100644 --- a/src/Basescape/PurchaseState.h +++ b/src/Basescape/PurchaseState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Savegame/Transfer.h" #include #include @@ -40,7 +40,7 @@ class RuleItem; * Purchase/Hire screen that lets the player buy * new items for a base. */ -class PurchaseState : public State +class PurchaseState : public ListState { private: Base *_base; diff --git a/src/Basescape/ResearchState.h b/src/Basescape/ResearchState.h index c81d47afd..2b2a31455 100644 --- a/src/Basescape/ResearchState.h +++ b/src/Basescape/ResearchState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class Base; * Research screen that lets the player manage * all the researching operations of a base. */ -class ResearchState : public State +class ResearchState : public ListState { private: Base *_base; diff --git a/src/Basescape/SellState.cpp b/src/Basescape/SellState.cpp index de85908a4..bac094a44 100644 --- a/src/Basescape/SellState.cpp +++ b/src/Basescape/SellState.cpp @@ -95,7 +95,7 @@ void SellState::delayedInit() _btnOk = new TextButton(148, 16, 8, 176); _btnCancel = new TextButton(148, 16, 164, 176); _btnTransfer = new TextButton(148, 16, 164, 176); - _txtTitle = new Text(310, 17, 5, 8); + _txtTitle = new Text(227, 17, 5, 8); _txtSales = new Text(150, 9, 10, 24); _txtFunds = new Text(150, 9, 160, 24); _txtSpaceUsed = new Text(150, 9, 160, 34); @@ -103,6 +103,7 @@ void SellState::delayedInit() _txtSell = new Text(96, 9, 190, 44); _txtValue = new Text(40, 9, 270, 44); _cbxCategory = new ComboBox(this, 120, 16, 10, 36); + _cbxSort = new ComboBox(this, 82, 16, 232, 6); _lstItems = new TextList(287, 120, 8, 54); // Set palette @@ -111,7 +112,6 @@ void SellState::delayedInit() _ammoColor = _game->getMod()->getInterface("sellMenu")->getElement("ammoColor")->color; add(_window, "window", "sellMenu"); - add(_btnQuickSearch, "button", "sellMenu"); add(_btnOk, "button", "sellMenu"); add(_btnCancel, "button", "sellMenu"); add(_btnTransfer, "button", "sellMenu"); @@ -124,6 +124,8 @@ void SellState::delayedInit() add(_txtValue, "text", "sellMenu"); add(_lstItems, "list", "sellMenu"); add(_cbxCategory, "text", "sellMenu"); + add(_cbxSort, "text", "sellMenu"); + add(_btnQuickSearch, "button", "sellMenu"); centerAllSurfaces(); @@ -327,6 +329,14 @@ void SellState::delayedInit() _cbxCategory->onKeyboardPress((ActionHandler)&SellState::btnSellAllClick, Options::keySellAll); _cbxCategory->onKeyboardPress((ActionHandler)&SellState::btnSellAllButOneClick, Options::keySellAllButOne); + std::string itemValueString = std::string(tr("STR_ITEM")) + " " + std::string(tr("STR_VALUE")); + std::string totalValueString = std::string(tr("STR_TOTAL")) + " " + std::string(tr("STR_VALUE")); + Unicode::upperCase(itemValueString); + Unicode::upperCase(totalValueString); + _sortModes = {tr("STR_SORT_DEFAULT"), tr("STR_SIZE_UC"), tr("STR_SPACE_USED_UC"), itemValueString, totalValueString}; + _cbxSort->setOptions(_sortModes); + _cbxSort->onChange((ActionHandler)&SellState::cbxCategoryChange); + _btnQuickSearch->setText(""); // redraw _btnQuickSearch->onEnter((ActionHandler)&SellState::btnQuickSearchApply); _btnQuickSearch->setVisible(false); @@ -521,7 +531,16 @@ void SellState::updateList() { std::string projectName = _items[i].name; Unicode::upperCase(projectName); - if (projectName.find(searchString) == std::string::npos) + + bool noBattleTypeMatch = true; + if (_items[i].type == TRANSFER_ITEM) + { + std::string battleTypeLocalName = _game->getLanguage()->getBattleTypeString(((RuleItem *)_items[i].rule)->getBattleType()); + Unicode::upperCase(battleTypeLocalName); + noBattleTypeMatch = (battleTypeLocalName.find(searchString) == std::string::npos); + } + + if (projectName.find(searchString) == std::string::npos && noBattleTypeMatch) { continue; } @@ -1138,8 +1157,9 @@ void SellState::cbxCategoryChange(Action *) } else { - _currentSort = TransferSortDirection::BY_LIST_ORDER; + _currentSort = (TransferSortDirection)_cbxSort->getSelected(); } + _cbxSort->setSelected((size_t)_currentSort); updateList(); } diff --git a/src/Basescape/SellState.h b/src/Basescape/SellState.h index 7af3ba3b4..078d183c9 100644 --- a/src/Basescape/SellState.h +++ b/src/Basescape/SellState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Savegame/Transfer.h" #include "../Menu/OptionsBaseState.h" #include @@ -41,7 +41,7 @@ class RuleItem; * Sell/Sack screen that lets the player sell * any items in a particular base. */ -class SellState : public State +class SellState : public ListState { private: Base *_base; @@ -50,11 +50,11 @@ private: TextEdit *_btnQuickSearch; Window *_window; Text *_txtTitle, *_txtSales, *_txtFunds, *_txtQuantity, *_txtSell, *_txtValue, *_txtSpaceUsed; - ComboBox *_cbxCategory; + ComboBox *_cbxCategory, *_cbxSort; TextList *_lstItems; std::vector _items; std::vector _rows; - std::vector _cats; + std::vector _cats, _sortModes; size_t _vanillaCategories; size_t _sel; int64_t _total; diff --git a/src/Basescape/SoldierArmorState.h b/src/Basescape/SoldierArmorState.h index 6bc66b751..82d121d8c 100644 --- a/src/Basescape/SoldierArmorState.h +++ b/src/Basescape/SoldierArmorState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -59,7 +59,7 @@ struct ArmorItem * Select Armor window that allows changing * of the armor equipped on a soldier. */ -class SoldierArmorState : public State +class SoldierArmorState : public ListState { private: Base *_base; diff --git a/src/Basescape/SoldierAvatarState.h b/src/Basescape/SoldierAvatarState.h index 58f2f2880..8a2a3b53c 100644 --- a/src/Basescape/SoldierAvatarState.h +++ b/src/Basescape/SoldierAvatarState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Savegame/SoldierAvatar.h" namespace OpenXcom @@ -36,7 +36,7 @@ class SoldierAvatar; * Select Avatar window that allows changing * of the soldier's avatar. */ -class SoldierAvatarState : public State +class SoldierAvatarState : public ListState { private: Base *_base; diff --git a/src/Basescape/SoldierBonusState.h b/src/Basescape/SoldierBonusState.h index bd868782b..78fec075d 100644 --- a/src/Basescape/SoldierBonusState.h +++ b/src/Basescape/SoldierBonusState.h @@ -19,7 +19,7 @@ */ #include #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class TextList; /** * SoldierBonus window displays all soldier bonuses. */ -class SoldierBonusState : public State +class SoldierBonusState : public ListState { private: Base *_base; diff --git a/src/Basescape/SoldierDiaryMissionState.h b/src/Basescape/SoldierDiaryMissionState.h index 48f7a43df..72fdd143c 100755 --- a/src/Basescape/SoldierDiaryMissionState.h +++ b/src/Basescape/SoldierDiaryMissionState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class Soldier; * Diary window that show * mission details for a soldier. */ -class SoldierDiaryMissionState : public State +class SoldierDiaryMissionState : public ListState { private: Soldier *_soldier; diff --git a/src/Basescape/SoldierDiaryOverviewState.h b/src/Basescape/SoldierDiaryOverviewState.h index 0e72989de..2e793ceb6 100755 --- a/src/Basescape/SoldierDiaryOverviewState.h +++ b/src/Basescape/SoldierDiaryOverviewState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -35,7 +35,7 @@ class Soldier; * Diary screen that shows all the * missions a soldier has. */ -class SoldierDiaryOverviewState : public State +class SoldierDiaryOverviewState : public ListState { private: Base *_base; diff --git a/src/Basescape/SoldierDiaryPerformanceState.cpp b/src/Basescape/SoldierDiaryPerformanceState.cpp index c8fcfba40..0f4fe3812 100644 --- a/src/Basescape/SoldierDiaryPerformanceState.cpp +++ b/src/Basescape/SoldierDiaryPerformanceState.cpp @@ -203,7 +203,7 @@ void SoldierDiaryPerformanceState::init() { State::init(); // Clear sprites - for (int i = 0; i != 10; ++i) + for (int i = 0; i != _commendations.size(); ++i) { _commendations[i]->clear(); _commendationDecorations[i]->clear(); @@ -370,8 +370,16 @@ void SoldierDiaryPerformanceState::drawSprites() SurfaceSet* commendationSprite = _game->getMod()->getSurfaceSet("Commendations"); SurfaceSet* commendationDecoration = _game->getMod()->getSurfaceSet("CommendationDecorations"); + // Add more surfaces as required for non-standard list sizes + for (int i = _commendations.size(); i < _lstCommendations->getVisibleRows(); i++) + { + _commendations.push_back(new Surface(31, 8, _commendations[i - 1]->getX(), _commendations[i - 1]->getY() + 8)); + _commendationDecorations.push_back(new Surface(31, 8, _commendationDecorations[i - 1]->getX(), _commendationDecorations[i - 1]->getY() + 8)); + add(_commendations[i]); + add(_commendationDecorations[i]); + } // Clear sprites - for (int i = 0; i != 10; ++i) + for (int i = 0; i != _commendations.size(); ++i) { _commendations[i]->clear(); _commendationDecorations[i]->clear(); @@ -384,7 +392,7 @@ void SoldierDiaryPerformanceState::drawSprites() { RuleCommendations *commendation = pair.second->getRule(); // Skip commendations that are not visible in the textlist - if ( vectorPosition < scrollDepth || vectorPosition - scrollDepth >= (int)_commendations.size()) + if (vectorPosition < scrollDepth || vectorPosition - scrollDepth >= _lstCommendations->getVisibleRows()) { vectorPosition++; continue; @@ -517,4 +525,20 @@ void SoldierDiaryPerformanceState::think() } } +/** + * Updates the scale with adjustments for arbitrary height lists. + * @param dX delta of X; + * @param dY delta of Y; + */ +void SoldierDiaryPerformanceState::resize(int &dX, int &dY) +{ + int oldVisibleRows = _lstCommendations->getVisibleRows(); + ListState::resize(dX, dY); + + if (_lstCommendations->getVisibleRows() != oldVisibleRows) + { + drawSprites(); + } +} + } diff --git a/src/Basescape/SoldierDiaryPerformanceState.h b/src/Basescape/SoldierDiaryPerformanceState.h index a58990f58..3cc97cc19 100755 --- a/src/Basescape/SoldierDiaryPerformanceState.h +++ b/src/Basescape/SoldierDiaryPerformanceState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include @@ -39,7 +39,7 @@ enum SoldierDiaryDisplay { DIARY_KILLS, DIARY_MISSIONS, DIARY_COMMENDATIONS }; /** * Diary screen that lists soldier totals. */ -class SoldierDiaryPerformanceState : public State +class SoldierDiaryPerformanceState : public ListState { private: Base *_base; @@ -90,6 +90,8 @@ public: void lstInfoMouseClick(Action *action); /// Runs state functionality every cycle. void think() override; + /// Updates the scale with adjustments for arbitrary height lists. + void resize(int &dX, int &dY) override; }; } diff --git a/src/Basescape/SoldierMemorialState.h b/src/Basescape/SoldierMemorialState.h index ad329c62a..1565ac656 100644 --- a/src/Basescape/SoldierMemorialState.h +++ b/src/Basescape/SoldierMemorialState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class TextList; * Screen that shows all the soldiers * that have died throughout the game. */ -class SoldierMemorialState : public State +class SoldierMemorialState : public ListState { private: TextButton *_btnOk, *_btnStatistics; diff --git a/src/Basescape/SoldierTransformationListState.h b/src/Basescape/SoldierTransformationListState.h index ed7e94705..b741eb919 100644 --- a/src/Basescape/SoldierTransformationListState.h +++ b/src/Basescape/SoldierTransformationListState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include "SoldierSortUtil.h" @@ -38,7 +38,7 @@ class RuleSoldierTransformation; * Transformations Overview screen that lets the player * manage all the soldier transformations in a base. */ -class SoldierTransformationListState : public State +class SoldierTransformationListState : public ListState { private: Base* _base; diff --git a/src/Basescape/SoldiersState.h b/src/Basescape/SoldiersState.h index 46cb1e065..eae19c2aa 100644 --- a/src/Basescape/SoldiersState.h +++ b/src/Basescape/SoldiersState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include "SoldierSortUtil.h" @@ -37,7 +37,7 @@ struct SortFunctor; * Soldiers screen that lets the player * manage all the soldiers in a base. */ -class SoldiersState : public State +class SoldiersState : public ListState { private: TextButton *_btnOk, *_btnPsiTraining, *_btnTraining, *_btnMemorial; diff --git a/src/Basescape/StoresState.cpp b/src/Basescape/StoresState.cpp index 429ffa764..b57483327 100644 --- a/src/Basescape/StoresState.cpp +++ b/src/Basescape/StoresState.cpp @@ -235,7 +235,11 @@ void StoresState::initList() { std::string projectName = tr(itemType); Unicode::upperCase(projectName); - if (projectName.find(searchString) == std::string::npos) + + std::string battleTypeLocalName = _game->getLanguage()->getBattleTypeString(_game->getMod()->getItem(itemType)->getBattleType()); + Unicode::upperCase(battleTypeLocalName); + + if (projectName.find(searchString) == std::string::npos && battleTypeLocalName.find(searchString) == std::string::npos) { continue; } diff --git a/src/Basescape/StoresState.h b/src/Basescape/StoresState.h index 7aec32727..1b0bc7258 100644 --- a/src/Basescape/StoresState.h +++ b/src/Basescape/StoresState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -64,7 +64,7 @@ struct StoredItem * Stores window that displays all * the items currently stored in a base. */ -class StoresState : public State +class StoresState : public ListState { private: Base *_base; diff --git a/src/Basescape/TechTreeSelectState.cpp b/src/Basescape/TechTreeSelectState.cpp index f183e4e77..2f327a165 100644 --- a/src/Basescape/TechTreeSelectState.cpp +++ b/src/Basescape/TechTreeSelectState.cpp @@ -403,4 +403,15 @@ void TechTreeSelectState::onSelectTopic(Action *) _game->popState(); } +void TechTreeSelectState::SearchTechTree(std::string& search) { + TechTreeViewerState* viewer = new TechTreeViewerState(); + _game->pushState(viewer); + TechTreeSelectState* selector = new TechTreeSelectState(viewer); + _game->pushState(selector); + + selector->_btnQuickSearch->setText(search); + selector->_btnQuickSearch->setFocus(false); + selector->initLists(); +} + } diff --git a/src/Basescape/TechTreeSelectState.h b/src/Basescape/TechTreeSelectState.h index 9d653eca5..e7124f02c 100644 --- a/src/Basescape/TechTreeSelectState.h +++ b/src/Basescape/TechTreeSelectState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class TextList; /** * Window which allows selecting a topic for the Tech Tree Viewer. */ -class TechTreeSelectState : public State +class TechTreeSelectState : public ListState { private: TechTreeViewerState *_parent; @@ -60,5 +60,7 @@ public: /// Handlers for Quick Search. void btnQuickSearchToggle(Action *action); void btnQuickSearchApply(Action *action); + /// Creates and pushes new TechTree*States with preset search string + static void SearchTechTree(std::string& search); }; } diff --git a/src/Basescape/TechTreeViewerState.h b/src/Basescape/TechTreeViewerState.h index 99e5f72c5..8db0162a1 100644 --- a/src/Basescape/TechTreeViewerState.h +++ b/src/Basescape/TechTreeViewerState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include #include @@ -40,7 +40,7 @@ enum TTVMode { TTV_NONE, TTV_RESEARCH, TTV_MANUFACTURING, TTV_FACILITIES, TTV_IT /** * TechTreeViewer screen, where you can browse the Tech Tree. */ -class TechTreeViewerState : public State +class TechTreeViewerState : public ListState { private: TextButton *_btnOk, *_btnNew; diff --git a/src/Basescape/TransferBaseState.h b/src/Basescape/TransferBaseState.h index 1b3022c8f..41b5a25d2 100644 --- a/src/Basescape/TransferBaseState.h +++ b/src/Basescape/TransferBaseState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -34,7 +34,7 @@ class DebriefingState; * Window that lets the player pick the base * to transfer items to. */ -class TransferBaseState : public State +class TransferBaseState : public ListState { private: Base *_base; diff --git a/src/Basescape/TransferItemsState.cpp b/src/Basescape/TransferItemsState.cpp index c7c67fc3f..1bb2d0691 100644 --- a/src/Basescape/TransferItemsState.cpp +++ b/src/Basescape/TransferItemsState.cpp @@ -69,11 +69,12 @@ TransferItemsState::TransferItemsState(Base *baseFrom, Base *baseTo, DebriefingS _btnQuickSearch = new TextEdit(this, 48, 9, 10, 13); _btnOk = new TextButton(148, 16, 8, 176); _btnCancel = new TextButton(148, 16, 164, 176); - _txtTitle = new Text(310, 17, 5, 8); + _txtTitle = new Text(227, 17, 5, 8); _txtQuantity = new Text(50, 9, 150, 24); _txtAmountTransfer = new Text(60, 17, 200, 24); _txtAmountDestination = new Text(60, 17, 260, 24); _cbxCategory = new ComboBox(this, 120, 16, 10, 24); + _cbxSort = new ComboBox(this, 82, 16, 232, 6); _lstItems = new TextList(287, 128, 8, 44); // Set palette @@ -91,6 +92,7 @@ TransferItemsState::TransferItemsState(Base *baseFrom, Base *baseTo, DebriefingS add(_txtAmountDestination, "text", "transferMenu"); add(_lstItems, "list", "transferMenu"); add(_cbxCategory, "text", "transferMenu"); + add(_cbxSort, "text", "transferMenu"); centerAllSurfaces(); @@ -253,6 +255,14 @@ TransferItemsState::TransferItemsState(Base *baseFrom, Base *baseTo, DebriefingS _cbxCategory->onChange((ActionHandler)&TransferItemsState::cbxCategoryChange); _cbxCategory->onKeyboardPress((ActionHandler)&TransferItemsState::btnTransferAllClick, Options::keyTransferAll); + std::string itemValueString = std::string(tr("STR_ITEM")) + " " + std::string(tr("STR_VALUE")); + std::string totalValueString = std::string(tr("STR_TOTAL")) + " " + std::string(tr("STR_VALUE")); + Unicode::upperCase(itemValueString); + Unicode::upperCase(totalValueString); + _sortModes = {tr("STR_SORT_DEFAULT"), tr("STR_SIZE_UC"), tr("STR_SPACE_USED_UC"), itemValueString, totalValueString}; + _cbxSort->setOptions(_sortModes); + _cbxSort->onChange((ActionHandler)&TransferItemsState::cbxCategoryChange); + _btnQuickSearch->setText(""); // redraw _btnQuickSearch->onEnter((ActionHandler)&TransferItemsState::btnQuickSearchApply); _btnQuickSearch->setVisible(false); @@ -443,7 +453,16 @@ void TransferItemsState::updateList() { std::string projectName = _items[i].name; Unicode::upperCase(projectName); - if (projectName.find(searchString) == std::string::npos) + + bool noBattleTypeMatch = true; + if (_items[i].type == TRANSFER_ITEM) + { + std::string battleTypeLocalName = _game->getLanguage()->getBattleTypeString(((RuleItem *)_items[i].rule)->getBattleType()); + Unicode::upperCase(battleTypeLocalName); + noBattleTypeMatch = (battleTypeLocalName.find(searchString) == std::string::npos); + } + + if (projectName.find(searchString) == std::string::npos && noBattleTypeMatch) { continue; } @@ -1077,8 +1096,9 @@ void TransferItemsState::cbxCategoryChange(Action *) } else { - _currentSort = TransferSortDirection::BY_LIST_ORDER; + _currentSort = (TransferSortDirection)_cbxSort->getSelected(); } + _cbxSort->setSelected((size_t)_currentSort); updateList(); } diff --git a/src/Basescape/TransferItemsState.h b/src/Basescape/TransferItemsState.h index dcc68d602..f6ea51547 100644 --- a/src/Basescape/TransferItemsState.h +++ b/src/Basescape/TransferItemsState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Savegame/Transfer.h" #include #include @@ -40,7 +40,7 @@ class RuleItem; * Transfer screen that lets the player pick * what items to transfer between bases. */ -class TransferItemsState : public State +class TransferItemsState : public ListState { private: Base *_baseFrom, *_baseTo; @@ -49,11 +49,11 @@ private: TextEdit *_btnQuickSearch; Window *_window; Text *_txtTitle, *_txtQuantity, *_txtAmountTransfer, *_txtAmountDestination; - ComboBox *_cbxCategory; + ComboBox *_cbxCategory, *_cbxSort; TextList *_lstItems; std::vector _items; std::vector _rows; - std::vector _cats; + std::vector _cats, _sortModes; size_t _vanillaCategories; size_t _sel; int _total, _pQty, _cQty, _aQty; diff --git a/src/Basescape/TransfersState.h b/src/Basescape/TransfersState.h index 83318ee52..1aa050054 100644 --- a/src/Basescape/TransfersState.h +++ b/src/Basescape/TransfersState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class TextList; * Transfers window that displays all * the items currently in-transit to a base. */ -class TransfersState : public State +class TransfersState : public ListState { private: Base *_base; diff --git a/src/Battlescape/BriefingLightState.cpp b/src/Battlescape/BriefingLightState.cpp index 8ab7f2187..af4efe9b2 100644 --- a/src/Battlescape/BriefingLightState.cpp +++ b/src/Battlescape/BriefingLightState.cpp @@ -30,6 +30,7 @@ #include "../Mod/Armor.h" #include "../Mod/ArticleDefinition.h" #include "../Mod/RuleStartingCondition.h" +#include "../Mod/RuleSoldier.h" #include "../Savegame/SavedGame.h" #include "../Engine/Options.h" #include "../Engine/Screen.h" @@ -50,10 +51,16 @@ BriefingLightState::BriefingLightState(AlienDeployment *deployment) _window = new Window(this, 320, 200, 0, 0); _btnOk = new TextButton(140, 18, 164, 164); _btnArmors = new ToggleTextButton(140, 18, 16, 164); + _btnSoldiers = new ToggleTextButton(140, 18, 16, 164); + _btnCraft = new ToggleTextButton(140, 18, 16, 164); _txtTitle = new Text(300, 32, 16, 24); _txtBriefing = new Text(288, 104, 16, 56); _txtArmors = new Text(288, 25, 16, 56); + _txtSoldiers = new Text(288, 25, 16, 56); + _txtCraft = new Text(288, 25, 16, 56); _lstArmors = new TextList(288, 80, 8, 81); + _lstSoldiers = new TextList(288, 80, 8, 81); + _lstCraft = new TextList(288, 80, 8, 81); std::string title = deployment->getType(); std::string desc = deployment->getAlertDescription(); @@ -65,10 +72,16 @@ BriefingLightState::BriefingLightState(AlienDeployment *deployment) add(_window, "window", "briefing"); add(_btnOk, "button", "briefing"); add(_btnArmors, "button", "briefing"); + add(_btnSoldiers, "button", "briefing"); + add(_btnCraft, "button", "briefing"); add(_txtTitle, "text", "briefing"); add(_txtBriefing, "text", "briefing"); add(_txtArmors, "text", "briefing"); + add(_txtSoldiers, "text", "briefing"); + add(_txtCraft, "text", "briefing"); add(_lstArmors, "text", "briefing"); + add(_lstSoldiers, "text", "briefing"); + add(_lstCraft, "text", "briefing"); centerAllSurfaces(); @@ -82,6 +95,14 @@ BriefingLightState::BriefingLightState(AlienDeployment *deployment) _btnArmors->onMouseClick((ActionHandler)&BriefingLightState::btnArmorsClick); _btnArmors->setVisible(false); + _btnSoldiers->setText(tr("STR_ELIGIBLE_SOLDIERS")); + _btnSoldiers->onMouseClick((ActionHandler)&BriefingLightState::btnSoldiersClick); + _btnSoldiers->setVisible(false); + + _btnCraft->setText(tr("ELIGIBLE CRAFT")); // FIXME: Find/add a localized string for this + _btnCraft->onMouseClick((ActionHandler)&BriefingLightState::btnCraftClick); + _btnCraft->setVisible(false); + _txtTitle->setBig(); _txtTitle->setText(tr(title)); @@ -91,15 +112,35 @@ BriefingLightState::BriefingLightState(AlienDeployment *deployment) _txtArmors->setWordWrap(true); _txtArmors->setVisible(false); + _txtSoldiers->setWordWrap(true); + _txtSoldiers->setVisible(false); + + _txtCraft->setWordWrap(true); + _txtCraft->setVisible(false); + _lstArmors->setColumns(2, 148, 132); _lstArmors->setSelectable(true); _lstArmors->setBackground(_window); _lstArmors->setMargin(8); _lstArmors->setVisible(false); + _lstSoldiers->setColumns(2, 148, 132); + _lstSoldiers->setSelectable(true); + _lstSoldiers->setBackground(_window); + _lstSoldiers->setMargin(8); + _lstSoldiers->setVisible(false); + + _lstCraft->setColumns(2, 148, 132); + _lstCraft->setSelectable(true); + _lstCraft->setBackground(_window); + _lstCraft->setMargin(8); + _lstCraft->setVisible(false); + checkStartingCondition(deployment); _lstArmors->onMouseClick((ActionHandler)&BriefingLightState::lstArmorsClick, SDL_BUTTON_MIDDLE); + _lstSoldiers->onMouseClick((ActionHandler)&BriefingLightState::lstSoldiersClick, SDL_BUTTON_MIDDLE); + _lstCraft->onMouseClick((ActionHandler)&BriefingLightState::lstCraftClick, SDL_BUTTON_MIDDLE); } /** @@ -144,6 +185,92 @@ void BriefingLightState::checkStartingCondition(AlienDeployment *deployment) _lstArmors->addRow(2, _armorNameList[i].second.c_str(), _armorNameList[i + halfSize].second.c_str()); } } + + checkStartingConditionSoldiers(deployment, startingCondition); + checkStartingConditionCraft(deployment, startingCondition); + int nb = _btnArmors->getVisible() + _btnSoldiers->getVisible() + _btnCraft->getVisible() + 1; + if (nb > 2) { + int maxw = _btnOk->getX() + _btnOk->getWidth() - _btnArmors->getX(); + int w = maxw / nb - 4; + int x = _btnArmors->getX(); + int ox = x; + + ToggleTextButton* buttons[] = {_btnArmors, _btnSoldiers, _btnCraft}; + for (ToggleTextButton* button : buttons) { + if (button->getVisible()) { + button->setWidth(std::max(w, button->getTextWidth() + 6)); + button->setX(x); + x += button->getWidth() + 4; + } + } + _btnOk->setX(x); + _btnOk->setWidth(std::max(maxw - (x - ox), _btnOk->getTextWidth())); + } + } +} + +/** +* Checks the starting conditions for soldiers. +*/ +void BriefingLightState::checkStartingConditionSoldiers(AlienDeployment* deployment, const RuleStartingCondition* rule) { + if (rule->getForbiddenSoldierTypes().empty() && rule->getAllowedSoldierTypes().empty()) return; + + // Ref Geoscape/ConfirmDestinationState.cpp + const std::string messageCode = rule->getForbiddenSoldierTypes().empty() ? "STR_STARTING_CONDITION_SOLDIER_TYPE_ALLOWED" : "STR_STARTING_CONDITION_SOLDIER_TYPE_FORBIDDEN"; + _txtSoldiers->setText(tr(messageCode).arg("")); + _btnSoldiers->setVisible(true); + + auto& list = rule->getForbiddenSoldierTypes().empty() ? rule->getAllowedSoldierTypes() : rule->getForbiddenSoldierTypes(); + std::string lastSoldierTranslation; + for (auto& soldierType : list) + { + RuleSoldier* soldierTypeRule = _game->getMod()->getSoldier(soldierType, false); + if (soldierTypeRule && _game->getSavedGame()->isResearched(soldierTypeRule->getRequirements())) + { + std::string translation = tr(soldierType); + _soldierNameList.push_back(std::make_pair(soldierType, translation)); + + if (!lastSoldierTranslation.empty()) { + _lstSoldiers->addRow(2, lastSoldierTranslation.c_str(), translation.c_str()); + lastSoldierTranslation.clear(); + } else { + lastSoldierTranslation = translation; + } + } + } + if (!lastSoldierTranslation.empty()) { + _lstSoldiers->addRow(2, lastSoldierTranslation.c_str(), ""); + } +} + +void BriefingLightState::checkStartingConditionCraft(AlienDeployment* deployment, const RuleStartingCondition* rule) { + if (rule->getForbiddenCraft().empty() && rule->getAllowedCraft().empty()) return; + + // Ref GeoScape/ConfirmDestinationState.cpp + const std::string messageCode = rule->getForbiddenCraft().empty() ? "STR_STARTING_CONDITION_CRAFT_ALLOWED" : "STR_STARTING_CONDITION_CRAFT_FORBIDDEN"; + _txtCraft->setText(tr(messageCode).arg("")); + _btnCraft->setVisible(true); + + auto& list = rule->getForbiddenCraft().empty() ? rule->getAllowedCraft() : rule->getForbiddenCraft(); + std::string lastCraftTranslation; + for (auto& craftName : list) + { + ArticleDefinition *article = _game->getMod()->getUfopaediaArticle(craftName, false); + if (article && Ufopaedia::isArticleAvailable(_game->getSavedGame(), article)) + { + std::string translation = tr(craftName); + _craftNameList.push_back(std::make_pair(craftName, translation)); + + if (!lastCraftTranslation.empty()) { + _lstCraft->addRow(2, lastCraftTranslation.c_str(), translation.c_str()); + lastCraftTranslation.clear(); + } else { + lastCraftTranslation = translation; + } + } + } + if (!lastCraftTranslation.empty()) { + _lstCraft->addRow(2, lastCraftTranslation.c_str(), ""); } } @@ -173,6 +300,61 @@ void BriefingLightState::btnArmorsClick(Action *) _txtArmors->setVisible(_btnArmors->getPressed()); _lstArmors->setVisible(_btnArmors->getPressed()); _txtBriefing->setVisible(!_btnArmors->getPressed()); + + if (_btnSoldiers->getVisible()) { + _btnSoldiers->setPressed(false); + _txtSoldiers->setVisible(false); + _lstSoldiers->setVisible(false); + } + if (_btnCraft->getVisible()) { + _btnCraft->setPressed(false); + _txtCraft->setVisible(false); + _lstCraft->setVisible(false); + } +} + +/** + * * Shows allowed soldier types. + * * @param action Pointer to an action. + * */ +void BriefingLightState::btnSoldiersClick(Action *) +{ + _txtSoldiers->setVisible(_btnSoldiers->getPressed()); + _lstSoldiers->setVisible(_btnSoldiers->getPressed()); + _txtBriefing->setVisible(!_btnSoldiers->getPressed()); + + if (_btnArmors->getVisible()) { + _btnArmors->setPressed(false); + _txtArmors->setVisible(false); + _lstArmors->setVisible(false); + } + if (_btnCraft->getVisible()) { + _btnCraft->setPressed(false); + _txtCraft->setVisible(false); + _lstCraft->setVisible(false); + } +} + +/** + * * Shows allowed craft. + * * @param action Pointer to an action. + * */ +void BriefingLightState::btnCraftClick(Action *) +{ + _txtCraft->setVisible(_btnCraft->getPressed()); + _lstCraft->setVisible(_btnCraft->getPressed()); + _txtBriefing->setVisible(!_btnCraft->getPressed()); + + if (_btnArmors->getVisible()) { + _btnArmors->setPressed(false); + _txtArmors->setVisible(false); + _lstArmors->setVisible(false); + } + if (_btnSoldiers->getVisible()) { + _btnSoldiers->setPressed(false); + _txtSoldiers->setVisible(false); + _lstSoldiers->setVisible(false); + } } /** @@ -199,4 +381,42 @@ void BriefingLightState::lstArmorsClick(Action* action) } } +/** + * Shows corresponding Ufopaedia article. + * @param action Pointer to an action. + */ +void BriefingLightState::lstSoldiersClick(Action* action) +{ + size_t halfSize = _soldierNameList.size() / 2; + + double mx = action->getAbsoluteXMouse(); + if (mx < _btnOk->getX()) + { + halfSize = 0; + } + + auto idx = halfSize + _lstSoldiers->getSelectedRow(); + const std::string& soldierType = _soldierNameList[idx].first; + Ufopaedia::openArticle(_game, soldierType); // FIXME: Custom soldier type articles seem to fall under the STR_HEAVY_WEAPONS_PLATFORMS ufopedia category with no soldier type -> article ID translation +} + +/** + * Shows corresponding Ufopaedia article. + * @param action Pointer to an action. + */ +void BriefingLightState::lstCraftClick(Action* action) +{ + size_t halfSize = _craftNameList.size() / 2; + + double mx = action->getAbsoluteXMouse(); + if (mx < _btnOk->getX()) + { + halfSize = 0; + } + + auto idx = halfSize + _lstCraft->getSelectedRow(); + const std::string& craftName = _craftNameList[idx].first; + Ufopaedia::openArticle(_game, craftName); +} + } diff --git a/src/Battlescape/BriefingLightState.h b/src/Battlescape/BriefingLightState.h index 9572cee3c..bb1f248b4 100644 --- a/src/Battlescape/BriefingLightState.h +++ b/src/Battlescape/BriefingLightState.h @@ -28,6 +28,7 @@ class Window; class Text; class TextList; class AlienDeployment; +class RuleStartingCondition; /** * Briefing screen which displays basic info @@ -37,13 +38,15 @@ class BriefingLightState : public State { private: TextButton *_btnOk; - ToggleTextButton *_btnArmors; + ToggleTextButton *_btnArmors, *_btnSoldiers, *_btnCraft; Window *_window; - Text *_txtTitle, *_txtBriefing, *_txtArmors; - TextList* _lstArmors; - std::vector > _armorNameList; + Text *_txtTitle, *_txtBriefing, *_txtArmors, *_txtSoldiers, *_txtCraft; + TextList* _lstArmors, *_lstSoldiers, *_lstCraft; + std::vector > _armorNameList, _soldierNameList, _craftNameList; // Checks the starting condition void checkStartingCondition(AlienDeployment *deployment); + void checkStartingConditionSoldiers(AlienDeployment* deployment, const RuleStartingCondition* rule); + void checkStartingConditionCraft(AlienDeployment* deployment, const RuleStartingCondition* rule); public: /// Creates the BriefingLight state. BriefingLightState(AlienDeployment *deployment); @@ -55,6 +58,14 @@ public: void btnArmorsClick(Action *action); /// Handler for clicking the Armors list. void lstArmorsClick(Action* action); + /// Handler for clicking the Soldier types button. + void btnSoldiersClick(Action *action); + /// Handler for clicking the Soldier types list. + void lstSoldiersClick(Action* action); + /// Handler for clicking the Craft button. + void btnCraftClick(Action *action); + /// Handler for clicking the Craft list. + void lstCraftClick(Action* action); }; } diff --git a/src/Battlescape/CannotReequipState.h b/src/Battlescape/CannotReequipState.h index 865977673..fbbdd2726 100644 --- a/src/Battlescape/CannotReequipState.h +++ b/src/Battlescape/CannotReequipState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "DebriefingState.h" #include @@ -34,7 +34,7 @@ class Base; * Screen shown when there's not enough equipment * to re-equip a craft after a mission. */ -class CannotReequipState : public State +class CannotReequipState : public ListState { private: std::vector _missingItems; diff --git a/src/Battlescape/CommendationLateState.h b/src/Battlescape/CommendationLateState.h index 0976b459c..900e51684 100755 --- a/src/Battlescape/CommendationLateState.h +++ b/src/Battlescape/CommendationLateState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -31,7 +31,7 @@ class Soldier; /** * Medals screen that displays dead soldier medals. */ -class CommendationLateState : public State +class CommendationLateState : public ListState { private: TextButton *_btnOk; diff --git a/src/Battlescape/CommendationState.h b/src/Battlescape/CommendationState.h index bcdf7e0ae..45c859f11 100755 --- a/src/Battlescape/CommendationState.h +++ b/src/Battlescape/CommendationState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -31,7 +31,7 @@ class Soldier; /** * Medals screen that displays new soldier medals. */ -class CommendationState : public State +class CommendationState : public ListState { private: TextButton *_btnOk; diff --git a/src/Battlescape/DebriefingState.h b/src/Battlescape/DebriefingState.h index c9997896b..850599e95 100644 --- a/src/Battlescape/DebriefingState.h +++ b/src/Battlescape/DebriefingState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include #include #include @@ -57,7 +57,7 @@ struct RecoveryItem { std::string name; int value; }; * Debriefing screen shown after a Battlescape * mission that displays the results. */ -class DebriefingState : public State +class DebriefingState : public ListState { private: typedef std::pair SoldierStatsEntry; diff --git a/src/Battlescape/Inventory.cpp b/src/Battlescape/Inventory.cpp index 091b96eda..a65002402 100644 --- a/src/Battlescape/Inventory.cpp +++ b/src/Battlescape/Inventory.cpp @@ -47,6 +47,10 @@ #include #include "../Engine/Screen.h" #include "../Engine/CrossPlatform.h" +#include "../Basescape/TechTreeViewerState.h" +#include "../Basescape/TechTreeSelectState.h" +#include "../Mod/ArticleDefinition.h" +#include "../Ufopaedia/StatsForNerdsState.h" #include "TileEngine.h" namespace OpenXcom @@ -1178,7 +1182,21 @@ void Inventory::mouseClick(Action *action, State *state) if (item != 0) { std::string articleId = item->getRules()->getUfopediaType(); - Ufopaedia::openArticle(_game, articleId); + ArticleDefinition* article = _game->getMod()->getUfopaediaArticle(articleId); + bool isArticleAvailable = (article && Ufopaedia::isArticleAvailable(_game->getSavedGame(), article)); + if (isArticleAvailable && article->section != UFOPAEDIA_NOT_AVAILABLE) { + Ufopaedia::openArticle(_game, articleId); + } else if (isArticleAvailable) { + _game->pushState(new StatsForNerdsState(article->getType(), article->id, false, false, false)); + } else { + const RuleResearch* researchTopic = _game->getMod()->getResearch(articleId, false); + if (researchTopic) { + _game->pushState(new TechTreeViewerState(researchTopic)); + } else { + std::string search = _game->getLanguage()->getString(item->getRules()->getType()); + TechTreeSelectState::SearchTechTree(search); + } + } } } } @@ -1414,12 +1432,13 @@ bool Inventory::isInSearchString(BattleItem *item) if (itemLocalName.find(_searchString) != std::string::npos) { // Name match. + Log(LOG_DEBUG) << "Item \"" << itemLocalName << "\" matched search string \"" << _searchString << "\""; return true; } // If present in the Ufopaedia, check categories for a match as well. ArticleDefinition *articleID = _game->getMod()->getUfopaediaArticle(item->getRules()->getType()); - if (articleID && Ufopaedia::isArticleAvailable(_game->getSavedGame(), articleID)) + if (Options::kaizokuInventorySearchIgnoreResearched || (articleID && Ufopaedia::isArticleAvailable(_game->getSavedGame(), articleID))) { for (const auto& itemCategoryName : item->getRules()->getCategories()) { @@ -1428,10 +1447,33 @@ bool Inventory::isInSearchString(BattleItem *item) if (catLocalName.find(_searchString) != std::string::npos) { // Category match + Log(LOG_DEBUG) << "Item \"" << itemLocalName << "\" matched item category \"" << catLocalName << "\""; + return true; + } + } + + // Search item battle type as well. + std::string battleTypeLocalName = _game->getLanguage()->getBattleTypeString(item->getRules()->getBattleType()); + Unicode::upperCase(battleTypeLocalName); + if (battleTypeLocalName.find(_searchString) != std::string::npos) + { + // Battle Type match + Log(LOG_DEBUG) << "Item \"" << itemLocalName << "\" matched item battle type \"" << battleTypeLocalName << "\""; + return true; + } + + // By inventory slot + std::string invLocalName; + for (const std::pair& invPair : *_game->getMod()->getInventories()) { + invLocalName = _game->getLanguage()->getString(invPair.first); + if (invLocalName.find(_searchString) != std::string::npos && item->getRules()->canBePlacedIntoInventorySection(invPair.second)) { + Log(LOG_DEBUG) << "Item \"" << itemLocalName << "\" matched inventory slot \"" << invPair.first << "\""; return true; } } + // Ignore weapon ammo category when strict search enabled + if (Options::kaizokuStrictInventoryWeaponCategorySearch) return false; for (int slot = 0; slot < RuleItem::AmmoSlotMax; ++slot) { if (item->getAmmoForSlot(slot)) @@ -1443,6 +1485,7 @@ bool Inventory::isInSearchString(BattleItem *item) if (catLocalName.find(_searchString) != std::string::npos) { // Category match + Log(LOG_DEBUG) << "Item \"" << itemLocalName << "\" matched ammo category \"" << catLocalName << "\""; return true; } } diff --git a/src/Battlescape/InventoryLoadState.h b/src/Battlescape/InventoryLoadState.h index 2c2703e21..883a8869c 100644 --- a/src/Battlescape/InventoryLoadState.h +++ b/src/Battlescape/InventoryLoadState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -32,7 +32,7 @@ class InventoryState; /** * Inventory Load window that allows changing of the equipment on a soldier. */ -class InventoryLoadState : public State +class InventoryLoadState : public ListState { private: InventoryState *_parent; diff --git a/src/Battlescape/InventorySaveState.h b/src/Battlescape/InventorySaveState.h index 4665c415b..2be53b3cd 100644 --- a/src/Battlescape/InventorySaveState.h +++ b/src/Battlescape/InventorySaveState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class InventoryState; /** * Inventory Save window that allows saving of the equipment on a soldier to a global template. */ -class InventorySaveState : public State +class InventorySaveState : public ListState { private: InventoryState *_parent; diff --git a/src/Battlescape/InventoryState.cpp b/src/Battlescape/InventoryState.cpp index 836096b86..69a13d6b5 100644 --- a/src/Battlescape/InventoryState.cpp +++ b/src/Battlescape/InventoryState.cpp @@ -47,10 +47,12 @@ #include "../Savegame/Craft.h" #include "../Savegame/ItemContainer.h" #include "../Savegame/Soldier.h" +#include "../Savegame/MissionSite.h" #include "../Mod/RuleItem.h" #include "../Mod/RuleInventory.h" #include "../Mod/RuleSoldier.h" #include "../Mod/Armor.h" +#include "../Mod/RuleStartingCondition.h" #include "../Engine/Options.h" #include "UnitInfoState.h" #include "BattlescapeState.h" @@ -177,6 +179,12 @@ InventoryState::InventoryState(bool tu, BattlescapeState *parent, Base *base, bo { _txtTus->setY(_txtTus->getY() + 8); } + if (Options::kaizokuInventoryForbiddenItems && _parent == 0) { + _txtForbiddenItems = new Text(316, 400, 2, 202); + add(_txtForbiddenItems, "warning", "battlescape", _bg); + _txtForbiddenItems->setHighContrast(true); + _txtForbiddenItems->setWordWrap(true, true); + } centerAllSurfaces(); @@ -708,6 +716,84 @@ void InventoryState::updateStats() updateStatLine(_txtStatLine2, "textStatLine2"); updateStatLine(_txtStatLine3, "textStatLine3"); updateStatLine(_txtStatLine4, "textStatLine4"); + + // Only check in base + if (Options::kaizokuInventoryForbiddenItems && _parent == 0) updateForbiddenItems(unit); +} + +/** + * Updates the soldier stats (Weight, TU). + */ +void InventoryState::updateForbiddenItems(BattleUnit* unit) { + // Ignore BattleScape + + std::vector *missionSites = _game->getSavedGame()->getMissionSites(); + if (!missionSites->empty()) { + Soldier *soldier = unit->getGeoscapeSoldier(); + Craft *craft = soldier->getCraft(); + std::string text = ""; + std::string strForbiddenItems; + + for (MissionSite* missionSite : *missionSites) { + const AlienDeployment *deployment = missionSite->getDeployment(); + RuleStartingCondition* sc = _game->getMod()->getStartingCondition(deployment->getStartingCondition()); + if (!sc) continue; + strForbiddenItems.clear(); + + // Soldier + if (!sc->isSoldierTypePermitted(soldier->getRules()->getType())) { + text.append(tr("STR_SOLDIER_NOT_ALLOWED_IN_MISSION").arg(tr(deployment->getType()))); + text.append("\n"); + continue; + } + + // Armor + const std::string& equippedArmor = unit->getArmor()->getType(); + bool armorForbidden = false; + if (!sc->getForbiddenArmors().empty()) { + for (const std::string& forbiddenArmor : sc->getForbiddenArmors()) { + if (equippedArmor == forbiddenArmor) { + armorForbidden = true; + break; + } + } + } + if (!armorForbidden && !sc->getAllowedArmors().empty()) { + armorForbidden = true; + for (const std::string& allowedArmor : sc->getAllowedArmors()) { + if (equippedArmor == allowedArmor) { + armorForbidden = false; + break; + } + } + } + if (armorForbidden) { + strForbiddenItems = tr(equippedArmor); + strForbiddenItems.append(1, Unicode::TOK_COLOR_FLIP).append(", ").append(1, Unicode::TOK_COLOR_FLIP); + } + + // Items + std::vector *inv = unit->getInventory(); + std::vector uniqueItems; + for (BattleItem *item : *inv) { + const std::string& itemType = item->getRules()->getType(); + if (itemType.find("INV_NULL") != std::string::npos || std::find(uniqueItems.begin(), uniqueItems.end(), &itemType) != uniqueItems.end()) continue; + + // Fixed weapons always allowed? + if (!item->getRules()->isFixed() && !sc->isItemPermitted(itemType, _game->getMod(), craft)) { + strForbiddenItems.append(tr(itemType)); + strForbiddenItems.append(1, Unicode::TOK_COLOR_FLIP).append(", ").append(1, Unicode::TOK_COLOR_FLIP); + uniqueItems.push_back(&itemType); + } + } + + if (!strForbiddenItems.empty()) { + strForbiddenItems.erase(strForbiddenItems.end() - 4, strForbiddenItems.end()); // Delete trailing ", " + color flips + text.append(tr("STR_ITEMS_NOT_ALLOWED_IN_MISSION").arg(tr(missionSite->getDeployment()->getType())).arg(strForbiddenItems + "\n")); + } + } + _txtForbiddenItems->setText(text); + } } /** diff --git a/src/Battlescape/InventoryState.h b/src/Battlescape/InventoryState.h index 71f05058e..bcd7d8de4 100644 --- a/src/Battlescape/InventoryState.h +++ b/src/Battlescape/InventoryState.h @@ -45,7 +45,7 @@ class InventoryState : public State { private: Surface *_bg, *_soldier; - Text *_txtItem, *_txtAmmo, *_txtWeight, *_txtTus, *_txtStatLine1, *_txtStatLine2, *_txtStatLine3, *_txtStatLine4, *_txtPosition; + Text *_txtItem, *_txtAmmo, *_txtWeight, *_txtTus, *_txtStatLine1, *_txtStatLine2, *_txtStatLine3, *_txtStatLine4, *_txtPosition, *_txtForbiddenItems; TextEdit *_txtName; TextEdit *_btnQuickSearch; BattlescapeButton *_btnOk, *_btnPrev, *_btnNext, *_btnUnload, *_btnGround, *_btnRank, *_btnArmor; @@ -86,6 +86,8 @@ public: void edtSoldierChange(Action *action); /// Updates the soldier info (Weight, TU). void updateStats(); + /// Update forbidden items text + void updateForbiddenItems(BattleUnit* unit); /// Saves the soldiers' equipment-layout. void saveEquipmentLayout(); /// Handler for clicking the Armor button. diff --git a/src/Battlescape/PromotionsState.h b/src/Battlescape/PromotionsState.h index cd954abdd..c4efd9e21 100644 --- a/src/Battlescape/PromotionsState.h +++ b/src/Battlescape/PromotionsState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -30,7 +30,7 @@ class TextList; /** * Promotions screen that displays new soldier ranks. */ -class PromotionsState : public State +class PromotionsState : public ListState { private: TextButton *_btnOk; diff --git a/src/Battlescape/TurnDiaryState.h b/src/Battlescape/TurnDiaryState.h index 7365535a9..66e310e9e 100644 --- a/src/Battlescape/TurnDiaryState.h +++ b/src/Battlescape/TurnDiaryState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -31,7 +31,7 @@ class HitLog; /** * Turn Diary window that displays the hit log history (for the current turn). */ -class TurnDiaryState : public State +class TurnDiaryState : public ListState { private: Window *_window; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4dddbd48d..bed863e04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,6 +144,7 @@ set ( engine_src Engine/InteractiveSurface.cpp Engine/Language.cpp Engine/LanguagePlurality.cpp + Engine/ListState.cpp Engine/LocalizedText.cpp Engine/ModInfo.cpp Engine/Music.cpp diff --git a/src/Engine/Game.cpp b/src/Engine/Game.cpp index 64b24b4af..23ab185dd 100644 --- a/src/Engine/Game.cpp +++ b/src/Engine/Game.cpp @@ -94,8 +94,10 @@ Game::Game(const std::string &title) : _screen(0), _cursor(0), _lang(0), _save(0 // Create invisible hardware cursor to workaround bug with absolute positioning pointing devices SDL_ShowCursor(SDL_ENABLE); - Uint8 cursor = 0; - SDL_SetCursor(SDL_CreateCursor(&cursor, &cursor, 1,1,0,0)); + if (!Options::kaizokuSystemCursor) { + Uint8 cursor = 0; + SDL_SetCursor(SDL_CreateCursor(&cursor, &cursor, 1,1,0,0)); + } // Create fps counter _fpsCounter = new FpsCounter(15, 5, 0, 0); diff --git a/src/Engine/Language.cpp b/src/Engine/Language.cpp index c8bda7a92..ecb3695df 100644 --- a/src/Engine/Language.cpp +++ b/src/Engine/Language.cpp @@ -29,6 +29,7 @@ #include "LanguagePlurality.h" #include "Unicode.h" #include "../Mod/ExtraStrings.h" +#include "../Mod/RuleItem.h" #include "../Savegame/Soldier.h" #include "FileMap.h" @@ -360,6 +361,42 @@ LocalizedText Language::getString(const std::string &id, SoldierGender gender) c return getString(genderId); } +/** + * Returns the localized text for the specified BattleType. + * If it's not found, just returns an empty string. + * @param BattleType ID of the string. + * @return String with the requested ID. + */ +LocalizedText Language::getBattleTypeString(int BattleType) const +{ + // Cache for the 12 BattleTypes + static std::array battleTypeLocalNames; + + if (BattleType >= 12) + { + return std::string(); + } + if (!battleTypeLocalNames[BattleType].empty()) + { + return battleTypeLocalNames[BattleType]; + } + + battleTypeLocalNames[BT_NONE] = getString("BT_NONE"); + battleTypeLocalNames[BT_FIREARM] = getString("BT_FIREARM"); + battleTypeLocalNames[BT_AMMO] = getString("BT_AMMO"); + battleTypeLocalNames[BT_MELEE] = getString("BT_MELEE"); + battleTypeLocalNames[BT_GRENADE] = getString("BT_GRENADE"); + battleTypeLocalNames[BT_PROXIMITYGRENADE] = getString("BT_PROXIMITYGRENADE"); + battleTypeLocalNames[BT_MEDIKIT] = getString("BT_MEDIKIT"); + battleTypeLocalNames[BT_SCANNER] = getString("BT_SCANNER"); + battleTypeLocalNames[BT_MINDPROBE] = getString("BT_MINDPROBE"); + battleTypeLocalNames[BT_PSIAMP] = getString("BT_PSIAMP"); + battleTypeLocalNames[BT_FLARE] = getString("BT_FLARE"); + battleTypeLocalNames[BT_CORPSE] = getString("BT_CORPSE"); + + return battleTypeLocalNames[BattleType]; +} + /** * Outputs all the language IDs and strings * to an HTML table. diff --git a/src/Engine/Language.h b/src/Engine/Language.h index c7d1891ab..cc9168f55 100644 --- a/src/Engine/Language.h +++ b/src/Engine/Language.h @@ -72,6 +72,8 @@ public: LocalizedText getString(const std::string &id, unsigned n) const; /// Get a gender-depended localized text. LocalizedText getString(const std::string &id, SoldierGender gender) const; + /// Get BattleType localized text. + LocalizedText getBattleTypeString(int BattleType) const; /// Gets the direction of text in this language. TextDirection getTextDirection() const; /// Gets the wrapping of text in this language. diff --git a/src/Engine/ListState.cpp b/src/Engine/ListState.cpp new file mode 100644 index 000000000..e3d71eb74 --- /dev/null +++ b/src/Engine/ListState.cpp @@ -0,0 +1,164 @@ + +#include "ListState.h" +#include "../Engine/Screen.h" +#include "../Engine/Game.h" +#include "../Engine/Options.h" +#include "../Interface/ComboBox.h" +#include "../Interface/TextButton.h" +#include "../Interface/Window.h" +#include "../Interface/Text.h" +#include "../Interface/TextEdit.h" +#include "../Interface/TextList.h" + +namespace OpenXcom +{ + +/** + * Centers and adjusts height of all the surfaces on the screen depending on the oxceListsHeightPercentage option. + */ +void ListState::centerAllSurfaces() +{ + if (Options::kaizokuListsScreenHeightPercentage == 0) + return State::centerAllSurfaces(); + + // Find main window. At the time of writing there aren't any relevant game states with more than one window. + for (std::vector::iterator i = _surfaces.begin(); i != _surfaces.end(); ++i) + { + if (Window *w = dynamic_cast(*i)) + { + _mainWindow = w; + break; + } + } + + Screen *screen = _game->getScreen(); + int oldMainWindowHeight = _mainWindow->getHeight(); + // int newMainWindowHeight = ((double)oldMainWindowHeight / screen->ORIGINAL_HEIGHT) * (Options::baseYResolution * (Options::kaizokuListsScreenHeightPercentage / 100.0)); + // The below is not really correct but prefer short windows to be slightly more expanded. The above line would more accurately keep to their original screen ratio. + int newMainWindowHeight = std::max(0.0, oldMainWindowHeight + (Options::baseYResolution * (Options::kaizokuListsScreenHeightPercentage / 100.0)) - screen->ORIGINAL_HEIGHT); + _mainWindow->setHeight(newMainWindowHeight); + + int oldMainWindowY = _mainWindow->getY(); + _mainWindow->setY((Options::baseYResolution - newMainWindowHeight) / 2); + + int mainWindowDeltaHeight = newMainWindowHeight - oldMainWindowHeight; + int mainWindowDeltaY = _mainWindow->getY() - oldMainWindowY; + + for (std::vector::iterator i = _surfaces.begin(); i != _surfaces.end(); ++i) + { + (*i)->setX((*i)->getX() + screen->getDX()); + + if ((*i) == _mainWindow) + continue; + + // Assume most things on the lower half of the screen should stay on the bottom. + if (dynamic_cast(*i) || dynamic_cast(*i) || dynamic_cast(*i)) + { + int y = (*i)->getY(); + if (y > screen->ORIGINAL_HEIGHT / 2) + { + (*i)->setY(y + mainWindowDeltaHeight); + setAnchoredBottom(*i); + } + } + // Expand TextList, keep height pegged to the anchored Surfaces later. + else if (dynamic_cast(*i)) + { + // Diary performance screens using TextLists as single line text displays makes this harder than it should be so we're back to making more assumptions. + if ((*i)->getY() > screen->ORIGINAL_HEIGHT / 2) + { + (*i)->setY((*i)->getY() + mainWindowDeltaHeight); + setAnchoredBottom(*i); + } + else + { + int h = (*i)->getHeight() + mainWindowDeltaHeight; + (*i)->setHeight(std::max(0, h - (h % 8))); // TextLists only render properly with multiples of 8 + } + } + + (*i)->setY((*i)->getY() + mainWindowDeltaY); + } +} + +/** + * Updates the scale with adjustments for arbitrary height lists. + * @param dX delta of X; + * @param dY delta of Y; + */ +void ListState::resize(int &dX, int &dY) +{ + if (Options::kaizokuListsScreenHeightPercentage == 0) + return State::resize(dX, dY); + + int oldMainWindowHeight = _mainWindow->getHeight(); + int newMainWindowHeight = ((double)oldMainWindowHeight / (Options::baseYResolution - dY)) * Options::baseYResolution; + _mainWindow->setHeight(newMainWindowHeight); + + int oldMainWindowY = _mainWindow->getY(); + _mainWindow->setY((Options::baseYResolution - newMainWindowHeight) / 2); + + int mainWindowDeltaHeight = newMainWindowHeight - oldMainWindowHeight; + int mainWindowDeltaY = _mainWindow->getY() - oldMainWindowY; + + int textlistAnchorY = _mainWindow->getY() + newMainWindowHeight - 24; // Just in case + std::vector textlists; + for (std::vector::const_iterator i = _surfaces.begin(); i != _surfaces.end(); ++i) + { + (*i)->setX((*i)->getX() + dX / 2); + + if ((*i) == _mainWindow) + continue; + + if (isAnchoredBottom(*i)) + { + int y = (*i)->getY() + mainWindowDeltaY + mainWindowDeltaHeight; + textlistAnchorY = std::min(textlistAnchorY, y); + (*i)->setY(y); + } + else + { + (*i)->setY((*i)->getY() + mainWindowDeltaY); + } + + // Do TextList height later when we are sure we have lowerButtonsY. + if (TextList *tl = dynamic_cast(*i)) + { + textlists.push_back(tl); + } + } + while (!textlists.empty()) + { + TextList *tl = textlists.back(); + int h = textlistAnchorY - 2 - tl->getY();// Use a point 2 pixels above the lower buttons as anchor + tl->setHeight(std::max(8, h - (h % 8))); // Set height a multiple of 8 for proper rendering + + textlists.pop_back(); + } +} + +/** + * Anchor to the bottom of the screen. + * @param surface Pointer to Surface; + * @param anchor Boolean whether to anchor or not; + */ +void ListState::setAnchoredBottom(Surface *surface, bool anchor) +{ + _anchoredSurfaces[surface] = anchor; +} + +/** + * Is Surface anchored to the bottom of the screen? + * @param surface Pointer to Surface; + */ +bool ListState::isAnchoredBottom(Surface *surface) +{ + std::unordered_map::const_iterator it = _anchoredSurfaces.find(surface); + if (it != _anchoredSurfaces.end()) + { + return (*it).second; + } + return false; +} + +} diff --git a/src/Engine/ListState.h b/src/Engine/ListState.h new file mode 100644 index 000000000..be232f802 --- /dev/null +++ b/src/Engine/ListState.h @@ -0,0 +1,45 @@ +#pragma once +/* + * Copyright 2010-2016 OpenXcom Developers. + * + * This file is part of OpenXcom. + * + * OpenXcom is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenXcom is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenXcom. If not, see . + */ +#include "State.h" +#include + +namespace OpenXcom +{ + +/** + * Game state with automatic resizing of lists. + */ +class ListState : public State +{ + private: + std::unordered_map _anchoredSurfaces; + Window *_mainWindow = 0; + public: + /// Centers and adjusts height of all the surfaces on the screen depending on the oxceListsHeightPercentage option. + virtual void centerAllSurfaces() override; + /// Updates the scale with adjustments for arbitrary height lists. + virtual void resize(int &dX, int &dY) override; + /// Anchor to the bottom of the screen. + void setAnchoredBottom(Surface *surface, bool anchor = true); + /// Is Surface anchored to the bottom of the screen? + bool isAnchoredBottom(Surface *surface); +}; + +} diff --git a/src/Engine/Options.cpp b/src/Engine/Options.cpp index ed3c5b482..05aaca11d 100644 --- a/src/Engine/Options.cpp +++ b/src/Engine/Options.cpp @@ -533,6 +533,12 @@ void createOptionsOTHER() void createAdvancedOptionsOTHER() { // your fork's advanced options here + _info.push_back(OptionInfo(OPTION_OTHER, "kaizokuNewBaseHoverAreaInfo", &kaizokuNewBaseHoverAreaInfo, 0, "STR_NEW_BASE_HOVER_AREA_INFO", "STR_GEOSCAPE")); + _info.push_back(OptionInfo(OPTION_OTHER, "kaizokuListsScreenHeightPercentage", &kaizokuListsScreenHeightPercentage, 0, "STR_LISTS_SCREEN_HEIGHT_PERCENTAGE", "STR_BASESCAPE")); + _info.push_back(OptionInfo(OPTION_OTHER, "kaizokuSystemCursor", &kaizokuSystemCursor, false, "STR_SYSTEM_CURSOR", "STR_GENERAL")); + _info.push_back(OptionInfo(OPTION_OTHER, "kaizokuStrictInventoryWeaponCategorySearch", &kaizokuStrictInventoryWeaponCategorySearch, false, "STR_STRICT_INVENTORY_WEAPON_CATEGORY_SEARCH", "STR_GENERAL")); + _info.push_back(OptionInfo(OPTION_OTHER, "kaizokuInventorySearchIgnoreResearched", &kaizokuInventorySearchIgnoreResearched, false, "STR_INVENTORY_SEARCH_IGNORE_RESEARCHED", "STR_GENERAL")); + _info.push_back(OptionInfo(OPTION_OTHER, "kaizokuInventoryForbiddenItems", &kaizokuInventoryForbiddenItems, false, "STR_INVENTORY_FORBIDDEN_ITEMS", "STR_GENERAL")); } void createControlsOTHER() @@ -1156,7 +1162,8 @@ void setFolders() CrossPlatform::createFolder(_userFolder + "mods"); } - if (_configFolder.empty()) + // Why were linux builds the only ones ignoring portable configs? + if (_configFolder.empty() || _userFolder == "./user/") { _configFolder = _userFolder; } diff --git a/src/Engine/Options.inc.h b/src/Engine/Options.inc.h index 8b9ea260d..93b876fe9 100644 --- a/src/Engine/Options.inc.h +++ b/src/Engine/Options.inc.h @@ -102,6 +102,14 @@ OPT bool oxceAutoSell; OPT bool oxceAutomaticPromotions; OPT bool oxceEnableOffCentreShooting; +// Fork options +OPT int kaizokuNewBaseHoverAreaInfo; +OPT int kaizokuListsScreenHeightPercentage; +OPT bool kaizokuSystemCursor; +OPT bool kaizokuStrictInventoryWeaponCategorySearch; +OPT bool kaizokuInventorySearchIgnoreResearched; +OPT bool kaizokuInventoryForbiddenItems; + // OXCE hidden, accessible only via options.cfg /** * Verification level of mod data. diff --git a/src/Engine/Screen.cpp b/src/Engine/Screen.cpp index d79f95cb2..af85551bc 100644 --- a/src/Engine/Screen.cpp +++ b/src/Engine/Screen.cpp @@ -358,7 +358,6 @@ void Screen::resetDisplay(bool resetVideo, bool noShaders) // Workaround for segfault when switching to opengl if ((oldFlags & SDL_OPENGL) != (_flags & SDL_OPENGL)) { - Uint8 cursor = 0; char *_oldtitle = 0; SDL_WM_GetCaption(&_oldtitle, NULL); std::string title(_oldtitle); @@ -370,7 +369,10 @@ void Screen::resetDisplay(bool resetVideo, bool noShaders) SDL_EnableUNICODE(1); SDL_WM_SetCaption(title.c_str(), 0); SDL_WM_GrabInput(Options::captureMouse); - SDL_SetCursor(SDL_CreateCursor(&cursor, &cursor, 1,1,0,0)); + if (!Options::kaizokuSystemCursor) { + Uint8 cursor = 0; + SDL_SetCursor(SDL_CreateCursor(&cursor, &cursor, 1,1,0,0)); + } } #endif _screen = SDL_SetVideoMode(width, height, _bpp, _flags); diff --git a/src/Engine/State.h b/src/Engine/State.h index 93c3c9779..3973b4586 100644 --- a/src/Engine/State.h +++ b/src/Engine/State.h @@ -104,7 +104,7 @@ public: /// redraw all the text-type surfaces. void redrawText(); /// center all surfaces relative to the screen. - void centerAllSurfaces(); + virtual void centerAllSurfaces(); /// lower all surfaces by half the screen height. void lowerAllSurfaces(); /// switch the colours to use the battlescape palette. diff --git a/src/Geoscape/AllocatePsiTrainingState.h b/src/Geoscape/AllocatePsiTrainingState.h index ce40b6492..0d1956f7a 100644 --- a/src/Geoscape/AllocatePsiTrainingState.h +++ b/src/Geoscape/AllocatePsiTrainingState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -37,7 +37,7 @@ struct SortFunctor; * Screen shown monthly to allow changing * soldiers currently in psi training. */ -class AllocatePsiTrainingState : public State +class AllocatePsiTrainingState : public ListState { private: TextButton *_btnOk; diff --git a/src/Geoscape/AllocateTrainingState.h b/src/Geoscape/AllocateTrainingState.h index 19015e290..a66054b71 100644 --- a/src/Geoscape/AllocateTrainingState.h +++ b/src/Geoscape/AllocateTrainingState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include namespace OpenXcom @@ -37,7 +37,7 @@ struct SortFunctor; * Screen shown monthly to allow changing * soldiers currently in psi training. */ -class AllocateTrainingState : public State +class AllocateTrainingState : public ListState { private: TextButton *_btnOk; diff --git a/src/Geoscape/BaseNameState.cpp b/src/Geoscape/BaseNameState.cpp index d2e54b8ed..2a1353316 100644 --- a/src/Geoscape/BaseNameState.cpp +++ b/src/Geoscape/BaseNameState.cpp @@ -25,6 +25,9 @@ #include "../Interface/TextEdit.h" #include "../Interface/TextButton.h" #include "../Savegame/Base.h" +#include "../Savegame/SavedGame.h" +#include "../Savegame/Region.h" +#include "../Savegame/Country.h" #include "../Basescape/PlaceLiftState.h" #include "../Engine/Options.h" #include "../Engine/RNG.h" @@ -51,6 +54,7 @@ BaseNameState::BaseNameState(Base *base, Globe *globe, bool first, bool fixedLoc _btnOk = new TextButton(162, 12, 47, 118); _txtTitle = new Text(182, 17, 37, 70); _edtName = new TextEdit(this, 127, 16, 59, 94); + _txtArea = new Text(180, 9, 38, 84); // Set palette setInterface("baseNaming"); @@ -59,6 +63,7 @@ BaseNameState::BaseNameState(Base *base, Globe *globe, bool first, bool fixedLoc add(_btnOk, "button", "baseNaming"); add(_txtTitle, "text", "baseNaming"); add(_edtName, "text", "baseNaming"); + add(_txtArea, "genericText", "geoscape"); centerAllSurfaces(); @@ -77,6 +82,19 @@ BaseNameState::BaseNameState(Base *base, Globe *globe, bool first, bool fixedLoc _txtTitle->setBig(); _txtTitle->setText(tr("STR_BASE_NAME")); + + std::string region = tr(Region::getRegionName(_game->getSavedGame()->getRegions(), _base->getLongitude(), _base->getLatitude())); + std::string country = tr(Country::getCountryName(_game->getSavedGame()->getCountries(), _base->getLongitude(), _base->getLatitude())); + if (country.empty()) + { + _txtArea->setText(tr("STR_AREA_").arg(region)); + } + else + { + _txtArea->setText(tr("STR_AREA_").arg(tr("STR_COUNTRIES_COMMA").arg(country).arg(region))); + } + _txtArea->setAlign(ALIGN_CENTER); + if (!_game->getMod()->getBaseNamesFirst().empty()) { std::ostringstream ss; diff --git a/src/Geoscape/BaseNameState.h b/src/Geoscape/BaseNameState.h index 5a429efa1..2333a620a 100644 --- a/src/Geoscape/BaseNameState.h +++ b/src/Geoscape/BaseNameState.h @@ -41,7 +41,7 @@ private: Base *_base; Globe *_globe; Window *_window; - Text *_txtTitle; + Text *_txtTitle, *_txtArea; TextEdit *_edtName; TextButton *_btnOk; bool _first; diff --git a/src/Geoscape/BuildNewBaseState.cpp b/src/Geoscape/BuildNewBaseState.cpp index 9622f4668..dd09a0076 100644 --- a/src/Geoscape/BuildNewBaseState.cpp +++ b/src/Geoscape/BuildNewBaseState.cpp @@ -31,11 +31,14 @@ #include "../Savegame/Base.h" #include "../Savegame/Craft.h" #include "../Savegame/SavedGame.h" +#include "../Savegame/Region.h" +#include "../Savegame/Country.h" #include "BaseNameState.h" #include "ConfirmNewBaseState.h" #include "../Engine/Options.h" #include "../Menu/ErrorMessageState.h" #include "../Mod/RuleInterface.h" +#include "../Mod/RuleRegion.h" namespace OpenXcom { @@ -64,12 +67,25 @@ BuildNewBaseState::BuildNewBaseState(Base *base, Globe *globe, bool first) : _ba _btnZoomIn = new InteractiveSurface(23, 23, 295 + dx * 2, 156 + dy); _btnZoomOut = new InteractiveSurface(13, 17, 300 + dx * 2, 182 + dy); - _window = new Window(this, 256, 28, 0, 0); + _window = new Window(this, 256, (Options::kaizokuNewBaseHoverAreaInfo == 1) ? (first ? 37 : 45) : 28, 0, 0); _window->setX(dx); _window->setDY(0); - _btnCancel = new TextButton(54, 12, 186 + dx, 8); + _btnCancel = new TextButton(54, 12, 186 + dx, (Options::kaizokuNewBaseHoverAreaInfo == 1) ? 13 : 8); _txtTitle = new Text(180, 16, 8 + dx, 6); + if (Options::kaizokuNewBaseHoverAreaInfo > 0) + { + _txtArea = new Text(240, (first ? 9 : 19), 8 + dx, 19); // Top + if (Options::kaizokuNewBaseHoverAreaInfo == 2) // Bottom + { + int hh = (first ? 28 : 36); + _windowArea = new Window(this, 256, hh, 0, 200 - hh); + _windowArea->setX(dx); + _windowArea->setY(globe->getHeight() - hh); + _txtArea->setY(globe->getHeight() - (hh - 10)); + } + } + _hoverTimer = new Timer(50); _hoverTimer->onTimer((StateHandler)&BuildNewBaseState::hoverRedraw); _hoverTimer->start(); @@ -88,6 +104,15 @@ BuildNewBaseState::BuildNewBaseState(Base *base, Globe *globe, bool first) : _ba add(_btnCancel, "genericButton2", "geoscape"); add(_txtTitle, "genericText", "geoscape"); + if (Options::kaizokuNewBaseHoverAreaInfo > 0) + { + if (Options::kaizokuNewBaseHoverAreaInfo == 2) + { + add(_windowArea, "genericWindow", "geoscape"); + } + add(_txtArea, "genericText", "geoscape"); + } + // Set up objects _globe->onMouseClick((ActionHandler)&BuildNewBaseState::globeClick); @@ -135,6 +160,11 @@ BuildNewBaseState::BuildNewBaseState(Base *base, Globe *globe, bool first) : _ba _txtTitle->setVerticalAlign(ALIGN_MIDDLE); _txtTitle->setWordWrap(true); + if (Options::kaizokuNewBaseHoverAreaInfo == 2) + { + setWindowBackground(_windowArea, "geoscape"); + } + if (_first) { _btnCancel->setVisible(false); @@ -203,6 +233,27 @@ void BuildNewBaseState::hoverRedraw(void) { _globe->setNewBaseHoverPos(lon,lat); _globe->setNewBaseHover(true); + + if (Options::kaizokuNewBaseHoverAreaInfo > 0) + { + Region* r = Region::getRegion(_game->getSavedGame()->getRegions(), lon, lat); + std::string region = tr(r->getRules()->getType()); + std::string country = tr(Country::getCountryName(_game->getSavedGame()->getCountries(), lon, lat)); + std::ostringstream ss; + if (!_first) { + int cost = r->getRules()->getBaseCost(); + ss << Unicode::TOK_COLOR_FLIP << tr("STR_COST_").arg(Unicode::formatFunding(cost)) << "\n" << Unicode::TOK_COLOR_FLIP; + } + if (country.empty()) + { + ss << tr("STR_AREA_").arg(region); + } + else + { + ss << tr("STR_AREA_").arg(tr("STR_COUNTRIES_COMMA").arg(country).arg(region)); + } + _txtArea->setText(ss.str()); + } } if (Options::globeRadarLines && !(AreSame(_oldlat, lat) && AreSame(_oldlon, lon)) ) { @@ -401,7 +452,11 @@ void BuildNewBaseState::resize(int &dX, int &dY) for (auto* surface : _surfaces) { surface->setX(surface->getX() + dX / 2); - if (surface != _window && surface != _btnCancel && surface != _txtTitle) + if (Options::kaizokuNewBaseHoverAreaInfo == 2 && (surface == _windowArea || surface == _txtArea)) // Bottom + { + surface->setY(surface->getY() + dY); + } + else if (surface != _window && surface != _btnCancel && surface != _txtTitle && surface != _windowArea && surface != _txtArea) { surface->setY(surface->getY() + dY / 2); } diff --git a/src/Geoscape/BuildNewBaseState.h b/src/Geoscape/BuildNewBaseState.h index 69d524375..e6a0a8744 100644 --- a/src/Geoscape/BuildNewBaseState.h +++ b/src/Geoscape/BuildNewBaseState.h @@ -40,8 +40,8 @@ private: Base *_base; Globe *_globe; InteractiveSurface *_btnRotateLeft, *_btnRotateRight, *_btnRotateUp, *_btnRotateDown, *_btnZoomIn, *_btnZoomOut; - Window *_window; - Text *_txtTitle; + Window *_window, *_windowArea; + Text *_txtTitle, *_txtArea; TextButton *_btnCancel; Timer *_hoverTimer; bool _first; diff --git a/src/Geoscape/ConfirmDestinationState.cpp b/src/Geoscape/ConfirmDestinationState.cpp index 8f1e9399a..bbfbe1b8d 100644 --- a/src/Geoscape/ConfirmDestinationState.cpp +++ b/src/Geoscape/ConfirmDestinationState.cpp @@ -163,7 +163,10 @@ ConfirmDestinationState::ConfirmDestinationState(std::vector crafts, Tar ssStatus << tr("STR_HOUR_SHORT").arg(hours); } _txtETA->setAlign(ALIGN_CENTER); - _txtETA->setText(tr("STR_ETA").arg(ssStatus.str())); + // calculateRange() doesn't take "weapon" bonus stats into account + double bonusFuelRatio = (double)_crafts.front()->getFuelMax() / _crafts.front()->getRules()->getMaxFuel(); + int maxRange = ((RuleCraft*)_crafts.front()->getRules())->calculateRange(0) * bonusFuelRatio; + _txtETA->setText(std::string(tr("STR_ETA").arg(ssStatus.str())).append(" ").append(tr("STR_FUEL_CAPACITY").arg(distance)).append(" ").append(tr("STR_MAXIMUM_RANGE").arg(maxRange))); } } } diff --git a/src/Geoscape/ConfirmNewBaseState.cpp b/src/Geoscape/ConfirmNewBaseState.cpp index 49e1f22d6..990ca139b 100644 --- a/src/Geoscape/ConfirmNewBaseState.cpp +++ b/src/Geoscape/ConfirmNewBaseState.cpp @@ -25,7 +25,9 @@ #include "../Interface/TextButton.h" #include "../Savegame/SavedGame.h" #include "../Savegame/Region.h" +#include "../Savegame/Country.h" #include "../Mod/RuleRegion.h" +#include "../Mod/RuleCountry.h" #include "../Savegame/Base.h" #include "BaseNameState.h" #include "../Menu/ErrorMessageState.h" @@ -51,7 +53,7 @@ ConfirmNewBaseState::ConfirmNewBaseState(Base *base, Globe *globe) : _base(base) _btnOk = new TextButton(54, 12, 68, 104); _btnCancel = new TextButton(54, 12, 138, 104); _txtCost = new Text(120, 9, 68, 80); - _txtArea = new Text(120, 9, 68, 90); + _txtArea = new Text(140, 9, 68, 90); // Set palette setInterface("geoscape"); @@ -75,20 +77,27 @@ ConfirmNewBaseState::ConfirmNewBaseState(Base *base, Globe *globe) : _base(base) _btnCancel->onMouseClick((ActionHandler)&ConfirmNewBaseState::btnCancelClick); _btnCancel->onKeyboardPress((ActionHandler)&ConfirmNewBaseState::btnCancelClick, Options::keyCancel); - std::string area; - for (const auto* region : *_game->getSavedGame()->getRegions()) - { - if (region->getRules()->insideRegion(_base->getLongitude(), _base->getLatitude())) - { - _cost = region->getRules()->getBaseCost(); - area = tr(region->getRules()->getType()); - break; - } - } + Region *r = Region::getRegion(_game->getSavedGame()->getRegions(), _base->getLongitude(), _base->getLatitude()); + _cost = r->getRules()->getBaseCost(); _txtCost->setText(tr("STR_COST_").arg(Unicode::formatFunding(_cost))); - _txtArea->setText(tr("STR_AREA_").arg(area)); + std::string region = tr(r->getRules()->getType()); + std::string country = tr(Country::getCountryName(_game->getSavedGame()->getCountries(), _base->getLongitude(), _base->getLatitude())); + if (country.empty()) + { + _txtArea->setText(tr("STR_AREA_").arg(region)); + } + else + { + _txtArea->setText(tr("STR_AREA_").arg(tr("STR_COUNTRIES_COMMA").arg(country).arg(region))); + } + if (_txtArea->getTextWidth() > _txtArea->getWidth()) + { + _txtArea->setX(_window->getX() + 6); + _txtArea->setWidth(_window->getWidth() - 12); + _txtArea->setAlign(ALIGN_CENTER); + } } /** diff --git a/src/Geoscape/Globe.cpp b/src/Geoscape/Globe.cpp index 802f6cb43..7c054de54 100644 --- a/src/Geoscape/Globe.cpp +++ b/src/Geoscape/Globe.cpp @@ -53,6 +53,8 @@ #include "../Mod/Texture.h" #include "../Interface/Cursor.h" #include "../Engine/Screen.h" +#include "../Mod/RuleTerrain.h" +#include "../Mod/RuleEnviroEffects.h" namespace OpenXcom { @@ -2143,4 +2145,32 @@ void Globe::setCraftRange(double lon, double lat, double range) _craftRange = range; } +std::unique_ptr> Globe::getPossibleEnvironmentConditions(double lon, double lat, const std::string& faction) { + // look up polygons texture + int texture, shade; + getPolygonTextureAndShade(lon, lat, &texture, &shade); + Texture* globeTexture = _game->getMod()->getGlobe()->getTexture(texture); + std::vector* terrains = globeTexture->getTerrain(); + + std::unique_ptr> environmentConditions(new std::vector); + for (const TerrainCriteria& terrainCriteria : *terrains) + { + if (terrainCriteria.weight > 0 && + lon >= terrainCriteria.lonMin && lon < terrainCriteria.lonMax && + lat >= terrainCriteria.latMin && lat < terrainCriteria.latMax) + { + RuleTerrain* terrain = _game->getMod()->getTerrain(terrainCriteria.name, false); + RuleEnviroEffects* enviro = _game->getMod()->getEnviroEffects(terrain->getEnviroEffects()); + if (enviro) { + std::string strEnvironmentCondition = enviro->getEnvironmetalCondition(faction).weaponOrAmmo; + // Unique only + if (std::find(environmentConditions->begin(), environmentConditions->end(), strEnvironmentCondition) == environmentConditions->end()) { + environmentConditions->push_back(strEnvironmentCondition); + } + } + } + } + return environmentConditions; +} + } diff --git a/src/Geoscape/Globe.h b/src/Geoscape/Globe.h index a0a8813fe..3bfe62047 100644 --- a/src/Geoscape/Globe.h +++ b/src/Geoscape/Globe.h @@ -213,6 +213,8 @@ public: void resize(); /// Move the mouse back to where it started after we finish drag scrolling. void stopScrolling(Action *action); + /// Get possible environment conditions at the given point. + std::unique_ptr> getPossibleEnvironmentConditions(double lon, double lat, const std::string& faction = "STR_FRIENDLY"); }; } diff --git a/src/Geoscape/InterceptState.h b/src/Geoscape/InterceptState.h index d28bf91f2..cedb3509a 100644 --- a/src/Geoscape/InterceptState.h +++ b/src/Geoscape/InterceptState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -36,7 +36,7 @@ class Target; * Intercept window that lets the player launch * crafts into missions from the Geoscape. */ -class InterceptState : public State +class InterceptState : public ListState { private: TextButton *_btnCancel, *_btnGotoBase; diff --git a/src/Geoscape/ItemsArrivingState.h b/src/Geoscape/ItemsArrivingState.h index f0a4daab7..994226a40 100644 --- a/src/Geoscape/ItemsArrivingState.h +++ b/src/Geoscape/ItemsArrivingState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -33,7 +33,7 @@ class Base; * Items Arriving window that displays all * the items that have arrived at bases. */ -class ItemsArrivingState : public State +class ItemsArrivingState : public ListState { private: GeoscapeState *_state; diff --git a/src/Geoscape/NewPossibleCraftState.h b/src/Geoscape/NewPossibleCraftState.h index 630672e64..e7ff5a4ae 100644 --- a/src/Geoscape/NewPossibleCraftState.h +++ b/src/Geoscape/NewPossibleCraftState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class RuleCraft; * Window which informs the player of new possible craft to buy/rent. * Also allows to go to the PurchaseState to order some new craft. */ -class NewPossibleCraftState : public State +class NewPossibleCraftState : public ListState { private: Window *_window; diff --git a/src/Geoscape/NewPossibleFacilityState.h b/src/Geoscape/NewPossibleFacilityState.h index ec929334d..cd82312fd 100644 --- a/src/Geoscape/NewPossibleFacilityState.h +++ b/src/Geoscape/NewPossibleFacilityState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -35,7 +35,7 @@ class RuleBaseFacility; * Window which informs the player of new possible base facility to build. * Also allows to go to the BaseView to build some new facilities. */ -class NewPossibleFacilityState : public State +class NewPossibleFacilityState : public ListState { private: Window *_window; diff --git a/src/Geoscape/NewPossibleManufactureState.h b/src/Geoscape/NewPossibleManufactureState.h index 0cd4bb135..342bd24e3 100644 --- a/src/Geoscape/NewPossibleManufactureState.h +++ b/src/Geoscape/NewPossibleManufactureState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class RuleManufacture; * Window which inform the player of new possible manufacture projects. * Also allow to go to the ManufactureState to dispatch available engineers. */ -class NewPossibleManufactureState : public State +class NewPossibleManufactureState : public ListState { private: Window *_window; diff --git a/src/Geoscape/NewPossiblePurchaseState.h b/src/Geoscape/NewPossiblePurchaseState.h index 62ace9168..7d20b8763 100644 --- a/src/Geoscape/NewPossiblePurchaseState.h +++ b/src/Geoscape/NewPossiblePurchaseState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class RuleItem; * Window which inform the player of new possible items to buy. * Also allows to go to the PurchaseState to order some new items. */ -class NewPossiblePurchaseState : public State +class NewPossiblePurchaseState : public ListState { private: Window *_window; diff --git a/src/Geoscape/NewPossibleResearchState.h b/src/Geoscape/NewPossibleResearchState.h index 6e4eb71df..07a8bc84e 100644 --- a/src/Geoscape/NewPossibleResearchState.h +++ b/src/Geoscape/NewPossibleResearchState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class RuleResearch; * Window which inform the player of new possible research projects. * Also allow to go to the ResearchState to dispatch available scientist. */ -class NewPossibleResearchState : public State +class NewPossibleResearchState : public ListState { private: Window *_window; diff --git a/src/Geoscape/ProductionCompleteState.h b/src/Geoscape/ProductionCompleteState.h index 09f1e4076..1caeb2826 100644 --- a/src/Geoscape/ProductionCompleteState.h +++ b/src/Geoscape/ProductionCompleteState.h @@ -20,7 +20,7 @@ #include #include #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Savegame/Production.h" namespace OpenXcom @@ -37,7 +37,7 @@ class GeoscapeState; * Window used to notify the player when * a production is completed. */ -class ProductionCompleteState : public State +class ProductionCompleteState : public ListState { private: Base *_base; diff --git a/src/Geoscape/SelectMusicTrackState.h b/src/Geoscape/SelectMusicTrackState.h index fafc0a5a0..5ed0583dc 100644 --- a/src/Geoscape/SelectMusicTrackState.h +++ b/src/Geoscape/SelectMusicTrackState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -39,7 +39,7 @@ class Music; * Select Music Track window that allows changing * of the currently played music track. */ -class SelectMusicTrackState : public State +class SelectMusicTrackState : public ListState { private: SelectMusicTrackOrigin _origin; diff --git a/src/Geoscape/TrainingFinishedState.h b/src/Geoscape/TrainingFinishedState.h index 96a45543e..f95eb7532 100644 --- a/src/Geoscape/TrainingFinishedState.h +++ b/src/Geoscape/TrainingFinishedState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -34,7 +34,7 @@ class Soldier; * Window which informs the player of finished soldier training. * Also allows to go to the AllocateTrainingState to assign more soldiers into training. */ -class TrainingFinishedState : public State +class TrainingFinishedState : public ListState { private: Window *_window; diff --git a/src/Geoscape/UfoDetectedState.cpp b/src/Geoscape/UfoDetectedState.cpp index 5668b6e83..507c37891 100644 --- a/src/Geoscape/UfoDetectedState.cpp +++ b/src/Geoscape/UfoDetectedState.cpp @@ -35,10 +35,26 @@ #include "../Savegame/AlienMission.h" #include "InterceptState.h" #include "../Mod/RuleCraft.h" +#include "../Mod/AlienDeployment.h" +#include "../Mod/RuleEnviroEffects.h" namespace OpenXcom { +// FIXME: Place this somewhere more appropriate +std::unique_ptr> getUniqueTranslatedEnvironmentConditions(GeoscapeState* state, double lon, double lat, const std::string& faction = "STR_FRIENDLY") { + std::unique_ptr> environmentConditions = state->getGlobe()->getPossibleEnvironmentConditions(lon, lat, faction); + std::unique_ptr> uniqueConditions(new std::vector); + std::string translatedCondition; + for (size_t i = 0; i < environmentConditions->size(); i++) { + translatedCondition = state->tr((*environmentConditions)[i]); + if (std::find(uniqueConditions->begin(), uniqueConditions->end(), translatedCondition) == uniqueConditions->end()) { + uniqueConditions->push_back(translatedCondition); + } + } + return uniqueConditions; +} + /** * Initializes all the elements in the Ufo Detected window. * @param game Pointer to the core game. @@ -182,18 +198,48 @@ UfoDetectedState::UfoDetectedState(Ufo *ufo, GeoscapeState *state, bool detected ss << Unicode::TOK_COLOR_FLIP << tr(altitude); _lstInfo->addRow(2, tr("STR_ALTITUDE").c_str(), ss.str().c_str()); - std::string heading = _ufo->getDirection(); - if (_ufo->getStatus() != Ufo::FLYING) - { - heading = "STR_NONE_UC"; + if (altitude != "STR_GROUNDED") { + std::string heading = _ufo->getDirection(); + if (_ufo->getStatus() != Ufo::FLYING) + { + heading = "STR_NONE_UC"; + } + ss.str(""); + ss << Unicode::TOK_COLOR_FLIP << tr(heading); + _lstInfo->addRow(2, tr("STR_HEADING").c_str(), ss.str().c_str()); + + ss.str(""); + ss << Unicode::TOK_COLOR_FLIP << Unicode::formatNumber(_ufo->getSpeed()); + _lstInfo->addRow(2, tr("STR_SPEED").c_str(), ss.str().c_str()); + } else { + // Use heading & speed rows for environment conditions + ss.str(""); + ss << Unicode::TOK_COLOR_FLIP; + AlienDeployment* deployment = _game->getMod()->getDeployment(_ufo->getRules()->getType()); + RuleEnviroEffects* enviro = _game->getMod()->getEnviroEffects(deployment->getEnviroEffects()); + if (enviro) { + ss << tr(enviro->getEnvironmetalCondition("STR_FRIENDLY").weaponOrAmmo); + } else { + std::unique_ptr> environmentConditions = getUniqueTranslatedEnvironmentConditions(_state, _ufo->getLongitude(), _ufo->getLatitude()); + if (environmentConditions->size() > 0) { + for (size_t i = 0; i < environmentConditions->size(); i++) { + if (i > 0) { + ss << Unicode::TOK_COLOR_FLIP << ", " << Unicode::TOK_COLOR_FLIP; + } + ss << environmentConditions->at(i); + } + } + } + //_lstInfo->setDot(false); + _lstInfo->setWordWrap(true); + //_lstInfo->setCondensed(true); + // Workaround for setCondensed() never having been implemented properly (text not being resized if _condensed in addRow()): + //_lstInfo->setColumns(2, 204, 1); + //_lstInfo->addRow(2, "POSSIBLE CONDITIONS", ""); // FIXME: Add translation string + //_lstInfo->addRow(1, ss.str().c_str()); + _lstInfo->setColumns(2, 77, 127); + _lstInfo->addRow(2, "ENVIRONMENT", ss.str().c_str()); // FIXME: Add translation string } - ss.str(""); - ss << Unicode::TOK_COLOR_FLIP << tr(heading); - _lstInfo->addRow(2, tr("STR_HEADING").c_str(), ss.str().c_str()); - - ss.str(""); - ss << Unicode::TOK_COLOR_FLIP << Unicode::formatNumber(_ufo->getSpeed()); - _lstInfo->addRow(2, tr("STR_SPEED").c_str(), ss.str().c_str()); _lstInfo2->setColumns(2, 77, 140); _lstInfo2->setDot(true); diff --git a/src/Geoscape/UfoTrackerState.h b/src/Geoscape/UfoTrackerState.h index 7bfef27bf..d6d63b3da 100644 --- a/src/Geoscape/UfoTrackerState.h +++ b/src/Geoscape/UfoTrackerState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -35,7 +35,7 @@ class GeoscapeState; * UFO Tracker window that allows the player to track * various things (UFOs, Crash sites, Landing sites, Terror sites, Mission sites, Alien bases) on the Geoscape. */ -class UfoTrackerState : public State +class UfoTrackerState : public ListState { private: TextButton *_btnCancel; diff --git a/src/Interface/ComboBox.cpp b/src/Interface/ComboBox.cpp index 3f32e459f..aa75e832d 100644 --- a/src/Interface/ComboBox.cpp +++ b/src/Interface/ComboBox.cpp @@ -298,11 +298,12 @@ void ComboBox::setDropdown(int options) { int items = std::min(options, MAX_ITEMS); int h = _button->getFont()->getHeight() + _button->getFont()->getSpacing(); - int dy = (Options::baseYResolution - 200) / 2; - while (_window->getY() + items * h + VERTICAL_MARGIN * 2 > 200 + dy) + while (_window->getY() + items * h + VERTICAL_MARGIN * 2 > Options::baseYResolution - h) { items--; } + if (items < 1) + items = 1; int popupHeight = items * h + VERTICAL_MARGIN * 2; int popupY = getPopupWindowY(getHeight(), getY(), popupHeight, _popupAboveButton); diff --git a/src/Interface/TextButton.cpp b/src/Interface/TextButton.cpp index 764f55cf3..462ddd62c 100644 --- a/src/Interface/TextButton.cpp +++ b/src/Interface/TextButton.cpp @@ -359,4 +359,8 @@ void TextButton::setGeoscapeButton(bool geo) _geoscapeButton = geo; } +int TextButton::getTextWidth(int line) const { + return _text->getTextWidth(line); +} + } diff --git a/src/Interface/TextButton.h b/src/Interface/TextButton.h index 947b1e01d..98971373f 100644 --- a/src/Interface/TextButton.h +++ b/src/Interface/TextButton.h @@ -88,6 +88,7 @@ public: void setWidth(int width) override; void setHeight(int height) override; void setGeoscapeButton(bool geo); + int getTextWidth(int line = -1) const; }; } diff --git a/src/Interface/TextList.cpp b/src/Interface/TextList.cpp index ecce75c2e..57baef536 100644 --- a/src/Interface/TextList.cpp +++ b/src/Interface/TextList.cpp @@ -96,6 +96,18 @@ void TextList::setX(int x) _scrollbar->setX(getX() + getWidth() + _scrollPos); if (_selector != 0) _selector->setX(getX()); + + if (_arrowPos != -1) + { + for (std::vector::iterator i = _arrowLeft.begin(); i < _arrowLeft.end(); ++i) + { + (*i)->setX(x + _arrowPos); + } + for (std::vector::iterator i = _arrowRight.begin(); i < _arrowRight.end(); ++i) + { + (*i)->setX(x + _arrowPos + 12); + } + } } /** diff --git a/src/Interface/Window.cpp b/src/Interface/Window.cpp index 200141f87..ad38aea02 100644 --- a/src/Interface/Window.cpp +++ b/src/Interface/Window.cpp @@ -257,14 +257,20 @@ void Window::draw() if (_bg != 0) { + int verticalTiles = std::ceil(((double)getHeight() - _dy - square.y) / _bg->getHeight()); + SurfaceCrop crop = _bg->getCrop(); crop.getCrop()->x = square.x - _dx; - crop.getCrop()->y = square.y - _dy; - crop.getCrop()->w = square.w ; - crop.getCrop()->h = square.h ; + crop.getCrop()->w = square.w; crop.setX(square.x); - crop.setY(square.y); - crop.blit(this); + for (int i = 0; i < verticalTiles; i++) + { + int y = ((i == 0) ? square.y : _dy) + (i * (_bg->getHeight())); + crop.getCrop()->h = (verticalTiles == 1) ? square.h : ((i < verticalTiles - 1) ? _bg->getHeight() : getHeight() - square.y - y); + crop.getCrop()->y = (i == 0) ? square.y - _dy : 0; + crop.setY(y); + crop.blit(this); + } } } diff --git a/src/Menu/ListGamesState.h b/src/Menu/ListGamesState.h index 278608d7d..f5fd211db 100644 --- a/src/Menu/ListGamesState.h +++ b/src/Menu/ListGamesState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "OptionsBaseState.h" #include #include "../Savegame/SavedGame.h" @@ -37,7 +37,7 @@ class ToggleTextButton; * Base class for saved game screens which * provides the common layout and listing. */ -class ListGamesState : public State +class ListGamesState : public ListState { protected: TextButton *_btnCancel; diff --git a/src/Menu/ModListState.h b/src/Menu/ModListState.h index 84045d60c..5c6efdde7 100644 --- a/src/Menu/ModListState.h +++ b/src/Menu/ModListState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Engine/ModInfo.h" #include #include @@ -35,7 +35,7 @@ class ComboBox; /** * Mods window to manage the installed mods. */ -class ModListState : public State +class ModListState : public ListState { private: Window *_window; diff --git a/src/Menu/OptionsAdvancedState.cpp b/src/Menu/OptionsAdvancedState.cpp index 37ffbb700..919d7c616 100644 --- a/src/Menu/OptionsAdvancedState.cpp +++ b/src/Menu/OptionsAdvancedState.cpp @@ -91,7 +91,7 @@ OptionsAdvancedState::OptionsAdvancedState(OptionsOrigin origin) : OptionsBaseSt _btnOTHER->setText(tr("STR_ENGINE_OTHER")); // rename in your fork _btnOTHER->setGroup(&_owner); _btnOTHER->onMousePress((ActionHandler)&OptionsAdvancedState::btnGroupPress, SDL_BUTTON_LEFT); - _btnOTHER->setVisible(false); // enable in your fork + _btnOTHER->setVisible(true); // enable in your fork // how much room do we need for YES/NO Text text = Text(100, 9, 0, 0); @@ -433,6 +433,16 @@ void OptionsAdvancedState::lstOptionsClick(Action *action) min = _isTFTD ? 2 : 1; max = _isTFTD ? 16 : 15; } + else if (i == &Options::kaizokuNewBaseHoverAreaInfo) + { + min = 0; + max = 2; + } + else if (i == &Options::kaizokuListsScreenHeightPercentage) + { + min = 0; + max = 100; + } if (*i < min) { diff --git a/src/Menu/StatisticsState.h b/src/Menu/StatisticsState.h index 3ca521983..aeb224794 100644 --- a/src/Menu/StatisticsState.h +++ b/src/Menu/StatisticsState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" namespace OpenXcom { @@ -31,7 +31,7 @@ class TextList; * Statistics window that shows up * at the end of the game. */ -class StatisticsState : public State +class StatisticsState : public ListState { private: TextButton *_btnOk; diff --git a/src/OpenXcom.2010.vcxproj b/src/OpenXcom.2010.vcxproj index 073cd5656..f4f8d7792 100644 --- a/src/OpenXcom.2010.vcxproj +++ b/src/OpenXcom.2010.vcxproj @@ -464,6 +464,7 @@ + @@ -853,6 +854,7 @@ + diff --git a/src/OpenXcom.2010.vcxproj.filters b/src/OpenXcom.2010.vcxproj.filters index a72057464..3c45b6214 100644 --- a/src/OpenXcom.2010.vcxproj.filters +++ b/src/OpenXcom.2010.vcxproj.filters @@ -1133,6 +1133,8 @@ Savegame + + Engine Basescape @@ -2336,6 +2338,8 @@ Mod + + Engine Basescape @@ -2387,4 +2391,4 @@ - \ No newline at end of file + diff --git a/src/Savegame/Country.cpp b/src/Savegame/Country.cpp index 5d7259c8a..b5882879a 100644 --- a/src/Savegame/Country.cpp +++ b/src/Savegame/Country.cpp @@ -357,6 +357,40 @@ bool Country::canBeInfiltrated() return false; } +/** + * get country at globe coordinates + * @param countries Pointer to a vector of Country pointers like in SavedGame::getCountries() + * @param lon Longitude in radians. + * @param lat Latitude in radians. + * @return Country pointer or 0 + */ +Country* Country::getCountry(std::vector *countries, double lon, double lat) +{ + for (std::vector::iterator i = countries->begin(); i != countries->end(); ++i) + { + if ((*i)->getRules()->insideCountry(lon, lat)) + { + return *i; + } + } + return 0; +} + +/** + * get country name at globe coordinates + * @param countries Pointer to a vector of Country pointers like in SavedGame::getCountries() + * @param lon Longitude in radians. + * @param lat Latitude in radians. + * @return unique country language string or empty string + */ +std::string Country::getCountryName(std::vector *countries, double lon, double lat) +{ + Country *c = getCountry(countries, lon, lat); + if (c != 0) + return c->getRules()->getType(); + return ""; +} + //////////////////////////////////////////////////////////// // Script binding //////////////////////////////////////////////////////////// diff --git a/src/Savegame/Country.h b/src/Savegame/Country.h index bd1f34aaa..462476191 100644 --- a/src/Savegame/Country.h +++ b/src/Savegame/Country.h @@ -90,6 +90,10 @@ public: void setPact(); /// can be (re)infiltrated? bool canBeInfiltrated(); + /// get country at globe coordinates + static Country* getCountry(std::vector *countries, double lon, double lat); + /// get country name at globe coordinates + static std::string getCountryName(std::vector *countries, double lon, double lat); private: int getCurrentFunding() const { return _funding.back(); } diff --git a/src/Savegame/Region.cpp b/src/Savegame/Region.cpp index 7d2352190..c3507a107 100644 --- a/src/Savegame/Region.cpp +++ b/src/Savegame/Region.cpp @@ -120,4 +120,38 @@ void Region::newMonth() _activityXcom.erase(_activityXcom.begin()); } +/** + * get region at globe coordinates + * @param regions Pointer to a vector of Region pointers like in SavedGame::getRegions() + * @param lon Longitude in radians. + * @param lat Latitude in radians. + * @return Region pointer or 0 + */ +Region* Region::getRegion(std::vector *regions, double lon, double lat) +{ + for (std::vector::iterator i = regions->begin(); i != regions->end(); ++i) + { + if ((*i)->getRules()->insideRegion(lon, lat)) + { + return *i; + } + } + return 0; +} + +/** + * get region name at globe coordinates + * @param regions Pointer to a vector of Region pointers like in SavedGame::getRegions() + * @param lon Longitude in radians. + * @param lat Latitude in radians. + * @return unique region language string or empty string + */ +std::string Region::getRegionName(std::vector *regions, double lon, double lat) +{ + Region *r = getRegion(regions, lon, lat); + if (r != 0) + return r->getRules()->getType(); + return ""; +} + } diff --git a/src/Savegame/Region.h b/src/Savegame/Region.h index 299506669..62dd38be2 100644 --- a/src/Savegame/Region.h +++ b/src/Savegame/Region.h @@ -56,6 +56,10 @@ public: std::vector &getActivityAlien(); /// start new month of activity void newMonth(); + /// get region at globe coordinates + static Region *getRegion(std::vector *regions, double lon, double lat); + /// get region name at globe coordinates + static std::string getRegionName(std::vector *regions, double lon, double lat); }; } diff --git a/src/Ufopaedia/StatsForNerdsState.h b/src/Ufopaedia/StatsForNerdsState.h index 0e7e0c70e..2ce455703 100644 --- a/src/Ufopaedia/StatsForNerdsState.h +++ b/src/Ufopaedia/StatsForNerdsState.h @@ -18,7 +18,7 @@ * along with OpenXcom. If not, see . */ #include "../Battlescape/Position.h" -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "../Mod/ArticleDefinition.h" #include "../Mod/Armor.h" #include "../Mod/MapData.h" @@ -43,7 +43,7 @@ template class ScriptValues; /** * A screen, where you can see the (almost) raw ruleset corresponding to the given Ufopedia article. */ -class StatsForNerdsState : public State +class StatsForNerdsState : public ListState { private: Window *_window; diff --git a/src/Ufopaedia/UfopaediaSelectState.h b/src/Ufopaedia/UfopaediaSelectState.h index 9d450a9a1..68d837a58 100644 --- a/src/Ufopaedia/UfopaediaSelectState.h +++ b/src/Ufopaedia/UfopaediaSelectState.h @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with OpenXcom. If not, see . */ -#include "../Engine/State.h" +#include "../Engine/ListState.h" #include "Ufopaedia.h" #include @@ -36,7 +36,7 @@ namespace OpenXcom * UfopaediaSelectState is the screen that lists articles of a given type. */ - class UfopaediaSelectState : public State + class UfopaediaSelectState : public ListState { public: UfopaediaSelectState(const std::string §ion, int heightOffset, int windowOffset);