Block.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include "Block.h"
  2. #include "Inventory.h"
  3. #include "NoBlock.h"
  4. #include "Game.h"
  5. #include "ItemEntity.h"
  6. #include "AddEntityUpdate.h"
  7. Block::Block(const BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos, bool hasInventory)
  8. : Inventory(pos, hasInventory)
  9. {
  10. transparent = false;
  11. passable = false;
  12. hp = 1;
  13. maxHP = 1;
  14. hardness = 1;
  15. this->zType = zType;
  16. this->zTool = zTool;
  17. speedModifier = 1;
  18. ticksLeftCounter = 0;
  19. wasTicked = 0;
  20. onTickCalled = 0;
  21. minTickTimeout = -1;
  22. maxTickTimeout = -1;
  23. tickSource = 0;
  24. currentTickTimeout = 0;
  25. dimensionId = 0;
  26. interactable = 0;
  27. deadAndRemoved = 0;
  28. memset(zNeighbours, 0, sizeof(Block*) * 6);
  29. }
  30. Block::~Block()
  31. {}
  32. void Block::onDestroy()
  33. {
  34. if (!deadAndRemoved)
  35. {
  36. Item* blockItem = zType->getItemFromBlock(this);
  37. if (blockItem)
  38. {
  39. ItemEntity* itemEntity = (ItemEntity*)ItemEntityType::INSTANCE->createEntity(location + Framework::Vec3<float>(0.5f, 0.5f, 0.5f), dimensionId, Game::INSTANCE->getNextEntityId());
  40. ItemStack* stack = new ItemStack(blockItem, 1, blockItem->getMaxStackSize());
  41. itemEntity->unsaveAddItem(stack, NO_DIRECTION);
  42. stack->release();
  43. Game::INSTANCE->requestWorldUpdate(new AddEntityUpdate(itemEntity, dimensionId));
  44. deadAndRemoved = 1;
  45. }
  46. }
  47. }
  48. void Block::tick(TickQueue* zQueue)
  49. {
  50. if (wasTicked)
  51. return;
  52. wasTicked = 1;
  53. ticksLeftCounter++;
  54. if (minTickTimeout >= 0)
  55. {
  56. if (currentTickTimeout < ticksLeftCounter)
  57. {
  58. onTickCalled = 1;
  59. bool blocked = 0;
  60. bool result = onTick(zQueue, ticksLeftCounter, blocked);
  61. if (blocked)
  62. {
  63. wasTicked = 0;
  64. ticksLeftCounter--;
  65. onTickCalled = 0;
  66. return;
  67. }
  68. if (result)
  69. currentTickTimeout = MAX(MIN(currentTickTimeout - 1, maxTickTimeout), MAX(minTickTimeout, 0));
  70. else
  71. currentTickTimeout = MAX(MIN(currentTickTimeout + 1, maxTickTimeout), MAX(minTickTimeout, 0));
  72. ticksLeftCounter = 0;
  73. }
  74. }
  75. }
  76. void Block::postTick()
  77. {
  78. wasTicked = 0;
  79. if (onTickCalled)
  80. {
  81. onPostTick();
  82. onTickCalled = 0;
  83. }
  84. }
  85. void Block::setNeighbour(Direction dir, Framework::Either<Block*, int> neighbour)
  86. {
  87. if (neighbour.isA())
  88. setNeighbourBlock(dir, neighbour);
  89. else
  90. {
  91. setNeighbourBlock(dir, 0);
  92. setNeighbourType(dir, neighbour);
  93. }
  94. }
  95. void Block::setNeighbourBlock(Direction dir, Block* zN)
  96. {
  97. if (zN)
  98. setNeighbourType(dir, zN->zBlockType()->getId());
  99. zNeighbours[getDirectionIndex(dir)] = zN;
  100. }
  101. void Block::setNeighbourType(Direction dir, int type)
  102. {
  103. neighbourTypes[getDirectionIndex(dir)] = type;
  104. }
  105. void Block::setDimensionId(int id)
  106. {
  107. dimensionId = id;
  108. }
  109. void api(Framework::StreamReader* zRequest, NetworkMessage* zResponse)
  110. {
  111. // TODO: answer api requests
  112. }
  113. bool Block::isTickSource() const
  114. {
  115. return tickSource;
  116. }
  117. const BlockType* Block::zBlockType() const
  118. {
  119. return zType;
  120. }
  121. bool Block::isTransparent() const
  122. {
  123. return transparent;
  124. }
  125. bool Block::isPassable() const
  126. {
  127. return passable;
  128. }
  129. bool Block::isInteractable() const
  130. {
  131. return interactable;
  132. }
  133. float Block::getHP() const
  134. {
  135. return hp;
  136. }
  137. float Block::getMaxHP() const
  138. {
  139. return maxHP;
  140. }
  141. float Block::getHardness() const
  142. {
  143. return hardness;
  144. }
  145. ItemType* Block::zEffectiveTool() const
  146. {
  147. return zTool;
  148. }
  149. float Block::getSpeedModifier() const
  150. {
  151. return speedModifier;
  152. }
  153. const Framework::Vec3<int> Block::getPos() const
  154. {
  155. return (Framework::Vec3<int>)location;
  156. }
  157. int Block::getDimensionId() const
  158. {
  159. return dimensionId;
  160. }
  161. bool Block::isVisible() const
  162. {
  163. if (passable || transparent)
  164. return 1;
  165. for (int i = 0; i < 6; i++)
  166. {
  167. const Block* neighbour = CONST_BLOCK(zNeighbours[i], neighbourTypes[i]);
  168. if (neighbour->isPassable() || neighbour->isTransparent())
  169. return 1;
  170. }
  171. return 0;
  172. }
  173. void Block::setHP(float hp)
  174. {
  175. bool isDead = this->hp == 0.f;
  176. this->hp = MAX(0.f, hp);
  177. if (!isDead && this->hp == 0.f)
  178. {
  179. for (int i = 0; i < 6; i++)
  180. {
  181. if (neighbourTypes[i] == NoBlockBlockType::ID)
  182. {
  183. Framework::Vec3<int> pos = getPos() + getDirection(getDirectionFromIndex(i));
  184. Game::INSTANCE->zDimension(dimensionId)->placeBlock(pos, Game::INSTANCE->zGenerator()->generateSingleBlock(pos, dimensionId));
  185. }
  186. }
  187. onDestroy();
  188. Game::INSTANCE->zDimension(dimensionId)->placeBlock(getPos(), AirBlockBlockType::ID);
  189. }
  190. else
  191. {
  192. NetworkMessage changeMsg;
  193. changeMsg.addressBlock(this);
  194. char msg[5];
  195. msg[0] = 0; // hp changed
  196. *(float*)(msg + 1) = this->hp;
  197. changeMsg.setMessage(msg, 5, 0);
  198. Game::INSTANCE->broadcastMessage(&changeMsg);
  199. }
  200. }
  201. bool Block::isDeadAndRemoved() const
  202. {
  203. return deadAndRemoved;
  204. }
  205. BasicBlockItem::BasicBlockItem(const ItemType* zType, const BlockType* zPlacedBlockType, const char* name)
  206. : Item(zType, name)
  207. {
  208. placeable = 1;
  209. zBlockType = zPlacedBlockType;
  210. }
  211. bool BasicBlockItem::canBeStackedWith(const Item* zItem) const
  212. {
  213. const BasicBlockItem* item = dynamic_cast<const BasicBlockItem*>(zItem);
  214. if (item)
  215. {
  216. return Item::canBeStackedWith(zItem) &&
  217. transparent == item->transparent &&
  218. passable == item->passable &&
  219. hp == item->hp &&
  220. maxHP == item->maxHP &&
  221. hardness == item->hardness &&
  222. toolId == item->toolId &&
  223. speedModifier == item->speedModifier && interactable == item->interactable;
  224. }
  225. return 0;
  226. }
  227. BasicBlockItemType::BasicBlockItemType(int id, const char* name, ItemSkillLevelUpRule* levelUpRule, const ItemType* zBrokenType, ModelInfo model)
  228. : ItemType(id, name, levelUpRule, zBrokenType, model)
  229. {}
  230. void BasicBlockItemType::loadSuperItem(Item* zItem, Framework::StreamReader* zReader) const
  231. {
  232. ItemType::loadSuperItem(zItem, zReader);
  233. BasicBlockItem* item = dynamic_cast<BasicBlockItem*>(zItem);
  234. if (!item)
  235. throw "BasicBlockItemType::loadSuperItem was called with an invalid item";
  236. zReader->lese((char*)&item->transparent, 1);
  237. zReader->lese((char*)&item->passable, 1);
  238. zReader->lese((char*)&item->hp, 4);
  239. zReader->lese((char*)&item->maxHP, 4);
  240. zReader->lese((char*)&item->hardness, 4);
  241. zReader->lese((char*)&item->toolId, 4);
  242. zReader->lese((char*)&item->speedModifier, 4);
  243. zReader->lese((char*)&item->interactable, 1);
  244. }
  245. void BasicBlockItemType::saveSuperItem(const Item* zItem, Framework::StreamWriter* zWriter) const
  246. {
  247. ItemType::saveSuperItem(zItem, zWriter);
  248. const BasicBlockItem* item = dynamic_cast<const BasicBlockItem*>(zItem);
  249. if (!item)
  250. throw "BasicBlockItemType::saveSuperItem was called with an invalid item";
  251. zWriter->schreibe((char*)&item->transparent, 1);
  252. zWriter->schreibe((char*)&item->passable, 1);
  253. zWriter->schreibe((char*)&item->hp, 4);
  254. zWriter->schreibe((char*)&item->maxHP, 4);
  255. zWriter->schreibe((char*)&item->hardness, 4);
  256. zWriter->schreibe((char*)&item->toolId, 4);
  257. zWriter->schreibe((char*)&item->speedModifier, 4);
  258. zWriter->schreibe((char*)&item->interactable, 1);
  259. }
  260. void BasicBlockItemType::initializeItem(BasicBlockItem* zItem, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier) const
  261. {
  262. zItem->transparent = transparent;
  263. zItem->passable = passable;
  264. zItem->hp = hp;
  265. zItem->maxHP = maxHP;
  266. zItem->hardness = hardness;
  267. zItem->toolId = toolId;
  268. zItem->speedModifier = speedModifier;
  269. }