Entity.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. #include "Entity.h"
  2. #include "Dimension.h"
  3. #include "Game.h"
  4. #include "BlockType.h"
  5. #include "ItemSkill.h"
  6. #include "PlaceBlockUpdate.h"
  7. #include "EntityRemovedUpdate.h"
  8. ActionTarget::ActionTarget( Vec3<int> blockPos, Direction blockSide )
  9. : blockPos( blockPos ),
  10. targetBlockSide( blockSide ),
  11. entityId( -1 )
  12. {}
  13. ActionTarget::ActionTarget( int entityId )
  14. : entityId( entityId )
  15. {}
  16. void ActionTarget::applyItemSkillOnTarget( Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem )
  17. {
  18. if( entityId >= 0 )
  19. {
  20. // TODO: get entity from game and apply skill
  21. }
  22. else
  23. {
  24. Block* block = Game::INSTANCE->zRealBlockInstance( blockPos, zActor->getCurrentDimensionId() );
  25. if( block )
  26. zItemSkill->use( zActor, zUsedItem, block );
  27. }
  28. }
  29. void ActionTarget::placeBlock( Entity* zActor, Item* zItem )
  30. {
  31. // TODO: check stamina of actor
  32. Block* block = zItem->zPlacedBlockType()->createBlockAt( blockPos + getDirection( targetBlockSide ), zItem );
  33. if( block )
  34. {
  35. if( Game::INSTANCE->requestWorldUpdate( new PlaceBlockUpdate( block, block->getPos(), zActor->getCurrentDimensionId() ) ) )
  36. {
  37. zItem->onPlaced();
  38. // TODO: decrese stamina of actor
  39. }
  40. }
  41. }
  42. void ActionTarget::save( Framework::StreamWriter* zWriter ) const
  43. {
  44. if( entityId >= 0 )
  45. {
  46. char b = 1;
  47. zWriter->schreibe( &b, 1 );
  48. zWriter->schreibe( (char*)&entityId, 4 );
  49. }
  50. else
  51. {
  52. char b = 2;
  53. zWriter->schreibe( &b, 1 );
  54. zWriter->schreibe( (char*)&blockPos.x, 4 );
  55. zWriter->schreibe( (char*)&blockPos.y, 4 );
  56. zWriter->schreibe( (char*)&blockPos.z, 4 );
  57. zWriter->schreibe( (char*)&targetBlockSide, 4 );
  58. }
  59. }
  60. Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId )
  61. : Inventory( location, true ),
  62. speed( 0, 0, 0 ),
  63. faceDir( 1, 0, 0 ),
  64. target( 0 ),
  65. zEntityType( zType ),
  66. currentDimensionId( dimensionId ),
  67. removed( 0 ),
  68. gravityMultiplier( 1.f ),
  69. id( entityId )
  70. {}
  71. void Entity::onDeath()
  72. {
  73. removed = 1;
  74. Game::INSTANCE->requestWorldUpdate( new EntityRemovedUpdate( id, currentDimensionId, location ) );
  75. }
  76. void Entity::useItem( const ItemType* zType, Item* zItem )
  77. {
  78. if( zItem && zItem->isEatable() )
  79. { // TODO: eat item
  80. zItem->applyFoodEffects( this );
  81. }
  82. else if( zItem && zItem->isPlaceable() )
  83. { // TODO: place item
  84. if( target )
  85. target->placeBlock( this, zItem );
  86. }
  87. else if( !zItem || zItem->isUsable() )
  88. { // use item skill
  89. if( target )
  90. {
  91. ItemSkill* selected = 0;
  92. for( ItemSkill* skill : skills )
  93. {
  94. if( skill->zSkillType() == zType )
  95. {
  96. selected = skill;
  97. break;
  98. }
  99. }
  100. if( !selected )
  101. {
  102. selected = zType->createDefaultItemSkill();
  103. skills.add( selected );
  104. }
  105. target->applyItemSkillOnTarget( this, selected, zItem );
  106. }
  107. }
  108. }
  109. void Entity::prepareTick( const Dimension* zDimension )
  110. {
  111. Vec3<float> headPosition = location + faceOffset;
  112. int px = (int)floor( headPosition.x );
  113. int py = (int)floor( headPosition.y );
  114. int pz = (int)floor( headPosition.z );
  115. faceDir.normalize();
  116. Direction dir = BOTTOM;
  117. while( true )
  118. {
  119. if( getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px, py, pz }, zDimension->getDimensionId() ) )->isInteractable() )
  120. {
  121. delete target;
  122. target = new ActionTarget( { px, py, pz }, dir );
  123. break;
  124. }
  125. // collision to neighbor of current block
  126. if( faceDir.x > 0 )
  127. {
  128. float xt = ((float)px + 1.f - headPosition.x) / faceDir.x;
  129. Vec3<float> tmp = headPosition + faceDir * xt;
  130. if( xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  131. {
  132. dir = WEST;
  133. px++;
  134. continue;
  135. }
  136. }
  137. if( faceDir.x < 0 )
  138. {
  139. float xt = ((float)px - headPosition.x) / faceDir.x;
  140. Vec3<float> tmp = headPosition + faceDir * xt;
  141. if( xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  142. {
  143. dir = EAST;
  144. px--;
  145. continue;
  146. }
  147. }
  148. if( faceDir.y > 0 )
  149. {
  150. float yt = ((float)py + 1.f - headPosition.y) / faceDir.y;
  151. Vec3<float> tmp = headPosition + faceDir * yt;
  152. if( yt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  153. {
  154. dir = NORTH;
  155. py++;
  156. continue;
  157. }
  158. }
  159. if( faceDir.y < 0 )
  160. {
  161. float yt = ((float)py - headPosition.y) / faceDir.y;
  162. Vec3<float> tmp = headPosition + faceDir * yt;
  163. if( yt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  164. {
  165. dir = SOUTH;
  166. py--;
  167. continue;
  168. }
  169. }
  170. if( faceDir.z > 0 )
  171. {
  172. float zt = ((float)pz + 1.f - headPosition.z) / faceDir.z;
  173. Vec3<float> tmp = headPosition + faceDir * zt;
  174. if( zt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f )
  175. {
  176. dir = BOTTOM;
  177. pz++;
  178. continue;
  179. }
  180. }
  181. if( faceDir.z < 0 )
  182. {
  183. float zt = ((float)pz - headPosition.z) / faceDir.z;
  184. Vec3<float> tmp = headPosition + faceDir * zt;
  185. if( zt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1 )
  186. {
  187. dir = TOP;
  188. pz--;
  189. continue;
  190. }
  191. }
  192. delete target;
  193. target = 0;
  194. break;
  195. }
  196. }
  197. void Entity::tick( const Dimension* zDimension )
  198. {
  199. Vec3<float> oldPos = location;
  200. // current block cooredinates
  201. int px = (int)floor( location.x );
  202. int py = (int)floor( location.y );
  203. int pz = (int)floor( location.z );
  204. // falling down
  205. speed.z -= (zDimension->getGravity() * gravityMultiplier) / 30.f;
  206. // movement in current tick
  207. Vec3<float> frameSpeed = speed / 30.f;
  208. // loop through all collided blocks
  209. bool needCollisionCheck = 1;
  210. while( needCollisionCheck )
  211. {
  212. needCollisionCheck = 0;
  213. // collision to neighbor of current block
  214. if( speed.x > 0 )
  215. {
  216. float xt = ((float)px + 1.f - oldPos.x) / frameSpeed.x;
  217. Vec3<float> tmp = oldPos + frameSpeed * xt;
  218. if( xt <= 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  219. {
  220. if( !getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px + 1, py, pz }, zDimension->getDimensionId() ) )->isPassable() )
  221. {
  222. frameSpeed.x = frameSpeed.x * (xt - 0.1f);
  223. speed.x = 0;
  224. }
  225. else
  226. px++;
  227. needCollisionCheck = 1;
  228. continue;
  229. }
  230. }
  231. if( speed.x < 0 )
  232. {
  233. float xt = ((float)px - oldPos.x) / frameSpeed.x;
  234. Vec3<float> tmp = oldPos + frameSpeed * xt;
  235. if( xt <= 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  236. {
  237. if( !getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px - 1, py, pz }, zDimension->getDimensionId() ) )->isPassable() )
  238. {
  239. frameSpeed.x = frameSpeed.x * (xt - 0.1f);
  240. speed.x = 0;
  241. }
  242. else
  243. px--;
  244. needCollisionCheck = 1;
  245. continue;
  246. }
  247. }
  248. if( speed.y > 0 )
  249. {
  250. float yt = ((float)py + 1.f - oldPos.y) / frameSpeed.y;
  251. Vec3<float> tmp = oldPos + frameSpeed * yt;
  252. if( yt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  253. {
  254. if( !getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px, py + 1, pz }, zDimension->getDimensionId() ) )->isPassable() )
  255. {
  256. frameSpeed.y = frameSpeed.y * (yt - 0.1f);
  257. speed.y = 0;
  258. }
  259. else
  260. py++;
  261. needCollisionCheck = 1;
  262. continue;
  263. }
  264. }
  265. if( speed.y < 0 )
  266. {
  267. float yt = ((float)py - oldPos.y) / frameSpeed.y;
  268. Vec3<float> tmp = oldPos + frameSpeed * yt;
  269. if( yt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
  270. {
  271. if( !getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px, py - 1, pz }, zDimension->getDimensionId() ) )->isPassable() )
  272. {
  273. frameSpeed.y = frameSpeed.y * (yt - 0.1f);
  274. speed.y = 0;
  275. }
  276. else
  277. py--;
  278. needCollisionCheck = 1;
  279. continue;
  280. }
  281. }
  282. if( speed.z > 0 )
  283. {
  284. float zt = ((float)pz + 1.f - oldPos.z) / frameSpeed.z;
  285. Vec3<float> tmp = oldPos + frameSpeed * zt;
  286. if( zt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f )
  287. {
  288. if( !getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px, py, pz + 1 }, zDimension->getDimensionId() ) )->isPassable() )
  289. {
  290. frameSpeed.z = frameSpeed.z * (zt - 0.1f);
  291. speed.z = 0;
  292. }
  293. else
  294. pz++;
  295. needCollisionCheck = 1;
  296. continue;
  297. }
  298. }
  299. if( speed.z < 0 )
  300. {
  301. float zt = ((float)pz - oldPos.z) / frameSpeed.z;
  302. Vec3<float> tmp = oldPos + frameSpeed * zt;
  303. if( zt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1 )
  304. {
  305. if( !getDefaultBlock( Game::INSTANCE->zBlockAt( Vec3<int>{ px, py, pz - 1 }, zDimension->getDimensionId() ) )->isPassable() )
  306. {
  307. frameSpeed.z = frameSpeed.z * (zt - 0.1f);
  308. onFall( speed.z );
  309. speed.z = 0;
  310. }
  311. else
  312. pz--;
  313. needCollisionCheck = 1;
  314. continue;
  315. }
  316. }
  317. }
  318. location += frameSpeed;
  319. }
  320. void Entity::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse )
  321. {
  322. // TODO: answer api requests
  323. }
  324. void Entity::onFall( float collisionSpeed )
  325. {
  326. if( collisionSpeed > 5 )
  327. {
  328. // TODO: take damage
  329. }
  330. }
  331. void Entity::setPosition( Framework::Vec3<float> pos )
  332. {
  333. location = pos;
  334. }
  335. float Entity::getMaxHP() const
  336. {
  337. return maxHP;
  338. }
  339. float Entity::getCurrentHP() const
  340. {
  341. return currentHP;
  342. }
  343. float Entity::getStamina() const
  344. {
  345. return stamina;
  346. }
  347. float Entity::getMaxStamina() const
  348. {
  349. return maxStamina;
  350. }
  351. float Entity::getHunger() const
  352. {
  353. return hunger;
  354. }
  355. float Entity::getMaxHunger() const
  356. {
  357. return maxHunger;
  358. }
  359. float Entity::getThirst() const
  360. {
  361. return thirst;
  362. }
  363. float Entity::getMaxThirst() const
  364. {
  365. return maxThirst;
  366. }
  367. Framework::Vec3<float> Entity::getSpeed() const
  368. {
  369. return speed;
  370. }
  371. Framework::Vec3<float> Entity::getFaceDir() const
  372. {
  373. return faceDir;
  374. }
  375. Framework::Vec3<float> Entity::getPosition() const
  376. {
  377. return location;
  378. }
  379. float Entity::getGravityMultiplier() const
  380. {
  381. return gravityMultiplier;
  382. }
  383. int Entity::getCurrentDimensionId() const
  384. {
  385. return currentDimensionId;
  386. }
  387. bool Entity::isRemoved() const
  388. {
  389. return removed;
  390. }
  391. const EntityType* Entity::zType() const
  392. {
  393. return zEntityType;
  394. }
  395. const ActionTarget* Entity::zTarget() const
  396. {
  397. return target;
  398. }
  399. int Entity::getId() const
  400. {
  401. return id;
  402. }