1
0
forked from 0ad/0ad

#Bar borders and angle penalty

-Changes to notifications. They take different parameters now-see
template_entity_script.js.  You can choose to destroy the notifiers
yourself in the script (useful for idle)
-Added "idle" event with registerIdle and registerDamage to assist with
the angle penalty.
-Bar border stuff
-Angle penalty is set up but untested-it just needs to use
this.getAttackDirections() to find the number of directions the entity
is being attacked from.  The penalty is specified in template_unit

There is a problem when the game exits-it attempts to destroy the
notifiers in entity.cpp's constructor, where it calls
DestroyAllNotifiers().  The problem is that the notifiers don't exist
any longer because they've been destroyed. I would fix it but I'm
leaving for vacation (Jason told me it was OK to comitt). Hope it isn't
too much of a problem.

This was SVN commit r3732.
This commit is contained in:
pyrolink 2006-04-08 22:34:54 +00:00
parent b6d46bb918
commit f2e867e239
19 changed files with 552 additions and 150 deletions

View File

@ -352,12 +352,18 @@ void Render()
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
g_Selection.renderRanks();
g_Mouseover.renderRanks();
g_Mouseover.renderBarBorders();
g_Selection.renderBarBorders();
glDisable( GL_TEXTURE_2D );
g_Mouseover.renderHealthBars();
g_Selection.renderHealthBars();
g_Mouseover.renderStaminaBars();
g_Selection.renderStaminaBars();
g_Selection.renderRanks();
g_Mouseover.renderRanks();
glEnable( GL_TEXTURE_2D );
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
@ -502,6 +508,8 @@ static void InitScripting()
g_ScriptingHost.DefineConstant( "FORMATION_ENTER", CFormationEvent::FORMATION_ENTER );
g_ScriptingHost.DefineConstant( "FORMATION_LEAVE", CFormationEvent::FORMATION_LEAVE );
g_ScriptingHost.DefineConstant( "FORMATION_DAMAGE", CFormationEvent::FORMATION_DAMAGE );
g_ScriptingHost.DefineConstant( "FORMATION_ATTACK", CFormationEvent::FORMATION_ATTACK );
g_ScriptingHost.DefineConstant( "NOTIFY_NONE", CEntityListener::NOTIFY_NONE );
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
@ -513,6 +521,8 @@ static void InitScripting()
g_ScriptingHost.DefineConstant( "NOTIFY_ESCORT", CEntityListener::NOTIFY_ESCORT );
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_ALL", CEntityListener::NOTIFY_ALL );
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );

View File

@ -118,6 +118,25 @@ void CSelectedEntities::renderStaminaBars()
glDisable( GL_BLEND );
}
}
void CSelectedEntities::renderBarBorders()
{
std::vector<HEntity>::iterator it;
for( it = m_selected.begin(); it < m_selected.end(); it++ )
(*it)->renderBarBorders();
if( m_group_highlight != -1 )
{
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_BLEND );
std::vector<HEntity>::iterator it;
for( it = m_groups[m_group_highlight].begin(); it < m_groups[m_group_highlight].end(); it++ )
(*it)->renderBarBorders();
glDisable( GL_BLEND );
}
}
void CSelectedEntities::renderRanks()
{
std::vector<HEntity>::iterator it;
@ -828,34 +847,48 @@ void CMouseoverEntities::renderRanks()
glDisable( GL_BLEND );
}
int CSelectedEntities::loadRankTextures()
void CMouseoverEntities::renderBarBorders()
{
VFSUtil::FileList ranklist;
VFSUtil::FindFiles( "art/textures/ui/session/icons", 0, ranklist );
for ( std::vector<CStr>::iterator it = ranklist.begin(); it != ranklist.end(); it++ )
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_BLEND );
std::vector<SMouseoverFader>::iterator it;
for( it = m_mouseover.begin(); it < m_mouseover.end(); it++ )
it->entity->renderBarBorders();
glDisable( GL_BLEND );
}
static void LoadUnitUIThunk( const char* path, const DirEnt* UNUSED(ent), void* context )
{
std::map<CStr, Handle>* textures = (std::map<CStr, Handle>*) context;
CStr name(path);
if ( !tex_is_known_extension(path) )
{
const char* filename = it->c_str();
if ( !tex_is_known_extension(filename) )
{
LOG(ERROR, LOG_CATEGORY, "Unknown rank texture extension (%s)", filename);
continue;
}
Handle ht = ogl_tex_load(filename);
if (ht <= 0)
{
LOG(ERROR, LOG_CATEGORY, "loadRankTextures failed on \"%s\"", filename);
return ht;
}
m_rankTextures[it->AfterLast("/")] = ht;
RETURN_ERR(ogl_tex_upload(ht));
if ( name.BeforeLast(".") == name ) //this is a directory (contains no ".")
return;
LOG(ERROR, "Unknown rank texture extension (%s)", path);
return;
}
Handle tmp = ogl_tex_load(path);
if (tmp <= 0)
{
LOG(ERROR, "Rank Textures", "loadRankTextures failed on \"%s\"", path);
return;
}
name.Remove("art/textures/ui/session/icons/"); //Names are relative to this directory
(*textures)[name] = tmp;
ogl_tex_upload(tmp);
}
int CSelectedEntities::loadUnitUITextures()
{
THROW_ERR( VFSUtil::EnumDirEnts( "art/textures/ui/session/icons/", VFSUtil::RECURSIVE,
NULL, LoadUnitUIThunk, &m_unitUITextures ) );
return 0;
}
void CSelectedEntities::destroyRankTextures()
void CSelectedEntities::destroyUnitUITextures()
{
for ( std::map<CStr, Handle>::iterator it=m_rankTextures.begin(); it != m_rankTextures.end(); it++ )
for ( std::map<CStr, Handle>::iterator it=m_unitUITextures.begin(); it != m_unitUITextures.end(); it++ )
{
ogl_tex_free(it->second);
it->second = 0;

View File

@ -37,11 +37,11 @@ struct CSelectedEntities : public Singleton<CSelectedEntities>
m_selectionChanged = true;
m_mouseOverMM = false;
loadRankTextures();
loadUnitUITextures();
}
~CSelectedEntities()
{
destroyRankTextures();
destroyUnitUITextures();
}
std::vector<HEntity> m_selected;
std::vector<HEntity> m_groups[MAX_GROUPS];
@ -78,10 +78,11 @@ struct CSelectedEntities : public Singleton<CSelectedEntities>
void renderHealthBars();
void renderStaminaBars();
void renderRanks();
void renderBarBorders();
void destroyRankTextures();
int loadRankTextures();
std::map<CStr, Handle> m_rankTextures;
void destroyUnitUITextures();
int loadUnitUITextures();
std::map<CStr, Handle> m_unitUITextures;
};
// CMouseoverEntities: the singleton containing entities the mouse is currently hovering over or bandboxing
@ -133,6 +134,7 @@ struct CMouseoverEntities : public Singleton<CMouseoverEntities>
void renderHealthBars();
void renderStaminaBars();
void renderRanks();
void renderBarBorders();
bool isBandbox() { return( m_bandbox ); }
void startBandbox( u16 x, u16 y );

