/*******************************************************************
/*  CommonUnit.cpp
/*  Author: Vadim Berman
/*
/*  Description:
/*  implementation of auxiliary structures handlers and most
/*  non-member service functions
/*
/*  The contents of this file are subject to the Brainiac Public License.
/*  Version 1.0 (the "License"); you may not use this file except in
/*  compliance with the License. You may obtain a copy of the License at
/*  http://www.twilightminds.com
/*
/*  Software distributed under the License is distributed on an "AS IS"
/*  basis WITHOUT WARRANTY OF ANY KIND, either express or implied. See
/*  the License for the specific language governing rights and limitations
/*  under the License.
/*
/*  Copyright (C) 1999 Twilight Minds. All rights reserved.
/********************************************************************/

#include "CommonUnit.h"
#include "DiskRecUnit.h"
char Msg1[200];
percentage AvgBeauty = 9;
char ErrorString[MAX_ERROR_LEN];
long BEErrorCode;

//***************************************************************************
//Stop
//********** Description: **************
//display a warning message with the option to end application
//********** Parameters:  **************
//char *szMsg - characters string to display
//--------------------------------------------------------------
void BBECALL Stop(char *szMsg)
{
	if(MessageBox(NULL, szMsg, "Stop", MB_OKCANCEL + MB_ICONEXCLAMATION)
        == IDCANCEL)
    {
        MessageBox(NULL, "Click OK to close this application", "Exit", MB_OK);
        ExitProcess(3);
    }
}

//***************************************************************************
//APIError
//********** Description: **************
//display the last Windows system error, with the option to end application
//********** Parameters:  **************
//none
//--------------------------------------------------------------
void BBECALL APIError()
{
    long i;
    for(i = 0;i < 200;i++)
        Msg1[i] = '\0';
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,
        GetLastError(),0,(LPTSTR)Msg1,100, NULL);
    Stop(Msg1);
}

//***************************************************************************
//SumAndMax
//********** Description: **************
//return both sum of the given components and the most influential
//component's index (the latter through a reference)
//********** Parameters:  **************
//percentage *ValList - array of the components
//unsigned int nLen   - array length
//percentage &nMaxI   - the "most influential" component index holder
//--------------------------------------------------------------
int BBECALL SumAndMax(percentage *ValList, unsigned int nLen, percentage &nMaxI)
{
	int nRes = 0;
    percentage nMax;
    nMax = ValList[0];
    nMaxI = 0;
	for(percentage i = 0; i < (percentage)nLen; i++)
    {
    	nRes += ValList[i];
        if( ABS(ValList[i]) > nMax)
        {
        	nMax = (percentage)(ABS(ValList[i]));
            nMaxI = i;
        }
    }
	return nRes;
}

//***************************************************************************
//GetAttitude
//********** Description: **************
//return attitude value to the given ID in the given attitude tree
//********** Parameters:  **************
//ID argPerson_id  - ID to get attitude for
//Attitude *Root   - attitude tree root
//BOOL GetExternal - whether to get external (seemed) or true attitude
//-------------------------------------------
percentage BBECALL GetAttitude(ID argPerson_id, Attitude *Root, BOOL GetExternal)
{
	Attitude *next;
	for( next = Root ; next != NULL ; )
    	if( next->person_id == argPerson_id )//match
        {
        	if( GetExternal == TRUE)
        		return next->Seemed;
         else
            return next->Real;
        }
        else
        	if( next->person_id > argPerson_id )
            	next = next->LSon;
            else
            	next = next->RSon;

	return ERROR_PERCENTAGE;
}

//***************************************************************************
//GetAttitudeNode
//********** Description: **************
//return attitude node to the given ID in the given attitude tree
//********** Parameters:  **************
//ID argPerson_id  - ID to get attitude for
//Attitude *Root   - attitude tree root
//-------------------------------------------
Attitude* BBECALL GetAttitudeNode(ID argPerson_id, Attitude *Root)
{
	Attitude *next;
	for( next = Root ; next != NULL ; )
    	if( next->person_id == argPerson_id )//match
            return next;
        else
        	if( next->person_id > argPerson_id )
            	next = next->LSon;
            else
            	next = next->RSon;

	return NULL;
}

//***************************************************************************
//AddAttitude
//********** Description: **************
//add a new attitude node by the given ID; if the node already exists, a new one
//will NOT be added
//********** Parameters:  **************
//ID argPerson_id        - ID to get attitude for
//percentage argAttitude - attitude value
//Attitude **Root        - attitude tree root address
//-------------------------------------------
BOOL BBECALL AddAttitude(ID argPerson_id, percentage argAttitude, Attitude **Root )
{
	Attitude *next,*sav_node;
    BOOL bInserted = FALSE;

    if(Root == NULL)
        return FALSE;
    next = *Root;
    if(next == NULL)
    {
        next = new Attitude;//(Attitude*)GlobalAlloc(GPTR,sizeof(Attitude));
        if ( next == NULL )
            return FALSE;
        next->Real      = argAttitude;
        next->Seemed    = argAttitude;
        next->person_id = argPerson_id;
        next->LSon      = NULL;
        next->RSon      = NULL;
        *Root = next;
        bInserted = TRUE;
    }

    while(!bInserted && next)
    {
        if(argPerson_id < next->person_id)
        {
            if(next->LSon != NULL)
            {
                next = next->LSon;
            }
            else
            {
                sav_node = next;
                next = new Attitude;//(Attitude*)GlobalAlloc(GPTR,sizeof(Attitude));
                if ( next == NULL )
                    return FALSE;
                sav_node->LSon  = next;
                next->Real      = argAttitude;
                next->Seemed    = argAttitude;
                next->person_id = argPerson_id;
                next->LSon      = NULL;
                next->RSon      = NULL;
                bInserted = TRUE;
            }
        }
        else
            if(argPerson_id > next->person_id)
            {
                if(next->RSon != NULL)
                {
                    next = next->RSon;
                }
                else
                {
                    sav_node = next;
                    next = new Attitude;//(Attitude*)GlobalAlloc(GPTR,sizeof(Attitude));
                    if ( next == NULL )
                        return FALSE;

                    sav_node->RSon  = next;
                    next->Real      = argAttitude;
                    next->Seemed    = argAttitude;
                    next->person_id = argPerson_id;
                    next->LSon      = NULL;
                    next->RSon      = NULL;
                    bInserted = TRUE;
                }
            }
            else
                return FALSE;   //because attitude already exists
    }

	return bInserted;
}

