// FOR_YOU:
// This is the main source of your plugin.
// It's in this source you'll type all your assembly or c++ code and all 
// the variables and memory zones you need.

// ************  Top/Header section ************
#include <StdAfx.h>
#include <trng_core.h>
#include "functions.h"
#include "functions_mine.h"  // assigments of custom tomb4 address
#include "utility.h"
#include "phd_math.h"
#include "Class/TRClass.h"
#include "Class/TRLog.h"
#include "Class/TRLara.h"
#include "Class/TRWeapons.h"
#include "Class/TRPatch.h"

// all effects:
#include "sphere_of_doom.h"
#include "missile.h"
#include "snow.h"

// all entities:
#include "bear.h"
#include "bat.h"
#include "wolf.h"
#include "raptor.h"
#include "trex.h"
#include "larson.h"
#include "mummy.h"
#include "pierre.h"
#include "lion.h"
#include "ape.h"
#include "crocodile.h"
#include "rat.h"
#include "centaur.h"
#include "mutant.h"
#include "skate_kid.h"
#include "baldy.h"
#include "cowboy.h"
#include "evil_lara.h"
#include "abortion.h"
#include "spider.h"
#include "crow.h"
#include "tiger.h"
#include "dog.h"
#include "mg_silencer.h"
#include "mouse.h"
#include "mg_stick.h"
#include "mg_dual_revolver.h"
#include "wk_shotgun.h"
#include "wk_machinegun.h"
#include "wk_flamethrower.h"
#include "barracuda.h"
#include "mercenary.h"
#include "eagle.h"
#include "monk.h"
#include "morey_eel.h"
#include "yeti.h"
#include "bird_monster.h"
#include "spear_guardian.h"
#include "sword_guardian.h"
#include "knifethrower.h"
#include "dragon.h"
#include "winston.h"
#include "lizman.h"
#include "sas.h"
#include "mafia2.h"

// vehicle:
#include "skidoo.h"

#pragma warning(error: 4706)
#pragma warning(disable: 4996)

// ************  Early function declarations ************

void void_effect(ITEM_INFO* lara) { return; }
void void_effect(ITEM_INFO* lara, COLL_INFO* coll) { return; }

// use TROFF_ flags !!
BITE_INFO EnemyBite[TROFF_NUMBER] = {
    { 0, 0, 0, 0 },     // nothing at
    { 3, 331, 56, 10 }, // baddy silencer
    { -2, 275, 23, 6 }, // dual gun (boss) (left)
    { 2, 275, 23, 10 }, // dual gun (boss) (right)
    { 240, -190, 540, 0 }, // skidoo (left)
    { -240, -190, 540, 0 }, // skidoo (right)
    { 0, 281, 40, 9 }, // Worker Shotgun
    { 0, 308, 32, 9 }, // Worker Machinegun
    { -2, 150, 19, 17 }, // Mercenary 1
    { -1, 230, 9, 17 }, // Mercenary 2
	{ -60, 170, 0, 14 }, // Larson
	{ 0, 150, 34, 7 }, // skate kid (left)
	{ 0, 150, 37, 4 }, // skate kid (right)
	{ -20, 440, 20, 9 }, // Baldy
	{ 60, 200, 0, 11 }, // Pierre (left)
	{ -57, 200, 0, 14 }, // Pierre (right)
	{ 1, 200, 41, 5 }, // Cowboy (left)
	{ -2, 200, 40, 8 }, // Cowboy (right)
	{ 15, 195, 60, 13 }, // SAS 1
	{ 20, 240, 95, 13 }, // SAS 2
	{ -20, 190, 80, 10 }, // Mafia (left)
	{ 10, 200, 60, 13 } // Mafia (right)
};

// ************  Global Variables Section *************

void(*lara_control_routines[])(ITEM_INFO* lara, COLL_INFO* coll) = {
    lara_as_walk,
    lara_as_run,
    lara_as_stop,
    lara_as_forwardjump,
    void_effect,
    lara_as_fastback,
    lara_as_turn_r,
    lara_as_turn_l,
    lara_as_death,
    lara_as_fastfall,
    lara_as_hang,
    lara_as_reach,
    lara_as_splat,
    lara_as_tread,
    void_effect,
    lara_as_compress,
    lara_as_back,
    lara_as_swim,
    lara_as_glide,
    lara_as_null,
    lara_as_fastturn,
    lara_as_stepright,
    lara_as_stepleft,
    void_effect,
    lara_as_slide,
    lara_as_backjump,
    lara_as_rightjump,
    lara_as_leftjump,
    lara_as_upjump,
    lara_as_fallback,
    lara_as_hangleft,
    lara_as_hangright,
    lara_as_slideback,
    lara_as_surftread,
    lara_as_surfswim,
    lara_as_dive,
    lara_as_pushblock,
    lara_as_pullblock,
    lara_as_ppready,
    lara_as_pickup,
    lara_as_switchon,
    lara_as_switchon,
    lara_as_usekey,
    lara_as_usepuzzle,
    lara_as_uwdeath,
    void_effect,
    lara_as_special,
    lara_as_surfback,
    lara_as_surfleft,
    lara_as_surfright,
    void_effect,
    void_effect,
    lara_as_swandive,
    lara_as_fastdive,
    lara_as_null,
    lara_as_waterout,
    lara_as_climbstnc,
    lara_as_climbing,
    lara_as_climbleft,
    lara_as_climbend,
    lara_as_climbright,
    lara_as_climbdown,
    void_effect,
    void_effect,
    void_effect,
    lara_as_wade,
    lara_as_waterroll,
    lara_as_pickupflare,
    void_effect,
    void_effect,
    lara_as_deathslide,
    lara_as_duck,
    lara_as_duck,    // duckroll
    lara_as_dash,
    lara_as_dashdive,
    lara_as_hang2,
    lara_as_monkeyswing,
    lara_as_monkeyl,
    lara_as_monkeyr,
    lara_as_monkey180,
    lara_as_all4s,
    lara_as_crawl,
    lara_as_hangturnl,
    lara_as_hangturnr,
    lara_as_all4turnl,
    lara_as_all4turnr,
    lara_as_crawlb,
    void_effect,
    void_effect,
    lara_as_controlled,
    lara_as_ropel,
    lara_as_roper,
    lara_as_controlled,
    lara_as_controlled,
    lara_as_controlled,
    lara_as_controlledl,
    lara_as_controlledl,
    lara_as_controlled,
    lara_as_pickup,
    lara_as_null,
    lara_as_null,
    lara_as_null,
    lara_as_poleleft,
    lara_as_poleright,
    lara_as_pulley,
    lara_as_duckl,
    lara_as_duckr,
    lara_as_extcornerl,
    lara_as_extcornerr,
    lara_as_intcornerl,
    lara_as_intcornerr,
    lara_as_rope,
    lara_as_climbrope,
    lara_as_climbroped,
    lara_as_rope,
    lara_as_rope,
    void_effect,
    lara_as_controlled
};
void(*lara_collision_routines[])(ITEM_INFO* lara, COLL_INFO* coll) = {
    lara_col_walk,
    lara_col_run,
    lara_col_stop,
    lara_col_forwardjump,
    lara_col_fastturn,
    lara_col_fastback,
    lara_col_turn_r,
    lara_col_turn_l,
    lara_col_death,
    lara_col_fastfall,
    lara_col_hang,
    lara_col_reach,
    lara_col_splat,
    lara_col_tread,
    lara_col_fastturn,
    lara_col_compress,
    lara_col_back,
    lara_col_swim,
    lara_col_glide,
    lara_col_null,
    lara_col_fastturn,
    lara_col_stepright,
    lara_col_stepleft,
    lara_col_roll2,
    lara_col_slide,
    lara_col_backjump,
    lara_col_rightjump,
    lara_col_leftjump,
    lara_col_upjump,
    lara_col_fallback,
    lara_col_hangleft,
    lara_col_hangright,
    lara_col_slideback,
    lara_col_surftread,
    lara_col_surfswim,
    lara_col_dive,
    lara_col_null,
    lara_col_null,
    lara_col_null,
    lara_col_null,
    lara_col_null,
    lara_col_null,
    lara_col_null,
    lara_col_null,
    lara_col_uwdeath,
    lara_col_roll,
    void_effect,
    lara_col_surfback,
    lara_col_surfleft,
    lara_col_surfright,
    void_effect,
    void_effect,
    lara_col_swandive,
    lara_col_fastdive,
    lara_col_null,
    lara_col_null,
    lara_col_climbstnc,
    lara_col_climbing,
    lara_col_climbleft,
    void_effect,
    lara_col_climbright,
    lara_col_climbdown,
    void_effect,
    void_effect,
    void_effect,
    lara_col_wade,
    lara_col_waterroll,
    lara_col_null,
    void_effect,
    void_effect,
    void_effect,
    lara_col_duck,
    lara_col_duck, //lara_col_duckroll, // not exist
    lara_col_dash,
    lara_col_dashdive,
    lara_col_hang2,
    lara_col_monkeyswing,
    lara_col_monkeyl,
    lara_col_monkeyr,
    lara_col_monkey180,
    lara_col_all4s,
    lara_col_crawl,
    lara_col_hangturnlr,
    lara_col_hangturnlr,
    lara_col_all4turnlr,
    lara_col_all4turnlr,
    lara_col_all4turnlrb,
    void_effect,
    lara_col_all4turnlr2hang,
    lara_default_col,
    void_effect,
    void_effect,
    lara_default_col,
    void_effect,
    void_effect,
    lara_col_turnswitch,
    void_effect,
    void_effect,
    lara_col_null,
    lara_col_polestat,
    lara_col_poleup,
    lara_col_poledown,
    void_effect,
    void_effect,
    lara_default_col,
    lara_col_ducklr,
    lara_col_ducklr, // duckll ?
    lara_default_col,
    lara_default_col,
    lara_default_col,
    lara_default_col,
    lara_col_rope,
    void_effect,
    void_effect,
    lara_col_ropefwd,
    lara_col_ropefwd,
    void_effect,
    void_effect
};

