diff --git a/Platform/Apple/virtual/src/plasma/gameloop.pla b/Platform/Apple/virtual/src/plasma/gameloop.pla index 9719f20d..80e33c10 100644 --- a/Platform/Apple/virtual/src/plasma/gameloop.pla +++ b/Platform/Apple/virtual/src/plasma/gameloop.pla @@ -116,6 +116,10 @@ byte decimalBuf[7] byte tabBuf[5] byte isPlural +// Combat variables that don't need to be saved in game state +byte nPlayersFighting +byte nEnemiesFighting + /////////////////////////////////////////////////////////////////////////////////////////////////// // Definitions used by assembly code asm __defs @@ -1532,7 +1536,96 @@ include "playtype.pla" //include "heaptest.pla" /////////////////////////////////////////////////////////////////////////////////////////////////// -def combat() +def playerCanFight(p) + return p=>w_health > 0 +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +def enemyCanFight(p) + return p=>w_health > 0 +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +def playerCombatTurn(pl) + displayf1("Player turn: %s\n", pl=>s_name) + getUpperKey() +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +def enemyCombatTurn(pe) + displayf1("Enemy turn: %s\n", pe=>s_name) + getUpperKey() +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +def combatInsert(toAdd) + word p, pPrev + + // Find the proper position based on combat order number (keep largest first in the list) + pPrev = global + p_combatFirst + while TRUE + p = *pPrev + if !p or p->b_combatOrder < toAdd->b_combatOrder + break + fin + pPrev = p + p_combatNext + loop + + // Add it right there. + toAdd=>p_combatNext = *pPrev + *pPrev = toAdd +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +def determineCombatOrder() + word p, p2 + + nPlayersFighting = 0 + nEnemiesFighting = 0 + + // Do each player character, with random chance based on their agility + global=>p_combatFirst = NULL + p = global=>p_players + while p + if playerCanFight(p) + p->b_combatOrder = rand16() % (p->b_agility * 10) + combatInsert(p) + nPlayersFighting = nPlayersFighting + 1 + fin + p = p=>p_nextObj + loop + + // Then all the enemies, with random chance based on their chance to hit. + p = global=>p_enemyGroups + while p + p2 = p=>p_enemies + while p2 + if enemyCanFight(p2) + p2->b_combatOrder = rand16() % p2->b_chanceToHit + combatInsert(p2) + nEnemiesFighting = nEnemiesFighting + 1 + fin + p2 = p2=>p_nextObj + loop + p = p=>p_nextObj + loop + + // For debuggging, print out the order + printf2("nPlayersFighting=%d nEnemiesFighting=%d.\nCombat order:\n", nPlayersFighting, nEnemiesFighting) + p = global=>p_combatFirst + while p + printf2(" %s (n=%d)\n", p=>s_name, p->b_combatOrder) + p = p=>p_combatNext + loop + + // FIXME: for debugging only + ^$C051 + getUpperKey() + ^$C050 +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +def startCombat() word p, p2, n, s // Create the enemy group(s). @@ -1542,9 +1635,14 @@ def combat() // Display portrait of first group setPortrait(global=>p_enemyGroups=>p_enemies=>ba_images[0]) - // Say who we're fighting + // We're going to do all our text drawing in window 2. Also, might as well + // set everything up so that the map gets redrawn when combat finishes. setWindow2() clearWindow() + textDrawn = TRUE + needRender = TRUE + + // Say who we're fighting when rand16() % 5 is 0 s = "Uh oh, it's gunna' be one of THOSE days.\n"; break @@ -1584,19 +1682,50 @@ def combat() if n == 'F' clearWindow() displayStr("Fight!") - break + return TRUE elsif n == 'R' clearWindow() displayStr("Coward.") - textDrawn = TRUE - needRender = TRUE - break + return FALSE fin beep() loop end +/////////////////////////////////////////////////////////////////////////////////////////////////// +def doCombat() + word p + + // Show portrait and threat details, find out if player wants to fight (vs. run) + if !startCombat(); return; fin + + // Do each round of combat until player wins or loses. + while TRUE + determineCombatOrder() + p = global=>p_combatFirst + while p + clearWindow() + if !nPlayersFighting + displayStr("You lost.") + return + elsif !nEnemiesFighting + displayStr("You won!") + return + fin + when p->t_type + is TYPE_PLAYER + playerCombatTurn(p); break + is TYPE_ENEMY + enemyCombatTurn(p); break + otherwise + brk() + wend + p = p=>p_combatNext + loop + loop +end + /////////////////////////////////////////////////////////////////////////////////////////////////// // Set up the command table for 3D mode def initCmds() @@ -1611,7 +1740,7 @@ def initCmds() initCmd('T', @kbdTeleport) initCmd('P', @showPos) initCmd('/', @testPortrait) - initCmd('!', @combat) + initCmd('!', @doCombat) // Commands handled differently in 3D vs 2D if mapIs3D diff --git a/Platform/Apple/virtual/src/plasma/playtype.plh b/Platform/Apple/virtual/src/plasma/playtype.plh index a39b5374..4d1cd1d0 100644 --- a/Platform/Apple/virtual/src/plasma/playtype.plh +++ b/Platform/Apple/virtual/src/plasma/playtype.plh @@ -6,6 +6,7 @@ struc Global byte t_type word p_players word p_enemyGroups + word p_combatFirst end byte typeTbl_Global[] = Global, p_players, p_enemyGroups, 0 @@ -14,6 +15,9 @@ struc Player byte t_type word p_nextObj word s_name + byte b_combatOrder + word p_combatNext + word w_health // Innate attributes byte b_intelligence @@ -33,7 +37,6 @@ struc Player byte b_wilderness // Status - word w_health word w_maxHealth // Lists @@ -142,8 +145,11 @@ struc Enemy byte t_type word p_nextObj word s_name - byte ba_images[2] + byte b_combatOrder + word p_combatNext word w_health + + byte ba_images[2] byte b_hitBonus byte b_attackType // 1=melee, 2=projectile word s_attackText