SBSPSS/Utils/Libs/GLib/objs.c
2000-12-04 14:13:40 +00:00

801 lines
20 KiB
C

/* ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
File: OBJS.C
Notes: Genric Object Server
Author: G Robert Liddon @ The Park
Created: Wednesday 5th April, 1995
Copyright (C) 1995 G Robert Liddon
All rights reserved.
ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ */
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Includes
ÄÄÄÄÄÄÄÄ */
/* Glib
ÄÄÄÄ */
#include "objs.h"
#include "gal.h"
#include "gdebug.h"
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function Prototypes
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_DetachOLFromList(OBJ_LIST **Head,OBJ_LIST *ThisObj);
static void OBJS_AddOLToList(OBJ_LIST **Head,OBJ_LIST *ThisObj);
static void OBJS_DetachFromList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj);
static void OBJS_AddToList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj);
static void SortList(OBJ_LIST *OL);
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Vars
ÄÄÄÄ */
int ObjsAlloced; /* Number of currently active objs */
OBJ_LIST * ListOfObjLists; /* Head of the list of print Qs */
BOOL AddVels; /* Should vels be auto added or not */
U32 MemId;
void (*ProcessEpilog)(void); /* Called after processobj */
void (*ProcessProlog)(void); /* Called after processobj */
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_OpenModule(U32 MemType)
Purpose: Initialise the object module for use.
Params: MyMaxObjs = Max objs to alloc for
MemType = GAL memtype to alloc in
Returns: TRUE if opened succesfuly
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_OpenModule(U32 MemType)
{
MemId=MemType;
ObjsAlloced=0;
ListOfObjLists=NULL;
AddVels=TRUE;
ProcessEpilog=NULL;
ProcessProlog=NULL;
return TRUE;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: BOOL OBJS_CloseModule(void)
Purpose: Closes the active obj module
Returns: TRUE if closed succesfuly
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_CloseModule(void)
{
OBJS_DestroyAllObjs();
return TRUE;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_AddDisplayList(OBJ_LIST *OL)
Purpose: Add a display list
Params: OL -> Object List to add
Returns: -> Created object if succesfull
NULL if not
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_AddDisplayList(OBJ_LIST *OL)
{
OBJS_AddOLToList(&ListOfObjLists,OL);
OL->Head=NULL;
OL->Visible=TRUE;
OL->SortCompare=NULL;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: OBJ_STRUCT *OBJS_MakeObj(const OBJ_TYPE_INFO *OTI,OBJ_LIST *OL,void *Ptr)
Purpose: Make an object
Params: OTI -> Obj type info
OL -> Object List to add to
Ptr -> Instance specefic info
Returns: -> Created object if succesfull
NULL if not
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
OBJ_STRUCT *OBJS_CreateObjMulti(const OBJ_TYPE_INFO *OTI,OBJ_LIST *OL,GAL_STRUCT * G,void *Ptr)
{
UINT TotalMem;
TotalMem=GAL_ProcessMultiStruct(G,MemId);
return(OBJS_CreateObj(OTI,OL,(int)TotalMem,Ptr));
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: OBJ_STRUCT *OBJS_MakeObj(const OBJ_TYPE_INFO *OTI,OBJ_LIST *OL,void *Ptr)
Purpose: Make an object
Params: OTI -> Obj type info
OL -> Object List to add to
Ptr -> Instance specefic info
Returns: -> Created object if succesfull
NULL if not
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
OBJ_STRUCT *OBJS_CreateObj(const OBJ_TYPE_INFO *OTI,OBJ_LIST *OL,int DataSize,void *Ptr)
{
MHANDLE ObjHandle;
int SizeOfObjstruct;
int SizeOfData;
OBJ_STRUCT * ThisObj;
SizeOfObjstruct=GAL_AlignSizeToType(sizeof(OBJ_STRUCT),MemId);
if (SizeOfObjstruct==-1)
return(NULL);
SizeOfData=GAL_AlignSizeToType((U32)DataSize,MemId);
if (SizeOfData==-1)
return(NULL);
ObjHandle=GAL_Alloc((U32)(SizeOfObjstruct+SizeOfData),MemId,"OBJ");
if (ObjHandle==NULL_HANDLE)
return(NULL);
ThisObj=GAL_Lock(ObjHandle);
if (ThisObj)
{
OBJS_AddToList(&OL->Head,ThisObj);
ThisObj->MemHandle=ObjHandle;
ThisObj->Data=(void *)((U32)ThisObj + SizeOfObjstruct);
ThisObj->OTI=OTI;
ThisObj->OL=OL;
ThisObj->ID=0;
ThisObj->XVel=0;
ThisObj->YVel=0;
ThisObj->ZVel=0;
if (ThisObj->OTI->Constructor)
ThisObj->OTI->Constructor(ThisObj,Ptr);
ObjsAlloced++;
}
return ThisObj;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_ProcessObjsEpilogue(void (*Func)(void))
Purpose: Add a call back that's executed after OBJS_ProcessObjs
Params: Func -> Function
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_ProcessObjsEpilogue(void (*Func)(void))
{
ProcessEpilog=Func;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_ProcessObjsPrologue(void (*Func)(void))
Purpose: Add a call back that's executed before OBJS_ProcessObjs
Params: Func -> Function
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_ProcessObjsPrologue(void (*Func)(void))
{
ProcessProlog=Func;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_DetachFromList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj)
Purpose: Take an object from an obj list
Params: Head -> Head ptr of list
ThisObj -> Obj to add
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
static void OBJS_DetachFromList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj)
{
if (ThisObj->Prev)
ThisObj->Prev->Next=ThisObj->Next;
else
*Head=ThisObj->Next;
if (ThisObj->Next)
ThisObj->Next->Prev=ThisObj->Prev;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_AddToList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj)
Purpose: Add an object to a obj list
Params: Head -> Head ptr of list
ThisObj -> Obj to add
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
static void OBJS_AddToList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj)
{
ThisObj->Prev=NULL;
if ((ThisObj->Next=*Head))
ThisObj->Next->Prev=ThisObj;
*Head=ThisObj;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_DetachFromList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj)
Purpose: Take an object from an obj list
Params: Head -> Head ptr of list
ThisObj -> Obj to add
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_DetachOLFromList(OBJ_LIST **Head,OBJ_LIST *ThisObj)
{
if (ThisObj->Prev)
ThisObj->Prev->Next=ThisObj->Next;
else
*Head=ThisObj->Next;
if (ThisObj->Next)
ThisObj->Next->Prev=ThisObj->Prev;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_AddToList(OBJ_STRUCT **Head,OBJ_STRUCT *ThisObj)
Purpose: Add an object to a obj list
Params: Head -> Head ptr of list
ThisObj -> Obj to add
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
static void OBJS_AddOLToList(OBJ_LIST **Head,OBJ_LIST *ThisObj)
{
ThisObj->Prev=NULL;
if ((ThisObj->Next=*Head))
ThisObj->Next->Prev=ThisObj;
*Head=ThisObj;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Change this Object's Print List
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_ChangeDisplayList(OBJ_STRUCT *O,OBJ_LIST *NewList)
{
if (NewList != O->OL)
{
OBJS_DetachFromList(&O->OL->Head,O);
OBJS_AddToList(&NewList->Head,O);
O->OL=NewList;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_ProcessObjs(void)
Purpose: Print the display lists
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_ProcessObjs(void)
{
OBJ_LIST *ThisList;
if (ProcessProlog)
ProcessProlog();
ThisList=ListOfObjLists;
while (ThisList)
{
if (ThisList->Visible)
{
{
OBJ_STRUCT *ObjList;
SortList(ThisList);
ObjList=ThisList->Head;
while (ObjList)
{
if (AddVels)
{
ObjList->XPos+=ObjList->XVel;
ObjList->YPos+=ObjList->YVel;
ObjList->ZPos+=ObjList->ZVel;
}
if (ObjList->OTI->Printer)
ObjList->OTI->Printer(ObjList,ThisList);
ObjList=ObjList->Next;
}
}
}
ThisList=ThisList->Next;
}
if (ProcessEpilog)
ProcessEpilog();
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_ProcessObjs(void)
Purpose: Print the display lists
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_ObjsVelAddOnly(void)
{
OBJ_LIST *ThisList;
ThisList=ListOfObjLists;
while (ThisList)
{
if (ThisList->Visible)
{
{
OBJ_STRUCT *ObjList;
SortList(ThisList);
ObjList=ThisList->Head;
while (ObjList)
{
if (AddVels)
{
ObjList->XPos+=ObjList->XVel;
ObjList->YPos+=ObjList->YVel;
ObjList->ZPos+=ObjList->ZVel;
}
ObjList=ObjList->Next;
}
}
}
ThisList=ThisList->Next;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_DestroyAllObjs(void)
Purpose: Delete all objects in all lists
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_DestroyAllObjs(void)
{
OBJ_LIST *ThisList;
ThisList=ListOfObjLists;
while (ThisList)
{
OBJS_DestroyListObjs(ThisList);
ThisList=ThisList->Next;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_DestroyListObjs(OBJ_LIST *OL)
Purpose: Destroy all the objs in a list if list is killable
Params: OL -> List
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_DestroyListObjs(OBJ_LIST *OL)
{
if (OL->Killable)
{
OBJ_STRUCT *O;
O=OL->Head;
while (O)
O=OBJS_DestroyObj(O);
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_DestroyAllObjsOfAType(U32 Type,U32 AndMask)
Purpose: Go through all display lists and destroy objs
of a certain type.
if (O->ID&AndMask)==Type then obj is destroyed
Params: Type = Type of objs to destroy
AndMask = And maks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_DestroyAllObjsOfAType(U32 Type,U32 AndMask)
{
OBJ_LIST *ThisList;
ThisList=ListOfObjLists;
while (ThisList)
{
OBJS_DestroyListObjsOfAType(ThisList,Type,AndMask);
ThisList=ThisList->Next;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_DestroyListObjsOfAType(OBJ_LIST *OL,U32 Type,U32 AndMask)
Purpose: Go through a single display list and destroy objs
of a certain type.
if (O->ID&AndMask)==Type then obj is destroyed
Params: Type = Type of objs to destroy
AndMask = And maks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_DestroyListObjsOfAType(OBJ_LIST *OL,U32 Type,U32 AndMask)
{
OBJ_STRUCT *O;
O=OL->Head;
while (O)
{
OBJ_STRUCT * NextO;
NextO=O->Next;
if (((O->ID)&AndMask)==Type)
OBJS_DestroyObj(O);
O=NextO;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: OBJ_STRUCT *OBJS_DestroyObj(OBJ_STRUCT *O)
Purpose: Destroy an object
Params: O -> Obj to destroy
Returns: -> to what was next in list
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
OBJ_STRUCT *OBJS_DestroyObj(OBJ_STRUCT *O)
{
MHANDLE ObjHandle;
OBJ_STRUCT * RetObj;
BOOL GalRet;
ObjHandle=O->MemHandle;
RetObj=O->Next;
if (O->OTI->Destructor)
O->OTI->Destructor(O);
OBJS_DetachFromList(&O->OL->Head,O);
O->Next=NULL; /* Handy for debugging */
O->Prev=NULL;
GalRet=GAL_Free(ObjHandle);
ASSERT(GalRet);
ObjsAlloced--;
return RetObj;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_IterateAllObjs(U32 Type,U32 AndMask,void (*CallBack)(OBJ_STRUCT *O))
Purpose: Go through all display lists and do a callback for objs
of a certain type.
if (O->ID&AndMask)==Type then obj is callbacked
Params: Type = Type of objs to callback
AndMask = And maks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_IterateAllObjs(U32 Type,U32 AndMask,void (*CallBack)(OBJ_STRUCT *O))
{
OBJ_LIST *ThisList;
ThisList=ListOfObjLists;
while (ThisList)
{
OBJS_IterateListObjs(ThisList,Type,AndMask,CallBack);
ThisList=ThisList->Next;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_IterateListObjs(OBJ_LIST *OL,U32 Type,U32 AndMask,void (*CallBack)(OBJ_STRUCT *O))
Purpose: Go through a single display list and do a callback for objs
of a certain type.
if (O->ID&AndMask)==Type then obj is callbacked
Params: Type = Type of objs to callback
AndMask = And maks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_IterateListObjs(OBJ_LIST *OL,U32 Type,U32 AndMask,void (*CallBack)(OBJ_STRUCT *O))
{
OBJ_STRUCT *O;
O=OL->Head;
while (O)
{
OBJ_STRUCT * NextO;
NextO=O->Next;
if (((O->ID)&AndMask)==Type)
CallBack(O);
O=NextO;
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Set the World's XY
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_SetListXY(OBJ_LIST *OL,S32 X,S32 Y)
{
OBJS_SetListX(OL,X);
OBJS_SetListY(OL,Y);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Set the World's X
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_SetListX(OBJ_LIST *OL,S32 X)
{
OL->X=X;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Set the World's X
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_SetListY(OBJ_LIST *OL,S32 Y)
{
OL->Y=Y;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Make a Priority level of sprites undestroyable
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_MakeListImmortal(OBJ_LIST *OL)
{
OL->Killable=FALSE;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Make a Priority level of sprites Destroyable
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_MakeListMortal(OBJ_LIST *OL)
{
OL->Killable=TRUE;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void MKOBJS_NoVels(void)
Purpose: Say no vels to be addes
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_NoAddVels(void)
{
BOOL OldVels;
OldVels=AddVels;
AddVels=FALSE;
return(OldVels);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void MKOBJS_AddVels(void)
Purpose: Say vels to be addes
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_AddVels(void)
{
BOOL OldVels;
OldVels=AddVels;
AddVels=TRUE;
return(OldVels);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_MakeListInvisible(OBJ_LIST *OL)
Purpose: Mark this list as invisble
Params: OL - > List to mark
Returns: Previous visible / invisible state of list
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_MakeListInvisible(OBJ_LIST *OL)
{
BOOL OldState;
OldState=OL->Visible;
OL->Visible=FALSE;
return(OldState);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_MakeListInvisible(OBJ_LIST *OL)
Purpose: Mark this list as visble
Params: OL - > List to mark
Returns: Previous visible / invisible state of list
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_MakeListVisible(OBJ_LIST *OL)
{
BOOL OldState;
OldState=OL->Visible;
OL->Visible=TRUE;
return(OldState);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Make a Priority level of sprites Invisible
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*/
BOOL OBJS_GetVelState(void)
{
return AddVels;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: BOOL OBJS_SetVelState(BOOL NewState)
Purpose: Set wether to add vels
Params: Newstate =
Returns: Previous addvel state of list
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
BOOL OBJS_SetVelState(BOOL NewState)
{
BOOL OldState;
OldState=AddVels;
AddVels=NewState;
return(OldState);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: void OBJS_SetSortCompare(OBJ_LIST *OL,void (*CompRout)(OBJ_STRUCT *O1,OBJ_STRUCT *O1))
Purpose: Set the call back used in the sort routine
Params: OL -> List to set sort routine for
CompRout -> Function to do the compare
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
void OBJS_SetSortCompare(OBJ_LIST *OL,BOOL (*CompRout)(OBJ_STRUCT *O1,OBJ_STRUCT *O2))
{
OL->SortCompare=CompRout;
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: int OBJS_GetWidth(OBJ_STRUCT *O)
Purpose: Get an objs width
Params: O -> Obj 2 get width off
Returns: Width, zero if no width routine
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
int OBJS_GetWidth(OBJ_STRUCT *O)
{
if (O->OTI->GetWidth)
return(O->OTI->GetWidth(O));
else
return(0);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: int OBJS_GetWidth(OBJ_STRUCT *O)
Purpose: Get an objs width
Params: O -> Obj 2 get width off
Returns: Width, zero if no width routine
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
int OBJS_GetHeight(OBJ_STRUCT *O)
{
if (O->OTI->GetHeight)
return(O->OTI->GetHeight(O));
else
return(0);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: int OBJS_GetXOff(OBJ_STRUCT *O)
Purpose: Get an objs X offset
Params: O -> Obj 2 get width off
Returns: Width, zero if no width routine
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
int OBJS_GetXOff(OBJ_STRUCT *O)
{
if (O->OTI->GetXOff)
return(O->OTI->GetXOff(O));
else
return(0);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: int OBJS_GetYOff(OBJ_STRUCT *O)
Purpose: Get an objs X offset
Params: O -> Obj 2 get width off
Returns: Width, zero if no width routine
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
int OBJS_GetYOff(OBJ_STRUCT *O)
{
if (O->OTI->GetYOff)
return(O->OTI->GetYOff(O));
else
return(0);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: int OBJS_GetYOff(OBJ_STRUCT *O)
Purpose: Get an objs X offset
Params: O -> Obj 2 get width off
Returns: Width, zero if no width routine
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
int OBJS_GetPal(OBJ_STRUCT *O)
{
if (O->OTI->GetPal)
return(O->OTI->GetPal(O));
else
return(0);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: static void SortList(OBJ_LIST *OL)
Purpose: Sort this list
Params: OL -> List to sort
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
static void SortList(OBJ_LIST *OL)
{
if (OL->SortCompare && OL->Head && OL->Head->Next)
{
BOOL DidSwap;
do
{
OBJ_STRUCT * O;
OBJ_STRUCT * NO;
O=OL->Head;
DidSwap=FALSE;
do
{
NO=O->Next;
if (OL->SortCompare(O,NO))
{
O->Next=NO->Next;
NO->Next=O;
NO->Prev=O->Prev;
O->Prev=NO;
if (NO->Prev)
NO->Prev->Next=NO;
else
OL->Head=NO;
if (O->Next)
O->Next->Prev=O;
DidSwap=TRUE;
}
else
O=O->Next;
}
while (O->Next);
}
while(DidSwap);
}
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Function: int OBJS_GetObjsAlloced(void)
Purpose: Tell us how many objects are out
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ */
int OBJS_GetObjsAlloced(void)
{
return(ObjsAlloced);
}
/* ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ends */