• Welcome to Battlezone Universe.
 

News:

Welcome to the BZU Archive dated December 24, 2009. Topics and posts are in read-only mode. Those with accounts will be able to login and browse anything the account had access granted to at the time. No changes to permissions will be made to be given access to particular content. If you have any questions, please reach out to squirrelof09/Rapazzini.

Main Menu

Spinoff: Uncle Avatar's Scriptor, C++ and Python Time...

Started by General BlackDragon, April 23, 2008, 06:03:45 PM

Previous topic - Next topic

bigbadbogie

Others would merely say it was good humour.


My BZ2 mods:

QF2: Essence to a Thief - Development is underway.

Fleshstorm 2: The Harvest - Released on the 6th of November 2009. Got to www.bz2md.com for details.

QF Mod - My first mod, finished over a year ago. It can be found on BZ2MD.com

OvermindDL1

Makes a pre-made animation of a msh file play and loop repeatedly (something that like the Ornithopter in DuneZone/DuneCommand used to always be flapping) from the looks of it, although there is the occasional erroneous bit, like TempMsgStr in one of thoes and so forth. :)

Generated by OvermindDL1's Signature Auto-Add Script via GreaseMonkey


bigbadbogie

 :-o all that just to do this?:

(in the scriptor)
SetAnimation,Object,"anim",0
StartAnimation,Object
Others would merely say it was good humour.


My BZ2 mods:

QF2: Essence to a Thief - Development is underway.

Fleshstorm 2: The Harvest - Released on the 6th of November 2009. Got to www.bz2md.com for details.

QF Mod - My first mod, finished over a year ago. It can be found on BZ2MD.com

Nielk1

@OvermindDL1
I though I got rid of all my debugging output lines. Fixing.

@BBB
In English, it does a lot more BBB.
It automatically waits for the amount of time set in the ODF, and then starts the animation listed in the ODF.
If you look, only 2 lines actually choose the animation and start it.

The cause for the wait time is to allow for deploy animations to not get in the way.

It is useful code, and it is bulky because it is dynamic and reads the ODF for information.

Click on the image...

OvermindDL1

Yea, the posted C++ can time it properly, loop it properly, etc...

Generated by OvermindDL1's Signature Auto-Add Script via GreaseMonkey


Nielk1

truthfully I got some old BZC DLL source code from GBD that handled animated the REC, MUF, and SLF and adapted it to use vectors for dynamic size and scanning ODFs so any object can use it.

Click on the image...

OvermindDL1

#51
Also, for note, it is not that hard to do 'linear' programming in C++ either.  An example (this is valid code and will compile and run as expected if I compiled it on my system as is, assuming I did not misspell anything):

This is the scheduler, you can probably ignore it, just normal write-once boilerplate code...
// This class is just a scheduler to keep things synced to the BZ2 world, you could ignore it...
typedef __coroutine__<void()> job_type;
typedef job_type::__self__ self_type;
class Scheduler
{
public:
typedef std::multimap<std::string,std::string>::const_iterator Iterator;

void newJob(function<void(self_type&)> fn)
{
add(job_type(fn));
}
  
void add(job_type job)
{
m_Map.insert(std::make_pair(m_CurTime+1, job));
    }
   
    void sleep(self_type &self, unsigned int ticks=0)
    {
m_Map.insert(std::make_pair(m_CurTime+ticks+1, m_Current));
m_Current = job_type();
sleep.__yield__();
}

void run()
{
const std::pair<Iterator,Iterator> now = questions.equal_range(++m_CurTime);
for (Iterator i=now.first; i!=now.second; ++i)
{
m_Current = i->second;
m_Current()(nothrow);
if(m_Current) add(m_Current);
}
m_Map.erase(now.first, now.second);
}

Scheduler(unsigned int startTime=0)
:m_CurTime(startTime)
{
}

private:
multimap<unsigned int, job_type> m_Map;
unsigned int m_CurTime;
job_type m_Current;
};

