Added number-of-attacks logic for high levels of hand-to-hand etc. Added stats cross-reference to pack report. Added more smart-quote translation to packer.

This commit is contained in:
Martin Haye 2021-08-02 08:24:28 -07:00
parent 5651578bbd
commit a6f974da33
2 changed files with 114 additions and 10 deletions

View File

@ -314,6 +314,10 @@ class A2PackPartitions
}
else if (ch == '\"')
buf << "\\\""
else if (ch == '“' || ch == '”') // translate smart quotes to straight quotes
buf << "\\\""
else if (ch == '' || ch == '')
buf << '\''
else if (prev == '^') {
def cp = Character.codePointAt(ch.toUpperCase(), 0)
// ^A = ctrl-A; ^M = ctrl-M (carriage return); ^Z = ctrl-Z; ^` = space
@ -2922,6 +2926,70 @@ class A2PackPartitions
}
}
def recordStatUse(mapName, script, statUses)
{
mapName = mapName.trim().replaceAll(/\s*-\s*[23][dD]\s*/, "")
script.block.'**'.each { blk ->
if (blk?.@type =~ /^interaction_(increase|decrease|set|get)_stat.*/) {
def statName = blk.field[0].text().trim().toLowerCase()
def getOrSet = blk.@type == "interaction_get_stat" ? "Checked" : "Set"
if (!statUses.containsKey(statName))
statUses[statName] = [] as Set
def scriptName = script.@name
statUses[statName] << "$getOrSet on map '$mapName' in script '$scriptName'"
}
}
}
def recordStats(data, statUses, skills)
{
def funcs = allPlayerFuncs(data.global.sheets.sheet)
funcs.each { func, index, row ->
row.attributes().sort().eachWithIndex { name, val, idx ->
if (name =~ /^skill-(.*)/) {
def skillName = name.replace("skill-", "").toLowerCase()
skills << skillName
if (!statUses.containsKey(skillName))
statUses[skillName] = [] as Set
statUses[skillName] << "Initialized in players sheet"
}
}
}
def el = data.global.sheets.sheet.find { it?.@name.equalsIgnoreCase("weapons") }
el.rows.row.findAll{"weapon"}.each { row ->
def kind = parseStringAttr(row, "weapon-kind").toLowerCase()
if (!statUses.containsKey(kind))
statUses[kind] = [] as Set
statUses[kind] << "Checked by weapon-kind in combat"
}
data.global.scripts.script.each { recordStatUse('global', it, statUses) }
data.map.each { map ->
map.scripts.script.each { recordStatUse(map.@name, it, statUses) }
}
return [statUses, skills]
}
def reportStatUse(data)
{
def statUses = [:]
def skills = [] as Set
reportWriter.println(
"\n============================== Stats and Skills Cross-reference ==================================\n")
recordStats(data, statUses, skills)
statUses.keySet().sort().each { statName ->
def uses = statUses[statName]
def skillOrStat = skills.contains(statName) ? "Skill" : "Stat"
reportWriter.println "$skillOrStat '$statName':"
statUses[statName].sort().each { useStr ->
reportWriter.println " $useStr"
}
}
}
def addResourceDep(fromType, fromName, toType, toName)
{
assert fromType != null && fromName != null
@ -3157,6 +3225,7 @@ class A2PackPartitions
reportScriptLocs(dataIn)
reportFlags(dataIn)
reportStoryLogs()
reportStatUse(dataIn)
if (debugCompression)
println "Compression savings: $compressionSavings"
@ -3793,9 +3862,11 @@ class A2PackPartitions
"${parseByteAttr(row, "pack size")})")
row.attributes().sort().eachWithIndex { name, val, idx ->
if (name =~ /^skill-(.*)/) {
def skillName = name.replace("skill-", "")
out.println(" addToList(@p=>p_skills, " +
"makeModifier(${escapeString(titleCase(name.replace("skill-", "")))}, " +
"makeModifier(${escapeString(titleCase(skillName))}, " +
"${parseByteAttr(row, name)}))")
skillName = skillName.toLowerCase()
}
else if (name =~ /^item-/) {
name = val.trim().toLowerCase()
@ -4671,7 +4742,8 @@ end
}
if (inst2.nWarnings > 0) {
reportWriter.println "Packing warnings:\n"
reportWriter.println(
"\n============================== Packing warnings ==================================\n")
reportWriter.println inst2.warningBuf.toString()
reportWriter.write()
watcher.warnings(inst2.nWarnings, inst2.warningBuf.toString())

View File

@ -782,10 +782,32 @@ def getWeapon(pl)#1
return first(pl=>p_items, &(p) p->t_type == TYPE_WEAPON and p->b_flags & ITEM_FLAG_EQUIP)
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def calcNumAtt(pl, isMelee, pWeapon)
byte skillPts
skillPts = 0
if pWeapon
if pWeapon->b_flags & WEAPON_FLAG_SINGLE_USE; return 1; fin
skillPts = scanModifiers(pl=>p_skills, pWeapon=>s_itemKind)
elsif isMelee
skillPts = scanModifiers(pl=>p_skills, @S_HAND_TO_HAND)
fin
if skillPts >= 9
return 3
elsif skillPts >= 6
return 2
fin
return 1
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def playerCombatTurn(pl)#1
word pWeapon, pGroup, pEnemy
byte i
byte i, j, nAttacks
if !nEnemiesFighting; return 0; fin
@ -795,18 +817,28 @@ def playerCombatTurn(pl)#1
// Execute the player's choice
when pl->b_combatChoice
is 'M'
playerMelee(pl, pWeapon)
nAttacks = calcNumAtt(pl, TRUE, pWeapon) // TRUE=melee
displayf1("nAttacks=%d\n", nAttacks)
for i = 1 to nAttacks
playerMelee(pl, pWeapon)
if i < nAttacks; combatPause; fin
next
checkSingleUse(pl, pWeapon)
break
is 'F'
return 0
is 'S'
for i = 1 to pl->b_shotChoice
if nEnemiesFighting and pWeapon->b_clipCurrent
playerShoot(pl, pWeapon)
consumeAmmo(pl, pWeapon)
if i+1 < pl->b_shotChoice; combatPause; fin
fin
nAttacks = calcNumAtt(pl, FALSE, pWeapon) // FALSE=not melee
displayf1("nAttacks=%d\n", nAttacks)
for i = 1 to nAttacks
for j = 1 to pl->b_shotChoice
if nEnemiesFighting and pWeapon->b_clipCurrent
playerShoot(pl, pWeapon)
consumeAmmo(pl, pWeapon)
if j < pl->b_shotChoice; combatPause; fin
fin
next
if i < nAttacks; combatPause; fin
next
checkSingleUse(pl, pWeapon)
break