#include <stdio.h>
#include "stdint.h"
#include <time.h>
#include <math.h>

#include "BSL.h"
#include "Utility.h"
#include "../Daodan_Patch.h"
#include "Console.h"

#include "../Oni/Oni.h"

#include "Character.h"

bool ONICALL argumentEmpty(sl_arg* arg) {
	if ((arg->type == sl_str32) && (strlen(arg->val.value_str32) == 0))
		return true;
	return false;
}

uint16_t ONICALL bsl_int32mul(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	ret->val.value_int32 = args[0].val.value_int32 * args[1].val.value_int32;
	ret->type = sl_int32;
	return 0;
}

uint16_t ONICALL bsl_mul(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	double val1;
	double val2;
	
	if (args[0].type == sl_int32)
		val1 = args[0].val.value_int32;
	else
		val1 = args[0].val.value_float;
	
	if (args[1].type == sl_int32)
		val2 = args[1].val.value_int32;
	else
		val2 = args[1].val.value_float;
	
	ret->val.value_float = (float)(val1 * val2);
	ret->type = sl_float;
	return 0;
}

uint16_t ONICALL bsl_int32div(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	ret->val.value_int32 = args[0].val.value_int32 / args[1].val.value_int32;
	ret->type = sl_int32;
	return 0;
}
uint16_t ONICALL bsl_div(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	double val1;
	double val2;
	
	if (args[0].type == sl_int32)
		val1 = args[0].val.value_int32;
	else
		val1 = args[0].val.value_float;
	
	if (args[1].type == sl_int32)
		val2 = args[1].val.value_int32;
	else
		val2 = args[1].val.value_float;
	
	ret->val.value_float = (float)(val1 / val2);
	ret->type = sl_float;
	return 0;
}

uint16_t ONICALL bsl_int32rand(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int32_t start = 0;
	int32_t end = 0;
	
	if (args[0].val.value_int32 == args[1].val.value_int32)
		return 1;
	else if (args[0].val.value_int32 > args[1].val.value_int32)
	{
		start = args[1].val.value_int32;
		end = args[0].val.value_int32;
	}
	else
	{
		start = args[0].val.value_int32;
		end = args[1].val.value_int32;
	}

	ret->val.value_int32 = start + (rand() % (uint32_t)(end - start + 1));
	ret->type = sl_int32;
	return 0;
}

uint16_t ONICALL bsl_getkills(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	if (argumentEmpty(&args[0])) index = 0;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	//killcount = ONgGameState->CharacterStorage[index].Kills;
		//ONgGameState + index * 0x16A0 + 0x1260 + 0x1670;
	ret->val.value_int32 = ONgGameState->CharacterStorage[index].Kills;
	ret->type = sl_int32;
	return 0;
}

uint16_t ONICALL bsl_getdamage(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	if (argumentEmpty(&args[0])) index = 0;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	ret->val.value_int32 = ONgGameState->CharacterStorage[index].Damage;
	ret->type = sl_int32;
	return 0;
}



uint16_t ONICALL bsl_powerup(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	void* returnval;
	bool is_lsi = 0;
	Character* Chr = ONgGameState->CharacterStorage;

	if (numargs < 2 || args[1].type != sl_str32) return 1;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;

	

	if(!strcmp(args[1].val.value_str32,"ammo")) 
	{
		returnval = &(Chr[index].Inventory.AmmoUsed);
	}
	else if(!strcmp(args[1].val.value_str32,"hypo")) 
	{
		returnval = &(Chr[index].Inventory.HypoUsed);
	}
	else if(!strcmp(args[1].val.value_str32,"cells")) 
	{
		returnval = &(Chr[index].Inventory.CellsUsed);
	}
	else if(!strcmp(args[1].val.value_str32,"invis")) 
	{
		returnval = &(Chr[index].Inventory.CloakUsed);
	}
	else if(!strcmp(args[1].val.value_str32,"shield")) 
	{
		returnval = &(Chr[index].Inventory.ShieldUsed);
	}
	else if(!strcmp(args[1].val.value_str32,"lsi")) 
	{
		returnval = &(Chr[index].Inventory.hasLSI);
		is_lsi = 1;
	}
//	else if(!strcmp(args[1].value_str32,"bossshield")) 
//	{
//		ret->value_int32 = Chr[index].Flags & char_bossshield;
//		ret->type = sl_int32;
//		if (numargs >=3) {
//			if (Chr[index].Flags & char_bossshield) Chr[index].Flags = Chr[index].Flags & ~char_bossshield;
//			else Chr[index].Flags = Chr[index].Flags | char_bossshield;
//		}
//		return 0;
//	}
	else return 1;
	//todo, add setting
	
	if(is_lsi) ret->val.value_int32 = (int)*(bool*)returnval;
	else	ret->val.value_int32 = *(int*)returnval;
	ret->type = sl_int32;

	if (numargs >= 3) 
	{
		if(is_lsi) *(bool*)returnval = args[2].val.value_int32;
		else *(int*)returnval = args[2].val.value_int32;
	}
	
	
	return 0;
}

