Jump to content

Attack notification


Recommended Posts

Ok thanks.

More questions.

Why does everything go through an interface. I mean, I like the idea, in OOPs there should be standard interfaces between classes. What I mean is what are they exactly in this case ? Are there different interfaces defined for different game entities. Is a entity the same as a component ?

When you say :

var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);

You are querying the Engine's Player interface for a particular player component ? The cmp stands for component I guess ?

Whats are the things like <AttackDetection/> or BattleDetection or FormationManager ? They are various parts of the system right ? So these are also components ?

Edited by madmax
Link to comment
Share on other sites

Yes, an "interface" in this context is a simulation component interface. Engine.QueryInterface() acquires a reference to a particular interface of a particular entity. (Though, to be honest I know little of how it actually does that, I just use it ;))

Some assorted background info: http://svn.wildfiregames.com/docs/writing-components.html

Elements like <AttackDetection/> in templates are references to components, yes.

Edited by zoot
Link to comment
Share on other sites

I believe it is DEBUG_PRINT() or DEBUG_WARN() or some such. For JS, it is warn() and error().

LOGWARNING() and LOGERROR() is what you are looking for.

EDIT: debug_warn() prints to stdout (or stderr (I'm not entirely sure without checking)) and breaks into the debugger, so it should be used if the code that triggers it indicates an engine bug. While LOGERROR() should be used for cases where modders can trigger it (eg: Wrong data files).

Edited by leper
some background info
Link to comment
Share on other sites

Unknown territory to me, so your guess is as good as mine, but I don't believe you will want to add it to any file in the simulation2 subdirectory, since the simulation is a different scripting context from the GUI. The attack notification sound is played from the GUI context (messages.js), so the ping probably should too.

Link to comment
Share on other sites

Once you've found the right place to add the function, you would likely want to add a reference to it here to expose it to the GUI JS context: https://github.com/0ad/0ad/blob/master/source/gui/scripting/ScriptFunctions.cpp#L612 (RegisterFunction() adds the function as a global Engine.* function in the given JS context.)

Edited by zoot
Link to comment
Share on other sites

Hmm, not sure what you mean. messages.js would call PingMiniMap(x, z) . This function will be implemented in C++. probably in CCmpMinimap.cpp. So to tie the Javascript call to the C++ function, I would need to probably add a line in ICmpMinimap as follows :


BEGIN_INTERFACE_WRAPPER(Minimap)
DEFINE_INTERFACE_METHOD_2("PingMiniMap", int, ICmpMinimap, PingMiniMap, int, int)
END_INTERFACE_WRAPPER(Minimap)

--------------

Once you've found the right place to add the function, you would likely want to add a reference to it here to expose it to the GUI JS context: https://github.com/0...ctions.cpp#L612 (RegisterFunction() adds the function as a global Engine.* function in the given JS context.)

Oh ok, I guess I can add it as a global function too so that the Minimap component does not have to be retrieved each time. I am not sure which approach is followed when. But I guess since there is just 1 minimap, therefore there is no minimap component as such. So it makes sense to register it as a global function.

Edited by madmax
Link to comment
Share on other sites

Your approach could work too, I'm not sure how that minimap component is actually organized. It just seems odd to me that the ping would need to go through the simulation, since it is specific to a single player and shouldn't need to be network synchronized or anything.

Edited by zoot
Link to comment
Share on other sites

The minimap code is actually in source/gui/. The minimap component is only used by the former to know which entities to render. Going from the gui code via the simulation just to update the minimap seems strange and is probably bogus. Either go from the simulation to the minimap (analogous to the way the entities are handled) or from the simulation to the gui code (which you already do) and then from the gui code to the minimap. The first way would probably lead to some problems that would need to be worked around, and the second does seem to be the better design choice.

Link to comment
Share on other sites

r from the simulation to the gui code (which you already do) and then from the gui code to the minimap

So how exactly is zoot already going from the simulation to the gui code. Is messages.js part of gui code ? Not exactly sure what executes in what context here.

------------

oh ok, I guess it is since it is in gui/session

So he is going from the simulation/components/AttackDetection.js which is simulation code to the gui code in message.js Thats what you meant ?

Edited by madmax
Link to comment
Share on other sites

ok so when execution reaches messages.js , into function handleNotifications() then what we want is to have this in there :


else if (notification.type == "attack")
{
if (notification.player == Engine.GetPlayerID())
Engine.GuiInterfaceCall("PlaySound", { "name":"attacked", "entity": notification.message.target });
Engine.PingMinimap({ "entity": notification.message.target });
}

That means PingMinimap() should be declared as a global function in GuiScriptingInit

And this function needs to get the position info from the passed entity and blink the correct position in the minimap. Or the position can be retrieved in JS itself and passed to PingMinimap().

Please tell me if I am hopelessly wrong here :P

Edited by madmax
Link to comment
Share on other sites

Exactly (or something very close to that, depending on what works out for you).

It's a detail, but you'd need to enclose both lines in the 'if' context:


else if (notification.type == "attack")
{
if (notification.player == Engine.GetPlayerID()) {
Engine.GuiInterfaceCall("PlaySound", { "name":"attacked", "entity": notification.message.target });
Engine.PingMinimap({ "entity": notification.message.target });
}
}

Edited by zoot
  • Like 1
Link to comment
Share on other sites

yes right.

ok, now for the rendering code in the minimap, Someone who has worked on it can please confirm my conjecture here :

So the units are rendered in this part of the code in CMiniMap::Draw()


PROFILE_START("minimap units");
// Don't enable GL_POINT_SMOOTH because it's far too slow
// (~70msec/frame on a GF4 rendering a thousand points)
glPointSize(3.f);
float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);
std::vector<MinimapUnitVertex> vertexArray;
vertexArray.reserve(ents.size());
for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
{
MinimapUnitVertex v;
ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
entity_pos_t posX, posZ;
if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
{
ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID());
if (vis != ICmpRangeManager::VIS_HIDDEN)
{
v.a = 255;
v.x = posX.ToFloat()*sx;
v.y = -posZ.ToFloat()*sy;
vertexArray.push_back(v);
}
}
}
if (!vertexArray.empty())
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
{
shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);
}
else
{
glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);
}
glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
PROFILE_END("minimap units");

