Browse Source

ItemEntities are now attracted by other entities with free inventory and add the carried items to them if possible

Kolja Strohm 3 years ago
parent
commit
dbdeace36e

+ 38 - 8
FactoryCraft/Dimension.cpp

@@ -28,21 +28,16 @@ void Dimension::tickEntities()
 {
     for( auto entity : *entities )
     {
-        if( zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
+        if( !entity->isRemoved() && zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
             entity->prepareTick( this );
     }
     int index = 0;
-    Array<int> removed;
     for( auto entity : *entities )
     {
-        if( zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
+        if( !entity->isRemoved() && zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
             entity->tick( this );
-        if( entity->isRemoved() )
-            removed.add( index, 0 );
         index++;
     }
-    for( int i : removed )
-        entities->remove( i );
 }
 
 void Dimension::getAddrOf( Punkt cPos, char* addr ) const
@@ -269,8 +264,43 @@ Entity* Dimension::zEntity( int id )
 {
     for( auto entity : *entities )
     {
-        if( entity->getId() == id )
+        if( !entity->isRemoved() && entity->getId() == id )
             return entity;
     }
     return 0;
+}
+
+Entity* Dimension::zNearestEntity( Framework::Vec3<float> pos, std::function<bool( Entity* )> filter )
+{
+    Entity* result = 0;
+    float sqDist = 0;
+    for( auto entity : *entities )
+    {
+        if( !entity->isRemoved() && filter( entity ) )
+        {
+            float d = pos.abstandSq( entity->getPosition() );
+            if( !result || d < sqDist )
+            {
+                result = entity;
+                sqDist = d;
+            }
+        }
+    }
+    return result;
+}
+
+void Dimension::removeEntity( int id )
+{
+    Entity* result = 0;
+    float sqDist = 0;
+    int index = 0;
+    for( auto entity : *entities )
+    {
+        if( entity->getId() == id )
+        {
+            entities->remove( index );
+            return;
+        }
+        index++;
+    }
 }

+ 2 - 0
FactoryCraft/Dimension.h

@@ -36,4 +36,6 @@ public:
     float getGravity() const;
     void removeOldChunks();
     Entity* zEntity( int id );
+    Entity* zNearestEntity( Framework::Vec3<float> pos, std::function<bool( Entity* )> filter );
+    void removeEntity( int id );
 };

+ 6 - 1
FactoryCraft/Entity.cpp

@@ -4,6 +4,8 @@
 #include "BlockType.h"
 #include "ItemSkill.h"
 #include "PlaceBlockUpdate.h"
+#include "EntityRemovedUpdate.h"
+
 
 ActionTarget::ActionTarget( Vec3<int> blockPos, Direction blockSide )
     : blockPos( blockPos ),
@@ -76,7 +78,10 @@ Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int di
 {}
 
 void Entity::onDeath()
-{}
+{
+    removed = 1;
+    Game::INSTANCE->requestWorldUpdate( new EntityRemovedUpdate( id ) );
+}
 
 void Entity::useItem( const ItemType* zType, Item* zItem )
 {

+ 27 - 0
FactoryCraft/EntityRemovedUpdate.cpp

@@ -0,0 +1,27 @@
+#include "EntityRemovedUpdate.h"
+#include "Dimension.h"
+
+
+EntityRemovedUpdate::EntityRemovedUpdate( int entityId, int dimensionId, Framework::Vec3<int> pos )
+    : WorldUpdate( EntityRemovedUpdateType::ID, dimensionId, pos, pos ),
+    entityId( entityId )
+{}
+
+EntityRemovedUpdate::~EntityRemovedUpdate()
+{}
+
+void EntityRemovedUpdate::onUpdate( Dimension* zDimension )
+{
+    zDimension->removeEntity( entityId );
+}
+
+void EntityRemovedUpdate::write( Framework::StreamWriter* zWriter )
+{
+    WorldUpdate::write( zWriter );
+    zWriter->schreibe( (char*)&entityId, 4 );
+}
+
+
+EntityRemovedUpdateType::EntityRemovedUpdateType()
+    : WorldUpdateType( ID )
+{}

+ 25 - 0
FactoryCraft/EntityRemovedUpdate.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "WorldUpdate.h"
+
+class EntityRemovedUpdate : public WorldUpdate
+{
+private:
+    int entityId;
+
+public:
+    EntityRemovedUpdate( int entityId, int dimensionId, Framework::Vec3<int> pos );
+    ~EntityRemovedUpdate();
+
+    void onUpdate( Dimension* zDimension ) override;
+    void write( Framework::StreamWriter* zWriter ) override;
+};
+
+class EntityRemovedUpdateType : WorldUpdateType
+{
+    REGISTRABLE( EntityRemovedUpdateType )
+
+protected:
+    EntityRemovedUpdateType();
+};
+REGISTER( EntityRemovedUpdateType, WorldUpdateType )

+ 2 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -109,6 +109,7 @@
     <ClInclude Include="EffectFactory.h" />
     <ClInclude Include="Entity.h" />
     <ClInclude Include="EntityChangedUpdate.h" />
+    <ClInclude Include="EntityRemovedUpdate.h" />
     <ClInclude Include="EntityType.h" />
     <ClInclude Include="FastNoiseLite.h" />
     <ClInclude Include="FastNoiseWrapper.h" />
@@ -156,6 +157,7 @@
     <ClCompile Include="DimensionGenerator.cpp" />
     <ClCompile Include="Entity.cpp" />
     <ClCompile Include="EntityChangedUpdate.cpp" />
+    <ClCompile Include="EntityRemovedUpdate.cpp" />
     <ClCompile Include="EntityType.cpp" />
     <ClCompile Include="FastNoiseWrapper.cpp" />
     <ClCompile Include="Game.cpp" />

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -198,6 +198,9 @@
     <ClInclude Include="EntityChangedUpdate.h">
       <Filter>world\update</Filter>
     </ClInclude>
+    <ClInclude Include="EntityRemovedUpdate.h">
+      <Filter>world\update</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -332,5 +335,8 @@
     <ClCompile Include="EntityChangedUpdate.cpp">
       <Filter>world\update</Filter>
     </ClCompile>
+    <ClCompile Include="EntityRemovedUpdate.cpp">
+      <Filter>world\update</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 10 - 1
FactoryCraft/Game.cpp

@@ -551,4 +551,13 @@ Entity* Game::zEntity( int id, int dimensionId ) const
     if( d )
         return d->zEntity( id );
     return 0;
-}
+}
+
+Entity* Game::zNearestEntity( int dimensionId, Framework::Vec3<float> pos, std::function<bool( Entity* )> filter )
+{
+    Dimension* d = zDimension( dimensionId );
+    if( !d )
+        return 0;
+    return d->zNearestEntity( pos, filter );
+}
+

+ 1 - 0
FactoryCraft/Game.h

@@ -99,6 +99,7 @@ public:
     int getNextEntityId();
     WorldGenerator* zGenerator() const;
     Entity* zEntity( int id, int dimensionId ) const;
+    Entity* zNearestEntity( int dimensionId, Framework::Vec3<float> pos, std::function<bool( Entity* )> filter );
 
     static Game* INSTANCE;
     static void initialize( Framework::Text name, Framework::Text worldsDir );

+ 15 - 2
FactoryCraft/Inventory.cpp

@@ -275,12 +275,12 @@ void Inventory::addSlot( ItemSlot* slot )
     cs.unlock();
 }
 
-bool Inventory::allowPullStack( ItemSlot* zSlot, Direction dir )
+bool Inventory::allowPullStack( ItemSlot* zSlot, Direction dir ) const
 {
     return pullSlotsOrder;
 }
 
-bool Inventory::allowPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int& count )
+bool Inventory::allowPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int& count ) const
 {
     return pushSlotsOrder;
 }