// Just a convenience function, ignore me too
__forceinline void sleep(self_type &self, unsigned int ticks=0)
{
scheduler->sleep(self, ticks);
}


Here is the interesting code, yes, valid C++ and this would compile for me as is (again, assuming I spelled everything correctly):
// Create the scheduler somewhere, like in the missions Init and Load functions...
if(scheduler) delete scheduler;
scheduler = new Scheduler(m_ElapsedGameTime);

// Let's create a couple jobs
void watchForUnitDeathOnceASecondAndDoEndgameIfDead(self_type &self, Handle watchedUnit)
{
sleep(self); // Just to give time for the unit to be fully created by BZ2
while(IsAlive2(watchedUnit)
sleep(self, m_GameTPS); // m_GameTPS is one second worth of ticks
// If I ever reach here, the unit died
NoteGameoverWithCustomMessage("Vital unit died");
DoGameover(5*m_GameTPS);
}

void someBasicScriptedActions(self_type &self)
{
Handle superUnit = BuildObject("someSuperUnit", 12, "superUnitSpawnPath")
sleep(self); // Wait a tick to let BZ2 fully spawn it in
Attack(superUnit, m_Player, 9999); // May it follow and attack the player to the end of its days...
while(IsAlive2(superUnit))
sleep(self, m_GameTPS);
// The end of its days has occurred
AddToMessageBox("Super unit has been destroyed");
// So on and so forth here, use sleep to sleep some amount of ticks, nice linear programming style now
}

// And use it as such to create some new jobs somewhere:
scheduler->newJob(bind(watchForUnitDeathOnceASecondAndDoEndgameIfDead, _1, m_PlayerRecycler));
scheduler->newJob(bind(watchForUnitDeathOnceASecondAndDoEndgameIfDead, _1, m_SomeMissionCriticalUnit));
scheduler->newJob(bind(watchForUnitDeathOnceASecondAndDoEndgameIfDead, _1, m_SomeOtherMissionCriticalUnit));
scheduler->newJob(someBasicScriptedActions);

// And be sure to run it once a tick, in the Update/Execute function for example:
scheduler->run();


Nielk1's previous example, if ported to this style, would be a lot more simple as well, allow me to just copy/paste while making the necessary modifications:
For the Header:

public:
void fullLoopAnim(self_type &self, Handle h);


For CPP:
void instantMission::fullLoopAnim(self_type &self, Handle h)
{
char ODFName[64];
if(GetObjInfo(h, Get_CFG, ODFName)) //is a game object check (double duty to ODFName)
{
GetObjInfo(h, Get_ODF, ODFName);
char loopAnimationName[64];
float loopAnimationDelay;
OpenODF(ODFName);
GetODFString(ODFName, "GameObjectClass", "loopAnimationName", 64, loopAnimationName);
GetODFFloat(ODFName, "GameObjectClass", "loopAnimationDelay", &loopAnimationDelay);
CloseODF(ODFName);
loopAnimationDelay *= m_GameTPS;
if((loopAnimationName[0]!=0) & (loopAnimationDelay>0))// not null
{
while(IsAlive2(h))
{
SetAnimation(h,loopAnimationName, 0);
StartAnimation(h);
sleep(loopAnimationDelay);
}
}
}
}
void instantMission::AddObject(Handle h)
{
...
scheduler->newJob(bind(instantMission::fullLoopAnim, this, _1, h));
}


Also, Nielk1, be sure to clean your memory, you are leaking horribly in your example, I fixed it mine.  Also fixed your string test that would *always* pass.  Yours also does not check to see if the unit died, because if they die then you start sending commands to an invalid Handle. :P

Use your imagination for further examples, as you can see it is quite possible in C++ to do these things as well.  Remember what I have said, C++ is one of those language where you can do anything, you may not always be able to do it 'pretty', but you can do it. :)

