1 /* 2 * Copyright (C) 2008-2020 by the Widelands Development Team 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 */ 19 20 #ifndef WL_LOGIC_GAME_SETTINGS_H 21 #define WL_LOGIC_GAME_SETTINGS_H 22 23 #include <memory> 24 #include <string> 25 26 #include "io/filesystem/layered_filesystem.h" 27 #include "logic/map_objects/tribes/tribe_basic_info.h" 28 #include "logic/player_end_result.h" 29 #include "logic/widelands.h" 30 #include "notifications/note_ids.h" 31 #include "notifications/notifications.h" 32 #include "scripting/lua_interface.h" 33 #include "scripting/lua_table.h" 34 35 // PlayerSlot 0 will give us Widelands::PlayerNumber 1 etc., so we rename it to avoid confusion. 36 // TODO(GunChleoc): Rename all uint8_t to PlayerSlot or Widelands::PlayerNumber 37 using PlayerSlot = Widelands::PlayerNumber; 38 39 struct PlayerSettings { 40 enum class State { kOpen, kHuman, kComputer, kClosed, kShared }; 41 42 /// Returns whether the given state allows sharing a slot at all can_be_sharedPlayerSettings43 static bool can_be_shared(PlayerSettings::State state) { 44 return state != PlayerSettings::State::kClosed && state != PlayerSettings::State::kShared; 45 } 46 47 State state; 48 uint8_t initialization_index; 49 std::string name; 50 std::string tribe; 51 bool random_tribe; 52 std::string ai; /**< Preferred AI provider for this player */ 53 bool random_ai; 54 Widelands::TeamNumber team; 55 bool closeable; // only used in multiplayer scenario maps 56 uint8_t shared_in; // the number of the player that uses this player's starting position 57 }; 58 59 struct UserSettings { 60 // TODO(k.halfman): make this some const instead of calculating this every time noneUserSettings61 static uint8_t none() { 62 return std::numeric_limits<uint8_t>::max(); 63 } not_connectedUserSettings64 static uint8_t not_connected() { 65 return none() - 1; 66 } highest_playernumUserSettings67 static uint8_t highest_playernum() { 68 return not_connected() - 1; 69 } 70 UserSettingsUserSettings71 UserSettings(Widelands::PlayerEndResult init_result, bool init_ready) 72 : result(init_result), ready(init_ready) { 73 } UserSettingsUserSettings74 UserSettings() : UserSettings(Widelands::PlayerEndResult::kUndefined, false) { 75 } 76 77 uint8_t position = 0; 78 std::string name; 79 Widelands::PlayerEndResult result; 80 std::string win_condition_string; 81 bool ready; // until now only used as a check for whether user is currently receiving a file or 82 // not 83 }; 84 85 /// The gamehost/gameclient are sending those to notify about status changes, which are then picked 86 /// up by the UI. 87 struct NoteGameSettings { 88 CAN_BE_SENT_AS_NOTE(NoteId::GameSettings) 89 90 enum class Action { 91 kUser, // A client has picked a different player slot / become an observer 92 kPlayer, // A player slot has changed its status (type, tribe etc.) 93 kMap // A new map/savegame was selected 94 }; 95 96 Action action; 97 PlayerSlot position; 98 uint8_t usernum; 99 100 explicit NoteGameSettings(Action init_action, 101 PlayerSlot init_position = std::numeric_limits<uint8_t>::max(), 102 uint8_t init_usernum = UserSettings::none()) actionNoteGameSettings103 : action(init_action), position(init_position), usernum(init_usernum) { 104 } 105 }; 106 107 /** 108 * Holds all settings about a game that can be configured before the 109 * game actually starts. 110 * 111 * Think of it as the Model in MVC. 112 */ 113 struct GameSettings { GameSettingsGameSettings114 GameSettings() 115 : playernum(0), 116 usernum(0), 117 scenario(false), 118 multiplayer(false), 119 savegame(false), 120 peaceful(false) { 121 std::unique_ptr<LuaInterface> lua(new LuaInterface); 122 std::unique_ptr<LuaTable> win_conditions( 123 lua->run_script("scripting/win_conditions/init.lua")); 124 for (const int key : win_conditions->keys<int>()) { 125 std::string filename = win_conditions->get_string(key); 126 if (g_fs->file_exists(filename)) { 127 win_condition_scripts.push_back(filename); 128 } else { 129 throw wexception("Win condition file \"%s\" does not exist", filename.c_str()); 130 } 131 } 132 } 133 134 /// Find a player number that the slot could share in. Does not guarantee that a viable slot was 135 /// actually found. 136 Widelands::PlayerNumber find_shared(PlayerSlot slot) const; 137 /// Check if the player number returned by find_shared is usable 138 bool is_shared_usable(PlayerSlot slot, Widelands::PlayerNumber shared) const; 139 /// Savegame slots and certain scenario slots can't be closed 140 bool uncloseable(PlayerSlot slot) const; 141 142 /// Number of player position 143 int16_t playernum; 144 /// Number of users entry 145 int8_t usernum; 146 147 /// Name of the selected map 148 std::string mapname; 149 std::string mapfilename; 150 151 /// Lua file defining the win condition to use. 152 std::string win_condition_script; 153 /// An ordered list of all win condition script files. 154 std::vector<std::string> win_condition_scripts; 155 156 /// Is map a scenario 157 bool scenario; 158 159 /// Is this a multiplayer game 160 bool multiplayer; 161 162 /// Is a savegame selected for loading? 163 bool savegame; 164 165 // Is all fighting forbidden? 166 bool peaceful; 167 168 /// List of tribes that players are allowed to choose 169 std::vector<Widelands::TribeBasicInfo> tribes; 170 171 /// Player configuration, with 0-based indices for players 172 std::vector<PlayerSettings> players; 173 174 /// Users connected to the game (0-based indices) - only used in multiplayer 175 std::vector<UserSettings> users; 176 }; 177 178 /** 179 * UI classes are given a GameSettingsProvider instead of direct 180 * access to \ref GameSettings. This allows pluggable behaviour in menus, 181 * depending on whether the menu was called for a singleplayer game or 182 * multiplayer game. 183 * 184 * Think of it as a mix of Model and Controller in MVC. 185 */ 186 struct GameSettingsProvider { ~GameSettingsProviderGameSettingsProvider187 virtual ~GameSettingsProvider() { 188 } 189 190 virtual const GameSettings& settings() = 0; 191 192 virtual void set_scenario(bool set) = 0; 193 virtual bool can_change_map() = 0; 194 virtual bool can_change_player_state(uint8_t number) = 0; 195 virtual bool can_change_player_tribe(uint8_t number) = 0; 196 virtual bool can_change_player_init(uint8_t number) = 0; 197 virtual bool can_change_player_team(uint8_t number) = 0; 198 199 virtual bool can_launch() = 0; 200 201 virtual void set_map(const std::string& mapname, 202 const std::string& mapfilename, 203 uint32_t maxplayers, 204 bool savegame = false) = 0; 205 virtual void set_player_state(uint8_t number, PlayerSettings::State) = 0; 206 virtual void set_player_ai(uint8_t number, const std::string&, bool const random_ai = false) = 0; 207 // Multiplayer no longer toggles per button next_player_stateGameSettingsProvider208 virtual void next_player_state(uint8_t /* number */) { 209 } 210 virtual void 211 set_player_tribe(uint8_t number, const std::string&, bool const random_tribe = false) = 0; 212 virtual void set_player_init(uint8_t number, uint8_t index) = 0; 213 virtual void set_player_name(uint8_t number, const std::string&) = 0; 214 virtual void set_player(uint8_t number, const PlayerSettings&) = 0; 215 virtual void set_player_number(uint8_t number) = 0; 216 virtual void set_player_team(uint8_t number, Widelands::TeamNumber team) = 0; 217 virtual void set_player_closeable(uint8_t number, bool closeable) = 0; 218 virtual void set_player_shared(PlayerSlot number, Widelands::PlayerNumber shared) = 0; 219 virtual void set_win_condition_script(const std::string& wc) = 0; 220 virtual std::string get_win_condition_script() = 0; 221 222 virtual void set_peaceful_mode(bool peace) = 0; 223 virtual bool is_peaceful_mode() = 0; 224 has_players_tribeGameSettingsProvider225 bool has_players_tribe() { 226 return UserSettings::highest_playernum() >= settings().playernum; 227 } 228 // For retrieving tips texts 229 struct NoTribe {}; get_players_tribeGameSettingsProvider230 const std::string& get_players_tribe() { 231 if (!has_players_tribe()) 232 throw NoTribe(); 233 return settings().players[settings().playernum].tribe; 234 } 235 }; 236 237 #endif // end of include guard: WL_LOGIC_GAME_SETTINGS_H 238