@@ -493,4 +493,17 @@ InventoryInteraction Inventory::interactWith( Inventory* zInventory, Direction d
 void Inventory::unsaveAddItem( ItemStack* zStack, Direction dir )
 {
     addItems( zStack, dir );
+}
+
+int Inventory::numberOfAddableItems( const ItemStack* zStack, Direction dir ) const
+{
+    int count = 0;
+    for( auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++ )
+    {
+        int maxCount = targetSlot->numberOfAddableItems( zStack, dir );
+        int allowed = maxCount;
+        if( allowPushStack( targetSlot, dir, zStack->zItem(), allowed ) )
+            count += MIN( maxCount, allowed );
+    }
+    return count;
 }

+ 3 - 2
FactoryCraft/Inventory.h

@@ -44,8 +44,8 @@ protected:
     Framework::Vec3<float> location;
     void addSlot( ItemSlot* slot );
     void localTransaction( Framework::Array< ItemSlot* >* zSourceSlots, Framework::Array< ItemSlot* >* zTargetSlots, ItemFilter* zFilter, int count );
-    virtual bool allowPullStack( ItemSlot* zSlot, Direction dir );
-    virtual bool allowPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int& count );
+    virtual bool allowPullStack( ItemSlot* zSlot, Direction dir ) const;
+    virtual bool allowPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int& count ) const;
     virtual void afterPullStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int count );
     virtual void afterPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int count );
     virtual void loadInventory( Framework::StreamReader* zReader );
