1
0
forked from 0ad/0ad

- Linux/GCC (as usual :P)

- Ported lockless code to gcc inline assembly
- A few new net messages (gather, attack, add waypoint)
- Support for new messages in network->entity order converter
- Implemented rudimentary JS interface for Interaction
- issueCommand JS API, connected to the network
- Removed Interaction stuff now replaced by JS
- And something in there should probably break VS builds :P

This was SVN commit r2316.
This commit is contained in:
Simon Brenner 2005-05-18 05:32:09 +00:00
parent 600a55b7d7
commit d0f7cb015c
66 changed files with 784 additions and 602 deletions

View File

@ -5,6 +5,7 @@
#include "GameView.h"
#include "Game.h"
#include "Camera.h"
#include "Interact.h"
#include "Matrix3D.h"
#include "Renderer.h"
@ -66,6 +67,8 @@ CGameView::CGameView(CGame *pGame):
m_Camera.m_Orientation.RotateY(DEGTORAD(-45));
m_Camera.m_Orientation.Translate (100, 150, -100);
g_Renderer.SetCamera(m_Camera);
ONCE( ScriptingInit(); );
}
CGameView::~CGameView()
@ -73,6 +76,13 @@ CGameView::~CGameView()
UnloadResources();
}
void CGameView::ScriptingInit()
{
AddMethod<bool, &CGameView::JSI_StartCustomSelection>("startCustomSelection", 0);
AddMethod<bool, &CGameView::JSI_EndCustomSelection>("endCustomSelection", 0);
CJSObject<CGameView>::ScriptingInit("GameView");
}
int CGameView::Initialize(CGameAttributes *pAttribs)
{
@ -691,3 +701,15 @@ int game_view_handler(const SDL_Event* ev)
return EV_PASS;
}
bool CGameView::JSI_StartCustomSelection(JSContext* context, unsigned int argc, jsval* argv)
{
StartCustomSelection();
return true;
}
bool CGameView::JSI_EndCustomSelection(JSContext* context, unsigned int argc, jsval* argv)
{
ResetInteraction();
return true;
}

View File

@ -4,6 +4,8 @@
#include "Camera.h"
#include "Vector3D.h"
#include "scripting/ScriptableObject.h"
class CGame;
class CGameAttributes;
class CWorld;
@ -12,7 +14,7 @@ class CUnitManager;
class CProjectileManager;
class CModel;
class CGameView
class CGameView: public CJSObject<CGameView>
{
CGame *m_pGame;
CWorld *m_pWorld;
@ -57,6 +59,12 @@ class CGameView
// UnloadResources(): Unload all graphics resources loaded by InitResources
void UnloadResources();
// JS Interface
bool JSI_StartCustomSelection(JSContext *cx, uintN argc, jsval *argv);
bool JSI_EndCustomSelection(JSContext *cx, uintN argc, jsval *argv);
static void ScriptingInit();
public:
CGameView(CGame *pGame);
~CGameView();

View File

@ -308,7 +308,7 @@ bool CObjectBase::Load(const char* filename)
}
else
{
LOG(ERROR, LOG_CATEGORY, "Invalid actor format (unrecognised root element '%s')", XeroFile.getElementString(root.getNodeName()));
LOG(ERROR, LOG_CATEGORY, "Invalid actor format (unrecognised root element '%s')", XeroFile.getElementString(root.getNodeName()).c_str());
return false;
}

View File

@ -5,6 +5,7 @@ class CModel;
class CSkeletonAnim;
#include <vector>
#include <set>
#include "CStr.h"
class CObjectBase

View File

@ -17,8 +17,9 @@
#include "lib/res/vfs.h"
#define LOG_CATEGORY "graphics"
#include <sstream>
#define LOG_CATEGORY "graphics"
CObjectEntry::CObjectEntry(int type, CObjectBase* base)
: m_Model(0), m_Type(type), m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f)

View File

@ -101,7 +101,8 @@ CObjectEntry* CObjectManager::FindObject(const char* objname)
CObjectBase::variation_key var;
base->CalculateVariation(choices, var);
return FindObjectVariation(base, var, var.begin());
CObjectBase::variation_key::iterator vars_it=var.begin();
return FindObjectVariation(base, var, vars_it);
}
CObjectEntry* CObjectManager::FindObjectVariation(const char* objname, CObjectBase::variation_key vars, CObjectBase::variation_key::iterator& vars_it)

View File

@ -31,7 +31,7 @@ class CObjectManager : public Singleton<CObjectManager>
public:
struct ObjectKey
{
ObjectKey(CStr& name, CObjectBase::variation_key& var)
ObjectKey(const CStr& name, const CObjectBase::variation_key& var)
: ActorName(name), ActorVariation(var) {}
CStr ActorName;

View File

@ -2,7 +2,7 @@
#ifndef CGUIList_H
#define CGUIList_H
#include "GUIText.h"
#include "GUItext.h"
class CGUIList
{

View File

@ -107,7 +107,7 @@ void CList::SetupText()
AddText(text);
}
m_ItemsYPositions[i] = buffered_y;
m_ItemsYPositions[pList->m_Items.size()] = buffered_y;
//if (! scrollbar)
// CalculateTextPosition(m_CachedActualSize, m_TextPos, *m_GeneratedTexts[0]);

View File

@ -17,6 +17,7 @@
#include "precompiled.h"
#include <stdarg.h>
#include <string.h>
#include "lib.h"

View File

@ -18,6 +18,7 @@
#include "precompiled.h"
#include <set>
#include <algorithm>
#include "lib.h"
@ -30,7 +31,6 @@
#define PERFORM_SELF_TEST 0
#endif
/*
liberties taken:
- R(H) will remain constant

View File

@ -55,6 +55,13 @@ need only be renamed (e.g. _open, _stat).
#else
// unix/linux/glibc/gcc says that this macro has to be defined when including
// stdint.h from C++ for stdint.h to define SIZE_MAX and friends
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>

View File

@ -10,5 +10,10 @@
#ifdef _WIN32
# include "sysdep/win/wposix_types.h"
#else
// unix/linux/glibc/gcc says that this macro has to be defined when including
// stdint.h from C++ for stdint.h to define SIZE_MAX and friends
# ifndef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS
# endif
# include <stdint.h>
#endif // #ifdef _WIN32

View File

@ -25,6 +25,7 @@
#include "detect.h"
#include "adts.h"
#include "sysdep/sysdep.h"
#include "byte_order.h"
#include <vector>
#include <algorithm>

View File

@ -32,11 +32,11 @@
#include <map>
#include <list>
#include <deque>
#include <vector>
#include <string>
#include <algorithm>
// currently not thread safe. will have to change that if
// a prefetch thread is to be used.
// not safe to call before main!
@ -294,7 +294,7 @@ struct DirAndPath
: dir(d), path(p) {}
};
typedef std::deque<const DirAndPath> DirQueue;
typedef std::deque<DirAndPath> DirQueue;
// passed through TDir::addR's file_enum to dirent_cb

View File

@ -119,7 +119,7 @@ bool path_component_valid(const char* name)
// convenience function
inline void path_copy(char* dst, const char* src)
void path_copy(char* dst, const char* src)
{
strcpy_s(dst, VFS_MAX_PATH, src);
}

View File

@ -215,7 +215,7 @@ public:
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef T T;
typedef ::T T;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
@ -623,14 +623,14 @@ void tree_init()
tree_root_dir->init();
}
inline void tree_clear()
void tree_clear()
{
tree_root_dir->clearR();
}
// write a representation of the VFS tree to stdout.
inline void tree_display()
void tree_display()
{
tree_root_dir->displayR(0);
}

View File

@ -1,3 +1,6 @@
#ifndef SYSDEP_CPU_H
#define SYSDEP_CPU_H
#ifdef __cplusplus
extern "C" {
#endif
@ -40,3 +43,5 @@ extern void serialize();
#ifdef __cplusplus
}
#endif
#endif

View File

@ -17,8 +17,6 @@
#include "precompiled.h"
#ifdef _M_IX86
#include "lib.h"
#include "posix.h"
#include "ia32.h"
@ -37,6 +35,7 @@
#include <vector>
#include <algorithm>
#ifndef __GNUC__
// replace pathetic MS libc implementation
#ifdef _WIN32
@ -616,4 +615,49 @@ void serialize()
__asm cpuid
}
#endif // #ifndef _M_IX86
#else // #ifndef __GNUC__
bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value)
{
uintptr_t prev;
assert2(location >= (uintptr_t *)0x10000);
__asm__ __volatile__("lock; cmpxchgl %1,%2"
: "=a"(prev) // %0: Result in eax should be stored in prev
: "q"(new_value), // %1: new_value -> e[abcd]x
"m"(*location), // %2: Memory operand
"0"(expected) // Stored in same place as %0
: "memory"); // We make changes in memory
return prev==expected;
}
void atomic_add(intptr_t *location, intptr_t increment)
{
__asm__ __volatile__ (
"cmpb $1, %1;"
"je 1f;"
"lock;"
"1: addl %3, %0"
: "=m" (*location) /* %0: Output into *location */
: "m" (cpus), /* %1: Input for cpu check */
"m" (*location), /* %2: *location is also an input */
"r" (increment) /* %3: Increment (store in register) */
: "memory"); /* clobbers memory (*location) */
}
void mfence()
{
// no cpu caps stored in gcc compiles, so we can't check for SSE2 support
/*
if (ia32_cap(SSE2))
__asm__ __volatile__ ("mfence");
*/
}
void serialize()
{
__asm__ __volatile__ ("cpuid");
}
#endif // #ifdef __GNUC__

