mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-03-01 03:30:04 +00:00
Refactor to use lambdas for list iteration everywhere it's reasonable.
This commit is contained in:
parent
082bd4bf22
commit
68399614a5
@ -108,15 +108,7 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def scanModifiers(pMod, s_match)
|
||||
word sum
|
||||
sum = 0
|
||||
while pMod
|
||||
if streqi(pMod=>s_name, s_match)
|
||||
sum = sum + pMod=>w_modValue
|
||||
fin
|
||||
pMod = pMod=>p_nextObj
|
||||
loop
|
||||
return sum
|
||||
ctx = s_match; return sum(pMod, &(p) streqi(p=>s_name, ctx), &(p) p=>w_modValue)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -174,6 +166,13 @@ def rollEnemyDodge(pPlayer, pEnemy, sAction)
|
||||
return FALSE
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def killEnemy(pEnemy)#0
|
||||
pEnemy=>w_health = 0
|
||||
printf1(" %s is killed!", pEnemy=>s_name)
|
||||
nEnemiesFighting = nEnemiesFighting - 1
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def damageEnemy(pPlayer, pEnemy, dmg, sAction)#0
|
||||
if combatDebug
|
||||
@ -184,12 +183,10 @@ def damageEnemy(pPlayer, pEnemy, dmg, sAction)#0
|
||||
buildString(@addToString)
|
||||
printf3("\n%s %s %s ", pPlayer=>s_name, sAction, pEnemy=>s_name)
|
||||
printf1("for %d damage.", dmg)
|
||||
if pEnemy=>w_health <= dmg
|
||||
pEnemy=>w_health = 0
|
||||
printf1(" %s is killed!", pEnemy=>s_name)
|
||||
nEnemiesFighting = nEnemiesFighting - 1
|
||||
else
|
||||
if pEnemy=>w_health > dmg
|
||||
pEnemy=>w_health = pEnemy=>w_health - dmg
|
||||
else
|
||||
killEnemy(pEnemy)
|
||||
fin
|
||||
puts("\n")
|
||||
displayStr(finishString(0))
|
||||
@ -307,6 +304,12 @@ def playerShoot(pPlayer, pWeapon)#0
|
||||
damageEnemy(pPlayer, pEnemy, dmg, sAction)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def ammoMatches(ammo, kind)
|
||||
if ammo->t_type <> TYPE_FANCY_ITEM; return FALSE; fin
|
||||
return streqi(ammo=>s_itemKind, kind)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reloads the given weapon, as full as it can be given the player's ammo supply.
|
||||
def reload(pl, pWeapon, echo)#0
|
||||
@ -322,13 +325,7 @@ def reload(pl, pWeapon, echo)#0
|
||||
fin
|
||||
|
||||
// Find matching ammo
|
||||
item = pl=>p_items
|
||||
while item
|
||||
if item->t_type == TYPE_FANCY_ITEM
|
||||
if streqi(item=>s_itemKind, pWeapon=>s_ammoKind); break; fin
|
||||
fin
|
||||
item = item=>p_nextObj
|
||||
loop
|
||||
ctx = pWeapon; item = first(pl=>p_items, &(p) ammoMatches(p, ctx=>s_ammoKind))
|
||||
if !item
|
||||
if echo
|
||||
displayf3("\n%s has no ammo for %s %s!\n", pl=>s_name, hisHerTheir(pl->c_gender), pWeapon=>s_name))
|
||||
@ -373,22 +370,22 @@ end
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def displayOpponents()#0
|
||||
word p
|
||||
byte count, first
|
||||
byte count, firstTime
|
||||
byte isPlural
|
||||
|
||||
displayStr("You face ")
|
||||
first = TRUE
|
||||
firstTime = TRUE
|
||||
p = global=>p_enemyGroups
|
||||
while p
|
||||
if !first
|
||||
if !firstTime
|
||||
if p=>p_nextObj
|
||||
displayStr(", ")
|
||||
else
|
||||
displayStr(" and ")
|
||||
fin
|
||||
fin
|
||||
first = FALSE
|
||||
count = countListFiltered(p=>p_enemies, p_nextObj, @canFight)
|
||||
firstTime = FALSE
|
||||
count = sum(p=>p_enemies, @canFight, @trueFunc)
|
||||
isPlural = count <> 1
|
||||
if (p=>p_enemies=>r_groupSize == 0)
|
||||
displayf2("%s at %d'", p=>p_enemies=>s_name, p->b_enemyGroupRange)
|
||||
@ -410,19 +407,13 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def minEnemyDist()#1
|
||||
word p, p2, anybodyAlive, minDist
|
||||
word p, anybodyAlive, minDist
|
||||
minDist = 9999
|
||||
|
||||
// Process each group
|
||||
p = global=>p_enemyGroups
|
||||
while p
|
||||
p2 = p=>p_enemies
|
||||
anybodyAlive = FALSE
|
||||
while p2
|
||||
if canFight(p2); anybodyAlive = TRUE; fin
|
||||
p2 = p2=>p_nextObj
|
||||
loop
|
||||
if anybodyAlive
|
||||
if first(p=>p_enemies, @canFight)
|
||||
minDist = min(minDist, p->b_enemyGroupRange)
|
||||
fin
|
||||
p = p=>p_nextObj
|
||||
@ -640,11 +631,7 @@ def playerCombatTurn(pl)#0
|
||||
if !nEnemiesFighting; return; fin
|
||||
|
||||
// Get weapon
|
||||
pWeapon = pl=>p_items
|
||||
while pWeapon
|
||||
if pWeapon->t_type == TYPE_WEAPON and pWeapon->b_flags & ITEM_FLAG_EQUIP; break; fin
|
||||
pWeapon = pWeapon=>p_nextObj
|
||||
loop
|
||||
pWeapon = first(pl=>p_items, &(p) p->t_type == TYPE_WEAPON and p->b_flags & ITEM_FLAG_EQUIP)
|
||||
|
||||
// Execute the player's choice
|
||||
when pl->b_combatChoice
|
||||
@ -697,10 +684,9 @@ def enemyCombatTurn(pe)#1
|
||||
word pl, dodgeChance, pItem, damReduce
|
||||
byte roll, dam, needShow
|
||||
|
||||
// Choose a target
|
||||
pl = randomFromListFiltered(global=>p_players, p_nextObj, @canFight)
|
||||
if !pl; return FALSE; fin
|
||||
|
||||
// Choose a random target from amongst the fighting players
|
||||
roll = rand16() % nPlayersFighting
|
||||
pl = select(global=>p_players, @canFight, roll)
|
||||
isPlural = FALSE
|
||||
displayf3("\n%s %s %s ", pe=>s_name, pe=>s_attackText, pl=>s_name)
|
||||
|
||||
@ -747,6 +733,7 @@ def enemyCombatTurn(pe)#1
|
||||
pl=>w_health = max(0, pl=>w_health - dam)
|
||||
if pl=>w_health == 0
|
||||
displayf1(" %s is killed!", pl=>s_name)
|
||||
nPlayersFighting--
|
||||
fin
|
||||
needShow = TRUE
|
||||
fin
|
||||
@ -836,6 +823,17 @@ def makeEnemyGroup(enemyFunc)#1
|
||||
return p
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Return a random entry from an array which is terminated by a zero entry
|
||||
def randomFromArray(arr)#1
|
||||
byte siz
|
||||
siz = 0
|
||||
while *((siz << 1) + arr)
|
||||
siz++
|
||||
loop
|
||||
return *(((rand16() % siz) << 1) + arr)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def makeRandomGroup(mapCode)#0
|
||||
word enemiesModule
|
||||
@ -994,27 +992,6 @@ def startCombat(mapCode)#1
|
||||
return 0 // just to keep compiler happy
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// For cheating in god mode, kill all enemies. This is better than just setting nEnemiesFighting
|
||||
// to zero, because we'll still get loot.
|
||||
def killAllEnemies()#0
|
||||
word pGroup, pEnemy
|
||||
pGroup = global=>p_enemyGroups
|
||||
// For every group...
|
||||
while pGroup
|
||||
pEnemy = pGroup=>p_enemies
|
||||
// For every enemy in the group...
|
||||
while pEnemy
|
||||
pEnemy=>w_health = 0 // kill em
|
||||
pEnemy = pEnemy=>p_nextObj
|
||||
loop
|
||||
pGroup = pGroup=>p_nextObj
|
||||
loop
|
||||
|
||||
// Update nEnemiesFighting
|
||||
determineCombatOrder()
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def processWin()#0
|
||||
word gold, xp
|
||||
@ -1040,7 +1017,7 @@ def _combat_zoneEncounter(s_encZone)#1
|
||||
// Show portrait and threat details, find out if player wants to fight (vs. run)
|
||||
answer = startCombat(s_encZone)
|
||||
if answer == 99
|
||||
killAllEnemies()
|
||||
forEach(global=>p_enemyGroups, &(g) forEach(g=>p_enemies, @killEnemy))
|
||||
elsif answer == -99
|
||||
return answer // special code for death
|
||||
elsif !answer
|
||||
@ -1061,13 +1038,7 @@ def _combat_zoneEncounter(s_encZone)#1
|
||||
rawDisplayStr("\n")
|
||||
|
||||
// Get the choice of each player or NPC
|
||||
p = global=>p_players
|
||||
while p
|
||||
if canFight(p) and nEnemiesFighting and !isFleeing
|
||||
playerCombatChoose(p)
|
||||
fin
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
forSome(global=>p_players, &(pl) canFight(pl) and nEnemiesFighting and !isFleeing, @playerCombatChoose)
|
||||
clearWindow()
|
||||
|
||||
determineCombatOrder()
|
||||
|
@ -36,9 +36,7 @@ import gamelib
|
||||
predef clearEncounterZones()#0
|
||||
predef clearPortrait()#0
|
||||
predef clearWindow()#0
|
||||
predef countArray(arr)#1
|
||||
predef countList(p)#1
|
||||
predef countListFiltered(p, offset, filterFunc)#1
|
||||
predef crout()#0
|
||||
predef displayChar(chr)#0
|
||||
predef displayf1(fmt, arg1)#0
|
||||
@ -46,9 +44,13 @@ import gamelib
|
||||
predef displayf3(fmt, arg1, arg2, arg3)#0
|
||||
predef displayStr(str)#0
|
||||
predef encodeDice(nDice, dieSize, add)#1
|
||||
predef equipItem(item)#0
|
||||
predef fatal(msg)#1
|
||||
predef finishString(isPlural)#1
|
||||
predef flipToPage1()#0
|
||||
predef first(p, sel)#1
|
||||
predef forEach(p, do)#0
|
||||
predef forSome(p, sel, do)#0
|
||||
predef getCharResponse()#1
|
||||
predef getCursor()#2
|
||||
predef getDir()#1
|
||||
@ -61,6 +63,7 @@ import gamelib
|
||||
predef girdPlayer(player)#0
|
||||
predef giveItemToPlayer(p_player, itemFuncNum)#0
|
||||
predef hisHerTheir(c_gender)#1
|
||||
predef index(p, num)#1
|
||||
predef initHeap(loadedSize)#0
|
||||
predef initPlayerXP(player)#0
|
||||
predef loadFrameImg(img)#0
|
||||
@ -72,7 +75,6 @@ import gamelib
|
||||
predef min(a, b)#1
|
||||
predef mmgr(cmd, wordParam)#1
|
||||
predef moveWayBackward()#1
|
||||
predef numToPlayer(num)#1
|
||||
predef parseDec(str)#1
|
||||
predef partyHasPlayer(playerName)#1
|
||||
predef pause(count)#0
|
||||
@ -87,8 +89,6 @@ import gamelib
|
||||
predef queue_setMap(is3D, num, x, y, dir)#0
|
||||
predef queue_teleport(x, y, dir)#0
|
||||
predef rand16()#1
|
||||
predef randomFromArray(arr)#1
|
||||
predef randomFromListFiltered(p, offset, filterFunc)#1
|
||||
predef rawDisplayf1(fmt, arg1)#0
|
||||
predef rawDisplayf2(fmt, arg1, arg2)#0
|
||||
predef rawDisplayf3(fmt, arg1, arg2, arg3)#0
|
||||
@ -108,6 +108,7 @@ import gamelib
|
||||
predef scriptEvent(event, param)#0
|
||||
predef scriptSetAvatar(avatarTileNum)#0
|
||||
predef scriptSwapTile(fromX, fromY, toX, toY)#0
|
||||
predef select(p, sel, num)#1
|
||||
predef setCmd(key, func)#0
|
||||
predef setCursor(x, y)#0
|
||||
predef setGameFlag(flagName, val)#0
|
||||
@ -130,9 +131,11 @@ import gamelib
|
||||
predef sprintf2(fmt, arg1, arg2)#1
|
||||
predef sprintf3(fmt, arg1, arg2, arg3)#1
|
||||
predef streqi(a, b)#1
|
||||
predef sum(p, sel, func)#1
|
||||
predef takeItemFromPlayer(p_player, itemName)#0
|
||||
predef textHome()#0
|
||||
predef tossStrings()#0
|
||||
predef trueFunc()#1
|
||||
predef unbenchPlayer()#0
|
||||
|
||||
// This pointer is the root of all heap-tracked (and garbage collected) objects.
|
||||
@ -148,6 +151,7 @@ import gamelib
|
||||
word pGodModule
|
||||
word typeHash
|
||||
byte isPlural
|
||||
word ctx
|
||||
|
||||
/////////// Shared string constants //////////////
|
||||
|
||||
|
@ -124,6 +124,9 @@ byte animDirCt
|
||||
byte anyAnims = TRUE
|
||||
word animPauseCt
|
||||
|
||||
// Context for lambda functions (in lieu of closures, for now at least)
|
||||
export word ctx
|
||||
|
||||
// Shared string constants
|
||||
export byte[] S_INTELLIGENCE = "Intelligence"
|
||||
export byte[] S_STRENGTH = "Strength"
|
||||
@ -941,39 +944,41 @@ export asm streqi(a, b)#1
|
||||
+asmPlasmRet 2
|
||||
sta tmp
|
||||
sty tmp+1
|
||||
beq .noteqi ; NULL is never equal
|
||||
lda evalStkL+1,x
|
||||
sta pTmp
|
||||
lda evalStkH+1,x
|
||||
sta pTmp+1
|
||||
beq .noteqi ; NULL is never equal
|
||||
ldy #0
|
||||
lda (tmp),y
|
||||
cmp (pTmp),y
|
||||
beq + ; if lengths not equal, strings can't be equal
|
||||
--
|
||||
beq + ; if lengths not equal, strings can't be equal
|
||||
.noteqi
|
||||
lda #0
|
||||
tay
|
||||
rts
|
||||
+ tax ; count up to (verified same) length of the strings
|
||||
+ tax ; count up to (verified same) length of the strings
|
||||
- iny
|
||||
lda (tmp),y
|
||||
cmp #('z'&$7F)+1 ; convert to upper case
|
||||
cmp #('z'&$7F)+1 ; convert to upper case
|
||||
bcs +
|
||||
cmp #'a'&$7F
|
||||
bcc +
|
||||
sbc #$20
|
||||
+ sta ysav
|
||||
lda (pTmp),y
|
||||
cmp #('z'&$7F)+1 ; convert to upper case
|
||||
cmp #('z'&$7F)+1 ; convert to upper case
|
||||
bcs +
|
||||
cmp #'a'&$7F
|
||||
bcc +
|
||||
sbc #$20
|
||||
+ cmp ysav
|
||||
bne -- ; abort on inequality
|
||||
bne .noteqi ; abort on inequality
|
||||
dex
|
||||
bne -
|
||||
lda #1
|
||||
ldy #0 ; okay, they're equal. Return 1 (not just any char; so that PLASMA when...is can work)
|
||||
ldy #0 ; okay, they're equal. Return 1 (not just any char; so that PLASMA when...is can work)
|
||||
rts
|
||||
end
|
||||
|
||||
@ -1227,6 +1232,57 @@ export def getCharResponse()#1
|
||||
return mmgr(HEAP_INTERN, $200)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def trueFunc(x)#1
|
||||
return 1
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def select(p, sel, num)#1
|
||||
while p
|
||||
if sel(p)
|
||||
if !num; break; fin
|
||||
num--
|
||||
fin
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
return p
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def first(p, sel)#1
|
||||
return select(p, sel, 0)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def index(p, num)#1
|
||||
return select(p, @trueFunc, num)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def sum(p, sel, func)#1
|
||||
word sum
|
||||
sum = 0
|
||||
while p
|
||||
if sel(p); sum = sum + func(p); fin
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
return sum
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def forSome(p, sel, do)#0
|
||||
while p
|
||||
if sel(p); do(p)#0; fin
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def forEach(p, do)#0
|
||||
forSome(p, @trueFunc, do)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Pause for a specified count period, advancing the animation periodically.
|
||||
export def pause(count)#0
|
||||
@ -1519,6 +1575,12 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Display the party data on the screen
|
||||
def showPartyLine(p)#0
|
||||
if p <> global=>p_players; displayChar('\n'); fin
|
||||
if p->b_skillPoints; rawDisplayStr("^I"); fin // inverse for chars needing lvl-up
|
||||
rawDisplayf1("%s^N", p=>s_name)
|
||||
rightJustifyStr(sprintf2("%d/%d", p=>w_health, p=>w_maxHealth), CHAR_WND_HEALTH_X)
|
||||
end
|
||||
export def showParty()#0
|
||||
word p, cursX, cursY
|
||||
|
||||
@ -1526,13 +1588,8 @@ export def showParty()#0
|
||||
setWindow3()
|
||||
clearWindow()
|
||||
|
||||
// Display header (or LEVEL UP message)
|
||||
p = global=>p_players
|
||||
while p
|
||||
if p->b_skillPoints; break; fin
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
if p
|
||||
// Display header (or LEVEL UP message if any player has un-applied skill pts)
|
||||
if first(global=>p_players, &(p) p->b_skillPoints)
|
||||
rawDisplayStr("^Y^I LEVEL U)P ^N\n")
|
||||
else
|
||||
rawDisplayStr("^LName")
|
||||
@ -1541,14 +1598,7 @@ export def showParty()#0
|
||||
fin
|
||||
|
||||
// Display each character's name and health
|
||||
p = global=>p_players
|
||||
while p
|
||||
if p <> global=>p_players; displayChar('\n'); fin
|
||||
if p->b_skillPoints; rawDisplayStr("^I"); fin // inverse for chars needing lvl-up
|
||||
rawDisplayf1("%s^N", p=>s_name)
|
||||
rightJustifyStr(sprintf2("%d/%d", p=>w_health, p=>w_maxHealth), CHAR_WND_HEALTH_X)
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
forEach(global=>p_players, @showPartyLine)
|
||||
|
||||
// Finish up
|
||||
if mapIs3D and texturesLoaded; copyWindow(); fin
|
||||
@ -2216,51 +2266,7 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def countList(p)#1
|
||||
byte n
|
||||
n = 0
|
||||
while p
|
||||
n++
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
return n
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def countListFiltered(p, offset, filterFunc)#1
|
||||
byte n
|
||||
n = 0
|
||||
while p
|
||||
if filterFunc(p)
|
||||
n++
|
||||
fin
|
||||
p = *(p + offset)
|
||||
loop
|
||||
return n
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Find the end of a null-terminated array
|
||||
export def countArray(arr)#1
|
||||
byte count
|
||||
for count = 0 to 127
|
||||
if !*arr; break; fin
|
||||
arr = arr + 2
|
||||
next
|
||||
return count
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def randomFromListFiltered(p, offset, filterFunc)#1
|
||||
byte n
|
||||
n = rand16() % countListFiltered(p, offset, filterFunc)
|
||||
while p
|
||||
if filterFunc(p)
|
||||
if n == 0; return p; fin
|
||||
n--
|
||||
fin
|
||||
p = *(p + offset)
|
||||
loop
|
||||
return NULL
|
||||
return sum(p, @trueFunc, @trueFunc)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2723,17 +2729,6 @@ export def initHeap(loadedSize)#0
|
||||
fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Return a random entry from an array which is terminated by a zero entry
|
||||
export def randomFromArray(arr)#1
|
||||
byte siz
|
||||
siz = 0
|
||||
while *((siz << 1) + arr)
|
||||
siz++
|
||||
loop
|
||||
return *(((rand16() % siz) << 1) + arr)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor: create a modifier given its name and value
|
||||
export def makeModifier(name, value)#1
|
||||
@ -2745,16 +2740,8 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Recalculate player's armor score based on their currently equipped armor
|
||||
export def calcPlayerArmor(player)#0
|
||||
word pItem
|
||||
player->b_armor = 0
|
||||
pItem = player=>p_items
|
||||
while pItem
|
||||
if pItem->t_type == TYPE_ARMOR and pItem->b_flags & ITEM_FLAG_EQUIP
|
||||
player->b_armor = player->b_armor + pItem->b_armorValue
|
||||
fin
|
||||
pItem = pItem=>p_nextObj
|
||||
loop
|
||||
export def calcPlayerArmor(pl)#0
|
||||
pl->b_armor = sum(pl=>p_items, &(p) p->t_type == TYPE_ARMOR and p->b_flags & ITEM_FLAG_EQUIP, &(p) p->b_armorValue)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2777,12 +2764,8 @@ export def payGold(amount)#1
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def scanForNamedObj(p_obj, name)#1
|
||||
while p_obj
|
||||
if streqi(p_obj=>s_name, name); return p_obj; fin
|
||||
p_obj = p_obj=>p_nextObj
|
||||
loop
|
||||
return NULL
|
||||
export def scanForNamedObj(list, name)#1
|
||||
ctx = name; return first(list, &(p) streqi(p=>s_name, ctx))
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2878,24 +2861,16 @@ export def initPlayerXP(player)#0
|
||||
player=>w_nextXP = callGlobalFunc(GS_LEVEL_X_P, player->b_level + 1, 0, 0)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def equipItem(item)#0
|
||||
item->b_flags = item->b_flags | ITEM_FLAG_EQUIP
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Arm newly created player (or NPC) with first weapon and all armor.
|
||||
export def girdPlayer(player)#0
|
||||
word pItem
|
||||
byte weaponFound
|
||||
weaponFound = FALSE
|
||||
pItem = player=>p_items
|
||||
while pItem
|
||||
if pItem->t_type == TYPE_WEAPON
|
||||
if !weaponFound
|
||||
pItem->b_flags = pItem->b_flags | ITEM_FLAG_EQUIP
|
||||
weaponFound = TRUE
|
||||
fin
|
||||
elsif pItem->t_type == TYPE_ARMOR
|
||||
pItem->b_flags = pItem->b_flags | ITEM_FLAG_EQUIP
|
||||
fin
|
||||
pItem = pItem=>p_nextObj
|
||||
loop
|
||||
equipItem(first(player=>p_items, &(p) p->t_type == TYPE_WEAPON))
|
||||
forSome(player=>p_items, &(p) p->t_type == TYPE_ARMOR, @equipItem)
|
||||
calcPlayerArmor(player)
|
||||
end
|
||||
|
||||
@ -2935,11 +2910,7 @@ export def takeItemFromPlayer(p_player, itemName)#0
|
||||
if removeNamed(itemName, @p_player=>p_items); return; fin
|
||||
|
||||
// Fall back to all players, e.g. Prosp. Paul using his TNT.
|
||||
p_player = global=>p_players
|
||||
while p_player
|
||||
if removeNamed(itemName, @p_player=>p_items); return; fin
|
||||
p_player = p_player=>p_nextObj
|
||||
loop
|
||||
ctx = itemName; first(global=>p_players, &(p) removeNamed(ctx, @p=>p_items))
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2950,12 +2921,12 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def playerHasItem(itemName)#1
|
||||
return scanForNamedObj(global=>p_players=>p_items, itemName) <> NULL
|
||||
ctx = itemName; return first(global=>p_players, &(p) scanForNamedObj(p=>p_items, ctx))
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def partyHasPlayer(playerName)#1
|
||||
return scanForNamedObj(global=>p_players, playerName) <> NULL
|
||||
return scanForNamedObj(global=>p_players, playerName)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2978,11 +2949,8 @@ export def getStat(player, statName)#1
|
||||
is streqi(statName, @S_XP); return player=>w_curXP
|
||||
is streqi(statName, @S_SP); return player->b_skillPoints
|
||||
wend
|
||||
pSkill = player=>p_skills
|
||||
while pSkill
|
||||
if streqi(statName, pSkill=>s_name); return pSkill=>w_modValue; fin
|
||||
pSkill = pSkill=>p_nextObj
|
||||
loop
|
||||
pSkill = scanForNamedObj(player=>p_skills, statName)
|
||||
if pSkill; return pSkill=>w_modValue; fin
|
||||
puts(statName); return fatal("getStat")
|
||||
end
|
||||
|
||||
@ -3019,15 +2987,12 @@ export def setStat(player, statName, val)#0
|
||||
is streqi(statName, @S_XP); player=>w_curXP = max(player=>w_curXP, val); needShowParty = TRUE; break
|
||||
is streqi(statName, @S_SP); player->b_skillPoints = max(0, val); needShowParty = TRUE; break
|
||||
otherwise
|
||||
pSkill = player=>p_skills
|
||||
while pSkill
|
||||
if streqi(statName, pSkill=>s_name)
|
||||
pSkill=>w_modValue = max(0, val)
|
||||
return
|
||||
fin
|
||||
pSkill = pSkill=>p_nextObj
|
||||
loop
|
||||
puts(statName); fatal("setStat")
|
||||
pSkill = scanForNamedObj(player=>p_skills, statName)
|
||||
if pSkill
|
||||
pSkill=>w_modValue = max(0, val)
|
||||
else
|
||||
puts(statName); fatal("setStat")
|
||||
fin
|
||||
wend
|
||||
end
|
||||
|
||||
@ -3088,17 +3053,6 @@ export def buySell(storeCode, profitRatio)#0
|
||||
if portrait; setPortrait(portrait); fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export def numToPlayer(num)#1
|
||||
word player
|
||||
player = global=>p_players
|
||||
while player and num > 0
|
||||
player = player=>p_nextObj
|
||||
num--
|
||||
loop
|
||||
return player
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def startGame(ask)#0
|
||||
word p_module
|
||||
|
@ -58,16 +58,6 @@ word = @_displayItemStats, @_displayItemName
|
||||
|
||||
// Other global variables here
|
||||
|
||||
def travFind2(pObj, val, func)
|
||||
word ret
|
||||
while pObj
|
||||
val, ret = func(val, pObj)#2
|
||||
if ret; return pObj; fin
|
||||
pObj = pObj=>p_nextObj
|
||||
loop
|
||||
return NULL
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def isEquipped(pItem)#1
|
||||
if pItem->t_type == TYPE_ARMOR or pItem->t_type == TYPE_WEAPON
|
||||
@ -76,29 +66,6 @@ def isEquipped(pItem)#1
|
||||
return FALSE
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def itemByNum(player, num)#1
|
||||
return travFind2(player=>p_items, num, &(n,p)(n-1, n==0))
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Unequip item kind
|
||||
def unequip(player, type, kind)#1
|
||||
word item
|
||||
|
||||
item = player=>p_items
|
||||
while item
|
||||
if item->t_type == type
|
||||
if (streqi(item=>s_itemKind, kind) or type == TYPE_WEAPON) and isEquipped(item)
|
||||
item->b_flags = item->b_flags & ~ITEM_FLAG_EQUIP
|
||||
break
|
||||
fin
|
||||
fin
|
||||
item = item=>p_nextObj
|
||||
loop
|
||||
return item
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Display title of a column at top but below character name. Optionally append a second string,
|
||||
// then leave a little vertical space below before beginning the content of the column.
|
||||
@ -114,24 +81,18 @@ end
|
||||
// Display inventory list page. Return number of items on page.
|
||||
def showInventory(player, page, select)#1
|
||||
word item
|
||||
byte s_item, n_item, n_page, totalPages, first
|
||||
byte s_item, n_item, n_page, totalPages, firstTime
|
||||
|
||||
s_item = 0
|
||||
n_item = 0
|
||||
n_page = page * INV_ROWS
|
||||
item = player=>p_items
|
||||
totalPages = (countList(item)+INV_ROWS-1) / INV_ROWS
|
||||
totalPages = (countList(player=>p_items)+INV_ROWS-1) / INV_ROWS
|
||||
showColumnTitle(INV_X-10, "Inventory", page+1, totalPages)
|
||||
if page
|
||||
while item and n_item < n_page
|
||||
item = item=>p_nextObj
|
||||
n_item++
|
||||
loop
|
||||
fin
|
||||
first = TRUE
|
||||
item = index(player=>p_items, n_page)
|
||||
n_item = n_page
|
||||
firstTime = TRUE
|
||||
while item and n_item < (n_page + INV_ROWS)
|
||||
if !first; displayChar('\n'); fin
|
||||
first = FALSE
|
||||
if !firstTime; displayChar('\n'); fin
|
||||
firstTime = FALSE
|
||||
|
||||
if isEquipped(item)
|
||||
rawDisplayStr("*")
|
||||
@ -188,12 +149,7 @@ def showDerived(player)#0
|
||||
rawDisplayf1("^T%DArmor\n", STATLBL_X)
|
||||
|
||||
// Get weapon
|
||||
weapon = player=>p_items
|
||||
while weapon
|
||||
if weapon->t_type == TYPE_WEAPON and isEquipped(weapon); break; fin
|
||||
weapon = weapon=>p_nextObj
|
||||
loop
|
||||
|
||||
weapon = first(player=>p_items, &(w) w->t_type == TYPE_WEAPON and isEquipped(w))
|
||||
if weapon
|
||||
if weapon=>r_projectileDmg
|
||||
displayDice(weapon=>r_projectileDmg)
|
||||
@ -258,13 +214,8 @@ def showSkills(player)#0
|
||||
if player->b_aiming; displaySkill(x1, @S_AIMING, @player->b_aiming, TRUE); fin
|
||||
if player->b_handToHand; displaySkill(x1, @S_HAND_TO_HAND, @player->b_handToHand, TRUE); fin
|
||||
if player->b_dodging; displaySkill(x1, @S_DODGING, @player->b_dodging, TRUE); fin
|
||||
skill = player=>p_skills
|
||||
while skill
|
||||
if skill=>w_modValue > 0
|
||||
displaySkill(x1, skill=>s_name, skill+w_modValue, TRUE)
|
||||
fin
|
||||
skill = skill=>p_nextObj
|
||||
loop
|
||||
ctx = x1
|
||||
forSome(player=>p_skills, &(p) p=>w_modValue, &(p) displaySkill(ctx, p=>s_name, p+w_modValue, TRUE))
|
||||
|
||||
// Second column: attributes
|
||||
showColumnTitle(STAT_X-5, "Attributes", 0, 0)
|
||||
@ -401,10 +352,30 @@ def clearMainRect()#0
|
||||
rawDisplayStr("^V000\n^J^J^J")
|
||||
end
|
||||
|
||||
// Equip/unequip an item.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def armsMatch(i1, i2)
|
||||
if i1 == i2 or i1->t_type <> i2->t_type or !isEquipped(i2); return FALSE; fin
|
||||
if i1->t_type == TYPE_WEAPON; return TRUE; fin // can only equip 1 weapon at a time
|
||||
return streqi(i1=>s_itemKind, i2=>s_itemKind) // type must be armor, since isEquipped is true
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def findMatchingEquip(player, item)
|
||||
ctx = item; return first(player=>p_items, &(p) armsMatch(ctx, p)))
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Equip/unequip a weapon or armor piece
|
||||
def doEquip(player, item)#0
|
||||
if unequip(player, item->t_type, item=>s_itemKind) <> item
|
||||
item->b_flags = item->b_flags | ITEM_FLAG_EQUIP
|
||||
word match
|
||||
if item->b_flags & ITEM_FLAG_EQUIP
|
||||
// Unequipping a piece
|
||||
item->b_flags = item->b_flags & ~ITEM_FLAG_EQUIP
|
||||
else
|
||||
// Equipping a piece: be sure to unequip other matching piece (if any)
|
||||
match = findMatchingEquip(player, item)
|
||||
if match; match->b_flags = item->b_flags & ~ITEM_FLAG_EQUIP; fin
|
||||
equipItem(item)
|
||||
fin
|
||||
calcPlayerArmor(player)
|
||||
end
|
||||
@ -441,17 +412,17 @@ end
|
||||
// Trade an item to another player/npc
|
||||
def doTrade(player, item)#1
|
||||
word destPlayer
|
||||
byte first, sel
|
||||
byte firstTime, sel
|
||||
|
||||
clearMenuRect()
|
||||
rawDisplayStr("To: ")
|
||||
destPlayer = global=>p_players
|
||||
sel = 0
|
||||
first = TRUE
|
||||
firstTime = TRUE
|
||||
while destPlayer
|
||||
if player <> destPlayer
|
||||
if !first; rawDisplayStr(", "); fin
|
||||
first = FALSE
|
||||
if !firstTime; rawDisplayStr(", "); fin
|
||||
firstTime = FALSE
|
||||
rawDisplayf2("%d. %s", sel+1, destPlayer=>s_name)
|
||||
fin
|
||||
sel++
|
||||
@ -462,7 +433,7 @@ def doTrade(player, item)#1
|
||||
while TRUE
|
||||
sel = getUpperKey()
|
||||
if sel == $1B; return 0; fin
|
||||
destPlayer = numToPlayer(sel-'1')
|
||||
destPlayer = index(global=>p_players, sel-'1')
|
||||
if destPlayer and destPlayer <> player
|
||||
removeFromList(@player=>p_items, item)
|
||||
addUnique(@destPlayer=>p_items, item)
|
||||
@ -528,26 +499,23 @@ def doUse(player, item)#1
|
||||
if item->t_type == TYPE_FANCY_ITEM and item=>p_modifiers
|
||||
clearMenuRect()
|
||||
clearMainRect()
|
||||
pMod = item=>p_modifiers
|
||||
while pMod
|
||||
oldVal = getStat(player, pMod=>s_name)
|
||||
setStat(player, pMod=>s_name, oldVal + pMod=>w_modValue)
|
||||
newVal = getStat(player, pMod=>s_name)
|
||||
rawDisplayStr(pMod=>s_name)
|
||||
if newVal <> oldVal
|
||||
takeItemFromPlayer(player, item=>s_name) // also handles reducing count of stackables
|
||||
if newVal > oldVal
|
||||
rawDisplayStr(" increased")
|
||||
else
|
||||
rawDisplayStr(" decreased")
|
||||
fin
|
||||
rawDisplayf2(" from %d to %d.", oldVal, newVal)
|
||||
pMod = item=>p_modifiers // we only support one per item at present
|
||||
oldVal = getStat(player, pMod=>s_name)
|
||||
setStat(player, pMod=>s_name, oldVal + pMod=>w_modValue)
|
||||
newVal = getStat(player, pMod=>s_name)
|
||||
rawDisplayStr(pMod=>s_name)
|
||||
if newVal <> oldVal
|
||||
takeItemFromPlayer(player, item=>s_name) // also handles reducing count of stackables
|
||||
if newVal > oldVal
|
||||
rawDisplayStr(" increased")
|
||||
else
|
||||
rawDisplayStr(" already at the limit.")
|
||||
rawDisplayStr(" decreased")
|
||||
fin
|
||||
pause(800)
|
||||
pMod = pMod=>p_nextObj
|
||||
loop
|
||||
rawDisplayf2(" from %d to %d.", oldVal, newVal)
|
||||
else
|
||||
rawDisplayStr(" already at the limit.")
|
||||
fin
|
||||
pause(800)
|
||||
return NULL
|
||||
fin
|
||||
return item // general 'use' handled by outer engine, because it might involve graphics
|
||||
@ -567,21 +535,6 @@ def doDestroy(player, item)#1
|
||||
return FALSE
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def matchEquipped(player, match)#1
|
||||
word item
|
||||
item = player=>p_items
|
||||
while item
|
||||
if item->t_type == match->t_type and item <> match and isEquipped(item)
|
||||
if item->t_type <> TYPE_ARMOR or (item=>s_itemKind == match=>s_itemKind)
|
||||
return item
|
||||
fin
|
||||
fin
|
||||
item = item=>p_nextObj
|
||||
loop
|
||||
return NULL
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def displayItems(pItem1, pItem2)#0
|
||||
clearMainRect()
|
||||
@ -598,21 +551,21 @@ def interactWithItem(player, item)#1
|
||||
word comp, quantity
|
||||
byte sel, ok
|
||||
ok = TRUE
|
||||
displayItems(item, matchEquipped(player, item))
|
||||
displayItems(item, findMatchingEquip(player, item))
|
||||
while TRUE
|
||||
showItemMenu(item)
|
||||
if !ok; beep; fin
|
||||
ok = FALSE
|
||||
sel = getUpperKey()
|
||||
when sel
|
||||
// Equip player with weapon/armor
|
||||
// Equip/unequip player with weapon/armor
|
||||
is 'E'
|
||||
if (item->t_type == TYPE_ARMOR or item->t_type == TYPE_WEAPON)
|
||||
doEquip(player, item)
|
||||
return displayDone()
|
||||
fin
|
||||
break
|
||||
// Use or Unequip an item
|
||||
// Use an item
|
||||
is 'U'
|
||||
if item->t_type == TYPE_PLAIN_ITEM or item->t_type == TYPE_FANCY_ITEM
|
||||
return doUse(player, item) // general 'use' handled by outer engine, because it might involve graphics
|
||||
@ -628,14 +581,14 @@ def interactWithItem(player, item)#1
|
||||
is 'S'
|
||||
if isSplittable(item)
|
||||
ok = doSplit(player, item)
|
||||
if ok; displayItems(item, matchEquipped(player, item)); fin
|
||||
if ok; displayItems(item, NULL); fin
|
||||
fin
|
||||
break
|
||||
// Join stacks
|
||||
is 'J'
|
||||
if isJoinable(item)
|
||||
ok = doJoin(player, item)
|
||||
if ok; displayItems(item, matchEquipped(player, item)); fin
|
||||
if ok; displayItems(item, NULL); fin
|
||||
fin
|
||||
break
|
||||
// Destroy an item
|
||||
@ -666,14 +619,14 @@ def _showPlayerSheet(player_num)#1 // funcTbl functions always have to return a
|
||||
i_page = 0
|
||||
redisplay = 2
|
||||
noRepeatMenu = FALSE
|
||||
player = numToPlayer(player_num)
|
||||
player = index(global=>p_players, player_num)
|
||||
if player->b_skillPoints
|
||||
mode = 'S' // go straight to level up if applicable
|
||||
else
|
||||
mode = 'I' // otherwise default to inventory mode
|
||||
fin
|
||||
repeat
|
||||
player = numToPlayer(player_num)
|
||||
player = index(global=>p_players, player_num)
|
||||
if !player; beep; return NULL; fin
|
||||
if redisplay >= 2
|
||||
clearWindow()
|
||||
@ -783,7 +736,7 @@ def _showPlayerSheet(player_num)#1 // funcTbl functions always have to return a
|
||||
elsif mode == 'I'
|
||||
sel = sel - 'A'
|
||||
if sel >= 0 and sel < itemsOnPage
|
||||
item = interactWithItem(player, itemByNum(player, i_page * INV_ROWS + sel))
|
||||
item = interactWithItem(player, index(player=>p_items, i_page * INV_ROWS + sel))
|
||||
if item; return item; fin // Use an item
|
||||
if countList(player=>p_items) <= i_page * INV_ROWS // destroyed last item on pg 2
|
||||
i_page--
|
||||
@ -836,17 +789,7 @@ def selectPlayer(players)#1
|
||||
// Then get a selection
|
||||
rawDisplayStr("\nWhich character?")
|
||||
n_item = getUpperKey() - 'A'
|
||||
player = players
|
||||
while player
|
||||
if player->b_playerFlags & PLAYER_FLAG_NPC
|
||||
if n_item == 0
|
||||
break
|
||||
fin
|
||||
n_item--
|
||||
fin
|
||||
player = player=>p_nextObj
|
||||
loop
|
||||
return player
|
||||
return select(players, &(p) p->b_playerFlags & PLAYER_FLAG_NPC, n_item)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -46,6 +46,17 @@ pTmp = $4
|
||||
ysav = $34
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Find the end of a null-terminated array
|
||||
def countArray(arr)#1
|
||||
byte count
|
||||
for count = 0 to 127
|
||||
if !*arr; break; fin
|
||||
arr = arr + 2
|
||||
next
|
||||
return count
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def loadExtraModules()#0
|
||||
mmgr(START_LOAD, 1) // code is in partition 1
|
||||
@ -235,7 +246,7 @@ def storeSetup()#0
|
||||
|
||||
playerCount = countList(global=>p_players)
|
||||
playerNum = 0
|
||||
pPlayer = numToPlayer(playerNum)
|
||||
pPlayer = index(global=>p_players, playerNum)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -264,7 +275,7 @@ def _buyFromStore(storeCode, profitPercent)#1
|
||||
pageNum++
|
||||
elsif choice >= '1' and (choice-'1') <= playerCount and (choice-'1') <> playerNum
|
||||
playerNum = choice - '1'
|
||||
pPlayer = numToPlayer(playerNum)
|
||||
pPlayer = index(global=>p_players, playerNum)
|
||||
elsif choice >= 'A' and (choice-'A' < nItemsOnPage)
|
||||
browseItem(choice-'A')
|
||||
elsif choice == $1B // Esc
|
||||
@ -364,7 +375,7 @@ def _sellToStore(profitPercent)#1
|
||||
pageNum++
|
||||
elsif choice >= '1' and (choice-'1') <= playerCount
|
||||
playerNum = choice - '1'
|
||||
pPlayer = numToPlayer(playerNum)
|
||||
pPlayer = index(global=>p_players, playerNum)
|
||||
totalItems = iterateSellables(9999, 0)
|
||||
elsif choice >= 'A' and (choice-'A' < nItemsOnPage)
|
||||
sellItem(choice-'A')
|
||||
|
Loading…
x
Reference in New Issue
Block a user