@@ -57,6 +57,7 @@ public:
     virtual ~Inventory();
     InventoryInteraction interactWith( Inventory* zInventory, Direction dir );
     void unsaveAddItem( ItemStack* zStack, Direction dir );
+    int numberOfAddableItems( const ItemStack* zStack, Direction dir ) const;
 
     friend InventoryInteraction;
 };

+ 31 - 1
FactoryCraft/ItemEntity.cpp

@@ -6,7 +6,7 @@
 ItemEntity::ItemEntity( Framework::Vec3<float> location, int dimensionId, int entityId )
     : Entity( ItemEntityType::INSTANCE, location, dimensionId, entityId )
 {
-    ItemSlot* slot = new ItemSlot( __INT32_MAX__, 0, 0, 0, ANY_DIRECTION, 0 );
+    slot = new ItemSlot( __INT32_MAX__, 0, 0, 0, ANY_DIRECTION, 0 );
     addSlot( slot );
     faceOffset = { 0.f, 0.f, 0.f };
     maxHP = 10;
@@ -24,6 +24,36 @@ void ItemEntity::tick( const Dimension* zDimension )
 {
     Framework::Vec3<float> pos = location;
     // TODO: add speed to next entity with free inventory
+    Entity* zOther = Game::INSTANCE->zNearestEntity( currentDimensionId, location, [this]( Entity* zOther ) {
+        return zOther != this && zOther->numberOfAddableItems( slot->zStack(), NO_DIRECTION );
+    } );
+    bool found = 1;
+    if( zOther )
+    {
+        float d = location.abstand( zOther->getPosition() );
+        if( d < 0.5f )
+        {
+            // add items of this entity to the other entity
+            zOther->interactWith( this, NO_DIRECTION ).pullItems( slot->getNumberOfItems(), 0 );
+            if( slot->getNumberOfItems() == 0 )
+                onDeath();
+        }
+        else if( d < 3.f )
+        {
+            // accelerate towards of the other entity
+            speed += (zOther->getPosition() - location).normalize() * (20 / (d + 0.5f)) / 30.f;
+        }
+        else
+            found = 0;
+    }
+    else
+        found = 0;
+    if( !found )
+    {
+        speed -= speed / 30.f;
+        if( speed.getLength() < 0.2f )
+            speed = { 0.f, 0.f, 0.f };
+    }
     Entity::tick( zDimension );
     if( pos != location )
     {

+ 2 - 0
FactoryCraft/ItemEntity.h

@@ -7,6 +7,8 @@ class ItemEntityType;
 
 class ItemEntity : public Entity
 {
+    ItemSlot* slot;
+
 public:
     ItemEntity( Framework::Vec3<float> location, int dimensionId, int entityId );
 

+ 10 - 0
FactoryCraft/ItemSlot.cpp

@@ -97,4 +97,14 @@ bool ItemSlot::isFull() const
 int ItemSlot::getFreeSpace() const
 {
     return items ? items->getMaxSize() - items->getSize() : maxSize;
+}
+
+bool ItemSlot::isEmpty() const
+{
+    return !items;
+}
+
+int ItemSlot::getNumberOfItems() const
+{
+    return items ? items->getSize() : 0;
 }

+ 2 - 0
FactoryCraft/ItemSlot.h

@@ -27,4 +27,6 @@ public:
     int getPushPriority() const;
     bool isFull() const;
     int getFreeSpace() const;
+    bool isEmpty() const;
+    int getNumberOfItems() const;
 };

+ 2 - 1
FactoryCraft/StaticInitializerOrder.cpp

@@ -31,4 +31,5 @@ const c *c::INSTANCE = new c();
 #include "BlockChangedUpdate.h"
 #include "BlockRemovedUpdate.h"
 #include "AddEntityUpdate.h"
-#include "EntityChangedUpdate.h"
+#include "EntityChangedUpdate.h"
+#include "EntityRemovedUpdate.h"