mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
Rework the target list, use a container instead of an hash set so the target list gets archived correctly
This fixes an issue when loading from a save. A variable referencing target list container would have random entities in it, which would cause errors and crashes when trying to do an action on the array of entities
This commit is contained in:
parent
590b3f5cbb
commit
3d454c90cb
6 changed files with 155 additions and 162 deletions
|
@ -2131,49 +2131,21 @@ void Entity::SetTeamEvent(Event *ev)
|
|||
|
||||
void Entity::TriggerEvent(Event *ev)
|
||||
{
|
||||
const char *name;
|
||||
Event *event;
|
||||
Entity *ent;
|
||||
ConSimple *tlist;
|
||||
int i;
|
||||
int num;
|
||||
SimpleEntity *ent;
|
||||
ScriptVariable arrayVar;
|
||||
int i;
|
||||
|
||||
name = ev->GetString(1);
|
||||
|
||||
// Check for object commands
|
||||
if (name && name[0] == '$') {
|
||||
str sName = str(name + 1);
|
||||
|
||||
tlist = world->GetTargetList(sName);
|
||||
num = tlist->NumObjects();
|
||||
for (i = 1; i <= num; i++) {
|
||||
ent = (Entity *)tlist->ObjectAt(i).Pointer();
|
||||
|
||||
assert(ent);
|
||||
|
||||
event = new Event(EV_Activate);
|
||||
arrayVar = ev->GetValue(1);
|
||||
arrayVar.CastConstArrayValue();
|
||||
|
||||
for (i = arrayVar.arraysize(); i > 0; i--) {
|
||||
const ScriptVariable *variable = arrayVar[i];
|
||||
ent = variable->simpleEntityValue();
|
||||
if (ent) {
|
||||
Event* event = new Event(EV_Activate);
|
||||
event->AddEntity(this);
|
||||
ent->ProcessEvent(event);
|
||||
}
|
||||
} else if (name[0] == '*') // Check for entnum commands
|
||||
{
|
||||
if (!IsNumeric(&name[1])) {
|
||||
gi.Printf("Expecting numeric value for * command, but found '%s'\n", &name[1]);
|
||||
} else {
|
||||
ent = G_GetEntity(atoi(&name[1]));
|
||||
if (ent) {
|
||||
event = new Event(EV_Activate);
|
||||
|
||||
event->AddEntity(this);
|
||||
ent->ProcessEvent(event);
|
||||
} else {
|
||||
gi.Printf("Entity not found for * command\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
gi.Printf("Invalid entity reference '%s'.\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1121,30 +1121,19 @@ qboolean Sentient::HasSecondaryWeapon(void)
|
|||
|
||||
void Sentient::EventGiveTargetname(Event *ev)
|
||||
{
|
||||
int i;
|
||||
ConSimple *tlist;
|
||||
str name;
|
||||
const char *ptr;
|
||||
qboolean found;
|
||||
int i;
|
||||
str name;
|
||||
qboolean found;
|
||||
ScriptVariable var;
|
||||
SimpleEntity *ent;
|
||||
|
||||
name = ev->GetString(1);
|
||||
var = ev->GetValue(1);
|
||||
var.CastConstArrayValue();
|
||||
|
||||
ptr = name.c_str();
|
||||
|
||||
// skip over the $
|
||||
ptr++;
|
||||
|
||||
found = qfalse;
|
||||
|
||||
str sName = ptr;
|
||||
tlist = world->GetTargetList(sName);
|
||||
for (i = 1; i <= tlist->NumObjects(); i++) {
|
||||
Entity *ent;
|
||||
|
||||
ent = (Entity *)tlist->ObjectAt(i).Pointer();
|
||||
assert(ent);
|
||||
|
||||
if (ent->isSubclassOf(Item)) {
|
||||
for (i = var.arraysize(); i > 0; i--) {
|
||||
const ScriptVariable *variable = var[i];
|
||||
ent = variable->simpleEntityValue();
|
||||
if (ent && ent->IsSubclassOfItem()) {
|
||||
Item *item;
|
||||
|
||||
item = (Item *)ent;
|
||||
|
|
|
@ -536,12 +536,18 @@ void SimpleEntity::GetUpVector(Event *ev)
|
|||
|
||||
SimpleEntity *SimpleEntity::Next(void)
|
||||
{
|
||||
SimpleEntity *ent = world->GetTarget(target, true);
|
||||
Listener* ent;
|
||||
|
||||
if (!target.length()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ent = world->GetTarget(target, true);
|
||||
|
||||
if (!ent || !ent->isSubclassOf(SimpleEntity)) {
|
||||
return NULL;
|
||||
} else {
|
||||
return ent;
|
||||
return static_cast<SimpleEntity*>(ent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -994,24 +994,23 @@ void World::SetNorthYaw(Event *ev)
|
|||
m_fNorth = anglemod(ev->GetFloat(1));
|
||||
}
|
||||
|
||||
SimpleEntity *World::GetTarget(str targetname, bool quiet)
|
||||
Listener *World::GetTarget(str targetname, bool quiet)
|
||||
{
|
||||
return GetTarget(Director.AddString(targetname), quiet);
|
||||
}
|
||||
TargetList* targetList = GetTargetList(targetname);
|
||||
|
||||
SimpleEntity *World::GetTarget(const_str targetname, bool quiet)
|
||||
{
|
||||
ConSimple *list = GetTargetList(targetname);
|
||||
if (!targetList) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (list->NumObjects() == 1) {
|
||||
return list->ObjectAt(1);
|
||||
} else if (list->NumObjects() > 1) {
|
||||
if (targetList->list.NumObjects() == 1) {
|
||||
return targetList->list.ObjectAt(1);
|
||||
} else if (targetList->list.NumObjects() > 1) {
|
||||
if (!quiet) {
|
||||
warning(
|
||||
"World::GetTarget",
|
||||
"There are %d entities with targetname '%s'. You are using a command that requires exactly one.",
|
||||
list->NumObjects(),
|
||||
Director.GetString(targetname).c_str()
|
||||
targetList->list.NumObjects(),
|
||||
targetname.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1019,79 +1018,83 @@ SimpleEntity *World::GetTarget(const_str targetname, bool quiet)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
SimpleEntity *World::GetScriptTarget(str targetname)
|
||||
Listener *World::GetScriptTarget(str targetname)
|
||||
{
|
||||
return GetScriptTarget(Director.AddString(targetname));
|
||||
}
|
||||
TargetList *targetList = GetTargetList(targetname);
|
||||
|
||||
SimpleEntity *World::GetScriptTarget(const_str targetname)
|
||||
{
|
||||
ConSimple *list = GetTargetList(targetname);
|
||||
|
||||
if (list->NumObjects() == 1) {
|
||||
return list->ObjectAt(1);
|
||||
} else if (list->NumObjects() > 1) {
|
||||
if (targetList->list.NumObjects() == 1) {
|
||||
return targetList->list.ObjectAt(1);
|
||||
} else if (targetList->list.NumObjects() > 1) {
|
||||
ScriptError(
|
||||
"There are %d entities with targetname '%s'. You are using a command that requires exactly one.",
|
||||
list->NumObjects(),
|
||||
Director.GetString(targetname).c_str()
|
||||
targetList->list.NumObjects(),
|
||||
targetname.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ConSimple *World::GetExistingTargetList(const str& targetname)
|
||||
TargetList*World::GetExistingTargetList(const str& targetname)
|
||||
{
|
||||
return GetExistingTargetList(Director.AddString(targetname));
|
||||
TargetList* targetList;
|
||||
int i;
|
||||
|
||||
if (!targetname.length()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = m_targetListContainer.NumObjects(); i > 0; i--) {
|
||||
targetList = m_targetListContainer.ObjectAt(i);
|
||||
if (targetname == targetList->targetname) {
|
||||
return targetList;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ConSimple *World::GetExistingTargetList(const_str targetname)
|
||||
TargetList *World::GetTargetList(str& targetname)
|
||||
{
|
||||
return m_targetList.findKeyValue(targetname);
|
||||
}
|
||||
TargetList* targetList;
|
||||
int i;
|
||||
|
||||
ConSimple *World::GetTargetList(str& targetname)
|
||||
{
|
||||
return GetTargetList(Director.AddString(targetname));
|
||||
}
|
||||
if (!targetname.length()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ConSimple *World::GetTargetList(const_str targetname)
|
||||
{
|
||||
return &m_targetList.addKeyValue(targetname);
|
||||
for (i = m_targetListContainer.NumObjects(); i > 0; i--) {
|
||||
targetList = m_targetListContainer.ObjectAt(i);
|
||||
if (targetname == targetList->targetname) {
|
||||
return targetList;
|
||||
}
|
||||
}
|
||||
|
||||
targetList = new TargetList(targetname);
|
||||
m_targetListContainer.AddObject(targetList);
|
||||
|
||||
return targetList;
|
||||
}
|
||||
|
||||
void World::AddTargetEntity(SimpleEntity *ent)
|
||||
{
|
||||
str targetname = ent->TargetName();
|
||||
TargetList *list = GetTargetList(ent->TargetName());
|
||||
|
||||
if (!targetname.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConSimple *list = GetTargetList(targetname);
|
||||
|
||||
list->AddObject(ent);
|
||||
list->AddEntity(ent);
|
||||
}
|
||||
|
||||
void World::AddTargetEntityAt(SimpleEntity *ent, int index)
|
||||
{
|
||||
str targetname = ent->TargetName();
|
||||
TargetList *list = GetTargetList(ent->TargetName());
|
||||
|
||||
if (!targetname.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConSimple *list = GetTargetList(targetname);
|
||||
|
||||
list->AddObjectAt(index, ent);
|
||||
list->AddEntityAt(ent, index);
|
||||
}
|
||||
|
||||
int World::GetTargetnameIndex(SimpleEntity *ent)
|
||||
{
|
||||
ConSimple *list = GetTargetList(ent->TargetName());
|
||||
TargetList *targetList = GetTargetList(ent->TargetName());
|
||||
|
||||
return list->IndexOfObject(ent);
|
||||
return targetList->GetEntityIndex(ent);
|
||||
}
|
||||
|
||||
void World::RemoveTargetEntity(SimpleEntity *ent)
|
||||
|
@ -1100,55 +1103,75 @@ void World::RemoveTargetEntity(SimpleEntity *ent)
|
|||
return;
|
||||
}
|
||||
|
||||
const str targetname = ent->TargetName();
|
||||
str targetname = ent->TargetName();
|
||||
|
||||
if (!targetname.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConSimple *list = GetExistingTargetList(targetname);
|
||||
|
||||
TargetList *list = GetExistingTargetList(targetname);
|
||||
if (list) {
|
||||
list->RemoveObject(ent);
|
||||
|
||||
if (list->NumObjects() <= 0) {
|
||||
m_targetList.remove(Director.AddString(targetname));
|
||||
}
|
||||
list->RemoveEntity(ent);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleEntity *World::GetNextEntity(str targetname, SimpleEntity *ent)
|
||||
{
|
||||
return GetNextEntity(Director.AddString(targetname), ent);
|
||||
}
|
||||
|
||||
SimpleEntity *World::GetNextEntity(const_str targetname, SimpleEntity *ent)
|
||||
{
|
||||
ConSimple *list = GetTargetList(targetname);
|
||||
int index;
|
||||
|
||||
if (ent) {
|
||||
index = list->IndexOfObject(ent) + 1;
|
||||
} else {
|
||||
index = 1;
|
||||
}
|
||||
|
||||
if (list->NumObjects() >= index) {
|
||||
return list->ObjectAt(index);
|
||||
} else {
|
||||
TargetList* targetList = GetExistingTargetList(targetname);
|
||||
if (!targetList) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return targetList->GetNextEntity(ent);
|
||||
}
|
||||
|
||||
void World::FreeTargetList()
|
||||
{
|
||||
m_targetList.clear();
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= m_targetListContainer.NumObjects(); i++) {
|
||||
delete m_targetListContainer.ObjectAt(i);
|
||||
}
|
||||
|
||||
m_targetListContainer.FreeObjectList();
|
||||
}
|
||||
|
||||
void World::Archive(Archiver& arc)
|
||||
{
|
||||
// FIXME: this is not the original way of archiving target list
|
||||
m_targetList.Archive(arc);
|
||||
int num;
|
||||
int num2;
|
||||
int i;
|
||||
TargetList *targetList;
|
||||
|
||||
if (arc.Loading()) {
|
||||
str targetname;
|
||||
|
||||
arc.ArchiveInteger(&num);
|
||||
for (i = 1; i <= num; i++) {
|
||||
arc.ArchiveString(&targetname);
|
||||
|
||||
targetList = new TargetList(targetname);
|
||||
m_targetListContainer.AddObject(targetList);
|
||||
|
||||
arc.ArchiveObjectPosition((LightClass*)&targetList->list);
|
||||
arc.ArchiveInteger(&num2);
|
||||
|
||||
targetList->list.Resize(num2);
|
||||
}
|
||||
} else {
|
||||
num = m_targetListContainer.NumObjects();
|
||||
arc.ArchiveInteger(&num);
|
||||
|
||||
for (i = 1; i <= num; i++) {
|
||||
targetList = m_targetListContainer.ObjectAt(i);
|
||||
|
||||
arc.ArchiveString(&targetList->targetname);
|
||||
arc.ArchiveObjectPosition((LightClass*)&targetList->list);
|
||||
|
||||
num2 = targetList->list.NumObjects();
|
||||
arc.ArchiveInteger(&num2);
|
||||
}
|
||||
}
|
||||
|
||||
Entity::Archive(arc);
|
||||
|
||||
|
@ -1236,7 +1259,15 @@ SimpleEntity *TargetList::GetNextEntity(SimpleEntity *ent)
|
|||
{
|
||||
int index;
|
||||
|
||||
for (index = list.IndexOfObject(ent); index <= list.NumObjects(); index++) {
|
||||
if (ent) {
|
||||
index = list.IndexOfObject(ent);
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
for (; index <= list.NumObjects(); index++) {
|
||||
Listener *objptr;
|
||||
|
||||
objptr = list.ObjectAt(index);
|
||||
|
|
|
@ -97,8 +97,8 @@ public:
|
|||
|
||||
class World : public Entity
|
||||
{
|
||||
con_set<const_str, ConSimple> m_targetList; // moh could have used con_set instead of TargetList
|
||||
qboolean world_dying;
|
||||
Container<TargetList*> m_targetListContainer;
|
||||
qboolean world_dying;
|
||||
|
||||
public:
|
||||
// farplane variables
|
||||
|
@ -144,17 +144,12 @@ public:
|
|||
void FreeTargetList();
|
||||
|
||||
SimpleEntity *GetNextEntity(str targetname, SimpleEntity *ent);
|
||||
SimpleEntity *GetNextEntity(const_str targetname, SimpleEntity *ent);
|
||||
SimpleEntity *GetScriptTarget(str targetname);
|
||||
SimpleEntity *GetScriptTarget(const_str targetname);
|
||||
SimpleEntity *GetTarget(str targetname, bool quiet);
|
||||
SimpleEntity *GetTarget(const_str targetname, bool quiet);
|
||||
Listener *GetScriptTarget(str targetname);
|
||||
Listener *GetTarget(str targetname, bool quiet);
|
||||
int GetTargetnameIndex(SimpleEntity *ent);
|
||||
|
||||
ConSimple *GetExistingTargetList(const str& targetname);
|
||||
ConSimple *GetExistingTargetList(const_str targetname);
|
||||
ConSimple *GetTargetList(str& targetname);
|
||||
ConSimple *GetTargetList(const_str targetname);
|
||||
TargetList *GetExistingTargetList(const str& targetname);
|
||||
TargetList *GetTargetList(str& targetname);
|
||||
|
||||
void SetFarClipOverride(Event *ev);
|
||||
void SetFarPlaneColorOverride(Event *ev);
|
||||
|
|
|
@ -1007,7 +1007,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label)
|
|||
Event ev;
|
||||
ScriptVariable *var = NULL;
|
||||
|
||||
ConSimple *targetList;
|
||||
TargetList *targetList;
|
||||
|
||||
if (Director.stackCount >= MAX_STACK_DEPTH) {
|
||||
state = STATE_EXECUTION;
|
||||
|
@ -1769,9 +1769,9 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label)
|
|||
|
||||
case OP_UN_TARGETNAME:
|
||||
// retrieve the target name
|
||||
targetList = world->GetExistingTargetList(m_VMStack.GetTop().constStringValue());
|
||||
targetList = world->GetExistingTargetList(m_VMStack.GetTop().stringValue());
|
||||
|
||||
if (!targetList || !targetList->NumObjects()) {
|
||||
if (!targetList || !targetList->list.NumObjects()) {
|
||||
str targetname = m_VMStack.GetTop().stringValue();
|
||||
// the target name was not found
|
||||
m_VMStack.GetTop().setListenerValue(NULL);
|
||||
|
@ -1780,12 +1780,12 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label)
|
|||
|| (*m_PrevCodePos >= OP_BOOL_UN_NOT && *m_PrevCodePos <= OP_UN_CAST_BOOLEAN)) {
|
||||
ScriptError("Targetname '%s' does not exist.", targetname.c_str());
|
||||
}
|
||||
} else if (targetList->NumObjects() == 1) {
|
||||
} else if (targetList->list.NumObjects() == 1) {
|
||||
// single listener
|
||||
m_VMStack.GetTop().setListenerValue(targetList->ObjectAt(1));
|
||||
} else if (targetList->NumObjects() > 1) {
|
||||
m_VMStack.GetTop().setListenerValue(targetList->list.ObjectAt(1));
|
||||
} else if (targetList->list.NumObjects() > 1) {
|
||||
// multiple listeners
|
||||
m_VMStack.GetTop().setContainerValue((Container<SafePtr<Listener>> *)targetList);
|
||||
m_VMStack.GetTop().setContainerValue((Container<SafePtr<Listener>> *)&targetList->list);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue