Browse Source

add eatable wheat plant

Kolja Strohm 2 years ago
parent
commit
5a7d42021f

+ 13 - 0
FactoryCraft/Block.cpp

@@ -305,6 +305,19 @@ Block* Block::zNeighbor(Direction dir) const
     return zNeighbours[getDirectionIndex(dir)];
 }
 
+void Block::updateModel(ModelInfo info) const
+{
+    NetworkMessage* changeMsg = new NetworkMessage();
+    changeMsg->addressBlock(this);
+    InMemoryBuffer buffer;
+    info.writeTo(&buffer);
+    char* msg = new char[(int)buffer.getSize() + 1];
+    msg[0] = 1; // hmodel change
+    buffer.lese(msg + 1, (int)buffer.getSize());
+    changeMsg->setMessage(msg, (int)buffer.getSize() + 1);
+    Game::INSTANCE->broadcastMessage(changeMsg);
+}
+
 BasicBlockItem::BasicBlockItem(
     int itemTypeId, int blockTypeId, const char* name)
     : Item(itemTypeId, name)

+ 1 - 0
FactoryCraft/Block.h

@@ -112,6 +112,7 @@ public:
     const unsigned char* getLightEmisionColor() const;
     virtual void filterPassingLight(unsigned char rgb[3]) const;
     Block* zNeighbor(Direction dir) const;
+    void updateModel(ModelInfo info) const;
 
     friend BlockType;
 };

+ 3 - 1
FactoryCraft/BlockType.h

@@ -38,8 +38,10 @@ public:
     static const int TORCH = 21;
     static const int GRASS = 22;
     static const int FARMLAND = 23;
+    static const int WHEAT_SEED = 24;
+    static const int WHEAT = 25;
 
-    static const int MAX_VALUE = 23;
+    static const int MAX_VALUE = 25;
 };
 
 class BlockType : public virtual Framework::ReferenceCounter

+ 2 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -158,6 +158,7 @@
     <ClInclude Include="TickWorker.h" />
     <ClInclude Include="TreeSeblingBlock.h" />
     <ClInclude Include="TreeTemplate.h" />
+    <ClInclude Include="GrowingPlant.h" />
     <ClInclude Include="WorldGenerator.h" />
     <ClInclude Include="WorldLoader.h" />
     <ClInclude Include="WorldUpdate.h" />
@@ -221,6 +222,7 @@
     <ClCompile Include="TickWorker.cpp" />
     <ClCompile Include="TreeSeblingBlock.cpp" />
     <ClCompile Include="TreeTemplate.cpp" />
+    <ClCompile Include="GrowingPlant.cpp" />
     <ClCompile Include="WorldGenerator.cpp" />
     <ClCompile Include="WorldLoader.cpp" />
     <ClCompile Include="WorldUpdate.cpp" />

+ 9 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -70,6 +70,9 @@
     <Filter Include="inventory\items\tools">
       <UniqueIdentifier>{1dafa00c-6eca-4e1f-aeda-ba7c1b95265d}</UniqueIdentifier>
     </Filter>
+    <Filter Include="world\blocks\plants">
+      <UniqueIdentifier>{4d1a59d1-2b8c-447f-b1fb-ae6e07b60983}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -270,6 +273,9 @@
     <ClInclude Include="BasicTool.h">
       <Filter>inventory\items\tools</Filter>
     </ClInclude>
+    <ClInclude Include="GrowingPlant.h">
+      <Filter>world\blocks\plants</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -455,5 +461,8 @@
     <ClCompile Include="BasicTool.cpp">
       <Filter>inventory\items\tools</Filter>
     </ClCompile>
+    <ClCompile Include="GrowingPlant.cpp">
+      <Filter>world\blocks\plants</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 1 - 0
FactoryCraft/Game.cpp

@@ -839,6 +839,7 @@ void Game::save() const
     d.close();
     for (auto dim : *dimensions)
         dim->save(path);
+    std::cout << "Game was saved\n";
 }
 
 void Game::requestStop()

+ 23 - 1
FactoryCraft/Grass.cpp

@@ -1,6 +1,8 @@
 #include "Grass.h"
 
+#include "AddEntityUpdate.h"
 #include "Game.h"