EDIT:  Also, for the keenly aware around here, I have been experimenting with this style programming in C++ for many years now, posting up examples that are in the now disappeared programming board (as such I can not link to some of my old examples and old methods of doing things so you can see just how much better it is now, gotta love when links are killed, breaks pages...), my libraries just keep getting more and more refined over time.

I also have something that takes source code and properly converts it to html with all the nice color coding I usually use, need to change it to use bbcode tags sometime since I cannot post html here...

Generated by OvermindDL1's Signature Auto-Add Script via GreaseMonkey


Nielk1

Would you mind helping with the leaking memory? I;m used to JAVA cleaning everything up for me.

The only think I can think of is where I said
char *loopAnimationName = new char[64];

I take it I need to delete that at the point where I remove it from the vector. I HATE VECTORS NOW. I cant believe I cant get a damn delete or remove function that asks for an index instead of a god forsaken iterator. The damn iterators beak the instant the thing they are iterating changes anyway. The change in index of so many elements is very wasteful, but I can't think of a better way.

EDIT: OK, I kinda cheated a bit and let the compiler tell me things I should have already known.
I tried:
delete waitingToLoopObjects[waitingToLoopObjects.size()- 1];
delete waitingToLoopNames[waitingToLoopNames.size()  - 1];
delete waitingToLoopTime[waitingToLoopTime.size()   - 1];
and since the first and last aren't pointers it nicely told me so and I commented them out. Does that stop the mem leak? Here is the new code so far:

void instantMission::queueLoopAnim(Handle h)
{
char ODFName[64];
if(GetObjInfo(h, Get_CFG, ODFName)) //is a game object check (double duty to ODFName)
{
GetObjInfo(h, Get_ODF, ODFName);
char *loopAnimationName = new char[64];
float loopAnimationDelay;
OpenODF(ODFName);
GetODFString(ODFName, "GameObjectClass", "loopAnimationName", 64/*0*/, loopAnimationName);
GetODFFloat(ODFName, "GameObjectClass", "loopAnimationDelay", &loopAnimationDelay);
CloseODF(ODFName);
loopAnimationDelay *= m_GameTPS;
if((loopAnimationName[0] != 0) & (loopAnimationDelay > 0))// not null
{
waitingToLoopObjects.push_back(h);
waitingToLoopNames.push_back(loopAnimationName);
waitingToLoopTime.push_back(loopAnimationDelay);
}
}
}
void instantMission::startLoopAnim()
{
for(int x = 0; x < waitingToLoopObjects.size(); x++)
{
if(IsAlive2(waitingToLoopObjects[x]))
{
--waitingToLoopTime[x];
if(waitingToLoopTime[x] < 0)
{
SetAnimation(waitingToLoopObjects[x],waitingToLoopNames[x], 0);
StartAnimation(waitingToLoopObjects[x]);
for(int y = x; y < (waitingToLoopObjects.size() - 1); y++)
{
waitingToLoopObjects[y] = waitingToLoopObjects[y + 1];
waitingToLoopNames[y]   = waitingToLoopNames[y   + 1];
waitingToLoopTime[y]    = waitingToLoopTime[y    + 1];
}
x--;
delete waitingToLoopNames[  waitingToLoopNames.size()  - 1]; //delete NEW allocation
waitingToLoopObjects.resize(waitingToLoopObjects.size()- 1);
waitingToLoopNames.resize(  waitingToLoopNames.size()  - 1);
waitingToLoopTime.resize(   waitingToLoopTime.size()   - 1);
}
}else{ //oh my, a dead thing is in here, dispose of it
for(int y = x; y < (waitingToLoopObjects.size() - 1); y++)
{
waitingToLoopObjects[y] = waitingToLoopObjects[y + 1];
waitingToLoopNames[y]   = waitingToLoopNames[y   + 1];
waitingToLoopTime[y]    = waitingToLoopTime[y    + 1];
}
x--;
delete waitingToLoopNames[  waitingToLoopNames.size()  - 1]; //delete NEW allocation
waitingToLoopObjects.resize(waitingToLoopObjects.size()- 1);
waitingToLoopNames.resize(  waitingToLoopNames.size()  - 1);
waitingToLoopTime.resize(   waitingToLoopTime.size()   - 1);
}
}
}



