diff --git a/debotc_defs.bts b/debotc_defs.bts new file mode 100644 index 0000000..0612f4c --- /dev/null +++ b/debotc_defs.bts @@ -0,0 +1,181 @@ +#!botc 1.0 + +// This file defines the functions and events for botc +// Do not edit unless you know what you are doing! + +// ============================================================================= +// +// Function definitions +// Syntax: funcdef : () +// +funcdef void 0:changestate (int newstate); +funcdef void 1:delay (int tics); +funcdef int 2:random (int a, int b); +funcdef int 3:StringsAreEqual (str string1, str string2); +funcdef int 4:LookForPowerups (int start, int visibilitycheck); +funcdef int 5:LookForWeapons (int start, int visibilitycheck); +funcdef int 6:LookForAmmo (int start, int visibilitycheck); +funcdef int 7:LookForBaseHealth (int start, int visibilitycheck); +funcdef int 8:LookForBaseArmor (int start, int visibilitycheck); +funcdef int 9:LookForSuperHealth (int start, int visibilitycheck); +funcdef int 10:LookForSuperArmor (int start, int visibilitycheck); +funcdef int 11:LookForPlayerEnemies (int start); +funcdef int 12:GetClosestPlayerEnemy(); +funcdef void 13:MoveLeft (int speed); +funcdef void 14:MoveRight (int speed); +funcdef void 15:MoveForward (int speed); +funcdef void 16:MoveBackwards (int speed); +funcdef void 17:StopMovement(); +funcdef void 18:StopForwardMovement(); +funcdef void 19:StopSidewaysMovement(); +funcdef int 20:CheckTerrain (int distance, int angle); +funcdef int 21:PathToGoal (int speed); +funcdef int 22:PathToLastKnownEnemyPosition (int speed); +funcdef int 23:PathToLastHeardSound (int speed); +funcdef int 24:Roam (int speed); +funcdef int 25:GetPathingCostToItem (int item); +funcdef int 26:GetDistanceToItem (int item); +funcdef str 27:GetItemName (int item); +funcdef int 28:IsItemVisible (int item); +funcdef void 29:SetGoal (int item); +funcdef void 30:BeginAimingAtEnemy(); +funcdef void 31:StopAimingAtEnemy(); +funcdef void 32:Turn (int turnangle); +funcdef int 33:GetCurrentAngle(); +funcdef void 34:SetEnemy (int player); +funcdef void 35:ClearEnemy(); +funcdef int 36:IsEnemyAlive(); +funcdef int 37:IsEnemyVisible(); +funcdef int 38:GetDistanceToEnemy(); +funcdef int 39:GetPlayerDamagedBy(); +funcdef int 40:GetEnemyInvulnerabilityTicks(); +funcdef void 41:FireWeapon(); +funcdef void 42:BeginFiringWeapon(); +funcdef void 43:StopFiringWeapon(); +funcdef str 44:GetCurrentWeapon(); +funcdef void 45:ChangeWeapon (str weapon); +funcdef str 46:GetWeaponFromItem (int item); +funcdef int 47:IsWeaponOwned (int item); +funcdef int 48:IsFavoriteWeapon (str weapon); +funcdef void 49:Say (str message); +funcdef void 50:SayFromFile (str filename, str section); +funcdef void 51:SayFromChatFile (str section); +funcdef void 52:BeginChatting(); +funcdef void 53:StopChatting(); +funcdef int 54:ChatSectionExists (str section); +funcdef int 55:ChatSectionExistsInFile (str filename, str section); +funcdef str 56:GetLastChatString(); +funcdef str 57:GetLastChatPlayer(); +funcdef int 58:GetChatFrequency(); +funcdef void 59:Jump(); +funcdef void 60:BeginJumping(); +funcdef void 61:StopJumping(); +funcdef void 62:Taunt(); +funcdef void 63:Respawn(); +funcdef void 64:TryToJoinGame(); +funcdef int 65:IsDead(); +funcdef int 66:IsSpectating(); +funcdef int 67:GetHealth(); +funcdef int 68:GetArmor(); +funcdef int 69:GetBaseHealth(); +funcdef int 70:GetBaseArmor(); +funcdef int 71:GetBotskill(); +funcdef int 72:GetAccuracy(); +funcdef int 73:GetIntellect(); +funcdef int 74:GetAnticipation(); +funcdef int 75:GetEvade(); +funcdef int 76:GetReactionTime(); +funcdef int 77:GetPerception(); +funcdef void 78:SetSkillIncrease (int increase); +funcdef int 79:IsSkillIncreased(); +funcdef void 80:SetSkillDecrease (int decrease); +funcdef int 81:IsSkillDecreased(); +funcdef int 82:GetGameMode(); +funcdef int 83:GetSpread(); +funcdef str 84:GetLastJoinedPlayer(); +funcdef str 85:GetPlayerName (int player); +funcdef int 86:GetReceivedMedal(); +funcdef void 87:ACS_Execute (int script, int map = 0, int arg0 = 0, int arg1 = 0, int arg2 = 0); +funcdef str 88:GetFavoriteWeapon(); +funcdef void 89:SayFromLump (str lump, str section); +funcdef void 90:SayFromChatLump (str section); +funcdef int 91:ChatSectionExistsInLump (str lump, str section); +funcdef int 92:ChatSectionExistsInChatLump (str section); + +// ============================================================================= +// +// Builtin function definitions +// Syntax: funcdef : () +// +builtindef void 70:MemSet (int array, int value, int numBytes); + +// ============================================================================= +// +// Events: +// eventdef :(); +// +eventdef 0:KilledByEnemy(); +eventdef 1:KilledByPlayer(); +eventdef 2:KilledBySelf(); +eventdef 3:KilledByEnvironment(); +eventdef 4:ReachedGoal(); +eventdef 5:GoalRemoved(); +eventdef 6:DamagedByPlayer(); +eventdef 7:PlayerSay(); +eventdef 8:EnemyKilled(); +eventdef 9:Respawned(); +eventdef 10:Intermission(); +eventdef 11:NewMap(); +eventdef 12:EnemyUsedFist(); +eventdef 13:EnemyUsedChainsaw(); +eventdef 14:EnemyFiredPistol(); +eventdef 15:EnemyFiredShotgun(); +eventdef 16:EnemyFiredSSG(); +eventdef 17:EnemyFiredChaingun(); +eventdef 18:EnemyFiredMinigun(); +eventdef 19:EnemyFiredRocket(); +eventdef 20:EnemyFiredGrenade(); +eventdef 21:EnemyFiredRailgun(); +eventdef 22:EnemyFiredPlasma(); +eventdef 23:EnemyFiredBFG(); +eventdef 24:EnemyFiredBFG10k(); +eventdef 25:PlayerUsedFist(); +eventdef 26:PlayerUsedChainsaw(); +eventdef 27:PlayerFiredPistol(); +eventdef 28:PlayerFiredShotgun(); +eventdef 29:PlayerFiredSSG(); +eventdef 30:PlayerFiredChaingun(); +eventdef 31:PlayerFiredMinigun(); +eventdef 32:PlayerFiredRocket(); +eventdef 33:PlayerFiredGrenade(); +eventdef 34:PlayerFiredRailgun(); +eventdef 35:PlayerFiredPlasma(); +eventdef 36:PlayerFiredBFG(); +eventdef 37:PlayerFiredBFG10k(); +eventdef 38:UsedFist(); +eventdef 39:UsedChainsaw(); +eventdef 40:FiredPistol(); +eventdef 41:FiredShotgun(); +eventdef 42:FiredSSG(); +eventdef 43:FiredChaingun(); +eventdef 44:FiredMinigun(); +eventdef 45:FiredRocket(); +eventdef 46:FiredGrenade(); +eventdef 47:FiredRailgun(); +eventdef 48:FiredPlasma(); +eventdef 49:FiredBFG(); +eventdef 50:FiredBFG10k(); +eventdef 51:PlayerJoinedGame(); +eventdef 52:JoinedGame(); +eventdef 53:DuelStartingCountdown(); +eventdef 54:DuelFight(); +eventdef 55:DuelWinSequence(); +eventdef 56:Spectating(); +eventdef 57:LMSStartingCountdown(); +eventdef 58:LMSFight(); +eventdef 59:LMSWinSequence(); +eventdef 60:WeaponChange(); +eventdef 61:EnemyBFGExplode(); +eventdef 62:PlayerBFGExplode(); +eventdef 63:BFGExplode(); +eventdef 64:ReceivedMedal(); diff --git a/src/main/kotlin/com/github/tarcv/zandronum/debotc/BaseEvent.kt b/src/main/kotlin/com/github/tarcv/zandronum/debotc/BaseEvent.kt index d374b55..344d4f6 100644 --- a/src/main/kotlin/com/github/tarcv/zandronum/debotc/BaseEvent.kt +++ b/src/main/kotlin/com/github/tarcv/zandronum/debotc/BaseEvent.kt @@ -14,7 +14,7 @@ abstract class BaseEvent { _commands.add(command) } - abstract val readableType: String + abstract val botcTitle: String private val _commands: ArrayList = ArrayList() val commands: List @@ -26,15 +26,15 @@ abstract class BaseEvent { } class BotEvent( - val eventType: BotEventType + private val eventType: BotEventType ) : BaseEvent() { - override val readableType: String - get() = eventType.name.substring("BOTEVENT_".length).toLowerCase() + override val botcTitle: String + get() = "event \"${eventType.botcName}\"" } class WorldEvent( - val eventType: DataHeaders + private val eventType: DataHeaders ) : BaseEvent() { - override val readableType: String + override val botcTitle: String get() = eventType.name.substring("DH_".length).toLowerCase() } \ No newline at end of file diff --git a/src/main/kotlin/com/github/tarcv/zandronum/debotc/BotEventType.kt b/src/main/kotlin/com/github/tarcv/zandronum/debotc/BotEventType.kt index 81eb811..38d2241 100644 --- a/src/main/kotlin/com/github/tarcv/zandronum/debotc/BotEventType.kt +++ b/src/main/kotlin/com/github/tarcv/zandronum/debotc/BotEventType.kt @@ -1,72 +1,71 @@ package com.github.tarcv.zandronum.debotc -enum class BotEventType -{ - BOTEVENT_KILLED_BYENEMY, - BOTEVENT_KILLED_BYPLAYER, - BOTEVENT_KILLED_BYSELF, - BOTEVENT_KILLED_BYENVIORNMENT, - BOTEVENT_REACHED_GOAL, - BOTEVENT_GOAL_REMOVED, - BOTEVENT_DAMAGEDBY_PLAYER, - BOTEVENT_PLAYER_SAY, - BOTEVENT_ENEMY_KILLED, - BOTEVENT_RESPAWNED, - BOTEVENT_INTERMISSION, - BOTEVENT_NEWMAP, - BOTEVENT_ENEMY_USEDFIST, - BOTEVENT_ENEMY_USEDCHAINSAW, - BOTEVENT_ENEMY_FIREDPISTOL, - BOTEVENT_ENEMY_FIREDSHOTGUN, - BOTEVENT_ENEMY_FIREDSSG, - BOTEVENT_ENEMY_FIREDCHAINGUN, - BOTEVENT_ENEMY_FIREDMINIGUN, - BOTEVENT_ENEMY_FIREDROCKET, - BOTEVENT_ENEMY_FIREDGRENADE, - BOTEVENT_ENEMY_FIREDRAILGUN, - BOTEVENT_ENEMY_FIREDPLASMA, - BOTEVENT_ENEMY_FIREDBFG, - BOTEVENT_ENEMY_FIREDBFG10K, - BOTEVENT_PLAYER_USEDFIST, - BOTEVENT_PLAYER_USEDCHAINSAW, - BOTEVENT_PLAYER_FIREDPISTOL, - BOTEVENT_PLAYER_FIREDSHOTGUN, - BOTEVENT_PLAYER_FIREDSSG, - BOTEVENT_PLAYER_FIREDCHAINGUN, - BOTEVENT_PLAYER_FIREDMINIGUN, - BOTEVENT_PLAYER_FIREDROCKET, - BOTEVENT_PLAYER_FIREDGRENADE, - BOTEVENT_PLAYER_FIREDRAILGUN, - BOTEVENT_PLAYER_FIREDPLASMA, - BOTEVENT_PLAYER_FIREDBFG, - BOTEVENT_PLAYER_FIREDBFG10K, - BOTEVENT_USEDFIST, - BOTEVENT_USEDCHAINSAW, - BOTEVENT_FIREDPISTOL, - BOTEVENT_FIREDSHOTGUN, - BOTEVENT_FIREDSSG, - BOTEVENT_FIREDCHAINGUN, - BOTEVENT_FIREDMINIGUN, - BOTEVENT_FIREDROCKET, - BOTEVENT_FIREDGRENADE, - BOTEVENT_FIREDRAILGUN, - BOTEVENT_FIREDPLASMA, - BOTEVENT_FIREDBFG, - BOTEVENT_FIREDBFG10K, - BOTEVENT_PLAYER_JOINEDGAME, - BOTEVENT_JOINEDGAME, - BOTEVENT_DUEL_STARTINGCOUNTDOWN, - BOTEVENT_DUEL_FIGHT, - BOTEVENT_DUEL_WINSEQUENCE, - BOTEVENT_SPECTATING, - BOTEVENT_LMS_STARTINGCOUNTDOWN, - BOTEVENT_LMS_FIGHT, - BOTEVENT_LMS_WINSEQUENCE, - BOTEVENT_WEAPONCHANGE, - BOTEVENT_ENEMY_BFGEXPLODE, - BOTEVENT_PLAYER_BFGEXPLODE, - BOTEVENT_BFGEXPLODE, - BOTEVENT_RECEIVEDMEDAL, +enum class BotEventType(val botcName: String) { + BOTEVENT_KILLED_BYENEMY("KilledByEnemy"), + BOTEVENT_KILLED_BYPLAYER("KilledByPlayer"), + BOTEVENT_KILLED_BYSELF("KilledBySelf"), + BOTEVENT_KILLED_BYENVIORNMENT("KilledByEnvironment"), + BOTEVENT_REACHED_GOAL("ReachedGoal"), + BOTEVENT_GOAL_REMOVED("GoalRemoved"), + BOTEVENT_DAMAGEDBY_PLAYER("DamagedByPlayer"), + BOTEVENT_PLAYER_SAY("PlayerSay"), + BOTEVENT_ENEMY_KILLED("EnemyKilled"), + BOTEVENT_RESPAWNED("Respawned"), + BOTEVENT_INTERMISSION("Intermission"), + BOTEVENT_NEWMAP("NewMap"), + BOTEVENT_ENEMY_USEDFIST("EnemyUsedFist"), + BOTEVENT_ENEMY_USEDCHAINSAW("EnemyUsedChainsaw"), + BOTEVENT_ENEMY_FIREDPISTOL("EnemyFiredPistol"), + BOTEVENT_ENEMY_FIREDSHOTGUN("EnemyFiredShotgun"), + BOTEVENT_ENEMY_FIREDSSG("EnemyFiredSSG"), + BOTEVENT_ENEMY_FIREDCHAINGUN("EnemyFiredChaingun"), + BOTEVENT_ENEMY_FIREDMINIGUN("EnemyFiredMinigun"), + BOTEVENT_ENEMY_FIREDROCKET("EnemyFiredRocket"), + BOTEVENT_ENEMY_FIREDGRENADE("EnemyFiredGrenade"), + BOTEVENT_ENEMY_FIREDRAILGUN("EnemyFiredRailgun"), + BOTEVENT_ENEMY_FIREDPLASMA("EnemyFiredPlasma"), + BOTEVENT_ENEMY_FIREDBFG("EnemyFiredBFG"), + BOTEVENT_ENEMY_FIREDBFG10K("EnemyFiredBFG10k"), + BOTEVENT_PLAYER_USEDFIST("PlayerUsedFist"), + BOTEVENT_PLAYER_USEDCHAINSAW("PlayerUsedChainsaw"), + BOTEVENT_PLAYER_FIREDPISTOL("PlayerFiredPistol"), + BOTEVENT_PLAYER_FIREDSHOTGUN("PlayerFiredShotgun"), + BOTEVENT_PLAYER_FIREDSSG("PlayerFiredSSG"), + BOTEVENT_PLAYER_FIREDCHAINGUN("PlayerFiredChaingun"), + BOTEVENT_PLAYER_FIREDMINIGUN("PlayerFiredMinigun"), + BOTEVENT_PLAYER_FIREDROCKET("PlayerFiredRocket"), + BOTEVENT_PLAYER_FIREDGRENADE("PlayerFiredGrenade"), + BOTEVENT_PLAYER_FIREDRAILGUN("PlayerFiredRailgun"), + BOTEVENT_PLAYER_FIREDPLASMA("PlayerFiredPlasma"), + BOTEVENT_PLAYER_FIREDBFG("PlayerFiredBFG"), + BOTEVENT_PLAYER_FIREDBFG10K("PlayerFiredBFG10k"), + BOTEVENT_USEDFIST("UsedFist"), + BOTEVENT_USEDCHAINSAW("UsedChainsaw"), + BOTEVENT_FIREDPISTOL("FiredPistol"), + BOTEVENT_FIREDSHOTGUN("FiredShotgun"), + BOTEVENT_FIREDSSG("FiredSSG"), + BOTEVENT_FIREDCHAINGUN("FiredChaingun"), + BOTEVENT_FIREDMINIGUN("FiredMinigun"), + BOTEVENT_FIREDROCKET("FiredRocket"), + BOTEVENT_FIREDGRENADE("FiredGrenade"), + BOTEVENT_FIREDRAILGUN("FiredRailgun"), + BOTEVENT_FIREDPLASMA("FiredPlasma"), + BOTEVENT_FIREDBFG("FiredBFG"), + BOTEVENT_FIREDBFG10K("FiredBFG10k"), + BOTEVENT_PLAYER_JOINEDGAME("PlayerJoinedGame"), + BOTEVENT_JOINEDGAME("JoinedGame"), + BOTEVENT_DUEL_STARTINGCOUNTDOWN("DuelStartingCountdown"), + BOTEVENT_DUEL_FIGHT("DuelFight"), + BOTEVENT_DUEL_WINSEQUENCE("DuelWinSequence"), + BOTEVENT_SPECTATING("Spectating"), + BOTEVENT_LMS_STARTINGCOUNTDOWN("LMSStartingCountdown"), + BOTEVENT_LMS_FIGHT("LMSFight"), + BOTEVENT_LMS_WINSEQUENCE("LMSWinSequence"), + BOTEVENT_WEAPONCHANGE("WeaponChange"), + BOTEVENT_ENEMY_BFGEXPLODE("EnemyBFGExplode"), + BOTEVENT_PLAYER_BFGEXPLODE("PlayerBFGExplode"), + BOTEVENT_BFGEXPLODE("BFGExplode"), + BOTEVENT_RECEIVEDMEDAL("ReceivedMedal"), - NUM_BOTEVENTS + NUM_BOTEVENTS(""); } \ No newline at end of file diff --git a/src/main/kotlin/com/github/tarcv/zandronum/debotc/DataHeaders.kt b/src/main/kotlin/com/github/tarcv/zandronum/debotc/DataHeaders.kt index c7aae13..28f46a0 100644 --- a/src/main/kotlin/com/github/tarcv/zandronum/debotc/DataHeaders.kt +++ b/src/main/kotlin/com/github/tarcv/zandronum/debotc/DataHeaders.kt @@ -193,13 +193,15 @@ enum class DataHeaders(requiredArgs: Int = 0) }, DH_PUSHGLOBALVAR { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return LiteralNode("global${command.arguments[0]}", ADDS_TO_NORMAL_STACK) + vmState.defineGlobalVariable(command.arguments[0]) + return LiteralNode("\$global${command.arguments[0]}", ADDS_TO_NORMAL_STACK) } }, DH_PUSHLOCALVAR { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return LiteralNode("local${command.arguments[0]}", ADDS_TO_NORMAL_STACK) + vmState.defineStateVariable(command.arguments[0]) + return LiteralNode("\$local${command.arguments[0]}", ADDS_TO_NORMAL_STACK) } }, @@ -220,82 +222,98 @@ enum class DataHeaders(requiredArgs: Int = 0) }, DH_INCGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CommandNode("global${command.arguments[0]}++;") + vmState.defineGlobalVariable(command.arguments[0]) + return CommandNode("\$global${command.arguments[0]}++;") } }, DH_DECGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CommandNode("global${command.arguments[0]}--;") + vmState.defineGlobalVariable(command.arguments[0]) + return CommandNode("\$global${command.arguments[0]}--;") } }, DH_ASSIGNGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "global${command.arguments[0]} = ${stackArgs[0]};" } + vmState.defineGlobalVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$global${command.arguments[0]} = ${stackArgs[0]};" } } }, DH_ADDGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "global${command.arguments[0]} += ${stackArgs[0]};" } + vmState.defineGlobalVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$global${command.arguments[0]} += ${stackArgs[0]};" } } }, DH_SUBGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "global${command.arguments[0]} -= ${stackArgs[0]};" } + vmState.defineGlobalVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$global${command.arguments[0]} -= ${stackArgs[0]};" } } }, DH_MULGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "global${command.arguments[0]} *= ${stackArgs[0]};" } + vmState.defineGlobalVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$global${command.arguments[0]} *= ${stackArgs[0]};" } } }, DH_DIVGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "global${command.arguments[0]} /= ${stackArgs[0]};" } + vmState.defineGlobalVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$global${command.arguments[0]} /= ${stackArgs[0]};" } } }, DH_MODGLOBALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "global${command.arguments[0]} %= ${stackArgs[0]};" } + vmState.defineGlobalVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$global${command.arguments[0]} %= ${stackArgs[0]};" } } }, DH_INCLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(0, DONT_PUSHES_TO_STACK) { "local${command.arguments[0]}++;" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(0, DONT_PUSHES_TO_STACK) { "\$local${command.arguments[0]}++;" } } }, DH_DECLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(0, DONT_PUSHES_TO_STACK) { "local${command.arguments[0]}--;" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(0, DONT_PUSHES_TO_STACK) { "\$local${command.arguments[0]}--;" } } }, DH_ASSIGNLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "local${command.arguments[0]} = ${stackArgs[0]};" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$local${command.arguments[0]} = ${stackArgs[0]};" } } }, DH_ADDLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "local${command.arguments[0]} += ${stackArgs[0]};" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$local${command.arguments[0]} += ${stackArgs[0]};" } } }, DH_SUBLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "local${command.arguments[0]} -= ${stackArgs[0]};" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$local${command.arguments[0]} -= ${stackArgs[0]};" } } }, DH_MULLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "local${command.arguments[0]} *= ${stackArgs[0]};" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$local${command.arguments[0]} *= ${stackArgs[0]};" } } }, DH_DIVLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "local${command.arguments[0]} /= ${stackArgs[0]};" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$local${command.arguments[0]} /= ${stackArgs[0]};" } } }, DH_MODLOCALVAR(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "local${command.arguments[0]} %= ${stackArgs[0]};" } + vmState.defineStateVariable(command.arguments[0]) + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "\$local${command.arguments[0]} %= ${stackArgs[0]};" } } }, DH_CASEGOTO(2) { @@ -314,47 +332,66 @@ enum class DataHeaders(requiredArgs: Int = 0) }, DH_INCGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}]++;" } + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}]++;" + } } }, DH_DECGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}]--;" } + return CustomStackConsumingNode(1, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}]--;" } } }, DH_ASSIGNGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}] = ${stackArgs[1]};" } + return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}] = ${stackArgs[1]};" } } }, DH_ADDGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}] += ${stackArgs[1]};" } + return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}] += ${stackArgs[1]};" } } }, DH_SUBGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}] -= ${stackArgs[1]};" } + return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}] -= ${stackArgs[1]};" } } }, DH_MULGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}] *= ${stackArgs[1]};" } + return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}] *= ${stackArgs[1]};" } } }, DH_DIVGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}] /= ${stackArgs[1]};" } + return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}] /= ${stackArgs[1]};" } } }, DH_MODGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}] %= ${stackArgs[1]};" } + return CustomStackConsumingNode(2, DONT_PUSHES_TO_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}] %= ${stackArgs[1]};" } } }, DH_PUSHGLOBALARRAY(1) { override fun processAndCreateNode(command: Command, vmState: VmState): BaseNode { - return CustomStackConsumingNode(1, ADDS_TO_NORMAL_STACK) { stackArgs -> "globalArray${command.arguments[0]}[${stackArgs[0]}]" } + return CustomStackConsumingNode(1, ADDS_TO_NORMAL_STACK) { stackArgs -> + vmState.defineGlobalArray(command.arguments[0]) + "\$globalArray${command.arguments[0]}[${stackArgs[0]}]" } } }, DH_SWAP{ diff --git a/src/main/kotlin/com/github/tarcv/zandronum/debotc/Decompiler.kt b/src/main/kotlin/com/github/tarcv/zandronum/debotc/Decompiler.kt index ba54136..7215320 100644 --- a/src/main/kotlin/com/github/tarcv/zandronum/debotc/Decompiler.kt +++ b/src/main/kotlin/com/github/tarcv/zandronum/debotc/Decompiler.kt @@ -9,7 +9,6 @@ import java.nio.ByteBuffer import java.nio.ByteOrder.LITTLE_ENDIAN import java.nio.file.Files import java.nio.file.Paths -import java.util.concurrent.atomic.AtomicInteger import kotlin.collections.ArrayList import kotlin.collections.HashSet import com.mxgraph.view.mxGraph @@ -35,31 +34,87 @@ class Decompiler { } private fun print() { - AtomicInteger() - states.forEach { state -> - val name = if (state.global) "" else "state ${state.name} " - val suffix = if (state.global) "" else " // ${state.index}" - println("$name{$suffix") - state.events.forEach { event -> - println("\tevent ${event.readableType}() {") - - val eventNodes = buildGraphForEvent(event) - if (eventNodes.isNotEmpty()) { - val currentNode = eventNodes[0] - compactAndPrintNodes(currentNode, "State ${state.index} - Event ${event.readableType}", - javaClass.desiredAssertionStatus() /*state.index == 1 && event.readableType == "mainloop" */) + println("#!botc 1.0.0") + println("#include \"debotc_defs.bts\"") + println() + + val globalVariables = HashSet() + val globalArrays = HashSet() + + // Have to scan for all global variables before printing + states + .map { state -> + val stateBuilder = StringBuilder() + + val stateHeader = if (state.global) "" else "state \"${state.name}\": // ${state.index}" + stateBuilder.appendln(stateHeader) + + val stateVariables = HashSet() + + // Have to scan for all global and state variables before printing + val stateScripts = state.events + .map { event -> + val eventScriptBuilder = StringBuilder() + + eventScriptBuilder.appendln("\t${event.botcTitle} {") + + val eventNodes = buildGraphForEvent(event, globalVariables, globalArrays, stateVariables) + if (eventNodes.isNotEmpty()) { + val currentNode = eventNodes[0] + val script = compactAndStringifyNodes(currentNode, "State ${state.index} - Event ${event.botcTitle}", + javaClass.desiredAssertionStatus()) + eventScriptBuilder.appendln(script) + } + + eventScriptBuilder.appendln("\t}") + } + .fold(initBlockForState(stateVariables)) { acc, script -> + acc.appendln(script) + } + stateBuilder.appendln(stateScripts) + + stateBuilder.appendln() + } + .let { + printBlockForGlobal(globalVariables, globalArrays) + println() + it } + .forEach { + println(it) + } + } - println("\t}") - } - println("}") - } + private fun initBlockForState(stateVariables: Set): StringBuilder { + return stateVariables + .sorted() + .map { "\tvar int \$local$it;" } + .fold(StringBuilder()) { acc, variables -> + acc.appendln(variables) + } + .appendln() } - private fun compactAndPrintNodes(rootNode: BaseNode, title: String, drawGraph: Boolean): Boolean { + private fun printBlockForGlobal(globalVariables: Set, globalArrays: Set) { + globalVariables + .sorted() + .forEach { + println("var int \$global$it;") + } + globalArrays + .sorted() + .forEach { + println("var int \$globalArray$it[];") + } + } + + private fun compactAndStringifyNodes(rootNode: BaseNode, title: String, drawGraph: Boolean): String { lateinit var origGraph: JFrame lateinit var optimizedGraph: JFrame lateinit var textGraph: JFrame + + var scriptText = "" + if (drawGraph) { origGraph = showGraph(rootNode, "$title - From bytes") } @@ -86,8 +141,7 @@ class Decompiler { assert(rootNode.nextNode.inputs.size == 1) assert(rootNode.nextNode.outputs.size == 0 || rootNode.nextNode.outputs.size == 1) if (rootNode.nextNode.outputs.size == 1) { - val code = (rootNode.nextNode as TextNode).asText.replace(Regex("^", MULTILINE), "\t\t") - println(code) + scriptText = (rootNode.nextNode as TextNode).asText.replace(Regex("^", MULTILINE), "\t\t") assert(rootNode.nextNode.nextNode is EndNode) } else { assert(rootNode.nextNode is EndNode) @@ -101,7 +155,7 @@ class Decompiler { origGraph.dispose() } - return wasAtLeastOneChange + return scriptText } private fun packToTextNodes(node: BaseNode): Boolean { @@ -321,9 +375,15 @@ class Decompiler { } } - private fun buildGraphForEvent(event: BaseEvent): ArrayList { + private fun buildGraphForEvent( + event: BaseEvent, + globalVariables: MutableSet, + globalArrays: MutableSet, + stateVariables: MutableSet + ): ArrayList { val vmState = VmState( - strings + strings, + globalVariables, globalArrays, stateVariables ) val gotos = ArrayList() @@ -550,8 +610,23 @@ inline fun > toEnum(index: Int): T { } class VmState( - val strings: List + val strings: List, + internal val globalVariables: MutableSet, + internal val globalArrays: MutableSet, + internal val stateVariables: MutableSet ) { + fun defineGlobalVariable(variableIndex: Int) { + globalVariables.add(variableIndex) + } + + fun defineStateVariable(variableIndex: Int) { + stateVariables.add(variableIndex) + } + + fun defineGlobalArray(arrayIndex: Int) { + globalArrays.add(arrayIndex) + } + lateinit var previousCommand: DataHeaders } diff --git a/src/main/kotlin/com/github/tarcv/zandronum/debotc/Nodes.kt b/src/main/kotlin/com/github/tarcv/zandronum/debotc/Nodes.kt index 987daf4..d9d8c52 100644 --- a/src/main/kotlin/com/github/tarcv/zandronum/debotc/Nodes.kt +++ b/src/main/kotlin/com/github/tarcv/zandronum/debotc/Nodes.kt @@ -111,7 +111,9 @@ abstract class BaseNode(open val asText: String, outputNum: Int) { } fun replace(oldValue: BaseNode, newValue: BaseNode) { - if (holder.count { it == oldValue } != 1) throw IllegalArgumentException() + if (holder.count { it == oldValue } != 1 && oldValue !is LabelNode) { + throw IllegalArgumentException() + } privateSet(holder.indexOf(oldValue), newValue) oldValue._inputs.remove(this@BaseNode)