I guess something similar needs to be done for rendering blinking dots in the minimap for the attack positions. So I pack all the required pinging locations into a vertexarray inside a large for loop and then send it for rendering via


shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);
....

glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());

in the shader render path ?

From what I understand in the code is that the for-loop fetches the minimap component for each entity/thing visible in the 0ad world and then uses the minimap component to fetch the rendering data (colors, position) to be used to display that entity in the minimap.

Edited by madmax
Link to comment
Share on other sites

I tried to print a large red blob on the minimap using this :


//-----------------------------------------

// Don't enable GL_POINT_SMOOTH because it's far too slow
// (~70msec/frame on a GF4 rendering a thousand points)
glPointSize(6.f);
float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
//CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);
std::vector<MinimapUnitVertex> vertexArray;
vertexArray.reserve(1);
MinimapUnitVertex v;
v.a = 255;
v.x = 10*sx;
v.y = 10*sy;
v.r = 255;
v.g = 100;
v.b = 100;
vertexArray.push_back(v);
std::cout << "Hallo\n";
debug_printf(L"Hello");

if (!vertexArray.empty())
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
{
shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);
}
else
{
glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);
}
glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}

//-----------------------------------------

It doesnt work. I am also having a hard time debugging as debug_warn() immediately breaks to the debugger. cout does not work but I would like to be able to print to the console every frame for now(for debugging only). Nor does debug_printf() . Do I need to run pyrogenesis_dbg.exe ?

If I run pyrogenesis_dbg.exe it says MSVCRT90D.dll is missing or something.

Link to comment
Share on other sites

OK, yeah I seem to be showing the dot on the minimap square outside the circle.

There were some handy commands to start pyrogenesis in windowed mode with a particular map, skipping the starting screen. There was even one for starting 2 AIs against each other.

Can anyone point me to that list of useful commands ?

---------------

Got one :

pyrogenesis -quickstart -autostart="Isthmus" -autostart-ai=1:qbot-wc -autostart-ai=2:qbot-wc

ok, to gain control over 1 player, I just leave it out in the command line.

pyrogenesis -quickstart -autostart="Isthmus" -autostart-ai=2:qbot-wc

What other options are there ?

Does -quickstart have sound suppressed ?

Also I dont see a directory for aegis-bot in the ai folder. Where is it located. How is the engine finding the code for it ?

Edited by madmax
Link to comment
Share on other sites

Does -quickstart have sound suppressed ?

Yes it does.

Also I dont see a directory for aegis-bot in the ai folder. Where is it located. How is the engine finding the code for it ?

It's called qbot-wc internally. I spose we should rename the folder to Aegis? Would that break anything? Probably the maps which use Aegis bot, but those can be fixed easily enough with a script.
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...