Making progress on combat gangs.

This commit is contained in:
Martin Haye 2019-10-10 09:48:21 -07:00
parent a2425e0751
commit 12d02919ab
3 changed files with 76 additions and 17 deletions

View File

@ -3120,12 +3120,14 @@ class A2PackPartitions
def parseDice(str)
{
str = str.trim()
// Handle single value
if (str =~ /^\d+$/) {
def n = str.toInteger()
if (n < 0 || n > 255) {
printWarning("Number $n forced to valid range 0..255")
return "0"
return n < 0 ? "0" : "255"
}
return str
}
@ -3182,11 +3184,15 @@ class A2PackPartitions
def name = row.@name
withContext(name)
{
def image1 = row.@image1
def images = row.@images.split(", *")
if (images.length < 1 || images.length > 2)
throw new Exception("Required: 1 or 2 images")
def image1 = images[0]
if (!portraits.containsKey(image1))
throw new Exception("Image '$image1' not found")
def image2 = row.@image2
def image2 = images.length > 1 ? images[1] : ""
if (image2.size() > 0 && !portraits.containsKey(image2))
throw new Exception("Image '$image2' not found")
@ -3208,6 +3214,7 @@ class A2PackPartitions
def lootChance = row.@"loot-chance"; // optional, defaults to 10%
def lootCode = row.@"loot-code" // optional
def goldLoot = row.@"gold-loot"; assert goldLoot
def gangChance = row.@"gang-chance"; // optional
out.println("word = " +
"@${strings[name]}, ${parseDice(hitPoints)} // name, hit dice")
@ -3215,14 +3222,15 @@ class A2PackPartitions
(image2.size() > 0 ? "PO${humanNameToSymbol(image2, false)}, " : "0, ") +
"$attackTypeCode // img0, img1, attack type")
out.println("word = @${strings[attackText]} // attack text")
out.println("byte = ${range.replace("'", "").toInteger()}, " +
"${chanceToHit.toInteger()} // attack range, chance to hit")
out.println("word = ${parseDice(range.replace("'", ""))} // attack range dice")
out.println("byte = ${chanceToHit.toInteger()} // chance to hit")
out.println("word = ${parseDice(damage)}, " +
"${parseDice(experience)}, " +
"${parseDice(groupSize)} // damage dice, exp dice, group size dice")
out.println("byte = ${lootChance ? lootChance.toInteger() : 10} // loot chance")
out.println("word = ${validateLootCode(lootCode, strings)}, " +
"${parseDice(goldLoot)} // lootCode, goldLoot")
out.println("byte = ${gangChance ? parseDice(gangChance) : 0} // gang chance")
out.println("")
// Add portrait dependencies based on encounter zone(s)

View File

@ -25,7 +25,7 @@ struc EnemyData
byte b_en_img1
byte b_en_attType
word s_en_attText
byte b_en_attRange
byte r_en_attRange
byte b_en_chanceToHit
word r_en_dmgDice
word r_en_expDice
@ -33,6 +33,7 @@ struc EnemyData
byte b_en_lootChance
word s_en_lootCode
word r_en_goldLoot
byte b_en_gangChance
end
predef _combat_zoneEncounter(s_encZone)#1
@ -55,6 +56,10 @@ byte[] toPreload = MOD_ITEMUTIL, GS_COMBAT_PROMPT, GS_ENEMY_INTRO, GS_COMBAT_WIN
word[4] preloads
word pItemUtil
const MAX_GROUPS = 3
byte[MAX_GROUPS] groupEnemyNums
byte nEnemyGroups
///////////////////////////////////////////////////////////////////////////////////////////////////
def preload()#0
byte i
@ -836,7 +841,7 @@ def makeEnemy(pData)
fin
p->b_attackType = pData->b_en_attType
p=>s_attackText = mmgr(HEAP_INTERN, pData=>s_en_attText)
p->b_enemyAttackRange = pData->b_en_attRange
p->b_enemyAttackRange = rollDice(pData=>r_en_attRange) // possibly random range
p->b_chanceToHit = pData->b_en_chanceToHit
p=>r_enemyDmg = pData=>r_en_dmgDice
p=>r_enemyXP = pData=>r_en_expDice
@ -869,31 +874,66 @@ end
///////////////////////////////////////////////////////////////////////////////////////////////////
// Return a random entry from an array which is terminated by a zero entry
def randomFromArray(arr)#1
byte siz
def randomFromArray(arr, filter)#1
byte siz, start, cur
word p
// Determine the array size by looking for the terminating zero
siz = 0
while *((siz << 1) + arr)
siz++
loop
return *(((rand16() % siz) << 1) + arr)
// Pick a random starting point in the array
start = rand16() % siz
// Advance until we find a filter-approved entry (or run out)
cur = start
while TRUE
p = *((cur << 1) + arr)
if !filter; break; fin
if filter(p); break; fin
cur++
if cur >= siz; cur = 0; fin
if cur == start
p = NULL
break
fin
loop
return p
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def makeRandomGroup(mapCode)#0
def nonDupeEnemy(enemyNum)#1
byte i
for i = 0 to nEnemyGroups
if enemyNum == groupEnemyNums[i]; return FALSE; fin
next
return TRUE
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def makeRandomGroup(mapCode)#1
word enemiesModule
byte enemyNum
word pEnemyData
word pEnemyData, pGroup
enemiesModule = mmgr(QUEUE_LOAD, MOD_GEN_ENEMIES<<8 | RES_TYPE_MODULE)
mmgr(FINISH_LOAD, 0)
enemyNum = randomFromArray(enemiesModule()=>enemies_forZone(mapCode))
enemyNum = randomFromArray(enemiesModule()=>enemies_forZone(mapCode), @nonDupeEnemy)
mmgr(FREE_MEMORY, enemiesModule)
if !enemyNum; return NULL; fin // no non-dupe enemies left in mapCode zone
groupEnemyNums[nEnemyGroups] = enemyNum
nEnemyGroups++
enemiesModule = mmgr(QUEUE_LOAD, (MOD_GEN_ENEMIES + 1 + ((enemyNum-1)&1))<<8 | RES_TYPE_MODULE)
mmgr(FINISH_LOAD, 0)
pEnemyData = enemiesModule() + 1 + (((enemyNum-1)>>1) * EnemyData)
addToList(@global=>p_enemyGroups, makeEnemyGroup(pEnemyData))
pGroup = makeEnemyGroup(pEnemyData)
addToList(@global=>p_enemyGroups, pGroup)
mmgr(FREE_MEMORY, enemiesModule)
return pGroup
end
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -975,7 +1015,7 @@ def collectLootAndXP()#2
mmgr(START_LOAD, 1) // code is in partition 1
pItemsModule = mmgr(QUEUE_LOAD, MOD_GEN_ITEMS<<8 | RES_TYPE_MODULE)
mmgr(FINISH_LOAD, 0)
itemFunc = randomFromArray(pItemsModule()=>items_forLootCode(enemy=>s_lootCode))
itemFunc = randomFromArray(pItemsModule()=>items_forLootCode(enemy=>s_lootCode), @trueFunc)
pItem = itemFunc()
if pItem->t_type == TYPE_FANCY_ITEM
pItem=>w_count = rollDiceWithLuck(pItem=>r_lootAmount, global=>p_players->b_luck)
@ -1003,7 +1043,18 @@ def startCombat(mapCode)#1
isFleeing = FALSE
combatDebug = FALSE
global=>p_enemyGroups = NULL
makeRandomGroup(mapCode)
nEnemyGroups = 0
// Make one or more enemy groups (rolling for gangChance on each to see if we need another)
while TRUE
// Generate a random, non-duplicate group (can fail if non-duplicate is impossible)
if !makeRandomGroup(mapCode); break; fin
// If maxed out on groups, or dice roll for gang fails, we're done
if nEnemyGroups < MAX_GROUPS and (rand16() % 100) >= p->b_en_gangChance
break
fin
loop
// Display portrait of first group
setPortrait(global=>p_enemyGroups=>p_enemies->b_image)

View File

@ -1606,7 +1606,7 @@ export def rollDice(encoded)#1
word result
nDice = (encoded >> 12) & $F // must mask off replicated hi-bits
dieSize = (encoded >> 8) & $F
result = encoded & $F // initial add
result = encoded & $FF // initial add
while nDice
result = result + (rand16() % dieSize) + 1
nDice--