forked from 0ad/0ad
# Fixed some trigger bugs.
- Conditions were not properly converted to JavaScript (not read from the XML file correctly either). - Added an OrderFromTriggers function so that triggers can give orders which ignore fog of war. - Fixed some spelling mistakes in TriggerSpecs.xml (parameter vs. parameters). - Moved trigger update to CSimulation update, which is more correct. This was SVN commit r4821.
This commit is contained in:
parent
41cf5c6139
commit
465c0a037b
@ -1,6 +1,6 @@
|
||||
<Definitions>
|
||||
|
||||
<Condition name ="DisplayName" function = "something" funcParameter = "0">
|
||||
<Condition name ="DisplayName" function = "something" funcParameters = "0">
|
||||
<WindowRow>
|
||||
<Parameter name = "Random">
|
||||
<Window type="text" position = "0,0" size = "80,20"/>
|
||||
@ -20,7 +20,7 @@
|
||||
</WindowRow>
|
||||
</Condition>
|
||||
|
||||
<Condition name = "Always" function = "trigGetAlwaysTrue" funcParameter = "0"/>
|
||||
<Condition name = "Always" function = "trigGetAlwaysTrue" funcParameters = "0"/>
|
||||
|
||||
<Condition name = "Player resource" function = "trigPlayerResourceCount" funcParameters = "2">
|
||||
<WindowRow>
|
||||
|
@ -19,12 +19,13 @@ function trigPlayerUnitCount(player, unit)
|
||||
function trigObjectTask(subjects, target, task)
|
||||
{
|
||||
for ( var i = 0; i < subjects.length; ++i )
|
||||
|
||||
getEntityByHandle(subjects[i]).order(ORDER_GENERIC, getEntityByHandle(target), task);
|
||||
getEntityByHandle(subjects[i]).orderFromTriggers(
|
||||
ORDER_GENERIC, getEntityByHandle(target[0]), task);
|
||||
}
|
||||
|
||||
function trigObjectGoto(subjects, destination)
|
||||
{
|
||||
for ( var i = 0; i < subjects.length; ++i )
|
||||
getEntityByHandle(subjects[i]).order(ORDER_GOTO, destination.x, destination.y);
|
||||
}
|
||||
getEntityByHandle(subjects[i]).orderFromTriggers(
|
||||
ORDER_GOTO, destination.x, destination.y);
|
||||
}
|
||||
|
@ -697,7 +697,8 @@ void CXMLReader::ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group)
|
||||
EL(display);
|
||||
|
||||
AT(name);
|
||||
|
||||
AT(function);
|
||||
AT(display);
|
||||
AT(not);
|
||||
|
||||
#undef EL
|
||||
@ -747,6 +748,8 @@ void CXMLReader::ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group)
|
||||
{
|
||||
MapTriggerCondition mapCondition;
|
||||
mapCondition.name = condition.getAttributes().getNamedItem(at_name);
|
||||
mapCondition.functionName = condition.getAttributes().getNamedItem(at_function);
|
||||
mapCondition.displayName = condition.getAttributes().getNamedItem(at_display);
|
||||
|
||||
CStr notAtt(condition.getAttributes().getNamedItem(at_not));
|
||||
if ( notAtt == CStr("true") )
|
||||
@ -849,8 +852,8 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
|
||||
XMBAttributeList attrs = entity.getAttributes();
|
||||
utf16string uid = attrs.getNamedItem(at_uid);
|
||||
int UnitID = uid.empty() ? -1 : CStr(uid).ToInt();
|
||||
maxUnitID = std::max(maxUnitID, UnitID);
|
||||
int unitId = uid.empty() ? -1 : CStr(uid).ToInt();
|
||||
maxUnitID = std::max(maxUnitID, unitId);
|
||||
}
|
||||
|
||||
m_MapReader.pUnitMan->SetNextID(maxUnitID + 1);
|
||||
@ -866,7 +869,7 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
|
||||
XMBAttributeList attrs = entity.getAttributes();
|
||||
utf16string uid = attrs.getNamedItem(at_uid);
|
||||
int UnitID = uid.empty() ? -1 : CStr(uid).ToInt();
|
||||
int unitId = uid.empty() ? -1 : CStr(uid).ToInt();
|
||||
|
||||
CStrW TemplateName;
|
||||
int PlayerID = 0;
|
||||
@ -913,7 +916,7 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
{
|
||||
std::set<CStr> selections; // TODO: read from file
|
||||
|
||||
HEntity ent = g_EntityManager.create(base, Position, Orientation, selections);
|
||||
HEntity ent = g_EntityManager.create(base, Position, Orientation, selections, 0, unitId);
|
||||
|
||||
if (! ent)
|
||||
LOG(ERROR, LOG_CATEGORY, "Failed to create entity of type '%ls'", TemplateName.c_str());
|
||||
@ -922,10 +925,10 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
||||
ent->m_actor->SetPlayerID(PlayerID);
|
||||
g_EntityManager.AddEntityClassData(ent);
|
||||
|
||||
if (UnitID < 0)
|
||||
if (unitId < 0)
|
||||
ent->m_actor->SetID(m_MapReader.pUnitMan->GetNewID());
|
||||
else
|
||||
ent->m_actor->SetID(UnitID);
|
||||
ent->m_actor->SetID(unitId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ that of Atlas depending on commandline parameters.
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Interact.h"
|
||||
#include "network/SessionManager.h"
|
||||
#include "simulation/TriggerManager.h"
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "simulation/Scheduler.h"
|
||||
@ -267,10 +266,6 @@ static void Frame()
|
||||
PROFILE( "camera update" );
|
||||
g_Game->GetView()->Update(float(TimeSinceLastFrame));
|
||||
}
|
||||
|
||||
PROFILE_START("trigger update");
|
||||
g_TriggerManager.Update( (float)TimeSinceLastFrame );
|
||||
PROFILE_END("trigger udpate");
|
||||
|
||||
PROFILE_START( "selection and interaction ui" );
|
||||
// TODO Where does GameView end and other things begin?
|
||||
|
@ -439,14 +439,20 @@ public:
|
||||
return ( m_formation != 0 ? true : false );
|
||||
}
|
||||
|
||||
bool Order( JSContext* cx, uintN argc, jsval* argv, bool Queued );
|
||||
bool Order( JSContext* cx, uintN argc, jsval* argv, CEntityOrder::EOrderSource source, bool Queued );
|
||||
|
||||
// TODO: Replace these variants of order() with a single function, and update scripts accordingly.
|
||||
inline bool OrderSingle( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
return( Order( cx, argc, argv, false ) );
|
||||
return( Order( cx, argc, argv, CEntityOrder::SOURCE_PLAYER, false ) );
|
||||
}
|
||||
inline bool OrderQueued( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
return( Order( cx, argc, argv, true ) );
|
||||
return( Order( cx, argc, argv, CEntityOrder::SOURCE_PLAYER, true ) );
|
||||
}
|
||||
inline bool OrderFromTriggers( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
return( Order( cx, argc, argv, CEntityOrder::SOURCE_TRIGGERS, true ) );
|
||||
}
|
||||
|
||||
bool IsIdle( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
|
||||
|
@ -85,28 +85,47 @@ void CEntityManager::deleteAll()
|
||||
|
||||
HEntity CEntityManager::create(CEntityTemplate* base, CVector3D position, float orientation,
|
||||
const std::set<CStr>& actorSelections,
|
||||
const CStrW* building)
|
||||
const CStrW* building, int desiredHandle)
|
||||
{
|
||||
debug_assert( base );
|
||||
if( !base )
|
||||
return HEntity();
|
||||
|
||||
while( m_entities[m_nextalloc].m_refcount )
|
||||
int pos = 0;
|
||||
|
||||
if(desiredHandle >= 0)
|
||||
{
|
||||
m_nextalloc++;
|
||||
if(m_nextalloc >= MAX_HANDLES)
|
||||
if( m_entities[desiredHandle].m_refcount )
|
||||
{
|
||||
debug_warn("Ran out of entity handles!");
|
||||
debug_warn("Tried to create an entity at index %d, which is already taken.", desiredHandle);
|
||||
return HEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = desiredHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( m_entities[m_nextalloc].m_refcount )
|
||||
{
|
||||
m_nextalloc++;
|
||||
if(m_nextalloc >= MAX_HANDLES)
|
||||
{
|
||||
debug_warn("Ran out of entity handles!");
|
||||
return HEntity();
|
||||
}
|
||||
}
|
||||
pos = m_nextalloc;
|
||||
m_nextalloc++;
|
||||
}
|
||||
|
||||
m_entities[m_nextalloc].m_entity = new CEntity( base, position, orientation, actorSelections, building );
|
||||
m_entities[pos].m_entity = new CEntity( base, position, orientation, actorSelections, building );
|
||||
if( m_collisionPatches)
|
||||
m_entities[m_nextalloc].m_entity->updateCollisionPatch();
|
||||
m_entities[m_nextalloc].m_entity->me = HEntity( m_nextalloc );
|
||||
m_entities[pos].m_entity->updateCollisionPatch();
|
||||
m_entities[pos].m_entity->me = HEntity( pos );
|
||||
|
||||
return( HEntity( m_nextalloc++ ) );
|
||||
return( HEntity( pos ) );
|
||||
}
|
||||
|
||||
void CEntityManager::AddEntityClassData(const HEntity& handle)
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
~CEntityManager();
|
||||
|
||||
HEntity create( CEntityTemplate* base, CVector3D position, float orientation,
|
||||
const std::set<CStr>& actorSelections, const CStrW* building = 0 );
|
||||
const std::set<CStr>& actorSelections, const CStrW* building = 0, int desiredHandle = -1 );
|
||||
|
||||
HEntity create( const CStrW& templateName, CPlayer* player, CVector3D position,
|
||||
float orientation, const CStrW* building = 0 );
|
||||
|
@ -23,7 +23,8 @@
|
||||
// order queue after it's executed. In this way, the entity will
|
||||
// circle round a list of patrol points.
|
||||
// Create this order when a standard patrol order is required.
|
||||
// ORDER_ATTACK_MELEE: Move towards target entity; start bashing it when close enough.
|
||||
// ORDER_GENERIC: Generic ranged action. Move towards target entity, then start
|
||||
// performing an action (call a JS event handler every few seconds).
|
||||
// If we collide with something (=> line-of-sight tracking no longer
|
||||
// sufficient) spawns a ORDER_GOTO to target's location and pushes it
|
||||
// immediately in front of this order.
|
||||
@ -105,7 +106,8 @@ public:
|
||||
enum EOrderSource
|
||||
{
|
||||
SOURCE_PLAYER,
|
||||
SOURCE_UNIT_AI
|
||||
SOURCE_UNIT_AI,
|
||||
SOURCE_TRIGGERS
|
||||
};
|
||||
EOrderSource m_source;
|
||||
|
||||
|
@ -49,6 +49,7 @@ void CEntity::ScriptingInit()
|
||||
AddMethod<jsval, &CEntity::ToString>( "toString", 0 );
|
||||
AddMethod<bool, &CEntity::OrderSingle>( "order", 1 );
|
||||
AddMethod<bool, &CEntity::OrderQueued>( "orderQueued", 1 );
|
||||
AddMethod<bool, &CEntity::OrderFromTriggers>( "orderFromTriggers", 1 );
|
||||
AddMethod<jsval, &CEntity::TerminateOrder>( "terminateOrder", 1 );
|
||||
AddMethod<bool, &CEntity::Kill>( "kill", 0 );
|
||||
AddMethod<bool, &CEntity::IsIdle>( "isIdle", 0 );
|
||||
@ -244,7 +245,7 @@ void CEntity::JSI_SetPlayer( jsval val )
|
||||
SetPlayer(newPlayer);
|
||||
}
|
||||
|
||||
bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
|
||||
bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, CEntityOrder::EOrderSource source, bool Queued )
|
||||
{
|
||||
// This needs to be sorted (uses Scheduler rather than network messaging)
|
||||
|
||||
@ -261,7 +262,9 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
|
||||
}
|
||||
|
||||
CEntityOrder newOrder;
|
||||
newOrder.m_source = CEntityOrder::SOURCE_PLAYER;
|
||||
|
||||
newOrder.m_source = source;
|
||||
|
||||
CEntity* target;
|
||||
|
||||
(int&)newOrder.m_type = orderCode;
|
||||
|
@ -375,7 +375,8 @@ bool CEntity::processContactAction( CEntityOrder* current, size_t UNUSED(timeste
|
||||
return false;
|
||||
}
|
||||
|
||||
if( g_Game->GetWorld()->GetLOSManager()->GetUnitStatus( target, m_player ) == UNIT_HIDDEN )
|
||||
if( current->m_source != CEntityOrder::SOURCE_TRIGGERS &&
|
||||
g_Game->GetWorld()->GetLOSManager()->GetUnitStatus( target, m_player ) == UNIT_HIDDEN )
|
||||
{
|
||||
popOrder();
|
||||
return false;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "simulation/Simulation.h"
|
||||
#include "simulation/TerritoryManager.h"
|
||||
#include "simulation/TurnManager.h"
|
||||
#include "simulation/TriggerManager.h"
|
||||
|
||||
CSimulation::CSimulation(CGame *pGame):
|
||||
m_pGame(pGame),
|
||||
@ -146,6 +147,10 @@ void CSimulation::Simulate()
|
||||
m_pWorld->GetLOSManager()->Update();
|
||||
PROFILE_END( "los update" );
|
||||
|
||||
PROFILE_START("trigger update");
|
||||
g_TriggerManager.Update( m_pTurnManager->GetTurnLength() );
|
||||
PROFILE_END("trigger udpate");
|
||||
|
||||
PROFILE_START( "turn manager update" );
|
||||
m_pTurnManager->NewTurn();
|
||||
m_pTurnManager->IterateBatch(0, TranslateMessage, this);
|
||||
|
@ -210,72 +210,79 @@ void CTriggerManager::SetAllGroups(const std::list<MapTriggerGroup>& groups)
|
||||
|
||||
void CTriggerManager::AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger)
|
||||
{
|
||||
CStrW conditionBody(L"if ( ");
|
||||
CStrW conditionBody;
|
||||
CStrW linkLogic[] = { CStrW(L""), CStrW(L" && "), CStrW(L" || ") };
|
||||
size_t i=0;
|
||||
bool allParameters = true;
|
||||
|
||||
for ( std::list<MapTriggerCondition>::const_iterator it = trigger.conditions.begin();
|
||||
it != trigger.conditions.end(); ++it, ++i )
|
||||
{
|
||||
//Opening parenthesis here?
|
||||
std::set<MapTriggerLogicBlock>::const_iterator blockIt;
|
||||
if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
|
||||
if(trigger.conditions.size() == 0) {
|
||||
conditionBody = CStrW(L"return ( true );");
|
||||
}
|
||||
else {
|
||||
conditionBody = CStrW(L"return ( ");
|
||||
|
||||
for ( std::list<MapTriggerCondition>::const_iterator it = trigger.conditions.begin();
|
||||
it != trigger.conditions.end(); ++it, ++i )
|
||||
{
|
||||
if ( blockIt->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += CStrW(L" (");
|
||||
}
|
||||
|
||||
if ( it->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += it->functionName;
|
||||
conditionBody += CStrW(L"(");
|
||||
|
||||
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
|
||||
it->parameters.end(); ++it2 )
|
||||
{
|
||||
size_t params = (size_t)std::find(m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName)->funcParameters;
|
||||
size_t distance = std::distance(it->parameters.begin(), it2);
|
||||
|
||||
//Parameters end here, additional "parameters" are used directly as script
|
||||
if ( distance == params )
|
||||
//Opening parenthesis here?
|
||||
std::set<MapTriggerLogicBlock>::const_iterator blockIt;
|
||||
if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
|
||||
{
|
||||
conditionBody += CStrW(L") ");
|
||||
allParameters = false;
|
||||
if ( blockIt->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += CStrW(L" (");
|
||||
}
|
||||
|
||||
//Take display parameter and translate into JS usable code...evilness
|
||||
CTriggerSpec spec = *std::find( m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName );
|
||||
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
|
||||
|
||||
//Don't use specialized find, since we're searching for a different member
|
||||
std::set<TriggerParameter>::const_iterator specParam = std::find(
|
||||
specParameters.begin(), specParameters.end(), (int)distance);
|
||||
std::wstring combined = std::wstring( it->functionName + specParam->name );
|
||||
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
|
||||
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
|
||||
if ( it->negated )
|
||||
conditionBody += CStrW(L"!");
|
||||
conditionBody += it->functionName;
|
||||
conditionBody += CStrW(L"(");
|
||||
|
||||
for ( std::list<CStrW>::const_iterator it2 = it->parameters.begin(); it2 !=
|
||||
it->parameters.end(); ++it2 )
|
||||
{
|
||||
size_t params = (size_t)std::find(m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName)->funcParameters;
|
||||
size_t distance = std::distance(it->parameters.begin(), it2);
|
||||
|
||||
//Parameters end here, additional "parameters" are used directly as script
|
||||
if ( distance == params )
|
||||
{
|
||||
conditionBody += CStrW(L") ");
|
||||
allParameters = false;
|
||||
}
|
||||
|
||||
if ( m_TriggerTranslations[combined].empty() )
|
||||
conditionBody += *it2;
|
||||
else
|
||||
conditionBody += m_TriggerTranslations[combined][translatedIndex];
|
||||
//Take display parameter and translate into JS usable code...evilness
|
||||
CTriggerSpec spec = *std::find( m_ConditionSpecs.begin(), m_ConditionSpecs.end(), it->displayName );
|
||||
const std::set<TriggerParameter>& specParameters = spec.GetParameters();
|
||||
|
||||
//Don't use specialized find, since we're searching for a different member
|
||||
std::set<TriggerParameter>::const_iterator specParam = std::find(
|
||||
specParameters.begin(), specParameters.end(), (int)distance);
|
||||
std::wstring combined = std::wstring( it->functionName + specParam->name );
|
||||
size_t translatedIndex = std::distance( m_TriggerChoices[combined].begin(),
|
||||
std::find(m_TriggerChoices[combined].begin(), m_TriggerChoices[combined].end(), std::wstring(*it2)) );
|
||||
|
||||
if ( distance + 1 < params )
|
||||
conditionBody += CStrW(L", ");
|
||||
if ( m_TriggerTranslations[combined].empty() )
|
||||
conditionBody += *it2;
|
||||
else
|
||||
conditionBody += m_TriggerTranslations[combined][translatedIndex];
|
||||
|
||||
if ( distance + 1 < params )
|
||||
conditionBody += CStrW(L", ");
|
||||
}
|
||||
|
||||
if ( allParameters ) //Otherwise, closed inside loop
|
||||
conditionBody += CStrW(L")");
|
||||
if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
|
||||
conditionBody += CStrW(L" )");
|
||||
|
||||
if ( std::distance(it, trigger.conditions.end()) != 1 )
|
||||
conditionBody += linkLogic[it->linkLogic];
|
||||
}
|
||||
|
||||
if ( allParameters ) //Otherwise, closed inside loop
|
||||
conditionBody += CStrW(L")");
|
||||
if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
|
||||
conditionBody += CStrW(L" )");
|
||||
|
||||
if ( std::distance(it, trigger.conditions.end()) != 1 )
|
||||
conditionBody += linkLogic[it->linkLogic];
|
||||
conditionBody += CStrW(L" );");
|
||||
}
|
||||
|
||||
conditionBody += CStrW(L" )"); //closing if
|
||||
conditionBody += CStrW(L" { return true; } ");
|
||||
CStrW effectBody;
|
||||
|
||||
for ( std::list<MapTriggerEffect>::const_iterator it = trigger.effects.begin();
|
||||
|
Loading…
Reference in New Issue
Block a user