I like loops, and I think in them (probably something to do with OCD or some other undiagnosed illness).

I don't quite understand your code. You call a sleep command, is that asynchronous or does it stall the whole DLL (something I am afraid of doing)? The way I have mine coded it waits for the set amount of time before executing the animation, but your looks like it sets the animation, starts it, then waits? The purpose of the wait was to allow deploy animations to finish, so even setting the animation before it is done would mess it up wouldn't it?

EDIT2:
OK, new issue. I made the code have a separate CPP and H from the main code, so it has to be imported, its constructor called, and its functions called. That all works. Now, the issue is it uses the TPS variable to calculate the time, and, I do not know how to get it over to the new class. I am thinking about adding "m_LoopAnimator.shareTPS(m_GameTPS);", but I am unsure of where to put it; does it go in load, the constructor, somewhere else, or everywhere?

Click on the image...

OvermindDL1

#53
Have not read the whole post, can later, but for fixing the memory, you are correct about where you are leaking.  Do not new the char array, rather just keep it a local, memset it fully empty each time before use, and stuff it in an std::string inside the vector, it will copy it and manage the memory properly (not the most efficient method, but very easy).  The reason you cannot delete an index is because it is a vector, a vector is an array, an array is a contiguous group of memory, you cannot just delete something inside of it, that is why when you do it using a vector it makes a copy of the entire array, sans the section you chose not to include.  If you want to be able to manage it easier then you might think of using std::list instead, it is less efficient then an array, but easier to use in those circumstances.  Might also consider an std::map, better then the list in efficiency, but better then a vector in usage capability.

As for my version of your code, look a little higher, I am not using the standard sleep, I am using my own function called sleep (different signature), it only sleeps the little job, not the whole dll, not BZ2, etc...  It sleeps like you sleep in my Python Scriptor, you create little different jobs (coroutines is more accurate, or in the case of my library, fibers) and you can pause in them, change between them without needing to return, so on and so forth, kinda like threads but vastly more lightweight and no concurrency issues since it is not actually pre-emptive.  Fibers are nice, they have a bit of a bug so they are not too usable for, say, creating 10000 of them (the bug is that even though you tell it to create it with a stack of say 2k, it still creates a stack the size of your program stack, so it ends up being a good 2megs or so each regardless, it has been a bug in Windows since Win95 sad enough, still not even fixed in Vista I think, which is odd because .NET2.0 makes heavy use of Win32 Fibers), but for a few hundred or so then they are perfect.

Generated by OvermindDL1's Signature Auto-Add Script via GreaseMonkey


Nielk1

Perhaps a list of structs containing the 3 variables. I wonder if that would work better. The TPS thing is really bothering me, and I would prefer to use the stop DLL format for now. When pb4 is done, is there any change of you getting the DLLs ready and out that use your system of threading instead? You have to understand my C++ knowledge is still pretty primitive.

Click on the image...

OvermindDL1

#55
Fiber stuff is pretty well documented, I have a few of my own ways of doing it as well, but you would not like them (faster, more efficient 'coroutines', but a lot of code noise, remember what I said about being able to do anything in C++, just not always 'pretty' :) ).

I could probably whip up a C++ library for BZ2 to do fiber/job/coroutine stuff, but a prerequisite (probably the only one) is to have Boost installed properly.  I should only need the function, bind, and so forth stuff in it, just header things, so compiling it would not be necessary.  I could always just include the parts I need though, just depends on if I want to do the work or not.

But yes, make all the information you store into a struct or tuple, example:
// Using a struct:
struct waitingToLoopStruct
{
Handle h;
string name;
unsigned int delay;
}
// and define your list/array like this:
vector<waitingToLoopStruct> waitingToLoop;