View File

@ -18,8 +18,8 @@
#ifndef IA32_H
#define IA32_H
#ifndef _M_IX86
#error "including ia32.h without _M_IX86 defined"
#if !(defined(__GNUC__) && defined(i386)) && !defined(_M_IX86)
#error "including ia32.h without _M_IX86 (or both __GNUC__ and i386) defined"
#endif
#include "lib/types.h"

View File

@ -13,13 +13,18 @@ static bool initialized=false;
static std::map<intptr_t, std::string> dirs;
void fam_deinit()
{
FAMClose(&fc);
}
int dir_add_watch(const char* const n_full_path, intptr_t* const watch)
{
if(!initialized)
{
CHECK_ERR(FAMOpen2(&fc, "lib_res"));
atexit2((void*)FAMClose, (uintptr_t)&fc);
initialized = true;
atexit(fam_deinit);
}
FAMRequest req;

View File

@ -4,6 +4,7 @@
#include "timer.h"
#include "sysdep/sysdep.h"
#include <stdarg.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>

View File

@ -24,6 +24,7 @@
#include <Xatom.h>
#include "lib.h"
#include "sysdep/debug.h"
#include "detect.h"
#include <algorithm>
@ -152,7 +153,7 @@ wchar_t *clipboard_get()
&len, &bytes_left,
&data);
if (result != Success)
debug_out("clipboard_get: result: %d type:%d len:%d format:%d bytes_left:%d\n",
debug_printf("clipboard_get: result: %d type:%d len:%d format:%d bytes_left:%d\n",
result, (int)type, len, format, bytes_left);
if (result == Success && bytes_left > 0)
{
@ -163,8 +164,8 @@ wchar_t *clipboard_get()
if (result == Success)
{
debug_out("clipboard_get: XGetWindowProperty succeeded, returning data\n");
debug_out("clipboard_get: data was: \"%s\", type was %d, XA_STRING atom is %d\n", data, type, XA_STRING);
debug_printf("clipboard_get: XGetWindowProperty succeeded, returning data\n");
debug_printf("clipboard_get: data was: \"%s\", type was %d, XA_STRING atom is %d\n", data, type, XA_STRING);
if (type == XA_STRING) //Latin-1: Just copy into low byte of wchar_t
{
@ -177,7 +178,7 @@ wchar_t *clipboard_get()
}
else
{
debug_out("clipboard_get: XGetWindowProperty failed!\n");
debug_printf("clipboard_get: XGetWindowProperty failed!\n");
return NULL;
}
}

View File

@ -807,6 +807,8 @@ TIMER(InitScripting)
g_ScriptingHost.DefineConstant( "ORDER_ATTACK", CEntityOrder::ORDER_ATTACK_MELEE );
g_ScriptingHost.DefineConstant( "ORDER_GATHER", CEntityOrder::ORDER_GATHER );
CNetMessage::ScriptingInit();
JSI_Camera::init();
JSI_Console::init();

View File

@ -134,9 +134,9 @@ namespace ConfigNamespace_JS
}
JSFunctionSpec Funcs[] = {
{ "WriteFile", WriteFile, 2, 0, 0},
{ "Reload", Reload, 0, 0, 0},
{ "SetFile", SetFile, 1, 0, 0},
{ "writeFile", WriteFile, 2, 0, 0},
{ "reload", Reload, 0, 0, 0},
{ "setFile", SetFile, 1, 0, 0},
{0}
};
};

View File

@ -11,177 +11,6 @@
CGame *g_Game=NULL;
/*
<<<<<<< .mine
namespace PlayerArray_JS
{
JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
CGameAttributes *pInstance=(CGameAttributes *)JS_GetPrivate(cx, obj);
if (!JSVAL_IS_INT(id))
return JS_FALSE;
uint index=g_ScriptingHost.ValueToInt(id);
// Clamp to a preset upper bound.
// FIXME I guess we'll ultimately have max players as a config variable
if (pInstance->m_NumPlayers > PS_MAX_PLAYERS)
pInstance->m_NumPlayers = PS_MAX_PLAYERS;
// Resize array according to new number of players (note that the array
// size will go up to PS_MAX_PLAYERS, but will never be made smaller -
// this to avoid losing player pointers and make sure they are all
// reclaimed in the end - it's just simpler that way ;-) )
if (pInstance->m_NumPlayers+1 > pInstance->m_Players.size())
{
for (size_t i=pInstance->m_Players.size();i<=index;i++)
{
CPlayer *pNewPlayer=new CPlayer((uint)i);
pNewPlayer->SetUpdateCallback(pInstance->m_PlayerUpdateCB, pInstance->m_PlayerUpdateCBData);
pInstance->m_Players.push_back(pNewPlayer);
}
}
if (index > pInstance->m_NumPlayers)
return JS_FALSE;
*vp=OBJECT_TO_JSVAL(pInstance->m_Players[index]->GetScript());
return JS_TRUE;
}
JSBool SetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
return JS_FALSE;
}
JSClass Class = {
"PlayerArray", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
GetProperty, SetProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub
};
JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval )
{
if (argc != 0)
return JS_FALSE;
JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj);
*rval=OBJECT_TO_JSVAL(newObj);
return JS_TRUE;
}
};
CGameAttributes::CGameAttributes():
m_UpdateCB(NULL),
m_MapFile("test01.pmp"),
m_NumPlayers(2)
{
ONCE(
g_ScriptingHost.DefineCustomObjectType(&PlayerArray_JS::Class,
PlayerArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
ScriptingInit();
);
m_PlayerArrayJS=g_ScriptingHost.CreateCustomObject("PlayerArray");
JS_SetPrivate(g_ScriptingHost.GetContext(), m_PlayerArrayJS, this);
AddSynchedProperty(L"mapFile", &m_MapFile);
AddSynchedProperty(L"numPlayers", &m_NumPlayers);
m_Players.resize(4);
for (int i=0;i<4;i++)
m_Players[i]=new CPlayer(i);
m_Players[0]->SetName(L"Gaia");
m_Players[0]->SetColour(SPlayerColour(0.2f, 0.7f, 0.2f));
m_Players[1]->SetName(L"Acumen");
m_Players[1]->SetColour(SPlayerColour(1.0f, 0.0f, 0.0f));
m_Players[2]->SetName(L"Boco the Insignificant");
m_Players[2]->SetColour(SPlayerColour(0.0f, 0.0f, 1.0f));
m_Players[3]->SetName(L"NoMonkey");
m_Players[3]->SetColour(SPlayerColour(0.5f, 0.0f, 1.0f));
}
CGameAttributes::~CGameAttributes()
{
std::vector<CPlayer *>::iterator it=m_Players.begin();
while (it != m_Players.end())
{
delete *it;
++it;
}
}
jsval CGameAttributes::JSGetPlayers()
{
return OBJECT_TO_JSVAL(m_PlayerArrayJS);
}
void CGameAttributes::SetValue(CStrW name, CStrW value)
{
ISynchedJSProperty *prop=GetSynchedProperty(name);
if (prop)
{
prop->FromString(value);
}
}
void CGameAttributes::Update(CStrW name, ISynchedJSProperty *attrib)
{
if (m_UpdateCB)
m_UpdateCB(name, attrib->ToString(), m_UpdateCBData);
}
void CGameAttributes::SetPlayerUpdateCallback(CPlayer::UpdateCallback *cb, void *userdata)
{
m_PlayerUpdateCB=cb;
m_PlayerUpdateCBData=userdata;
for (size_t i=0;i<m_Players.size();i++)
{
m_Players[i]->SetUpdateCallback(cb, userdata);
}
}
void CGameAttributes::ScriptingInit()
{
AddClassProperty(L"players", (GetFn)&CGameAttributes::JSGetPlayers);
CJSObject<CGameAttributes>::ScriptingInit( "Game" );
}
/*void CGameAttributes::CreateJSObject()
{
CAttributeMap::CreateJSObject();
ONCE(
g_ScriptingHost.DefineCustomObjectType(&PlayerArray_JS::Class,
PlayerArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
);
m_PlayerArrayJS=g_ScriptingHost.CreateCustomObject("PlayerArray");
JS_SetPrivate(g_ScriptingHost.GetContext(), m_PlayerArrayJS, this);
int flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
JS_DefineProperty(g_ScriptingHost.GetContext(), m_JSObject, "players",
OBJECT_TO_JSVAL(m_PlayerArrayJS), NULL, NULL, flags);
}
JSBool CGameAttributes::GetJSProperty(jsval id, jsval *ret)
{
CStr name=g_ScriptingHost.ValueToString(id);
if (name == CStr("players"))
return JS_TRUE;
return CAttributeMap::GetJSProperty(id, ret);
}*//*
=======
>>>>>>> .r2037
*/
// Disable "warning C4355: 'this' : used in base member initializer list".
// "The base-class constructors and class member constructors are called before
// this constructor. In effect, you've passed a pointer to an unconstructed