View File

@ -22,6 +22,7 @@ enum EEventType
EVENT_ORDER_TRANSITION,
EVENT_NOTIFICATION,
EVENT_FORMATION,
EVENT_IDLE,
EVENT_LAST,
// Projectile events
@ -49,7 +50,8 @@ static const wchar_t* const EventNames[EVENT_LAST] =
/* EVENT_PREPARE_ORDER */ L"onPrepareOrder", /* To check if a unit can execute a given order */
/* 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_FORMATION */ L"onFormation", /* When this unit does something with a formation */
/* EVENT_IDLE */ L"onIdle" /* When this unit becomes idle, do something */
};
#endif // #ifndef EVENTTYPES_H__

View File

@ -231,12 +231,11 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
else
entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
//Destroy old listeners if we're explicitly being reassigned
//Destroy old notifiers if we're explicitly being reassigned
for ( size_t i=0; i < entities.size(); i++)
{
if ( entities[i]->m_currentListener )
entities[i]->DestroyListeners( entities[i]->m_currentListener );
entities[i]->m_currentListener = NULL;
if ( entities[i]->m_destroyNotifiers )
entities[i]->DestroyAllNotifiers();
}
std::vector<CNetMessage*> messages;
CNetMessage* msg = CNetMessage::CommandFromJSArgs(entities, cx, argc-1, argv+1);
@ -273,6 +272,48 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
return JS_TRUE;
}
//Formation stuff
JSBool createEntityFormation( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
{
REQUIRE_MIN_PARAMS(2, createEntityFormation);
CEntityList entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
CStrW name = ToPrimitive<CStrW>( argv[1] );
g_FormationManager.CreateFormation( entities, name );
*rval = JSVAL_VOID;
return JS_TRUE;
}
JSBool removeFromFormation( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
{
REQUIRE_MIN_PARAMS(1, removeFromFormation);
CEntityList entities;
if (JS_GetClass(JSVAL_TO_OBJECT(argv[0])) == &CEntity::JSI_class)
entities.push_back( (ToNative<CEntity>(argv[0])) ->me);
else
entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
*rval = g_FormationManager.RemoveUnitList(entities) ? JS_TRUE : JS_FALSE;
return JS_TRUE;
}
JSBool lockEntityFormation( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
{
REQUIRE_MIN_PARAMS(1, lockEntityFormation);
CEntity* entity = ToNative<CEntity>( argv[0] );
entity->GetFormation()->SetLock( ToPrimitive<bool>( argv[1] ) );
*rval = JSVAL_VOID;
return JS_TRUE;
}
JSBool isFormationLocked( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
{
REQUIRE_MIN_PARAMS(1, isFormationLocked);
CEntity* entity = ToNative<CEntity>( argv[0] );
*rval = entity->GetFormation()->IsLocked() ? JS_TRUE : JS_FALSE;
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// Events
@ -1072,6 +1113,11 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC(issueCommand, issueCommand, 2)
JS_FUNC(startPlacing, startPlacing, 1)
JS_FUNC(createEntityFormation, createEntityFormation, 2)
JS_FUNC(removeFromFormation, removeFromFormation, 1)
JS_FUNC(lockEntityFormation, lockEntityFormation, 1)
JS_FUNC(isFormationLocked, isFormationLocked, 1)
// Camera
JS_FUNC(setCameraTarget, setCameraTarget, 1)

View File

@ -31,14 +31,25 @@ CBaseEntity::CBaseEntity()
AddProperty( L"traits.health.max", &m_healthMax );
AddProperty( L"traits.health.bar_height", &m_healthBarHeight );
AddProperty( L"traits.health.bar_size", &m_healthBarSize );
AddProperty( L"traits.health.bar_width", &m_healthBarWidth );
AddProperty( L"traits.health.border_height", &m_healthBorderHeight);
AddProperty( L"traits.health.border_width", &m_healthBorderWidth );
AddProperty( L"traits.health.border_name", &m_healthBorderName );
AddProperty( L"traits.health.regen_rate", &m_healthRegenRate );
AddProperty( L"traits.health.regen_start", &m_healthRegenStart );
AddProperty( L"traits.health.decay_rate", &m_healthDecayRate );
AddProperty( L"traits.stamina.curr", &m_staminaCurr );
AddProperty( L"traits.stamina.max", &m_staminaMax );
AddProperty( L"traits.stamina.bar_height", &m_staminaBarHeight );
AddProperty( L"traits.stamina.bar_size", &m_staminaBarSize );
AddProperty( L"traits.rank.size", &m_rankSize );
AddProperty( L"traits.stamina.bar_width", &m_staminaBarWidth );
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.rank.width", &m_rankWidth );
AddProperty( L"traits.rank.height", &m_rankHeight );
AddProperty( L"traits.rank.name", &m_rankName );
AddProperty( L"traits.minimap.type", &m_minimapType );

View File

@ -61,20 +61,30 @@ public:
float m_staminaMax;
float m_staminaBarHeight;
int m_staminaBarSize;
float m_staminaBarWidth;
int m_staminaBorderWidth;
int m_staminaBorderHeight;
CStr m_staminaBorderName;
// HP properties
float m_healthCurr;
float m_healthMax;
float m_healthBarHeight;
int m_healthBarSize;
float m_healthBarWidth;
int m_healthBorderWidth;
int m_healthBorderHeight;
CStr m_healthBorderName;
float m_healthRegenRate;
float m_healthRegenStart;
float m_healthDecayRate;
//Rank properties
float m_rankHeight;
int m_rankSize;
float m_rankWidth;
int m_rankHeight;
CStr m_rankName;
// Minimap properties
@ -100,6 +110,9 @@ public:
SEntityAction m_run;
SEntityAction m_generic;
int m_sectorDivs;
float m_sectorPenalty;
float m_turningRadius;
CScriptObject m_EventHandlers[EVENT_LAST];

View File

@ -2,6 +2,7 @@
#include "BaseFormation.h"
#include "CLogger.h"
#include "CStr.h"
#include "maths\MathUtil.h"
#define LOG_CATEGORY "Formation"
@ -30,6 +31,11 @@ bool CBaseFormation::loadXML(CStr filename)
AT(penalty);
AT(penaltytype);
AT(penaltyval);
AT(anglepenalty);
AT(anglepenaltydivs);
AT(anglepenaltytype);
AT(anglepenaltyval);
AT(required);
AT(next);
AT(prior);
@ -53,36 +59,46 @@ bool CBaseFormation::loadXML(CStr filename)
for ( int i=0; i<Attributes.Count; ++i )
{
XMBAttribute Attr = Attributes.item(i);
if ( Attr.Name == at_tag )
if ( Attr.Name == at_tag )
m_tag = CStr(Attr.Value);
else if ( Attr.Name == at_bonus )
else if ( Attr.Name == at_bonus )
m_bonus = CStr(Attr.Value);
else if ( Attr.Name == at_bonustype )
else if ( Attr.Name == at_bonustype )
m_bonusType = CStr(Attr.Value);
else if ( Attr.Name == at_bonusval )
else if ( Attr.Name == at_bonusval )
m_bonusVal = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_penalty )
else if ( Attr.Name == at_penalty )
m_penalty = CStr(Attr.Value);
else if ( Attr.Name == at_penaltytype )
else if ( Attr.Name == at_penaltytype )
m_penaltyType = CStr(Attr.Value);
else if ( Attr.Name == at_penaltyval )
else if ( Attr.Name == at_penaltyval )
m_penaltyVal = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_required)
else if ( Attr.Name == at_anglepenalty )
m_anglePenalty = CStr(Attr.Value);
else if ( Attr.Name == at_anglepenaltydivs )
m_anglePenaltyDivs = CStr(Attr.Value).ToInt();
else if ( Attr.Name == at_anglepenaltytype )
m_anglePenaltyType = CStr(Attr.Value);
else if ( Attr.Name == at_anglepenaltyval )
m_anglePenaltyVal = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_required)
m_required = CStr(Attr.Value).ToInt();
else if ( Attr.Name == at_next )
else if ( Attr.Name == at_next )
m_next = CStr(Attr.Value);
else if ( Attr.Name == at_prior )
else if ( Attr.Name == at_prior )
m_prior = CStr(Attr.Value);
else if ( Attr.Name == at_movement )
else if ( Attr.Name == at_movement )
m_movement = CStr(Attr.Value);
else if ( Attr.Name == at_rankspacing )
else if ( Attr.Name == at_rankspacing )
m_rankSpacing = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_filespacing )
else if ( Attr.Name == at_filespacing )
m_fileSpacing = CStr(Attr.Value).ToFloat();
else
{
CStr invAttr = XeroFile.getAttributeString(Attr.Name);
LOG( ERROR, LOG_CATEGORY, "CBaseFormation::LoadXML: Invalid attribute defined in formation file %s. Load failed.", filename.c_str() );
const char* invAttr = XeroFile.getAttributeString(Attr.Name).c_str();
LOG( ERROR, LOG_CATEGORY, "CBaseFormation::LoadXML: Invalid attribute %s defined in formation file %s. Load failed.", invAttr, filename.c_str() );
return( false );
}
}

View File

@ -36,6 +36,12 @@ public:
CStr GetPenaltyType(){ return m_penaltyType; }
float GetPenaltyVal(){ return m_penaltyVal; }
CStr GetAnglePenalty(){ return m_anglePenalty; }
CStr GetAnglePenaltyType(){ return m_anglePenaltyType; }
int GetAnglePenaltyDivs(){ return m_anglePenaltyDivs; }
float GetAnglePenaltyVal(){ return m_anglePenaltyVal; }
private:
CStr m_tag;
@ -47,6 +53,11 @@ private:
CStr m_penaltyType;
float m_penaltyVal;
CStr m_anglePenalty;
int m_anglePenaltyDivs;
CStr m_anglePenaltyType;
float m_anglePenaltyVal;
int m_required;
CStr m_next;
CStr m_prior;
@ -60,6 +71,7 @@ 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

View File

@ -61,14 +61,25 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
AddProperty( L"traits.health.max", &m_healthMax );
AddProperty( L"traits.health.bar_height", &m_healthBarHeight );
AddProperty( L"traits.health.bar_size", &m_healthBarSize );
AddProperty( L"traits.health.bar_width", &m_healthBarWidth );
AddProperty( L"traits.health.border_height", &m_healthBorderHeight);
AddProperty( L"traits.health.border_width", &m_healthBorderWidth );
AddProperty( L"traits.health.border_name", &m_healthBorderName );
AddProperty( L"traits.health.regen_rate", &m_healthRegenRate );
AddProperty( L"traits.health.regen_start", &m_healthRegenStart );
AddProperty( L"traits.health.decay_rate", &m_healthDecayRate );
AddProperty( L"traits.stamina.curr", &m_staminaCurr );
AddProperty( L"traits.stamina.max", &m_staminaMax );
AddProperty( L"traits.stamina.bar_height", &m_staminaBarHeight );
AddProperty( L"traits.stamina.bar_size", &m_staminaBarSize );
AddProperty( L"traits.rank.size", &m_rankSize );
AddProperty( L"traits.stamina.bar_width", &m_staminaBarWidth );
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.rank.width", &m_rankWidth );
AddProperty( L"traits.rank.height", &m_rankHeight );
AddProperty( L"traits.rank.name", &m_rankName );
AddProperty( L"traits.minimap.type", &m_minimapType );
@ -89,6 +100,18 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
AddProperty( EventNames[t], &m_EventHandlers[t], false );
AddHandler( t, &m_EventHandlers[t] );
}
if ( m_sectorDivs >= 0 )
{
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;
@ -127,7 +150,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
m_frameCheck = 0;
m_lastCombatTime = 0;
m_currentNotification = 0;
m_currentListener = NULL;
m_currentRequest = 0;
m_destroyNotifiers = true;
m_formationSlot = -1;
m_formation = -1;
@ -161,6 +185,10 @@ CEntity::~CEntity()
}
m_auras.clear();
for ( size_t i=0; i<m_listeners.size(); i++ )
m_listeners[i].m_sender->DestroyNotifier( this );
DestroyAllNotifiers();
CEntity* remove = this;
g_FormationManager.RemoveUnit(remove);
}
@ -207,6 +235,8 @@ void CEntity::kill()
CEntity* remove = this;
g_FormationManager.RemoveUnit(remove);
DestroyAllNotifiers();
if( m_bounds )
delete( m_bounds );
@ -662,9 +692,21 @@ void CEntity::Tick()
void CEntity::clearOrders()
{
m_orderQueue.clear();
if ( m_orderQueue.empty() )
return;
CIdleEvent evt( m_orderQueue.front(), m_currentNotification );
DispatchEvent(&evt);
m_orderQueue.clear();
}
void CEntity::popOrder()
{
if ( m_orderQueue.empty() )
return;
CIdleEvent evt( m_orderQueue.front(), m_currentNotification );
DispatchEvent(&evt);
m_orderQueue.pop_front();
}
void CEntity::pushOrder( CEntityOrder& order )
{
CEventPrepareOrder evt( order.m_data[0].entity, order.m_type, order.m_data[1].data, order.m_data[0].string );
@ -683,17 +725,36 @@ void CEntity::DispatchNotification( CEntityOrder order, int type )
CEventNotification evt( order, type );
DispatchEvent( &evt );
}
void CEntity::DestroyListeners( CEntity* target )
int CEntity::DestroyNotifier( CEntity* target )
{
if (target->m_listeners.empty())
return;
for ( size_t i=0; i < target->m_listeners.size(); i++)
if (target->m_listeners.empty() || !m_destroyNotifiers)
return 0;
//Stop listening
for ( size_t i=0; i < target->m_listeners.size(); i++ )
{
if ( target->m_listeners[i].m_sender == this )
target->m_listeners.erase(target->m_listeners.begin() + i);
}
int removed=0;
//Get rid of our copy
for ( size_t i=0; i < target->m_notifiers.size(); i++ )
{
if ( m_notifiers[i] == target )
{
m_notifiers.erase(m_notifiers.begin() + i);
++removed;
}
}
return removed;
}
void CEntity::DestroyAllNotifiers()
{
debug_assert(m_destroyNotifiers);
//Make them stop listening to us
if ( m_notifiers.empty() )
return;
for ( size_t i=0; i<m_notifiers.size(); i++ )
i -= DestroyNotifier( m_notifiers[i] );
}
CEntityFormation* CEntity::GetFormation()
{
@ -1001,29 +1062,81 @@ void CEntity::renderSelectionOutline( float alpha )
glEnd();
}
CVector2D CEntity::getScreenCoords( float height )
{
CCamera &g_Camera=*g_Game->GetView()->GetCamera();
float sx, sy;
CVector3D above;
above.X = m_position.X;
above.Z = m_position.Z;
above.Y = getAnchorLevel(m_position.X, m_position.Z) + height;
g_Camera.GetScreenCoordinates(above, sx, sy);
return CVector2D( sx, sy );
}
void CEntity::renderBarBorders()
{
pglActiveTextureARB( GL_TEXTURE0_ARB );
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
if ( g_Selection.m_unitUITextures.find(m_healthBorderName) != g_Selection.m_unitUITextures.end() )
{
ogl_tex_bind( g_Selection.m_unitUITextures[m_healthBorderName] );
CVector2D pos = getScreenCoords( m_healthBarHeight );
float left = pos.x - m_healthBorderWidth/2;
float right = pos.x + m_healthBorderWidth/2;
pos.y = g_yres - pos.y;
float bottom = pos.y + m_healthBorderHeight/2;
float top = pos.y - m_healthBorderHeight/2;
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f( left, bottom, 0 );
glTexCoord2f(0.0f, 1.0f); glVertex3f( left, top, 0 );
glTexCoord2f(1.0f, 1.0f); glVertex3f( right, top, 0 );
glTexCoord2f(1.0f, 0.0f); glVertex3f( right, bottom, 0 );
glEnd();
}
if ( g_Selection.m_unitUITextures.find(m_staminaBorderName) != g_Selection.m_unitUITextures.end() )
{
ogl_tex_bind( g_Selection.m_unitUITextures[m_staminaBorderName] );
CVector2D pos = getScreenCoords( m_staminaBarHeight );
float left = pos.x - m_staminaBorderWidth/2;
float right = pos.x + m_staminaBorderWidth/2;
pos.y = g_yres - pos.y;
float bottom = pos.y + m_staminaBorderHeight/2;
float top = pos.y - m_staminaBorderHeight/2;
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f( left, bottom, 0 );
glTexCoord2f(0.0f, 1.0f); glVertex3f( left, top, 0 );
glTexCoord2f(1.0f, 1.0f); glVertex3f( right, top, 0 );
glTexCoord2f(1.0f, 0.0f); glVertex3f( right, bottom, 0 );
glEnd();
}
}
void CEntity::renderHealthBar()
{
if( !m_bounds )
return;
if( m_healthBarHeight < 0 )
return; // negative bar height means don't display health bar
CCamera &g_Camera=*g_Game->GetView()->GetCamera();
float sx, sy;
CVector3D above;
above.X = m_position.X;
above.Z = m_position.Z;
above.Y = getAnchorLevel(m_position.X, m_position.Z) + m_healthBarHeight;
g_Camera.GetScreenCoordinates(above, sx, sy);
CVector2D pos = getScreenCoords( m_healthBarHeight );
float fraction = clamp(m_healthCurr / m_healthMax, 0.0f, 1.0f);
float x1 = sx - m_healthBarSize/2;
float x2 = sx + m_healthBarSize/2;
float y = g_yres - sy;
glBegin(GL_LINES);
float x1 = pos.x - m_healthBarSize/2;
float x2 = pos.x + m_healthBarSize/2;
float y = g_yres - pos.y;
glLineWidth( m_healthBarWidth );
glBegin(GL_LINES);
// green part of bar
glColor3f( 0, 1, 0 );
@ -1038,6 +1151,9 @@ void CEntity::renderHealthBar()
glVertex3f( x2, y, 0 );
glEnd();
glLineWidth(1.0f);
}
void CEntity::renderStaminaBar()
@ -1047,20 +1163,13 @@ void CEntity::renderStaminaBar()
if( m_staminaBarHeight < 0 )
return; // negative bar height means don't display stamina bar
CCamera *g_Camera=g_Game->GetView()->GetCamera();
float sx, sy;
CVector3D above;
above.X = m_position.X;
above.Z = m_position.Z;
above.Y = getAnchorLevel(m_position.X, m_position.Z) + m_staminaBarHeight;
g_Camera->GetScreenCoordinates(above, sx, sy);
CVector2D pos = getScreenCoords( m_staminaBarHeight );
float fraction = clamp(m_staminaCurr / m_staminaMax, 0.0f, 1.0f);
float x1 = sx - m_staminaBarSize/2;
float x2 = sx + m_staminaBarSize/2;
float y = g_yres - sy;
float x1 = pos.x - m_staminaBarSize/2;
float x2 = pos.x + m_staminaBarSize/2;
float y = g_yres - pos.y;
glLineWidth( m_staminaBarWidth );
glBegin(GL_LINES);
// blue part of bar
@ -1076,17 +1185,18 @@ void CEntity::renderStaminaBar()
glVertex3f( x2, y, 0 );
glEnd();
glLineWidth(1.0f);
}
void CEntity::renderRank()
{
if( !m_bounds )
return;
if( m_rankHeight < 0 )
return; // negative bar height means don't display stamina bar
return; // negative height means don't display stamina bar
//Check for valid texture
if( g_Selection.m_rankTextures.find( m_rankName ) == g_Selection.m_rankTextures.end() )
if( g_Selection.m_unitUITextures.find( m_rankName ) == g_Selection.m_unitUITextures.end() )
return;
CCamera *g_Camera=g_Game->GetView()->GetCamera();
float sx, sy;
@ -1095,14 +1205,14 @@ void CEntity::renderRank()
above.Z = m_position.Z;
above.Y = getAnchorLevel(m_position.X, m_position.Z) + m_rankHeight;
g_Camera->GetScreenCoordinates(above, sx, sy);
int size = m_rankSize/2;
int size = m_rankWidth/2;
float x1 = sx - size;
float x2 = sx + size;
float y1 = g_yres - (sy - size); //top
float y2 = g_yres - (sy + size); //bottom
ogl_tex_bind(g_Selection.m_rankTextures[m_rankName]);
ogl_tex_bind(g_Selection.m_unitUITextures[m_rankName]);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
@ -1167,7 +1277,9 @@ void CEntity::ScriptingInit()
AddMethod<jsval, &CEntity::RemoveAura>( "removeAura", 1 );
AddMethod<jsval, &CEntity::SetActionParams>( "setActionParams", 5 );
AddMethod<bool, &CEntity::ForceCheckListeners>( "forceCheckListeners", 2 );
AddMethod<bool, &CEntity::RequestNotification>( "requestNotification", 3 );
AddMethod<bool, &CEntity::RequestNotification>( "requestNotification", 4 );
AddMethod<jsval, &CEntity::DestroyNotifier>( "destroyNotifier", 1 );
AddMethod<jsval, &CEntity::DestroyAllNotifiers>( "destroyAllNotifiers", 0 );
AddMethod<jsval, &CEntity::TriggerRun>( "triggerRun", 1 );
AddMethod<jsval, &CEntity::SetRun>( "setRun", 1 );
AddMethod<jsval, &CEntity::GetRunState>( "getRunState", 0 );
@ -1178,7 +1290,8 @@ void CEntity::ScriptingInit()
AddMethod<jsval, &CEntity::GetFormationPenalty>( "getFormationPenalty", 0 );
AddMethod<jsval, &CEntity::GetFormationPenaltyType>( "getFormationPenaltyType", 0 );
AddMethod<jsval, &CEntity::GetFormationPenaltyVal>( "getFormationPenaltyVal", 0 );
AddMethod<bool, &CEntity::IsInClass>( "isInClass", 1 );
AddMethod<jsval, &CEntity::RegisterDamage>( "registerDamage", 0 );
AddMethod<jsval, &CEntity::RegisterIdle>( "registerIdle", 0 );
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
AddClassProperty( L"traits.id.classes", (GetFn)&CEntity::getClassSet, (SetFn)&CEntity::setClassSet );
@ -1311,11 +1424,12 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
//It's not a notification order
if ( argc == 3 )
{
if ( m_currentListener )
DestroyListeners( m_currentListener );
m_currentListener = NULL;
if ( m_destroyNotifiers )
{
m_currentRequest=0;
DestroyAllNotifiers();
}
}
break;
case CEntityOrder::ORDER_GENERIC:
if( argc < 3 )
@ -1342,9 +1456,11 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
//It's not a notification order
if ( argc == 3 )
{
if ( m_currentListener )
DestroyListeners( m_currentListener );
m_currentListener = NULL;
if ( m_destroyNotifiers )
{
m_currentRequest=0;
DestroyAllNotifiers();
}
}
break;
case CEntityOrder::ORDER_PRODUCE:
@ -1627,32 +1743,35 @@ jsval CEntity::SetActionParams( JSContext* UNUSED(cx), uintN argc, jsval* argv )
bool CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv )
{
if( argc < 3 )
if( argc < 4 )
{
JS_ReportError( cx, "Too few parameters" );
return( false );
}
CEntityListener notify;
notify.m_sender = this;
//(Convert from int to enum)
CEntity *target = ToNative<CEntity>( argv[0] );
(int&)notify.m_type = ToPrimitive<int>( argv[1] );
bool tmpDestroyNotifiers = ToPrimitive<bool>( argv[2] );
bool m_destroyNotifiers = !ToPrimitive<bool>( argv[3] );
if (target == this)
return false;
*( (int*) &(notify.m_type) ) = ToPrimitive<int>( argv[1] );
notify.m_sender = this;
//Clean up old requests
if ( ToPrimitive<bool>( argv[2] ) && !target->m_listeners.empty() )
DestroyListeners( target );
if ( target != m_currentListener && m_currentListener )
DestroyListeners( m_currentListener );
if ( tmpDestroyNotifiers )
DestroyAllNotifiers();
//If new request is not the same and we're destroy notifiers, reset
else if ( !(notify.m_type & m_currentRequest) && m_destroyNotifiers )
DestroyAllNotifiers();
m_currentListener = target;
m_currentRequest = notify.m_type;
m_notifiers.push_back( target );
int result = target->m_currentNotification & notify.m_type;
//If our target isn't stationary and it's doing something we want to follow, send notification
int result = target->m_currentNotification & notify.m_type;
if ( result && !target->m_orderQueue.empty() )
{
CEntityOrder order = target->m_orderQueue.front();
@ -1667,11 +1786,6 @@ bool CEntity::RequestNotification( JSContext* cx, uintN argc, jsval* argv )
case CEntityListener::NOTIFY_ATTACK:
case CEntityListener::NOTIFY_GATHER:
case CEntityListener::NOTIFY_DAMAGE:
if( argc < 2 )
{
JS_ReportError( cx, "Too few parameters" );
}
DispatchNotification( order, result );
break;
default:
@ -1713,11 +1827,13 @@ bool CEntity::ForceCheckListeners( JSContext *cx, uintN argc, jsval* argv )
case CEntityListener::NOTIFY_ATTACK:
case CEntityListener::NOTIFY_GATHER:
case CEntityListener::NOTIFY_DAMAGE:
case CEntityListener::NOTIFY_IDLE: //target should be 'this'
m_listeners[i].m_sender->DispatchNotification( order, result );
break;
default:
JS_ReportError( cx, "Invalid order type" );
continue;
break;
}
}
}
@ -1754,6 +1870,21 @@ void CEntity::CheckListeners( int type, CEntity *target)
}
}
}
jsval CEntity::DestroyAllNotifiers( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
DestroyAllNotifiers();
return JS_TRUE;
}
jsval CEntity::DestroyNotifier( JSContext* cx, uintN argc, jsval* argv )
{
if ( argc < 1 )
{
JS_ReportError(cx, "too few parameters: CEntity::DestroyNotifier");
return JS_FALSE;
}
DestroyNotifier( ToNative<CEntity>( argv[0] ) );
return JS_TRUE;
}
jsval CEntity::TriggerRun( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
@ -1800,13 +1931,64 @@ jsval CEntity::GetFormationBonusVal( JSContext* UNUSED(cx), uintN UNUSED(argc),
{
return ToJSVal( GetFormation()->GetBase()->GetBonusVal() );
}
bool CEntity::IsInClass( JSContext* cx, uintN argc, jsval* argv )
jsval CEntity::RegisterDamage( JSContext* cx, uintN argc, jsval* argv )
{
if( argc < 1 )
if ( argc < 1 )
{
JS_ReportError( cx, "Too few parameters" );
return( false );
}
CStr test = ToPrimitive<CStr>( argv[0] );
return m_classes.IsMember( test );
}
CEntity* inflictor = ToNative<CEntity>( argv[0] );
CVector2D up(1.0f, 0.0f);
CVector2D pos = CVector2D( inflictor->m_position.X, inflictor->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] = true;
else if ( angle > m_sectorAngles[i] && angle < m_sectorAngles[i+1] )
m_sectorValues[i] = true;
}
return JS_TRUE;
}
jsval CEntity::RegisterIdle( JSContext* cx, uintN argc, jsval* argv )
{
if ( argc < 1 )
{
JS_ReportError( cx, "Too few parameters" );
return( false );
}
CEntity* idleEntity = ToNative<CEntity>( argv[0] );
CVector2D up(1.0f, 0.0f);
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;
}
return JS_TRUE;
}
jsval CEntity::GetAttackDirections( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
int directions=0;
for ( std::vector<bool>::iterator it=m_sectorValues.begin(); it != m_sectorValues.end(); it++ )
{
if ( *it )
++directions;
}
return ToJSVal( directions );
}

