// Resident Evil 5 Autosplitter Version 2.2.0 (02/05/2023)
// Supports LRT
// Supports all difficulties
// Splits can be obtained from https://www.speedrun.com/re5/resources
// Script and Remodification by Mysterion06, TheDementedSalad
// Area codes found and added by Asterxyx
// Pointers by Dread, Austin "Auddy" Davenport, Wipefinger, Mysterion06, TheDementedSalad & Mattmatt

// Special thanks to 
// Everybody who has worked on this Autosplitter over the years and made it possible


state("re5dx9", "1.1.0")
{
	byte   Level: 		0xDA23D8, 0x273D0; 				// Current Level					
	byte   newCut: 		0xE2487C, 0x984, 0x2EDC, 0x4; 			// Gamestate - 2 in game, 4 in cutscenes, 3 in shops, 0 loading screens
	byte   isPaused: 	0xE2487C, 0x984, 0x2EDC, 0x3D; 			// 8 paused, 0 unpaused	
	byte   menu: 		0xDA2970, 0x84, 0x4BC, 0x3A4;			// 1 main menu, 6 in game, 3 in shop (Makes sure timer doesn't count in main menu)
	byte   QTE:		0xDA1934, 0x2F8;				// Checks if a QTE prompt is active, 0 when no prompt, 1 when prompt.
	byte   areaCode: 	0xDA23D8, 0x273D8;				// Current area code, 100 beginning of 1-1, 115 when getting guns, 116 first majini attack
	ushort HP: 		0xE243B4, 0xEC, 0x1364;				// Char HP	
	int    P1ItemID: 	0xDA1934, 0xEBC;				// Player 1's latest item pickup ID
	int    P2ItemID: 	0xDA1934, 0xF38;				// Player 2's latest item pickup ID (DLC)
	int    keyItem: 	0xDA2970, 0x84, 0x18;				// Latest picked up key item (doesn't change on checkpoint reset)
	float  IGT: 		0xDA23D8, 0x273F8;				// Gametime
	float  PauseBuff: 	0xDA1F8C, 0x53C;				// 0.5 paused in game, 0 in shops, 1 in cutscenes (Catches any time bleed between pauses)
	byte   Cutscene:	0xDA1934, 0xDB8;				// 1 Cutscene 0 no Cutscene
}

state("re5dx9", "1.2.0")
{
	byte   Level: 		0xDB2158, 0x273D0; 															
	byte   newCut: 		0xE34578, 0x984, 0x2EDC, 0x4; 			
	byte   isPaused: 	0xE34578, 0x984, 0x2EDC, 0x3D; 			
	byte   menu: 		0xDB26F0, 0x84, 0x4BC, 0x5E4;			
	byte   QTE:		0xDB1794, 0x338;						
	byte   areaCode: 	0xDB2158, 0x273D8;
	ushort HP: 		0xE340B0, 0xEC, 0x1364;		
	int    P1ItemID: 	0xDB1794, 0xEFC;						
	int    P2ItemID: 	0xDB1794, 0xF78;						
	int    keyItem: 	0xDB26F0, 0x84, 0x18;					
	float  IGT: 		0xDB2158, 0x273F8;						
	float  PauseBuff: 	0xDB1D0C, 0x53C;					    
	byte   Cutscene:	0xDB1794, 0xDF8;
}

init
{
	switch (modules.First().ModuleMemorySize) 
    {
        case 16109568: 
            version = "1.1.0";
            break;
	case 26210304: 
	case 26382336: 
            version = "1.2.0";
            break;
		default:
			print("Unknown version detected");
			return false;
    }
}

