mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-08-12 02:25:10 +00:00
Progress on group selection in combat.
This commit is contained in:
@@ -44,6 +44,7 @@ byte nPartyFighting
|
|||||||
byte nPlayersFighting
|
byte nPlayersFighting
|
||||||
byte nEnemiesFighting
|
byte nEnemiesFighting
|
||||||
byte isFleeing
|
byte isFleeing
|
||||||
|
byte isAdvancing
|
||||||
//combatDebug// byte combatDebug
|
//combatDebug// byte combatDebug
|
||||||
|
|
||||||
byte[] S_AN = "an "
|
byte[] S_AN = "an "
|
||||||
@@ -58,7 +59,6 @@ word pItemUtil
|
|||||||
|
|
||||||
const MAX_GROUPS = 3
|
const MAX_GROUPS = 3
|
||||||
byte nEnemyGroups
|
byte nEnemyGroups
|
||||||
byte isAdvancing
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
def preload()#0
|
def preload()#0
|
||||||
@@ -123,12 +123,12 @@ def combatPause()#0
|
|||||||
pause(global=>w_combatPauseCt)
|
pause(global=>w_combatPauseCt)
|
||||||
|
|
||||||
// Check for speed-up / slow-down
|
// Check for speed-up / slow-down
|
||||||
key = ^kbd
|
key = ^kbd & $7F
|
||||||
if key == (11 + 128) or key == ('-'+128) // up-arrow or minus
|
if key == 11 or key == '-' // up-arrow or minus
|
||||||
if !recordMode; ^kbdStrobe; fin
|
^kbdStrobe
|
||||||
global=>w_combatPauseCt = max(100, global=>w_combatPauseCt - addPercent(global=>w_combatPauseCt, 20))
|
global=>w_combatPauseCt = max(100, global=>w_combatPauseCt - addPercent(global=>w_combatPauseCt, 20))
|
||||||
elsif key == (10 + 128) or key == ('+'+128) // down-arrow or plus
|
elsif key == 10 or key == '+' // down-arrow or plus
|
||||||
if !recordMode; ^kbdStrobe; fin
|
^kbdStrobe
|
||||||
global=>w_combatPauseCt = min(9999, global=>w_combatPauseCt + addPercent(global=>w_combatPauseCt, 20))
|
global=>w_combatPauseCt = min(9999, global=>w_combatPauseCt + addPercent(global=>w_combatPauseCt, 20))
|
||||||
fin
|
fin
|
||||||
end
|
end
|
||||||
@@ -380,29 +380,44 @@ def playerDodge(pPlayer)#0
|
|||||||
// no need to display anything. Actual dodging mechanics handled in enemy attack function.
|
// no need to display anything. Actual dodging mechanics handled in enemy attack function.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
def groupCanFight(p)#1
|
||||||
|
return first(p=>p_enemies, @canFight)
|
||||||
|
end
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
def formatGroupName(p, withDist)#1
|
||||||
|
byte count
|
||||||
|
count = sum(p=>p_enemies, NULL, @canFight)
|
||||||
|
isPlural = count <> 1
|
||||||
|
if (p=>p_enemies=>r_groupSize == 0)
|
||||||
|
if withDist
|
||||||
|
return sprintf2("%s at %d'", p=>p_enemies=>s_name, p=>p_enemies->b_enemyAttackRange)
|
||||||
|
else
|
||||||
|
return sprintf1("%s", p=>p_enemies=>s_name)
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
if withDist
|
||||||
|
return sprintf3("%d %s at %d'", count, p=>p_enemies=>s_name, p=>p_enemies->b_enemyAttackRange)
|
||||||
|
fin
|
||||||
|
return sprintf2("%d %s", count, p=>p_enemies=>s_name)
|
||||||
|
end
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
def displayOpponents()#0
|
def displayOpponents()#0
|
||||||
word p
|
word p
|
||||||
byte count, firstTime
|
byte firstTime
|
||||||
|
|
||||||
displayStr("You face ")
|
displayStr("You face ")
|
||||||
firstTime = TRUE
|
firstTime = TRUE
|
||||||
p = global=>p_enemyGroups
|
p = global=>p_enemyGroups
|
||||||
while p
|
while p
|
||||||
if !firstTime
|
if groupCanFight(p)
|
||||||
if p=>p_nextObj
|
if !firstTime
|
||||||
displayStr(", ")
|
displayStr(p=>p_nextObj ?? ", " :: " and ")
|
||||||
else
|
|
||||||
displayStr(" and ")
|
|
||||||
fin
|
fin
|
||||||
fin
|
firstTime = FALSE
|
||||||
firstTime = FALSE
|
displayStr(formatGroupName(p, TRUE))
|
||||||
count = sum(p=>p_enemies, NULL, @canFight)
|
|
||||||
isPlural = count <> 1
|
|
||||||
if (p=>p_enemies=>r_groupSize == 0)
|
|
||||||
displayf2("%s at %d'", p=>p_enemies=>s_name, p=>p_enemies->b_enemyAttackRange)
|
|
||||||
else
|
|
||||||
displayf3("%d %s at %d'", count, p=>p_enemies=>s_name, p=>p_enemies->b_enemyAttackRange)
|
|
||||||
fin
|
fin
|
||||||
p = p=>p_nextObj
|
p = p=>p_nextObj
|
||||||
loop
|
loop
|
||||||
@@ -414,7 +429,7 @@ def displayOption(key, str)#0
|
|||||||
rawDisplayStr("\n (")
|
rawDisplayStr("\n (")
|
||||||
displayChar(key)
|
displayChar(key)
|
||||||
rawDisplayStr(")^T028")
|
rawDisplayStr(")^T028")
|
||||||
rawDisplayStr(str)
|
displayStr(str)
|
||||||
end
|
end
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -425,7 +440,7 @@ def minEnemyDist()#1
|
|||||||
// Process each group
|
// Process each group
|
||||||
p = global=>p_enemyGroups
|
p = global=>p_enemyGroups
|
||||||
while p
|
while p
|
||||||
if first(p=>p_enemies, @canFight)
|
if groupCanFight(p)
|
||||||
minDist = min(minDist, p=>p_enemies->b_enemyAttackRange)
|
minDist = min(minDist, p=>p_enemies->b_enemyAttackRange)
|
||||||
fin
|
fin
|
||||||
p = p=>p_nextObj
|
p = p=>p_nextObj
|
||||||
@@ -433,6 +448,71 @@ def minEnemyDist()#1
|
|||||||
return minDist
|
return minDist
|
||||||
end
|
end
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
def noneInRange()#1
|
||||||
|
rawDisplayStr("^D") // clear to end of page
|
||||||
|
displayStr("No enemy in range.")
|
||||||
|
combatPause
|
||||||
|
return FALSE
|
||||||
|
end
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Phase 0: count alive & in-range gangs
|
||||||
|
// Phase 1: display gangs
|
||||||
|
// Phase 2: select gang by number, return enemyNum
|
||||||
|
def groupLoop(minDist, phase, choiceNum)#1
|
||||||
|
word p
|
||||||
|
byte n
|
||||||
|
|
||||||
|
p = global=>p_enemyGroups
|
||||||
|
n = 0
|
||||||
|
while p
|
||||||
|
if p=>p_enemies->b_enemyAttackRange <= minDist and groupCanFight(p)
|
||||||
|
if phase == 1
|
||||||
|
displayOption(n + 'A', formatGroupName(p, FALSE))
|
||||||
|
elsif phase == 2 and n == choiceNum
|
||||||
|
return p->b_enemyNum
|
||||||
|
fin
|
||||||
|
n++
|
||||||
|
fin
|
||||||
|
p = p=>p_nextObj
|
||||||
|
loop
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
def chooseGroup(pl, minDist)#1
|
||||||
|
word p
|
||||||
|
byte nAvailGroups, choiceNum
|
||||||
|
|
||||||
|
// First, determine how many groups are alive and within striking distance
|
||||||
|
nAvailGroups = groupLoop(minDist, 0, 0)
|
||||||
|
|
||||||
|
// If nobody in range, ack!
|
||||||
|
if !nAvailGroups; return noneInRange(); fin
|
||||||
|
|
||||||
|
// If only one group, the choice is trivially obvious.
|
||||||
|
if nAvailGroups == 1
|
||||||
|
choiceNum = 0
|
||||||
|
else
|
||||||
|
rawDisplayf1("^D%s attack:", pl=>s_name) // ctrl-D = clear to end of page
|
||||||
|
groupLoop(minDist, 1, 0)
|
||||||
|
while TRUE
|
||||||
|
choiceNum = getUpperKey()
|
||||||
|
if choiceNum == $1B // esc
|
||||||
|
return FALSE
|
||||||
|
fin
|
||||||
|
choiceNum = choiceNum - 'A'
|
||||||
|
if choiceNum >= 0 and choiceNum < nAvailGroups; break; fin
|
||||||
|
beep()
|
||||||
|
loop
|
||||||
|
fin
|
||||||
|
|
||||||
|
// Success.
|
||||||
|
pl->b_gangChoice = groupLoop(minDist, 2, choiceNum)
|
||||||
|
return TRUE
|
||||||
|
end
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Determine number of shots. Only gets called for projectile attack
|
// Determine number of shots. Only gets called for projectile attack
|
||||||
def chooseShotNumber(pl, pWeapon)#0
|
def chooseShotNumber(pl, pWeapon)#0
|
||||||
@@ -452,7 +532,7 @@ def chooseShotNumber(pl, pWeapon)#0
|
|||||||
if nChoices <= 1; return; fin
|
if nChoices <= 1; return; fin
|
||||||
|
|
||||||
// Let player choose
|
// Let player choose
|
||||||
rawDisplayf1("^D%s shoot:", pl=>s_name) // ctrl-D = clear to end of page
|
rawDisplayf1("^D%s shot type:", pl=>s_name) // ctrl-D = clear to end of page
|
||||||
if pWeapon->ba_attacks[0]; displayOption('O', "One shot"); fin
|
if pWeapon->ba_attacks[0]; displayOption('O', "One shot"); fin
|
||||||
if pWeapon->ba_attacks[1] == 2
|
if pWeapon->ba_attacks[1] == 2
|
||||||
displayOption('D', "Double-shot")
|
displayOption('D', "Double-shot")
|
||||||
@@ -530,7 +610,7 @@ end
|
|||||||
def playerCombatChoose(pl)#0
|
def playerCombatChoose(pl)#0
|
||||||
word p, pWeapon
|
word p, pWeapon
|
||||||
byte key
|
byte key
|
||||||
byte canShoot, canReload, canChange, canAdvance
|
byte canShoot, canReload, canChange, canAdvance, redisplayMenu
|
||||||
word cursX, cursY
|
word cursX, cursY
|
||||||
|
|
||||||
// The party advances all at once
|
// The party advances all at once
|
||||||
@@ -560,41 +640,53 @@ def playerCombatChoose(pl)#0
|
|||||||
p = p=>p_nextObj
|
p = p=>p_nextObj
|
||||||
loop
|
loop
|
||||||
|
|
||||||
// Let them know their options
|
redisplayMenu = TRUE
|
||||||
setCursor(cursX, cursY)
|
|
||||||
rawDisplayStr("^D") // clear to end of page
|
|
||||||
displayf1("%s:\nM)elee, ", pl=>s_name)
|
|
||||||
if pWeapon
|
|
||||||
// Special (for e.g. bows): clipSize zero means weapon reloads automatically
|
|
||||||
if pWeapon=>r_projectileDmg and !pWeapon->b_clipCurrent and !pWeapon->b_clipSize
|
|
||||||
pItemUtil=>itemutil_reloadWeapon(pl, pWeapon, FALSE) // silently reload
|
|
||||||
fin
|
|
||||||
if pWeapon->b_clipCurrent
|
|
||||||
canShoot = TRUE
|
|
||||||
if pWeapon->b_clipSize
|
|
||||||
displayf2("S)hoot %d:%d, ", pWeapon->b_clipCurrent, pWeapon->b_clipSize))
|
|
||||||
else
|
|
||||||
displayStr("S)hoot, ")
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
if pWeapon->b_clipCurrent < pWeapon->b_clipSize
|
|
||||||
canReload = TRUE
|
|
||||||
displayStr("R)eload, ")
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
if canChange
|
|
||||||
displayStr("C)hange weapon, ")
|
|
||||||
fin
|
|
||||||
displayStr("D)odge, ")
|
|
||||||
canAdvance = (pl == global=>p_players) and (minEnemyDist() > 5) // only one advance per turn
|
|
||||||
if canAdvance; displayStr("A)dvance, "); fin
|
|
||||||
displayStr("F)lee")
|
|
||||||
setCursor(cursX, cursY)
|
|
||||||
|
|
||||||
|
// Loop until a valid option is chosen
|
||||||
while TRUE
|
while TRUE
|
||||||
|
|
||||||
|
// Let them know their options
|
||||||
|
if redisplayMenu
|
||||||
|
setCursor(cursX, cursY)
|
||||||
|
rawDisplayStr("^D") // clear to end of page
|
||||||
|
displayf1("%s:\nM)elee, ", pl=>s_name)
|
||||||
|
if pWeapon
|
||||||
|
// Special (for e.g. bows): clipSize zero means weapon reloads automatically
|
||||||
|
if pWeapon=>r_projectileDmg and !pWeapon->b_clipCurrent and !pWeapon->b_clipSize
|
||||||
|
pItemUtil=>itemutil_reloadWeapon(pl, pWeapon, FALSE) // silently reload
|
||||||
|
fin
|
||||||
|
if pWeapon->b_clipCurrent
|
||||||
|
canShoot = TRUE
|
||||||
|
if pWeapon->b_clipSize
|
||||||
|
displayf2("S)hoot %d:%d, ", pWeapon->b_clipCurrent, pWeapon->b_clipSize))
|
||||||
|
else
|
||||||
|
displayStr("S)hoot, ")
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
if pWeapon->b_clipCurrent < pWeapon->b_clipSize
|
||||||
|
canReload = TRUE
|
||||||
|
displayStr("R)eload, ")
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
if canChange
|
||||||
|
displayStr("C)hange weapon, ")
|
||||||
|
fin
|
||||||
|
displayStr("D)odge, ")
|
||||||
|
canAdvance = (pl == global=>p_players) and (minEnemyDist() > 5) // only one advance per turn
|
||||||
|
if canAdvance; displayStr("A)dvance, "); fin
|
||||||
|
displayStr("F)lee")
|
||||||
|
setCursor(cursX, cursY)
|
||||||
|
fin
|
||||||
|
|
||||||
pl->b_combatChoice = getUpperKey()
|
pl->b_combatChoice = getUpperKey()
|
||||||
|
redisplayMenu = FALSE
|
||||||
when pl->b_combatChoice
|
when pl->b_combatChoice
|
||||||
is 'M'
|
is 'M'
|
||||||
|
if !chooseGroup(pl, 5)
|
||||||
|
redisplayMenu = TRUE
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
setCursor(cursX, cursY)
|
||||||
return
|
return
|
||||||
is 'F'
|
is 'F'
|
||||||
isFleeing = TRUE
|
isFleeing = TRUE
|
||||||
@@ -603,6 +695,11 @@ def playerCombatChoose(pl)#0
|
|||||||
return
|
return
|
||||||
is 'S'
|
is 'S'
|
||||||
if canShoot
|
if canShoot
|
||||||
|
if !chooseGroup(pl, pWeapon->b_weaponRange)
|
||||||
|
redisplayMenu = TRUE
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
setCursor(cursX, cursY)
|
||||||
chooseShotNumber(pl, pWeapon)
|
chooseShotNumber(pl, pWeapon)
|
||||||
setCursor(cursX, cursY)
|
setCursor(cursX, cursY)
|
||||||
return
|
return
|
||||||
@@ -638,7 +735,7 @@ def playerCombatChoose(pl)#0
|
|||||||
fin
|
fin
|
||||||
return
|
return
|
||||||
wend
|
wend
|
||||||
beep()
|
if !redisplayMenu; beep(); fin
|
||||||
loop
|
loop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user