View File

@ -114,16 +114,26 @@ public:
float m_staminaMax;
float m_staminaBarHeight;
int m_staminaBarSize;
float m_staminaBarWidth;
int m_staminaBorderWidth;
int m_staminaBorderHeight;
CStr m_staminaBorderName;
// HP properties
float m_healthCurr;
float m_healthMax;
float m_healthBarHeight;
int m_healthBarSize;
float m_healthBarWidth;
int m_healthBorderWidth;
int m_healthBorderHeight;
CStr m_healthBorderName;
//Rank properties
float m_rankHeight;
int m_rankSize;
int m_rankWidth;
CStr m_rankName;
bool m_healthDecay;
@ -189,8 +199,16 @@ public:
std::deque<CEntityOrder> m_orderQueue;
std::deque<CEntityListener> m_listeners;
int m_currentNotification;
CEntity* m_currentListener;
std::vector<CEntity*> m_notifiers;
int m_currentNotification; //Current order in the form of a notification code
int m_currentRequest; //Notification we our notifiers are sending
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;
private:
CEntity( CBaseEntity* base, CVector3D position, float orientation, const std::set<CStrW>& actorSelections, CStrW building = L"" );
@ -261,10 +279,11 @@ public:
// Things like selection circles and debug info - possibly move to gui if/when it becomes responsible for (and capable of) it.
void render();
void renderSelectionOutline( float alpha = 1.0f );
void renderBarBorders( );
void renderHealthBar();
void renderStaminaBar();
void renderRank();
CVector2D getScreenCoords( float height );
// After a collision, recalc the path to the next fixed waypoint.
void repath();
@ -283,10 +302,12 @@ public:
void checkExtant(); // Existence
void clearOrders();
void popOrder(); //Use this if and order has finished instead of m_orderQueue.pop_front()
void pushOrder( CEntityOrder& order );
void DispatchNotification( CEntityOrder order, int type );
void DestroyListeners( CEntity* target );
int DestroyNotifier( CEntity* target ); //Stop notifier from sending to us
void DestroyAllNotifiers();
CEntityFormation* GetFormation();
bool IsInClass( JSContext* cx, uintN argc, jsval* argv );
@ -297,7 +318,12 @@ public:
jsval GetFormationBonus( 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 GetAttackDirections( JSContext* cx, uintN argc, jsval* argv );
// Script constructor
static JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval );
@ -322,6 +348,8 @@ public:
//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 );
void CheckListeners( int type, CEntity *target );
jsval DestroyAllNotifiers( JSContext* cx, uintN argc, jsval* argv );
jsval DestroyNotifier( JSContext* cx, uintN argc, jsval* argv );
bool IsInFormation( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{

View File

@ -91,19 +91,21 @@ void CEntityFormation::RemoveUnit( CEntity*& entity )
--m_numEntities;
//UpdateFormation();
}
bool CEntityFormation::IsSlotAppropriate( int order, CEntity*& entity )
bool CEntityFormation::IsSlotAppropriate( int order, CEntity* entity )
{
debug_assert( entity );
if ( !IsValidOrder(order) )
return false;
for ( size_t idx=0; idx < m_base->m_slots[order].category.size(); ++idx )
{
if ( entity->m_classes.IsMember( m_base->m_slots[order].category[idx] ) )
CStr tmp( m_base->m_slots[order].category[idx] );
if ( entity->m_classes.IsMember( tmp ) )
return true;
}
return false;
}
bool CEntityFormation::IsBetterUnit( int order, CEntity*& entity )
bool CEntityFormation::IsBetterUnit( int order, CEntity* entity )
{
if ( !( IsValidOrder(order) || entity ) )
return false;
@ -163,6 +165,11 @@ void CEntityFormation::ResetAllEntities()
for ( int i=0; i<m_base->m_numSlots; ++i )
m_entities[i] = NULL;
}
void CEntityFormation::ResetAngleDivs()
{
for ( int i=0; i<m_base->m_anglePenaltyDivs; ++i )
m_angleDivs[i] = false;
}
void CEntityFormation::SelectAllUnits()
{
for ( int i=0; i<m_base->m_numSlots; ++i )

View File

@ -36,8 +36,6 @@ public:
inline void SetDuplication( bool duplicate ) { m_duplication=duplicate; }
inline bool IsDuplication() { return m_duplication; }
//inline void SetDuplication( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) );
//inline bool IsDuplication( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) );
inline void SetLock( bool lock ){ m_locked=lock; }
inline bool IsLocked() { return m_locked; }
inline bool IsValidOrder(int order) { return ( order >= 0 && order < m_base->m_numSlots ); }
@ -55,19 +53,21 @@ private:
CBaseFormation* m_base;
CBaseFormation* m_self; //Keeps track of base (referred to during movement switching)
std::vector<CEntity*> m_entities; //number of units currently in this formation
std::vector<CEntity*> m_entities; //number of units currently in this formation
std::vector<bool> m_angleDivs; //attack direction penalty-true=being attacked from sector
std::vector<float> m_angleVals;
bool AddUnit( CEntity*& entity );
void RemoveUnit( CEntity*& entity );
bool IsSlotAppropriate( int order, CEntity*& entity ); //If empty, can we use this slot?
bool IsBetterUnit( int order, CEntity*& entity );
bool IsSlotAppropriate( int order, CEntity* entity ); //If empty, can we use this slot?
bool IsBetterUnit( int order, CEntity* entity );
void UpdateFormation();
void SwitchBase( CBaseFormation*& base );
//void UpdateGridOffset();
void ResetIndex( size_t index );
void ResetAllEntities(); //Sets all handles to invalid
void ResetAngleDivs();
};
#endif

View File

@ -66,7 +66,10 @@ public:
NOTIFY_ESCORT = 0x0F, //GOTO | ATTACK | DAMAGE
NOTIFY_HEAL = 0x10,
NOTIFY_GATHER = 0x20
NOTIFY_GATHER = 0x20,
NOTIFY_IDLE = 0x40,
NOTIFY_ALL = 0x7F
} m_type;

