|
@@ -2,11 +2,72 @@
|
|
#include "Dimension.h"
|
|
#include "Dimension.h"
|
|
#include "Game.h"
|
|
#include "Game.h"
|
|
#include "BlockType.h"
|
|
#include "BlockType.h"
|
|
|
|
+#include "ItemSkill.h"
|
|
|
|
+#include "PlaceBlockUpdate.h"
|
|
|
|
+
|
|
|
|
+ActionTarget::ActionTarget( Vec3<int> blockPos, Direction blockSide )
|
|
|
|
+ : blockPos( blockPos ),
|
|
|
|
+ targetBlockSide( blockSide ),
|
|
|
|
+ entityId( -1 )
|
|
|
|
+{}
|
|
|
|
+
|
|
|
|
+ActionTarget::ActionTarget( int entityId )
|
|
|
|
+ : entityId( entityId )
|
|
|
|
+{}
|
|
|
|
+
|
|
|
|
+void ActionTarget::applyItemSkillOnTarget( Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem, Game* zGame )
|
|
|
|
+{
|
|
|
|
+ if( entityId >= 0 )
|
|
|
|
+ {
|
|
|
|
+ // TODO: get entity from game and apply skill
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ Block* block = zGame->zRealBlockInstance( blockPos, zActor->getCurrentDimensionId() );
|
|
|
|
+ if( block )
|
|
|
|
+ zItemSkill->use( zActor, zUsedItem, block );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ActionTarget::placeBlock( Entity* zActor, Item* zItem, Game* zGame )
|
|
|
|
+{
|
|
|
|
+ // TODO: check stamina of actor
|
|
|
|
+ Block* block = zItem->zPlacedBlockType()->createBlockAt( blockPos + getDirection( targetBlockSide ), zGame, zItem );
|
|
|
|
+ if( block )
|
|
|
|
+ {
|
|
|
|
+ if( zGame->requestWorldUpdate( new PlaceBlockUpdate( block, zActor->getCurrentDimensionId() ) ) )
|
|
|
|
+ {
|
|
|
|
+ zItem->onPlaced();
|
|
|
|
+ // TODO: decrese stamina of actor
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void ActionTarget::save( Framework::StreamWriter* zWriter ) const
|
|
|
|
+{
|
|
|
|
+ if( entityId >= 0 )
|
|
|
|
+ {
|
|
|
|
+ char b = 1;
|
|
|
|
+ zWriter->schreibe( &b, 1 );
|
|
|
|
+ zWriter->schreibe( (char*)&entityId, 4 );
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ char b = 2;
|
|
|
|
+ zWriter->schreibe( &b, 1 );
|
|
|
|
+ zWriter->schreibe( (char*)&blockPos.x, 4 );
|
|
|
|
+ zWriter->schreibe( (char*)&blockPos.y, 4 );
|
|
|
|
+ zWriter->schreibe( (char*)&blockPos.z, 4 );
|
|
|
|
+ zWriter->schreibe( (char*)&targetBlockSide, 4 );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId )
|
|
Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId )
|
|
: Inventory( location, true ),
|
|
: Inventory( location, true ),
|
|
speed( 0, 0, 0 ),
|
|
speed( 0, 0, 0 ),
|
|
faceDir( 1, 0, 0 ),
|
|
faceDir( 1, 0, 0 ),
|
|
|
|
+ target( 0 ),
|
|
zEntityType( zType ),
|
|
zEntityType( zType ),
|
|
currentDimensionId( dimensionId ),
|
|
currentDimensionId( dimensionId ),
|
|
removed( 0 ),
|
|
removed( 0 ),
|
|
@@ -17,6 +78,169 @@ Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int di
|
|
void Entity::onDeath()
|
|
void Entity::onDeath()
|
|
{}
|
|
{}
|
|
|
|
|
|
|
|
+void Entity::useItem( const ItemType* zType, Item* zItem, Game* zGame )
|
|
|
|
+{
|
|
|
|
+ if( zItem && zItem->isEatable() )
|
|
|
|
+ { // TODO: eat item
|
|
|
|
+ zItem->applyFoodEffects( this );
|
|
|
|
+ }
|
|
|
|
+ else if( zItem && zItem->isPlaceable() )
|
|
|
|
+ { // TODO: place item
|
|
|
|
+ if( target )
|
|
|
|
+ target->placeBlock( this, zItem, zGame );
|
|
|
|
+ }
|
|
|
|
+ else if( !zItem || zItem->isUsable() )
|
|
|
|
+ { // use item skill
|
|
|
|
+ if( target )
|
|
|
|
+ {
|
|
|
|
+ ItemSkill* selected = 0;
|
|
|
|
+ for( ItemSkill* skill : skills )
|
|
|
|
+ {
|
|
|
|
+ if( skill->zSkillType() == zType )
|
|
|
|
+ {
|
|
|
|
+ selected = skill;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( !selected )
|
|
|
|
+ {
|
|
|
|
+ selected = zType->createDefaultItemSkill();
|
|
|
|
+ skills.add( selected );
|
|
|
|
+ }
|
|
|
|
+ target->applyItemSkillOnTarget( this, selected, zItem, zGame );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Entity::prepareTick( const Dimension* zDimension, Game* zGame )
|
|
|
|
+{
|
|
|
|
+ Vec3<float> headPosition = location + faceOffset;
|
|
|
|
+ int px = (int)floor( headPosition.x );
|
|
|
|
+ int py = (int)floor( headPosition.y );
|
|
|
|
+ int pz = (int)floor( headPosition.z );
|
|
|
|
+ faceDir.normalize();
|
|
|
|
+ bool needCollisionCheck = 1;
|
|
|
|
+ while( needCollisionCheck )
|
|
|
|
+ {
|
|
|
|
+ if( getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py, pz }, zDimension->getDimensionId() ) )->isInteractable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, BOTTOM );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ needCollisionCheck = 0;
|
|
|
|
+ // collision to neighbor of current block current block
|
|
|
|
+ if( faceDir.x > 0 )
|
|
|
|
+ {
|
|
|
|
+ float xt = ((float)px + 1.f - headPosition.x) / faceDir.x;
|
|
|
|
+ Vec3<float> tmp = headPosition + faceDir * xt;
|
|
|
|
+ if( xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
|
|
|
|
+ {
|
|
|
|
+ if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px + 1, py, pz }, zDimension->getDimensionId() ) )->isInteractable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, WEST );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ px++;
|
|
|
|
+ needCollisionCheck = 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( faceDir.x < 0 )
|
|
|
|
+ {
|
|
|
|
+ float xt = ((float)px - headPosition.x) / faceDir.x;
|
|
|
|
+ Vec3<float> tmp = headPosition + faceDir * xt;
|
|
|
|
+ if( xt <= 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
|
|
|
|
+ {
|
|
|
|
+ if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px - 1, py, pz }, zDimension->getDimensionId() ) )->isPassable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, EAST );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ px--;
|
|
|
|
+ needCollisionCheck = 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( speed.y > 0 )
|
|
|
|
+ {
|
|
|
|
+ float yt = ((float)py + 1.f - headPosition.y) / faceDir.y;
|
|
|
|
+ Vec3<float> tmp = headPosition + faceDir * yt;
|
|
|
|
+ if( yt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
|
|
|
|
+ {
|
|
|
|
+ if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py + 1, pz }, zDimension->getDimensionId() ) )->isPassable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, NORTH );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ py++;
|
|
|
|
+ needCollisionCheck = 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( speed.y < 0 )
|
|
|
|
+ {
|
|
|
|
+ float yt = ((float)py - headPosition.y) / faceDir.y;
|
|
|
|
+ Vec3<float> tmp = headPosition + faceDir * yt;
|
|
|
|
+ if( yt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
|
|
|
|
+ {
|
|
|
|
+ if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py - 1, pz }, zDimension->getDimensionId() ) )->isPassable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, SOUTH );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ py--;
|
|
|
|
+ needCollisionCheck = 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( speed.z > 0 )
|
|
|
|
+ {
|
|
|
|
+ float zt = ((float)pz + 1.f - headPosition.z) / faceDir.z;
|
|
|
|
+ Vec3<float> tmp = headPosition + faceDir * zt;
|
|
|
|
+ if( zt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f )
|
|
|
|
+ {
|
|
|
|
+ if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py, pz + 1 }, zDimension->getDimensionId() ) )->isPassable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, BOTTOM );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ pz++;
|
|
|
|
+ needCollisionCheck = 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( speed.z < 0 )
|
|
|
|
+ {
|
|
|
|
+ float zt = ((float)pz - headPosition.z) / faceDir.z;
|
|
|
|
+ Vec3<float> tmp = headPosition + faceDir * zt;
|
|
|
|
+ if( zt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1 )
|
|
|
|
+ {
|
|
|
|
+ if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py, pz - 1 }, zDimension->getDimensionId() ) )->isPassable() )
|
|
|
|
+ {
|
|
|
|
+ delete target;
|
|
|
|
+ target = new ActionTarget( { px, py, pz }, TOP );
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ pz--;
|
|
|
|
+ needCollisionCheck = 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
void Entity::tick( const Dimension* zDimension, Game* zGame )
|
|
void Entity::tick( const Dimension* zDimension, Game* zGame )
|
|
{
|
|
{
|
|
Vec3<float> oldPos = location;
|
|
Vec3<float> oldPos = location;
|
|
@@ -234,6 +458,11 @@ const EntityType* Entity::zType() const
|
|
return zEntityType;
|
|
return zEntityType;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+const ActionTarget* Entity::zTarget() const
|
|
|
|
+{
|
|
|
|
+ return target;
|
|
|
|
+}
|
|
|
|
+
|
|
int Entity::getId() const
|
|
int Entity::getId() const
|
|
{
|
|
{
|
|
return id;
|
|
return id;
|