Entity.cpp 12 KB

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