//***************************************************************************
//AddBothAttitudes
//********** Description: **************
//add a new attitude node by the given ID; if the node already exists, a new one
//will NOT be added. The difference between AddBothAttitudes and AddAttitude is
//that the former allows adding a node containing different true and seemed
//attitudes
//********** Parameters:  **************
//ID argPerson_id      - ID to get attitude for
//percentage argReal   - real (true) attitude value
//percentage argSeemed - seemed attitude value
//Attitude **Root      - attitude tree root address
//-----------------------------------------------------------------------------
BOOL BBECALL AddBothAttitudes(ID argPerson_id, percentage argReal, percentage argSeemed, Attitude **Root )
{
	Attitude *next,*sav_node;
    BOOL bInserted = FALSE;

    if(Root == NULL)
        return FALSE;
    next = *Root;
    if(next == NULL)
    {
        next = new Attitude;
        if ( next == NULL )
            return FALSE;

        next->Real      = argReal;
        next->Seemed    = argSeemed;
        next->person_id = argPerson_id;
        next->LSon      = NULL;
        next->RSon      = NULL;
        *Root = next;
        bInserted = TRUE;
    }

    while(!bInserted && next)
    {
        if(argPerson_id < next->person_id)
        {
            if(next->LSon != NULL)
            {
                next = next->LSon;
            }
            else
            {
                sav_node = next;
                next = new Attitude;//(Attitude*)GlobalAlloc(GPTR,sizeof(Attitude));
                if ( next == NULL )
                    return FALSE;
                sav_node->LSon  = next;
                next->Real      = argReal;
                next->Seemed    = argSeemed;
                next->person_id = argPerson_id;
                next->LSon      = NULL;
                next->RSon      = NULL;
                bInserted = TRUE;
            }
        }
        else
            if(argPerson_id > next->person_id)
            {
                if(next->RSon != NULL)
                {
                    next = next->RSon;
                }
                else
                {
                    sav_node = next;
                    next = new Attitude;//(Attitude*)GlobalAlloc(GPTR,sizeof(Attitude));
                    if ( next == NULL )
                        return FALSE;

                    sav_node->RSon  = next;
                    next->Real      = argReal;
                    next->Seemed    = argSeemed;
                    next->person_id = argPerson_id;
                    next->LSon      = NULL;
                    next->RSon      = NULL;
                    bInserted = TRUE;
                }
            }
            else
                return FALSE;   //because attitude already exists
    }

	return bInserted;
}

//***************************************************************************
//ModifyAttitude
//********** Description: **************
//modify an existing attitude node BY argAttitude points
//will NOT be added. The difference between AddBothAttitudes and AddAttitude is
//that the former allows adding a node containing different true and seemed
//attitudes
//********** Parameters:  **************
//ID argPerson_id       - ID to get attitude for
//short argAttitude     - value to modify by (not a direct assignment)
//Attitude *Root        - attitude tree root
//unsigned char UseWhat - which attitude to use (SEEMED / TRUE / BOTH)
//-------------------------------------------
BOOL BBECALL ModifyAttitude(ID argPerson_id, short argAttitude,
	Attitude *Root, unsigned char UseWhat )
{
	Attitude *next;
    short ModAtt;

	for( next = Root ; next != NULL ; )
    	if( next->person_id != argPerson_id )
        {
			if( next->person_id > argPerson_id )
            	next = next->LSon;
            else
            	next = next->RSon;
        }
        else
        {
        	if( UseWhat == SEEMED || UseWhat == BOTH )
            {
                ModAtt = (short)(next->Seemed + argAttitude);
                if(ModAtt > 99)
                    ModAtt = 99;
                if(ModAtt < -99)
                    ModAtt = -99;
                next->Seemed = (percentage)ModAtt;
            }
        	if( UseWhat == TRUE || UseWhat == BOTH )
            {
                ModAtt = (short)(next->Real + argAttitude);
                if(ModAtt > 99)
                    ModAtt = 99;
                if(ModAtt < -99)
                    ModAtt = -99;
                next->Real = (percentage)ModAtt;
            }
        	return TRUE;
        }

   	return FALSE;
}

//***************************************************************************
//UpdateAttitude
//********** Description: **************
//set(add or modify) an existing attitude node to argAttitude points
//********** Parameters:  **************
//ID argPerson_id       - ID to get attitude for
//short argAttitude     - attitude value to set
//Attitude **Root       - attitude tree root address
//unsigned char UseWhat - which attitude to set (SEEMED / TRUE / BOTH)
//-------------------------------------------
BOOL BBECALL UpdateAttitude(ID argPerson_id, percentage argAttitude,
	Attitude **Root, unsigned char UseWhat )
{
	Attitude *next;
    if(argAttitude > 99)
        argAttitude = 99;
    if(argAttitude < -99)
        argAttitude = -99;

	for( next = *Root ; next != NULL ; )
    	if( next->person_id != argPerson_id )
        {
			if( next->person_id > argPerson_id )
            	next = next->LSon;
            else
            	next = next->RSon;
        }
        else
        {
        	if( UseWhat == SEEMED || UseWhat == BOTH )
             next->Seemed = argAttitude;
        	if( UseWhat == TRUE || UseWhat == BOTH )
             next->Real = argAttitude;
        	return TRUE;
        }
    //attitude doesn't exist; add it
    return AddAttitude(argPerson_id, argAttitude, Root );
}

//***************************************************************************
//DelAttitudeTree
//********** Description: **************
//delete the given attitude tree and set the root point to NULL
//********** Parameters:  **************
//Attitude **pRoot - attitude tree root address
//-------------------------------------------
void BBECALL DelAttitudeTree(Attitude **pRoot)
{
    if(pRoot)
      if((*pRoot) != NULL)
      {
         if((*pRoot)->LSon != NULL)
            DelAttitudeTree(&((*pRoot)->LSon));
         if((*pRoot)->RSon != NULL)
            DelAttitudeTree(&((*pRoot)->RSon));
         delete (*pRoot);
         (*pRoot) = NULL;
      }
}