uint16_t ONICALL bsl_health(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	Character* Chr;
	int* health;
	if (argumentEmpty(&args[0])) index = 0;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	Chr = ONgGameState->CharacterStorage;
	health = &Chr[index].Health;

	ret->val.value_int32 = *health;
	ret->type = sl_int32;

	if (args[1].val.value_int32) {
		*health = args[1].val.value_int32;
	}
	ret->val.value_int32 = *health;
	ret->type = sl_int32;
	return 0;
}

uint16_t ONICALL bsl_regen(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	Character* Chr;
	if (argumentEmpty(&args[0])) index = 0;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	Chr = ONgGameState->CharacterStorage ;
	
	/*
	DDrConsole_PrintF("Character %s", Chr[index].Name);
	DDrConsole_PrintF("Spawn %s", Chr[index].ScriptSpawn);
	DDrConsole_PrintF("Death %s", Chr[index].ScriptDie);
	DDrConsole_PrintF("Aware %s", Chr[index].ScriptAware);
	DDrConsole_PrintF("Alarm %s", Chr[index].ScriptAlarm);
	DDrConsole_PrintF("Hurt %s", Chr[index].ScriptHurt);
	DDrConsole_PrintF("Defeat %s", Chr[index].ScriptDefeat);
	DDrConsole_PrintF("NoAmmo %s", Chr[index].ScriptNoAmmo);
	DDrConsole_PrintF("NoPath %s", Chr[index].ScriptNoPath);
	*/
	ret->val.value_int32 = Chr[index].RegenHax;
	ret->type = sl_int32;

	if (numargs >= 2) {
		Chr[index].RegenHax = args[1].val.value_int32;
	}
	return 0;
}

//wow this is broken.
uint16_t ONICALL bsl_distance(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret) {
	int index;
	int index2;
	Character* Chr = ONgGameState->CharacterStorage;
	Character* Char1;
	Character* Char2;

	if (numargs < 2) return 1;

	if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	if (index == -1) index = args[0].val.value_int32;

	if (args[1].type == sl_str32) index2 = DDrGetCharacterIndexFromName(args[1].val.value_str32);
	else index2 = args[1].val.value_int32;
	if (index2 == -1) index2 = args[1].val.value_int32;
		Char1 = &Chr[index];
	Char2 = &Chr[index2];


	ret->val.value_float = sqrt( pow((Char1->Location.X - Char2->Location.X), 2) + pow((Char1->Location.Y - Char2->Location.Y), 2) + pow((Char1->Location.Z - Char2->Location.Z),2));
	ret->type = sl_float;
	return 0;
}
uint16_t ONICALL bsl_location(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret) {
	int index, i;
	float* loc;
	Character* Chr;
		numargs = 0;
	for(i = 0; args[i].type < sl_void; i++)
	{
		numargs++;
	}


	if (numargs < 2) return 1;
	if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	if (index == -1) index = args[0].val.value_int32;
	Chr = ONgGameState->CharacterStorage;
	if(numargs == 3)
	{
		if (!strcmp(args[1].val.value_str32,"X") || !strcmp(args[1].val.value_str32,"x"))
			loc = &(Chr[index].Position.X);
		else if (!strcmp(args[1].val.value_str32,"Y") || !strcmp(args[1].val.value_str32,"y"))
			loc = &(Chr[index].Position.Y);
		else if (!strcmp(args[1].val.value_str32,"Z") || !strcmp(args[1].val.value_str32,"z"))
			loc = &(Chr[index].Position.Z);
	}
	else if (numargs == 4) {
		ActiveCharacter* Active = (ActiveCharacter*)ONrGetActiveCharacter(&Chr[index]);
		Chr[index].Location.X = args[1].val.value_float;
		Chr[index].Location.Y = args[2].val.value_float;
		Chr[index].Location.Z = args[3].val.value_float;
		if(Active)
		{
			Active->PhyContext->Position = Chr[index].Location;
		}
		ret->val.value_float = 1;
		ret->type = sl_float;
		return 0;
	}
	else return 1;
	
	ret->val.value_float = *loc;
	ret->type = sl_float;
	
	if(numargs == 3) {
		//currently broken, does nothing.
		*loc = args[2].val.value_float;
	}
	return 0;
}