// FOR_YOU:
// here you type the variables or memory zones you wish use in different
// C++ procedures.
// If you use the assembly you'll have to type ALL your variables in this
// section.
// for example if you wish have a 32 bits signed variable to store big
// numbers you can type:
// TYPE_HERE:
// int MyNumber;
// and then you can use it in asm in this way:
//        mov  eax, [MyNumber]
// or
//      mov eax, dword ptr [MyNumber]
// same speech for wide memory zones.
// If you wish having a memory zone of 13000 bytes you can type:
//  BYTE MyZone[13000];
// and then you can use it in this way:
//     mov  al, MyNumber[ecx]  ; read the ECXth byte and copy it in AL
// or also:
//     mov al, [MyNumber+ecx] ; same result of above instruction

// Variables and memory zone to TYPE_HERE:

HINSTANCE MyDllInstance = NULL;  // the instance handle of your dll
extern char BufferLog[4096]; // temporary global buffer to host error and warning messages

// FOR_YOU: If you mean create code patch (changes in tomb4 code to call your code in the plugin dll,
// you MUST change the MyTomb4PatcherAddress value (here below) 
// You can discover a free tomb4 zone using TrngPatcher program, with the 
// menu command "Tools->Get Assignment of Free Memory range"
// Note: choose an address, in the given range, terminating with hex 
// digits: 0,4,8, or C
// because it's usefull that the address was a multiple by 4
// If you chose an address used from other plugins you'll get an error and
// the game will be aborted
// note: if you don't mean use code patches you can let 0x0 in following line
DWORD MyTomb4PatcherAddress = 0x0; // <- TYPE_HERE: the new address you chose

// this text will contain your plugin name (omitting .dll extension).
// it will be used to give a title to messagebox for error messages or warnings
char TexMyPluginName[80];

// in this MyData structure you can store all global variables for your plugin
// you have to define them in structures_mine.h source inside structure "StrMyData" or for variable
// to save and restore in savegames, in "StrSavegameGlobalData" or "StrSavegameLocalData" structures
StrMyData mydata;

bool tsu_active;
int tsu_handle;

short tsu_links[TR_OBJECTS_NUMBER][LNK_NUMBER], tsu_objects[TR_OBJECTS_NUMBER], tsu_attributes[TR_OBJECTS_NUMBER][ATT_NUMBER], tsu_slots[SLOT_NUMBER_OBJECTS], tsu_properties[TR_OBJECTS_NUMBER][PTY_NUMBER], tsu_options[TR_OBJECTS_NUMBER][OPT_NUMBER], tsu_meshswaps[TR_OBJECTS_NUMBER][32][MSH_NUMBER], tsu_killer, tsu_spaz, tsu_frame, tsu_direction, tsu_sprites[TR_OBJECTS_NUMBER][SPR_NUMBER];
bool tsu_aiming_status, tsu_aiming[AIM_NUMBER];
int tsu_x, tsu_z;

// ************  Utilities section  ****************



// ************  Patcher Functions section  ***************
// Note: please, don't change or remove the C++ procedure you find here,
// because they are necessary to do work the plugin with the trng dll
// Anyway in many of these functions you can add your code

int Patch00_InitialiseSlot(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x0, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x454950, VetBytes, 10, 0x454950, 0x454AF6);
}

int Patch01_CreatureDie(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x1, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x440840, VetBytes, 10, 0x440840, 0x4409E6);
}

int Patch02_LaraAboveWater(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x2, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x420940, VetBytes, 10, 0x420940, 0x420B7B);
}

int Patch03_PistolHandler(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x3, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x42B850, VetBytes, 10, 0x42B850, 0x42BA60);
}

int Patch04_ShotgunHandler(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x4, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x428BC0, VetBytes, 10, 0x428BC0, 0x428F00);
}

int Patch05_LaraTargetInfo(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x5, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x42DB10, VetBytes, 10, 0x42DB10, 0x42DC95);
}

int Patch06_AddFootprint(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x6, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x437790, VetBytes, 10, 0x437790, 0x43789A);
}

int Patch07_LaraGun(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x7, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x42D430, VetBytes, 10, 0x42D430, 0x42D93E);
}

/*
int Patch12_DrawEffect(void)
{
    static BYTE VetBytes[] = { 0x66, 0xB8, 0x12, 0x0, 0xFF, 0x25, 0x60, 0x7, 0x67, 0x0 };
    return ApplyRelocatorPatch(0x44F1B0, VetBytes, 10, 0x44F1B0, 0x44F298);
}
*/