//***************************************************************************
//DelAttitude
//********** Description: **************
//delete attitude node by the given ID
//********** Parameters:  **************
//ID attToDel      - ID of the node to delete
//Attitude **pRoot - attitude tree root address
//-------------------------------------------
void BBECALL DelAttitude(ID attToDel, Attitude **pRoot)
{
    Attitude *pDelNode;
    Attitude *pDelParent;
    char WhoseSon = 'N';
    BOOL found;
    Attitude *Current,*Successor;

    Current = *pRoot;
    pDelParent = *pRoot;
    found = FALSE;
    while(!found && (Current != NULL))
    {
        if(Current->person_id == attToDel)  found = TRUE;
        else
            if(Current->person_id < attToDel)
            {
                WhoseSon = 'L';
                pDelParent = Current;
                Current = Current->LSon;
            }
            else
            if(Current->person_id > attToDel)
            {
                WhoseSon = 'R';
                pDelParent = Current;
                Current = Current->RSon;
            }
    }

    if(!found)
        return; // no luck this time

    pDelNode = Current;
    if((Current->RSon == NULL) && (Current->LSon == NULL))
    // no sons at all - "easy money"
    {
        Successor = NULL;
    }
    else
        // right son only
        if((Current->RSon != NULL) && (Current->LSon == NULL))
        {
            Successor = Current->RSon;
        }
        else
        // left son only
            if((Current->RSon == NULL) && (Current->LSon != NULL))
            {
                Successor = Current->LSon;
            }
            else
            // behold: two children
            if((Current->RSon != NULL) && (Current->LSon != NULL))
            {
                Successor = Current->RSon;
                // get down to the "right leaves" - extreme right node
                while(Current->RSon != NULL)
                {
                    Current = Successor;
                    Successor = Current->RSon;
                }
                Current->RSon = NULL; //just to make sure
                Successor->LSon = pDelNode->LSon;
                Successor->RSon = pDelNode->RSon;
            }
            else
            {
                Successor = Current;
                Successor->RSon = pDelNode->RSon;
            }
    if(WhoseSon != 'N')
    {
        if(WhoseSon == 'L')
            pDelParent->LSon = Successor;
        else
            pDelParent->RSon = Successor;
    }
    else
    {
        *pRoot = NULL;
    }
    delete pDelNode;//GlobalFree((HGLOBAL)pDelNode);
}

//***************************************************************************
//CopyAttitudeTree
//********** Description: **************
//return copy of the given attitude tree
//********** Parameters:  **************
//Attitude *attRoot - attitude tree root
//--------------------------------------------------------------
Attitude *BBECALL CopyAttitudeTree(Attitude *attRoot)
{
    Attitude *NewTree, *LeftSon = NULL, *RightSon = NULL;
    if(attRoot == NULL)
        return NULL;

    if(attRoot->LSon)
        LeftSon = CopyAttitudeTree(attRoot->LSon);
    if(attRoot->RSon)
        RightSon = CopyAttitudeTree(attRoot->RSon);

    NewTree = new Attitude;//(Attitude*)GlobalAlloc(GPTR,sizeof(Attitude));
    if(NewTree != NULL)
    {
        NewTree->person_id = attRoot->person_id;
        NewTree->Seemed = attRoot->Seemed;
        NewTree->Real = attRoot->Real;
        NewTree->RSon = RightSon;
        NewTree->LSon = LeftSon;
    }
    return NewTree;
}

//***************************************************************************
//DumpAttitudeTree2Buffer
//********** Description: **************
//dump attitude tree to the given buffer
//********** Parameters:  **************
//Attitude *attRoot - attitude tree root
//BYTE *pbBuffer    - buffer to fill
//--------------------------------------------------------------
unsigned short BBECALL DumpAttitudeTree2Buffer(Attitude *attRoot, BYTE *pbBuffer)
{
    unsigned short nAllocated = 0;
    if(attRoot == NULL)
        return 0;

    if(attRoot->LSon)
        nAllocated += DumpAttitudeTree2Buffer(attRoot->LSon,pbBuffer
            + nAllocated);

    if(attRoot->RSon)
        nAllocated += DumpAttitudeTree2Buffer(attRoot->RSon,pbBuffer
            + nAllocated);

    memcpy(pbBuffer + nAllocated,&(attRoot->person_id),sizeof(ID));
    nAllocated += (unsigned short)sizeof(ID);
    pbBuffer[nAllocated++] = attRoot->Real;
    pbBuffer[nAllocated++] = attRoot->Seemed;

    return nAllocated;
}

//***************************************************************************
//RestoreAttitudeTreeFromBuffer
//********** Description: **************
//restore attitude tree from the given buffer
//********** Parameters:  **************
//BYTE *pbBuffer      - buffer to fill
//unsigned short nLen - buffer length
//--------------------------------------------------------------
Attitude *BBECALL RestoreAttitudeTreeFromBuffer(BYTE *pbBuffer,
    unsigned short nLen)
{
    Attitude NewAtt, *TreeRoot = NULL;
    int nCopied;

    for(nCopied = 0; nCopied < nLen; )
    {
        memcpy(&(NewAtt.person_id),pbBuffer + nCopied,sizeof(ID));
        nCopied += sizeof(ID);
        NewAtt.Real = *(pbBuffer + nCopied);
        nCopied++;
        NewAtt.Seemed = *(pbBuffer + nCopied);
        nCopied++;
        if(NewAtt.person_id)
        {
            AddBothAttitudes(NewAtt.person_id, NewAtt.Real,
                    NewAtt.Seemed, &TreeRoot );
        }
    }
    return TreeRoot;
}

//***************************************************************************
//Attitudes2String
//********** Description: **************
//compose a string containing attitudes for debugging purposes
//********** Parameters:  **************
//Attitude *attRoot - attitude tree root
//char *szBuf       - buffer to fill
//--------------------------------------------------------------
void BBECALL Attitudes2String(Attitude *attRoot, char *szBuf)
{
    char szAux[20];
    if(attRoot == NULL)
        return;

    if(attRoot->LSon)
        Attitudes2String(attRoot->LSon,szBuf);
    sprintf(szAux,"att to %d=%d,",attRoot->person_id,attRoot->Real);
    strcat(szBuf,szAux);
    if(attRoot->RSon)
        Attitudes2String(attRoot->RSon,szBuf);
}

//***************************************************************************
//ForDiff
//********** Description: **************
//return difference in foreignness attribute (once used to be two-coordinate)
//********** Parameters:  **************
//percentage For1 - foreignness 1
//percentage For2 - foreignness 2
//-------------------------------------------
percentage BBECALL ForDiff(percentage For1, percentage For2)
{
	return (percentage)(ABS(For1 - For2));
}

//***************************************************************************
//Random
//********** Description: **************
//return a random number in range {LoLimit, HiLimit}
//********** Parameters:  **************
//int LoLimit - low limit value
//int HiLimit - high limit value
//--------------------------------------------------------------
int BBECALL Random(int LoLimit, int HiLimit)
{
    srand(time(0)); //randomize();
    //return (LoLimit + random( HiLimit + 1 ));
	return (rand() % (HiLimit - LoLimit + 1));
}