uint16_t ONICALL bsl_maxhealth(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	if (argumentEmpty(&args[0])) index = 0;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	if(1) {
	Character* Chr = ONgGameState->CharacterStorage ;
	int* maxhealth = &Chr[index].MaxHealth;
	int oldmaxhealth = Chr[index].MaxHealth;
	int oldhealth = Chr->Health;
	if (numargs >= 2) {
		*maxhealth = args[1].val.value_int32;
	}
	if (numargs >= 3 && args[2].val.value_bool) {
		Chr->Health = (int)(((float)args[1].val.value_int32 / (float)oldmaxhealth) * (float)oldhealth);
	}
	ret->val.value_int32 = oldmaxhealth;
	ret->type = sl_int32;
	return 0;
	}
}

uint16_t ONICALL bsl_getattacker(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	//broken
	
	int index;
	if (argumentEmpty(&args[0])) index = 0;
	else	if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	if(1) {
	Character* Chr = ONgGameState->CharacterStorage;
	ActiveCharacter* Active = (ActiveCharacter*)ONrGetActiveCharacter(&Chr[index]);
	if (!Active) return 1;
//	ret->val.value_int32 = Active->LastDamageSourceCharacter;
	ret->type = sl_int32;
	return 0;
	} 
}



uint16_t ONICALL bsl_chrname(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	int index;
	char* name;

	if (argumentEmpty(&args[0])) index = 0;
	else if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;
	if (index == -1) {
		ret->type = sl_str32;
		ret->val.value_str32 = "NULL";
		return 0;
	}
	name = (char*)(&ONgGameState->CharacterStorage[index].Name);
	if (numargs == 2) {
		strncpy(name, (char*)args[1].val.value_str32, 31);
	}
	
	ret->type = sl_str32;
	ret->val.value_str32 = name;
	
	return 0;
}


uint16_t ONICALL bsl_count(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	//testing numargs...
	ret->type = sl_int32;
	ret->val.value_int32 = numargs;
	return 0;
}

uint16_t ONICALL bsl_dprintcolored(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	//TODO: figure out why our implementation of dprint shows after dev mode is turned off
	RGBA color;
	RGBA shade;
	int i;
	numargs = 0;
	for(i = 0; args[i].type < sl_void; i++)
	{
		numargs++;
	}
	if(argumentEmpty(&args[0])) return 0;
	if(numargs > 1 ) color.R = (char)args[1].val.value_int32;
	else color.R = 255;
	if(numargs > 2 ) color.G = (char)args[2].val.value_int32;
	else color.G = 255;
	if(numargs > 3 ) color.B = (char)args[3].val.value_int32;
	else color.B = 255;
	color.A = 0;
	if(numargs > 5 ) shade.R = (char)args[5].val.value_int32;
	else shade.R = 0x3F;
	if(numargs > 6 ) shade.G = (char)args[6].val.value_int32;
	else shade.G = 0x3F;
	if(numargs > 7 ) shade.B = (char)args[7].val.value_int32;
	else shade.B = 0x3F;
	shade.A = 0; 

	DDrConsole_PrintColored(args[0].val.value_str32, 1, color, shade);
	return 0;
}


