mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-02-27 08:34:02 +00:00
Implement element tags
A map element ("tile") can now be tagged with an int. In the editor: Ctrl+Numpad to quickly set tag 0-9 Ctrl+T to input tag number for selection This tag can be used by scripts for more advanced tile manipulation compared to the old node_setElementsInLayerActive(). This function now takes a 4th parameter, the tag. If 0 or omitted, the behavior is unchanged. Otherwise, only affect tiles with that tag. Add Lua func refreshElementsWithTagCallback(tag, callback): Call callback(templateIdx:int, texture:str, active:bool, layer:int, tag:int), and the tile is set to active when the return value is true. refreshElementsOnLayerCallback(tag, callback) is also changed to use the same callback. Also fix UB (dangling pointer)in Element::render() that never even caused a single problem.
This commit is contained in:
parent
c73aa23906
commit
33e8c0643d
5 changed files with 156 additions and 31 deletions
|
@ -42,6 +42,7 @@ Element::Element() : Quad()
|
|||
elementFlag = EF_NONE;
|
||||
elementActive = true;
|
||||
bgLayer = 0;
|
||||
tag = 0;
|
||||
templateIdx = -1;
|
||||
eff = NULL;
|
||||
}
|
||||
|
@ -280,37 +281,66 @@ void Element::setElementEffectByIndex(int eidx)
|
|||
}
|
||||
}
|
||||
|
||||
// shamelessly ripped from paint.net default palette
|
||||
static const Vector s_tagColors[] =
|
||||
{
|
||||
/* 0 */ Vector(0.5f, 0.5f, 0.5f),
|
||||
/* 1 */ Vector(1,0,0),
|
||||
/* 2 */ Vector(1, 0.415686f, 0),
|
||||
/* 3 */ Vector(1,0.847059f, 0),
|
||||
/* 4 */ Vector(0.298039f,1,0),
|
||||
/* 5 */ Vector(0,1,1),
|
||||
/* 6 */ Vector(0,0.580392,1),
|
||||
/* 7 */ Vector(0,0.149020f,1),
|
||||
/* 8 */ Vector(0.282353f,0,1),
|
||||
/* 9 */ Vector(0.698039f,0,1),
|
||||
|
||||
/* 10 */ Vector(1,0,1), // anything outside of the pretty range
|
||||
};
|
||||
|
||||
static inline const Vector& getTagColor(int tag)
|
||||
{
|
||||
const unsigned idx = std::min<unsigned>(unsigned(tag), Countof(s_tagColors)-1);
|
||||
return s_tagColors[idx];
|
||||
|
||||
}
|
||||
|
||||
void Element::render(const RenderState& rs) const
|
||||
{
|
||||
if (!elementActive) return;
|
||||
const RenderState *rsp = &rs;
|
||||
|
||||
if (dsq->game->isSceneEditorActive() && this->bgLayer == dsq->game->sceneEditor.bgLayer
|
||||
&& dsq->game->sceneEditor.editType == ET_ELEMENTS)
|
||||
{
|
||||
RenderState rs2(rs);
|
||||
rsp = &rs2;
|
||||
rs2.forceRenderBorder = true;
|
||||
rs2.forceRenderCenter = true;
|
||||
rs2.renderBorderColor = Vector(0.5f, 0.5f, 0.5f);
|
||||
|
||||
Vector tagColor = getTagColor(tag);
|
||||
bool hl = false;
|
||||
if (!dsq->game->sceneEditor.selectedElements.empty())
|
||||
{
|
||||
for (size_t i = 0; i < dsq->game->sceneEditor.selectedElements.size(); i++)
|
||||
{
|
||||
if (this == dsq->game->sceneEditor.selectedElements[i])
|
||||
rs2.renderBorderColor = Vector(1,1,1);
|
||||
{
|
||||
hl = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dsq->game->sceneEditor.editingElement == this)
|
||||
rs2.renderBorderColor = Vector(1,1,1);
|
||||
hl = dsq->game->sceneEditor.editingElement == this;
|
||||
}
|
||||
|
||||
}
|
||||
if(hl)
|
||||
tagColor += Vector(0.5f, 0.5f, 0.5f);
|
||||
|
||||
Quad::render(*rsp);
|
||||
RenderState rs2(rs);
|
||||
rs2.forceRenderBorder = true;
|
||||
rs2.forceRenderCenter = true;
|
||||
rs2.renderBorderColor = tagColor;
|
||||
Quad::render(rs2);
|
||||
}
|
||||
else // render normally
|
||||
Quad::render(rs);
|
||||
}
|
||||
|
||||
void Element::fillGrid()
|
||||
|
@ -336,3 +366,7 @@ void Element::fillGrid()
|
|||
}
|
||||
}
|
||||
|
||||
void Element::setTag(int tag)
|
||||
{
|
||||
this->tag = tag;
|
||||
}
|
||||
|
|
|
@ -65,15 +65,17 @@ public:
|
|||
void update(float dt);
|
||||
size_t templateIdx;
|
||||
int bgLayer;
|
||||
int tag;
|
||||
Element *bgLayerNext;
|
||||
void render(const RenderState& rs) const OVERRIDE;
|
||||
ElementFlag elementFlag;
|
||||
void fillGrid();
|
||||
bool isElementActive() { return elementActive; }
|
||||
bool isElementActive() const { return elementActive; }
|
||||
int getElementEffectIndex();
|
||||
void setElementEffectByIndex(int e);
|
||||
void setElementActive(bool v) { elementActive = v; }
|
||||
void doInteraction(Entity *ent, float mult, float touchWidth);
|
||||
void setTag(int tag);
|
||||
protected:
|
||||
void ensureEffectData();
|
||||
void freeEffectData();
|
||||
|
|
|
@ -1889,7 +1889,7 @@ bool Game::loadSceneXML(std::string scene)
|
|||
}
|
||||
if (simpleElements->Attribute("repeatScale"))
|
||||
{
|
||||
SimpleIStringStream is2(simpleElements->Attribute("repeatScale"));
|
||||
SimpleIStringStream is2(simpleElements->Attribute("repeatScale"), SimpleIStringStream::REUSE);
|
||||
for(size_t i = 0; i < loadedElements.size(); ++i)
|
||||
{
|
||||
Element *e = loadedElements[i];
|
||||
|
@ -1904,6 +1904,18 @@ bool Game::loadSceneXML(std::string scene)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (simpleElements->Attribute("tag"))
|
||||
{
|
||||
SimpleIStringStream is2(simpleElements->Attribute("tag"), SimpleIStringStream::REUSE);
|
||||
for(size_t i = 0; i < loadedElements.size(); ++i)
|
||||
{
|
||||
Element *e = loadedElements[i];
|
||||
int tag = 0;
|
||||
if(!(is2 >> tag))
|
||||
break;
|
||||
e->setTag(tag);
|
||||
}
|
||||
}
|
||||
simpleElements = simpleElements->NextSiblingElement("SE");
|
||||
}
|
||||
|
||||
|
@ -2130,6 +2142,8 @@ bool Game::saveScene(std::string scene)
|
|||
|
||||
std::ostringstream simpleElements[LR_MAX];
|
||||
std::ostringstream simpleElements_repeatScale[LR_MAX];
|
||||
std::ostringstream simpleElements_tag[LR_MAX];
|
||||
unsigned tagBitsUsed[LR_MAX] = { 0 };
|
||||
|
||||
for (size_t i = 0; i < dsq->getNumElements(); i++)
|
||||
{
|
||||
|
@ -2153,6 +2167,9 @@ bool Game::saveScene(std::string scene)
|
|||
SE_rs << e->repeatToFillScale.x << " "
|
||||
<< e->repeatToFillScale.y << " ";
|
||||
}
|
||||
|
||||
simpleElements_tag[e->bgLayer] << e->tag << " ";
|
||||
tagBitsUsed[e->bgLayer] |= e->tag;
|
||||
}
|
||||
|
||||
if (dsq->game->entitySaveData.size() > 0)
|
||||
|
@ -2187,9 +2204,16 @@ bool Game::saveScene(std::string scene)
|
|||
XMLElement *simpleElementsXML = saveFile.NewElement("SE");
|
||||
simpleElementsXML->SetAttribute("k", s.c_str());
|
||||
simpleElementsXML->SetAttribute("l", i);
|
||||
std::string repeatScaleStr = simpleElements_repeatScale[i].str();
|
||||
if(!repeatScaleStr.empty())
|
||||
simpleElementsXML->SetAttribute("repeatScale", repeatScaleStr.c_str());
|
||||
std::string str = simpleElements_repeatScale[i].str();
|
||||
if(!str.empty())
|
||||
simpleElementsXML->SetAttribute("repeatScale", str.c_str());
|
||||
if(tagBitsUsed[i]) // skip writing tags on layers where it's all zero (mainly to avoid putting a long string of 0's for border elements)
|
||||
{
|
||||
str = simpleElements_tag[i].str();
|
||||
if(!str.empty())
|
||||
simpleElementsXML->SetAttribute("tag", str.c_str());
|
||||
}
|
||||
|
||||
saveFile.InsertEndChild(simpleElementsXML);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -787,11 +787,23 @@ void SceneEditor::reversePath()
|
|||
|
||||
void SceneEditor::setGridPattern(int gi)
|
||||
{
|
||||
if(core->getCtrlState())
|
||||
{
|
||||
const int tag = gi + 1; // key 0 is tag 0... otherwise it's all off by one
|
||||
if (selectedElements.size())
|
||||
for (size_t i = 0; i < selectedElements.size(); ++i)
|
||||
selectedElements[i]->setTag(tag);
|
||||
else if (editingElement)
|
||||
editingElement->setTag(tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selectedElements.size())
|
||||
for (size_t i = 0; i < selectedElements.size(); ++i)
|
||||
selectedElements[i]->setElementEffectByIndex(gi);
|
||||
else if (editingElement)
|
||||
editingElement->setElementEffectByIndex(gi);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneEditor::setGridPattern0()
|
||||
|
@ -1755,6 +1767,23 @@ void SceneEditor::flipElementHorz()
|
|||
if (editType != ET_ELEMENTS)
|
||||
return;
|
||||
|
||||
if(core->getCtrlState())
|
||||
{
|
||||
if(!selectedElements.empty() || editingElement)
|
||||
{
|
||||
std::string inp = dsq->getUserInputString("Enter tag (int):");
|
||||
if(inp.empty())
|
||||
return;
|
||||
int tag = atoi(inp.c_str());
|
||||
if(!selectedElements.empty())
|
||||
for(size_t i = 0; i < selectedElements.size(); ++i)
|
||||
selectedElements[i]->setTag(tag);
|
||||
else
|
||||
editingElement->setTag(tag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (editingElement)
|
||||
editingElement->flipHorizontal();
|
||||
else
|
||||
|
@ -2607,10 +2636,11 @@ void SceneEditor::updateText()
|
|||
if (e)
|
||||
{
|
||||
os << " id: " << e->templateIdx;
|
||||
os << " efx: " << (e->getElementEffectIndex() + 1); // +1 so that it resembles the layout on numpad
|
||||
os << " tag: " << e->tag;
|
||||
ElementTemplate *et = game->getElementTemplateByIdx(e->templateIdx);
|
||||
if (et)
|
||||
os << " gfx: " << et->gfx;
|
||||
os << " efx: " << (e->getElementEffectIndex() + 1); // +1 so that it resembles the layout on numpad
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -7672,9 +7672,10 @@ luaFunc(node_setElementsInLayerActive)
|
|||
{
|
||||
int l = lua_tointeger(L, 2);
|
||||
bool v = getBool(L, 3);
|
||||
int tag = lua_tointeger(L, 3);
|
||||
for (Element *e = dsq->getFirstElementOnLayer(l); e; e = e->bgLayerNext)
|
||||
{
|
||||
if (e && p->isCoordinateInside(e->position))
|
||||
if (e && (!tag || e->tag == tag) && p->isCoordinateInside(e->position))
|
||||
{
|
||||
e->setElementActive(v);
|
||||
}
|
||||
|
@ -7683,22 +7684,55 @@ luaFunc(node_setElementsInLayerActive)
|
|||
luaReturnNil();
|
||||
}
|
||||
|
||||
luaFunc(refreshElementsOnLayerCallback)
|
||||
static int pushElementData(lua_State *L, const Element *e)
|
||||
{
|
||||
int layer = lua_tointeger(L, 1);
|
||||
for (Element *e = dsq->getFirstElementOnLayer(layer); e; e = e->bgLayerNext)
|
||||
{
|
||||
bool on = e->isElementActive();
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
lua_pushinteger(L, e->templateIdx);
|
||||
lua_pushstring(L, e->texture->name.c_str());
|
||||
lua_pushboolean(L, e->isElementActive());
|
||||
lua_call(L, 3, 1);
|
||||
lua_pushinteger(L, e->bgLayer);
|
||||
lua_pushinteger(L, e->tag);
|
||||
return 5;
|
||||
}
|
||||
|
||||
// (layer, func)
|
||||
luaFunc(refreshElementsOnLayerCallback)
|
||||
{
|
||||
const int layer = lua_tointeger(L, 1);
|
||||
size_t done = 0;
|
||||
for (Element *e = dsq->getFirstElementOnLayer(layer); e; e = e->bgLayerNext)
|
||||
{
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
int args = pushElementData(L, e);
|
||||
lua_call(L, args, 1);
|
||||
bool newon = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
e->setElementActive(newon);
|
||||
++done;
|
||||
}
|
||||
luaReturnNil();
|
||||
luaReturnInt(done);
|
||||
}
|
||||
|
||||
// (tag, func)
|
||||
luaFunc(refreshElementsWithTagCallback)
|
||||
{
|
||||
const int tag = lua_tointeger(L, 1);
|
||||
const size_t N = dsq->getNumElements();
|
||||
size_t done = 0;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
Element *e = dsq->getElement(i);
|
||||
if(e->tag == tag)
|
||||
{
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
int args = pushElementData(L, e);
|
||||
lua_call(L, args, 1);
|
||||
bool newon = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
e->setElementActive(newon);
|
||||
++done;
|
||||
}
|
||||
}
|
||||
luaReturnInt(done);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10747,6 +10781,7 @@ static const struct {
|
|||
|
||||
luaRegister(node_setElementsInLayerActive),
|
||||
luaRegister(refreshElementsOnLayerCallback),
|
||||
luaRegister(refreshElementsWithTagCallback),
|
||||
|
||||
|
||||
luaRegister(entity_setHealth),
|
||||
|
|
Loading…
Add table
Reference in a new issue