Can't declare war on newly added player

deafhandaxes

Chieftain
Joined
Oct 25, 2014
Messages
7
Hi,

So I'm writing a mod to turn barbarian camps into civilizations after a reasonable amount of time. New civilizations are added and act just like normal civs, but I have a couple of issues, the only game-breaking one is that it is impossible to declare war on a new civ.

Team.CanDeclareWar(TeamID team) returns false when asked a bout a new civ, but there seems to be no method that would allow me to change this. A "SetCanDeclareWar" method would have been nice.

Anyone know how to change this?

Details about adding civs:

  • I add new civs by using Game.AddPlayer
  • I make sure that the new civs are in separate teams

Other than the fact that the new civs can't be DOW'd the mod seems to mostly work fine.

Some minor issues:
  • Leader Diplo screen is missing. It appears if I save and load again. Is there a place to initialize this?
  • New Players have 0 score throughout whole game

I have taken a couple of hints from this post
 
How have you found Game.AddPlayer()? When I tried to use this to create new civs out of colonies in my Exploration Continued mod, the game became quite unstable (would crash infrequently when executing the function).
 
How have you found Game.AddPlayer()? When I tried to use this to create new civs out of colonies in my Exploration Continued mod, the game became quite unstable (would crash infrequently when executing the function).

Strange, I haven't had an issue with crashes and I must have added players more than a hundred times now. The game seems fine with it.

What essentially happens in my logic is that I delete the barb camp, add a player in an open slot and then call
Code:
Players[iNewPlayer]:InitCity(fPlot:GetX(), fPlot:GetY());
on the position where the barb camp was. But no crashes so far.
 
Don't know about the inability to declare war, but I've got a utility you might want to look into for the leaderscreen issue. Link.

Unfortunately, you will never be able to make the game load a 3D leader scene for new leaders; that code is in the graphical DLL, which is still, and likely will forever remain, closed source. However, this should be a fair substitute.
 
My guess is that it has to do with the team not the player since canDeclareWar is defined in CvTeam and all of its conditions are based on the team. Without seeing your code, I'm assuming you simply did a Player.SetTeam and assigned it an unused team, but I think you probably have to initialize that team first, maybe using AddTeam. I saw your screenshot on the other post, and the "special rule" message is just the default text for TXT_KEY_DIPLO_MAY_NOT_ATTACK_MOD which is called by LeaderHeadRoot.lua when CanDeclareWar returns false, so the scenario part of that is a bit of a red herring.
 
My guess is that it has to do with the team not the player since canDeclareWar is defined in CvTeam and all of its conditions are based on the team. Without seeing your code, I'm assuming you simply did a Player.SetTeam and assigned it an unused team, but I think you probably have to initialize that team first, maybe using AddTeam. I saw your screenshot on the other post, and the "special rule" message is just the default text for TXT_KEY_DIPLO_MAY_NOT_ATTACK_MOD which is called by LeaderHeadRoot.lua when CanDeclareWar returns false, so the scenario part of that is a bit of a red herring.


I just gave it a try but it makes no difference. It seems Team.AddTeam() is there so you can add different players to a team.

But I think you have the right idea. The newly added players also have no score so it seems that a part of the game doesn't seem to register that these new teams are there. I can't find any other command that would change it though.

I played around with some of the other commands:
  • Team.DeclareWar allows me to declare war on a newly added player, but after the peace treaty expires there is no difference.
  • Teams.SetPermanentWarPeace can set me to permanent peace (it takes away the declare war button) but setting it to permanent war does nothing


Don't know about the inability to declare war, but I've got a utility you might want to look into for the leaderscreen issue. Link.

Unfortunately, you will never be able to make the game load a 3D leader scene for new leaders; that code is in the graphical DLL, which is still, and likely will forever remain, closed source. However, this should be a fair substitute.

Thanks, will give it a try. Anything is better than a blank screen!
 
I put together a quick test with some of the code from that other thread and was able to recreate your issue exactly. What I found is that calling IsAlive() on the new player's team returns false. That would definitely keep most functions relating to that team from working properly. I have a bad feeling that calling PreGame.SetTeam while in game isn't fully initializing the new team and setting the number of alive players in that team to 1. I haven't yet found a way to initialize the team correctly.
 
Literally right after I posted this, I found something that worked: setting the team before you add the player. Below is the code I used/changed from the other thread that seems to work.

Code:
        local iNewPlayer = g_nextAvailablePlayerIndex
	g_nextAvailablePlayerID = g_nextAvailablePlayerIndex + 1
	local newCivInfo = GameInfo.Civilizations[newCivID]
	local oldPlayer = Players[iOldPlayer]
	local iTeam = iNewPlayer


	--Get the proper leader for the new civ
	local newLeaderID
	for row in GameInfo.Civilization_Leaders() do
		if newCivInfo.Type == row.CivilizationType then
			newLeaderID = GameInfoTypes[row.LeaderheadType]
			break
		end
	end
	if not newLeaderID then
		error("PlayerCivSwap: No leader for new civ type")
	end


	--Add new player here?
	print("AddPlayer")
	PreGame.SetTeam(iNewPlayer, iTeam)
	Game.AddPlayer(iNewPlayer, newLeaderID, newCivID)

	--Setup the new player in PreGame
	PreGame.SetLeaderName(iNewPlayer, GameInfo.Leaders[newLeaderID].Description)					
	PreGame.SetCivilizationDescription(iNewPlayer, newCivInfo.Description)
	PreGame.SetCivilizationShortDescription(iNewPlayer, newCivInfo.ShortDescription)
	PreGame.SetCivilizationAdjective(iNewPlayer, newCivInfo.Adjective)
	PreGame.SetPassword(iNewPlayer, "")
	PreGame.SetCivilization(iNewPlayer, newCivID)
	PreGame.SetLeaderType(iNewPlayer, newLeaderID)
	PreGame.SetHandicap(iNewPlayer, oldPlayer:GetHandicapType())
	PreGame.SetSlotStatus(iNewPlayer, SlotStatus.SS_COMPUTER)
	PreGame.SetSlotClaim(iNewPlayer, SlotClaim.SLOTCLAIM_ASSIGNED)

	print("GetSlotStatus = ", PreGame.GetSlotStatus(iNewPlayer))

	local newPlayer = Players[iNewPlayer]
	newPlayer:SetStartingPlot(oldPlayer:GetStartingPlot())
	

	print("New player team is / should be= ", newPlayer:GetTeam(), iTeam)
	print("Starting plot, old/new = ", oldPlayer:GetStartingPlot(), newPlayer:GetStartingPlot())

	local oldCapital = oldPlayer:GetCapitalCity()
	local newCity = newPlayer:InitCity(oldCapital:GetX()+3, oldCapital:GetY())
 
Literally right after I posted this, I found something that worked: setting the team before you add the player. Below is the code I used/changed from the other thread that seems to work.

It works! Amazing, thanks a lot! They also have scores now!

It seems odd to me to that you add a player which does not yet exist to a team, as opposed to creating a player and then adding it to a team, but there must be some implicit hierarchy that's not well documented.
 
Glad I could help!

Yeah, that's basically right. I figured it out by trying to find where in the DLL the team members are set, and found that AddPlayer calls CvPlayer::init which then sets the player's team membership to 1, whereas SetTeam doesn't touch that at all. So when AddPlayer was called first, init would fail to set the team membership because the player had no associated team, and SetTeam wouldn't correct that.
 
Back
Top Bottom