SDK-Problem: setPlotType()

kipkuhmi

Warlord
Joined
Aug 8, 2007
Messages
131
Hi everybody,

I'm trying to implement a land reclamation system where a land reclamation boat turns a coastal tile into grass land.

This is the function that actually converts sea into land:

Code:
void CvPlot::reclameLand()
{
        CvPlot* pPlot;
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;

       
        // Get the unit out of the way first

    	pUnitNode = headUnitNode();


     	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);			
		pUnitNode = nextUnitNode(pUnitNode);
            	pLoopUnit->kill(false);
        }
	

        // Now turn water into land

        setPlotType(PLOT_LAND,true,true);


        for (int iK = 0; iK < NUM_DIRECTION_TYPES; iK++)
        {

            CvPlot* pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iK));

            if (pLoopPlot != NULL)
            {
                pLoopPlot->updateSymbols();
                pLoopPlot->updateFeatureSymbol(true);
                pLoopPlot->updateSymbolDisplay();
                pLoopPlot->updateRiverSymbol(true, true);
                pLoopPlot->updateMinimapColor();
            }

            if (!pLoopPlot->isWater())
            {
	
                setArea(pLoopPlot->getArea());
            }
        }

        gDLL->getEngineIFace()->RebuildAllPlots();
        gDLL->getEngineIFace()->SetDirty(CultureBorders_DIRTY_BIT, true);
    }
}

When running this, the game keeps crashing. It must have sth to do with the units on the plot, because according to WinDbg the commands that are causing the crash are things like

CvPlot::headUnitNode()
CvArea::getNumUnits()

Does anyone have an idea? Thanks in advance.
 
This is the strangest thing ...

I have changed the code a little bit and put the main trunk into the CvUnit::kill() function. The general idea is first to get rid of the unit and then to turn the water plot into land. It all works smoothly until the "setPlotType()" command.

This is the code:

Code:
void CvUnit::kill(bool bDelay, PlayerTypes ePlayer)
{
	 [...]
	 
    bool bReclame = false;
    int iPlot_X = pPlot->getX();
    int iPlot_Y = pPlot->getY();

    if (isReclameLandUnit())
    {
        if (getGroup()->getActivityType() == ACTIVITY_RECLAME_LAND)
        {
            pPlot = plot();
            bReclame = true;
        }
    }

    

  [... unit gets deleted ...]


    if (bReclame)
    {
            if (pPlot != NULL)
            {
                pPlot->setPlotType(PLOT_LAND, true, true);

                gDLL->getEngineIFace()->RebuildPlot(pPlot->getX(), pPlot->getY(), true, true);


                pPlot->setLayoutDirty(true);
                pPlot->updateSymbols();
                pPlot->updateFeatureSymbol(true);
                pPlot->updateSymbolDisplay();
                pPlot->updateRiverSymbol(true, true);
                pPlot->updateMinimapColor();

                for (int iK = 0; iK < NUM_DIRECTION_TYPES; iK++)
                {
                    CvPlot* pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iK));

                    if (pLoopPlot != NULL)
                    {                    
                        gDLL->getEngineIFace()->RebuildPlot(pLoopPlot->getX(), pLoopPlot->getY(), true, true);
                        pLoopPlot->updateSymbols();
                        pLoopPlot->updateFeatureSymbol(true);
                        pLoopPlot->updateSymbolDisplay();
                        pLoopPlot->updateRiverSymbol(true, true);
                        pLoopPlot->updateMinimapColor();

                        pLoopPlot->setLayoutDirty(true);
                    }
                }

                gDLL->getEngineIFace()->RebuildPlot(pPlot->getX(), pPlot->getY(), true, true);
                gDLL->getEngineIFace()->RebuildAllPlots();
                GC.getGameINLINE().updatePlotGroups();
                gDLL->getEngineIFace()->SetDirty(CultureBorders_DIRTY_BIT, true);

        }
    }
}

Now I have a situation with two land reclaming boats (looking like normal work boats). You can see them in the screen shot below:

oj882o


1)
When I use the boat in the front first and the one in the back after, then the game crushes.
WinDbg tells me there's a problem at CvArea::changeUnitsPerPlot().
Within the setPlotType() routine, there's a call to "GC.getGameINLINE().recalculateAreas()", which is obviously causing the crash.

2)
When I do it the other way round, it works perfectly.

?!?
 
Sorry, I couldn't read my own hand writing there. :)

It's "changeUnitsPerPlayer()", not "changeUnitsPerPlot()"
 
I think this is just too complicated. I´m doing the same thing, and I made it this way:
First I made a new improvement and allowed the workboat to build it. Then I changed the CvEventManager.py this way:
PHP:
def onImprovementBuilt(self, argsList):
		'Improvement Built'
		iImprovement, iX, iY = argsList
###New reclamation
		pPlot = CyMap().plot(iX, iY)
		if iImprovement == gc.getInfoTypeForString('IMPROVEMENT_RECLAMATION'):
		    pPlot.setPlotType(PlotTypes.PLOT_LAND, True, True)
		    pPlot.setImprovementType(-1)
###End reclamation

		if (not self.__LOG_IMPROVEMENT):
			return
		CvUtil.pyPrint('Improvement %s was built at %d, %d'
			%(PyInfo.ImprovementInfo(iImprovement).getDescription(), iX, iY))
If you want to have a certain TerrainType set, just add the following line after pPlot.setImprovementType(-1):
PHP:
pPlot.setTerrainType (TerrainTypes(0))
This will make the plot a grass-plot, 2 is a desert. The numbers are the order of the terrain types in the TerrainInfos.xml. If you don´t do this the TerrainType is the first one from the TerrainInfos.xml.
In my eyes this is way easyer because you don´t have to compile a new dll.
You too have the DOMAIN_SEA units deleted, as well as the workboat itself. You can add a line which says that if there´s water tile nearby a new workboat is allocated on this tile. But I don´t know this line by now.:nope:
 
@deepwater

Sorry for not answering earlier. I had no time over the last weeks to look into the problem, but now I'm confident about finally having found and solved it.

The Great Wall was responsible for it. I still don't know what exactly that Wall didn't like about my land reclamation and why the crash happened only very late in the game. Yet it seems to have come down to this: when a new land tile is added to a continent, the Great Wall has to know if this is a plot where barbarians are not allowed to enter. This is automatically checked when you use CvPlot::setPlotType(), but maybe before the new plot is assigned an area ID (so the Great Wall doesn't know where to put the new plot, that's my guess).

Whatever, I added an exception handling, so the crash is gone. I hope.

Thanks for your advice, anyway. Using the new plot as some kind of phantom improvement is a good idea. I added it to my code. Not in Python, however (I feel more comfortable in C++).
 
Back
Top Bottom