//***************************************************************************
//CheckCriteria
//********** Description: **************
//checks whether the given Core matches the given criterion
//********** Parameters:  **************
//GoalDefNodeP gpCrit - criterion node
//Core *bsCmp         - pointer to Core to check
//Core *bsRel         - pointer to a relative Core, if comparison is relative
//percentage *pAtt    - array of attitudes
//--------------------------------------------------------------
BOOL BBECALL CheckCriteria(GoalDefNodeP gpCrit, Core *bsCmp, Core *bsRel,
        percentage *pAtt)
{
    Core LoLimit,HiLimit,Checked;
    BOOL bRetVal;
    percentage Att2StrObj = ERROR_PERCENTAGE,Att2LastInit = ERROR_PERCENTAGE,
        Att2RefActObj = ERROR_PERCENTAGE,Att2UserDef = ERROR_PERCENTAGE,
        AttByStrObj = ERROR_PERCENTAGE,AttByLastInit = ERROR_PERCENTAGE,
        AttByRefActObj = ERROR_PERCENTAGE;
    percentage LoAtt2StrObj,LoAttByStrObj,LoAtt2LastInit,LoAttByLastInit,
        LoAtt2RefActObj,LoAttByRefActObj,LoAtt2UserDef;

    LoLimit = gpCrit->LoReqs;
    HiLimit = gpCrit->HiReqs;
    Checked = *bsCmp;

    if(pAtt)
    {
        Att2StrObj = pAtt[CRIT_ATT2STROBJ - CRIT_ATT_OFFSET];
        Att2LastInit = pAtt[CRIT_ATT2LASTINIT - CRIT_ATT_OFFSET];
        Att2RefActObj = pAtt[CRIT_ATT2REFACTOBJ - CRIT_ATT_OFFSET];
        Att2UserDef = pAtt[CRIT_ATT_BY_REFACTOBJ - CRIT_ATT_OFFSET+1];
        AttByStrObj = pAtt[CRIT_ATT_BY_STROBJ - CRIT_ATT_OFFSET];
        AttByLastInit = pAtt[CRIT_ATT_BY_LASTINIT - CRIT_ATT_OFFSET];
        AttByRefActObj = pAtt[CRIT_ATT_BY_REFACTOBJ - CRIT_ATT_OFFSET];
    }

    if(bsRel != NULL)
    {
        Checked.Wickedness -= bsRel->Wickedness;
        if(Checked.Wickedness < -EXTREME_PER_VAL || Checked.Wickedness > EXTREME_PER_VAL)
            Checked.Wickedness = EXTREME_PER_VAL;
        Checked.Anarchy -= bsRel->Anarchy;
        if(Checked.Anarchy < -EXTREME_PER_VAL || Checked.Anarchy > EXTREME_PER_VAL)
            Checked.Anarchy = EXTREME_PER_VAL;
        Checked.Meanness[0] -= bsRel->Meanness[0];
        if(Checked.Meanness[0] < -EXTREME_PER_VAL || Checked.Meanness[0] > EXTREME_PER_VAL)
            Checked.Meanness[0] = EXTREME_PER_VAL;
        Checked.Wealth[0] -= bsRel->Wealth[0];
        if(Checked.Wealth[0] < -EXTREME_PER_VAL || Checked.Wealth[0] > EXTREME_PER_VAL)
            Checked.Wealth[0] = EXTREME_PER_VAL;
        Checked.Beauty -= bsRel->Beauty;
        if(Checked.Beauty < -EXTREME_PER_VAL || Checked.Beauty > EXTREME_PER_VAL)
            Checked.Beauty = EXTREME_PER_VAL;
        Checked.Intelligence[0] -= bsRel->Intelligence[0];
        if(Checked.Intelligence[0] < -EXTREME_PER_VAL || Checked.Intelligence[0] > EXTREME_PER_VAL)
            Checked.Intelligence[0] = EXTREME_PER_VAL;
        Checked.Intelligence[1] -= bsRel->Intelligence[1];
        if(Checked.Intelligence[1] < -EXTREME_PER_VAL || Checked.Intelligence[1] > EXTREME_PER_VAL)
            Checked.Intelligence[1] = EXTREME_PER_VAL;
        Checked.Courage -= bsRel->Courage;
        if(Checked.Courage < -EXTREME_PER_VAL || Checked.Courage > EXTREME_PER_VAL)
            Checked.Courage = EXTREME_PER_VAL;
        Checked.UserDefined[0] -= bsRel->UserDefined[0];
        Checked.UserDefined[1] -= bsRel->UserDefined[1];
        Checked.UserDefined[2] -= bsRel->UserDefined[2];
    }
  //forgive me the absense of indentation here -
  // I don't want to go around the earth

	if (
        (Checked.Wickedness >= LoLimit.Wickedness && Checked.Wickedness <= HiLimit.Wickedness || HiLimit.Wickedness > EXTREME_PER_VAL || LoLimit.Wickedness < -EXTREME_PER_VAL)
	&& (Checked.Anarchy >= LoLimit.Anarchy && Checked.Anarchy <= HiLimit.Anarchy || HiLimit.Anarchy > EXTREME_PER_VAL || LoLimit.Anarchy < -EXTREME_PER_VAL)
    //these two are, in fact, attitudes
    && (Checked.InitialAttitude >= LoLimit.InitialAttitude && Checked.InitialAttitude <= HiLimit.InitialAttitude || HiLimit.InitialAttitude > EXTREME_PER_VAL || LoLimit.InitialAttitude < -EXTREME_PER_VAL)
    && (Checked.AttitudeChangeUnit >= LoLimit.AttitudeChangeUnit && Checked.AttitudeChangeUnit <= HiLimit.AttitudeChangeUnit || HiLimit.AttitudeChangeUnit > EXTREME_PER_VAL || LoLimit.AttitudeChangeUnit < -EXTREME_PER_VAL)
    && (Checked.Meanness[0] >= LoLimit.Meanness[0] && Checked.Meanness[0] <= HiLimit.Meanness[0] || HiLimit.Meanness[0] > EXTREME_PER_VAL || LoLimit.Meanness[0] < -EXTREME_PER_VAL)
    && (Checked.Wealth[0] >= LoLimit.Wealth[0] && Checked.Wealth[0] <= HiLimit.Wealth[0] || HiLimit.Wealth[0] > EXTREME_PER_VAL || LoLimit.Wealth[0] < -EXTREME_PER_VAL)
    && (Checked.Beauty >= LoLimit.Beauty && Checked.Beauty <= HiLimit.Beauty || HiLimit.Beauty > EXTREME_PER_VAL || LoLimit.Beauty < -EXTREME_PER_VAL)
    && (Checked.Foreignness >= LoLimit.Foreignness && Checked.Foreignness <= HiLimit.Foreignness || HiLimit.Foreignness > EXTREME_PER_VAL || LoLimit.Foreignness < -EXTREME_PER_VAL)
    && (Checked.Intelligence[0] >= LoLimit.Intelligence[0] && Checked.Intelligence[0] <= HiLimit.Intelligence[0] || HiLimit.Intelligence[0] > EXTREME_PER_VAL || LoLimit.Intelligence[0] < -EXTREME_PER_VAL)
    && (Checked.Intelligence[1] >= LoLimit.Intelligence[1] && Checked.Intelligence[1] <= HiLimit.Intelligence[1] || HiLimit.Intelligence[1] > EXTREME_PER_VAL || LoLimit.Intelligence[1] < -EXTREME_PER_VAL)
    && (Checked.Courage >= LoLimit.Courage && Checked.Courage <= HiLimit.Courage || HiLimit.Courage > EXTREME_PER_VAL || LoLimit.Courage < -EXTREME_PER_VAL)
    && (LoLimit.CurrentEnvironment == 0 || Checked.CurrentEnvironment >= LoLimit.CurrentEnvironment && Checked.CurrentEnvironment <= HiLimit.CurrentEnvironment)
    && (Checked.Dead >= LoLimit.Dead && Checked.Dead <= HiLimit.Dead)
    && (Checked.UserDefined[0] >= LoLimit.UserDefined[0] && Checked.UserDefined[0] <= HiLimit.UserDefined[0] || HiLimit.UserDefined[0] > 32000 || LoLimit.UserDefined[0] < -32000)
    && (Checked.UserDefined[1] >= LoLimit.UserDefined[1] && Checked.UserDefined[0] <= HiLimit.UserDefined[1] || HiLimit.UserDefined[1] > 32000 || LoLimit.UserDefined[1] < -32000)
    && (Checked.UserDefined[2] >= LoLimit.UserDefined[1] && Checked.UserDefined[0] <= HiLimit.UserDefined[2] || HiLimit.UserDefined[2] > 32000 || LoLimit.UserDefined[2] < -32000)
        )
    {
    	bRetVal = TRUE;
    }
    else
    {
        return FALSE;
    }

    LoAtt2StrObj = GetAttitude(CRIT_ATT2STROBJ,LoLimit.attPersonal);
    if(LoAtt2StrObj != ERROR_PERCENTAGE)
    {
        if(Att2StrObj < LoAtt2StrObj
                ||
                Att2StrObj > GetAttitude(CRIT_ATT2STROBJ,HiLimit.attPersonal))
        {
            return FALSE;
        }
    }

    LoAttByStrObj = GetAttitude(CRIT_ATT_BY_STROBJ,LoLimit.attPersonal);
    if(LoAttByStrObj != ERROR_PERCENTAGE)
        if(AttByStrObj < LoAttByStrObj
                ||
                AttByStrObj > GetAttitude(CRIT_ATT_BY_STROBJ,HiLimit.attPersonal))
            return FALSE;

    LoAtt2LastInit = GetAttitude(CRIT_ATT2LASTINIT,LoLimit.attPersonal);
    if(LoAtt2LastInit != ERROR_PERCENTAGE)
    {
        if(Att2LastInit < LoAtt2LastInit
                ||
                Att2LastInit > GetAttitude(CRIT_ATT2LASTINIT,HiLimit.attPersonal))
        {
            return FALSE;
        }

    }
    LoAttByLastInit = GetAttitude(CRIT_ATT_BY_LASTINIT,LoLimit.attPersonal);
    if(LoAttByLastInit != ERROR_PERCENTAGE)
        if(AttByLastInit < LoAttByLastInit
                ||
                AttByLastInit > GetAttitude(CRIT_ATT_BY_LASTINIT,HiLimit.attPersonal))
            return FALSE;

    LoAtt2RefActObj = GetAttitude(CRIT_ATT2REFACTOBJ,LoLimit.attPersonal);
    if(LoAtt2RefActObj != ERROR_PERCENTAGE)
    {
        if(Att2RefActObj < LoAtt2RefActObj
                ||
                Att2RefActObj > GetAttitude(CRIT_ATT2REFACTOBJ,HiLimit.attPersonal))
        {
            return FALSE;
        }
    }

    LoAttByRefActObj = GetAttitude(CRIT_ATT_BY_REFACTOBJ,LoLimit.attPersonal);
    if(LoAttByRefActObj != ERROR_PERCENTAGE)
        if(AttByRefActObj < LoAttByRefActObj
                ||
                AttByRefActObj > GetAttitude(CRIT_ATT_BY_REFACTOBJ,HiLimit.attPersonal))
            return FALSE;

    LoAtt2UserDef = GetAttitude(gpCrit->UserDefAttID,LoLimit.attPersonal);
    if(LoAtt2UserDef != ERROR_PERCENTAGE)
    {
        if(Att2UserDef < LoAtt2UserDef
                ||
                Att2UserDef > GetAttitude(gpCrit->UserDefAttID,HiLimit.attPersonal))
        {
            return FALSE;
        }
    }

    switch(gpCrit->IdFlag1)
    {
        case FL1_LASTINIT:  //last initiated action #... (on bsRel)
            //if comparison is relative, check if it's the same initiator
            if(bsRel != NULL && bsRel->LastAccessedBy != NULL)
                if(Checked.attId != bsRel->LastAccessedBy->attId
                     && Checked.LastCommittedAction != 0)
                    return FALSE;
            if(Checked.LastCommittedAction != gpCrit->IdFlag2)
                return FALSE;
            break;
        case FL1_LASTOBJ :  //objective of (bsRel's) last action #...
            if(bsRel != NULL && bsRel->LastAccessedBy != NULL)
                if(bsRel->attId != Checked.LastAccessedBy->attId
                     && Checked.LastTargettedInAction != 0)
                    return FALSE;
            if(Checked.LastTargettedInAction != gpCrit->IdFlag2)
                return FALSE;
            break;
        default:
            break;
    }
	return bRetVal;
}