View File

@ -18,59 +18,6 @@ ERROR_GROUP(Game);
// This may be overriden by system.cfg ("max_players")
#define PS_MAX_PLAYERS 6
/*
<<<<<<< .mine
namespace PlayerArray_JS
{
JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
};
#define g_GameAttributes CGameAttributes::GetSingleton()
class CGameAttributes:
public CSynchedJSObject<CGameAttributes>,
public Singleton<CGameAttributes>
{
public:
typedef void (UpdateCallback)(CStrW name, CStrW newValue, void *data);
private:
friend JSBool PlayerArray_JS::GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
virtual void Update(CStrW name, ISynchedJSProperty *attrib);
UpdateCallback *m_UpdateCB;
void *m_UpdateCBData;
CPlayer::UpdateCallback *m_PlayerUpdateCB;
void *m_PlayerUpdateCBData;
jsval JSGetPlayers();
public:
CStrW m_MapFile;
uint m_NumPlayers;
CGameAttributes();
virtual ~CGameAttributes();
void SetValue(CStrW name, CStrW value);
inline void SetUpdateCallback(UpdateCallback *cb, void *userdata)
{
m_UpdateCB=cb;
m_UpdateCBData=userdata;
}
void SetPlayerUpdateCallback(CPlayer::UpdateCallback *cb, void *userdata);
std::vector <CPlayer *> m_Players;
JSObject *m_PlayerArrayJS;
static void ScriptingInit();
};
=======
>>>>>>> .r2037
*/
class CGame
{
CWorld m_World;

View File

@ -1,4 +1,7 @@
#include "precompiled.h"
#include "CLogger.h"
#include "Interact.h"
#include "Renderer.h"
#include "input.h"
@ -22,6 +25,8 @@ extern CStr g_CursorName;
static const float SELECT_DBLCLICK_RATE = 0.5f;
const int ORDER_DELAY = 5;
bool customSelectionMode=false;
void CSelectedEntities::addSelection( HEntity entity )
{
m_group = -1;
@ -356,6 +361,10 @@ void CSelectedEntities::update()
{
static std::vector<HEntity> lastSelection;
// Drop out immediately if we're in some special interaction mode
if (customSelectionMode)
return;
if( !( m_selected == lastSelection ) )
{
g_JSGameEvents.FireSelectionChanged( m_selectionChanged );
@ -367,17 +376,18 @@ void CSelectedEntities::update()
// Can't order anything off the map
if( !g_Game->GetWorld()->GetTerrain()->isOnMap( g_Mouseover.m_worldposition ) )
{
m_contextOrder = -1;
m_defaultCommand = -1;
return;
}
// Quick count to see which is the modal default order.
int defaultPoll[CEntityOrder::ORDER_LAST];
std::map<CStrW, int, CStrW_hash_compare> defaultCursor[CEntityOrder::ORDER_LAST];
const int numCommands=NMT_COMMAND_LAST - NMT_COMMAND_FIRST;
int defaultPoll[numCommands];
std::map<CStrW, int, CStrW_hash_compare> defaultCursor[numCommands];
int t, vote;
for( t = 0; t < CEntityOrder::ORDER_LAST; t++ )
for( t = 0; t < numCommands; t++ )
defaultPoll[t] = 0;
std::vector<HEntity>::iterator it;
@ -385,9 +395,9 @@ void CSelectedEntities::update()
{
CEventTargetChanged evt( g_Mouseover.m_target );
(*it)->DispatchEvent( &evt );
vote = evt.m_defaultAction;
vote = evt.m_defaultAction - NMT_COMMAND_FIRST;
if( ( vote >= 0 ) && ( vote < CEntityOrder::ORDER_LAST ) )
if( ( vote >= 0 ) && ( vote < numCommands ) )
{
defaultPoll[vote]++;
defaultCursor[vote][evt.m_defaultCursor]++;
@ -395,14 +405,14 @@ void CSelectedEntities::update()
}
vote = -1;
for( t = 0; t < CEntityOrder::ORDER_LAST; t++ )
for( t = 0; t < numCommands; t++ )
{
if( ( vote == -1 ) || ( defaultPoll[t] > defaultPoll[vote] ) )
vote = t;
}
std::map<CStrW, int, CStrW_hash_compare>::iterator itv;
m_contextOrder = vote;
m_defaultCommand = vote + NMT_COMMAND_FIRST;
// Now find the most appropriate cursor
t = 0;
@ -422,176 +432,6 @@ void CSelectedEntities::update()
}
void CSelectedEntities::setContext( int contextOrder )
{
assert( isContextValid( contextOrder ) );
m_contextOrder = contextOrder;
}
bool CSelectedEntities::nextContext()
{
// No valid orders?
if( m_contextOrder == -1 ) return( false );
int t = m_contextOrder + 1;
while( t != m_contextOrder )
{
if( t == CEntityOrder::ORDER_LAST ) t = 0;
if( isContextValid( t ) ) break;
t++;
}
if( m_contextOrder == t )
return( false );
m_contextOrder = t;
return( true );
}
bool CSelectedEntities::previousContext()
{
// No valid orders?
if( m_contextOrder == -1 ) return( false );
int t = m_contextOrder - 1;
while( t != m_contextOrder )
{
if( isContextValid( t ) ) break;
if( t == 0 ) t = CEntityOrder::ORDER_LAST;
t--;
}
if( m_contextOrder == t )
return( false );
m_contextOrder = t;
return( true );
}
bool CSelectedEntities::isContextValid( int contextOrder )
{
if( contextOrder == -1 ) return( false );
// Can't order anything off the map
if( !g_Game->GetWorld()->GetTerrain()->isOnMap( g_Mouseover.m_worldposition ) )
return( false );
// Check to see if any member of the selection supports this order type.
std::vector<HEntity>::iterator it;
for( it = m_selected.begin(); it < m_selected.end(); it++ )
if( (*it)->acceptsOrder( contextOrder, g_Mouseover.m_target ) )
return( true );
return( false );
}
void CSelectedEntities::contextOrder( bool pushQueue )
{
CCamera *pCamera=g_Game->GetView()->GetCamera();
CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain();
std::vector<HEntity>::iterator it;
CEntityOrder context, contextRandomized;
(int&)context.m_type = m_contextOrder;
switch( m_contextOrder )
{
// PATROL order: temporatily disabled until we define the network command for it
case CEntityOrder::ORDER_PATROL:
case CEntityOrder::ORDER_GOTO:
{
context.m_data[0].location = g_Mouseover.m_worldposition;
break;
/*
CGotoCommand *msg=new CGotoCommand();
msg->m_Entity=m_selected[0]->me;
msg->m_TargetX=(u32)g_Mouseover.m_worldposition.x;
msg->m_TargetY=(u32)g_Mouseover.m_worldposition.y;
g_Game->GetSimulation()->QueueLocalCommand(msg);
break;
*/
}
case CEntityOrder::ORDER_ATTACK_MELEE:
{
context.m_data[0].entity = g_Mouseover.m_target;
for( it = m_selected.begin(); it < m_selected.end(); it++ )
if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) )
{
if( !pushQueue )
(*it)->clearOrders();
(*it)->pushOrder( context );
}
return;
}
case CEntityOrder::ORDER_GATHER:
{
context.m_data[0].entity = g_Mouseover.m_target;
for( it = m_selected.begin(); it < m_selected.end(); it++ )
if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) )
{
if( !pushQueue )
(*it)->clearOrders();
(*it)->pushOrder( context );
}
return;
}
default:
break;
}
// Location randomizer, for group orders...
// Having the group turn up at the destination with /some/ sort of cohesion is good
// but tasking them all to the exact same point will leave them brawling for it
// at the other end (it shouldn't, but the PASAP pathfinder is too simplistic)
// Task them all to a point within a radius of the target, radius depends upon
// the number of units in the group.
/* (Simon)
Hmm. Disabled in the makeshift transition to Command Message Queueing...
Ideally, we'd create a Group with the selected entities, then queue a
command with the Group ID as performing entity, with the center as the
target, then let the location randomization be done in the
net command=>ent. order translator (for now, CSimulation::TranslateMessage)
Unless this is a problem that'll only be around until we make the real
pathfinder?
*/
float radius = 2.0f * sqrt( (float)m_selected.size() - 1 );
float _x, _y;
for( it = m_selected.begin(); it < m_selected.end(); it++ )
if( ( (*it)->GetPlayer() == g_Game->GetLocalPlayer() ) &&
( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) ) )
{
contextRandomized = context;
do
{
_x = (float)( rand() % 20000 ) / 10000.0f - 1.0f;
_y = (float)( rand() % 20000 ) / 10000.0f - 1.0f;
}
while( ( _x * _x ) + ( _y * _y ) > 1.0f );
contextRandomized.m_data[0].location.x += _x * radius;
contextRandomized.m_data[0].location.y += _y * radius;
// Clamp it to within the map, just in case.
float mapsize = (float)g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide() * CELL_SIZE;
if( contextRandomized.m_data[0].location.x < 0.0f )
contextRandomized.m_data[0].location.x = 0.0f;
if( contextRandomized.m_data[0].location.x >= mapsize )
contextRandomized.m_data[0].location.x = mapsize;
if( contextRandomized.m_data[0].location.y < 0.0f )
contextRandomized.m_data[0].location.y = 0.0f;
if( contextRandomized.m_data[0].location.y >= mapsize )
contextRandomized.m_data[0].location.y = mapsize;
if( !pushQueue )
(*it)->clearOrders();
(*it)->pushOrder( contextRandomized );
}
}
void CMouseoverEntities::update( float timestep )
{
CCamera *pCamera=g_Game->GetView()->GetCamera();
@ -881,6 +721,58 @@ void CMouseoverEntities::stopBandbox()
m_bandbox = false;
}
void FireWorldClickEvent(uint button, int clicks)
{
debug_printf("FireWorldClickEvent: button %d, clicks %d\n", button, clicks);
g_JSGameEvents.FireWorldClick(
button,
clicks,
g_Selection.m_defaultCommand,
-1, // FIXME Secondary command, depends entity scripts etc
g_Mouseover.m_target,
(uint)g_Mouseover.m_worldposition.x,
(uint)g_Mouseover.m_worldposition.y);
}
void MouseButtonUpHandler(const SDL_Event *ev, int clicks)
{
FireWorldClickEvent(ev->button.button, clicks);
switch( ev->button.button )
{
case SDL_BUTTON_LEFT:
if (customSelectionMode)
break;
if( g_Mouseover.m_viewall )
break;
if( clicks == 2 )
{
// Double click
g_Mouseover.expandAcrossScreen();
}
else if( clicks == 3 )
{
// Triple click
g_Mouseover.expandAcrossWorld();
}
g_Mouseover.stopBandbox();
if( hotkeys[HOTKEY_SELECTION_ADD] )
{
g_Mouseover.addSelection();
}
else if( hotkeys[HOTKEY_SELECTION_REMOVE] )
{
g_Mouseover.removeSelection();
}
else
g_Mouseover.setSelection();
break;
}
}
int interactInputHandler( const SDL_Event* ev )
{
if (!g_active || !g_Game)
@ -890,13 +782,19 @@ int interactInputHandler( const SDL_Event* ev )
CCamera *pCamera=pView->GetCamera();
CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain();
static float lastclicktime = 0.0f;
static HEntity lastclickobject;
static u8 clicks = 0;
// One entry for each of five mouse buttons (SDL mouse buttons 1-5, mouse
// buttons over 5 if existant, will be ignored)
static float lastclicktime[5] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
static HEntity lastclickobject[5];
static u8 clicks[5] = {0, 0, 0, 0, 0};
static u16 button_down_x, button_down_y;
static float button_down_time;
static bool button_down = false;
if (customSelectionMode && ev->type != SDL_MOUSEBUTTONUP)
return EV_PASS;
switch( ev->type )
{
case SDL_HOTKEYDOWN:
@ -909,12 +807,6 @@ int interactInputHandler( const SDL_Event* ev )
if( g_Selection.m_selected.size() )
pView->SetCameraTarget( g_Selection.getSelectionPosition() );
break;
case HOTKEY_CONTEXTORDER_NEXT:
g_Selection.nextContext();
break;
case HOTKEY_CONTEXTORDER_PREVIOUS:
g_Selection.previousContext();
break;
default:
if( ( ev->user.code >= HOTKEY_SELECTION_GROUP_0 ) && ( ev->user.code <= HOTKEY_SELECTION_GROUP_19 ) )
{
@ -964,53 +856,34 @@ int interactInputHandler( const SDL_Event* ev )
}
return( EV_HANDLED );
case SDL_MOUSEBUTTONUP:
switch( ev->button.button )
{
// Assumes SDL button enums in range [1, 5]
int button = ev->button.button - 1;
// Only process buttons within the range for which we have button state
// arrays above.
if (button >= 0 && button < 5)
{
case SDL_BUTTON_LEFT:
if( g_Mouseover.m_viewall )
break;
float time;
time = (float)get_time();
// Reset clicks counter if too slow or if the cursor's
// hovering over something else now.
if( time - lastclicktime >= SELECT_DBLCLICK_RATE )
clicks = 0;
if( g_Mouseover.m_target != lastclickobject )
clicks = 0;
clicks++;
if( time - lastclicktime[button] >= SELECT_DBLCLICK_RATE )
clicks[button] = 0;
if( g_Mouseover.m_target != lastclickobject[button] )
clicks[button] = 0;
clicks[button]++;
if( clicks == 2 )
{
// Double click
g_Mouseover.expandAcrossScreen();
}
else if( clicks == 3 )
{
// Triple click
g_Mouseover.expandAcrossWorld();
}
lastclicktime = time;
lastclickobject = g_Mouseover.m_target;
lastclicktime[button] = time;
lastclickobject[button] = g_Mouseover.m_target;
button_down = false;
g_Mouseover.stopBandbox();
if( hotkeys[HOTKEY_SELECTION_ADD] )
{
g_Mouseover.addSelection();
}
else if( hotkeys[HOTKEY_SELECTION_REMOVE] )
{
g_Mouseover.removeSelection();
}
else
g_Mouseover.setSelection();
break;
case SDL_BUTTON_RIGHT:
g_Selection.contextOrder( hotkeys[HOTKEY_ORDER_QUEUE] );
break;
if (ev->button.button == SDL_BUTTON_LEFT)
button_down = false;
MouseButtonUpHandler(ev, clicks[button]);
}
break;
}
case SDL_MOUSEBUTTONDOWN:
switch( ev->button.button )
{
@ -1018,6 +891,7 @@ int interactInputHandler( const SDL_Event* ev )
button_down = true;
button_down_x = ev->button.x;
button_down_y = ev->button.y;
button_down_time = get_time();
break;
}
break;
@ -1057,3 +931,13 @@ bool isMouseoverType( CEntity* ev, void* userdata )
}
return( false );
}
void StartCustomSelection()
{
customSelectionMode = true;
}
void ResetInteraction()
{
customSelectionMode = false;
}