+#include "ItemEntity.h"
 
 GrassBlock::GrassBlock(
     int typeId, const ItemType* zTool, Framework::Vec3<int> pos)
@@ -33,7 +35,27 @@ void GrassBlock::onDestroy()
                             pos, getDimensionId()));
             }
         }
-        // TODO: calculate chance for dropping wheat seeds
+        if ((double)rand() / RAND_MAX < 0.1)
+        {
+            ItemStack* spawnedItems = StaticRegistry<ItemType>::INSTANCE
+                                          .zElement(ItemTypeEnum::WHEAT_SEED)
+                                          ->createItemStack(1);
+            if (spawnedItems)
+            {
+                ItemEntity* itemEntity
+                    = (ItemEntity*)StaticRegistry<EntityType>::INSTANCE
+                          .zElement(EntityTypeEnum::ITEM)
+                          ->createEntity(
+                              location
+                                  + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
+                              getDimensionId(),
+                              Game::INSTANCE->getNextEntityId());
+                itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION);
+                spawnedItems->release();
+                Game::INSTANCE->requestWorldUpdate(
+                    new AddEntityUpdate(itemEntity, getDimensionId()));
+            }
+        }
         for (MultiblockStructure* structure : structures)
             structure->onBlockRemoved(this);
         Game::INSTANCE->zDimension(getDimensionId())

+ 178 - 0
FactoryCraft/GrowingPlant.cpp

