Announcement

Collapse
No announcement yet.

Limiting City placement/terrain specific cities

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Limiting City placement/terrain specific cities

    This has probably been asked before but...

    How do I make it so cities can only be built on grassland and plains tiles.

    I've seen that I can restrict it to land and sea, how do I get it for specific tiles...

    On top of thatcan I have later game settlers build on other specific terrain?

    how do I get sea cities look different than normal cities?

    I'd like to eventually have unique looking desert cities, arctic cities etc for my mod.

    thanks....
    Formerly known as "E" on Apolyton

    See me at Civfanatics.com

  • #2
    Re: Limiting City placement/terrain specific cities

    Originally posted by E
    How do I make it so cities can only be built on grassland and plains tiles.

    I've seen that I can restrict it to land and sea, how do I get it for specific tiles...
    By using slic, that is triggered on the Settle events. And prevents the events from beeing executed of course if the conditions are met. The only problem is that the AI might not handle it well, or you put it under slic control. Conditions fro preventing it from being executed are the location's terrain types.

    Originally posted by E
    On top of thatcan I have later game settlers build on other specific terrain?
    Then add another condition that is unit specific.

    Originally posted by E
    how do I get sea cities look different than normal cities?
    By using the Apolytonm edition of CTP2.

    Originally posted by E
    I'd like to eventually have unique looking desert cities, arctic cities etc for my mod.
    Also another thing that is hard encoded and can only be changed in the source code.

    -Martin
    Civ2 military advisor: "No complaints, Sir!"

    Comment


    • #3
      I guess it might be easier to see how the code hands settle-land and create settle grass, or settle plains instead of building a big slic...

      but looking at units.txt It could be podssible to have terrain specific cities if I could make certain settlers settle on certain tiles...

      I found this in unit.cpp

      Code:
      BOOL Unit::CanSettle(const MapPoint &pos) const
      {
          return GetData()->CanSettle(pos); 
      } 
      
      BOOL Unit::IsSettleLand() const
      {
          return GetDBRec()->GetSettleLand(); 
      } 
      
      BOOL Unit::IsSettleMountain() const
      {
          return GetDBRec()->GetSettleMountain(); 
      } 
      
      BOOL Unit::IsSettleWater() const
      {
          return GetDBRec()->GetSettleWater(); 
      }

      and found this in unitdata.cpp

      Code:
      BOOL UDUnitTypeCanSettle(sint32 unit_type, const MapPoint &pos) 
      
      { 
        	sint32 searching = TRUE;    
      	const UnitRecord *rec = g_theUnitDB->Get(unit_type);   
        	sint32 t = rec->GetSettleCityTypeIndex();
      
      	if (t < 0) {
      		return FALSE; 
      	}
      
      	if (g_theUnitDB->Get(t)->GetHasPopAndCanBuild() == FALSE) {
      		return FALSE; 
      	}
      
      	if (g_theWorld->HasCity(pos)) 
      		return FALSE; 
      
      	if (rec->GetSettleLand() && g_theWorld->IsLand(pos))
      		searching = FALSE; 
      	else if (rec->GetSettleMountain() && g_theWorld->IsMountain(pos))
      		searching = FALSE; 
      	else if (rec->GetSettleWater() && g_theWorld->IsWater(pos))
      		searching = FALSE; 
      	else if (rec->GetSettleSpace() && g_theWorld->IsSpace(pos))
      		searching = FALSE; 
           
      	if (searching) 
      		return FALSE; 
      
          return TRUE; 
      }
      and in citydata.cpp
      Code:
      	if(!rec->GetMovementTypeLand() && !rec->GetMovementTypeTrade() && !rec->GetIsTrader()) {
      		if(g_theWorld->IsWater(pos.x, pos.y) && rec->GetSeaCityCanBuild()) {
      			
      			
      			return TRUE;
      		}
      		
      		if((g_theWorld->IsLand(pos.x, pos.y) || 
      			g_theWorld->IsMountain(pos.x, pos.y)) &&
      			rec->GetLandCityCanBuild()) {
      			
      			return TRUE;
      		}
      		
      		
      		if(rec->GetMovementTypeSea() || rec->GetMovementTypeShallowWater()) {
      			
      			if(g_theWorld->IsNextToWater(pos.x, pos.y)) {
      				return TRUE;
      			}
      			
      			return FALSE;
      		} else if(rec->GetMovementTypeAir()) {
      			return TRUE;
      		}
      		return FALSE;
      	}
      
      	
      	return TRUE;
      }
      I think I'm learning my way around the code. And I think like your tutorial on SLIC I need to add something here in wrlEnv.cpp

      Code:
      sint32 World::EnvIsLand(const uint32 env) const
      {
      	return ((env & k_MASK_ENV_MOVEMENT_TYPE) & k_BIT_MOVEMENT_TYPE_LAND) != 0; 
      }
      
      sint32 World::IsLand(const MapPoint &pos) const
      
      {
      	return EnvIsLand(GetCell(pos)->m_env);
      
      }
      
      sint32 World::IsLand(const sint32 x, const sint32 y) const
      
      { 
      	Assert (m_isYwrap ? (-k_MAP_WRAPAROUND < y) : 0 <= y); 
      	Assert (m_isYwrap ? (y < (m_size.y + k_MAP_WRAPAROUND)) : y < m_size.y); 
      	
      	return EnvIsLand(m_map[x][y]->m_env);


      I know I'm an annoying amateur, but I'm thinking it is here we could add terrain specific settle spots. I'd like to find some little code to practice on first but it looks like everything requires a lot of work ...I was going to add a IsOpenLand type for plains and grasslands, but I wanted to check in first, don't want to screw up the code.
      Last edited by Ekmek; January 13, 2005, 14:17.
      Formerly known as "E" on Apolyton

      See me at Civfanatics.com

      Comment


      • #4
        The better idea is to make it terrain specific rather than class specific. It should depent on the terrain records from the database. To modify the text files according to units should be the easiest task as these files are generated automaticly by dbgen.

        You should take a look into the *.cdb files. Oh and of course I don't tell you were you can find them, because you should already be familiar with the builtin windows file search engine.

        The second problem is to make CTP2 use the new stuff and of course to make it backwards compartible. But to that when you have modified the unit.txt.

        -Martin
        Civ2 military advisor: "No complaints, Sir!"

        Comment


        • #5
          Thanks Martin. Looking at the way the world.h used it and trying to follow the links for SettleLand and is Land. It looks like t identifies everything by MovementType.

          The terrain.txt requires a field that is Movementtype and I think it is there that things are defined as land or sea. I'm thinking of just adding more MovementType based on tile names (plains, grassland, etc) plus Extra 1 to 10 (for modders).

          I think Settle:Land loks for MovementType:Land so if I change things to have new Movement Types than it might work. Of course for grassland tiles I'll have to have Movement Type:Land and Movementtype: Grass and update the txt for a later release (like you said easiest part).


          I'll mess with this probably this weekend (and the SLIC stuff too) I just hope the more professional programmers, like yourself, wil be available to check my work.

          THANKS!
          Formerly known as "E" on Apolyton

          See me at Civfanatics.com

          Comment


          • #6
            Originally posted by E
            The terrain.txt requires a field that is Movementtype and I think it is there that things are defined as land or sea. I'm thinking of just adding more MovementType based on tile names (plains, grassland, etc) plus Extra 1 to 10 (for modders).

            I think Settle:Land loks for MovementType:Land so if I change things to have new Movement Types than it might work. Of course for grassland tiles I'll have to have Movement Type:Land and Movementtype: Grass and update the txt for a later release (like you said easiest part).
            So you really like to force every modder to change the source code if he wants to add a new terrain? Actual I meant the movent type should be replaced by terrain type. And terrain type is determined by the entries you have in your terrain database, the actual database records no hard encoded builtin stuff.

            -Martin
            Civ2 military advisor: "No complaints, Sir!"

            Comment


            • #7
              Ahhhhhhhhh!

              Just have it look elsewhere, right? Just have it check terraintype then make the unit.txt have settle:grassland etc for each settler etc.

              Ok, I'll take a look. I guess as a side benefit it could make some more unique units like Jungle guerrillas, desert camels...
              Formerly known as "E" on Apolyton

              See me at Civfanatics.com

              Comment


              • #8
                Actual I thought of something like this:

                Code:
                   CantBuildOn TERRAIN_BROWN_MOUNTAIN
                   CantBuildOn TERRAIN_GLACIER
                   CantBuildOn TERRAIN_MOUNTAIN
                   CantBuildOn TERRAIN_TUNDRA
                   CantBuildOn TERRAIN_WATER_BEACH
                   CantBuildOn TERRAIN_WATER_DEEP
                   CantBuildOn TERRAIN_WATER_RIFT
                   CantBuildOn TERRAIN_WATER_SHALLOW
                   CantBuildOn TERRAIN_WATER_SHELF
                   CantBuildOn TERRAIN_WATER_TRENCH
                   CantBuildOn TERRAIN_WATER_VOLCANO
                   CantBuildOn TERRAIN_WHITE_HILL
                   CantBuildOn TERRAIN_WHITE_MOUNTAIN
                This is from tileimp.txt, of course it should be something like CanSettleOn or CantSettleOn instead of CantBuildOn and of course this would go into the settler unit records.

                -Martin
                Civ2 military advisor: "No complaints, Sir!"

                Comment


                • #9
                  I found this in terrainimprovementrecord.cpp

                  Code:
                  sint32 TerrainImprovementRecord::GetCantBuildOnIndex(sint32 index) const
                  {
                      Assert(index >= 0);
                      Assert(index < m_numCantBuildOn);
                      if((index < 0) || (index >= m_numCantBuildOn)) {
                          return 0;
                      }
                      return m_CantBuildOn[index];
                  }
                  
                  const TerrainRecord *TerrainImprovementRecord::GetCantBuildOn(sint32 index) const
                  {
                      Assert(index >= 0);
                      Assert(index < m_numCantBuildOn);
                      if((index < 0) || (index >= m_numCantBuildOn)) {
                          return 0;
                      }
                      return g_theTerrainDB->Get(m_CantBuildOn[index]);
                  }
                  theoretically I should be able to port this into unitdata.cpp in the settle areas right?
                  Formerly known as "E" on Apolyton

                  See me at Civfanatics.com

                  Comment


                  • #10
                    Originally posted by E
                    theoretically I should be able to port this into unitdata.cpp in the settle areas right?
                    Of course you should use the equivalent in UmitRecord you have still to create and you do that by modifying one of these *.ccdb files.

                    -Martin
                    Civ2 military advisor: "No complaints, Sir!"

                    Comment


                    • #11
                      If found this in terrain CDB. I think I could add all my terrain types here, but I think that will create the problem that modders have to mod the code. So should I copy the terrain movement types into settle types ? I'm kind of lost at how to link it to a terrain name, but I'll keep digging.

                      Code:
                       unit.cdb
                      	Bits Settle { 
                      		Land,
                      		Water,
                      		Mountain,
                      		Space
                      probably add a can'tsettle?

                      Code:
                       terrain.cdb
                      	Bits MovementType {
                      		Land,
                      		Sea,
                      		Air,
                      		Mountain,
                      		Trade,
                      		ShallowWater,
                      		Space
                      	}		
                      
                      	# Map record to the pseudo-enum (TERRAIN_*, not an enum any more)
                      	Bits InternalType {
                      		Forest,
                      		Plains,
                      		Tundra,
                      		Glacier,
                      		Grassland,
                      		Desert,
                      		Swamp,
                      		Jungle,
                      		Mountain,
                      		Hill,
                      		WaterShallow,
                      		WaterDeep,
                      		WaterVolcano,
                      		WaterBeach,
                      		WaterShelf,
                      		WaterTrench,
                      		WaterRift,
                      		Dead,
                      		BrownHill,
                      		BrownMountain,
                      		WhiteHill,
                      		WhiteMountain,
                      		WaterKelp,
                      		WaterReef,
                      		Special
                      	}
                      
                      	# For gfx system use
                      	Int TilesetIndex
                      }
                      Code:
                       terrimprove.cdb
                      Record Terrain[] CantBuildOn

                      Or should I just copy the terrimprove cantbuild on and rename it and put it into the unit.cdb?
                      Formerly known as "E" on Apolyton

                      See me at Civfanatics.com

                      Comment


                      • #12
                        Originally posted by E
                        Code:
                         terrimprove.cdb
                        Record Terrain[] CantBuildOn

                        Or should I just copy the terrimprove cantbuild on and rename it and put it into the unit.cdb?
                        Actual this is the one I have in mind, you have here a list of terrain, and I think we should go for a CanSettleOn flag. And of course it should be backwards compartible, if the unit does not have any CanSettleOn entry it should go for the old terrain class thingy stuff.

                        -Martin
                        Civ2 military advisor: "No complaints, Sir!"

                        Comment


                        • #13
                          martin,

                          Question #1
                          I added CanSettleOn into Unit.cdb assuming that its almost a mirror copy however as I went into UnitRecord.h (at the top it says don't edit it, does that still apply?) I was taking stuff from terrimproverecord.h then realized that this code should start copying the normal settle code to allow city settling (as opposed to not building tiles)

                          I think its at this part of the code that I should start copying:
                          Code:
                           from newdb/UnitRecord.h
                           // Settle flag group
                              uint32           GetSettle() const { return m_Settle; }
                              bool             GetSettleLand() const { return (m_Settle & k_Unit_Settle_Land_Bit) != 0; }
                              bool             GetSettleWater() const { return (m_Settle & k_Unit_Settle_Water_Bit) != 0; }
                              bool             GetSettleMountain() const { return (m_Settle & k_Unit_Settle_Mountain_Bit) != 0; }
                              bool             GetSettleSpace() const { return (m_Settle & k_Unit_Settle_Space_Bit) != 0; }
                              // End Settle flag group
                              //
                              sint32           GetSettleCityTypeIndex() const { return m_SettleCityType; }
                              const UnitRecord *GetSettleCityType() const;
                              sint32           GetSettleSize() const { return m_SettleSize; }
                              sint32           GetSettleBuildingIndex(sint32 index) const;
                              const BuildingRecord *GetSettleBuilding(sint32 index) const;
                              sint32           GetNumSettleBuilding() const { return m_numSettleBuilding;}
                              bool             GetSpaceLaunch() const { return (m_flags0 & k_Unit_SpaceLaunch_Bit) != 0; }
                              bool             GetSpaceLaunch(sint32 &value) const {
                                                   if((m_flags0 & k_Unit_SpaceLaunch_Bit) == 0) return false;
                                                   value = m_SpaceLaunchValue;
                                                   return true;
                          I could just do a name replace but I'm thinking I have to put a reference to the index where the GetSettleLand stuff is. Something like:

                          Code:
                          sint32           GetCanSettleOnIndex(sint32 index) const;
                              const TerrainRecord *GetCanSettleOn(sint32 index) const;
                              sint32           GetNumCanSettleOn() const { return m_numCantBuildOn;}
                          I'm thinking I should either add the above code in the settle section or copy the settle section and then just replace.


                          Question #2
                          I know I have to link it to settle some how and since its Can instead of Cant I figure I have to change the true\false statement.

                          Code:
                          		for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
                          			if(rec->GetCantBuildOnIndex(i) == cell->GetTerrain()) {
                          				return FALSE;

                          I thinking I add it like this:

                          Code:
                           from UnitData.cpp
                          BOOL UDUnitTypeCanSettle(sint32 unit_type, const MapPoint &pos) 
                          
                          { 
                            	sint32 searching = TRUE;    
                          	const UnitRecord *rec = g_theUnitDB->Get(unit_type);   
                            	sint32 t = rec->GetSettleCityTypeIndex();
                          
                          	if (t < 0) {
                          		return FALSE; 
                          	}
                          
                          	[b]for(i = 0; i < rec->GetNumCanSettleOn(); i++) {
                          			if(rec->GetCanSettleOnIndex(i) == cell->GetTerrain()) {
                          				return FALSE;[/b]
                          
                          	if (g_theUnitDB->Get(t)->GetHasPopAndCanBuild() == FALSE) {
                          		return FALSE; 
                          	}
                          
                          	if (g_theWorld->HasCity(pos)) 
                          		return FALSE; 
                          
                          	if (rec->GetSettleLand() && g_theWorld->IsLand(pos))
                          		searching = FALSE; 
                          	else if (rec->GetSettleMountain() && g_theWorld->IsMountain(pos))
                          		searching = FALSE; 
                          	else if (rec->GetSettleWater() && g_theWorld->IsWater(pos))
                          		searching = FALSE; 
                          	else if (rec->GetSettleSpace() && g_theWorld->IsSpace(pos))
                          		searching = FALSE; 
                               
                          	if (searching) 
                          		return FALSE; 
                          
                              return TRUE; 
                          }


                          I think this is a small problem but if anyone could provide a recommendation I'd appreciate it.
                          Last edited by Ekmek; January 15, 2005, 15:48.
                          Formerly known as "E" on Apolyton

                          See me at Civfanatics.com

                          Comment


                          • #14
                            Originally posted by E
                            martin,

                            Question #1
                            I added CanSettleOn into Unit.cdb assuming that its almost a mirror copy however as I went into UnitRecord.h (at the top it says don't edit it, does that still apply?) I was taking stuff from terrimproverecord.h then realized that this code should start copying the normal settle code to allow city settling (as opposed to not building tiles)
                            You don't touch any of these *Record.* files they are generated by dbgen automaticly, that is the sense of these *.cdb files.


                            Originally posted by E
                            Question #2
                            I know I have to link it to settle some how and since its Can instead of Cant I figure I have to change the true\false statement.

                            Code:
                            		for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
                            			if(rec->GetCantBuildOnIndex(i) == cell->GetTerrain()) {
                            				return FALSE;
                            As the function you are in should return whether a the given unit can settle at the current location it should return TRUE. However you should close all your blocks you open with a brace '{'.

                            I thinking I add it like this:

                            Originally posted by E
                            Code:
                             from UnitData.cpp
                            BOOL UDUnitTypeCanSettle(sint32 unit_type, const MapPoint &pos) 
                            
                            { 
                              	sint32 searching = TRUE;    
                            	const UnitRecord *rec = g_theUnitDB->Get(unit_type);   
                              	sint32 t = rec->GetSettleCityTypeIndex();
                            
                            	if (t < 0) {
                            		return FALSE; 
                            	}
                            
                            	[b]for(i = 0; i < rec->GetNumCanSettleOn(); i++) {
                            			if(rec->GetCanSettleOnIndex(i) == cell->GetTerrain()) {
                            				return FALSE;[/b]
                            
                            	if (g_theUnitDB->Get(t)->GetHasPopAndCanBuild() == FALSE) {
                            		return FALSE; 
                            	}
                            
                            	if (g_theWorld->HasCity(pos)) 
                            		return FALSE; 
                            
                            	if (rec->GetSettleLand() && g_theWorld->IsLand(pos))
                            		searching = FALSE; 
                            	else if (rec->GetSettleMountain() && g_theWorld->IsMountain(pos))
                            		searching = FALSE; 
                            	else if (rec->GetSettleWater() && g_theWorld->IsWater(pos))
                            		searching = FALSE; 
                            	else if (rec->GetSettleSpace() && g_theWorld->IsSpace(pos))
                            		searching = FALSE; 
                                 
                            	if (searching) 
                            		return FALSE; 
                            
                                return TRUE; 
                            }
                            That's actual not a good idea even if you add the closing braces and make the new code return TRUE. You would still allow, then to settle in cities with your new code. However for the sake of backwards compartibility you should put the code into a if-else instructions. The new code comes under if condition, the condition is whether the CanSettleOn array as more than zero members, meaning it exists. Otherwise the else block is executed that contains the old code with the GetSettleLand etc. However this searching variable is superfluous all the code related to it can be deleted, when this variable is set to FALSE, the function should return TRUE.

                            -Martin
                            Civ2 military advisor: "No complaints, Sir!"

                            Comment


                            • #15
                              I guess this should be moved to the source code forum but anyways...

                              Originally posted by Martin Gühmann

                              That's actual not a good idea even if you add the closing braces and make the new code return TRUE. You would still allow, then to settle in cities with your new code. However for the sake of backwards compartibility you should put the code into a if-else instructions. The new code comes under if condition, the condition is whether the CanSettleOn array as more than zero members, meaning it exists. Otherwise the else block is executed that contains the old code with the GetSettleLand etc. However this searching variable is superfluous all the code related to it can be deleted, when this variable is set to FALSE, the function should return TRUE.

                              -Martin
                              Martin, thanks for taking the time to help me with this. I really hope yu don't feel anoyed because I'm really learning a lot. and if anything if I grasp enough of this I'll stop pestering you with requests

                              Having said that, I think understand what you said and I made these code adjustments...


                              Code:
                               from UnitData.cpp
                              BOOL UDUnitTypeCanSettle(sint32 unit_type, const MapPoint &pos) 
                              
                              { 
                                	sint32 searching = TRUE;    
                              	const UnitRecord *rec = g_theUnitDB->Get(unit_type);   
                                	sint32 t = rec->GetSettleCityTypeIndex();
                              
                              	if (t < 0) {
                              		return FALSE; 
                              	}
                              
                              
                              	if (g_theUnitDB->Get(t)->GetHasPopAndCanBuild() == FALSE) {
                              		return FALSE; 
                              	}
                              
                              	if (g_theWorld->HasCity(pos)) 
                              		return FALSE; 
                              [b]
                              	if(rec->GetCanSettleOnIndex() == cell->GetTerrain()) { 
                              				return TRUE;
                                             } [/b]
                              
                              	else if (rec->GetSettleLand() && g_theWorld->IsLand(pos))
                              		searching = FALSE; 
                              	else if (rec->GetSettleMountain() && g_theWorld->IsMountain(pos))
                              		searching = FALSE; 
                              	else if (rec->GetSettleWater() && g_theWorld->IsWater(pos))
                              		searching = FALSE; 
                              	else if (rec->GetSettleSpace() && g_theWorld->IsSpace(pos))
                              		searching = FALSE; 
                                   
                              	if (searching) 
                              		return FALSE; 
                              
                                  return TRUE; 
                              }

                              Am I getting closer? and I didn't see any other references to Settle and CantBuildOn so I think this is the only place in the code to do this.

                              Seriously, thanks for the help.
                              Formerly known as "E" on Apolyton

                              See me at Civfanatics.com

                              Comment

                              Working...
                              X