View File

@ -379,7 +379,7 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
if(!DispatchEvent( contactEvent ))
{
// Cancel current order
m_orderQueue.pop_front();
popOrder();
m_isRunning = false;
m_shouldRun = false;
m_actor->SetEntitySelection( L"idle" );
@ -406,7 +406,7 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
//TODO: eventually when stances/formations are implemented, if applicable (e.g. not
//heal or if defensive stance), the unit should expand and continue the order.
m_orderQueue.pop_front();
popOrder();
m_isRunning = false;
m_shouldRun = false;
return( false );

View File

@ -97,8 +97,21 @@ CEventNotification::CEventNotification( CEntityOrder order, int notifyType ) : C
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"location", &m_location );
}
CFormationEvent::CFormationEvent( int type ) : CScriptEvent( L"formationEvent", EVENT_FORMATION, true )
CFormationEvent::CFormationEvent( int type ) : CScriptEvent( L"formationEvent", EVENT_FORMATION, true )
{
(int&) m_formationEvent = type;
AddLocalProperty( L"formationEvent", &m_formationEvent );
}
CIdleEvent::CIdleEvent( CEntityOrder order, int notifyType ) : CScriptEvent( L"idleEvent", EVENT_IDLE, false )
{
m_notifyType = notifyType;
m_orderType = order.m_type;
m_target = order.m_data[0].entity;
CVector3D convert( order.m_data[0].location.x, 0.0f, order.m_data[0].location.y );
m_location = convert;
AddLocalProperty( L"notifyType", &m_notifyType );
AddLocalProperty( L"orderType", &m_orderType );
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"location", &m_location );
}