startup
{	
	vars.LvlStorage = new List<int>()
	{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

	vars.CAC = new List<int>()
    {118,103,119,109,94,200,201,204,205,57,102,46,97,244,101,247,250,252,99};

    vars.OAC = new List<int>()
    {103,106,108,111,94,202,209,95,205,45,102,53,97,245,101,100,98,252};

	vars.completedSplits = new List<string>();
	vars.totalGameTime = 0;
	
	settings.Add("Time", false, "Timing Methods");
	settings.CurrentDefaultParent = "Time";
	settings.Add("LRT", false, "Load Remover Time");
	settings.Add("IGT", false, "In Game Time (Legacy, can't be submitted)");
	settings.CurrentDefaultParent = null;
	
	settings.Add("Main", false, "Main Game Extras");
	settings.CurrentDefaultParent = "Main";
	settings.Add("No1-1", false, "Enable No 1-1");
	settings.Add("IL", false, "Enable Individual Levels");
	settings.CurrentDefaultParent = null;

	settings.Add("Split", false, "Main Game Splits");
	settings.CurrentDefaultParent = "Split";
	settings.Add("Chapter", false, "Chapter Splits");
	settings.Add("Area", false, "Area Splits");
	
	settings.Add("DLC", false, "Enable DLC's & Item Splits");
	settings.CurrentDefaultParent = "DLC";
	settings.Add("LiN", false, "Lost in Nightmares");
	settings.CurrentDefaultParent = "LiN";
	settings.Add("1316", false, "Password 3");
	settings.Add("1314", false, "Password 1");
	settings.Add("1313", false, "Centaur Emblem");
	settings.Add("1320", false, "Heat-Sensitive Paper");
	settings.Add("1315", false, "Password 2");
	settings.Add("1312", false, "Square Crank");
	settings.Add("1317", false, "Jail Key");
	settings.Add("1318", false, "Gold Crest");
	settings.Add("1319", false, "Silver Crest");
	settings.Add("1327", false, "Crank (Red)");
	settings.Add("1328", false, "Crank (Blue)");
	settings.Add("1329", false, "Crank (Violet)");
	settings.Add("1330", false, "Crank (Green)");
	settings.Add("1323", false, "Sun Eater Serpent Shard");
	settings.Add("1324", false, "Dual-Head Serpent Shard");
	settings.Add("1325", false, "Serpent Tail Shard");
	settings.Add("1326", false, "Tri-Head Serpent Shard");
	settings.Add("LiNEnd", true, "Final Split LiN (Always Active)");
	settings.CurrentDefaultParent = "DLC";
	settings.Add("DE", false, "Desperate Escape");
	settings.CurrentDefaultParent = "DE";
	settings.Add("1321", true, "Transport Area Key");
	settings.Add("1322", true, "Emergency Exit Key");
	settings.Add("DEEnd", true, "Final Split DE (Always Active)");
	settings.CurrentDefaultParent = null;
	
}

update{
    if (timer.CurrentPhase == TimerPhase.NotRunning)
    {
		vars.completedSplits.Clear();
		vars.totalGameTime = 0;
    }
	
	//print(modules.First().ModuleMemorySize.ToString());
}

start
{
	return vars.LvlStorage.Contains(current.Level) && current.IGT > old.IGT && current.newCut == 2;
}

split
{
	if(current.QTE == 0 && old.QTE == 1 && current.Cutscene == 1 && current.areaCode == 252){
		return true;
	}
	
	if(settings ["Chapter"] && current.newCut == 7 && old.newCut != 7){
		return true;
	}
	
	if(settings ["Area"]){
		if(vars.CAC.Contains(current.areaCode) && vars.OAC.Contains(old.areaCode)){
            return false;
        }

        else if(current.areaCode != old.areaCode){
            return true;
        }
	}
		
	if(settings ["DLC"]){
		vars.hashString = current.keyItem.ToString();
	
		if (current.keyItem == current.P1ItemID || current.keyItem == current.P2ItemID || current.keyItem == 1315){
			if (settings[vars.hashString] && !vars.completedSplits.Contains(vars.hashString))
			{
				vars.completedSplits.Add(vars.hashString);
				return true;
			}
		}
	}
}
	
isLoading
{
	if(settings["LRT"]){
		// Stops the timer in cutscenes and loading screens. Keeps running in shops and gameplay.
		if(current.newCut == 3 && current.HP != 0 || current.newCut != 2 && current.newCut != 3 && current.HP != 0 || current.menu == 1 || current.isPaused == 8 && current.newCut != 3 || current.PauseBuff != 1 && current.IGT == old.IGT || current.newCut == 7){
			return true;
		}
		
		else{
			return false;
		
		}
	}
	
	if(settings["IGT"]){
		return true;
	}
}

gameTime
{
	if(settings["IGT"]){
		if(current.IGT > old.IGT){
			return TimeSpan.FromSeconds(System.Math.Floor(vars.totalGameTime + current.IGT));
		}
		if(current.IGT == 0 && current.Level != old.Level){
			vars.totalGameTime = System.Math.Floor(vars.totalGameTime + old.IGT);
			return TimeSpan.FromSeconds(System.Math.Floor(vars.totalGameTime + current.IGT));
		}
	}
		
	if(settings["IGT"] && settings["IL"]){
		return TimeSpan.FromSeconds(current.IGT);
	}
	if(settings["IGT"] && settings["DLC"]){
			return TimeSpan.FromSeconds(System.Math.Floor(vars.totalGameTime + current.IGT));
	}
}

reset
{
	if(current.Level == 0 && current.IGT == 0 && current.newCut == 2 && current.menu != 1){
		return true;
	}
	
	if(settings["No1-1"]){
		return current.Level == 1 && current.areaCode == 114 && current.IGT > 0 && old.IGT == 0;
	}
	
	if(settings["IL"]){
		return vars.LvlStorage.Contains(current.Level) && current.IGT > old.IGT && old.IGT == 0 && current.newCut == 2;
	}
}