// Or by using a tuple (note, this requires either the latest TR1 or later headers of the newest C++ standard, or boost installed, either work
vector<tuple<Handle, string, unsigned int> > waitingToLoop;


Also, "stop DLL format" is what?
Another also, the above example did not use threading, it used coroutines they are not anywhere near the same thing. :)

EDIT:As for the TPS, just pass it in as a constructor parameter to your class.
Example:
class myClass
{
unsigned int m_I;
public:
myClass(unsigned int i)
:m_I(i)
{}
}

// When you need to make the above class, construct it as:
myClass myClassInstance(42);


If you really want it default constructable then just set a variable in the class directly, or call a member function to set an internal variable, or give a link back to the parent class, or... or... or...  Lot's of choices. :)


Generated by OvermindDL1's Signature Auto-Add Script via GreaseMonkey


Nielk1

Opps, meant "Stock DLL Format"

I will get my code working again (the TPS), post the code, then move on to getting it to use the better list/struct.

I have a lot of trouble with iterators. Should I still try to use one or can I directly access the nodes in a linked list?

EDIT: OK, question because of how I moved to C++ from Java. What is 'unsigned'?

Click on the image...

Nielk1

Evil double post...

New code:

LoopAnimator.h
//To use, place in header:
//#include "..\Shared\LoopAnimator.h"
//private:
// LoopAnimator m_LoopAnimator;
//
//Place the following in the end of the constructor
//m_LoopAnimator.shareTPS(m_GameTPS)

//in execute call:
//m_LoopAnimator.execute()
//in addObject call:
//m_LoopAnimator.addObject(h)
//and so on

#ifndef _LoopAnimator_
#define _LoopAnimator_

# pragma once

#include "..\..\source\fun3d\ScriptUtils.h"
#include <vector>

class LoopAnimator {

unsigned int m_GameTPS; // How many turns per second there are (10, 15, 20, or 30)

int i_first,
i_last;

Handle h_first,
h_last;

bool b_first,
b_last;

float f_first,
f_last;

std::vector<Handle> waitingToLoopObjects;
std::vector<char*> waitingToLoopNames;
std::vector<float> waitingToLoopTime;
std::vector<bool> waitingToLoopMode;

bool *b_array;
int b_count;

float *f_array;
int f_count;

int *h_array;
int h_count;

int *i_array;
int i_count;

public:
LoopAnimator(void);
void shareTPS(int inTPS);
virtual bool Save(bool missionSave);
virtual bool Load(bool missionSave);
virtual bool PostLoad(bool missionSave);
virtual void AddObject(Handle h);
virtual void DeleteObject(Handle h);
virtual void Execute(void);
};
#endif


LoopAnimator.cpp
#include "LoopAnimator.h"
#include <string.h>

LoopAnimator::LoopAnimator(void)
{
b_count = &b_last - &b_first - 1;
b_array = &b_first + 1;

f_count = &f_last - &f_first - 1;
f_array = &f_first + 1;

    h_count = &h_last - &h_first - 1;
h_array = &h_first + 1;

i_count = &i_last - &i_first - 1;
i_array = &i_first + 1;
}

void LoopAnimator::shareTPS(int inTPS)
{
m_GameTPS = inTPS;
}

bool LoopAnimator::Load(bool missionSave)
{
if (missionSave) {
int i;

// init bools
if((b_array) && (b_count))
for (i = 0; i < b_count; i++)
b_array[i] = false;

// init floats
if((f_array) && (f_count))
for (i = 0; i < f_count; i++)
f_array[i] = 0.0f;

// init handles
if((h_array) && (h_count))
for (i = 0; i < h_count; i++)
h_array[i] = 0;

// init ints
if((i_array) && (i_count))
for (i = 0; i < i_count; i++)
i_array[i] = 0;

return true;
}

bool ret = true;

// bools
if (b_array != NULL)
Read(b_array, b_count);

// floats
if (f_array != NULL)
Read(f_array, f_count);

// Handles
if (h_array != NULL)
Read(h_array, h_count);

// ints
if (i_array != NULL)
Read(i_array, i_count);

return ret;
}

