mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-02-27 16:44:00 +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;
|
elementFlag = EF_NONE;
|
||||||
elementActive = true;
|
elementActive = true;
|
||||||
bgLayer = 0;
|
bgLayer = 0;
|
||||||
|
tag = 0;
|
||||||
templateIdx = -1;
|
templateIdx = -1;
|
||||||
eff = NULL;
|
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
|
void Element::render(const RenderState& rs) const
|
||||||
{
|
{
|
||||||
if (!elementActive) return;
|
if (!elementActive) return;
|
||||||
const RenderState *rsp = &rs;
|
|
||||||
|
|
||||||
if (dsq->game->isSceneEditorActive() && this->bgLayer == dsq->game->sceneEditor.bgLayer
|
if (dsq->game->isSceneEditorActive() && this->bgLayer == dsq->game->sceneEditor.bgLayer
|
||||||
&& dsq->game->sceneEditor.editType == ET_ELEMENTS)
|
&& dsq->game->sceneEditor.editType == ET_ELEMENTS)
|
||||||
{
|
{
|
||||||
RenderState rs2(rs);
|
Vector tagColor = getTagColor(tag);
|
||||||
rsp = &rs2;
|
bool hl = false;
|
||||||
rs2.forceRenderBorder = true;
|
|
||||||
rs2.forceRenderCenter = true;
|
|
||||||
rs2.renderBorderColor = Vector(0.5f, 0.5f, 0.5f);
|
|
||||||
|
|
||||||
if (!dsq->game->sceneEditor.selectedElements.empty())
|
if (!dsq->game->sceneEditor.selectedElements.empty())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < dsq->game->sceneEditor.selectedElements.size(); i++)
|
for (size_t i = 0; i < dsq->game->sceneEditor.selectedElements.size(); i++)
|
||||||
{
|
{
|
||||||
if (this == dsq->game->sceneEditor.selectedElements[i])
|
if (this == dsq->game->sceneEditor.selectedElements[i])
|
||||||
rs2.renderBorderColor = Vector(1,1,1);
|
{
|
||||||
|
hl = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (dsq->game->sceneEditor.editingElement == this)
|
hl = dsq->game->sceneEditor.editingElement == this;
|
||||||
rs2.renderBorderColor = Vector(1,1,1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
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()
|
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);
|
void update(float dt);
|
||||||
size_t templateIdx;
|
size_t templateIdx;
|
||||||
int bgLayer;
|
int bgLayer;
|
||||||
|
int tag;
|
||||||
Element *bgLayerNext;
|
Element *bgLayerNext;
|
||||||
void render(const RenderState& rs) const OVERRIDE;
|
void render(const RenderState& rs) const OVERRIDE;
|
||||||
ElementFlag elementFlag;
|
ElementFlag elementFlag;
|
||||||
void fillGrid();
|
void fillGrid();
|
||||||
bool isElementActive() { return elementActive; }
|
bool isElementActive() const { return elementActive; }
|
||||||
int getElementEffectIndex();
|
int getElementEffectIndex();
|
||||||
void setElementEffectByIndex(int e);
|
void setElementEffectByIndex(int e);
|
||||||
void setElementActive(bool v) { elementActive = v; }
|
void setElementActive(bool v) { elementActive = v; }
|
||||||
void doInteraction(Entity *ent, float mult, float touchWidth);
|
void doInteraction(Entity *ent, float mult, float touchWidth);
|
||||||
|
void setTag(int tag);
|
||||||
protected:
|
protected:
|
||||||
void ensureEffectData();
|
void ensureEffectData();
|
||||||
void freeEffectData();
|
void freeEffectData();
|
||||||
|
|
|
@ -1889,7 +1889,7 @@ bool Game::loadSceneXML(std::string scene)
|
||||||
}
|
}
|
||||||
if (simpleElements->Attribute("repeatScale"))
|
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)
|
for(size_t i = 0; i < loadedElements.size(); ++i)
|
||||||
{
|
{
|
||||||
Element *e = loadedElements[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");
|
simpleElements = simpleElements->NextSiblingElement("SE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2130,6 +2142,8 @@ bool Game::saveScene(std::string scene)
|
||||||
|
|
||||||
std::ostringstream simpleElements[LR_MAX];
|
std::ostringstream simpleElements[LR_MAX];
|
||||||
std::ostringstream simpleElements_repeatScale[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++)
|
for (size_t i = 0; i < dsq->getNumElements(); i++)
|
||||||
{
|
{
|
||||||
|
@ -2153,6 +2167,9 @@ bool Game::saveScene(std::string scene)
|
||||||
SE_rs << e->repeatToFillScale.x << " "
|
SE_rs << e->repeatToFillScale.x << " "
|
||||||
<< e->repeatToFillScale.y << " ";
|
<< e->repeatToFillScale.y << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simpleElements_tag[e->bgLayer] << e->tag << " ";
|
||||||
|
tagBitsUsed[e->bgLayer] |= e->tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsq->game->entitySaveData.size() > 0)
|
if (dsq->game->entitySaveData.size() > 0)
|
||||||
|
@ -2187,9 +2204,16 @@ bool Game::saveScene(std::string scene)
|
||||||
XMLElement *simpleElementsXML = saveFile.NewElement("SE");
|
XMLElement *simpleElementsXML = saveFile.NewElement("SE");
|
||||||
simpleElementsXML->SetAttribute("k", s.c_str());
|
simpleElementsXML->SetAttribute("k", s.c_str());
|
||||||
simpleElementsXML->SetAttribute("l", i);
|
simpleElementsXML->SetAttribute("l", i);
|
||||||
std::string repeatScaleStr = simpleElements_repeatScale[i].str();
|
std::string str = simpleElements_repeatScale[i].str();
|
||||||
if(!repeatScaleStr.empty())
|
if(!str.empty())
|
||||||
simpleElementsXML->SetAttribute("repeatScale", repeatScaleStr.c_str());
|
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);
|
saveFile.InsertEndChild(simpleElementsXML);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -787,11 +787,23 @@ void SceneEditor::reversePath()
|
||||||
|
|
||||||
void SceneEditor::setGridPattern(int gi)
|
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())
|
if (selectedElements.size())
|
||||||
for (size_t i = 0; i < selectedElements.size(); ++i)
|
for (size_t i = 0; i < selectedElements.size(); ++i)
|
||||||
selectedElements[i]->setElementEffectByIndex(gi);
|
selectedElements[i]->setElementEffectByIndex(gi);
|
||||||
else if (editingElement)
|
else if (editingElement)
|
||||||
editingElement->setElementEffectByIndex(gi);
|
editingElement->setElementEffectByIndex(gi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneEditor::setGridPattern0()
|
void SceneEditor::setGridPattern0()
|
||||||
|
@ -1755,6 +1767,23 @@ void SceneEditor::flipElementHorz()
|
||||||
if (editType != ET_ELEMENTS)
|
if (editType != ET_ELEMENTS)
|
||||||
return;
|
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)
|
if (editingElement)
|
||||||
editingElement->flipHorizontal();
|
editingElement->flipHorizontal();
|
||||||
else
|
else
|
||||||
|
@ -2607,10 +2636,11 @@ void SceneEditor::updateText()
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
os << " id: " << e->templateIdx;
|
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);
|
ElementTemplate *et = game->getElementTemplateByIdx(e->templateIdx);
|
||||||
if (et)
|
if (et)
|
||||||
os << " gfx: " << et->gfx;
|
os << " gfx: " << et->gfx;
|
||||||
os << " efx: " << (e->getElementEffectIndex() + 1); // +1 so that it resembles the layout on numpad
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -7672,9 +7672,10 @@ luaFunc(node_setElementsInLayerActive)
|
||||||
{
|
{
|
||||||
int l = lua_tointeger(L, 2);
|
int l = lua_tointeger(L, 2);
|
||||||
bool v = getBool(L, 3);
|
bool v = getBool(L, 3);
|
||||||
|
int tag = lua_tointeger(L, 3);
|
||||||
for (Element *e = dsq->getFirstElementOnLayer(l); e; e = e->bgLayerNext)
|
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);
|
e->setElementActive(v);
|
||||||
}
|
}
|
||||||
|
@ -7683,22 +7684,55 @@ luaFunc(node_setElementsInLayerActive)
|
||||||
luaReturnNil();
|
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_pushinteger(L, e->templateIdx);
|
||||||
lua_pushstring(L, e->texture->name.c_str());
|
lua_pushstring(L, e->texture->name.c_str());
|
||||||
lua_pushboolean(L, e->isElementActive());
|
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);
|
bool newon = lua_toboolean(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
e->setElementActive(newon);
|
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(node_setElementsInLayerActive),
|
||||||
luaRegister(refreshElementsOnLayerCallback),
|
luaRegister(refreshElementsOnLayerCallback),
|
||||||
|
luaRegister(refreshElementsWithTagCallback),
|
||||||
|
|
||||||
|
|
||||||
luaRegister(entity_setHealth),
|
luaRegister(entity_setHealth),
|
||||||
|
|
Loading…
Add table
Reference in a new issue