-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lua: Allow setting number of players, and placing HQs. Then fix the mission on map "The snake" #1683
base: master
Are you sure you want to change the base?
Conversation
This is gerat, but I'd still like to have some feature to "fix" map 6, where they failed when converting from WORLD.DAT to WLD :D |
What do you mean by this? |
On map IX they changed the map between the original version and gold/mission CD. For one instance they removed the harbors completly, this means there is no more seafaring. They also changed the terrain for the second AI, which had nearly no way of farming or producing wood since they used a non farmable terrain which simply stopped that AI from doing anything usefull. You can compare that version: Campaign_OriginalRoman/MISS208.WLD with the one in your game directory, I've created it by reading the WORLD.DAT file of the original campaign and replacing the terrain with the correct one and re adding the harbors |
Ah yes, that one. Yeah this one is messed up in mission CD/gold. The RTX file is also wrong in a couple of places resulting in If you create an issue for this I would very much like to take a look at this once I finish all the stuff I currently have open. While this does actually change an original map (which I don't like in principle), I think it is safe to assume the map was not supposed to be played as it was post mission CD. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope this does not break something later on, but looks good for now :)
If you put two HQs for a player from LUA then only the first one will be placed. This needs documenting.
Indeed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some comments and questions.
We also need to increase the version in unsigned LuaInterfaceGameBase::GetFeatureLevel()
due to the added functions such that scripts can check for that. Also the 2 changed mission scripts should require that new version too
@@ -376,6 +377,19 @@ void GamePlayer::RemoveBuildingSite(noBuildingSite* bldSite) | |||
buildings.Remove(bldSite); | |||
} | |||
|
|||
bool GamePlayer::IsHQTent() const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason for adding this here? It isn't used (yet)
return false; | ||
} | ||
|
||
void GamePlayer::SetHQIsTent(bool isTent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and GetHQ
is basically the code moved from ModifyHQ
. What was the motivation?
I'm thinking about the case where there are multiple HQs (e.g. the S2 cheats had it) and one might want to specify which HQ to change. Putting the code in the caller uses the world to get a specific HQ and changes that.
Although we already have GetHQPos
which returns the position of "a" HQ, IIRC the last one added that still exists.
|
||
void GamePlayer::SetHQIsTent(bool isTent) | ||
{ | ||
if(nobHQ* hq = const_cast<nobHQ*>(GetHQ())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that GetSpecObj
(in GetHQ
) can return a non-const pointer. So we don't need the const cast at all.
If you make GetHQ
non-const then this can be removed
{ | ||
if(const auto num = lua->GetNumPlayersFromScript()) | ||
{ | ||
GAMESERVER.SetNumPlayers(num); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't work for savegames, will it? Because I think for a savegame the player needs to be already initialized.
Or does that work still?
|
||
unsigned LuaInterfaceSettings::GetNumPlayersFromScript() | ||
{ | ||
kaguya::LuaRef func = lua["getNumPlayers"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add documentation for this new function.
const MapPoint mp{x, y}; | ||
constexpr auto checkExists = false; | ||
world.DestroyNO(mp, checkExists); | ||
BuildingFactory::CreateBuilding(world, BuildingType::Headquarters, mp, player.GetPlayerId(), player.nation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Better use pos(ition)
as in other places
const MapPoint mp{x, y}; | |
constexpr auto checkExists = false; | |
world.DestroyNO(mp, checkExists); | |
BuildingFactory::CreateBuilding(world, BuildingType::Headquarters, mp, player.GetPlayerId(), player.nation); | |
const MapPoint pos{x, y}; | |
constexpr auto checkExists = false; | |
world.DestroyNO(pos, checkExists); | |
BuildingFactory::CreateBuilding(world, BuildingType::Headquarters, pos, player.GetPlayerId(), player.nation); |
if((!mapinfo.luaFilepath.empty() && !loader.LoadLuaScript(*game, *this, mapinfo.luaFilepath)) | ||
|| !loader.Load(mapinfo.filepath)) // Do not reorder: load lua first, load map second. | ||
// If the map is loaded first and it does not have a player HQ set, it | ||
// will not load correctly, even though the HQ may be set using LUA. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still find it hard to understand why it will "not load correctly" and what loading the script first changes. What about:
if((!mapinfo.luaFilepath.empty() && !loader.LoadLuaScript(*game, *this, mapinfo.luaFilepath)) | |
|| !loader.Load(mapinfo.filepath)) // Do not reorder: load lua first, load map second. | |
// If the map is loaded first and it does not have a player HQ set, it | |
// will not load correctly, even though the HQ may be set using LUA. | |
// Load (and verify) Lua script before the map. | |
// If a valid script exists loading the map will not abort when HQ positions in the map are missing | |
// as HQs might be placed by the script when starting the game. | |
if((!mapinfo.luaFilepath.empty() && !loader.LoadLuaScript(*game, *this, mapinfo.luaFilepath)) | |
|| !loader.Load(mapinfo.filepath)) |
@@ -526,6 +526,11 @@ bool GameServer::assignPlayersOfRandomTeams(std::vector<JoinPlayerInfo>& playerI | |||
return playerWasAssigned; | |||
} | |||
|
|||
void GameServer::SetNumPlayers(unsigned num) | |||
{ | |||
playerInfos.resize(num); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a check (state == ServerState::Config)
before doing this. Maybe:
playerInfos.resize(num); | |
if(state != ServerState::Config) | |
throw std::logic_error("Changing the number of players must only be done during game configuration"); | |
if(num < 1 || num > MAX_PLAYERS) | |
throw std::invalid_argument("Invalid number of players"); | |
playerInfos.resize(num); |
Not sure about the 2nd check as the value is likely from a lua script. So maybe rather return false here and abort the game in the caller.
@@ -52,6 +52,8 @@ class GameServer : | |||
/// Assign players that do not have a fixed team, return true if any player was assigned. | |||
static bool assignPlayersOfRandomTeams(std::vector<JoinPlayerInfo>& playerInfos); | |||
|
|||
void SetNumPlayers(unsigned num); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe document as something like:
void SetNumPlayers(unsigned num); | |
/// Change number of players (after loading the map but before starting the game) | |
void SetNumPlayers(unsigned num); |
@@ -421,8 +421,9 @@ bool MapLoader::PlaceHQs(GameWorldBase& world, std::vector<MapPoint> hqPositions | |||
// Does the HQ have a position? | |||
if(i >= hqPositions.size() || !hqPositions[i].isValid()) | |||
{ | |||
LOG.write(_("Player %u does not have a valid start position!")) % i; | |||
return false; | |||
LOG.write(_("Player %u does not have a valid start position!\n")) % i; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs an update to the translations. I used a quick regex-search-replace in that repo. Please update the submodule external/languages to the current master (revision fa7f546)
- document PlaceHQ - document why LUA should be loaded before the map
dd32aa1
to
9ea584a
Compare
Fixes map "The snake" WITHOUT changing the map. You can now use the original S2 map, but I needed to implement some additional features, like placing HQs and overriding the number of players from LUA scripts. For example Roman chapter 1 does not show 7 players anymore and chapter 7 has the player 3 HQ set from LUA (video). This also makes it possible to fix all other maps where the positions are not set in the map but only in RTX files (like half the FANpaign maps - example video).
Fixes #1624