// FOR_YOU: In this function you insert the callings of functions used to change tomb4 code
// You can get these functions, in the correct format, using Trng Core -> Asm Souce Editor -> Debugging menu
// program
// note: if there is a conflict the function will return "false"
// and the tomb4 program will abort with an error message

// MOV AX,0
// JMP DWORD PTR DS:[<ClassicInventoryPatcher>]

bool CreateMyCodePatches(void)
{
    //if (SetReservedDataZone(MyTomb4PatcherAddress, 128) != APPC_OK) return false;

    //SET_PATCH(Patch00_InitialiseSlot);
    //SET_PATCH(Patch01_CreatureDie);
    //SET_PATCH(Patch02_LaraAboveWater);
    //SET_PATCH(Patch03_PistolHandler);
    //SET_PATCH(Patch04_ShotgunHandler);
    //SET_PATCH(Patch05_LaraTargetInfo);
    //SET_PATCH(Patch06_AddFootprint);
    //SET_PATCH(Patch07_LaraGun);
    return true;
}
//SET_PATCH(Patch12_DrawEffect);

// ************  Assembly Procedures section  ******************

// FOR_YOU: In the SubPatchArray you'll type all procedure names of your code in the dll you
// wish were called from tomb4 code.
// type them in the order of ax value. So first asm proc in the list, will be called
// with ax=0, while the second in the list will be called with ax=1 ect.



void* SubPatchArray[] = {
    &Patch_InitialiseSlot,
    NULL, //&Patch_CreatureDie,
    &Patch_LaraAboveWater,
    &Patch_PistolsHandler,
    &Patch_ShotgunHandler,
    &Patch_LaraTargetInfo,
    NULL, //&Patch_AddFootprint,
    &Patch_LaraGun,
    NULL
};
//&Patch_DrawEffect,

// ************  MainPatcher() asm procedure  *****************

// FOR_YOU: This is your main patcher procedure.
// All your patch in tomb4 code will call this procedure passing to it, in ax register,
// the number of subpatch to call

BEGIN_ASM_PROC(MainPatcher)
    and eax, 0ffffh
    mov eax, dword ptr [SubPatchArray+eax*4];
    jmp eax
END_ASM_PROC

// ************  CallBack functions section  *****************

// TYPE_HERE: your callback function

void cbInitProgram(int NumberLoadedPlugins, char *VetPluginNames[]) 
{

    // save number of plugins (enclosed yours and the tomb_nextgeneration.dll ) and their names
    // these data will be used to locate IDs of any loaded plugins using FindPluginID() function
    Trng.TotPlugins = NumberLoadedPlugins;
    Trng.pVetPluginNames = VetPluginNames;

    // clear all my global variables
    ClearMemory(&mydata, sizeof(StrMyData));
}

void cbInitGame(void)
{
    // here you can initialize your global data for whole adventure
    // this procedure will be called only once, before loading title level

    weapons.create_weapons();
    weapons.initialise_weapons();

	tsu_active = false;
	if (PerformConditionTrigger(STRING_PLUGIN_OBJECT_HELPER, HELPER_CONDITION_ACTIVE, 0, 0))
	{
		Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = (int) TexMyPluginName;
		PerformFlipeffect(STRING_PLUGIN_OBJECT_HELPER, HELPER_FLIPEFFECT_PLUGIN, 0, 0);
		tsu_handle = Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
		if (tsu_handle != -1)
			tsu_active = true;
	}
	if (tsu_active)
	{
		Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = (int) cbFlipEffectMine;
		PerformFlipeffect(STRING_PLUGIN_OBJECT_HELPER, HELPER_FLIPEFFECT_POINTER, tsu_handle, 0);
		Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = GLOBAL_TARGET;
		PerformFlipeffect(STRING_PLUGIN_OBJECT_HELPER, HELPER_FLIPEFFECT_GLOBAL, tsu_handle, 0);
		Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = GLOBAL_LOCK;
		PerformFlipeffect(STRING_PLUGIN_OBJECT_HELPER, HELPER_FLIPEFFECT_GLOBAL, tsu_handle, 0);
	}
}

void cbInitLevel(void)
{
    // here you can initialize specific items of current level.
    // it will be called only once for level, when all items has been already initialized
    // and just a moment before entering in main game cycle.

    Utils.FootstepSFX.initialiseFootstep();
}

// called everytime player save the game (but also when lara move from a level to another HUB saving). 
// in this procedure your plugin will save its own data in savegame
// SavingType inform about the kind of saving it is happening (SAVT_... values)
// pAdrZone is a byte pointer where this procedure will save the address from where begin data to save in savegame
// this function will return the size of data to save
// note: It's better you don't change anything of this code. It will save byself of data you stored in MyData.Save
// structure. If you wish adding other variables to save, just you add new fields in Structures of MyData.Save 
DWORD cbSaveMyData(BYTE **pAdrZone, int SavingType)
{
    DWORD SizeData;
    int i;
    static WORD *pVetExtras;
    int TotNWords;
    int TotNewActions;


    if (SavingType & SAVT_COMPLETED) {
        // this call is not to save data but only it is a confirm that the previous saving has been completed
        // now we can free the temporary memory used to save the data in previous call
        if (pVetExtras != NULL) {
            FreeMemory(pVetExtras);
            pVetExtras=NULL;
        }

        return 0;
    }


    TotNWords=0;
    pVetExtras = (WORD *) GetMemory(16);
    // save id of my plugin in first word

    pVetExtras[TotNWords++] = Trng.IdMyPlugin;

    if (SavingType & SAVT_LOCAL_DATA) {
        // save local data

        // save Local structure
        AddNGToken(NGTAG_LOCAL_DATA, NO_ARRAY, sizeof(StrSavegameLocalData), &mydata.save.current, 
                        &pVetExtras, &TotNWords);


        // save all (currently enabled) progressive actions
        // before saving, compact progressive action array to remove intermediate free records
        TotNewActions=0;

        for (i=0;i<mydata.TotProgrActions;i++) {
            if (mydata.VetProgrActions[i].ActionType != AXN_FREE) {

                mydata.VetProgrActions[TotNewActions] = mydata.VetProgrActions[i];

                TotNewActions++;
            }
        }
        // update new valuese after recompatting
        mydata.LastProgrActionIndex =0;
        mydata.TotProgrActions= TotNewActions;

        // store all progressive action records
        AddNGToken(NGTAG_PROGRESSIVE_ACTIONS, mydata.TotProgrActions, sizeof(StrProgressiveAction), 
                &mydata.VetProgrActions[0], &pVetExtras, &TotNWords);

    }

    if (SavingType & SAVT_GLOBAL_DATA) {
        // save global data
        AddNGToken(NGTAG_GLOBAL_DATA, NO_ARRAY, sizeof(StrSavegameGlobalData), &mydata.save.all , 
                        &pVetExtras, &TotNWords);
    }
    // write final sequence
    AddTokenFinalSequence(&pVetExtras, &TotNWords);

    // return to trng the infos about start of memory where there are our data and their size:
    *pAdrZone = (BYTE *) pVetExtras;
    SizeData = TotNWords * 2;

    return SizeData;
    

}
// called when a savegame will be loaded (but also when lara move from a level to another)
// pAdrZone will point to memory zone with data just loaded from savegame
// SizeData is the size of data pointed by pAdrZone
// note: it's better you don't change anything of this code. It's alread thought to reload all data you saved in MyData.Save 
// structure. There is no need of changes by you
void cbLoadMyData(BYTE *pAdrZone, DWORD SizeData)
{

    WORD *pVetExtras;
    StrParseNGField  ParseField;
    int Indice;
    int i;
    WORD TotActions;

    
    pVetExtras = (WORD*) pAdrZone;

    Indice=0;

    while (ParseNgField(pVetExtras ,Indice, &ParseField)==true) {
        
        // recover different ng token
        switch (ParseField.Type) {
        case NGTAG_LOCAL_DATA:
            // local data
            memcpy(&mydata.save.current, ParseField.pData, sizeof(StrSavegameLocalData));
            break;

        case NGTAG_GLOBAL_DATA:
            // global data
            memcpy(&mydata.save.all, ParseField.pData, sizeof(StrSavegameGlobalData));
            break;
            
        case NGTAG_PROGRESSIVE_ACTIONS:
            // progressive actions
            i= ParseField.StartDataIndex;
            // read tot actions value
            TotActions = pVetExtras[i++];
            // copy all tot records
            memcpy(&mydata.VetProgrActions[0], &pVetExtras[i], sizeof(StrProgressiveAction) * TotActions);
            mydata.TotProgrActions = TotActions;
            break;
        }
        Indice= ParseField.NextIndex; 
    }

}
// free memory used to store all data about your customize commands loaded in previous level
void FreeMemoryCustomize(void)
{
    int i;

    for (i=0;i<mydata.BaseCustomizeMine.TotCustomize;i++) {
        FreeMemory(mydata.BaseCustomizeMine.pVetCustomize[i].pVetArg);
    }

    if (mydata.BaseCustomizeMine.TotCustomize > 0) {
        FreeMemory(mydata.BaseCustomizeMine.pVetCustomize);
        mydata.BaseCustomizeMine.TotCustomize=0;
    }


    mydata.BaseCustomizeMine.pVetCustomize=NULL;
}