//***************************************************************************
//CheckItemCriteria
//********** Description: **************
//checks whether the given item matches the given criterion (analogous to
//CheckCriteria)
//********** Parameters:  **************
//GoalDefNodeP gpCrit - criterion node
//ItemScores *isChk   - pointer to the item to check
//ItemScores *isRel   - pointer to a relative item, if comparison is relative
//--------------------------------------------------------------
BOOL BBECALL CheckItemCriteria(GoalDefNodeP gpCrit,ItemScores *isChk,ItemScores *isRel)
{
    Core LoLimit,HiLimit;
    ItemScores Checked;

    LoLimit = gpCrit->LoReqs;
    HiLimit = gpCrit->HiReqs;
    Checked = *isChk;

    if(isRel != NULL)
    {
        Checked.Wickedness -= isRel->Wickedness;
        if(Checked.Wickedness < -EXTREME_PER_VAL || Checked.Wickedness > EXTREME_PER_VAL)
            Checked.Wickedness = EXTREME_PER_VAL;
        Checked.Anarchy -= isRel->Anarchy;
        if(Checked.Anarchy < -EXTREME_PER_VAL || Checked.Anarchy > EXTREME_PER_VAL)
            Checked.Anarchy = EXTREME_PER_VAL;
        Checked.Meanness -= isRel->Meanness;
        if(Checked.Meanness < -EXTREME_PER_VAL || Checked.Meanness > EXTREME_PER_VAL)
            Checked.Meanness = EXTREME_PER_VAL;
        Checked.Wealth -= isRel->Wealth;
        if(Checked.Wealth < -EXTREME_PER_VAL || Checked.Wealth > EXTREME_PER_VAL)
            Checked.Wealth = EXTREME_PER_VAL;
        Checked.Beauty -= isRel->Beauty;
        if(Checked.Beauty < -EXTREME_PER_VAL || Checked.Beauty > EXTREME_PER_VAL)
            Checked.Beauty = EXTREME_PER_VAL;
        Checked.Personality -= isRel->Personality;
        if(Checked.Personality < -EXTREME_PER_VAL || Checked.Personality > EXTREME_PER_VAL)
            Checked.Personality = EXTREME_PER_VAL;
        Checked.UserDefined[0] -= isRel->UserDefined[0];
        Checked.UserDefined[1] -= isRel->UserDefined[1];
        Checked.UserDefined[2] -= isRel->UserDefined[2];
    }


	if (
        (Checked.Wickedness >= LoLimit.Wickedness && Checked.Wickedness <= HiLimit.Wickedness || HiLimit.Wickedness > EXTREME_PER_VAL || LoLimit.Wickedness < -EXTREME_PER_VAL)
	&& (Checked.Anarchy >= LoLimit.Anarchy && Checked.Anarchy <= HiLimit.Anarchy || HiLimit.Anarchy > EXTREME_PER_VAL || LoLimit.Anarchy < -EXTREME_PER_VAL)
    && (Checked.Meanness >= LoLimit.Meanness[0] && Checked.Meanness <= HiLimit.Meanness[0] || HiLimit.Meanness[0] > EXTREME_PER_VAL || LoLimit.Meanness[0] < -EXTREME_PER_VAL)
    && (Checked.Wealth >= LoLimit.Wealth[0] &&
            (Checked.Wealth <= HiLimit.Wealth[0]
                || ((Checked.Wealth > HiLimit.Wealth[0]) && Checked.CanBeDivided)
            )
                || HiLimit.Wealth[0] > EXTREME_PER_VAL || LoLimit.Wealth[0] < -EXTREME_PER_VAL)
    && (Checked.Beauty >= LoLimit.Beauty && Checked.Beauty <= HiLimit.Beauty || HiLimit.Beauty > EXTREME_PER_VAL || LoLimit.Beauty < -EXTREME_PER_VAL)
    && (Checked.Personality >= LoLimit.Intelligence[1] && Checked.Personality <= HiLimit.Intelligence[1] || HiLimit.Intelligence[0] > EXTREME_PER_VAL || LoLimit.Intelligence[1] < -EXTREME_PER_VAL)
    && (Checked.UserDefined[0] >= LoLimit.UserDefined[0] && Checked.UserDefined[0] <= HiLimit.UserDefined[0] || HiLimit.UserDefined[0] > 32000 || LoLimit.UserDefined[0] < -32000)
    && (Checked.UserDefined[1] >= LoLimit.UserDefined[1] && Checked.UserDefined[0] <= HiLimit.UserDefined[1] || HiLimit.UserDefined[1] > 32000 || LoLimit.UserDefined[1] < -32000)
    && (Checked.UserDefined[2] >= LoLimit.UserDefined[1] && Checked.UserDefined[0] <= HiLimit.UserDefined[2] || HiLimit.UserDefined[2] > 32000 || LoLimit.UserDefined[2] < -32000)
        )
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

//***************************************************************************
//DecodeShort
//********** Description: **************
//reverse unsigned short value
//********** Parameters:  **************
//unsigned short argEncoded - encoded value
//--------------------------------------------------------------
unsigned short BBECALL DecodeShort(unsigned short argEncoded)
{
    return (unsigned short)(argEncoded%256*256+argEncoded/256);
}

//***************************************************************************
//SetCoreDefaults
//********** Description: **************
//set Core minimal defaults to avoid strange effects
//********** Parameters:  **************
//Core& bs - reference to the Core to set value to
//--------------------------------------------------------------
void BBECALL SetCoreDefaults(Core& bs)
{
    if(!bs.Intelligence[0])
        if(bs.Intelligence[1])  bs.Intelligence[0] = bs.Intelligence[1];
        //else                    bs.Intelligence[0] = 1;
    if(!bs.Intelligence[1]) bs.Intelligence[1] = bs.Intelligence[0];

    if(!bs.Wealth[0])
        if(bs.Wealth[1])    bs.Wealth[0] = bs.Wealth[1];
        //else                bs.Wealth[0] = 1;
    if(!bs.Wealth[1])   bs.Wealth[1] = bs.Wealth[0];

    if(!bs.Meanness[0])
        if(bs.Meanness[1])  bs.Meanness[0] = bs.Meanness[1];
        //else                bs.Meanness[0] = 1;
    if(!bs.Meanness[1]) bs.Meanness[1] = bs.Meanness[0];
}

//***************************************************************************
//CustomNew
//********** Description: **************
//custom "new" handler
//********** Parameters:  **************
//none
//--------------------------------------------------------------
void BBECALL CustomNew()
{
    Stop("*** Memory allocation failed ****");
}

//***************************************************************************
//GetAttitudeDesc
//********** Description: **************
//return default attitude description
//********** Parameters:  **************
//percentage Att - attitude value
//--------------------------------------------------------------
char *BBECALL GetAttitudeDesc(percentage Att)
{
    if(Att < -80)
        return "hostile";
    else
    if(Att < -50)
        return "angry";
    else
    if(Att < -30)
        return "unfriendly";
    else
    if(Att < 30)
        return "indifferent";
    else
    if(Att < 70)
        return "friendly";
    else
    if(Att < 101)
        return "loving";
    else
        return "***";
}

//***************************************************************************
//OutOfLimits
//********** Description: **************
//check whether Checked wickedness / anarchy is within allowed limits
//********** Parameters:  **************
//percentage Checked  - value to check (typically an Action)
//percentage Original - value to set limits (typically a person)
//--------------------------------------------------------------
percentage BBECALL OutOfLimits(percentage Checked,percentage Original)
{
    short Difference;
    if(Checked == 0)
        return 0;   //action is neutral. Nothing to check
    Difference = (short)(Checked - Original);

    // these strange looking conditions are meant to block
    // situations when an evil person can't commit a minor evil action
    // or a good one is unable to do something that is not "kind enough".
    // However, border is not crossed
    if( (Difference > UNSURPASSED_MORAL_DIFF) && (Checked > 0) )
        return 1;

    if( (Difference < -UNSURPASSED_MORAL_DIFF) && (Checked < 0) )
        return -1;
    return 0;
}

//***************************************************************************
//ScoreVal
//********** Description: **************
//return value to a specified field within Core
//********** Parameters:  **************
//unsigned char score   - index (recommended to use constants)
//Core bs               - Core to use
//unsigned char UseTrue - whether to return true values (not seemed ones)
//--------------------------------------------------------------
percentage BBECALL ScoreVal(unsigned char score, Core bs, unsigned char UseTrue)
{
    switch(score)
    {
        case WICK: return bs.Wickedness;
        case ANAR: return bs.Anarchy;
        case INIT_ATT: return bs.Anarchy;
        case ACU: return bs.AttitudeChangeUnit;
        case SCHANGE: return bs.SuddenChange;
        case LIE_PROB: return bs.LieProbability;
        case MEANNESS: return bs.Meanness[UseTrue];
        case WEALTH:    return bs.Wealth[UseTrue];
        case BEAUTY:    return bs.Beauty;
        case FOREIGN:   return bs.Foreignness;
        case INT    :   return bs.Intelligence[UseTrue];
        case COU    :   return bs.Courage;
    }
    return ERROR_PERCENTAGE;
}

//***************************************************************************
//ItemPersonalEval
//********** Description: **************
//return Agent's attitude to the given item
//********** Parameters:  **************
//Core &bs             - Agent's Core to use
//ItemScores& EvalItem - item to evaluate
//---------------------------------------------------------------------------
percentage BBECALL ItemPersonalEval(Core &bs, ItemScores& EvalItem)
{
	short ResAttitude;
    MindDefNodeP pThisMindset = NULL;

    if(bs.alType > CUSTOM_MINDSET_START)
        pThisMindset = GetMindNode(bs.alType);

    if(pThisMindset != NULL)
    {
        ResAttitude =
            (percentage)((
            (EvalItem.Meanness / bs.Meanness[TRUE])
            * pThisMindset->ItemMeanness/100
            + (EvalItem.Beauty * EvalItem.Influence / AvgBeauty)
            * pThisMindset->ItemBeauty/100
            + (EvalItem.Wealth / bs.Wealth[TRUE])
            * pThisMindset->ItemWealth/100
            + (EvalItem.Personality / bs.Intelligence[1])
            * pThisMindset->ItemIntelligence/100
            ) * bs.AttitudeChangeUnit/1);
    }
    else
    {
        switch (bs.alType){
		case alPureGood:
                  ResAttitude =
                  (0.3 * (EvalItem.Personality / bs.Intelligence[1])
                  + (0.5 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty) )
                  * bs.AttitudeChangeUnit/1;
				break;
		case alLawfulGood:
                 ResAttitude =
                  (0.3 * (EvalItem.Personality / bs.Intelligence[1]) + (0.5 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty) ) * bs.AttitudeChangeUnit/1;
				break;
		case alNeutralGood:
            ResAttitude = (
                  //0.3 * (EvalItem.Wealth / bs.Wealth[1]) +
                  (0.4 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty) ) * bs.AttitudeChangeUnit/1;
				break;
		case alChaoticGood:
            ResAttitude =
                  (-0.1 * (EvalItem.Personality / bs.Intelligence[1]) + 0.3 * (EvalItem.Meanness / bs.Meanness[1])
                   //- 0.1 * (EvalItem.Wealth / bs.Wealth[1])
                   + (0.4 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty) - 0.1 * ForDiff(EvalItem.Foreignness, bs.Foreignness) ) * bs.AttitudeChangeUnit/1;
				break;
		case alLawfulNeutral:
            ResAttitude =
                  (0.1 * (EvalItem.Personality / bs.Intelligence[1])
                  //+ 0.5 * (EvalItem.Wealth / bs.Wealth[1])
                  + (0.4 * EvalItem.Beauty / AvgBeauty * EvalItem.Influence )
                  - 0.2 * ForDiff(EvalItem.Foreignness, bs.Foreignness)
                  ) * bs.AttitudeChangeUnit/1;
				break;
		case alTrueNeutral:
            ResAttitude = (
                  //0.3 * (EvalItem.Wealth / bs.Wealth[1]) +
                  (0.4 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty) ) * bs.AttitudeChangeUnit/1;
				break;
		case alChaoticNeutral:
            ResAttitude =
                  (-0.1 * (EvalItem.Personality / bs.Intelligence[1]) + 0.5 * (EvalItem.Meanness / bs.Meanness[1]) - 0.2 * ForDiff(EvalItem.Foreignness, bs.Foreignness) ) * bs.AttitudeChangeUnit/1;
				break;
		case alLawfulEvil:
            ResAttitude =
                  (0.1 * (EvalItem.Personality / bs.Intelligence[1]) + 0.4 * (EvalItem.Meanness / bs.Meanness[1])
                  //+ 0.5 * (EvalItem.Wealth / bs.Wealth[1])
                  + (0.2 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty) - 0.1 * ForDiff(EvalItem.Foreignness, bs.Foreignness) ) * bs.AttitudeChangeUnit/1;
				break;
		case alNeutralEvil:
            ResAttitude =
                  (4 * (EvalItem.Meanness / bs.Meanness[1])
                  //+ 0.5 * (EvalItem.Wealth / bs.Wealth[1])
                  - 0.2 * ForDiff(EvalItem.Foreignness, bs.Foreignness) )
                  * bs.AttitudeChangeUnit/1;
				break;
		case alChaoticEvil:
            ResAttitude =
                  (0.3 * (EvalItem.Personality / bs.Intelligence[1])
                  + 6 * EvalItem.Meanness / bs.Meanness[1]
                  //+ 0.5 * (EvalItem.Wealth / bs.Wealth[1])
                  //- (0.2 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty)
                  - 0.4 * ForDiff(EvalItem.Foreignness, bs.Foreignness) )
                  * bs.AttitudeChangeUnit/1;
				break;
		case alUltimateEvil:
            ResAttitude =
                  (0.3 * (EvalItem.Personality / bs.Intelligence[1])
                  + 6 * (EvalItem.Meanness / bs.Meanness[1])
                  //+ 0.5 * (EvalItem.Wealth / bs.Wealth[1])
                  - (0.2 * EvalItem.Beauty * EvalItem.Influence / AvgBeauty)
                  - 0.4 * ForDiff(EvalItem.Foreignness, bs.Foreignness) )
                  * bs.AttitudeChangeUnit/1;
				break;
        default:
        	ResAttitude = 0;
	    }
    }
    
    if(ResAttitude < -EXTREME_PER_VAL)
        ResAttitude = -EXTREME_PER_VAL;
    if(ResAttitude > EXTREME_PER_VAL)
        ResAttitude = EXTREME_PER_VAL;
	return (percentage)ResAttitude;
}

//***************************************************************************
//PostError
//********** Description: **************
//update Brainiac error handler
//********** Parameters:  **************
//long nErrorCode - new errorcode
//---------------------------------------------------------------------------
void BBECALL PostError(long nErrorCode)
{
    BEErrorCode = nErrorCode;
}

//***************************************************************************
//LastBEError
//********** Description: **************
//return last Brainiac error string
//********** Parameters:  **************
//none
//---------------------------------------------------------------------------
char *BBECALL LastBEError()
{
    switch(BEErrorCode)
    {
        case 0:
            strncpy(ErrorString,"BBE: Operation completed successfully",
                MAX_ERROR_LEN);
            break;
        case INVALID_PARAM:
            strncpy(ErrorString,"BBE: Invalid parameter(s)",MAX_ERROR_LEN);
            break;
        case INVALID_PROP:
            strncpy(ErrorString,"BBE: NULL pointer property",MAX_ERROR_LEN);
            break;
        case PERSON_DEAD:
            strncpy(ErrorString,"BBE: The person is dead",MAX_ERROR_LEN);
            break;
        case MEM_ALLOC_FAILED:
            strncpy(ErrorString,"BBE: Could not allocate memory",MAX_ERROR_LEN);
            break;
        default:
            strncpy(ErrorString,"BBE: Invalid error identifier",MAX_ERROR_LEN);
    }

    return &(ErrorString[0]);
}

//***************************************************************************
//LastBEErrorCode
//********** Description: **************
//return last Brainiac errorcode
//********** Parameters:  **************
//none
//---------------------------------------------------------------------------
long BBECALL LastBEErrorCode()
{
    return BEErrorCode;
}

//***************************************************************************
//BSFillSaveBuffer
//********** Description: **************
//encode the given Core to the given buffer, replacing pointers with IDs. Number
//of allocated bytes is returned.
//********** Parameters:  **************
//Core ToSave      - Core to save
//BYTE *SaveBuffer - buffer to encode to
//---------------------------------------------------------------------------
unsigned short BBECALL BSFillSaveBuffer(Core ToSave, BYTE *SaveBuffer)
{
    if(ToSave.LastAccessedBy != NULL)
        //replace pointer by ID
        ToSave.LastAccessedBy = (Core*)ToSave.LastAccessedBy->attId;
    memcpy(SaveBuffer,&ToSave,sizeof(Core));
    return (unsigned short)(sizeof(Core)
        + DumpAttitudeTree2Buffer(ToSave.attPersonal,
        SaveBuffer + sizeof(Core)));
}

//***************************************************************************
//BSRestoreFromBufferStep1
//********** Description: **************
//decode the given Core from the given buffer, step 1
//********** Parameters:  **************
//BYTE* SaveBuffer    - buffer containing the saved info
//unsigned short nLen - buffer length
//Core *ToRestore     - Core to restore into
//---------------------------------------------------------------------------
void BBECALL BSRestoreFromBufferStep1(BYTE *SaveBuffer, unsigned short nLen,
        Core *ToRestore)
{
    memset(ToRestore,0,sizeof(Core));
    if(SaveBuffer == NULL)
        return;

    memcpy(ToRestore,SaveBuffer,sizeof(Core));
    if(ToRestore->attPersonal != NULL)
    {
        ToRestore->attPersonal = RestoreAttitudeTreeFromBuffer(
            SaveBuffer + sizeof(Core),
            (unsigned short)(nLen - sizeof(Core)));
    }
}

//***************************************************************************
//BSRestoreFromBufferStep2
//********** Description: **************
//decode the given Core from the given buffer, step 2
//********** Parameters:  **************
//Core **pbspPopulation   - current population
//unsigned short nPopSize - population size
//Core *Restored          - Core to restore into
//---------------------------------------------------------------------------
void BBECALL BSRestoreFromBufferStep2(Core *Restored,
        Core **pbspPopulation, unsigned short nPopSize)
{
    Restored->LastAccessedBy = FindBSAddress((ID)Restored->LastAccessedBy,
        pbspPopulation,nPopSize);
}

//***************************************************************************
//FindBSAddress
//********** Description: **************
//try to locate and return a Core address from the given population for the given ID
//********** Parameters:  **************
//ID idToBeFound          - ID to locate
//Core **pbspPopulation   - current population
//unsigned short nPopSize - population size
//---------------------------------------------------------------------------
Core *BBECALL FindBSAddress(ID idToBeFound,
        Core **pbspPopulation, unsigned short nPopSize)
{
    unsigned short i;

    if(pbspPopulation == NULL)
        return NULL;
    for(i = 0; i < nPopSize; i++)
        if(pbspPopulation[i] != NULL)
            if(pbspPopulation[i]->attId == idToBeFound)
                return pbspPopulation[i];

    return NULL;    //if nothing found
}

//***************************************************************************
//FindItemAddress
//********** Description: **************
//try to locate and return an item address from the given population for the
//given item's and its owner's IDs
//********** Parameters:  **************
//ID ItemID                 - item to locate ID
//ID Owner                  - item's owner ID
//unsigned short nPopSize   - population size
//ItemPtrArr* ipapItems     - all the inventories
//unsigned short *nInvSizes - array of the inventory sizes. The array length is
//                            nPopSize
//---------------------------------------------------------------------------
ItemScores *BBECALL FindItemAddress(ID ItemID,ID Owner,
            unsigned short nPopSize,ItemPtrArr* ipapAllItems,
            unsigned short* nInvSizes)
{
    unsigned short i,j;

    if(ipapAllItems == NULL || nInvSizes == NULL || nPopSize == 0
        || ItemID == 0)
        return NULL;
    for(i = 0; i < nPopSize; i++)
    {
        if(ipapAllItems[i] == NULL)
            continue;
        for(j = 0; j < nInvSizes[i]; j++)
            if(ipapAllItems[i][j] != NULL)
                if(ipapAllItems[i][j]->ItemID == ItemID
                    && ipapAllItems[i][j]->Owner == Owner)
                    return ipapAllItems[i][j];
    }

    return NULL;    //if nothing found
}


//****************************************************************
//twGetModuleDirectory
//********** Description: **************
//get the current directory (ie the directory where the DLL resides)
//********** Parameters:  **************
//none
//---------------------------------------------------------------------------
const char* BBECALL twGetModuleDirectory()
{
	// pathBuffer must be static because it is returned. _MAX_PATH is a Windows constant.
	static char pathBuffer[_MAX_PATH];
    HANDLE hModuleHandle;

	// Get the DLL's path and name
    hModuleHandle = GetModuleHandle(NULL);//GetCurrentProcess();
	if ( GetModuleFileName((HMODULE)hModuleHandle,
            pathBuffer, _MAX_PATH - 1) == 0 )
    {
		return 0;
    }

	// Strip off the DLL name to leave path
	int i;
	for ( i = strlen(pathBuffer) - 1; i > 0; i--)
	{
		if ( pathBuffer[i] == '\\' )
		{
			pathBuffer[i + 1] = 0;//store with the backslash
			break;
		}
	}
	
	// If couldn't strip off the name return error
	if ( i == 0 )
		return 0;

	return pathBuffer;
}

//---------------------------------------------------------------------------