uint16_t ONICALL bsl_nametoindex(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{

	ret->type = sl_int32;
	ret->val.value_int32 = DDrGetCharacterIndexFromName(args[0].val.value_str32);

	return 0;
}

typedef struct {
char Name[16];
uint64_t Bit;
} KeyBit;

static KeyBit Actions[] = {
	{"Escape", Action_Escape},
	{"Console", Action_Console},
	{"PauseScreen", Action_PauseScreen},
	{"Cutscene1", Action_Cutscene_1                },
	{"Cutscene2", Action_Cutscene_2                },
	{"F4", Action_F4                      },
	{"F5", Action_F5                        },
	{"F6", Action_F6                       },
	{"F7", Action_F7                        },
	{"F8", Action_F8                        },
	{"StartRecord", Action_StartRecord        },
	{"StopRecord", Action_StopRecord            },
	{"PlayRecord", Action_PlayRecord              },
	{"F12", Action_F12                       },
	{"LookMode", Action_LookMode           },
	{"Screenshot", Action_Screenshot         },
	{"Forward", Action_Forward                 },
	{"Backward", Action_Backward                },
	{"TurnLeft", Action_TurnLeft                },
	{"TurnRight", Action_TurnRight               },
	{"StepLeft", Action_StepLeft                },
	{"StepRight", Action_StepRight               },
	{"Jump", Action_Jump                    },
	{"Crouch", Action_Crouch                  },
	{"Punch",Action_Punch                   },
	{"Kick", Action_Kick                    },
	{"Block", Action_Block                   },
	{"Walk", Action_Walk},
	{"Action", Action_Action},
	{"Hypo", Action_Hypo},
	{"Reload", Action_Reload                },
	{"Swap", Action_Swap                },
	{"Drop", Action_Drop                     },
	{"Fire1", Action_Fire1                       },
	{"Fire2", Action_Fire2                       },
	{"Fire3", Action_Fire3                       }
};

uint16_t ONICALL bsl_holdkey(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	uint32_t index;
	uint32_t i = 2;
	uint32_t j = 0;
	uint64_t Input = 0;
	Character* Chr;
	ActiveCharacter* Active;
	if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
	else index = args[0].val.value_int32;

	Chr = &(ONgGameState->CharacterStorage[index]);
	Active = ONrGetActiveCharacter(Chr);
	if (!Active) return 1;

	for(i = 1; i < numargs - 1; i++) {
		for(j = 0; j < 32; j++) {
			if(!strcmp(args[i].val.value_str32, Actions[j].Name)) {
				Input = Input | Actions[j].Bit;
			}
		}
	}
	Active->Input.ActionsDown = Active->Input.ActionsDown | Input;
	if( Input == 0 ) {
		DDrConsole_PrintF("Func \"%s\", File \"%s\", Line %d: semantic error, \"%s\": No valid keys given.", callinfo->name, callinfo->calllocation, callinfo->linenumber, callinfo->name);
		return 0;
	}
	if (  args[numargs - 1].val.value_int32 <= 0) {
		return 0;
	}
	else {
		 args[numargs - 1].val.value_int32 -= 1;
		*dontuse2 = 1;
		*dontuse1 = 1;
	}
	return 0;
}
	
uint16_t ONICALL bsl_isheld(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
	{
//		int index;
//		if (numargs < 4) index = 0;
//		else	if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
//		else index = args[0].val.value_int32;

//		Character* Chr = ONgGameState->CharacterStorage;
//	ActiveCharacter* Active = (ActiveCharacter*)ONrGetActiveCharacter(&Chr[index]);
//	if ((int)Active == 0) return 1;
	uint32_t i = 2;
	uint32_t j = 0;
	uint64_t Input = 0;
	for(i = 0; i < numargs; i++) {
		for(j = 0; j < 32; j++) {
			//DDrConsole_PrintF("Testing %s against %s 0x%x", args[i].val.value_str32, Actions1[j].Name, Actions1[j].Bit);
			if(!strcmp(args[i].val.value_str32, Actions[j].Name)) {
				Input = Input | Actions[j].Bit;
				//DDrConsole_PrintF("Success!");
			}

		}
		}
	//DDrConsole_PrintF("Testing: 0x%x Input: 0x%x",Input1, *(int*)(ONgGameState + 0xB8 + 0x10));
	ret->val.value_int32 = 0;
	ret->type = sl_int32;
	if (ONgGameState->Input.ActionsDown == Input) ret->val.value_int32 = 1;
	return 0;
}

uint16_t ONICALL bsl_waitforkey(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
	{
//		int index;
//		if (numargs < 4) index = 0;
//		else	if (args[0].type == sl_str32) index = DDrGetCharacterIndexFromName(args[0].val.value_str32);
//		else index = args[0].val.value_int32;

//		Character* Chr = ONgGameState->CharacterStorage;
//	ActiveCharacter* Active = (ActiveCharacter*)ONrGetActiveCharacter(&Chr[index]);
//	if ((int)Active == 0) return 1;

	int i = 2;
	int j = 0;
	uint64_t Input = 0;
/*
	numargs = 0;
	for(i = 0; args[i].type <= sl_void; i++)
	{
		//DDrConsole_PrintF("%i", args[i].type );
		numargs++;

	}
	if(numargs < 1 || args[0].val.value == 0)  return;
	//for(i = 0; i < numargs; i++) {
	*/
	i = 0;
		for(j = 0; j < 32; j++) {
			//DDrConsole_PrintF("Testing %s against %s 0x%x", args[i].val.value_str32, Actions1[j].Name, Actions1[j].Bit);
			if(!strcmp(args[i].val.value_str32, Actions[j].Name)) {
				Input = Input | Actions[j].Bit;
				//DDrConsole_PrintF("Success!");
			}

		}
	//	}
	DDrConsole_PrintF("Waiting...");
	if (( ONgGameState->Input.ActionsDown & Input) == Input)
	{
	DDrConsole_PrintF("Found key!");
	}
	else {
	//else (int)*ret = 1;
	*dontuse2 = 1;
	*dontuse1 = 1;
	}
	return 0;
}


uint16_t ONICALL bsl_sprintf(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	char output[1024];
	char buffer[1024];
	unsigned int i;
	char* placeinoutput = output;
	char* placeininput = args[0].val.value_str32;
	int formatnum = 0;
	//fix the broken bsl numargs...
	numargs = 0;
	
	for(i = 0; args[i].type < sl_void; i++)
	{
		numargs++;
	}
	
	
	if (numargs < 1)
		return 1;
	
	while(1)
	{
		int size;
		//s is the pointer to the args
		char* s = strchr(placeininput , '%');
		//we didnt find a %, break!
		if(!s)
		{
			strcpy(placeinoutput, placeininput);
			break;
		}
		size = (int)s - (int)placeininput ;
		//we found one, so copy the portion of string
		

		
		memcpy( placeinoutput,placeininput, size);
		placeininput += size;
		placeinoutput += size;

		memset( placeinoutput, '%', (int)pow(2, formatnum));
		placeinoutput += (int)pow(2, formatnum);


		placeininput += 1;
		*placeinoutput = 0;
		formatnum++;
		
	}

	for(i = 1; i < numargs; i++)	{
		//sprintf(output, output, args[i].value_str32);
		memcpy(buffer, output, 1024);
		if(args[i].val.value == 0) break;
		switch(args[i].type)
		{
		case sl_bool:
		case sl_int32:
			sprintf(output, buffer, args[i].val.value_int32);
			break;
		case sl_float:
			sprintf(output, buffer, args[i].val.value_float);
			break;
		case sl_str32:
			sprintf(output, buffer, args[i].val.value_str32);
			break;
		case sl_void:
		default:
			break;
		}	
	}
	ret->val.value_str32 = output;
	ret->type = sl_str32;
	return 0;
}

// Widescreen patch for talking heads.
uint16_t ONICALL cinematic_start_patch(sl_callinfo* callinfo, unsigned int numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	args[1].val.value_int32 = (double)args[1].val.value_int32 / (double)(gl->DisplayMode.Width) * (4.0 / 3.0 * (double)(gl->DisplayMode.Height));
	// Call orig OCiCinematic_ScriptStart
	return ((sl_func)(OniExe + 0x000f3830))(callinfo, numargs, args, dontuse1, dontuse2, ret);
}

void ONICALL SLrDaodan_Register_ReturnType(char* name, char* desc, char* argfmt, sl_type type, sl_func callback) {
	char argfmt2[512];
	uint16_t errornum;
	if (argfmt && strlen(argfmt) < 507) {
		sprintf(argfmt2, "%s [|]", argfmt);
		errornum = SLrScript_Command_Register_ReturnType(name, desc, argfmt2, type, callback);
		if(errornum)
		{
			STARTUPMESSAGE("Registration of script command %s failed with error %i", name, errornum);
		}
	} else {
		STARTUPMESSAGE("Registration of script command %s failed because of a too long argfmt", name);
	}
}

void* TSrTest = 0;
uint16_t ONICALL new_text(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret)
{
	void* TSFFTahoma;

	if(!TSrTest){
		TMrInstance_GetDataPtr( 'TSFF', "Tahoma", &TSFFTahoma);
		TSrContext_New( TSFFTahoma, 7, 1, 1,  0, &TSrTest);
	}
	DDrPatch_MakeCall((void*)0x004FBCEA, (void*)DDrText_Hook);
	
	*dontuse2 = 1;
	return 0;
}

void SLrDaodan_Initialize()
{
// 	SLrConfig();

	SLrScript_Command_Register_Void("debug_daodan","Adds text to screen", "", new_text);

	SLrScript_Command_Register_ReturnType("int32mul", "Multiplies two numbers", "n1:int n2:int", sl_int32, bsl_int32mul);
	SLrScript_Command_Register_ReturnType("mul", "Multiplies two numbers", "[int1:int|float1:float] [int2:int|float2:float]", sl_float, bsl_mul);
	SLrScript_Command_Register_ReturnType("int32div", "Divides two numbers", "n1:int n2:int", sl_int32, bsl_int32div);
	SLrScript_Command_Register_ReturnType("div", "Divides two numbers", "[int1:int|float1:float] [int2:int|float2:float]", sl_float, bsl_div);
	srand((uint32_t)time(NULL));
	SLrScript_Command_Register_ReturnType("int32rand", "Returns a pseudo-random number between two numbers (inclusive).", "start:int end:int", sl_int32, bsl_int32rand);
	SLrScript_Command_Register_ReturnType("d_getkills","Gets the number of kills a character has", "[ai_name:string | script_id:int] [|]", sl_int32, bsl_getkills);
	SLrScript_Command_Register_ReturnType("d_getdamage","Gets the amount of damage a character has caused", "[ai_name:string | script_id:int]", sl_int32, bsl_getdamage);
	SLrScript_Command_Register_ReturnType("d_name","Gets or sets a character's name", "[ai_name:string | script_id:int] [newname:string|]", sl_str32, bsl_chrname);
	SLrScript_Command_Register_ReturnType("d_getindex","Converts a character's name to its index", "ai_name:string", sl_int32, bsl_nametoindex);
	SLrScript_Command_Register_ReturnType("d_health","Gets or sets a character's health", "[ai_name:string | script_id:int] [newhealth:int]", sl_str32, bsl_health);
	SLrScript_Command_Register_ReturnType("d_regen","Gets or sets a character's regeneration abilities", "[ai_name:string | script_id:int] [newhealth:int]", sl_str32, bsl_regen);
	SLrScript_Command_Register_ReturnType("d_maxhealth","Gets or sets a character's maximum health", "[ai_name:string | script_id:int] [newmaxhealth:int] [scalehealth:bool]", sl_str32, bsl_maxhealth);
	SLrScript_Command_Register_ReturnType("d_powerup","Gets or sets a character's powerups", "[ai_name:string | script_id:int] powerup:string", sl_int32, bsl_powerup);
	//d_holdkey is broken!
	SLrScript_Command_Register_ReturnType("d_holdkey","Makes a character hold a key", "[ai_name:string | script_id:int] frames:int keys:string", sl_int32, bsl_holdkey);
	SLrScript_Command_Register_ReturnType("d_isheld","Checks if player is holding a key", "[ai_name:string | script_id:int] [keys:string]", sl_int32, bsl_isheld);
	SLrScript_Command_Register_ReturnType("d_location","Returns the X, Y or Z coord of a character", "", sl_float, bsl_location);
	SLrScript_Command_Register_ReturnType("d_distance","Returns the distance between two characters", "ai_name:string | script_id:int ai_name:string | script_id:int", sl_float, bsl_distance);
	SLrScript_Command_Register_Void("d_waitforkey","Waits for a keypress from the player", "key:string", bsl_waitforkey);

	//broken, only works for one damage type.
	//SLrDaodan_Register_ReturnType("d_getattacker","Gets the last person to hurt a character", "[ai_name:string | script_id:int]", sl_int32, bsl_getattacker);
	
	//used for debugging.
//	SLrDaodan_Register_ReturnType("d_active","Returns a hex offset. ;)", "[ai_name:string | script_id:int]", sl_int32, bsl_getactiveoffset);

	SLrScript_Command_Register_Void("sprintf", "C-style sprintf.", "", bsl_sprintf);
	SLrScript_Command_Register_ReturnType("st", "Prints to console in color", "", sl_void, bsl_dprintcolored);
	SLrScript_Command_Register_ReturnType("d_dprint", "Prints to console in color", "", sl_void, bsl_dprintcolored);

	SLrGlobalVariable_Register_Int32("show_triggervolumes", "Show trigger volumes", &OBJgTriggerVolume_Visible);
}

// Patch for cinematic_start to work on widescreen resolutions
void SLrDaodan_Patch()
{
	// PUSH OCiCinematic_ScriptStart -> PUSH cinematic_start_patch
	DDrPatch_Int32((int*)(OniExe + 0x000f3755), (int)cinematic_start_patch);
}
