mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-02-24 00:29:12 +00:00
Now generating enemies from table instead of hand coding them.
This commit is contained in:
parent
8c6c658ecf
commit
7e9bcabcc1
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
if (allUpper) {
|
||||
if (needSeparator)
|
||||
buf.append('_')
|
||||
needUnderscore = false
|
||||
if (allUpper)
|
||||
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 ->
|
||||
|
@ -157,7 +157,11 @@ def displayOpponents()
|
||||
first = FALSE
|
||||
count = countListFiltered(p=>p_enemies, p_nextObj, @canFight)
|
||||
isPlural = (count <> 1)
|
||||
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,6 +421,9 @@ def startCombat()
|
||||
while p
|
||||
n = countList(p=>p_enemies)
|
||||
setPlural(n <> 1)
|
||||
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
|
||||
@ -430,6 +437,7 @@ def startCombat()
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user