@@ -0,0 +1,178 @@
+#include "GrowingPlant.h"
+
+#include "Game.h"
+
+GrowthState::GrowthState(float percentage, ModelInfo model)
+    : percentage(percentage),
+      model(model)
+{}
+
+GrowthState::GrowthState()
+    : percentage(1),
+      model("", "", 0)
+{}
+
+GrowthState& GrowthState::operator=(const GrowthState& right)
+{
+    percentage = right.percentage;
+    model = ModelInfo(right.model);
+    return *this;
+}
+
+GrowingPlantBlock::GrowingPlantBlock(int typeId,
+    const ItemType* zTool,
+    Framework::Vec3<int> pos,
+    int maxTicks,
+    const char* name,
+    int blockTypeAfterGrowth)
+    : Block(typeId, zTool, pos, 0),
+      seblingTicks(0),
+      seblingTicksMax(maxTicks),
+      name(name),
+      states(),
+      blockTypeAfterGrowth(blockTypeAfterGrowth),
+      plantSpawned(0),
+      modelUpdated(0)
+{
+    tickSource = 1;
+}
+
+bool GrowingPlantBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
+{
+    float beforePercentage = seblingTicks / (float)seblingTicksMax;
+    seblingTicks += (float)numTicks;
+    if ((int)(seblingTicks / (float)seblingTicksMax * 100.f)
+        != (int)(beforePercentage * 100.f))
+    {
+        Game::INSTANCE->blockTargetChanged(this);
+    }
+    for (const GrowthState& state : states)
+    {
+        if ((state.percentage > beforePercentage || !modelUpdated)
+            && state.percentage <= seblingTicks / (float)seblingTicksMax)
+        {
+            updateModel(state.model);
+            modelUpdated = 1;
+        }
+    }
+    return 1;
+}
+
+void GrowingPlantBlock::onPostTick()
+{
+    if (seblingTicks >= (float)seblingTicksMax && !plantSpawned)
+    {
+        plantSpawned = 1;
+        Game::INSTANCE->doLater([this]() {
+            Game::INSTANCE->zDimension(getDimensionId())
+                ->placeBlock(getPos(), blockTypeAfterGrowth);
+        });
+    }
+}
+
+Framework::Text GrowingPlantBlock::getTargetUIML()
+{
+    return Text("<targetInfo><text width=\"auto\" height=\"auto\">") + name
+         + "\n" + "Growth: "
+         + Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
+         + "%</text></targetInfo>";
+}
+
+GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState state)
+{
+    int index = 0;
+    for (const GrowthState& s : states)
+    {
+        if (s.percentage > state.percentage)
+        {
+            states.add(state, index);
+            return this;
+        }
+        index++;
+    }
+    states.add(state);
+    return this;
+}
+
+GrowingPlantlockType::GrowingPlantlockType(int typeId,
+    ModelInfo model,
+    const char* name,
+    int blockTypeAfterGrowth,
+    const char* readableName,
+    int ticksNeeded)
+    : BlockType(typeId, 0, model, 1, 10.f, 0, name),
+      transparent(1),
+      passable(1),
+      hardness(0.1f),
+      zTool(0),
+      speedModifier(0.3f),
+      interactable(1),
+      states(),
+      blockTypeAfterGrowth(blockTypeAfterGrowth),
+      readableName(readableName),
+      ticksNeeded(ticksNeeded)
+{}
+
+GrowingPlantlockType* GrowingPlantlockType::setHardness(float hardness)
+{
+    this->hardness = hardness;
+    return this;
+}
+
+GrowingPlantlockType* GrowingPlantlockType::addGrowthState(
+    float growthPercentage, ModelInfo model)
+{
+    states.add(GrowthState(growthPercentage, model));
+    return this;
+}
+
+void GrowingPlantlockType::createSuperBlock(Block* zBlock, Item* zItem) const
+{
+    GrowingPlantlockType* block = dynamic_cast<GrowingPlantlockType*>(zBlock);
+    if (!block)
+        throw "TreeSeblingBlockType::createSuperBlock was called with a block "
+              "witch is not an instance of TreeSeblingBlock";
+    block->transparent = transparent;
+    block->passable = passable;
+    block->hardness = hardness;
+    block->zTool = zTool;
+    block->speedModifier = speedModifier;
+    block->interactable = interactable;
+    BlockType::createSuperBlock(zBlock, zItem);
+}
+
+void GrowingPlantlockType::loadSuperBlock(
+    Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
+{
+    BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
+    GrowingPlantBlock* block = dynamic_cast<GrowingPlantBlock*>(zBlock);
+    zReader->lese((char*)&block->seblingTicks, 4);
+}
+
+void GrowingPlantlockType::saveSuperBlock(
+    Block* zBlock, Framework::StreamWriter* zWriter) const
+{
+    BlockType::saveSuperBlock(zBlock, zWriter);
+    GrowingPlantBlock* block = dynamic_cast<GrowingPlantBlock*>(zBlock);
+    zWriter->schreibe((char*)&block->seblingTicks, 4);
+}
+
+Item* GrowingPlantlockType::createItem() const
+{
+    return 0;
+}
+
+Block* GrowingPlantlockType::createBlock(Framework::Vec3<int> position) const
+{
+    GrowingPlantBlock* block = new GrowingPlantBlock(getId(),
+        zTool,
+        position,
+        ticksNeeded,
+        readableName,
+        blockTypeAfterGrowth);
+    for (const GrowthState& state : states)
+    {
+        block->addGrowthState(state);
+    }
+    return block;
+}

+ 82 - 0
FactoryCraft/GrowingPlant.h

@@ -0,0 +1,82 @@
+#pragma once
+
+#include "Block.h"
+
+
+class GrowingPlantlockType;
+
+struct GrowthState
+{
+    GrowthState(float percentage, ModelInfo model);
+    GrowthState();
+
+    GrowthState& operator=(const GrowthState& right);
+
+    float percentage;
+    ModelInfo model;
+};
+
+class GrowingPlantBlock : public Block
+{
+private:
+    float seblingTicks;
+    int seblingTicksMax;
+    const char* name;
+    Framework::Array<GrowthState> states;
+    int blockTypeAfterGrowth;
+    bool plantSpawned;
+    bool modelUpdated;
+
+public:
+    GrowingPlantBlock(
+        int typeId,
+        const ItemType* zTool,
+                      Framework::Vec3<int> pos,
+                      int maxTicks,
+                      const char* name,
+                      int blockTypeAfterGrowth);
+    virtual bool onTick(
+        TickQueue* zQueue, int numTicks, bool& blocked) override;
+    virtual void onPostTick() override;
+    virtual Framework::Text getTargetUIML();
+    GrowingPlantBlock* addGrowthState(GrowthState state);
+
+    friend GrowingPlantlockType;
+};
+
+class GrowingPlantlockType : public BlockType
+{
+private:
+    bool transparent;
+    bool passable;
+    float hardness;
+    const ItemType* zTool;
+    float speedModifier;
+    bool interactable;
+    Framework::Array<GrowthState> states;
+    int blockTypeAfterGrowth;
+    const char* readableName;
+    int ticksNeeded;
+
+protected:
+    virtual void loadSuperBlock(Block* zBlock,
+        Framework::StreamReader* zReader,
+        int dimensionId) const override;
+    void createSuperBlock(
+        Block* zBlock, Item* zItem) const override;
+    virtual void saveSuperBlock(
+        Block* zBlock, Framework::StreamWriter* zWriter) const override;
+    virtual Item* createItem() const override;
+    virtual Block* createBlock(Framework::Vec3<int> position) const override;
+
+public:
+    GrowingPlantlockType(int typeId,
+        ModelInfo model,
+        const char* name,
+        int blockTypeAfterGrowth,
+        const char* readableName,
+        int ticksNeeded);
+    GrowingPlantlockType* setHardness(float hardness);
+    GrowingPlantlockType* addGrowthState(
+        float growthPercentage, ModelInfo model);
+};

+ 1 - 1
FactoryCraft/ItemStack.cpp

@@ -40,7 +40,7 @@ Item* ItemStack::extractFromStack()
 
 bool ItemStack::addToStack(Item* item)
 {
-    if (size < maxSize && this->item->canBeStackedWith(item))
+    if (size < maxSize && (size == 0 || this->item->canBeStackedWith(item)))
     {
         ++size;
         item->release();

+ 19 - 1
FactoryCraft/ModelInfo.cpp

@@ -5,7 +5,7 @@ using namespace Framework;
 ModelInfo::ModelInfo(
     const char* modelPath, const char* texturPath, int textureCount)
     : modelPath(modelPath),
-      transparent(1)
+      transparent(0)
 {
     for (int i = 0; i < textureCount; i++)
         texturePaths.add(new Text(texturPath));
@@ -19,6 +19,24 @@ ModelInfo::ModelInfo(
         this->texturePaths.add(new Text(texturPath));
 }
 
+ModelInfo::ModelInfo(const ModelInfo& right)
+    : modelPath(right.modelPath),
+      transparent(right.transparent)
+{
+    for (int i = 0; i < right.texturePaths.getEintragAnzahl(); i++)
+        texturePaths.add(right.texturePaths.get(i));
+}
+
+ModelInfo& ModelInfo::operator=(const ModelInfo& right)
+{
+    modelPath = right.modelPath;
+    transparent = right.transparent;
+    texturePaths.leeren();
+    for (int i = 0; i < right.texturePaths.getEintragAnzahl(); i++)
+        texturePaths.add(right.texturePaths.get(i));
+    return *this;
+}
+
 void ModelInfo::writeTo(Framework::StreamWriter* zWriter) const
 {
     char len = (char)modelPath.getLength();

+ 3 - 1
FactoryCraft/ModelInfo.h

@@ -7,7 +7,7 @@
 class ModelInfo
 {
 private:
-    const Framework::Text modelPath;
+    Framework::Text modelPath;
     Framework::RCArray<Framework::Text> texturePaths;
     bool transparent;
 
@@ -15,6 +15,8 @@ public:
     ModelInfo(const char* modelPath, const char* texturPath, int textureCount);
     ModelInfo(
         const char* modelPath, std::initializer_list<const char*> texturePaths);
+    ModelInfo(const ModelInfo& right);
+    ModelInfo& operator=(const ModelInfo& right);
     void writeTo(Framework::StreamWriter* zWriter) const;
     ModelInfo& setTransparent();
 };

+ 3 - 3
FactoryCraft/NetworkMessage.cpp

@@ -21,7 +21,7 @@ NetworkMessage::~NetworkMessage()
     delete[] address;
 }
 
-void NetworkMessage::addressChunck(Chunk* zChunk)
+void NetworkMessage::addressChunck(const Chunk* zChunk)
 {
     delete[] address;
     addressLength = 10;
@@ -33,7 +33,7 @@ void NetworkMessage::addressChunck(Chunk* zChunk)
     *(int*)(address + 6) = center.y;
 }
 
-void NetworkMessage::addressEntity(Entity* zEntity)
+void NetworkMessage::addressEntity(const Entity* zEntity)
 {
     delete[] address;
     addressLength = 6;
@@ -51,7 +51,7 @@ void NetworkMessage::addressDimension()
     address[0] = 1; // dimension response
 }
 
-void NetworkMessage::addressBlock(Block* zBlock)
+void NetworkMessage::addressBlock(const Block* zBlock)
 {
     delete[] address;
     addressLength = 14;

+ 3 - 3
FactoryCraft/NetworkMessage.h

@@ -22,9 +22,9 @@ public:
     NetworkMessage();
     ~NetworkMessage();
 
-    void addressChunck(Chunk* zChunk);
-    void addressEntity(Entity* zEntity);
-    void addressBlock(Block* zBlock);
+    void addressChunck(const Chunk* zChunk);
+    void addressEntity(const Entity* zEntity);
+    void addressBlock(const Block* zBlock);
     void addressDimension();
     void openDialog(Framework::Text dialogName);
     void addressGui(Framework::Text elementId);

+ 62 - 1
FactoryCraft/StaticInitializerOrder.cpp

@@ -4,6 +4,7 @@
 // block types
 #include "BasicBlocks.h"
 #include "Grass.h"
+#include "GrowingPlant.h"
 #include "NoBlock.h"
 #include "TreeSeblingBlock.h"
 // dimensions
@@ -208,7 +209,8 @@ void initializeBlockTypes()
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::FARMLAND,
          ItemTypeEnum::DIRT,
-         ModelInfo("cube", {"blocks.ltdb/dirt.png",
+         ModelInfo("cube",
+             {"blocks.ltdb/dirt.png",
                  "blocks.ltdb/dirt.png",
                  "blocks.ltdb/dirt.png",
                  "blocks.ltdb/dirt.png",
@@ -216,6 +218,38 @@ void initializeBlockTypes()
                  "blocks.ltdb/dirt.png"}),
          "Farmland"))
         ->initializeDefault();
+    (new GrowingPlantlockType(BlockTypeEnum::WHEAT_SEED,
+         ModelInfo("grass", "plants.ltdb/wheatseeds.png", 16).setTransparent(),
+         "WheatSeeds",
+         BlockTypeEnum::WHEAT,
+         "Growing wheat",
+         18000))
+        ->addGrowthState(0.2f,
+            ModelInfo("grass", "plants.ltdb/wheatseedsa.png", 16)
+                .setTransparent())
+        ->addGrowthState(0.4f,
+            ModelInfo("grass", "plants.ltdb/wheatseedsb.png", 16)
+                .setTransparent())
+        ->addGrowthState(0.6f,
+            ModelInfo("grass", "plants.ltdb/wheatseedsc.png", 16)
+                .setTransparent())
+        ->addGrowthState(0.8f,
+            ModelInfo("grass", "plants.ltdb/wheatseedsd.png", 16)
+                .setTransparent())
+        ->initializeDefault();
+    (new BasicBlockType(
+         BlockTypeEnum::WHEAT,
+         ItemTypeEnum::WHEAT,
+         ModelInfo("grass", "plants.ltdb/wheat.png", 16).setTransparent(),
+         [](Vec3<int> pos) {
+             AdditionalItemSpawningBlock* block
+                 = new AdditionalItemSpawningBlock(
+                     BlockTypeEnum::WHEAT, 0, pos);
+             block->addSpawn({0, 4, 1.0, ItemTypeEnum::WHEAT});
+             return (Block*)block;
+         },
+         "Wheat"))
+        ->initializeDefault();
 }
 
 void initializeItemTypes()
@@ -459,6 +493,33 @@ void initializeItemTypes()
                 0,
                 50);
         }));
+
+    (new BasicBlockItemType(ItemTypeEnum::WHEAT_SEED,
+         "Wheat Seeds",
+         0,
+         0,
+         ModelInfo("grass", "plants.ltdb/wheatseeds.png", 16),
+         BlockTypeEnum::WHEAT_SEED))
+        ->setHardness(0.1f);
+    (new NoBlockItemType(ItemTypeEnum::WHEAT,
+        "Wheat",
+        0,
+        0,
+        ModelInfo("grass", "plants.ltdb/wheat.png", 16),
+        []() {
+            return ItemType::createBasicItem(ItemTypeEnum::WHEAT,
+                "Wheat",
+                1.f,
+                1.f,
+                10.f,
+                10.f,
+                1,
+                0,
+                0,
+                1,
+                0,
+                50); // TODO: add food increment on eating
+        }));
 }
 
 void initializeEntityTypes()