// free memory used to store all data about your parameters commands loaded in previous level
void FreeMemoryParameters(void)
{
    int i;

    for (i=0;i<mydata.BaseParametersMine.TotParameters;i++) {
        FreeMemory(mydata.BaseParametersMine.pVetParameters[i].pVetArg);
    }

    if (mydata.BaseParametersMine.TotParameters > 0) {
        FreeMemory(mydata.BaseParametersMine.pVetParameters);
        mydata.BaseParametersMine.TotParameters=0;
    }

    mydata.BaseParametersMine.pVetParameters=NULL;
}

// this procedure will be called at end of any level
// you can type here code to free resources allocated for level (that quits now)
void FreeLevelResources(void)
{

    // free memory used to store all data about your customize commands loaded in previous level
    FreeMemoryCustomize();
    // free memory used to store all data about your parameters commands loaded in previous level
    FreeMemoryParameters();
    mydata.BaseAssignSlotMine.TotAssign=0;

}
// it will be called before beginning the loading for a new level.
// you can type here code to initialise all variables used for level (to clear old values changed by previous level)
// and to free resources allocated in old level since now we'are going to another new level.

void cbInitLoadNewLevel(void)
{
    int i;

    StrProgressiveAction *pAction;

    // clear all LOCAL variables
    ClearMemory(&mydata.save.current,sizeof(StrSavegameLocalData));

    // clear progressive actions
    pAction= &mydata.VetProgrActions[0];

    for (i=0;i<mydata.TotProgrActions;i++) {
        if (pAction->ActionType != AXN_FREE) {
            // here you could analise to free resoruce allocated from this specific action

            pAction->ActionType = AXN_FREE;
        }
    }

    mydata.TotProgrActions=0;
    mydata.LastProgrActionIndex=0;

    // here you can initialise other variables of MyData different than Local and progressive actions
    // free resources allocate in previous level
    FreeLevelResources();
    
    // initialise dragon variable (not used if the dragon not exist in the game)
    dragon = NULL;
    dragonb = NULL;
    dragonbindex = NULL;
    dragon_already_enabled = false;
    dragon_ocb = NO_ITEM;

    mydata.save.current.monks_attack_lara = 0;
	mydata.save.current.poisoned = 0;
	mydata.save.current.dpoisoned = 0;

    for (int index = 0; index < TR_OBJECTS_NUMBER; ++index)
    {
        tsu_links[index][LNK_OBJECT1] = NO_ITEM;
        tsu_links[index][LNK_OBJECT2] = NO_ITEM;
        tsu_objects[index] = NO_ITEM;
        for (int value = 0; value < ATT_NUMBER; ++value)
            tsu_attributes[index][value] = NO_ITEM;
        for (int value = 0; value < PTY_NUMBER; ++value)
            tsu_properties[index][value] = NO_ITEM;
        for (int value = 0; value < OPT_NUMBER; ++value)
            tsu_options[index][value] = NO_ITEM;
        for (int mesh = 0; mesh < 32; ++mesh)
		{
			for (int value = 0; value < MSH_NUMBER; ++value)
				tsu_meshswaps[index][mesh][value] = NO_ITEM;
		}
		for (int value = 0; value < SPR_NUMBER; ++value)
            tsu_sprites[index][value] = NO_ITEM;
    }
    for (int index = 0; index < SLOT_NUMBER_OBJECTS; ++index)
        tsu_slots[index] = NO_ITEM;
    tsu_aiming_status = false;
    for (int index = 0; index < AIM_NUMBER; ++index)
        tsu_aiming[index] = false;
	tsu_killer = NO_ITEM;
	tsu_spaz = 0;
	tsu_frame = 0;
	tsu_direction = -1;
}

// this procedure will be called everytime a flipeffect of yours will be engaged
// you have to elaborate it and then return a TRET_.. value (most common is TRET_PERFORM_ONCE_AND_GO)
int cbFlipEffectMine(WORD FlipIndex, WORD Timer, WORD Extra, WORD ActivationMode)
{
    int RetValue;
    WORD TimerFull;

    RetValue = enumTRET.PERFORM_ONCE_AND_GO;
    // if the flip has no Extra paremeter you can handle a Timer value with values upto 32767
    // in this case you'll use the following TimerFull variable, where (with following code) we set a unique big number 
    // pasting togheter the timer+extra arguments:
    TimerFull = Timer | (Extra << 8);

	WEAPON_INFO* winfo;
	ITEM_INFO* item, *enemy;
	CREATURE_INFO* creature;
	short object;
    StrBoxCollisione* Box;
	StrGunflashArguments* gunflash_input;
	StrPatrolPickupArguments* pickup_input;
	StrVaultArguments* vault_input;
	BITE_INFO* bite;
	WORD offset;
	AIOBJECT* ai;
	bool vault_ok;

    switch (FlipIndex) {
        // here type the "case Number:" for each flipeffect number. At end of the code you'll use the "break;" instruction to signal the code ending
        // Note: when you'll add your first "case Number:" then you can remove the following "case -1: and break;" instructions
		case FLIPEFFECT_FUNCTION:
			if (ActivationMode & enumSCANF.DIRECT_CALL)
			{
				switch (DecodeTimer(Timer, Extra))
				{
				case FUNCTION_ZONE_BEFORE:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					creature = (CREATURE_INFO*) item->data;
					object = tsu_slots[item->object_number];
					Utils.EnableZone(object, creature);
					break;
				case FUNCTION_SHADOW_BEFORE:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					if (item->hit_points <= 0)
					{
						tsu_x = item->pos.x_pos;
						tsu_z = item->pos.z_pos;
						Box = GetBoundsAccurate((StrItemTr4*) item);
						phd_pushUnitMatrix();
						phd_RotYXZ(item->pos.y_rot, item->pos.x_rot, item->pos.z_rot);
						phd_TranslateRel((Box->MinX + Box->MaxX) / 2, (Box->MinY + Box->MaxY) / 2, (Box->MinZ + Box->MaxZ) / 2);
						item->pos.x_pos += Ptr_ZonaRecord30[3] >> W2V_SHIFT;
						item->pos.z_pos += Ptr_ZonaRecord30[11] >> W2V_SHIFT;
						Utils.jmn_PopMatrix();
					}
					break;
				case FUNCTION_SHADOW_AFTER:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					if (item->hit_points <= 0)
					{
						item->pos.x_pos = tsu_x;
						item->pos.z_pos = tsu_z;
					}
					break;
				}
			}
			break;
        case FLIPEFFECT_GLOBAL:
			if (ActivationMode & enumSCANF.DIRECT_CALL)
			{
				switch (Timer)
				{
				case GLOBAL_TARGET:
					winfo = (WEAPON_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					if (Utils.getPluginAimingStatus())
					{
						if (input & CMD_ACTION)
							LaraTargetInfo(winfo);
						else
							Lara.setTarget(NULL);

						if (Lara.getTarget() == NULL)
							LaraGetNewTarget(winfo);
					}
					else
					{
						LaraGetNewTarget(winfo);
						if (input & CMD_ACTION)
							LaraTargetInfo(winfo);
					}
					break;
				case GLOBAL_LOCK:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					/* If Target Doesn't Exist use Defaults */
					if (item == NULL)
					{
						Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = false;
					}
					// check if the target is in target range of the current equipped weapon, else not target it !
					// ps: need the customize enabled !
					else if (item != NULL && !Utils.getPluginAiming(AIM_RESDISTANCE) && GetDistanceXZY(LaraItem->pos.x_pos, LaraItem->pos.y_pos, LaraItem->pos.z_pos, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos) > Weapons[WeaponSelect].target_dist)
					{
						Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = false;
					}
					else
					{
						Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = true;
					}
					break;
				}
			}
            break;
		case FLIPEFFECT_QUERY:
			if (ActivationMode & enumSCANF.DIRECT_CALL)
			{
				switch (DecodeTimer(Timer, Extra))
				{
				case QUERY_SPRITE:
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = true;
					break;
				case QUERY_GUNFLASH:
					gunflash_input = (StrGunflashArguments*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					item = gunflash_input->item;
					bite = NULL;
					offset = Ptr_VetObjects[item->object_number].bit_offset & OFFSET_MUZZLEFLASH;
					if (Ptr_VetObjects[item->object_number].bit_offset & DOUBLE_OFFSET_MUZZLEFLASH)
					{
						if (gunflash_input->mesh_num == EnemyBite[offset].mesh_num)
						{
							if (item->reserved_1 & 1)
								bite = &EnemyBite[offset];
						}
						else if (gunflash_input->mesh_num == EnemyBite[offset + 1].mesh_num)
						{
							if (item->reserved_1 & 2)
								bite = &EnemyBite[offset + 1];
						}
					}
					else if (gunflash_input->mesh_num == EnemyBite[offset].mesh_num)
						bite = &EnemyBite[offset];
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = (int) bite;
					break;
				case QUERY_ZOMBIE:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = !item->meshswap_meshbits;
					break;
				case QUERY_KILLER:
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = true;
					break;
				case QUERY_DEATH:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = item->current_anim_state == AS_DEATH;
					break;
				case QUERY_HEADSHOT:
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = true;
					break;
				case QUERY_PATROL:
					item = (ITEM_INFO*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					creature = (CREATURE_INFO*) item->data;
					enemy = creature->enemy;
					if (creature->alerted || creature->hurt_by_lara)
					{
						creature->enemy = LaraItem;
						item->ai_bits &= ~SAI_PATROL1;
						if (item->ai_bits & SAI_AMBUSH)
						{
							item->ai_bits |= SAI_MODIFY;
							item->reserved_4 = item->reserved_3;
						}
					}
					else if (!enemy || enemy->object_number != SLOT_AI_PATROL1)
						FindAITargetObject(creature, SLOT_AI_PATROL1);
					else if (ABS(enemy->pos.x_pos - item->pos.x_pos) < 640 && ABS(enemy->pos.y_pos - item->pos.y_pos) < 640 && ABS(enemy->pos.z_pos - item->pos.z_pos) < 640)
						creature->reached_goal = 1;
					break;
				case QUERY_PATROL2:
					pickup_input = (StrPatrolPickupArguments*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					item = pickup_input->item;
					ai = pickup_input->ai;
					if (ai->object_number == SLOT_AI_AMBUSH || ai->object_number == SLOT_AI_PATROL1)
					{
						item->reserved_3 = ai->trigger_flags;
						item->reserved_4 = ai->trigger_flags;
					}
					break;
				case QUERY_VAULT:
					vault_input = (StrVaultArguments*) Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue;
					item = vault_input->item;
					vault_ok = false;
					if (vault_input->vault)
					{
						object = tsu_slots[item->object_number];
						vault_ok = Utils.IsVaultEnabled(object, vault_input->vault);
					}
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = vault_ok;
					break;
				case QUERY_TOUCH:
					Trng.pGlobTomb4->pBaseVariableTRNG->Globals.CurrentValue = true;
					break;
				}
			}
			break;
        default:
            SendToLog("WARNING: Flipeffect trigger number %d has not been handled in cbFlipEffectMine() function", FlipIndex);
            break;
    }

    // if there was the one-shot button enabled, return TRET_PERFORM_NEVER_MORE
    if (ActivationMode & enumSCANF.BUTTON_ONE_SHOT) RetValue= enumTRET.PERFORM_NEVER_MORE; 
    return RetValue;
}
// this procedure will be called everytime an action trigger of yours will be engaged 
// you have to elaborate it and then return a TRET_.. value (most common is TRET_PERFORM_ONCE_AND_GO)
int cbActionMine(WORD ActionIndex, int ItemIndex, WORD Extra, WORD ActivationMode)
{
    int RetValue;
    
    RetValue=TRET_PERFORM_ONCE_AND_GO;

    switch (ActionIndex) {
        // type here the code per your action trigger.
        // add "case Number:" and complete the code with "break;" instruction
    case -1:
        // note: remove this "case -1:" and its "break;" it has been added only to avoid warning messages about empty switch
        break;
    default:
        SendToLog("WARNING: action trigger number %d has not been handled in cbActionMine() function", ActionIndex);
        break;
    }
    
    // if there was the one-shot button enabled, return TRET_PERFORM_NEVER_MORE
    if (ActivationMode & enumSCANF.BUTTON_ONE_SHOT) RetValue= enumTRET.PERFORM_NEVER_MORE;
    return RetValue;


}

// this procedure will be called everytime a conditional trigger of yours will be engaged
// you have to elaborate it and then return a CTRET_.. value (most common is CTRET_ONLY_ONCE_ON_TRUE)
int cbConditionMine(WORD ConditionIndex, int ItemIndex, WORD Extra, WORD ActivationMode)
{
    int RetValue;
    
    RetValue=CTRET_ONLY_ONCE_ON_TRUE;

    switch (ConditionIndex){
        // type here the code for your condition trigger, inserting the code in the section
        // beginning with "case NumberOfAction:" and ending with row "break;"
    case -1:
        // note: remove this "case -1:" and its "break;" it has been added only to avoid warning messages about empty switch
        break;
    default:
        SendToLog("WARNING: condition trigger number %d has not been handled in cbConditionMine() function", ConditionIndex);
        break;


    }
    return RetValue;
      
}

// this procedure vill be called for each Customize=CUST_... command read from script
// having one of yours CUST_ constant
// CustomizeValue will be the value of your CUST_ constant
// NumberOfItems will be the number of following Item (signed 16 bit values) following
// the CUST_ constant in the customize= script command
// pItemArray is the array with all NumberOfItems arguments of customize command
void cbCustomizeMine(WORD CustomizeValue, int NumberOfItems, short *pItemArray)
{
    // here you can replace this default management of anonymous customize commands
    // with your procedure where you can recognize each different CUST_ value and 
    // save its arguments in meaningful names fields, or elaboriting them immediatly
    // when it is possible (warning: in this moment nothing of level it has been yet loaded, excepting the script section)

    // ----- default management (optional)----
    // all customize values will be saved in MyData structure
    DWORD SizeMem;
    StrGenericCustomize *pMyCust;
    int TotCust;

    // ask memory to have another (new) record of StrGenericCustomize structure
    TotCust= mydata.BaseCustomizeMine.TotCustomize;
    TotCust++;
    SizeMem = TotCust * sizeof(StrGenericCustomize);
    mydata.BaseCustomizeMine.pVetCustomize = 
                (StrGenericCustomize *) ResizeMemory(mydata.BaseCustomizeMine.pVetCustomize, SizeMem);

    pMyCust = & mydata.BaseCustomizeMine.pVetCustomize[TotCust-1];
    
    // now require memory for all arguments (NumberOfItems) store in pItemArray

    pMyCust->pVetArg = (short *) GetMemory(2 * NumberOfItems);
    // copy data
    pMyCust->NArguments = NumberOfItems;
    memcpy(pMyCust->pVetArg, pItemArray, 2*NumberOfItems);
    pMyCust->CustValue = CustomizeValue;

    mydata.BaseCustomizeMine.TotCustomize= TotCust;
    // ---- end of default managemnt for generic customize -------------    

    switch (CustomizeValue)
    {
    case CUST_TSU_LINKS:
        if (NumberOfItems >= LINKS_VALUE && pItemArray[LINKS_NAME] >= 0 && pItemArray[LINKS_NAME] < TR_OBJECTS_NUMBER)
        {
			int args = NumberOfItems < LINKS_ARGS ? NumberOfItems : LINKS_ARGS;
            for (int index = LINKS_VALUE; index < args; ++index)
                tsu_links[pItemArray[LINKS_NAME]][index - LINKS_VALUE] = pItemArray[index];
        }
        break;
    case CUST_TSU_OBJECTS:
        if (NumberOfItems >= OBJECTS_VALUE && pItemArray[OBJECTS_NAME] >= 0 && pItemArray[OBJECTS_NAME] < TR_OBJECTS_NUMBER)
        {
            tsu_objects[pItemArray[OBJECTS_NAME]] = pItemArray[OBJECTS_ID];
			int args = NumberOfItems < OBJECTS_ARGS ? NumberOfItems : OBJECTS_ARGS;
            for (int index = OBJECTS_VALUE; index < args; ++index)
                tsu_attributes[pItemArray[OBJECTS_NAME]][index - OBJECTS_VALUE] = pItemArray[index];
        }
        break;
    case CUST_TSU_AIMING:
        if (NumberOfItems >= AIMING_VALUE)
        {
            tsu_aiming_status = pItemArray[AIMING_SYSTEM] > 0;
			int args = NumberOfItems < AIMING_ARGS ? NumberOfItems : AIMING_ARGS;
            for (int index = AIMING_VALUE; index < args; ++index)
                tsu_aiming[index - AIMING_VALUE] = pItemArray[index] > 0;
        }
        break;
    case CUST_TSU_PROPERTIES:
        if (NumberOfItems >= PROPERTIES_VALUE && pItemArray[PROPERTIES_NAME] >= 0 && pItemArray[PROPERTIES_NAME] < TR_OBJECTS_NUMBER)
        {
			int args = NumberOfItems < PROPERTIES_ARGS ? NumberOfItems : PROPERTIES_ARGS;
            for (int index = PROPERTIES_VALUE; index < args; ++index)
                tsu_properties[pItemArray[PROPERTIES_NAME]][index - PROPERTIES_VALUE] = pItemArray[index];
        }
        break;
    case CUST_TSU_OPTIONS:
        if (NumberOfItems >= OPTIONS_VALUE && pItemArray[OPTIONS_NAME] >= 0 && pItemArray[OPTIONS_NAME] < TR_OBJECTS_NUMBER)
        {
			int args = NumberOfItems < OPTIONS_ARGS ? NumberOfItems : OPTIONS_ARGS;
            for (int index = OPTIONS_VALUE; index < args; ++index)
                tsu_options[pItemArray[OPTIONS_NAME]][index - OPTIONS_VALUE] = pItemArray[index];
        }
        break;
    case CUST_TSU_MESHSWAPS:
        if (NumberOfItems >= MESHSWAPS_VALUE && pItemArray[MESHSWAPS_NAME] >= 0 && pItemArray[MESHSWAPS_NAME] < TR_OBJECTS_NUMBER)
        {
			int loops = (NumberOfItems - MESHSWAPS_ID) / MESHSWAPS_STEP;
			for (int value = 0; value < loops; ++value)
			{
				short* iterator = &pItemArray[MESHSWAPS_STEP * value];
				if (iterator[MESHSWAPS_ID] >= 0 && iterator[MESHSWAPS_ID] < 32)
				{
					for (int index = MESHSWAPS_VALUE; index < MESHSWAPS_ARGS; ++index)
						tsu_meshswaps[pItemArray[MESHSWAPS_NAME]][iterator[MESHSWAPS_ID]][index - MESHSWAPS_VALUE] = iterator[index];
				}
			}
        }
        break;
    case CUST_TSU_SPRITES:
        if (NumberOfItems >= SPRITES_VALUE && pItemArray[SPRITES_NAME] >= 0 && pItemArray[SPRITES_NAME] < TR_OBJECTS_NUMBER)
        {
			int args = NumberOfItems < SPRITES_ARGS ? NumberOfItems : SPRITES_ARGS;
            for (int index = SPRITES_VALUE; index < args; ++index)
                tsu_sprites[pItemArray[SPRITES_NAME]][index - SPRITES_VALUE] = pItemArray[index];
        }
        break;
    }
}
// callback called everytime in current level section of the script it has been found an AssignSlot command
// with one of your OBJ_ constants
void cbAssignSlotMine(WORD Slot, WORD ObjType)
{
    int i;

    i = mydata.BaseAssignSlotMine.TotAssign;

    if (i >= MAX_ASSIGN_SLOT_MINE) {
        SendToLog("ERROR: too many AssignSlot= commands for current plugin");
        return;
    }

    mydata.BaseAssignSlotMine.VetAssignSlot[i].MioSlot = Slot;
    mydata.BaseAssignSlotMine.VetAssignSlot[i].TipoSlot = ObjType;
    mydata.BaseAssignSlotMine.TotAssign++;

}
// this procedure vill be called for each Parameters=PARAM_... command read from script
// having one of yours PARAM_ constants
// ParameterValue will be the value of your PARAM_ constant
// NumberOfItems will be the number of following Item (signed 16 bit values) following
// the PARAM_ constant in the customize= script command
// pItemArray is the array with all NumberOfItems arguments of Parameter command
void cbParametersMine(WORD ParameterValue, int NumberOfItems, short *pItemArray)
{
    // here you can replace this default management of anonymous parameters commands
    // with your procedure where you can recognize each different Param_ value and 
    // save its arguments in meaningful names fields, or elaboriting them immediatly
    // when it is possible (warning: in this moment nothing of level it has been yet loaded, excepting the script section)

    // ----- default management (optional)----
    // all parameters values will be saved in MyData structure
    DWORD SizeMem;
    StrGenericParameters *pMyParam;
    int TotParam;

    // ask memory to have another (new) record of StrGenericparameters structure
    TotParam= mydata.BaseParametersMine.TotParameters;
    TotParam++;
    SizeMem = TotParam * sizeof(StrGenericParameters);
    mydata.BaseParametersMine.pVetParameters = 
        (StrGenericParameters *) ResizeMemory(mydata.BaseParametersMine.pVetParameters, SizeMem);

    pMyParam = & mydata.BaseParametersMine.pVetParameters[TotParam-1];
    
    // now require memory for all arguments (NumberOfItems) store in pItemArray

    pMyParam->pVetArg = (short *) GetMemory(2 * NumberOfItems);
    // copy data
    pMyParam->NArguments = NumberOfItems;
    memcpy(pMyParam->pVetArg, pItemArray, 2*NumberOfItems);

    mydata.BaseParametersMine.TotParameters= TotParam;
    // ---- end of default managemnt for generic parameters -------------


}

// this procedure will be called every game cycle (at begin of cycle)
void cbCycleBegin(void)
{

    
}

// Not yet linked! To link it add to RequireMyCallBacks() function the row:
//      GET_CALLBACK(CB_CYCLE_END, 0, 0, cbCycleEnd);
// this procedure will be called everygame cycle, at end.
// you have to return a RET_CYCLE_ value
int cbCycleEnd(void)
{
    return RET_CYCLE_CONTINUE;    
}

// this function will be called for each your (common) progressive action to be peformed
void PerformMyProgrAction(StrProgressiveAction *pAction)
{
    switch (pAction->ActionType) {
        // replace the "case -1:" with your first "case AXN_...:" progressive action to manage)        
        case -1:
            break;

    }
}

// callback called from trng for each frame in game cycle to perform your (common) progressive action
void cbProgrActionMine(void)
{
    int i;
    StrProgressiveAction *pAction;

    pAction = &mydata.VetProgrActions[0];
    for (i=0;i<mydata.TotProgrActions;i++) {
        if (pAction->ActionType != AXN_FREE) {
            PerformMyProgrAction(pAction);
        }
        pAction++;
    }
}

// inside this function you'll type call to functions to intialise your new objects or customize that olds.
// this callback will be called at start of loading new level and a bit after having started to load level data
void InitialiseNewObjects(void) 
{
    /* Initialise Effects before Entity */
	InitialiseTR1_Rocket();
	InitialiseTR1_Shard();
	InitialiseTR1_Alligator();
	InitialiseTR1_Vole();
	InitialiseTR1_SkateBoard();

    InitialiseTR2_Sparkles();
    InitialiseTR2_DragonFire();
    InitialiseTR2_Knife();
    InitialiseTR2_SphereOfDoom1();
    InitialiseTR2_SphereOfDoom2();
    InitialiseTR2_SphereOfDoom3();
    InitialiseTR2_SpearGuardianStatue();
    InitialiseTR2_SwordGuardianStatue();

	InitialiseTR3_Gas();

    /* Initialise Entity */
	InitialiseTR1_Bear();
	InitialiseTR1_Bat();
	InitialiseTR1_Wolf();
	InitialiseTR1_Raptor();
    InitialiseTR1_TRex();
	InitialiseTR1_Larson();
	InitialiseTR1_Mummy();
	InitialiseTR1_Pierre();
	InitialiseTR1_Lion();
	InitialiseTR1_Lioness();
	InitialiseTR1_Puma();
	InitialiseTR1_Ape();
	InitialiseTR1_Crocodile();
	InitialiseTR1_Rat();
	InitialiseTR1_Centaur();
	InitialiseTR1_Warrior();
	InitialiseTR1_SkateKid();
	InitialiseTR1_Baldy();
	InitialiseTR1_Cowboy();
	InitialiseTR1_EvilLara();
	InitialiseTR1_Abortion();

    InitialiseTR2_Spider();
    InitialiseTR2_SpiderBig();
    InitialiseTR2_Crow();
    InitialiseTR2_Tiger();
    InitialiseTR2_TRex();
    InitialiseTR2_Dog();
    InitialiseTR2_GoonSilencer();
    InitialiseTR2_Mouse();
    InitialiseTR2_GoonStick();
    InitialiseTR2_DualGun();
    InitialiseTR2_GoonShotgun();
    InitialiseTR2_GoonMachineGun();
    InitialiseTR2_GoonFlamethrower();
    InitialiseTR2_Barracuda();
    InitialiseTR2_MoreyEelBlack();
    InitialiseTR2_MoreyEelYellow();
    InitialiseTR2_Mercenary1();
    InitialiseTR2_Mercenary2();
    InitialiseTR2_Eagle();
    InitialiseTR2_Monk1();
    InitialiseTR2_Yeti();
    InitialiseTR2_MonsterBird();
    InitialiseTR2_SpearGuardian();
    InitialiseTR2_SwordGuardian();
    InitialiseTR2_Knifethrower();
    InitialiseTR2_DragonFront();
    InitialiseTR2_DragonBack();
    InitialiseTR2_DragonBoneFront();
    InitialiseTR2_DragonBoneBack();
    InitialiseTR2_MarcoBartoli();
    InitialiseTR2_Winston();

    /* Vehicle and Driver */
    InitialiseTR2_Skidoo();          // Normal Skidoo (no guns)
    InitialiseTR2_SkidooLaraAnim();
    InitialiseTR2_SkidooTrack();
    InitialiseTR2_SkidooSnow();      // Vehicle effects
    InitialiseTR2_SkidooGun();       // Vehicle used by the driver.
    InitialiseTR2_SkidooDriver();
    InitialiseTR2_SkidooAfterDeath();// Vehicle used normally or after driver death !
    
	InitialiseTR3_LizMan();

	InitialiseTR5_BlueGuard();
	InitialiseTR5_Swat();
	InitialiseTR5_SwatPlus();
	InitialiseTR5_Mafia();
	InitialiseTR5_Scientist();
	InitialiseTR5_Mafia2();
}

int ControlStateDeath(WORD StateId, WORD CBT_Type, StrItemTr4 *pLara, StrCollisionLara * pCollision)
{
	ITEM_INFO *lara;

	lara = (ITEM_INFO*)pLara;

	if (tsu_killer != NO_ITEM)
	{
		switch (MapToFirst(tsu_killer, SLOTS_NUMBER))
		{
		case TR1_GIANT_MUTANT1:
			SetCameraDistance = 2 * WALL_L;
			TestForzaQuestaCamera = 1;
			SetCameraHOrient = 170 * ONE_DEGREE;
			SetCameraVOrient = -25 * ONE_DEGREE;
			break;
		case TR1_TYRANNOSAUR1:
		case TR2_TYRANNOSAUR1:
			TestForzaQuestaCamera = 1;
			SetCameraHOrient = 170 * ONE_DEGREE;
			SetCameraVOrient = -25 * ONE_DEGREE;
			if (lara->frame_number < Ptr_VetAnimations[lara->anim_number].frame_end - 30)
				Lara.setDeathCount(1);
			break;
		case TR2_YETI1:
		case TR2_SPEAR_XIAN_GUARD1:
			SetCameraHOrient = 160 * ONE_DEGREE;
			SetCameraDistance = 3 * WALL_L;
			if (lara->frame_number < Ptr_VetAnimations[lara->anim_number].frame_end - 30)
				Lara.setDeathCount(1);
			break;
		}
	}
	return SRET_OK;
}

int ControlLaraFirst(WORD CBT_Flags, StrItemTr4 *pLara)
{
	if (mydata.save.current.poisoned && !GL_playing_cutseq)
	{
		if (mydata.save.current.poisoned > 4096)
			mydata.save.current.poisoned = 4096;
		else if (mydata.save.current.dpoisoned)
			mydata.save.current.dpoisoned++;
	}
	if (mydata.save.current.poisoned == Lara.getPoison1() && mydata.save.current.dpoisoned == Lara.getPoison2())
	{
		Lara.setPoison2(Lara.getPoison1());
		mydata.save.current.dpoisoned = mydata.save.current.poisoned;
	}
	else
	{
		mydata.save.current.poisoned = 0;
		mydata.save.current.dpoisoned = 0;
	}

	return SRET_OK;
}

int ControlLaraAfter(WORD CBT_Flags, StrItemTr4 *pLara)
{
	if (tsu_spaz)
	{
		++tsu_frame;
		if (tsu_frame > 30)
			tsu_frame = 30;
		if (Lara.getHitDirection() == -1 && Ptr_LaraColl->enable_spaz)
		{
			Lara.setHitDirection(tsu_direction);
			Lara.setPoseCount(tsu_frame);
		}
		--tsu_spaz;
	}
	else
	{
		tsu_direction = -1;
		tsu_frame = 0;
	}
	return SRET_OK;
}

// FOR_YOU:
// in this function RequireMyCallBacks() you'll type
// a list of:
//        GET_CALLBACK(CB_..., ,)
// one for each callback you need
bool RequireMyCallBacks(void)
{
// ************  RequireMyCallBacks() function  *****************
    // protype of GET_CALLBACK:
    // GET_CALLBACK(CallBackCB, CBT_Flags, Index, MyProcToCall)
    // default callbacks required always 
    GET_CALLBACK(CB_INIT_PROGRAM, 0, 0, cbInitProgram)
    GET_CALLBACK(CB_INIT_GAME, 0, 0, cbInitGame)
    GET_CALLBACK(CB_INIT_LEVEL, 0,0, cbInitLevel)
    GET_CALLBACK(CB_SAVING_GAME, 0, 0, cbSaveMyData)
    GET_CALLBACK(CB_LOADING_GAME, 0, 0, cbLoadMyData)
    GET_CALLBACK(CB_INIT_LOAD_NEW_LEVEL, 0,0, cbInitLoadNewLevel);
    GET_CALLBACK(CB_FLIPEFFECT_MINE, 0, 0, cbFlipEffectMine);
    GET_CALLBACK(CB_ACTION_MINE, 0,0, cbActionMine);
    GET_CALLBACK(CB_CONDITION_MINE,0,0,cbConditionMine);
    GET_CALLBACK(CB_CUSTOMIZE_MINE, 0,0, cbCustomizeMine);
    GET_CALLBACK(CB_PARAMETER_MINE, 0, 0, cbParametersMine);
    GET_CALLBACK(CB_ASSIGN_SLOT_MINE, 0,0, cbAssignSlotMine);
    GET_CALLBACK(CB_CYCLE_BEGIN, 0, 0, cbCycleBegin);
    //GET_CALLBACK(CB_CYCLE_END, 0, 0, cbCycleEnd);
    GET_CALLBACK(CB_PROGR_ACTION_MINE, 0, 0, cbProgrActionMine);
    GET_CALLBACK(CB_INIT_OBJECTS, 0, 0, InitialiseNewObjects);
    GET_CALLBACK(CB_STATE_ID_LARA_CTRL, CBT_AFTER, AS_DEATH, ControlStateDeath);
	GET_CALLBACK(CB_LARA_CONTROL, CBT_FIRST, 0, ControlLaraFirst);
    GET_CALLBACK(CB_LARA_CONTROL, CBT_AFTER, 0, ControlLaraAfter);
    return true;
}

// FOR_YOU:
// This function will be the first code to be executed of your plugin
// It happens when trng will load your plugin.
// In this moment no directX graphic is yet active, so you can show
// message boxes (TryMessageBox) to advise your players or level designer 
// about something
// Note: if you wish abort all (because there is an error or something
// is missing) you have to exit from this function returning: false
bool InitializeAll(void)
{
// ************  InitializeAll() function  ****************
    //  perform all your patches
    CALL_CHECK(CreateMyCodePatches)

    // call the function that requires all callback you need
    CALL_CHECK(RequireMyCallBacks)

    return true;
}

// FOR_YOU: Tyis function will be called when tomb4 game is to be closed.
// you should type in this function further codes to free the global
// resource you had allocated in the InitializeAll() function 
void ReleaseAll(void)
{
    // ************  ReleaseAll() function  ******************
    FreeLevelResources();
}


BOOL APIENTRY DllMain(HINSTANCE hInstanceDll, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
            MyDllInstance = hInstanceDll;
            GetTrngInfo();
            // control per check control value about size and alignment with globtomb4 structure
            if (CheckControlGlobTomb4() == false) return FALSE;

            if  (InitializeAll()==false) {
                return FALSE;
            }
            
            // initialise logger.
            logger.start("plugin_tokyosu", pFILE);
            return TRUE;

        case DLL_PROCESS_DETACH:
            ReleaseAll();

            // free logger.
            logger.end(pFILE);

            // free weapon system.
            weapons.free_weapons();
            break;
    }

    return TRUE;
}


