#Fixes to flank penalty, notifications, sectors, terrain conformance. Added speed bonus based on terrain slope.
-added NOTIFY_ORDER_CHANGE, which is used for flank penalty instead of idle. -entity speed is now actions.move.speed_curr for the current speed, but the original speed is still actions.move.speed. Changes take place in entityEventMovemen. This was SVN commit r3840.
This commit is contained in:
parent
16b94e5604
commit
39e89c406e
@ -24,8 +24,8 @@
|
||||
; System settings:
|
||||
|
||||
novbo=false
|
||||
noframebufferobject=false
|
||||
shadows=true
|
||||
noframebufferobject=true
|
||||
shadows=false
|
||||
vsync=false
|
||||
|
||||
; Specify the render path. This can be one of:
|
||||
@ -34,7 +34,7 @@ vsync=false
|
||||
; vertexshader Use vertex shaders for transform and lighting where possible
|
||||
; Using 'fixed' instead of 'default' may work around some graphics-related problems,
|
||||
; but will reduce performance when a modern graphics card is available.
|
||||
renderpath=default
|
||||
renderpath=fixed
|
||||
|
||||
; Adjusts how OpenGL calculates mipmap level of detail. 0.0f is the default (blurry) value.
|
||||
; Lower values sharpen/extend, and higher values blur/decrease. Clamped at -3.0 to 3.0.
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
<formation Tag="Form Box 2"
|
||||
bonus="actions.move.speed"
|
||||
bonus="actions.move.speed_curr"
|
||||
bonusbase="actions.move.speed"
|
||||
bonustype="Melee"
|
||||
bonusval=".2"
|
||||
penalty=""
|
||||
|
@ -13,6 +13,9 @@
|
||||
<!-- All but sea units are attached to the ground plane. -->
|
||||
<Anchor>
|
||||
<Type>Ground</Type>
|
||||
<!-- If negative or > 90.0, entity will always conform to terrain (assuming traits.pitch allows it) -->
|
||||
<ConformX>3.141592</ConformX>
|
||||
<ConformZ>3.141592</ConformZ>
|
||||
</Anchor>
|
||||
|
||||
<!-- Defaults to no armour. -->
|
||||
@ -49,14 +52,13 @@
|
||||
<Height>-1.0</Height>
|
||||
<Name></Name>
|
||||
</Rank>
|
||||
<AnglePenalty>
|
||||
<Flank_Penalty>
|
||||
<Sectors>6</Sectors>
|
||||
<Value>.2</Value>
|
||||
</AnglePenalty>
|
||||
</Flank_Penalty>
|
||||
<Pitch>
|
||||
<Max_Actor>0.03</Max_Actor>
|
||||
<Min_Actor>-0.03</Min_Actor>
|
||||
|
||||
<Sectors>7</Sectors>
|
||||
<Value>.1</Value>
|
||||
</Pitch>
|
||||
|
||||
</Traits>
|
||||
|
@ -22,5 +22,6 @@
|
||||
<Event On="Notification" Function="entityEventNotification" />
|
||||
<Event On="Formation" Function="entityEventFormation" />
|
||||
<Event On="Idle" Function="entityEventIdle" />
|
||||
<Event On="Movement" Function="entityEventMovement" />
|
||||
|
||||
</Entity>
|
@ -157,6 +157,9 @@ function entityInit()
|
||||
// Register our actions with the generic order system
|
||||
if( this.actions )
|
||||
{
|
||||
if ( this.actions.move && this.actions.move.speed )
|
||||
this.actions.move.speed_curr = this.actions.move.speed;
|
||||
|
||||
if( this.actions.attack && this.actions.attack.melee )
|
||||
{
|
||||
a = this.actions.attack.melee;
|
||||
@ -341,7 +344,7 @@ function performAttack( evt )
|
||||
|
||||
// Attack logic.
|
||||
var dmg = new DamageType();
|
||||
|
||||
var flank = (evt.target.getAttackDirections()-1)*evt.target.traits.flank_penalty.value;
|
||||
if ( this.getRunState() )
|
||||
{
|
||||
dmg.crush = parseInt(this.actions.attack.charge.damage * this.actions.attack.charge.crush);
|
||||
@ -354,6 +357,9 @@ function performAttack( evt )
|
||||
dmg.hack = parseInt(this.actions.attack.melee.damage * this.actions.attack.melee.hack);
|
||||
dmg.pierce = parseInt(this.actions.attack.melee.damage * this.actions.attack.melee.pierce);
|
||||
}
|
||||
dmg.crush += dmg.crush * flank;
|
||||
dmg.hack += dmg.hack * flank;
|
||||
dmg.pierce += dmg.pierce * flank;
|
||||
|
||||
evt.target.damage( dmg, this );
|
||||
|
||||
@ -371,7 +377,12 @@ function performAttackRanged( evt )
|
||||
dmg.hack = parseInt(this.actions.attack.ranged.damage * this.actions.attack.ranged.hack);
|
||||
dmg.pierce = parseInt(this.actions.attack.ranged.damage * this.actions.attack.ranged.pierce);
|
||||
|
||||
// The parameters for Projectile are:
|
||||
var flank = (evt.target.getAttackDirections()-1)*evt.target.traits.flank_penalty.value;
|
||||
dmg.crush += dmg.crush * flank;
|
||||
dmg.hack += dmg.hack * flank;
|
||||
dmg.pierce += dmg.pierce * flank;
|
||||
|
||||
// The parameters for Projectile are:
|
||||
// 1 - The actor to use as the projectile. There are two ways of specifying this:
|
||||
// the first is by giving an entity. The projectile's actor is found by looking
|
||||
// in the actor of that entity. This way is usual, and preferred - visual
|
||||
@ -564,7 +575,7 @@ function damage( dmg, inflictor )
|
||||
if(!this.traits.armour) return; // corpses have no armour, everything else should
|
||||
|
||||
this.last_combat_time = getGameTime();
|
||||
|
||||
|
||||
// Apply armour and work out how much damage we actually take
|
||||
crushDamage = parseInt(dmg.crush - this.traits.armour.value * this.traits.armour.crush);
|
||||
if ( crushDamage < 0 ) crushDamage = 0;
|
||||
@ -666,14 +677,14 @@ function damage( dmg, inflictor )
|
||||
// If we're not already doing something else, take a measured response - hit 'em back.
|
||||
// You know, I think this is quite possibly the first AI code the AI divlead has written
|
||||
// for 0 A.D....
|
||||
//When the entity changes order, we can readjust flank penalty. We must destroy the notifiers ourselves later,however.
|
||||
this.requestNotification( inflictor, NOTIFY_ORDER_CHANGE, false, true );
|
||||
this.registerDamage( inflictor );
|
||||
if( this.isIdle() )
|
||||
this.order( ORDER_GENERIC, inflictor, getAttackAction( this, inflictor ) );
|
||||
}
|
||||
|
||||
// FIXME: These seemed to cause a crash I fixed the spelling from register to Register, so I've commented them out (Matei)
|
||||
//When the entity is idle, we can readjust angle penalty. We must destroy the notifiers ourselves later, however.
|
||||
//this.requestNotification( inflictor, NOTIFY_IDLE, false, true );
|
||||
//this.registerDamage( inflictor );
|
||||
|
||||
}
|
||||
// ====================================================================
|
||||
|
||||
@ -710,11 +721,18 @@ function entityEventGeneric( evt )
|
||||
|
||||
function entityEventNotification( evt )
|
||||
{
|
||||
//This is used to adjust the flank penalty (we're no longer being attacked).
|
||||
if ( this.getCurrentRequest() == NOTIFY_ORDER_CHANGE )
|
||||
{
|
||||
this.registerOrderChange();
|
||||
destroyNotifier( evt.target );
|
||||
return;
|
||||
}
|
||||
//Add "true" to the end of order() to indicate that this is a notification order.
|
||||
switch( evt.notifyType )
|
||||
{
|
||||
|
||||
case NOTIFY_GOTO:
|
||||
case NOTIFY_GOTO:
|
||||
this.GotoInRange( evt.location.x, evt.location.z, false);
|
||||
break;
|
||||
case NOTIFY_RUN:
|
||||
@ -731,13 +749,13 @@ function entityEventNotification( evt )
|
||||
this.order( ORDER_GENERIC, evt.target, ACTION_GATHER, true );
|
||||
break;
|
||||
case NOTIFY_IDLE:
|
||||
//target is the unit that has become idle
|
||||
this.registerIdle( evt.target );
|
||||
//target is the unit that has become idle. Eventually...do something here.
|
||||
break;
|
||||
default:
|
||||
console.write( "Unknown notification request " + evt.notifyType );
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
@ -765,9 +783,30 @@ function entityComplete()
|
||||
//=====================================================================
|
||||
function entityEventIdle( evt )
|
||||
{
|
||||
//Use our own data for target; we aren't affecting anyone, so listeners wants to know about us
|
||||
//Use our own data for target; we aren't affecting anyone, so listeners want to know about us
|
||||
this.forceCheckListeners( NOTIFY_IDLE, this );
|
||||
}
|
||||
//=====================================================================
|
||||
function entityEventMovement( evt )
|
||||
{
|
||||
var divs = this.traits.pitch.sectors;
|
||||
var sector = this.findSector( divs, evt.slope, 3.141592, true );
|
||||
|
||||
if ( divs % 2 )
|
||||
{
|
||||
sector += ((divs+1)/2 - sector)*2;
|
||||
sector -= (divs+1)/2;
|
||||
this.actions.move.speed_curr = this.actions.move.speed;
|
||||
this.actions.move.speed_curr += this.actions.move.speed*this.traits.pitch.value*sector;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector += ((divs)/2 - sector)*2;
|
||||
sector -= (divs)/2;
|
||||
this.actions.move.speed_curr = this.actions.move.speed;
|
||||
this.actions.move.speed_curr += this.actions.move.speed*this.traits.pitch.value*sector;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
@ -867,26 +906,40 @@ function entityEventPrepareOrder( evt )
|
||||
|
||||
//evt.notifySource is the entity order data will be obtained from, so if we're attacking and we
|
||||
//want our listeners to copy us, then we will use our own order as the source.
|
||||
//registerOrderChange() is used to adjust the flank penalty
|
||||
|
||||
switch( evt.orderType )
|
||||
{
|
||||
case ORDER_GOTO:
|
||||
if ( !this.actions.move )
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
evt.notifyType = NOTIFY_GOTO;
|
||||
evt.notifySource = this;
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
|
||||
case ORDER_RUN:
|
||||
if ( !this.actions.move.run )
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
evt.notifyType = NOTIFY_RUN;
|
||||
evt.notifySource = this;
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
|
||||
case ORDER_PATROL:
|
||||
if ( !this.actions.patrol )
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
this.registerOrderChange();
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
|
||||
case ORDER_GENERIC:
|
||||
@ -897,26 +950,42 @@ function entityEventPrepareOrder( evt )
|
||||
case ACTION_ATTACK_RANGED:
|
||||
evt.action = getAttackAction( this, evt.target );
|
||||
if ( evt.action == ACTION_NONE )
|
||||
evt.preventDefault();
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
evt.notifyType = NOTIFY_ATTACK;
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
|
||||
case ACTION_GATHER:
|
||||
if ( !this.actions.gather )
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
evt.notifyType = NOTIFY_GATHER;
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
|
||||
case ACTION_HEAL:
|
||||
if ( !this.actions.heal )
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
evt.notifyType = NOTIFY_HEAL;
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
|
||||
case ACTION_BUILD:
|
||||
if ( !this.actions.build )
|
||||
{
|
||||
evt.preventDefault();
|
||||
return;
|
||||
}
|
||||
evt.notifyType = NOTIFY_NONE;
|
||||
this.forceCheckListeners( NOTIFY_ORDER_CHANGE, this );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1463,12 +1532,12 @@ function entityEventFormation( evt )
|
||||
{
|
||||
if ( this.getFormationBonus() && this.hasClass( this.getFormationBonusType() ) )
|
||||
{
|
||||
eval( this + this.getFormationBonus() ) += eval( this + this.getFormationBonus() ) *
|
||||
eval( this + this.getFormationBonus() ) += eval( this + this.getFormationBonusBase() ) *
|
||||
this.getFormationBonusVal();
|
||||
}
|
||||
if ( this.getFormationPenalty() && this.hasInClass( this.getFormationPenaltyType() ) )
|
||||
{
|
||||
eval( this + this.getFormationPenalty() ) -= eval( this + this.getFormationbonus() ) *
|
||||
eval( this + this.getFormationPenalty() ) -= eval( this + this.getFormationPenaltyBase() ) *
|
||||
this.getFormationPenaltyVal();
|
||||
}
|
||||
}
|
||||
@ -1477,12 +1546,12 @@ function entityEventFormation( evt )
|
||||
{
|
||||
if ( this.getFormationPenalty() && this.hasInClass( this.getFormationPenaltyType() ) )
|
||||
{
|
||||
eval( this + this.getFormationPenalty() ) += eval( this + this.getFormationbonus() ) *
|
||||
eval( this + this.getFormationPenalty() ) += eval( this + this.getFormationPenaltyBase() ) *
|
||||
this.getFormationPenaltyVal();
|
||||
}
|
||||
if ( this.getFormationBonus() && this.hasClass( this.getFormationBonusType() ) )
|
||||
{
|
||||
eval( this + this.getFormationBonus() ) -= eval( this + this.getFormationBonus() ) * this.getFormationBonusVal();
|
||||
eval( this + this.getFormationBonus() ) -= eval( this + this.getFormationBonusBase() ) * this.getFormationBonusVal();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -77,6 +77,7 @@
|
||||
|
||||
<Move>
|
||||
<Speed>7.0</Speed>
|
||||
<Speed_Curr/>
|
||||
<TurningRadius>0.0</TurningRadius>
|
||||
|
||||
<Run>
|
||||
|
@ -510,7 +510,7 @@ void CGameView::Update(float DeltaTime)
|
||||
|
||||
if (m_UnitView)
|
||||
{
|
||||
m_ViewCamera.m_Orientation.SetYRotation(m_UnitView->m_orientation);
|
||||
m_ViewCamera.m_Orientation.SetYRotation(m_UnitView->m_orientation.Y);
|
||||
m_ViewCamera.m_Orientation.Translate(m_UnitViewProp->GetTransform().GetTranslation());
|
||||
m_ViewCamera.UpdateFrustum();
|
||||
return;
|
||||
|
@ -179,7 +179,7 @@ int CMapReader::ApplyData()
|
||||
{
|
||||
// initialise the terrain
|
||||
pTerrain->Initialize(m_MapSize, &m_Heightmap[0]);
|
||||
|
||||
|
||||
// setup the textures on the minipatches
|
||||
STileDesc* tileptr = &m_Tiles[0];
|
||||
for (u32 j=0; j<m_MapSize; j++) {
|
||||
@ -218,13 +218,14 @@ int CMapReader::ApplyData()
|
||||
unit->GetModel()->SetTransform(transform);
|
||||
}
|
||||
}
|
||||
//Make units start out conforming correctly
|
||||
g_EntityManager.conformAll();
|
||||
|
||||
if (unpacker.GetVersion() >= 2)
|
||||
{
|
||||
// copy over the lighting parameters
|
||||
*pLightEnv = m_LightEnv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ void CMapWriter::WriteXML(const char* filename, CUnitManager* pUnitMan, CLightEn
|
||||
}
|
||||
|
||||
{
|
||||
float angle = entity->m_orientation;
|
||||
float angle = entity->m_orientation.Y;
|
||||
|
||||
XML_Element("Orientation");
|
||||
XML_Attribute("angle", angle);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
#include "EntityManager.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "Terrain.h"
|
||||
#include "MathUtil.h"
|
||||
@ -207,14 +209,27 @@ float CTerrain::getSlope(float x, float z) const
|
||||
return MAX(MAX(h00, h01), MAX(h10, h11)) -
|
||||
MIN(MIN(h00, h01), MIN(h10, h11));
|
||||
}
|
||||
float CTerrain::getSlopeAngle( float x, float y ) const
|
||||
CVector2D CTerrain::getSlopeAngleFace(float x, float y, CEntity*& entity ) const
|
||||
{
|
||||
//side start at 0 at -180 degrees, and end up at 7 at 180 degrees
|
||||
int side;
|
||||
bool invert;
|
||||
float top, bottom, topZ, bottomZ;
|
||||
float fCell = (float)CELL_SIZE;
|
||||
x /= fCell;
|
||||
y /= fCell;
|
||||
int xi = (int)floor(x);
|
||||
int yi = (int)floor(y);
|
||||
|
||||
|
||||
CVector3D flat(0.0f, 0.0f, 0.0f);
|
||||
CVector3D flatZ = flat;
|
||||
CVector2D ret;
|
||||
side = entity->findSector( 8, entity->m_orientation.Y, DEGTORAD(360.0f) ) - 1;
|
||||
|
||||
//Wrap around
|
||||
if ( side < 0 )
|
||||
side += 8;
|
||||
|
||||
//Keep it in bounds
|
||||
if (xi < 0)
|
||||
xi = 0;
|
||||
@ -230,125 +245,45 @@ float CTerrain::getSlopeAngle( float x, float y ) const
|
||||
float h10 = m_Heightmap[yi*m_MapSize + xi + 1] * HEIGHT_SCALE;
|
||||
float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1] * HEIGHT_SCALE;
|
||||
|
||||
CVector3D flat, elevated;
|
||||
float low, high;
|
||||
|
||||
if ( h00 < h01 && h00 < h10 && h00 < h11 )
|
||||
low = h00;
|
||||
else if ( h01 < h10 && h01 < h11 )
|
||||
low = h01;
|
||||
else if ( h10 < h11 )
|
||||
low = h10;
|
||||
else
|
||||
low = h11;
|
||||
|
||||
//Find correct vector representing the flat version of the vector from low to high points
|
||||
if ( h00 > h01 && h00 > h10 && h00 > h11 )
|
||||
//Find heights
|
||||
if ( side == 0 || side == 7 )
|
||||
{
|
||||
high = h00;
|
||||
if ( low == h10 )
|
||||
flat = CVector3D( fCell, 0.0f, 0.0f );
|
||||
else if ( low == h01 )
|
||||
flat = CVector3D( 0.0f, 0.0f, fCell );
|
||||
else if ( low == h11 )
|
||||
flat = CVector3D( fCell, 0.0f, fCell );
|
||||
top = (h00 + h10)/2.0f;
|
||||
bottom = (h01 + h11)/2.0f;
|
||||
topZ = (h00 + h01)/2.0f;
|
||||
bottomZ = (h10 + h11)/2.0f;
|
||||
flat.Z = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
|
||||
flatZ.X = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
|
||||
}
|
||||
else if ( h01 > h10 && h01 > h11 )
|
||||
else if ( side == 1 || side == 2 )
|
||||
{
|
||||
high = h01;
|
||||
if ( low == h00 )
|
||||
flat = CVector3D( 0.0f, 0.0f, fCell );
|
||||
else if ( low == h01 )
|
||||
flat = CVector3D( fCell, 0.0f, fCell );
|
||||
else if ( low == h11 )
|
||||
flat = CVector3D( fCell, 0.0f, 0.0f );
|
||||
top = (h00 + h01)/2.0f;
|
||||
bottom = (h10 + h11)/2.0f;
|
||||
topZ = (h01 + h11)/2.0f;
|
||||
bottomZ = (h00 + h10)/2.0f;
|
||||
flat.X = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
|
||||
flatZ.Z = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
|
||||
}
|
||||
else if ( h10 > h11 )
|
||||
else if ( side == 3 || side == 4 )
|
||||
{
|
||||
high = h10;
|
||||
if ( low == h00 )
|
||||
flat = CVector3D( fCell, 0.0f, 0.0f );
|
||||
else if ( low == h01 )
|
||||
flat = CVector3D( fCell, 0.0f, fCell );
|
||||
else if ( low == h11 )
|
||||
flat = CVector3D( 0.0f, 0.0f, fCell );
|
||||
top = (h01 + h11)/2.0f;
|
||||
bottom = (h00 + h10)/2.0f;
|
||||
topZ = (h11 + h10)/2.0f;
|
||||
bottomZ = (h00 + h01)/2.0f;
|
||||
flat.Z = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
|
||||
flatZ.X = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
high = h11;
|
||||
if ( low == h10 )
|
||||
flat = CVector3D( 0.0f, 0.0f, fCell );
|
||||
else if ( low == h01 )
|
||||
flat = CVector3D( fCell, 0.0f, 0.0f );
|
||||
else if ( low == h00 )
|
||||
flat = CVector3D( fCell, 0.0f, fCell );
|
||||
top = (h11 + h10)/2.0f;
|
||||
bottom = (h00 + h01)/2.0f;
|
||||
topZ = (h00 + h10)/2.0f;
|
||||
bottomZ = (h01 + h11)/2.0f;
|
||||
flat.X = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
|
||||
flatZ.Z = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
|
||||
}
|
||||
elevated = flat;
|
||||
elevated.Y = high - low;
|
||||
elevated.Normalize();
|
||||
flat.Normalize();
|
||||
return acosf( flat.Dot( elevated ) );
|
||||
}
|
||||
float CTerrain::getSlopeAngleFace(float x, float y, float orientation) const
|
||||
{
|
||||
bool right; //true means use 0,0 and 1,1; false means use 1,0 and 0,1
|
||||
bool invert;
|
||||
float top, bottom;
|
||||
x /= (float)CELL_SIZE;
|
||||
y /= (float)CELL_SIZE;
|
||||
int xi = (int)floor(x);
|
||||
int yi = (int)floor(y);
|
||||
CVector3D flat( (float)CELL_SIZE, 0.0f, (float)CELL_SIZE );
|
||||
CVector3D elevated=flat;
|
||||
|
||||
/* JW: currently all unused, so commented out to avoid warning
|
||||
const float a0 = DEGTORAD(0.0f);
|
||||
const float a90 = DEGTORAD(90.0f);
|
||||
const float a180 = DEGTORAD(180.0f);
|
||||
const float neg = DEGTORAD(-90.0f);
|
||||
const float a45 = DEGTORAD(45.0f);
|
||||
const float a135 = DEGTORAD(135.0f);*/
|
||||
|
||||
//Find which side it's facing; use that and the opposite
|
||||
if ( orientation > 0.0f && orientation < DEGTORAD(90.0f) )
|
||||
right = true;
|
||||
else if ( orientation > DEGTORAD(90.0f) && orientation < DEGTORAD(180.0f) )
|
||||
right = false;
|
||||
else if ( orientation < DEGTORAD(-180.0f) && orientation > DEGTORAD(-90.0f) )
|
||||
right = true;
|
||||
else
|
||||
right = false;
|
||||
|
||||
//Keep it in bounds
|
||||
if (xi < 0)
|
||||
xi = 0;
|
||||
else if (xi >= (int)m_MapSize-1)
|
||||
xi = m_MapSize - 2;
|
||||
if (yi < 0)
|
||||
yi = 0;
|
||||
else if (yi >= (int)m_MapSize-1)
|
||||
yi = m_MapSize - 2;
|
||||
|
||||
if ( right )
|
||||
{
|
||||
bottom = m_Heightmap[yi*m_MapSize + xi]*HEIGHT_SCALE;
|
||||
top = m_Heightmap[yi*m_MapSize+m_MapSize + xi + 1]*HEIGHT_SCALE;
|
||||
if ( (orientation > DEGTORAD(-45.0f) && orientation < 0.0f) ||
|
||||
(orientation < DEGTORAD(135.0f) && orientation > 0.0f) )
|
||||
elevated.Y = top-bottom;
|
||||
else
|
||||
elevated.Y = bottom-top;
|
||||
}
|
||||
else
|
||||
{
|
||||
bottom = m_Heightmap[yi*m_MapSize + xi + 1]*HEIGHT_SCALE;
|
||||
top = m_Heightmap[yi*m_MapSize+m_MapSize + xi]*HEIGHT_SCALE;
|
||||
if ( (orientation > DEGTORAD(-135.0f) && orientation < 0.0f) ||
|
||||
(orientation < DEGTORAD(45.0f) && orientation > 0.0f) )
|
||||
elevated.Y = top-bottom;
|
||||
else
|
||||
elevated.Y = bottom-top;
|
||||
}
|
||||
elevated.Y = top-bottom;
|
||||
if ( elevated.Y > 0.0f )
|
||||
invert=false;
|
||||
else
|
||||
@ -356,12 +291,27 @@ float CTerrain::getSlopeAngleFace(float x, float y, float orientation) const
|
||||
elevated.Y = fabs(elevated.Y);
|
||||
elevated.Normalize();
|
||||
flat.Normalize();
|
||||
float ret = elevated.Dot(flat);
|
||||
if ( invert )
|
||||
ret.x = -acosf( elevated.Dot(flat) );
|
||||
else
|
||||
ret.x = acosf( elevated.Dot(flat) );
|
||||
|
||||
if (invert)
|
||||
return -acosf(ret);
|
||||
return acosf(ret);
|
||||
|
||||
//Z component
|
||||
elevated = flatZ;
|
||||
elevated.Y = topZ-bottomZ;
|
||||
if ( elevated.Y > 0.0f )
|
||||
invert=true;
|
||||
else
|
||||
invert=false;
|
||||
elevated.Y = fabs(elevated.Y);
|
||||
elevated.Normalize();
|
||||
flatZ.Normalize();
|
||||
if ( invert )
|
||||
ret.y = -acosf( elevated.Dot(flatZ) );
|
||||
else
|
||||
ret.y = acosf( elevated.Dot(flatZ) );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float CTerrain::getExactGroundLevel(float x, float z) const
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "Patch.h"
|
||||
#include "Vector3D.h"
|
||||
#include "Vector2D.h"
|
||||
#include "Entity.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CTerrain: main terrain class; contains the heightmap describing elevation
|
||||
@ -45,9 +46,8 @@ public:
|
||||
inline float getExactGroundLevel(const CVector2D& v) const { return getExactGroundLevel(v.x, v.y); }
|
||||
|
||||
float getSlope(float x, float z) const ;
|
||||
float getSlopeAngle( float x, float y) const; //In radians
|
||||
//Same as above, but picks the two vertices that the unit is facing (front+back) for slope
|
||||
float getSlopeAngleFace(float x, float y, float orientation) const;
|
||||
//Find the slope of in X and Z axes depending on the way the entity is facing
|
||||
CVector2D getSlopeAngleFace(float x, float y, CEntity*& entity) const;
|
||||
// resize this terrain such that each side has given number of patches
|
||||
void Resize(u32 size);
|
||||
|
||||
|
@ -73,7 +73,6 @@ PSRETURN CGame::RegisterInit(CGameAttributes* pAttribs)
|
||||
m_GameView->RegisterInit(pAttribs);
|
||||
m_World->RegisterInit(pAttribs);
|
||||
m_Simulation->RegisterInit(pAttribs);
|
||||
|
||||
LDR_EndRegistering();
|
||||
return 0;
|
||||
}
|
||||
|
@ -522,6 +522,7 @@ static void InitScripting()
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_HEAL", CEntityListener::NOTIFY_HEAL );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_GATHER", CEntityListener::NOTIFY_GATHER );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_IDLE", CEntityListener::NOTIFY_IDLE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ORDER_CHANGE", CEntityListener::NOTIFY_ORDER_CHANGE );
|
||||
g_ScriptingHost.DefineConstant( "NOTIFY_ALL", CEntityListener::NOTIFY_ALL );
|
||||
|
||||
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
|
||||
|
@ -23,6 +23,7 @@ enum EEventType
|
||||
EVENT_NOTIFICATION,
|
||||
EVENT_FORMATION,
|
||||
EVENT_IDLE,
|
||||
EVENT_MOVEMENT,
|
||||
EVENT_LAST,
|
||||
|
||||
// Projectile events
|
||||
@ -51,7 +52,9 @@ static const wchar_t* const EventNames[EVENT_LAST] =
|
||||
/* EVENT_ORDER_TRANSITION */ L"onOrderTransition", /* When we change orders (sometimes...) */
|
||||
/* EVENT_NOTIFICATION */ L"onNotification", /*When we receive a notification */
|
||||
/* EVENT_FORMATION */ L"onFormation", /* When this unit does something with a formation */
|
||||
/* EVENT_IDLE */ L"onIdle" /* When this unit becomes idle, do something */
|
||||
/* EVENT_IDLE */ L"onIdle", /* When this unit becomes idle, do something */
|
||||
/* EVENT_MOVEMENT */ L"onMovement" /*Triggered by processGotoHelper(), when unit moves */
|
||||
};
|
||||
|
||||
#endif // #ifndef EVENTTYPES_H__
|
||||
|
||||
|
@ -17,9 +17,9 @@ CBaseEntity::CBaseEntity()
|
||||
|
||||
AddProperty( L"tag", &m_Tag, false );
|
||||
AddProperty( L"parent", &m_base, false );
|
||||
AddProperty( L"actions.move.speed", &m_speed );
|
||||
AddProperty( L"actions.move.speed_curr", &m_speed );
|
||||
AddProperty( L"actions.move.turningradius", &m_turningRadius );
|
||||
AddProperty( L"actions.move.run.speed", &( m_run.m_Speed ) );
|
||||
AddProperty( L"actions.move.run.speed.curr", &( m_run.m_Speed ) );
|
||||
AddProperty( L"actions.move.run.rangemin", &( m_run.m_MinRange ) );
|
||||
AddProperty( L"actions.move.run.range", &( m_run.m_MaxRange ) );
|
||||
AddProperty( L"actions.move.run.regen_rate", &m_runRegenRate );
|
||||
@ -47,10 +47,8 @@ CBaseEntity::CBaseEntity()
|
||||
AddProperty( L"traits.stamina.border_height", &m_staminaBorderHeight);
|
||||
AddProperty( L"traits.stamina.border_width", &m_staminaBorderWidth );
|
||||
AddProperty( L"traits.stamina.border_name", &m_staminaBorderName );
|
||||
AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs );
|
||||
AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty );
|
||||
AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch );
|
||||
AddProperty( L"traits.pitch.min_actor", &m_minActorPitch );
|
||||
AddProperty( L"traits.flank_penalty.sectors", &m_sectorDivs );
|
||||
AddProperty( L"traits.pitch.sectors", &m_pitchDivs );
|
||||
AddProperty( L"traits.rank.width", &m_rankWidth );
|
||||
AddProperty( L"traits.rank.height", &m_rankHeight );
|
||||
AddProperty( L"traits.rank.name", &m_rankName );
|
||||
@ -59,6 +57,8 @@ CBaseEntity::CBaseEntity()
|
||||
AddProperty( L"traits.minimap.green", &m_minimapG );
|
||||
AddProperty( L"traits.minimap.blue", &m_minimapB );
|
||||
AddProperty( L"traits.anchor.type", &m_anchorType );
|
||||
AddProperty( L"traits.anchor.conformx", &m_anchorConformX );
|
||||
AddProperty( L"traits.anchor.conformz", &m_anchorConformZ );
|
||||
AddProperty( L"traits.vision.los", &m_los );
|
||||
AddProperty( L"traits.vision.permanent", &m_permanent );
|
||||
AddProperty( L"traits.foundation", &m_foundation );
|
||||
@ -76,6 +76,7 @@ CBaseEntity::CBaseEntity()
|
||||
m_foundation = CStrW();
|
||||
|
||||
// Sentinel values for stamina and health (so scripts can check if an entity has no stamina or no HP).
|
||||
m_speed=0;
|
||||
m_staminaCurr = 0;
|
||||
m_staminaMax = 0;
|
||||
m_healthCurr = 0;
|
||||
|
@ -111,10 +111,9 @@ public:
|
||||
SEntityAction m_generic;
|
||||
|
||||
int m_sectorDivs;
|
||||
float m_sectorPenalty;
|
||||
|
||||
float m_maxActorPitch;
|
||||
float m_minActorPitch;
|
||||
int m_pitchDivs;
|
||||
float m_anchorConformX;
|
||||
float m_anchorConformZ;
|
||||
|
||||
float m_turningRadius;
|
||||
CScriptObject m_EventHandlers[EVENT_LAST];
|
||||
|
@ -26,9 +26,11 @@ bool CBaseFormation::loadXML(CStr filename)
|
||||
|
||||
AT(tag);
|
||||
AT(bonus);
|
||||
AT(bonusbase);
|
||||
AT(bonustype);
|
||||
AT(bonusval);
|
||||
AT(penalty);
|
||||
AT(penaltybase);
|
||||
AT(penaltytype);
|
||||
AT(penaltyval);
|
||||
AT(anglepenalty);
|
||||
@ -63,12 +65,16 @@ bool CBaseFormation::loadXML(CStr filename)
|
||||
m_tag = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_bonus )
|
||||
m_bonus = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_bonusbase )
|
||||
m_bonusBase = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_bonustype )
|
||||
m_bonusType = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_bonusval )
|
||||
m_bonusVal = CStr(Attr.Value).ToFloat();
|
||||
else if ( Attr.Name == at_penalty )
|
||||
m_penalty = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_penaltybase )
|
||||
m_penaltyBase = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_penaltytype )
|
||||
m_penaltyType = CStr(Attr.Value);
|
||||
else if ( Attr.Name == at_penaltyval )
|
||||
@ -200,4 +206,4 @@ void CBaseFormation::AssignCategory(int order, CStr category)
|
||||
size_t off = category.find(temp);
|
||||
category.erase( off, temp.length() );
|
||||
}
|
||||
}
|
||||
}
|
@ -29,10 +29,12 @@ public:
|
||||
~CBaseFormation(){}
|
||||
|
||||
CStr GetBonus(){ return m_bonus; }
|
||||
CStr GetBonusBase(){ return m_bonusBase; }
|
||||
CStr GetBonusType(){ return m_bonusType; }
|
||||
float GetBonusVal(){ return m_bonusVal; }
|
||||
|
||||
CStr GetPenalty(){ return m_penalty; }
|
||||
CStr GetPenaltyBase(){ return m_penaltyBase; }
|
||||
CStr GetPenaltyType(){ return m_penaltyType; }
|
||||
float GetPenaltyVal(){ return m_penaltyVal; }
|
||||
|
||||
@ -46,10 +48,12 @@ private:
|
||||
|
||||
CStr m_tag;
|
||||
CStr m_bonus;
|
||||
CStr m_bonusBase;
|
||||
CStr m_bonusType;
|
||||
float m_bonusVal;
|
||||
|
||||
CStr m_penalty;
|
||||
CStr m_penaltyBase;
|
||||
CStr m_penaltyType;
|
||||
float m_penaltyVal;
|
||||
|
||||
@ -71,9 +75,9 @@ private:
|
||||
|
||||
//The key is the "order" of the slot
|
||||
std::map<int, FormationSlot> m_slots;
|
||||
std::vector<float> m_angleValues; //cosine of angle divisions
|
||||
|
||||
bool loadXML(CStr filename);
|
||||
void AssignCategory(int order, CStr category); //takes care of formatting strings
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -36,21 +36,20 @@ using namespace std;
|
||||
CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, CStrW building )
|
||||
{
|
||||
m_position = position;
|
||||
m_orientation = orientation;
|
||||
m_ahead.x = sin( m_orientation );
|
||||
m_ahead.y = cos( m_orientation );
|
||||
m_orientation.Y = orientation;
|
||||
m_ahead.x = sin( m_orientation.Y );
|
||||
m_ahead.y = cos( m_orientation.Y );
|
||||
|
||||
// set sane default in case someone forgets to add this to the entity's
|
||||
// XML file, which is prone to happen. (prevents crash below when
|
||||
// using this value to resize a vector)
|
||||
const int sane_sectordivs_default = 4;
|
||||
m_sectorDivs = sane_sectordivs_default;
|
||||
|
||||
/* Anything added to this list MUST be added to BaseEntity.cpp (and variables used should
|
||||
also be added to BaseEntity.h */
|
||||
|
||||
AddProperty( L"actions.move.speed", &m_speed );
|
||||
AddProperty( L"actions.move.run.speed", &( m_run.m_Speed ) );
|
||||
|
||||
AddProperty( L"actions.move.speed_curr", &m_speed );
|
||||
AddProperty( L"actions.move.run.speed.curr", &( m_run.m_Speed ) );
|
||||
AddProperty( L"actions.move.run.rangemin", &( m_run.m_MinRange ) );
|
||||
AddProperty( L"actions.move.run.range", &( m_run.m_MaxRange ) );
|
||||
AddProperty( L"actions.move.run.regen_rate", &m_runRegenRate );
|
||||
@ -61,7 +60,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
AddProperty( L"traits.corpse", &m_corpse );
|
||||
AddProperty( L"actions.move.turningradius", &m_turningRadius );
|
||||
AddProperty( L"position", &m_graphics_position, false, (NotifyFn)&CEntity::teleport );
|
||||
AddProperty( L"orientation", &m_graphics_orientation, false, (NotifyFn)&CEntity::reorient );
|
||||
AddProperty( L"orientation", &(m_orientation.Y), false, (NotifyFn)&CEntity::reorient );
|
||||
AddProperty( L"player", &m_player, false, (NotifyFn)&CEntity::playerChanged );
|
||||
AddProperty( L"traits.health.curr", &m_healthCurr );
|
||||
AddProperty( L"traits.health.max", &m_healthMax );
|
||||
@ -83,10 +82,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
AddProperty( L"traits.stamina.border_height", &m_staminaBorderHeight);
|
||||
AddProperty( L"traits.stamina.border_width", &m_staminaBorderWidth );
|
||||
AddProperty( L"traits.stamina.border_name", &m_staminaBorderName );
|
||||
AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs);
|
||||
AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty );
|
||||
AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch );
|
||||
AddProperty( L"traits.pitch.min_actor", &m_minActorPitch );
|
||||
AddProperty( L"traits.flank_penalty.sectors", &m_sectorDivs);
|
||||
AddProperty( L"traits.pitch.sectors", &m_pitchDivs );
|
||||
AddProperty( L"traits.rank.width", &m_rankWidth );
|
||||
AddProperty( L"traits.rank.height", &m_rankHeight );
|
||||
AddProperty( L"traits.rank.name", &m_rankName );
|
||||
@ -95,6 +92,9 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
AddProperty( L"traits.minimap.green", &m_minimapG );
|
||||
AddProperty( L"traits.minimap.blue", &m_minimapB );
|
||||
AddProperty( L"traits.anchor.type", &m_anchorType );
|
||||
AddProperty( L"traits.anchor.conformx", &m_anchorConformX );
|
||||
AddProperty( L"traits.anchor.conformz", &m_anchorConformZ );
|
||||
|
||||
AddProperty( L"traits.vision.los", &m_los );
|
||||
AddProperty( L"traits.vision.permanent", &m_permanent );
|
||||
AddProperty( L"last_combat_time", &m_lastCombatTime );
|
||||
@ -109,23 +109,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
AddHandler( t, &m_EventHandlers[t] );
|
||||
}
|
||||
|
||||
// this has been the cause of several crashes (due to not being
|
||||
// specified in the XML file), so in addition to the above default,
|
||||
// we'll sanity check its value.
|
||||
if(!(0 <= m_sectorDivs && m_sectorDivs < 1000))
|
||||
{
|
||||
debug_warn("invalid entity angle_penalty.sectors value");
|
||||
m_sectorDivs = sane_sectordivs_default;
|
||||
}
|
||||
m_sectorAngles.resize(m_sectorDivs);
|
||||
m_sectorValues.resize(m_sectorDivs);
|
||||
float step = DEGTORAD(360.0f / m_sectorDivs);
|
||||
for ( int i=0; i<m_sectorDivs; ++i )
|
||||
{
|
||||
m_sectorAngles[i] = cosf( step*i );
|
||||
m_sectorValues[i] = false;
|
||||
}
|
||||
|
||||
m_collisionPatch = NULL;
|
||||
|
||||
// Set our parent unit and build us an actor.
|
||||
@ -141,6 +124,18 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
m_actorSelections = actorSelections;
|
||||
loadBase();
|
||||
|
||||
// this has been the cause of several crashes (due to not being
|
||||
// specified in the XML file), so in addition to the above default,
|
||||
// we'll sanity check its value.
|
||||
if(!(0 <= m_sectorDivs && m_sectorDivs < 360))
|
||||
{
|
||||
debug_warn("invalid entity flank_penalty.sectors value");
|
||||
m_sectorDivs = sane_sectordivs_default;
|
||||
}
|
||||
m_sectorValues.resize(m_sectorDivs);
|
||||
for ( int i=0; i<m_sectorDivs; ++i )
|
||||
m_sectorValues[i] = false;
|
||||
|
||||
if( m_bounds )
|
||||
m_bounds->setPosition( m_position.X, m_position.Z );
|
||||
|
||||
@ -151,7 +146,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
m_graphics_orientation = m_orientation;
|
||||
m_actor_transform_valid = false;
|
||||
|
||||
m_pitchOrientation = m_pitchOrientation_previous = m_graphics_pitchOrientation = 0.0f;
|
||||
m_destroyed = false;
|
||||
|
||||
m_selected = false;
|
||||
@ -172,7 +166,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
|
||||
m_grouped = -1;
|
||||
|
||||
m_building = building;
|
||||
|
||||
|
||||
m_player = g_Game->GetPlayer( 0 );
|
||||
|
||||
Initialize();
|
||||
@ -198,7 +192,8 @@ CEntity::~CEntity()
|
||||
delete it->second;
|
||||
}
|
||||
m_auras.clear();
|
||||
|
||||
|
||||
m_destroyNotifiers=true;
|
||||
for ( size_t i=0; i<m_listeners.size(); i++ )
|
||||
m_listeners[i].m_sender->DestroyNotifier( this );
|
||||
DestroyAllNotifiers();
|
||||
@ -249,7 +244,10 @@ void CEntity::kill()
|
||||
|
||||
CEntity* remove = this;
|
||||
g_FormationManager.RemoveUnit(remove);
|
||||
|
||||
|
||||
m_destroyNotifiers=true;
|
||||
for ( size_t i=0; i<m_listeners.size(); i++ )
|
||||
m_listeners[i].m_sender->DestroyNotifier( this );
|
||||
DestroyAllNotifiers();
|
||||
|
||||
if( m_bounds )
|
||||
@ -286,22 +284,22 @@ void CEntity::SetPlayer(CPlayer *pPlayer)
|
||||
void CEntity::updateActorTransforms()
|
||||
{
|
||||
CMatrix3D m;
|
||||
CMatrix3D mX;
|
||||
float Cos = cosf( m_graphics_orientation );
|
||||
float Sin = sinf( m_graphics_orientation );
|
||||
CMatrix3D mXZ;
|
||||
float Cos = cosf( m_graphics_orientation.Y );
|
||||
float Sin = sinf( m_graphics_orientation.Y );
|
||||
|
||||
m._11=-Cos; m._12=0.0f; m._13=-Sin; m._14=0.0f;
|
||||
m._21=0.0f; m._22=1.0f; m._23=0.0f; m._24=0.0f;
|
||||
m._31=Sin; m._32=0.0f; m._33=-Cos; m._34=0.0f;
|
||||
m._41=0.0f; m._42=0.0f; m._43=0.0f; m._44=1.0f;
|
||||
|
||||
mX.SetXRotation( m_graphics_pitchOrientation );
|
||||
mX = m*mX;
|
||||
mX.Translate(m_graphics_position);
|
||||
//m.RotateX(m_graphics_pitchOrientation);
|
||||
mXZ.SetXRotation( m_graphics_orientation.X );
|
||||
mXZ.RotateZ( m_graphics_orientation.Z );
|
||||
mXZ = m*mXZ;
|
||||
mXZ.Translate(m_graphics_position);
|
||||
|
||||
if( m_actor )
|
||||
m_actor->GetModel()->SetTransform( mX );
|
||||
m_actor->GetModel()->SetTransform( mXZ );
|
||||
}
|
||||
|
||||
void CEntity::snapToGround()
|
||||
@ -384,7 +382,6 @@ void CEntity::update( size_t timestep )
|
||||
{
|
||||
m_position_previous = m_position;
|
||||
m_orientation_previous = m_orientation;
|
||||
m_pitchOrientation_previous = m_pitchOrientation;
|
||||
|
||||
CalculateRun( timestep );
|
||||
CalculateHealth( timestep );
|
||||
@ -756,7 +753,7 @@ struct isListenerSender
|
||||
|
||||
int CEntity::DestroyNotifier( CEntity* target )
|
||||
{
|
||||
if (target->m_listeners.empty() || !m_destroyNotifiers)
|
||||
if ( target->m_listeners.empty() )
|
||||
return 0;
|
||||
//Stop listening
|
||||
// (Don't just loop and use 'erase', because modifying the deque while
|
||||
@ -812,9 +809,9 @@ void CEntity::repath()
|
||||
void CEntity::reorient()
|
||||
{
|
||||
m_orientation = m_graphics_orientation;
|
||||
m_pitchOrientation = m_graphics_pitchOrientation;
|
||||
m_ahead.x = sin( m_orientation );
|
||||
m_ahead.y = cos( m_orientation );
|
||||
|
||||
m_ahead.x = sin( m_orientation.Y );
|
||||
m_ahead.y = cos( m_orientation.Y );
|
||||
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
||||
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
|
||||
updateActorTransforms();
|
||||
@ -858,24 +855,27 @@ void CEntity::checkGroup()
|
||||
void CEntity::interpolate( float relativeoffset )
|
||||
{
|
||||
CVector3D old_graphics_position = m_graphics_position;
|
||||
float old_graphics_orientation = m_graphics_orientation;
|
||||
float old_graphics_pitchOrientation = m_graphics_pitchOrientation;
|
||||
|
||||
CVector3D old_graphics_orientation = m_graphics_orientation;
|
||||
|
||||
m_graphics_position = Interpolate<CVector3D>( m_position_previous, m_position, relativeoffset );
|
||||
|
||||
// Avoid wraparound glitches for interpolating angles.
|
||||
while( m_orientation < m_orientation_previous - PI )
|
||||
m_orientation_previous -= 2 * PI;
|
||||
while( m_orientation > m_orientation_previous + PI )
|
||||
m_orientation_previous += 2 * PI;
|
||||
while( m_orientation.Y < m_orientation_previous.Y - PI )
|
||||
m_orientation_previous.Y -= 2 * PI;
|
||||
while( m_orientation.Y > m_orientation_previous.Y + PI )
|
||||
m_orientation_previous.Y += 2 * PI;
|
||||
|
||||
while( m_pitchOrientation < m_pitchOrientation_previous - PI )
|
||||
m_pitchOrientation_previous -= 2 * PI;
|
||||
while( m_pitchOrientation > m_pitchOrientation_previous + PI )
|
||||
m_pitchOrientation_previous += 2 * PI;
|
||||
while( m_orientation.X < m_orientation_previous.X - PI )
|
||||
m_orientation_previous.X -= 2 * PI;
|
||||
while( m_orientation.X > m_orientation_previous.X + PI )
|
||||
m_orientation_previous.X += 2 * PI;
|
||||
|
||||
m_graphics_orientation = Interpolate<float>( m_orientation_previous, m_orientation, relativeoffset );
|
||||
m_graphics_pitchOrientation = Interpolate<float>( m_pitchOrientation_previous, m_pitchOrientation, relativeoffset );
|
||||
while( m_orientation.Z < m_orientation_previous.Z - PI )
|
||||
m_orientation_previous.Z -= 2 * PI;
|
||||
while( m_orientation.Z > m_orientation_previous.Z + PI )
|
||||
m_orientation_previous.Z += 2 * PI;
|
||||
|
||||
m_graphics_orientation = Interpolate<CVector3D>( m_orientation_previous, m_orientation, relativeoffset );
|
||||
|
||||
// Mark the actor transform data as invalid if the entity has moved since
|
||||
// the last call to 'interpolate'.
|
||||
@ -884,8 +884,7 @@ void CEntity::interpolate( float relativeoffset )
|
||||
// handle flying units or moving terrain.
|
||||
if( m_graphics_orientation != old_graphics_orientation ||
|
||||
m_graphics_position.X != old_graphics_position.X ||
|
||||
m_graphics_position.Z != old_graphics_position.Z ||
|
||||
m_graphics_pitchOrientation != old_graphics_pitchOrientation
|
||||
m_graphics_position.Z != old_graphics_position.Z
|
||||
)
|
||||
{
|
||||
m_actor_transform_valid = false;
|
||||
@ -999,7 +998,39 @@ float CEntity::getAnchorLevel( float x, float z )
|
||||
return max( groundLevel, g_Renderer.GetWaterManager()->m_WaterHeight );
|
||||
}
|
||||
}
|
||||
|
||||
int CEntity::findSector( int divs, float angle, float maxAngle, bool negative )
|
||||
{
|
||||
float step=maxAngle/divs;
|
||||
if ( negative )
|
||||
{
|
||||
float tracker;
|
||||
int i=1, sectorRemainder;
|
||||
for ( tracker=-maxAngle/2.0f; tracker+step<0.0f; tracker+=step, ++i )
|
||||
{
|
||||
if ( angle > tracker && angle <= tracker+step )
|
||||
return i;
|
||||
}
|
||||
sectorRemainder = i;
|
||||
i=divs;
|
||||
for ( tracker=maxAngle/2.0f; tracker-step>0.0f; tracker-=step, --i )
|
||||
{
|
||||
if ( angle < tracker && angle >= tracker-step )
|
||||
return i;
|
||||
}
|
||||
return sectorRemainder;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i=0;
|
||||
for ( float tracker=0.0f; tracker<maxAngle; tracker+=step, ++i )
|
||||
{
|
||||
if ( angle > tracker && angle <= tracker+step )
|
||||
return i;
|
||||
}
|
||||
}
|
||||
debug_warn("CEntity::findSector() - invalid parameters passed.");
|
||||
return -1;
|
||||
}
|
||||
void CEntity::renderSelectionOutline( float alpha )
|
||||
{
|
||||
if( !m_bounds )
|
||||
@ -1047,8 +1078,8 @@ void CEntity::renderSelectionOutline( float alpha )
|
||||
float d = ((CBoundingBox*)m_bounds)->m_d;
|
||||
float w = ((CBoundingBox*)m_bounds)->m_w;
|
||||
|
||||
u.x = sin( m_graphics_orientation );
|
||||
u.y = cos( m_graphics_orientation );
|
||||
u.x = sin( m_graphics_orientation.Y );
|
||||
u.y = cos( m_graphics_orientation.Y );
|
||||
v.x = u.y;
|
||||
v.y = -u.x;
|
||||
|
||||
@ -1316,6 +1347,7 @@ void CEntity::ScriptingInit()
|
||||
AddMethod<jsval, &CEntity::AddAura>( "addAura", 3 );
|
||||
AddMethod<jsval, &CEntity::RemoveAura>( "removeAura", 1 );
|
||||
AddMethod<jsval, &CEntity::SetActionParams>( "setActionParams", 5 );
|
||||
AddMethod<int, &CEntity::GetCurrentRequest>( "getCurrentRequest", 0 );
|
||||
AddMethod<bool, &CEntity::ForceCheckListeners>( "forceCheckListeners", 2 );
|
||||
AddMethod<bool, &CEntity::RequestNotification>( "requestNotification", 4 );
|
||||
AddMethod<jsval, &CEntity::DestroyNotifier>( "destroyNotifier", 1 );
|
||||
@ -1331,7 +1363,9 @@ void CEntity::ScriptingInit()
|
||||
AddMethod<jsval, &CEntity::GetFormationPenaltyType>( "getFormationPenaltyType", 0 );
|
||||
AddMethod<jsval, &CEntity::GetFormationPenaltyVal>( "getFormationPenaltyVal", 0 );
|
||||
AddMethod<jsval, &CEntity::RegisterDamage>( "registerDamage", 0 );
|
||||
AddMethod<jsval, &CEntity::RegisterIdle>( "registerIdle", 0 );
|
||||
AddMethod<jsval, &CEntity::RegisterOrderChange>( "registerOrderChange", 0 );
|
||||
AddMethod<jsval, &CEntity::GetAttackDirections>( "getAttackDirections", 0 );
|
||||
AddMethod<jsval, &CEntity::FindSector>("findSector", 4);
|
||||
|
||||
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
|
||||
AddClassProperty( L"traits.id.classes", (GetFn)&CEntity::getClassSet, (SetFn)&CEntity::setClassSet );
|
||||
@ -1793,8 +1827,7 @@ bool CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv )
|
||||
CEntity *target = ToNative<CEntity>( argv[0] );
|
||||
(int&)notify.m_type = ToPrimitive<int>( argv[1] );
|
||||
bool tmpDestroyNotifiers = ToPrimitive<bool>( argv[2] );
|
||||
// TODO: ??? This local variable overrides the member variable of the same name...
|
||||
bool m_destroyNotifiers = !ToPrimitive<bool>( argv[3] );
|
||||
m_destroyNotifiers = !ToPrimitive<bool>( argv[3] );
|
||||
|
||||
if (target == this)
|
||||
return false;
|
||||
@ -1840,6 +1873,10 @@ bool CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv )
|
||||
target->m_listeners.push_back( notify );
|
||||
return false;
|
||||
}
|
||||
int CEntity::GetCurrentRequest( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
{
|
||||
return m_currentRequest;
|
||||
}
|
||||
bool CEntity::ForceCheckListeners( JSContext *cx, uintN argc, jsval* argv )
|
||||
{
|
||||
if( argc < 2 )
|
||||
@ -1952,6 +1989,10 @@ jsval CEntity::GetFormationPenalty( JSContext* UNUSED(cx), uintN UNUSED(argc), j
|
||||
{
|
||||
return ToJSVal( GetFormation()->GetBase()->GetPenalty() );
|
||||
}
|
||||
jsval CEntity::GetFormationPenaltyBase( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
{
|
||||
return ToJSVal( GetFormation()->GetBase()->GetPenaltyBase() );
|
||||
}
|
||||
jsval CEntity::GetFormationPenaltyType( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
{
|
||||
return ToJSVal( GetFormation()->GetBase()->GetPenaltyType() );
|
||||
@ -1964,6 +2005,10 @@ jsval CEntity::GetFormationBonus( JSContext* UNUSED(cx), uintN UNUSED(argc), jsv
|
||||
{
|
||||
return ToJSVal( GetFormation()->GetBase()->GetBonus() );
|
||||
}
|
||||
jsval CEntity::GetFormationBonusBase( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
{
|
||||
return ToJSVal( GetFormation()->GetBase()->GetBonusBase() );
|
||||
}
|
||||
jsval CEntity::GetFormationBonusType( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
{
|
||||
return ToJSVal( GetFormation()->GetBase()->GetBonusType() );
|
||||
@ -1985,19 +2030,13 @@ jsval CEntity::RegisterDamage( JSContext* cx, uintN argc, jsval* argv )
|
||||
CVector2D pos = CVector2D( inflictor->m_position.X, inflictor->m_position.Z );
|
||||
CVector2D posDelta = (pos - m_position).normalize();
|
||||
|
||||
float angle = up.dot(posDelta);
|
||||
float angle = acosf( up.dot(posDelta) );
|
||||
//Find what section it is between and "activate" it
|
||||
for ( int i=0; i<m_sectorDivs; ++i )
|
||||
{
|
||||
//Wrap around to the start-if we've made it this far, it's here
|
||||
if ( i == m_base->m_sectorDivs )
|
||||
m_sectorValues[i] = true;
|
||||
else if ( angle > m_sectorAngles[i] && angle < m_sectorAngles[i+1] )
|
||||
m_sectorValues[i] = true;
|
||||
}
|
||||
int sector = findSector(m_sectorDivs, angle, DEGTORAD(360.0f))-1;
|
||||
m_sectorValues[sector]=true;
|
||||
return JS_TRUE;
|
||||
}
|
||||
jsval CEntity::RegisterIdle( JSContext* cx, uintN argc, jsval* argv )
|
||||
jsval CEntity::RegisterOrderChange( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
if ( argc < 1 )
|
||||
{
|
||||
@ -2010,16 +2049,10 @@ jsval CEntity::RegisterIdle( JSContext* cx, uintN argc, jsval* argv )
|
||||
CVector2D pos = CVector2D( idleEntity->m_position.X, idleEntity->m_position.Z );
|
||||
CVector2D posDelta = (pos - m_position).normalize();
|
||||
|
||||
float angle = up.dot(posDelta);
|
||||
//Find what section it is between and "activate" it
|
||||
for ( int i=0; i<m_sectorDivs; ++i )
|
||||
{
|
||||
//Wrap around to the start-if we've made it this far, it's here
|
||||
if ( i == m_base->m_sectorDivs )
|
||||
m_sectorValues[i] = false;
|
||||
else if ( angle > m_sectorAngles[i] && angle < m_sectorAngles[i+1] )
|
||||
m_sectorValues[i] = false;
|
||||
}
|
||||
float angle = acosf( up.dot(posDelta) );
|
||||
//Find what section it is between and "deactivate" it
|
||||
int sector = MAX( 0.0, findSector(m_sectorDivs, angle, DEGTORAD(360.0f)) );
|
||||
m_sectorValues[sector]=false;
|
||||
return JS_TRUE;
|
||||
}
|
||||
jsval CEntity::GetAttackDirections( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
@ -2033,3 +2066,46 @@ jsval CEntity::GetAttackDirections( JSContext* UNUSED(cx), uintN UNUSED(argc), j
|
||||
}
|
||||
return ToJSVal( directions );
|
||||
}
|
||||
jsval CEntity::FindSector( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
if ( argc < 4 )
|
||||
{
|
||||
JS_ReportError( cx, "Too few parameters" );
|
||||
return( false );
|
||||
}
|
||||
int divs = ToPrimitive<int>( argv[0] );
|
||||
float angle = ToPrimitive<float>( argv[1] );
|
||||
float maxAngle = ToPrimitive<float>( argv[2] );
|
||||
bool negative = ToPrimitive<bool>( argv[3] );
|
||||
float step = maxAngle/divs;
|
||||
|
||||
if ( negative )
|
||||
{
|
||||
float tracker;
|
||||
int i=1, sectorRemainder;
|
||||
for ( tracker=-maxAngle/2.0f; tracker+step<0.0f; tracker+=step, ++i )
|
||||
{
|
||||
if ( angle > tracker && angle <= tracker+step )
|
||||
return ToJSVal(i);
|
||||
}
|
||||
sectorRemainder = i;
|
||||
i=divs;
|
||||
for ( tracker=maxAngle/2.0f; tracker-step>0.0f; tracker-=step, --i )
|
||||
{
|
||||
if ( angle < tracker && angle >= tracker-step )
|
||||
return ToJSVal(i);
|
||||
}
|
||||
return ToJSVal(sectorRemainder);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i=1;
|
||||
for ( float tracker=0.0f; tracker<maxAngle; tracker+=step, ++i )
|
||||
{
|
||||
if ( angle > tracker && angle <= tracker+step )
|
||||
return ToJSVal(i);
|
||||
}
|
||||
}
|
||||
debug_warn("JS - FindSector(): invalid parameters");
|
||||
return ToJSVal(-1);
|
||||
}
|
||||
|
@ -149,6 +149,8 @@ public:
|
||||
|
||||
// Y anchor
|
||||
CStrW m_anchorType;
|
||||
float m_anchorConformX;
|
||||
float m_anchorConformZ;
|
||||
|
||||
// LOS
|
||||
int m_los;
|
||||
@ -168,13 +170,12 @@ public:
|
||||
CVector2D m_ahead;
|
||||
|
||||
//-- Interpolated property
|
||||
float m_orientation;
|
||||
float m_orientation_previous;
|
||||
float m_graphics_orientation;
|
||||
CVector3D m_orientation;
|
||||
CVector3D m_orientation_previous;
|
||||
CVector3D m_graphics_orientation;
|
||||
|
||||
float m_pitchOrientation;
|
||||
float m_pitchOrientation_previous;
|
||||
float m_graphics_pitchOrientation;
|
||||
CVector2D m_orientation_unclamped;
|
||||
|
||||
|
||||
// If the actor's current transform data is valid (i.e. the entity hasn't
|
||||
// moved since it was last calculated, and the terrain hasn't been changed).
|
||||
@ -213,9 +214,9 @@ public:
|
||||
bool m_destroyNotifiers; //True: we destroy them. False: the script does.
|
||||
|
||||
std::vector<bool> m_sectorValues;
|
||||
std::vector<float> m_sectorAngles;
|
||||
int m_sectorDivs;
|
||||
float m_sectorPenalty;
|
||||
|
||||
int m_pitchDivs;
|
||||
|
||||
private:
|
||||
CEntity( CBaseEntity* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, CStrW building = L"" );
|
||||
@ -317,21 +318,26 @@ public:
|
||||
int DestroyNotifier( CEntity* target ); //Stop notifier from sending to us
|
||||
void DestroyAllNotifiers();
|
||||
|
||||
int findSector( int divs, float angle, float maxAngle, bool negative=true );
|
||||
|
||||
CEntityFormation* GetFormation();
|
||||
bool IsInClass( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationPenalty( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationPenaltyBase( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationPenaltyType( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationPenaltyVal( JSContext* cx, uintN argc, jsval* argv );
|
||||
|
||||
jsval GetFormationBonus( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationBonusBase( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationBonusType( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetFormationBonusVal( JSContext* cx, uintN argc, jsval* argv );
|
||||
|
||||
void DispatchFormationEvent( int type );
|
||||
|
||||
jsval RegisterDamage( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval RegisterIdle( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval RegisterOrderChange( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetAttackDirections( JSContext* cx, uintN argc, jsval* argv );
|
||||
|
||||
jsval FindSector( JSContext* cx, uintN argc, jsval* argv );
|
||||
// Script constructor
|
||||
|
||||
static JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval );
|
||||
@ -355,6 +361,7 @@ public:
|
||||
bool RequestNotification( JSContext* cx, uintN argc, jsval* argv );
|
||||
//Just in case we want to explicitly check the listeners without waiting for the order to be pushed
|
||||
bool ForceCheckListeners( JSContext* cx, uintN argc, jsval* argv );
|
||||
int GetCurrentRequest( JSContext* cx, uintN argc, jsval* argv );
|
||||
void CheckListeners( int type, CEntity *target );
|
||||
jsval DestroyAllNotifiers( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval DestroyNotifier( JSContext* cx, uintN argc, jsval* argv );
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "Profile.h"
|
||||
#include "Terrain.h"
|
||||
#include "Game.h"
|
||||
|
||||
#include "MathUtil.h"
|
||||
int SELECTION_CIRCLE_POINTS;
|
||||
int SELECTION_BOX_POINTS;
|
||||
int SELECTION_SMOOTHNESS_UNIFIED = 9;
|
||||
@ -284,6 +284,30 @@ void CEntityManager::renderAll()
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
m_entities[i].m_entity->render();
|
||||
}
|
||||
void CEntityManager::conformAll()
|
||||
{
|
||||
PROFILE_START("conform all");
|
||||
for ( int i=0; i < MAX_HANDLES; i++ )
|
||||
{
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
{
|
||||
CEntity* entity = m_entities[i].m_entity;
|
||||
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( entity->m_position.X, entity->m_position.Z, entity );
|
||||
|
||||
while( targetXZ.x > PI ) targetXZ.x -= 2 * PI;
|
||||
while( targetXZ.x < -PI ) targetXZ.x += 2 * PI;
|
||||
while( targetXZ.y > PI ) targetXZ.y -= 2 * PI;
|
||||
while( targetXZ.y < -PI ) targetXZ.y += 2 * PI;
|
||||
|
||||
entity->m_orientation.X = clamp( targetXZ.x, -entity->m_anchorConformX, entity->m_anchorConformX );
|
||||
entity->m_orientation.Z = clamp( targetXZ.y, -entity->m_anchorConformZ, entity->m_anchorConformZ );
|
||||
entity->m_orientation_unclamped.x = targetXZ.x;
|
||||
entity->m_orientation_unclamped.y = targetXZ.y;
|
||||
entity->updateActorTransforms();
|
||||
}
|
||||
}
|
||||
PROFILE_END("conform all");
|
||||
}
|
||||
|
||||
void CEntityManager::invalidateAll()
|
||||
{
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
void InitializeAll();
|
||||
void TickAll();
|
||||
void renderAll();
|
||||
void conformAll();
|
||||
void invalidateAll();
|
||||
|
||||
void deleteAll();
|
||||
|
@ -68,7 +68,8 @@ public:
|
||||
NOTIFY_HEAL = 0x10,
|
||||
NOTIFY_GATHER = 0x20,
|
||||
|
||||
NOTIFY_IDLE = 0x40,
|
||||
NOTIFY_IDLE = 0x40,
|
||||
NOTIFY_ORDER_CHANGE = 0x80, //this isn't counted in NOTIFY_ALL
|
||||
NOTIFY_ALL = 0x7F
|
||||
|
||||
} m_type;
|
||||
|
@ -95,7 +95,7 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
|
||||
// trig every time.right
|
||||
|
||||
m_targetorientation = atan2( delta.x, delta.y );
|
||||
float deltatheta = m_targetorientation - (float)m_orientation;
|
||||
float deltatheta = m_targetorientation - (float)m_orientation.Y;
|
||||
while( deltatheta > PI ) deltatheta -= 2 * PI;
|
||||
while( deltatheta < -PI ) deltatheta += 2 * PI;
|
||||
|
||||
@ -106,10 +106,10 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
|
||||
float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep;
|
||||
deltatheta = clamp( deltatheta, -maxTurningSpeed, maxTurningSpeed );
|
||||
}
|
||||
m_orientation = m_orientation + deltatheta;
|
||||
m_orientation.Y = m_orientation.Y + deltatheta;
|
||||
|
||||
m_ahead.x = sin( m_orientation );
|
||||
m_ahead.y = cos( m_orientation );
|
||||
m_ahead.x = sin( m_orientation.Y );
|
||||
m_ahead.y = cos( m_orientation.Y );
|
||||
|
||||
// We can only really attempt to smooth paths the pathfinder
|
||||
// has flagged for us. If the turning-radius calculations are
|
||||
@ -127,20 +127,29 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
|
||||
// let's not.
|
||||
|
||||
if( current->m_type != CEntityOrder::ORDER_GOTO_SMOOTHED )
|
||||
m_orientation = m_targetorientation;
|
||||
m_orientation.Y = m_targetorientation;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ahead = delta / len;
|
||||
m_orientation = m_targetorientation;
|
||||
m_orientation.Y = m_targetorientation;
|
||||
}
|
||||
CEntity* _this = this;
|
||||
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( m_position.X, m_position.Z, _this );
|
||||
|
||||
float targetpitch = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( m_position.X, m_position.Z, m_orientation );
|
||||
while( targetpitch > PI ) targetpitch -= 2 * PI;
|
||||
while( targetpitch < -PI ) targetpitch += 2 * PI;
|
||||
m_pitchOrientation = clamp( targetpitch, m_minActorPitch, m_maxActorPitch );
|
||||
while( targetXZ.x > PI ) targetXZ.x -= 2 * PI;
|
||||
while( targetXZ.x < -PI ) targetXZ.x += 2 * PI;
|
||||
while( targetXZ.y > PI ) targetXZ.y -= 2 * PI;
|
||||
while( targetXZ.y < -PI ) targetXZ.y += 2 * PI;
|
||||
|
||||
m_orientation.X = clamp( targetXZ.x, -m_anchorConformX, m_anchorConformX );
|
||||
m_orientation.Z = clamp( targetXZ.y, -m_anchorConformZ, m_anchorConformZ );
|
||||
m_orientation_unclamped.x = targetXZ.x;
|
||||
m_orientation_unclamped.y = targetXZ.y;
|
||||
|
||||
CMovementEvent evt( m_orientation_unclamped.x );
|
||||
DispatchEvent(&evt);
|
||||
|
||||
if( m_bounds && m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
||||
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
|
||||
@ -496,7 +505,7 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
|
||||
else
|
||||
{
|
||||
// Close enough, but turn to face them.
|
||||
m_orientation = atan2( delta.x, delta.y );
|
||||
m_orientation.Y = atan2( delta.x, delta.y );
|
||||
m_ahead = delta.normalize();
|
||||
m_isRunning = false;
|
||||
}
|
||||
|
@ -114,4 +114,10 @@ CIdleEvent::CIdleEvent( CEntityOrder order, int notifyType ) : CScriptEvent( L"i
|
||||
AddLocalProperty( L"orderType", &m_orderType );
|
||||
AddLocalProperty( L"target", &m_target );
|
||||
AddLocalProperty( L"location", &m_location );
|
||||
}
|
||||
CMovementEvent::CMovementEvent( float slope ) : CScriptEvent( L"movementEvent", EVENT_MOVEMENT, false )
|
||||
{
|
||||
m_slope = slope;
|
||||
|
||||
AddLocalProperty( L"slope", &m_slope );
|
||||
}
|
@ -132,5 +132,10 @@ class CIdleEvent : public CScriptEvent
|
||||
public:
|
||||
CIdleEvent( CEntityOrder order, int notifyType );
|
||||
};
|
||||
|
||||
class CMovementEvent : public CScriptEvent
|
||||
{
|
||||
float m_slope;
|
||||
public:
|
||||
CMovementEvent( float slope );
|
||||
};
|
||||
#endif
|
||||
|
@ -491,7 +491,7 @@ BEGIN_COMMAND(RotateObject)
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
m_AngleOld = unit->GetEntity()->m_orientation;
|
||||
m_AngleOld = unit->GetEntity()->m_orientation.Y;
|
||||
if (msg->usetarget)
|
||||
{
|
||||
CVector3D& pos = unit->GetEntity()->m_position;
|
||||
@ -543,7 +543,7 @@ BEGIN_COMMAND(RotateObject)
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
unit->GetEntity()->m_orientation = angle;
|
||||
unit->GetEntity()->m_orientation.Y = angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user