@@ -111,14 +111,27 @@ public static Vector3 GetWorldPosition(EntityDef def, World world, BlockmapNode
111
111
if ( occupiedNodes == null ) return new Vector3 ( basePosition . x , originNode . BaseWorldAltitude , basePosition . y ) ;
112
112
113
113
// Else calculate the exact y position
114
- // Identify the lowest node of all occupied nodes.
115
- float lowestY = occupiedNodes . Min ( n => n . BaseWorldAltitude ) ;
116
- List < BlockmapNode > lowestYNodes = occupiedNodes . Where ( n => n . BaseWorldAltitude == lowestY ) . ToList ( ) ;
117
- float y = lowestY ;
114
+ float y = 0 ;
115
+ bool isInWater = false ;
116
+
117
+ // For moving characters (always 1x1, just take the center world position of the node)
118
+ if ( def . HasCompProperties < CompProperties_Movement > ( ) )
119
+ {
120
+ y = occupiedNodes . First ( ) . MeshCenterWorldPosition . y ;
121
+ isInWater = occupiedNodes . First ( ) is WaterNode ;
122
+ }
123
+
124
+ // For static objects the lowest node of all occupied nodes.
125
+ else
126
+ {
127
+ float lowestY = occupiedNodes . Min ( n => n . BaseWorldAltitude ) ;
128
+ List < BlockmapNode > lowestYNodes = occupiedNodes . Where ( n => n . BaseWorldAltitude == lowestY ) . ToList ( ) ;
129
+ y = lowestY ;
130
+ isInWater = lowestYNodes . Any ( n => n is WaterNode || ( n is GroundNode ground && ground . WaterNode != null && ground . IsCenterUnderWater ) ) ;
131
+ }
118
132
119
133
// Move position halfway below water surface if required
120
- bool placementIsInWater = lowestYNodes . Any ( n => n is WaterNode || ( n is GroundNode ground && ground . WaterNode != null && ground . IsCenterUnderWater ) ) ;
121
- if ( placementIsInWater && def . WaterBehaviour == WaterBehaviour . HalfBelowWaterSurface )
134
+ if ( isInWater && def . WaterBehaviour == WaterBehaviour . HalfBelowWaterSurface )
122
135
{
123
136
y -= ( entityHeight * World . NodeHeight ) / 2 ;
124
137
}
@@ -209,7 +222,7 @@ public static Vector2Int GetTranslatedPosition(Vector2Int position, Vector2Int d
209
222
/// <summary>
210
223
/// Spawns an entity on a random node near the given point and returns the entity instance.
211
224
/// </summary>
212
- public static Entity SpawnEntityAround ( World world , EntityDef def , Actor player , Vector2Int worldCoordinates , float standard_deviation , Direction forcedRotation = Direction . None , int maxAttempts = 1 , int requiredRoamingArea = - 1 , List < BlockmapNode > forbiddenNodes = null , string variantName = "" , bool randomMirror = false )
225
+ public static Entity SpawnEntityAround ( World world , EntityDef def , Actor player , Vector2Int worldCoordinates , float standard_deviation , Direction forcedRotation = Direction . None , int maxAttempts = 1 , int requiredRoamingArea = - 1 , List < BlockmapNode > forbiddenNodes = null , string variantName = "" , bool randomMirror = false , List < string > forbiddenTags = null )
213
226
{
214
227
if ( standard_deviation == 0f ) maxAttempts = 1 ;
215
228
int numAttempts = 0 ;
@@ -220,7 +233,7 @@ public static Entity SpawnEntityAround(World world, EntityDef def, Actor player,
220
233
Direction rotation = forcedRotation == Direction . None ? HelperFunctions . GetRandomSide ( ) : forcedRotation ;
221
234
bool isMirrored = randomMirror ? Random . value < 0.5f : false ;
222
235
223
- Entity spawnedEntity = TrySpawnEntity ( world , def , player , targetCoordinates , rotation , isMirrored , variantName , requiredRoamingArea , forbiddenNodes ) ;
236
+ Entity spawnedEntity = TrySpawnEntity ( world , def , player , targetCoordinates , rotation , isMirrored , variantName , requiredRoamingArea , forbiddenNodes , forbiddenTags ) ;
224
237
if ( spawnedEntity != null ) return spawnedEntity ;
225
238
}
226
239
@@ -231,7 +244,7 @@ public static Entity SpawnEntityAround(World world, EntityDef def, Actor player,
231
244
/// <summary>
232
245
/// Spawns an entity within a given area in the world and returns the entity instance.
233
246
/// </summary>
234
- public static Entity SpawnEntityWithin ( World world , EntityDef def , Actor player , int minX , int maxX , int minY , int maxY , Direction forcedRotation = Direction . None , int maxAttempts = 1 , int requiredRoamingArea = - 1 , List < BlockmapNode > forbiddenNodes = null , string variantName = "" , bool randomMirror = false )
247
+ public static Entity SpawnEntityWithin ( World world , EntityDef def , Actor player , int minX , int maxX , int minY , int maxY , Direction forcedRotation = Direction . None , int maxAttempts = 1 , int requiredRoamingArea = - 1 , List < BlockmapNode > forbiddenNodes = null , string variantName = "" , bool randomMirror = false , List < string > forbiddenTags = null )
235
248
{
236
249
int numAttempts = 0 ;
237
250
while ( numAttempts ++ < maxAttempts ) // Keep searching until we find a suitable position
@@ -240,7 +253,7 @@ public static Entity SpawnEntityWithin(World world, EntityDef def, Actor player,
240
253
Direction rotation = forcedRotation == Direction . None ? HelperFunctions . GetRandomSide ( ) : forcedRotation ;
241
254
bool isMirrored = randomMirror ? Random . value < 0.5f : false ;
242
255
243
- Entity spawnedEntity = TrySpawnEntity ( world , def , player , targetCoordinates , rotation , isMirrored , variantName , requiredRoamingArea , forbiddenNodes ) ;
256
+ Entity spawnedEntity = TrySpawnEntity ( world , def , player , targetCoordinates , rotation , isMirrored , variantName , requiredRoamingArea , forbiddenNodes , forbiddenTags ) ;
244
257
if ( spawnedEntity != null ) return spawnedEntity ;
245
258
}
246
259
@@ -251,12 +264,17 @@ public static Entity SpawnEntityWithin(World world, EntityDef def, Actor player,
251
264
/// <summary>
252
265
/// Tries spawning an entity on a random node on the given coordinates with all the given restrictions.
253
266
/// <br/>Returns the entity instance if successful or null of not successful.
254
- private static Entity TrySpawnEntity ( World world , EntityDef def , Actor player , Vector2Int worldCoordinates , Direction rotation , bool isMirrored , string variantName = "" , int requiredRoamingArea = - 1 , List < BlockmapNode > forbiddenNodes = null )
267
+ private static Entity TrySpawnEntity ( World world , EntityDef def , Actor player , Vector2Int worldCoordinates , Direction rotation , bool isMirrored , string variantName = "" , int requiredRoamingArea = - 1 , List < BlockmapNode > forbiddenNodes = null , List < string > forbiddenTags = null )
255
268
{
256
269
if ( ! world . IsInWorld ( worldCoordinates ) ) return null ;
257
270
258
271
BlockmapNode targetNode = world . GetNodes ( worldCoordinates ) . RandomElement ( ) ;
259
272
if ( forbiddenNodes != null && forbiddenNodes . Contains ( targetNode ) ) return null ;
273
+ if ( forbiddenTags != null && targetNode . Tags . Any ( t => forbiddenTags . Contains ( t ) ) )
274
+ {
275
+ Debug . Log ( $ "Not spawning { def . LabelCap } on { targetNode } because it has a forbidden tag") ;
276
+ return null ;
277
+ }
260
278
if ( ! world . CanSpawnEntity ( def , targetNode , rotation , isMirrored , forceHeadspaceRecalc : true ) ) return null ;
261
279
262
280
int variantIndex = 0 ;
0 commit comments