bool LoopAnimator::PostLoad(bool missionSave)
{
if (missionSave)
return true;

bool ret = true;

ConvertHandles(h_array, h_count);

return ret;
}

bool LoopAnimator::Save(bool missionSave)
{
if (missionSave)
return true;

bool ret = true;

// bools
if (b_array != NULL)
Write(b_array, b_count);

// floats
if (f_array != NULL)
Write(f_array, f_count);

// Handles
if (h_array != NULL)
Write(h_array, h_count);

// ints
if (i_array != NULL)
Write(i_array, i_count);

return ret;
}

void LoopAnimator::AddObject(Handle h)
{
// Start Queue Loop Animation
char ODFName[64];
if(GetObjInfo(h, Get_CFG, ODFName)) //is a game object check (double duty to ODFName)
{
GetObjInfo(h, Get_ODF, ODFName);
char *loopAnimationName = new char[64];
float loopAnimationDelay;
bool loopAnimationType;
OpenODF(ODFName);
GetODFString(ODFName, "GameObjectClass", "loopAnimationName", 64, loopAnimationName);
GetODFFloat(ODFName, "GameObjectClass", "loopAnimationDelay", &loopAnimationDelay);
GetODFBool(ODFName, "GameObjectClass", "loopAnimationType", &loopAnimationType);
CloseODF(ODFName);
loopAnimationDelay *= m_GameTPS;
if((loopAnimationType != 0)&&(loopAnimationType != 1)){loopAnimationType = 0;}
if((loopAnimationName[0] != 0) & (loopAnimationDelay > 0))// not null
{
waitingToLoopObjects.push_back(h);
waitingToLoopNames.push_back(loopAnimationName);
waitingToLoopTime.push_back(loopAnimationDelay);
waitingToLoopMode.push_back(loopAnimationType);
}
}
// End Queue Loop Animation
}

void LoopAnimator::DeleteObject(Handle h)
{

}

void LoopAnimator::Execute()
{
// Start Loop Animation
for(int x = 0; x < waitingToLoopObjects.size(); x++)
{
if(IsAlive2(waitingToLoopObjects[x]))
{
--waitingToLoopTime[x];
if(waitingToLoopTime[x] < 0)
{
SetAnimation(waitingToLoopObjects[x],waitingToLoopNames[x],waitingToLoopMode[x]);
StartAnimation(waitingToLoopObjects[x]);
for(int y = x; y < (waitingToLoopObjects.size() - 1); y++)
{
waitingToLoopObjects[y] = waitingToLoopObjects[y + 1];
waitingToLoopNames[y]   = waitingToLoopNames[y   + 1];
waitingToLoopTime[y]    = waitingToLoopTime[y    + 1];
waitingToLoopMode[y]    = waitingToLoopMode[y    + 1];
}
x--;
delete waitingToLoopNames[  waitingToLoopNames.size()  - 1]; //delete NEW allocation
waitingToLoopObjects.resize(waitingToLoopObjects.size()- 1);
waitingToLoopNames.resize(  waitingToLoopNames.size()  - 1);
waitingToLoopTime.resize(   waitingToLoopTime.size()   - 1);
waitingToLoopMode.resize(   waitingToLoopMode.size()   - 1);
}
}else{ //oh my, a dead thing is in here, dispose of it
for(int y = x; y < (waitingToLoopObjects.size() - 1); y++)
{
waitingToLoopObjects[y] = waitingToLoopObjects[y + 1];
waitingToLoopNames[y]   = waitingToLoopNames[y   + 1];
waitingToLoopTime[y]    = waitingToLoopTime[y    + 1];
waitingToLoopMode[y]    = waitingToLoopMode[y    + 1];
}
x--;
delete waitingToLoopNames[  waitingToLoopNames.size()  - 1]; //delete NEW allocation
waitingToLoopObjects.resize(waitingToLoopObjects.size()- 1);
waitingToLoopNames.resize(  waitingToLoopNames.size()  - 1);
waitingToLoopTime.resize(   waitingToLoopTime.size()   - 1);
waitingToLoopMode.resize(   waitingToLoopMode.size()   - 1);
}
}
// End Loop Animation
}

