Backwards NPC pointer referencing?
#1
Posted 03 January 2011 - 01:05 AM
My guess-- and it is only a guess-- is that there's issues with such an operation if NPC pointers are all re-calculated after every Waitframe(). So, maybe it would help if I explain what I'm trying to do: I'm getting an enemy to manually spawn an EWeapon from the code itself when it attacks... the EWeapon in question being ID# "31", one of the Dummy Weapons, which I intend to specify the behavior for in the Main Global Script. As soon as the EWeapon is spawned, it's supposed to write the Pointer of the enemy that spawned it as its Misc[0] value, because this weapon's movements can change on the fly as the attacker's X,Y position changes (as the enemy walks around and stuff). But I can't figure out what I'm supposed to store, because you're not allowed to typecast an Integer into an NPC, obviously-- not without some in-between steps or whatever.
If someone out there is sufficiently knowledgeable to help me overcome this instrument of melancholy amidst my endeavors of creative pursuit, they will be greatly loved and GREATLY credited. Thanks, love you.
--Schwa
#2
Posted 05 January 2011 - 06:34 PM
However, there are ways to work around it, and you're sort of onto it. You're trying to save the enemy via a pointer. As of the moment, there's no variable to specify each enemy after each frame, but that doesn't mean you can't make a variable. I would have a script (be it in the global script or in a ffc script) that will scan each enemy after they are created, then will assign each of your custom enemies a unique value in Misc[0]. This will only have to be for one frame. Do something like this:
// This basically ensures that the script will wait until enemies are created
while(Screen->NumNPCs() == 0)
waitframe();
for(int i = 0; i < Screen->NumNPCs(); i++)
// Check each enemy for your custom enemy and change the Misc[0]
Then, when each enemy spawns your custom weapon, the value of Misc[0] for that enemy is placed into the Misc[0] of the weapon. Then in the global loop, when you need to find the enemy associated with each weapon, you scan each enemy until you find one that matches the Misc[0] value.
That should do it for you.
Edited by LinktheMaster, 05 January 2011 - 06:35 PM.
#3
Posted 06 January 2011 - 02:12 AM
When you create a new child eweapon, you'll set child->Misc[0] = parent->Misc[0], and when you need to update the eweapon's position, you'll get the parent npc at parents[child->Misc[0]].
#4
Posted 06 January 2011 - 03:25 PM
Actually, I thought enemies and weapons were given unique IDs upon creation that don't change and could let you pull the actual pointer during every frame. Actually... *looks*... why isn't there a function for pulling entity pointers via ID? That should be super easy to do :/
EDIT - Actually I'm dumb, you could actually do it via scripting.
weapon whatever = CreateEWpn(whatever);
...
whatever->Misc[0] = this->ID;
<other init stuff>
And then in the weapon code
bool found=false;
npc temp;
for(int i = 0; i < Screen->NumNPCs(); i++)
{
temp = screen->LoadNPC(i);
if(temp->ID == this->Misc[0])
{
found=true;
...<do whatever here>
}
}
See if that or a possible variant works for you.
Edited by jman2050, 06 January 2011 - 03:43 PM.
#5
Posted 06 January 2011 - 04:17 PM
(to everyone) I had been giving this some thought, and yes, associating the EWeapon's Misc[] with an NPC's Misc[] appeared to be the best solution... but I'm afraid of one thing.
Running a loop that checks every NPC multiple times per frame will slow down my game, won't it? Remember, this isn't the only extensive script I have going on, and even if I get fancy stuff to work, it means nothing if there's a critical slowdown problem; sucks out all the redeeming value and enjoyment.
I've been afraid to write a couple different scripts, actually, for this very reason. I'll try these methods, since nothing else seems plausible as a solution, but I'm still concerned...
#6
Posted 06 January 2011 - 04:41 PM
(to Jman) Oh hi! Good idea, but doesn't NPC->ID refer to the "species" of enemy it is, rather than its screen pointer? Six Peahats on the screen would all have an ID variable of 32.
You're right actually, my bad. There should be a way to access an entities unique ID though. I guess I can work on that at some point
Running a loop that checks every NPC multiple times per frame will slow down my game, won't it? Remember, this isn't the only extensive script I have going on, and even if I get fancy stuff to work, it means nothing if there's a critical slowdown problem; sucks out all the redeeming value and enjoyment.
I've been afraid to write a couple different scripts, actually, for this very reason. I'll try these methods, since nothing else seems plausible as a solution, but I'm still concerned...
Just write the script and see if things slow down. It would typically take a lot of continuous script processing to really start slowing things down, especially after the optimizations that were made to the scripting engine. So the way I see it, don't worry about speed issues until they actually become issues.
#7
Posted 06 January 2011 - 09:06 PM
const int IDX_ENEMY_ID=0;
// Enemy cache; associates generated IDs with current enemy indices
int npcCache[256];
// Get a unique ID number for the given enemy. A new ID will be
// assigned if it doesn't have one already.
// Note: using this on a very large number of enemies without
// changing screens (more than npcCache can hold) will cause problems.
int GetID(npc enemy)
{
// If the enemy already has an ID, return it
if(enemy->Misc[IDX_ENEMY_ID]>0)
return enemy->Misc[IDX_ENEMY_ID];
// No ID; generate a new one
int newID=0;
int index=0;
npc temp;
// Find the highest ID in use and add one
for(int i=Screen->NumNPCs(); i>0; i--)
{
temp=Screen->LoadNPC(i);
if(temp==enemy) // Found the input enemy; remember the index so it can be cached
index=i;
else
newID=Max(newID, temp->Misc[IDX_ENEMY_ID]+1);
}
// Assign the ID, cache the index, and return
enemy->Misc[IDX_ENEMY_ID]=newID;
npcCache[newID-1]=index;
return newID;
}
// Get the enemy with the ID returned by GetID().
// If no such enemy exists, the returned enemy will be invalid.
npc LoadNPCByID(int id)
{
// Load from cache
npc ret=Screen->LoadNPC(npcCache[id-1]);
if(ret->isValid() && ret->Misc[IDX_ENEMY_ID]==id)
return ret;
// Cached enemy was wrong; refresh cache
ret=Screen->LoadNPC(0); // Invalid
npc temp;
for(int i=Screen->NumNPCs(); i>0; i--)
{
temp=Screen->LoadNPC(i);
if(temp->Misc[IDX_ENEMY_ID]==0)
continue;
npcCache[temp->Misc[IDX_ENEMY_ID]-1]=i;
// Found the requested enemy; set return value
if(temp->Misc[IDX_ENEMY_ID]==id)
ret=temp;
}
return ret;
}
Use GetID() to get an ID number for an enemy, then use LoadNPCByID() to reload the enemy. The enemy returned by the latter will be invalid if no enemy has the given ID.
Just don't use it on more than 256 enemies on the same screen. It could be fixed to account for that, but I figure it's not worth it.
Oh, in case it's not clear, those should be global, not in a script.
Edited by Saffith, 06 January 2011 - 09:12 PM.
#8
Posted 06 January 2011 - 09:55 PM
// Index of npc->Misc[] to use for storing IDs
const int IDX_ENEMY_ID=0;
int unique_id;
int GetID(npc enemy)
{
if(enemy->Misc[IDX_ENEMY_ID]>0)
return enemy->Misc[IDX_ENEMY_ID];
// No ID; generate a new one
unique_id++;
enemy->Misc[IDX_ENEMY_ID] = unique_id;
return unique_id;
}
npc LoadNPCByID(int id)
{
npc temp;
for(int i=Screen->NumNPCs(); i>0; i--)
{
temp=Screen->LoadNPC(i);
if(temp->Misc[IDX_ENEMY_ID]==id)
break;
}
return temp;
}
#9
Posted 07 January 2011 - 10:37 PM
This would help prevent the (highly unlikely) occurrence of reaching the max value for integers. Besides, you'll only have up to 10 enemies (normally, at least), so this keeps things streamlined. The +1 is to prevent it from being 0, the default value.
#10
Posted 07 January 2011 - 10:57 PM
That's quite unlikely, of course, but so are the problems with the previous two approaches. The way to be perfectly safe is to check the IDs currently in use to find one that's free, but that's almost always going to be more trouble than it's worth.
Edited by Saffith, 07 January 2011 - 10:57 PM.
#11
Posted 08 January 2011 - 03:13 AM
..I forget zscript integers are fake real numbers though. So just increment by .0001:
unique_id += 0.0001;
There.
#12
Posted 08 January 2011 - 11:10 AM
If you were to create, ID, and kill 256 enemies per frame, it'd take more than three days before it cycled through all possible numbers, and maybe longer if it couldn't maintain 60 FPS. So, yeah, it's hardcore nitpicking, but still.
#13
Posted 08 January 2011 - 10:09 PM
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users