View File

@ -29,14 +29,14 @@ struct CSelectedEntities : public Singleton<CSelectedEntities>
clearSelection();
m_group = -1;
m_group_highlight = -1;
m_contextOrder = -1;
m_defaultCommand = -1;
m_selectionChanged = true;
}
std::vector<HEntity> m_selected;
std::vector<HEntity> m_groups[MAX_GROUPS];
i8 m_group, m_group_highlight;
bool m_selectionChanged;
int m_contextOrder;
int m_defaultCommand;
void addSelection( HEntity entity );
void removeSelection( HEntity entity );
@ -57,11 +57,6 @@ struct CSelectedEntities : public Singleton<CSelectedEntities>
CVector3D getGroupPosition( i8 groupid );
void update();
bool isContextValid( int contextOrder );
void contextOrder( bool pushQueue = false );
void setContext( int contextOrder );
bool nextContext();
bool previousContext();
void renderSelectionOutlines();
void renderOverlays();
@ -121,6 +116,9 @@ struct CMouseoverEntities : public Singleton<CMouseoverEntities>
bool isMouseoverType( CEntity* ev, void* userdata );
bool isOnScreen( CEntity* ev, void* userdata );
void StartCustomSelection();
void ResetInteraction();
int interactInputHandler( const SDL_Event* ev );
#define g_Selection CSelectedEntities::GetSingleton()

View File

@ -7,7 +7,7 @@
#include "precompiled.h"
#include <deque>
#include <functional>
#include <numeric>
#include "lib.h" // error codes
#include "timer.h"
@ -66,7 +66,7 @@ struct LoadRequest
}
};
typedef std::deque<const LoadRequest> LoadRequests;
typedef std::deque<LoadRequest> LoadRequests;
static LoadRequests load_requests;
// std::accumulate binary op; used by LDR_EndRegistering to sum up all

View File

@ -56,9 +56,12 @@ enum ENetMessageType
NMT_StartGame,
/* In-Game Stage */
NMT_EndCommandBatch,
NMT_COMMAND_FIRST,
NMT_GotoCommand=NMT_COMMAND_FIRST,
NMT_COMMAND_LAST=NMT_GotoCommand,
NMT_Goto, NMT_COMMAND_FIRST=NMT_Goto,
NMT_Patrol,
NMT_AddWaypoint,
NMT_AttackMelee,
NMT_Gather,
NMT_COMMAND_LAST,
/* Post-Game Stage */
/**
@ -120,6 +123,7 @@ enum
#define ALLNETMSGS_DONT_CREATE_NMTS
#define START_NMT_CLASS_(_nm) START_NMT_CLASS(C ## _nm, NMT_ ## _nm)
#define DERIVE_NMT_CLASS_(_base, _nm) START_NMT_CLASS_DERIVED(C ## _base, C ## _nm, NMT_ ## _nm)
START_NMTS()
@ -198,24 +202,32 @@ START_NMT_CLASS_(EndCommandBatch)
NMT_FIELD_INT(m_TurnLength, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(GotoCommand)
NMT_FIELD(HEntity, m_Entity)
START_NMT_CLASS(CCommand, NMT_NONE)
NMT_FIELD(CEntityList, m_Entities)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Goto)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
/*
#define NMT_FIELD_MAPPOS(_nm) NMT_FIELD_INT(_nm##X, u32, 2) NMT_FIELD_INT(_nm##Y, u32, 2)
START_NMT_CLASS_(SetWaypoint)
NMT_FIELD(HEntity, m_Entity)
NMT_FIELD_MAPPOS(m_Target)
DERIVE_NMT_CLASS_(Command, Patrol)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(AddWaypoint)
NMT_FIELD(HEntity, m_Entity)
NMT_FIELD_MAPPOS(m_Target)
END_NMY_CLASS()*/
DERIVE_NMT_CLASS_(Command, AddWaypoint)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, AttackMelee)
NMT_FIELD(HEntity, m_Target)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Gather)
NMT_FIELD(HEntity, m_Target)
END_NMT_CLASS()
END_NMTS()

View File