View File

@ -116,8 +116,21 @@ public:
{
FORMATION_ENTER,
FORMATION_LEAVE,
FORMATION_DAMAGE,
FORMATION_ATTACK,
FORMATION_LAST
};
};
class CIdleEvent : public CScriptEvent
{
int m_notifyType; //previous order in notification code form
int m_orderType;
int m_action; //previous order in terms of generic order action
CVector3D m_location;
CEntity* m_target;
public:
CIdleEvent( CEntityOrder order, int notifyType );
};
#endif

View File

@ -13,7 +13,7 @@ CFormationManager::~CFormationManager()
for ( size_t i=0; i<m_formations.size(); i++ )
delete m_formations[i];
}
void CFormationManager::CreateFormation( CStrW& name, CEntityList& entities )
void CFormationManager::CreateFormation( CEntityList& entities, CStrW& name )
{
if ( entities.empty() )
{
@ -120,6 +120,16 @@ bool CFormationManager::RemoveUnit( CEntity*& entity )
(*it)->RemoveUnit( entity );
return true;
}
bool CFormationManager::RemoveUnitList( CEntityList& entities )
{
for ( CEntityList::iterator it=entities.begin(); it != entities.end(); it++ )
{
CEntity* entity = *it;
if ( !RemoveUnit(entity) )
return false;
}
return true;
}
CEntityFormation* CFormationManager::GetFormation(int form)
{
if ( IsValidFormation(form) )

View File

@ -23,7 +23,7 @@ class CFormationManager : public Singleton<CFormationManager>
public:
CFormationManager() {}
~CFormationManager();
void CreateFormation( CStrW& name, CEntityList& entities );
void CreateFormation( CEntityList& entities, CStrW& name );
//entity is any unit in the formation
void DestroyFormation( size_t form );
inline bool IsValidFormation( int index )
@ -35,6 +35,7 @@ public:
//Returns false if the formation is destroyed
bool RemoveUnit( CEntity*& entity );
bool RemoveUnitList( CEntityList& entities );
CEntityFormation* GetFormation(int form);
void UpdateIndexes( size_t update );