Click on the image...

OvermindDL1

Definitely use iterators.  Also, Java uses iterators pretty heavily as well so you should know how to use them, the usage is near identical.

And an unsigned int is exactly that, it is an int with no sign (no negative, only positive), good to do if your number is not supposed to ever be negative. :)

Generated by OvermindDL1's Signature Auto-Add Script via GreaseMonkey


Nielk1

Now I am having new issues:

LoopAnimator.h
//To use, place in header:
//#include "..\Shared\LoopAnimator.h"
//private:
// LoopAnimator m_LoopAnimator;
//
//Place the following in the end of the constructor
//m_LoopAnimator.shareTPS(m_GameTPS)

//in execute call:
//m_LoopAnimator.execute()
//in addObject call:
//m_LoopAnimator.addObject(h)
//and so on

#ifndef _LoopAnimator_
#define _LoopAnimator_

# pragma once

#include "..\..\source\fun3d\ScriptUtils.h"
#include <vector>
#include <list>

class LoopAnimator {

unsigned int m_GameTPS; // How many turns per second there are (10, 15, 20, or 30)

int i_first,
i_last;

Handle h_first,
h_last;

bool b_first,
b_last;

float f_first,
f_last;

//std::vector<Handle> waitingToLoopObjects;
//std::vector<char*> waitingToLoopNames;
//std::vector<float> waitingToLoopTime;
//std::vector<bool> waitingToLoopMode;

struct loopQueue {
Handle loopObject;
std::string *loopName;
float loopTime;
bool loopMode;
};

std::list<loopQueue> waitingLoops;

bool *b_array;
int b_count;

float *f_array;
int f_count;

int *h_array;
int h_count;

int *i_array;
int i_count;

public:
LoopAnimator(void);
void shareTPS(int inTPS);
virtual bool Save(bool missionSave);
virtual bool Load(bool missionSave);
virtual bool PostLoad(bool missionSave);
virtual void AddObject(Handle h);
virtual void DeleteObject(Handle h);
virtual void Execute(void);
};
#endif


LoopAnimator.cpp
#include "LoopAnimator.h"
#include <string.h>
#include <list> //tmp

LoopAnimator::LoopAnimator(void)
{
b_count = &b_last - &b_first - 1;
b_array = &b_first + 1;

f_count = &f_last - &f_first - 1;
f_array = &f_first + 1;

    h_count = &h_last - &h_first - 1;
h_array = &h_first + 1;

i_count = &i_last - &i_first - 1;
i_array = &i_first + 1;
}

void LoopAnimator::shareTPS(int inTPS)
{
m_GameTPS = inTPS;
}

bool LoopAnimator::Load(bool missionSave)
{
if (missionSave) {
int i;

// init bools
if((b_array) && (b_count))
for (i = 0; i < b_count; i++)
b_array[i] = false;

// init floats
if((f_array) && (f_count))
for (i = 0; i < f_count; i++)
f_array[i] = 0.0f;

// init handles
if((h_array) && (h_count))
for (i = 0; i < h_count; i++)
h_array[i] = 0;

// init ints
if((i_array) && (i_count))
for (i = 0; i < i_count; i++)
i_array[i] = 0;

return true;
}

bool ret = true;

// bools
if (b_array != NULL)
Read(b_array, b_count);

// floats
if (f_array != NULL)
Read(f_array, f_count);

// Handles
if (h_array != NULL)
Read(h_array, h_count);

// ints
if (i_array != NULL)
Read(i_array, i_count);

return ret;
}