@ -324,7 +324,7 @@ bool CNetClient::InGameHandler(CNetMessage *pMsg, CNetSession *pSession)
CHAIN(BaseHandler);
CHAIN(ChatHandler);
if (msgType >= NMT_COMMAND_FIRST && msgType <= NMT_COMMAND_LAST)
if (msgType >= NMT_COMMAND_FIRST && msgType < NMT_COMMAND_LAST)
{
pClient->QueueMessage(1, pMsg);
TAKEN(pMsg);

View File

@ -9,6 +9,7 @@
#undef START_NMTS
#undef END_NMTS
#undef START_NMT_CLASS
#undef START_NMT_CLASS_DERIVED
#undef NMT_FIELD_INT
#undef NMT_FIELD
#undef NMT_START_ARRAY
@ -32,18 +33,29 @@
#define START_NMTS()
#define END_NMTS()
#define START_NMT_CLASS(_nm, _tp) \
START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
/**
* Start the definition of a network message type.
*
* @param _base The name of the base class of the message
* @param _nm The name of the class
* @param _tp The NetMessageType associated with the class. It is *not* safe to
* have several classes with the same value of _tp in the same executable
*/
#define START_NMT_CLASS(_nm, _tp) \
#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
CNetMessage *Deserialize##_nm(const u8 *, uint); \
struct _nm: public CNetMessage \
class _nm: public _base \
{ \
_nm(): CNetMessage(_tp) {} \
protected: \
_nm(ENetMessageType type): _base(type) {}\
\
/* This one is for subclasses that want to use the base class' string */ \
/* converters to get SubMessage { <parent fields>, ... } */ \
CStr GetStringRaw() const;\
public: \
_nm(): _base(_tp) {} \
virtual uint GetSerializedLength() const; \
virtual u8 *Serialize(u8 *buffer) const; \
virtual const u8 *Deserialize(const u8 *pos, const u8 *end); \
@ -103,9 +115,11 @@ struct _nm: public CNetMessage \
#define END_NMTS()
#define START_NMT_CLASS(_nm, _tp) \
START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
uint _nm::GetSerializedLength() const \
{ \
uint ret=0; \
uint ret=_base::GetSerializedLength(); \
const _nm *thiz=this;
#define NMT_START_ARRAY(_nm) \
@ -140,10 +154,12 @@ uint _nm::GetSerializedLength() const \
#define END_NMTS()
#define START_NMT_CLASS(_nm, _tp) \
START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
u8 *_nm::Serialize(u8 *buffer) const \
{ \
/*printf("In " #_nm "::Serialize()\n");*/ \
u8 *pos=buffer; \
u8 *pos=_base::Serialize(buffer); \
const _nm *thiz=this;
#define NMT_START_ARRAY(_nm) \
@ -181,6 +197,8 @@ u8 *_nm::Serialize(u8 *buffer) const \
#define BAIL_DESERIALIZER return NULL
#define START_NMT_CLASS(_nm, _tp) \
START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
CNetMessage *Deserialize##_nm(const u8 *buffer, uint length) \
{ \
_nm *ret=new _nm(); \
@ -191,6 +209,7 @@ CNetMessage *Deserialize##_nm(const u8 *buffer, uint length) \
} \
const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \
{ \
pos=_base::Deserialize(pos, end); \
_nm *thiz=this; \
/*printf("In Deserialize" #_nm "\n"); */
@ -229,6 +248,8 @@ const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \
#define END_NMTS() { NMT_NONE, NULL } };
#define START_NMT_CLASS(_nm, _tp) \
START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp)
#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
{ _tp, Deserialize##_nm },
#define NMT_START_ARRAY(_nm)
@ -254,6 +275,22 @@ const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \
CStr _nm::GetString() const \
{ \
CStr ret=#_nm _T(" { "); \
return ret + GetStringRaw() + _T(" }"); \
} \
CStr _nm::GetStringRaw() const \
{ \
CStr ret; \
const _nm *thiz=this;
#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \
CStr _nm::GetString() const \
{ \
CStr ret=#_nm _T(" { "); \
return ret + GetStringRaw() + _T(" }"); \
} \
CStr _nm::GetStringRaw() const \
{ \
CStr ret=_base::GetStringRaw() + _T(", "); \
const _nm *thiz=this;
#define NMT_START_ARRAY(_nm) \
@ -281,7 +318,7 @@ CStr _nm::GetString() const \
ret += _T(", ");
#define END_NMT_CLASS() \
return ret.GetSubstring(0, ret.Length()-2)+_T(" }"); \
return ret.GetSubstring(0, ret.Length()-2); \
}
#include "NMTCreator.h"

View File

@ -5,6 +5,8 @@
#include <stdio.h>
#include <map>
#include "Entity.h"
#define ALLNETMSGS_IMPLEMENT
#include "NetMessage.h"
@ -69,3 +71,98 @@ CNetMessage *CNetMessage::DeserializeMessage(ENetMessageType type, u8 *buffer, u
return (pDes)(buffer, length);
}
void CNetMessage::ScriptingInit()
{
#define def(_msg) g_ScriptingHost.DefineConstant(#_msg, _msg)
def(NMT_Goto);
def(NMT_Patrol);
def(NMT_AddWaypoint);
def(NMT_AttackMelee);
def(NMT_Gather);
}
CCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSContext *cx, uintN argc, jsval *argv)
{
assert(argc >= 1);
int msgType;
try
{
msgType = g_ScriptingHost.ValueToInt( argv[0] );
}
catch(PSERROR_Scripting_ConversionFailed)
{
JS_ReportError(cx, "Invalid order type");
return NULL;
}
#define ArgumentCountError() STMT(\
JS_ReportError(cx, "Too few parameters!"); \
return NULL; )
#define ArgumentTypeError() STMT(\
JS_ReportError(cx, "Parameter type error!"); \
return NULL; )
#define ReadPosition(_msg, _field) \
try { \
if (argIndex+2 > argc) \
ArgumentCountError();\
if (!JSVAL_IS_INT(argv[argIndex]) || !JSVAL_IS_INT(argv[argIndex+1])) \
ArgumentTypeError(); \
_msg->_field ## X = g_ScriptingHost.ValueToInt(argv[argIndex++]); \
_msg->_field ## Y = g_ScriptingHost.ValueToInt(argv[argIndex++]); \
} catch (PSERROR_Scripting_ConversionFailed) { \
JS_ReportError(cx, "Invalid location"); \
return NULL; \
}
#define ReadEntity(_msg, _field) \
STMT(\
if (argIndex+1 > argc) \
ArgumentCountError(); \
if (!JSVAL_IS_OBJECT(argv[argIndex])) \
ArgumentTypeError(); \
CEntity *ent=ToNative<CEntity>(argv[argIndex++]); \
if (!ent) \
{ \
JS_ReportError(cx, "Invalid entity parameter"); \
return NULL; \
} \
_msg->_field=ent->me; \
)
#define PositionMessage(_msg) \
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_Entities = entities; \
ReadPosition(msg, m_Target); \
return msg; \
}
#define EntityMessage(_msg) \
case NMT_ ## _msg: \
{ \
C##_msg *msg = new C##_msg(); \
msg->m_Entities = entities; \
ReadEntity(msg, m_Target); \
return msg; \
}
// argIndex, incremented by reading macros. We have already "eaten" the
// first argument (message type)
uint argIndex = 1;
switch (msgType)
{
// NMT_Goto, targetX, targetY
PositionMessage(Goto)
PositionMessage(Patrol)
PositionMessage(AddWaypoint)
EntityMessage(AttackMelee)
EntityMessage(Gather)
default:
JS_ReportError(cx, "Invalid order type");
return NULL;
}
}

View File

@ -11,6 +11,9 @@
#include "AllNetMessages.h"
#undef ALLNETMSGS_DONT_CREATE_NMTS
class CCommand;
class CEntityList;
/**
* The base class for network messages
*/
@ -63,6 +66,14 @@ public:
* there was an error in data format.
*/
static CNetMessage *DeserializeMessage(ENetMessageType type, u8 *buffer, uint length);
/**
* Register a selection of message types as JS constants.
* The constant's names will be the same as those of the enums
*/
static void ScriptingInit();
static CCommand *CommandFromJSArgs(const CEntityList &entities, JSContext* cx, uintN argc, jsval* argv);
};
typedef CNetMessage * (*NetMessageDeserializer) (const u8 *buffer, uint length);

View File

@ -182,7 +182,7 @@ bool CNetServerSession::InGameHandler(CNetMessage *pMsg, CNetSession *pNetSessio
if (ChatHandler(pMsg, pNetSession))
return true;
if (pMsg->GetType() >= NMT_COMMAND_FIRST && pMsg->GetType() <= NMT_COMMAND_LAST)
if (pMsg->GetType() >= NMT_COMMAND_FIRST && pMsg->GetType() < NMT_COMMAND_LAST)
{
// All Command Messages (i.e. simulation turn synchronized messages)
//pSession->m_pPlayer->ValidateCommand(pMsg);

View File

@ -40,7 +40,7 @@ void CPlayer::ScriptingInit()
// AddClassProperty( L"name", &CPlayer::m_Name );
// AddClassProperty( L"colour", &CPlayer::m_Colour );
AddProperty( L"controlled", (IJSObject::GetFn)JSI_GetControlledEntities );
AddProperty( L"controlled", (IJSObject::GetFn)&CPlayer::JSI_GetControlledEntities );
CJSObject<CPlayer>::ScriptingInit( "Player" );
}

View File

@ -173,7 +173,7 @@ bool CProfileNode::Return()
void CProfileNode::ScriptingInit()
{
AddProperty( L"name", (IJSObject::GetFn)CProfileNode::JS_GetName );
AddProperty( L"name", (IJSObject::GetFn)&CProfileNode::JS_GetName );
/*
AddReadOnlyClassProperty( L"callsTotal", &CProfileNode::calls_total );
AddReadOnlyClassProperty( L"callsPerFrame", &CProfileNode::calls_frame_last );

View File

@ -7,6 +7,8 @@
#include "CLogger.h"
#define LOG_CATEGORY "vfs"
#include <deque>
using namespace VFSUtil;
// Because I'm lazy, and it saves a few lines of code in other places:
@ -73,7 +75,7 @@ int VFSUtil::EnumDirEnts(const CStr start_path, const char* user_filter,
// (less stack usage; avoids seeks by reading all entries in a
// directory consecutively)
std::deque<const CStr> dir_queue;
std::deque<CStr> dir_queue;
dir_queue.push_back(start_path);
// for each directory:

View File

@ -283,7 +283,7 @@ template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::E
std::vector<T>* b = RetrieveSet( cx, JSVAL_TO_OBJECT( argv[0] ) );
if( !b )
return( JS_FALSE );
std::vector<T>::iterator ita, itb;
typename std::vector<T>::iterator ita, itb;
size_t seek = a->size();
for( ita = a->begin(); ita != a->end(); ita++ )

View File

@ -91,48 +91,3 @@ JSBool JSI_Selection::setGroups( JSContext* context, JSObject* obj, jsval id, js
return( JS_TRUE );
}
JSBool JSI_Selection::isValidContextOrder( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
{
assert( argc >= 1 );
int orderCode;
try
{
orderCode = g_ScriptingHost.ValueToInt( argv[0] );
}
catch( ... )
{
JS_ReportError( context, "Invalid order type" );
*rval = BOOLEAN_TO_JSVAL( false );
return( JS_TRUE );
}
*rval = BOOLEAN_TO_JSVAL( g_Selection.isContextValid( orderCode ) );
return( JS_TRUE );
}
JSBool JSI_Selection::getContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp )
{
*vp = INT_TO_JSVAL( g_Selection.m_contextOrder );
return( JS_TRUE );
}
JSBool JSI_Selection::setContextOrder( JSContext* context, JSObject* obj, jsval id, jsval* vp )
{
int orderCode;
try
{
orderCode = g_ScriptingHost.ValueToInt( *vp );
}
catch( ... )
{
JS_ReportError( context, "Invalid order type" );
return( JS_TRUE );
}
if( !g_Selection.isContextValid( orderCode ) )
{
JS_ReportError( context, "Order is not valid in this context: %d", orderCode );
return( JS_TRUE );
}
g_Selection.setContext( orderCode );
return( JS_TRUE );
}

View File

@ -1,5 +1,7 @@
#include "precompiled.h"
#include <sstream>
#include "ps/CStr.h"
#include "ps/VFSUtil.h"
#include "lib/res/res.h"
@ -7,7 +9,6 @@
#include "scripting/JSConversions.h"
#include "scripting/JSInterface_VFS.h"
// shared error handling code
#define JS_CHECK_FILE_ERR(err)\
/* this is liable to happen often, so don't complain */\

View File

@ -148,7 +148,7 @@ void CScriptEvent::ScriptingInit()
AddMethod<jsval, &CScriptEvent::ToString>( "toString", 0 );
AddMethod<jsval, &CScriptEvent::PreventDefault>( "preventDefault", 0 );
AddMethod<jsval, &CScriptEvent::PreventDefault>( "cancel", 0 );
AddMethod<jsval, StopPropagation>( "stopPropagation", 0 );
AddMethod<jsval, &CScriptEvent::StopPropagation>( "stopPropagation", 0 );
AddProperty( L"type", &CScriptEvent::m_Type, true );
AddProperty( L"cancelable", &CScriptEvent::m_Cancelable, true );

View File

@ -20,6 +20,7 @@ enum EEventType
EVENT_GAME_START = 0,
EVENT_GAME_TICK,
EVENT_SELECTION_CHANGED,
EVENT_WORLD_CLICK,
};
// Only used for entity events...

View File

@ -18,18 +18,58 @@ class CGameEvents : public IEventTarget, public Singleton<CGameEvents>
{
bool m_CausedByPlayer;
public:
CEventSelectionChanged( bool CausedByPlayer ) : CScriptEvent( L"selectionChanged", EVENT_SELECTION_CHANGED, false )
CEventSelectionChanged(bool CausedByPlayer):
CScriptEvent( L"selectionChanged", EVENT_SELECTION_CHANGED, false ),
m_CausedByPlayer(CausedByPlayer)
{
AddLocalProperty( L"byPlayer", &m_CausedByPlayer, true );
}
};
class CEventWorldClick: public CScriptEvent
{
int m_Button;
int m_Clicks;
int m_Command;
int m_SecondaryCommand;
CEntity *m_Entity;
uint m_X, m_Y;
public:
CEventWorldClick(int button, int clicks, int command, int secCommand, CEntity *ent, uint x, uint y):
CScriptEvent(L"worldClick", EVENT_WORLD_CLICK, false),
m_Button(button),
m_Clicks(clicks),
m_Command(command),
m_SecondaryCommand(secCommand),
m_Entity(ent),
m_X(x),
m_Y(y)
{
AddLocalProperty(L"button", &m_Button);
AddLocalProperty(L"clicks", &m_Clicks);
AddLocalProperty(L"command", &m_Command);
AddLocalProperty(L"secondaryCommand", &m_SecondaryCommand);
if (ent)
AddLocalProperty(L"entity", &m_Entity);
else
AddProperty(L"entity", JSVAL_NULL);
AddLocalProperty(L"x", &m_X);
AddLocalProperty(L"y", &m_Y);
}
};
public:
void FireSelectionChanged( bool CausedByPlayer )
{
CEventSelectionChanged evt( CausedByPlayer );
DispatchEvent( &evt );
}
void FireWorldClick(int button, int clicks, int command, int secCommand, CEntity *ent, uint x, uint y)
{
CEventWorldClick evt(button, clicks, command, secCommand, ent, x, y);
DispatchEvent(&evt);
}
};
#define g_JSGameEvents CGameEvents::GetSingleton()

View File

@ -13,6 +13,7 @@
#include "LightEnv.h"
#include "MapWriter.h"
#include "GameEvents.h"
#include "Interact.h"
#include "Game.h"
#include "Network/Server.h"
@ -82,6 +83,8 @@ JSFunctionSpec ScriptFunctionTable[] =
{"v3dist", v3dist, 2, 0, 0 },
{"issueCommand", issueCommand, 2, 0, 0 },
{"exit", exitProgram, 0, 0, 0 },
{"crash", crash, 0, 0, 0 },
{"forceGC", forceGC, 0, 0, 0 },
@ -108,6 +111,7 @@ JSPropertySpec ScriptGlobalTable[] =
{ "players", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetPlayerSet, NULL },
{ "localPlayer", 0, JSPROP_PERMANENT, GetLocalPlayer, SetLocalPlayer },
{ "gaiaPlayer", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetGaiaPlayer, NULL },
{ "gameView", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetGameView, NULL },
{ 0, 0, 0, 0, 0 },
};
@ -238,6 +242,15 @@ JSBool SetLocalPlayer( JSContext* context, JSObject* obj, jsval id, jsval* vp )
return( JS_TRUE );
}
JSBool GetGameView( JSContext* cx, JSObject* globalObject, jsval id, jsval* vp )
{
if (g_Game)
*vp = OBJECT_TO_JSVAL( g_Game->GetView()->GetScript() );
else
*vp = JSVAL_NULL;
return( JS_TRUE );
}
JSBool AddGlobalHandler( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
{
*rval = BOOLEAN_TO_JSVAL( g_JSGameEvents.AddHandlerJS( cx, argc, argv ) );
@ -553,3 +566,30 @@ JSBool _rewriteMaps(JSContext* UNUSEDPARAM(context), JSObject* UNUSEDPARAM(globa
CMapWriter::RewriteAllMaps(g_Game->GetWorld()->GetTerrain(), g_Game->GetWorld()->GetUnitManager(), &g_LightEnv);
return JS_TRUE;
}
JSBool issueCommand(JSContext* context, JSObject* UNUSEDPARAM(globalObject), unsigned int argc, jsval* argv, jsval* rval)
{
assert(argc >= 2);
assert(JSVAL_IS_OBJECT(argv[0]));
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(context, JSVAL_TO_OBJECT(argv[0]));
CNetMessage *msg=CNetMessage::CommandFromJSArgs(entities, context, argc-1, argv+1);
if (msg)
{
g_Console->InsertMessage(L"issueCommand: %hs", msg->GetString().c_str());
*rval = g_ScriptingHost.UCStringToValue(msg->GetString());
g_Game->GetSimulation()->QueueLocalCommand(msg);
}
else
{
*rval = JSVAL_FALSE;
}
return JS_TRUE;
}

View File

@ -45,6 +45,7 @@ JSFunc getGlobal;
JSFunc setCursor;
JSBool GetGameView( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
JSFunc GetGameObject;
JSFunc createServer;
JSFunc createClient;
@ -61,6 +62,8 @@ JSFunc getFPS;
JSFunc getCursorPosition;
JSFunc v3dist;
JSFunc issueCommand;
// Returns a string that says when ScriptGlue.cpp was last recompiled
JSFunc buildTime;

View File

@ -8,6 +8,8 @@
#include <jsatom.h>
#include <set>
#ifndef SCRIPTABLE_COMPLEX_INCLUDED
#define SCRIPTABLE_COMPLEX_INCLUDED
@ -958,7 +960,7 @@ template<typename T, bool ReadOnly> JSPropertySpec CJSComplex<T, ReadOnly>::JSI_
};
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSComplex<T, ReadOnly>::m_Methods;
template<typename T, bool ReadOnly> typename CJSComplex<typename T, ReadOnly>::PropertyTable CJSComplex<T, ReadOnly>::m_IntrinsicProperties;
template<typename T, bool ReadOnly> typename CJSComplex<T, ReadOnly>::PropertyTable CJSComplex<T, ReadOnly>::m_IntrinsicProperties;
template<typename T, bool ReadOnly> bool CJSComplex<T, ReadOnly>::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
{

View File

@ -143,7 +143,7 @@ public:
}
void Uproot()
{
if( JSVAL_IS_GCTHING( m_Data ) )
if( JSVAL_IS_GCTHING( m_Data ))
JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
}
jsval Get( JSContext* cx, IJSObject* object )
@ -439,7 +439,7 @@ template<typename T, bool ReadOnly> JSPropertySpec CJSObject<T, ReadOnly>::JSI_p
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSObject<T, ReadOnly>::m_Methods;
template<typename T, bool ReadOnly> typename CJSObject<typename T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_NativeProperties;
template<typename T, bool ReadOnly> typename CJSObject<T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_NativeProperties;
#endif

View File

@ -245,7 +245,7 @@ bool CBaseEntity::loadXML( CStr filename )
CStrW EventName = L"on" + (CStrW)Child.getAttributes().getNamedItem( at_on );
CStrW Code (Child.getText());
CStrW ExternalFunction = (CStrW)Child.getAttributes().getNamedItem( at_function );
utf16string ExternalFunction = Child.getAttributes().getNamedItem( at_function );
// Does a property with this name already exist?
@ -253,10 +253,10 @@ bool CBaseEntity::loadXML( CStr filename )
{
if( CStrW( EventNames[eventID] ) == EventName )
{
if( ExternalFunction != CStrW() )
if( ExternalFunction != utf16string() )
{
jsval fnval;
JSBool ret = JS_GetUCProperty( g_ScriptingHost.GetContext(), g_ScriptingHost.GetGlobalObject(), ExternalFunction.c_str(), ExternalFunction.Length(), &fnval );
JSBool ret = JS_GetUCProperty( g_ScriptingHost.GetContext(), g_ScriptingHost.GetGlobalObject(), ExternalFunction.c_str(), ExternalFunction.size(), &fnval );
assert( ret );
JSFunction* fn = JS_ValueToFunction( g_ScriptingHost.GetContext(), fnval );
if( !fn )
@ -346,7 +346,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement&
void CBaseEntity::ScriptingInit()
{
AddMethod<jsval, &CBaseEntity::ToString>( "toString", 0 );
AddClassProperty( L"traits.id.classes", (GetFn)getClassSet, (SetFn)setClassSet );
AddClassProperty( L"traits.id.classes", (GetFn)&CBaseEntity::getClassSet, (SetFn)&CBaseEntity::setClassSet );
CJSComplex<CBaseEntity>::ScriptingInit( "EntityTemplate" );
}

View File

@ -3,6 +3,8 @@
#include "Collision.h"
#include "EntityManager.h"
#include <float.h>
CBoundingObject* getContainingObject( const CVector2D& point )
{
std::vector<HEntity>* entities = g_EntityManager.getExtant();

View File

@ -648,7 +648,7 @@ void CEntity::ScriptingInit()
AddMethod<jsval, &CEntity::GetSpawnPoint>( "getSpawnPoint", 1 );
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
AddClassProperty( L"traits.id.classes", (GetFn)getClassSet, (SetFn)setClassSet );
AddClassProperty( L"traits.id.classes", (GetFn)&CEntity::getClassSet, (SetFn)&CEntity::setClassSet );
CJSComplex<CEntity>::ScriptingInit( "Entity", Construct, 2 );
}

View File

@ -106,7 +106,7 @@ public:
int m_lastState;
// Position in the current state's cycle
static const size_t NOT_IN_CYCLE = -1;
static const size_t NOT_IN_CYCLE = (size_t)-1;
size_t m_fsm_cyclepos; // -cycle_length....cycle_length
CSkeletonAnim* m_fsm_animation; // the animation we're about to play this cycle,
size_t m_fsm_anipos; // the time at which we should start playing it.
@ -197,6 +197,7 @@ public:
// Script-bound functions
jsval ToString( JSContext* cx, uintN argc, jsval* argv );
bool Order( JSContext* cx, uintN argc, jsval* argv, bool Queued );
inline bool OrderSingle( JSContext* cx, uintN argc, jsval* argv )
{

View File

@ -129,3 +129,57 @@ HEntity::operator CStr() const
sprintf(buf, "Entity#%04x", m_handle);
return CStr(buf);
}
uint CEntityList::GetSerializedLength() const
{
return 2*size();
}
u8 *CEntityList::Serialize(u8 *buffer) const
{
for (int i=0;i<size();i++)
Serialize_int_2(buffer, at(i).m_handle);
Serialize_int_2(buffer, back().m_handle | HANDLE_SENTINEL_BIT);
return buffer;
}
const u8 *CEntityList::Deserialize(const u8 *buffer, const u8 *end)
{
u16 n=0, handle;
while (!(n & HANDLE_SENTINEL_BIT))
{
Deserialize_int_2(buffer, n);
handle = n & ~HANDLE_SENTINEL_BIT;
// We have to validate the data, or the HEntity constructor will assert
// on us.
// FIXME 4096 shouldn't be hard-coded
// FIXME We should also check that the entity actually exists
if (handle < 4096 && handle != INVALID_HANDLE)
push_back(HEntity(handle));
}
return buffer;
}
CEntityList::operator CStr() const
{
if (size() == 0)
{
return CStr("Entities {}");
}
else if (size() == 1)
{
return front().operator CStr();
}
else
{
CStr buf="{ ";
buf += front().operator CStr();
for (const_iterator it=begin();it != end();++it)
{
buf += ", ";
buf += it->operator CStr();
}
buf += " }";
return buf;
}
}

View File

@ -24,9 +24,16 @@
#include "Network/Serialization.h"
#define INVALID_HANDLE 65535
// The maximum numerical value of an entity handle sent over the network
#define MAX_HANDLE 0x7fff
// If (handle & PS_ENTITY_SENTINEL_BIT) is non-zero, this is a terminating
// entity id. Reset the sentinel bit to get the original handle.
#define HANDLE_SENTINEL_BIT 0x8000
class CEntity;
class CEntityManager;
class CEntityList;
class CStr8;
class CHandle
@ -40,6 +47,7 @@ public:
class HEntity
{
friend class CEntityManager;
friend class CEntityList;
u16 m_handle;
private:
void addRef();
@ -64,4 +72,35 @@ public:
operator CStr8() const;
};
/*
CEntityList
DESCRIPTION: Represents a group of entities that is the target/subject of
a network command. Use for easy serialization of one or more entity IDs.
SERIALIZED FORMAT: The entities are stored as a sequence of 16-bit ints, the
termination of the list marked by an integer with HANDLE_SENTINEL_BIT
set. The length is thus 2*(number of entities)
*/
struct CEntityList: public std::vector<HEntity>
{
// Create an empty list
inline CEntityList()
{}
// Create a list from an existing entity vector
inline CEntityList(const std::vector<HEntity> &vect):
std::vector<HEntity>(vect)
{}
// Create a list containing one entity
inline CEntityList(HEntity oneEntity)
{
push_back(oneEntity);
}
uint GetSerializedLength() const;
u8 *Serialize(u8 *buffer) const;
const u8 *Deserialize(const u8 *buffer, const u8 *end);
operator CStr8() const;
};
#endif

View File

@ -54,7 +54,7 @@ HEntity CEntityManager::create( CBaseEntity* base, CVector3D position, float ori
{
assert( base );
if( !base )
return( HEntity() );
return HEntity();
while( m_entities[m_nextalloc].m_refcount )
{

View File

@ -192,10 +192,12 @@ JSBool CProjectile::Construct( JSContext* cx, JSObject* obj, unsigned int argc,
if( argc >= 7 )
Miss = argv[6]; // Script to run on impact with the floor.
CProjectile* p = g_ProjectileManager.AddProjectile( Model, Here, There, Speed / 1000.0f, Originator, Impact, Miss );
{
CProjectile* p = g_ProjectileManager.AddProjectile( Model, Here, There, Speed / 1000.0f, Originator, Impact, Miss );
*rval = ToJSVal<CProjectile>( *p );
return( JS_TRUE );
*rval = ToJSVal<CProjectile>( *p );
return( JS_TRUE );
}
fail:
*rval = JSVAL_NULL;

View File

@ -10,7 +10,7 @@
#include "Vector3D.h"
#include "Vector2D.h"
#include "Singleton.h"
#include "Scripting/ScriptableObject.h"
#include "scripting/ScriptableObject.h"
#include "scripting/DOMEvent.h"
#include "ScriptObject.h"

View File

@ -9,6 +9,8 @@
#define SCHEDULER_INCLUDED
#include <queue>
#include <list>
#include "EntityMessage.h"
#include "EntityHandles.h"
#include "Singleton.h"
@ -73,7 +75,7 @@ struct CScheduler : public Singleton<CScheduler>
class CJSProgressTimer : public CJSObject<CJSProgressTimer>
{
friend CScheduler;
friend struct CScheduler;
double m_Max, m_Current, m_Increment;
JSFunction* m_Callback;
JSObject* m_OperateOn;

View File

@ -94,7 +94,7 @@ bool CScriptObject::Run( JSObject* Context, jsval* rval, uintN argc, jsval* argv
bool CScriptObject::Run( JSObject* Context, uintN argc, jsval* argv )
{
jsval Temp;
if( !Run( Context, &Temp ) )
if( !Run( Context, &Temp, argc, argv ) )
return( false );
return( g_ScriptingHost.ValueToBool( Temp ) );
}

View File

@ -1,5 +1,7 @@
#include "precompiled.h"
#include <vector>
#include <timer.h>
#include "Profile.h"
@ -19,6 +21,8 @@
#include "gui/CGUI.h"
using namespace std;
extern CConsole *g_Console;
CSimulation::CSimulation(CGame *pGame):
@ -119,21 +123,135 @@ void CSimulation::Simulate()
PROFILE_END( "turn manager update" );
}
// Location randomizer, for group orders...
// Having the group turn up at the destination with /some/ sort of cohesion is
// good but tasking them all to the exact same point will leave them brawling
// for it at the other end (it shouldn't, but the PASAP pathfinder is too
// simplistic)
// Task them all to a point within a radius of the target, radius depends upon
// the number of units in the group.
void RandomizeLocations(CEntityOrder order, const vector <HEntity> &entities, bool clearQueue)
{
vector<HEntity>::const_iterator it;
float radius = 2.0f * sqrt( (float)entities.size() - 1 );
for (it = entities.begin(); it < entities.end(); it++)
{
float _x, _y;
CEntityOrder randomizedOrder = order;
do
{
_x = (float)( rand() % 20000 ) / 10000.0f - 1.0f;
_y = (float)( rand() % 20000 ) / 10000.0f - 1.0f;
}
while( ( _x * _x ) + ( _y * _y ) > 1.0f );
randomizedOrder.m_data[0].location.x += _x * radius;
randomizedOrder.m_data[0].location.y += _y * radius;
// Clamp it to within the map, just in case.
float mapsize = (float)g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide() * CELL_SIZE;
if( randomizedOrder.m_data[0].location.x < 0.0f )
randomizedOrder.m_data[0].location.x = 0.0f;
if( randomizedOrder.m_data[0].location.x >= mapsize )
randomizedOrder.m_data[0].location.x = mapsize;
if( randomizedOrder.m_data[0].location.y < 0.0f )
randomizedOrder.m_data[0].location.y = 0.0f;
if( randomizedOrder.m_data[0].location.y >= mapsize )
randomizedOrder.m_data[0].location.y = mapsize;
if( clearQueue )
(*it)->clearOrders();
(*it)->pushOrder( randomizedOrder );
}
}
void QueueOrder(CEntityOrder order, const vector <HEntity> &entities, bool clearQueue)
{
vector<HEntity>::const_iterator it;
for (it = entities.begin(); it < entities.end(); it++)
{
if( clearQueue )
(*it)->clearOrders();
(*it)->pushOrder( order );
}
}
uint CSimulation::TranslateMessage(CNetMessage *pMsg, uint clientMask, void *userdata)
{
CSimulation *pSimulation=(CSimulation *)userdata;
CEntityOrder order;
bool clearQueue = true;
#define ENTITY_POSITION(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].location.x=(float)msg->m_TargetX; \
order.m_data[0].location.y=(float)msg->m_TargetY; \
RandomizeLocations(order, msg->m_Entities, clearQueue); \
} while(0)
#define ENTITY_ENTITY(_msg, _order) do\
{ \
_msg *msg=(_msg *)pMsg; \
order.m_type=CEntityOrder::_order; \
order.m_data[0].entity=msg->m_Target; \
QueueOrder(order, msg->m_Entities, clearQueue); \
} while(0)
CEntityOrder entOrder;
switch (pMsg->GetType())
{
case NMT_GotoCommand:
CGotoCommand *msg=(CGotoCommand *)pMsg;
entOrder.m_type=CEntityOrder::ORDER_GOTO;
entOrder.m_data[0].location.x=(float)msg->m_TargetX;
entOrder.m_data[0].location.y=(float)msg->m_TargetY;
CEntity *ent=msg->m_Entity;
ent->pushOrder( entOrder );
break;
case NMT_AddWaypoint:
{
CAddWaypoint *msg=(CAddWaypoint *)pMsg;
order.m_type=CEntityOrder::ORDER_LAST;
order.m_data[0].location.x=(float)msg->m_TargetX;
order.m_data[0].location.y=(float)msg->m_TargetY;
vector<HEntity>::iterator it = msg->m_Entities.begin();
for (;it != msg->m_Entities.end(); ++it)
{
deque<CEntityOrder>::const_iterator ord_it;
ord_it=(*it)->m_orderQueue.end() - 1;
for (;ord_it >= (*it)->m_orderQueue.begin();--ord_it)
{
if (ord_it->m_type == CEntityOrder::ORDER_PATH_END_MARKER)
{
order.m_type = CEntityOrder::ORDER_GOTO;
(*it)->pushOrder(order);
break;
}
if (ord_it->m_type == CEntityOrder::ORDER_PATROL)
{
order.m_type = ord_it->m_type;
(*it)->pushOrder(order);
break;
}
}
if (order.m_type == CEntityOrder::ORDER_LAST)
{
LOG(ERROR, "simulation", "Got an AddWaypoint message for an entity that isn't moving.");
}
}
break;
}
case NMT_Goto:
ENTITY_POSITION(CGoto, ORDER_GOTO);
break;
case NMT_Patrol:
ENTITY_POSITION(CPatrol, ORDER_PATROL);
break;
case NMT_AttackMelee:
ENTITY_ENTITY(CAttackMelee, ORDER_ATTACK_MELEE);
break;
case NMT_Gather:
ENTITY_ENTITY(CGather, ORDER_GATHER);
break;
}
return clientMask;