Now generating enemies from table instead of hand coding them.

This commit is contained in:
Martin Haye 2016-01-01 07:53:57 -08:00
parent 8c6c658ecf
commit 7e9bcabcc1
8 changed files with 115 additions and 69 deletions

View File

@ -1460,6 +1460,7 @@ int parse_defs(void)
{
if (!(id_type(tokenstr, tokenlen) & PREDEF_TYPE))
{
// TODO: Print symbols
parse_error("Mismatch function type");
return (0);
}

View File

@ -1269,6 +1269,7 @@ class PackPartitions
readModule("gameloop", "src/plasma/build/gameloop.b")
readModule("globalScripts", "src/plasma/build/globalScripts.b")
readModule("combat", "src/plasma/build/combat.b")
readModule("gen_enemies", "src/plasma/build/gen_enemies.b")
}
def pack(xmlPath, binPath, javascriptPath)
@ -1420,7 +1421,7 @@ class PackPartitions
def buf = new StringBuilder()
def inParen = false
def inSlash = false
def needUnderscore = false
def needSeparator = false
str.eachWithIndex { ch, idx ->
if (ch == '(') {
inParen = true
@ -1438,18 +1439,19 @@ class PackPartitions
inSlash = false
if (ch && !inParen && !inSlash) {
if (ch >= 'A' && ch <= 'Z')
needUnderscore = true
if (ch == ' ' || ch == '_')
needUnderscore = true
if ((ch >= 'A' && ch <= 'Z') || ch == ' ' || ch == '_')
needSeparator = (idx > 0)
if (isAlnum(ch)) {
if (needUnderscore && idx > 0)
buf.append('_')
needUnderscore = false
if (allUpper)
if (allUpper) {
if (needSeparator)
buf.append('_')
buf.append(ch.toUpperCase())
else
buf.append(ch.toLowerCase())
}
else {
// Camel case
buf.append(needSeparator ? ch.toUpperCase() : ch.toLowerCase())
}
needSeparator = false
}
}
}
@ -1468,7 +1470,7 @@ class PackPartitions
def nDice = m[0][1].toInteger()
def dieSize = m[0][2].toInteger()
def add = m[0][4] ? m[0][3].toInteger() : 0
return "encodeDice($nDice,$dieSize,$add)"
return String.format("\$%X", ((nDice << 12) | (dieSize << 8) | add))
}
void genEnemy(out, columns, data)
@ -1476,7 +1478,7 @@ class PackPartitions
assert columns[0] == "Name"
def name = data[0]
out.print("def new_enemy_${humanNameToSymbol(name, false)}()\n")
out.print("def NE${humanNameToSymbol(name, false)}()\n")
assert columns[1] == "Image1"
def image1 = data[1]
@ -1489,6 +1491,10 @@ class PackPartitions
assert columns[4] == "Attack Type"
def attackType = data[4]
def attackTypeCode = attackType.toLowerCase() == "melee" ? 1 :
attackType.toLowerCase() == "projectile" ? 2 :
0
if (!attackTypeCode) throw new Exception("Can't parse attack type '$attackType'")
assert columns[5] == "Attack Text"
def attackText = data[5]
@ -1520,22 +1526,18 @@ class PackPartitions
assert columns[14].toLowerCase() =~ /gold loot/
def goldLoot = data[14]
out.println(" word p; p = mmgr(HEAP_ALLOC, TYPE_ENEMY)")
out.println(" p=>s_name = mmgr(HEAP_INTERN, \"$name\")")
out.println(" p=>w_health = rollDice(${parseDice(hitPoints)}) // $hitPoints")
out.println(" p->ba_images[0] = PORTRAIT_${humanNameToSymbol(image1, true)}")
def attackTypeCode = attackType.toLowerCase() == "melee" ? 1 :
attackType.toLowerCase() == "projectile" ? 2 :
0
if (!attackTypeCode) throw new Exception("Can't parse attack type '$attackType'")
out.println(" p->b_attackType = $attackTypeCode // $attackType")
out.println(" p=>s_attackText = mmgr(HEAP_INTERN, \"$attackText\")")
out.println(" p->b_enemyAttackRange = ${range.replace("'", "").toInteger()}")
out.println(" p->b_chanceToHit = ${chanceToHit.toInteger()}")
out.println(" p=>r_enemyDmg = ${parseDice(damage)} // $damage")
out.println(" p=>r_groupSize = ${parseDice(groupSize)} // $groupSize")
out.println(" return p")
out.println("end\n")
out.println(" return makeEnemy(" +
"\"$name\", " +
"${parseDice(hitPoints)}, " +
"PORTRAIT_${humanNameToSymbol(image1, true)}, " +
(image2.size() > 0 ? "PORTRAIT_${humanNameToSymbol(image2, true)}, " : "0, ") +
"$attackTypeCode, " +
"\"$attackText\", " +
"${range.replace("'", "").toInteger()}, " +
"${chanceToHit.toInteger()}, " +
"${parseDice(damage)}, " +
"${parseDice(groupSize)})")
out.println("end")
}
def dataGen(xmlPath)
@ -1571,8 +1573,9 @@ class PackPartitions
new File("src/plasma/gen_enemies.plh").withWriter { out ->
out.println("// Generated code - DO NOT MODIFY BY HAND\n")
enemyLines[1..-1].eachWithIndex { line, index ->
out.println("const new_enemy_${humanNameToSymbol(line.split("\t")[0], false)} = ${index*2}")
out.println("const CE${humanNameToSymbol(line.split("\t")[0], false)} = ${index*2}")
}
out.println("const NUM_ENEMIES = ${enemyLines.size - 1}")
}
new File("src/plasma/gen_enemies.pla").withWriter { out ->
out.println("// Generated code - DO NOT MODIFY BY HAND")
@ -1584,11 +1587,11 @@ class PackPartitions
def columns = enemyLines[0].split("\t")
enemyLines[1..-1].each { line ->
out.println("predef new_enemy_${humanNameToSymbol(line.split("\t")[0], false)}")
out.println("predef NE${humanNameToSymbol(line.split("\t")[0], false)}")
}
enemyLines[1..-1].eachWithIndex { line, index ->
out.print((index == 0) ? "\nword[] funcTbl = " : "word = ")
out.println("@new_enemy_${humanNameToSymbol(line.split("\t")[0], false)}")
out.println("@NE${humanNameToSymbol(line.split("\t")[0], false)}")
}
out.println()
enemyLines[1..-1].each { line ->

View File

@ -157,7 +157,11 @@ def displayOpponents()
first = FALSE
count = countListFiltered(p=>p_enemies, p_nextObj, @canFight)
isPlural = (count <> 1)
printf3("%d %s at %d'", count, p=>p_enemies=>s_name, p->b_enemyGroupRange)
if (p=>p_enemies=>r_groupSize == 0)
printf2("%s at %d'", p=>p_enemies=>s_name, p->b_enemyGroupRange)
else
printf3("%d %s at %d'", count, p=>p_enemies=>s_name, p->b_enemyGroupRange)
fin
p = p=>p_nextObj
loop
puts(".\n")
@ -389,7 +393,7 @@ def startCombat()
isFleeing = FALSE
// Display portrait of first group
setPortrait(global=>p_enemyGroups=>p_enemies->ba_images[0])
setPortrait(global=>p_enemyGroups=>p_enemies->b_image)
// If portrait was already in memory, the memory mgr load might still be open. Close it.
mmgr(FINISH_LOAD, 0)
@ -417,19 +421,23 @@ def startCombat()
while p
n = countList(p=>p_enemies)
setPlural(n <> 1)
when rand16() % 5
is 0
s = "From out of nowhere comes/come %d %s to have their way with you!\n"; break
is 1
s = "%d nasty %s comes/come to stake their claim on you!\n"; break
is 2
s = "It's gone from bad to worse, %d %s is/are looking for trouble!\n"; break
is 3
s = "%d %s is/are sniffing you out, shoulda' bathed last week!\n"; break
otherwise
s = "You mutter a curse under your breath as you see %d %s approach you with malice!\n"; break
wend
displayf2(s, n, p=>p_enemies=>s_name)
if p=>p_enemies=>r_groupSize == 0
displayf1("%s is in a fightin' mood!\n", p=>p_enemies=>s_name)
else
when rand16() % 5
is 0
s = "From out of nowhere comes/come %d %s to have their way with you!\n"; break
is 1
s = "%d nasty %s comes/come to stake their claim on you!\n"; break
is 2
s = "It's gone from bad to worse, %d %s is/are looking for trouble!\n"; break
is 3
s = "%d %s is/are sniffing you out, shoulda' bathed last week!\n"; break
otherwise
s = "You mutter a curse under your breath as you see %d %s approach you with malice!\n"; break
wend
displayf2(s, n, p=>p_enemies=>s_name)
fin
p = p=>p_nextObj
loop

View File

@ -110,7 +110,7 @@ const brk = gameLibVecs + 3*47
const encodeDice = gameLibVecs + 3*48
const rollDice = gameLibVecs + 3*49
const setPlural = gameLibVecs + 3*50
const FUNCN51 = gameLibVecs + 3*51
const makeEnemy = gameLibVecs + 3*51
const FUNCN52 = gameLibVecs + 3*52
const FUNCN53 = gameLibVecs + 3*53
const FUNCN54 = gameLibVecs + 3*54

View File

@ -37,6 +37,7 @@ const ANIM_PAUSE_MAX = 300
include "playtype.plh"
include "gen_images.plh"
include "gen_modules.plh"
include "gen_enemies.plh"
include "globalScripts.plh"
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -105,7 +106,7 @@ predef _puts, _min, _max
predef _countList, _countListFiltered, _randomFromListFiltered, _addToList, _beep
predef _showParty, _mmgr, _setWindow1, _setWindow2, _setWindow3
predef _reboot, _brk, _encodeDice, _rollDice
predef _setPlural
predef _setPlural, _makeEnemy
word gameLib_addrs = @_setScriptInfo, @_pushAuxStr, @_scriptDisplayStr, @_scriptDisplayStrNL, @_getYN
word = @_queue_setMap, @_setSky, @_setGround, @_queue_teleport, @_setPortrait, @_clearPortrait
@ -120,7 +121,7 @@ word = @_puts, @_min, @_max
word = @_countList, @_countListFiltered, @_randomFromListFiltered, @_addToList, @_beep
word = @_showParty, @_mmgr, @_setWindow1, @_setWindow2, @_setWindow3
word = @_reboot, @_brk, @_encodeDice, @_rollDice
word = @_setPlural
word = @_setPlural, @_makeEnemy
word = 0 // end of library functions
@ -1849,9 +1850,50 @@ def restoreMapPos()
initMap(global=>w_mapX, global=>w_mapY, global->b_mapDir)
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def _makeEnemy(name, healthDice, image0, image1, attackType, attackText, attackRange, chanceToHit, dmg, groupSize)
word p; p = mmgr(HEAP_ALLOC, TYPE_ENEMY)
p=>s_name = mmgr(HEAP_INTERN, name)
p=>w_health = rollDice(healthDice) // 4d6
if !image1 or (rand16() % 2)
p->b_image = image0
else
p->b_image = image1
fin
p->b_attackType = attackType
p=>s_attackText = mmgr(HEAP_INTERN, attackText)
p->b_enemyAttackRange = attackRange
p->b_chanceToHit = chanceToHit
p=>r_enemyDmg = dmg
p=>r_groupSize = groupSize
return p
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def makeEnemyGroup(enemyFunc)
word p, enem, groupSize
p = mmgr(HEAP_ALLOC, TYPE_ENEMY_GROUP)
enem = enemyFunc()
p->b_enemyGroupRange = max(1, rand16() % (enem->b_enemyAttackRange))
if enem=>r_groupSize == 0 // handle unique enemies
groupSize = 1
else
groupSize = rollDice(enem=>r_groupSize)
fin
addToList(p + p_enemies, enem)
while groupSize > 1
addToList(p + p_enemies, enemyFunc())
groupSize = groupSize - 1
loop
return p
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def testCombat()
word globalScripts
word enemiesModule
word enemyNum, enemyTbl, enemyFunc
word combatEngine
word x, y
byte dir
@ -1864,21 +1906,19 @@ def testCombat()
renderLoaded = FALSE
combatEngine = mmgr(QUEUE_LOAD, MODULE_COMBAT<<8 | RES_TYPE_MODULE)
globalScripts = mmgr(QUEUE_LOAD, MODULE_GLOBAL_SCRIPTS<<8 | RES_TYPE_MODULE)
enemiesModule = mmgr(QUEUE_LOAD, MODULE_GEN_ENEMIES<<8 | RES_TYPE_MODULE)
mmgr(FINISH_LOAD, 1) // 1 = keep open
// Create the enemy group(s).
global=>p_enemyGroups = NULL
when rand16() % 2
is 0
addToList(@global=>p_enemyGroups, globalScripts()=>script_new_EnemyGroup_Dirt_Bags())
break
otherwise
addToList(@global=>p_enemyGroups, globalScripts()=>script_new_EnemyGroup_Flesh_Feeders())
break
wend
enemyNum = rand16() % NUM_ENEMIES
enemyTbl = enemiesModule()
enemyFunc = *((enemyNum<<1) + enemyTbl)
addToList(@global=>p_enemyGroups, makeEnemyGroup(enemyFunc))
// No need for the global scripts now that everything has been created
mmgr(FREE_MEMORY, globalScripts)
mmgr(FREE_MEMORY, enemiesModule)
// Run the combat engine
combatEngine()

View File

@ -13,14 +13,12 @@ include "playtype.plh"
include "gen_images.plh"
predef new_Modifier, new_Armor_Chaps, new_Armor_ShamanHeaddress, new_Armor_TahnkuPants, new_Armor_TahnkuVest
predef new_Weapon_Handgun, new_Weapon_SpiritBow, new_Weapon_SpiritBlade, calcPlayerArmor, new_Player_Hue_Hauser
predef new_Player_Mokahnu, new_Enemy_Dirt_Bag, new_EnemyGroup_Dirt_Bags, new_Enemy_Flesh_Feeder
predef new_EnemyGroup_Flesh_Feeders
predef new_Weapon_Handgun, new_Weapon_SpiritBow, new_Weapon_SpiritBlade, calcPlayerArmor
predef new_Player_Hue_Hauser, new_Player_Mokahnu
word[] funcTbl = @new_Modifier, @new_Armor_Chaps, @new_Armor_ShamanHeaddress, @new_Armor_TahnkuPants, @new_Armor_TahnkuVest
word = @new_Weapon_Handgun, @new_Weapon_SpiritBow, @new_Weapon_SpiritBlade, @calcPlayerArmor, @new_Player_Hue_Hauser
word = @new_Player_Mokahnu, @new_Enemy_Dirt_Bag, @new_EnemyGroup_Dirt_Bags, @new_Enemy_Flesh_Feeder
word = @new_EnemyGroup_Flesh_Feeders
word = @new_Weapon_Handgun, @new_Weapon_SpiritBow, @new_Weapon_SpiritBlade, @calcPlayerArmor
word = @new_Player_Hue_Hauser, @new_Player_Mokahnu
///////////////////////////////////////////////////////////////////////////////////////////////////
def new_Modifier(kind, value)

View File

@ -19,7 +19,3 @@ const script_new_Weapon_SpiritBlade = 14
const script_calcPlayerArmor = 16
const script_new_Player_Hue_Hauser = 18
const script_new_Player_Mokahnu = 20
const script_new_Enemy_Dirt_Bag = 22
const script_new_EnemyGroup_Dirt_Bags = 24
const script_new_Enemy_Flesh_Feeder = 26
const script_new_EnemyGroup_Flesh_Feeders = 28

View File

@ -162,7 +162,7 @@ struc Enemy
word p_combatNext
word w_health
byte ba_images[2]
byte b_image
byte b_hitBonus
byte b_attackType // 1=melee, 2=projectile
word s_attackText