bool LoopAnimator::PostLoad(bool missionSave)
{
if (missionSave)
return true;

bool ret = true;

ConvertHandles(h_array, h_count);

return ret;
}

bool LoopAnimator::Save(bool missionSave)
{
if (missionSave)
return true;

bool ret = true;

// bools
if (b_array != NULL)
Write(b_array, b_count);

// floats
if (f_array != NULL)
Write(f_array, f_count);

// Handles
if (h_array != NULL)
Write(h_array, h_count);

// ints
if (i_array != NULL)
Write(i_array, i_count);

return ret;
}

void LoopAnimator::AddObject(Handle h)
{
// Start Queue Loop Animation
char ODFName[64];
if(GetObjInfo(h, Get_CFG, ODFName)) //is a game object check (double duty to ODFName)
{
GetObjInfo(h, Get_ODF, ODFName);
//char *loopAnimationName = new char[64];
//float loopAnimationDelay;
//bool loopAnimationType;
loopQueue tmpHolder;
tmpHolder.loopObject = h;
OpenODF(ODFName);
GetODFString(ODFName, "GameObjectClass", "loopAnimationName", 64, tmpHolder.loopName);
GetODFFloat(ODFName, "GameObjectClass", "loopAnimationDelay", &tmpHolder.loopTime);
GetODFBool(ODFName, "GameObjectClass", "loopAnimationType", &tmpHolder.loopMode);
CloseODF(ODFName);
tmpHolder.loopTime *= m_GameTPS;
if((!(tmpHolder.loopName.empty())) && (tmpHolder.loopTime >= 0))// not null
{
waitingLoops.push_back(tmpHolder);
}
}
// End Queue Loop Animation
}

void LoopAnimator::DeleteObject(Handle h)
{

}

void LoopAnimator::Execute()
{
// Start Loop Animation
std::list<loopQueue>::iterator iter1 = waitingLoops.begin();
while( iter1 != waitingLoops.end() )
{
if(IsAlive2(iter1->loopObject))
{
--(iter1->loopTime);
if((iter1->loopTime) < 0)
{
SetAnimation(iter1->loopObject,iter1->loopName,iter1->loopMode);
StartAnimation(iter1->loopObject);
waitingLoops.remove(iter1);
}
}else{
waitingLoops.remove(iter1);
}
iter1++;
}   
// End Loop Animation
}


Errors (I'm sure some early ones spawn later ones):
Error 1 error C2664: 'GetODFString' : cannot convert parameter 5 from 'std::string *' to 'char *' d:\Battlezone\DLLs\BZ2_1.3pb4rc1_DLLSource\Missions\Shared\LoopAnimator.cpp 125
Error 2 error C2228: left of '.empty' must have class/struct/union d:\Battlezone\DLLs\BZ2_1.3pb4rc1_DLLSource\Missions\Shared\LoopAnimator.cpp 130
Error 3 error C2664: 'SetAnimation' : cannot convert parameter 2 from 'std::string *' to 'Name' d:\Battlezone\DLLs\BZ2_1.3pb4rc1_DLLSource\Missions\Shared\LoopAnimator.cpp 154
Error 4 error C2664: 'std::list<_Ty>::remove' : cannot convert parameter 1 from 'std::list<_Ty>::_Iterator<_Secure_validation>' to 'const LoopAnimator::loopQueue &' d:\Battlezone\DLLs\BZ2_1.3pb4rc1_DLLSource\Missions\Shared\LoopAnimator.cpp 156
Error 5 error C2664: 'std::list<_Ty>::remove' : cannot convert parameter 1 from 'std::list<_Ty>::_Iterator<_Secure_validation>' to 'const LoopAnimator::loopQueue &' d:\Battlezone\DLLs\BZ2_1.3pb4rc1_DLLSource\Missions\Shared\LoopAnimator.cpp 159

Click on the image...