mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-09-27 14:56:40 +00:00
Added ability to reload weapon from inventory screen. Added auto-reload after combat.
This commit is contained in:
parent
37af866d24
commit
cda4387507
@ -16,6 +16,7 @@ include "gen_items.plh"
|
||||
include "gen_enemies.plh"
|
||||
include "gen_modules.plh"
|
||||
include "combat.plh"
|
||||
include "itemutil.plh"
|
||||
|
||||
struc EnemyData
|
||||
word s_en_name
|
||||
@ -49,26 +50,25 @@ byte[] S_A = "a "
|
||||
byte[] S_EMPTY = ""
|
||||
|
||||
// To save time, we preload global funcs
|
||||
const NUM_PRELOADS = 3
|
||||
byte[] toPreload = GS_COMBAT_PROMPT, GS_ENEMY_INTRO, GS_COMBAT_WIN
|
||||
const NUM_PRELOADS = 4
|
||||
byte[] toPreload = MOD_ITEMUTIL, GS_COMBAT_PROMPT, GS_ENEMY_INTRO, GS_COMBAT_WIN
|
||||
word[4] preloads
|
||||
word pItemUtil
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def preload()#0
|
||||
byte i
|
||||
for i = 0 to NUM_PRELOADS-1
|
||||
mmgr(QUEUE_LOAD, toPreload[i]<<8 | RES_TYPE_MODULE)
|
||||
preloads[i] = mmgr(QUEUE_LOAD, toPreload[i]<<8 | RES_TYPE_MODULE)
|
||||
next
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def freePreloaded()#0
|
||||
byte i
|
||||
word p
|
||||
for i = 0 to NUM_PRELOADS-1
|
||||
p = mmgr(FIND_IN_MEM, toPreload[i]<<8 | RES_TYPE_MODULE)
|
||||
if p; mmgr(FREE_MEMORY, p); fin
|
||||
mmgr(FREE_MEMORY, preloads[i])
|
||||
next
|
||||
mmgr(FINISH_LOAD, 0)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -362,52 +362,6 @@ 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
|
||||
word item
|
||||
byte orig, n
|
||||
|
||||
isPlural = FALSE
|
||||
|
||||
// If ammo type is null, it means weapon doesn't use ammo in traditional sense.
|
||||
if !pWeapon=>s_ammoKind
|
||||
pWeapon->b_clipCurrent = 1
|
||||
return
|
||||
fin
|
||||
|
||||
// Find matching ammo
|
||||
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))
|
||||
fin
|
||||
return
|
||||
fin
|
||||
|
||||
// Transfer ammo to weapon
|
||||
if pWeapon->b_clipSize
|
||||
n = min(item=>w_count, pWeapon->b_clipSize - pWeapon->b_clipCurrent)
|
||||
else
|
||||
n = min(item=>w_count, 1) // clipSize=0 implies auto-reloading weapon
|
||||
fin
|
||||
pWeapon->b_clipCurrent = pWeapon->b_clipCurrent + n
|
||||
item=>w_count = item=>w_count - n
|
||||
if item=>w_count == 0
|
||||
removeFromList(@pl=>p_items, item)
|
||||
fin
|
||||
if echo
|
||||
displayf3("\n%s reloads %s %s.\n", pl=>s_name, hisHerTheir(pl->c_gender), pWeapon=>s_name)
|
||||
fin
|
||||
if combatDebug; displayf2("Moved %d ammo, %d left\n", n, item=>w_count); getUpperKey; fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def consumeAmmo(pl, pWeapon)#0
|
||||
if !pWeapon->b_clipCurrent; fatal("clip zero"); fin // sanity check
|
||||
@ -416,7 +370,7 @@ def consumeAmmo(pl, pWeapon)#0
|
||||
|
||||
// Special (for e.g. bows): clipSize zero means weapon reloads automatically
|
||||
if !pWeapon->b_clipCurrent and !pWeapon->b_clipSize
|
||||
reload(pl, pWeapon, FALSE) // silently reload
|
||||
pItemUtil=>itemutil_reloadWeapon(pl, pWeapon, FALSE) // silently reload
|
||||
fin
|
||||
end
|
||||
|
||||
@ -605,7 +559,7 @@ def playerCombatChoose(pl)#0
|
||||
if pWeapon
|
||||
// Special (for e.g. bows): clipSize zero means weapon reloads automatically
|
||||
if pWeapon=>r_projectileDmg and !pWeapon->b_clipCurrent and !pWeapon->b_clipSize
|
||||
reload(pl, pWeapon, FALSE) // silently reload
|
||||
pItemUtil=>itemutil_reloadWeapon(pl, pWeapon, FALSE) // silently reload
|
||||
fin
|
||||
if pWeapon->b_clipCurrent
|
||||
canShoot = TRUE
|
||||
@ -680,6 +634,11 @@ def checkSingleUse(pl, pWeapon)#0
|
||||
removeFromList(@pl=>p_items, pWeapon)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def getWeapon(pl)#1
|
||||
return first(pl=>p_items, &(p) p->t_type == TYPE_WEAPON and p->b_flags & ITEM_FLAG_EQUIP)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def playerCombatTurn(pl)#0
|
||||
word pWeapon, pGroup, pEnemy
|
||||
@ -688,7 +647,7 @@ def playerCombatTurn(pl)#0
|
||||
if !nEnemiesFighting; return; fin
|
||||
|
||||
// Get weapon
|
||||
pWeapon = first(pl=>p_items, &(p) p->t_type == TYPE_WEAPON and p->b_flags & ITEM_FLAG_EQUIP)
|
||||
pWeapon = getWeapon(pl)
|
||||
|
||||
// Execute the player's choice
|
||||
when pl->b_combatChoice
|
||||
@ -709,7 +668,7 @@ def playerCombatTurn(pl)#0
|
||||
checkSingleUse(pl, pWeapon)
|
||||
break
|
||||
is 'R'
|
||||
reload(pl, pWeapon, TRUE) // TRUE = echo
|
||||
pItemUtil=>itemutil_reloadWeapon(pl, pWeapon, TRUE) // TRUE = echo
|
||||
break
|
||||
is 'C'
|
||||
// Choose a different weapon
|
||||
@ -1049,6 +1008,7 @@ def startCombat(mapCode)#1
|
||||
// Display portrait of first group
|
||||
setPortrait(global=>p_enemyGroups=>p_enemies->b_image)
|
||||
mmgr(FINISH_LOAD, 0)
|
||||
pItemUtil = preloads[0]()
|
||||
|
||||
// Clear keyboard stobe, because while wandering the map, the player may have
|
||||
// queued up movement keys, which are made obsolete by the surprise of combat.
|
||||
@ -1091,12 +1051,24 @@ def startCombat(mapCode)#1
|
||||
return 0 // just to keep compiler happy
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def autoReload(pl)#0
|
||||
pItemUtil=>itemutil_reloadWeapon(pl, getWeapon(pl), FALSE)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def processWin()#0
|
||||
word gold, xp
|
||||
rawDisplayStr("^T000")
|
||||
word gold, xp, player, tmp
|
||||
|
||||
// Reload each player's weapon if possible
|
||||
forEach(global=>p_players, &(pl) autoReload(pl))
|
||||
|
||||
// Clear the window, then display the win message
|
||||
clearWindow
|
||||
callGlobalFunc(GS_COMBAT_WIN, 0, 0, 0)
|
||||
|
||||
// Grab the loot
|
||||
freePreloaded() // make max space avail for item tables
|
||||
gold, xp = collectLootAndXP()
|
||||
if gold > 0
|
||||
displayf1("You find %d gold! ", addGold(gold))
|
||||
@ -1105,8 +1077,7 @@ def processWin()#0
|
||||
addXP_all(xp)
|
||||
displayf1("You earn %d experience! ", xp)
|
||||
fin
|
||||
displayStr("\n(press any key)\n")
|
||||
getUpperKey()
|
||||
promptAnyKey(FALSE)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1149,9 +1120,8 @@ def _combat_zoneEncounter(s_encZone)#1
|
||||
freePreloaded()
|
||||
return -99 // special code for death
|
||||
elsif !nEnemiesFighting
|
||||
processWin()
|
||||
processWin() // also calls freePreloaded
|
||||
// Note: no need to clear heap -- the caller does that.
|
||||
freePreloaded()
|
||||
return 1
|
||||
elsif !p
|
||||
break
|
||||
|
@ -27,7 +27,8 @@ include "itemutil.plh"
|
||||
// in the same order as the constants are defined in the header.
|
||||
predef _displayItemStats(pItem1, pItem2)#1
|
||||
predef _displayItemName(pItem)#1
|
||||
word[] funcTbl = @_displayItemStats, @_displayItemName
|
||||
predef _reloadWeapon(pl, pWeapon, echo)#1
|
||||
word[] funcTbl = @_displayItemStats, @_displayItemName, @_reloadWeapon
|
||||
|
||||
// Other global variables here
|
||||
|
||||
@ -123,15 +124,18 @@ end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def displayWeaponStats(pItem1, pItem2)#0
|
||||
displayTwoCol("Equip'd", pItem1, pItem2, b_flags, @equippedField, @formatEquipped)
|
||||
displayTwoCol("Ammo", pItem1, pItem2, s_ammoKind, @wordField, @formatStr)
|
||||
displayTwoCol("Clip", pItem1, pItem2, b_clipSize, @byteField, @formatNum)
|
||||
displayTwoCol("Melee", pItem1, pItem2, r_meleeDmg, @wordField, @formatDice)
|
||||
displayTwoCol("Proj", pItem1, pItem2, r_projectileDmg, @wordField, @formatDice)
|
||||
displayTwoCol("Attack", pItem1, pItem2, ba_attacks+0, @byteField, @formatAttack)
|
||||
displayTwoCol("Att 2", pItem1, pItem2, ba_attacks+1, @byteField, @formatAttack)
|
||||
displayTwoCol("Att 3", pItem1, pItem2, ba_attacks+2, @byteField, @formatAttack)
|
||||
displayTwoCol("Range", pItem1, pItem2, b_weaponRange, @byteField, @formatNum)
|
||||
displayTwoCol("Equip'd", pItem1, pItem2, b_flags, @equippedField, @formatEquipped)
|
||||
displayTwoCol("Ammo", pItem1, pItem2, s_ammoKind, @wordField, @formatStr)
|
||||
displayTwoCol("Clip size", pItem1, pItem2, b_clipSize, @byteField, @formatNum)
|
||||
if (pItem1->b_flags & ITEM_FLAG_EQUIP) and !pItem2
|
||||
displayTwoCol("Current", pItem1, pItem2, b_clipCurrent, @byteField, @formatNum)
|
||||
fin
|
||||
displayTwoCol("Melee", pItem1, pItem2, r_meleeDmg, @wordField, @formatDice)
|
||||
displayTwoCol("Proj", pItem1, pItem2, r_projectileDmg, @wordField, @formatDice)
|
||||
displayTwoCol("Attack", pItem1, pItem2, ba_attacks+0, @byteField, @formatAttack)
|
||||
displayTwoCol("Att 2", pItem1, pItem2, ba_attacks+1, @byteField, @formatAttack)
|
||||
displayTwoCol("Att 3", pItem1, pItem2, ba_attacks+2, @byteField, @formatAttack)
|
||||
displayTwoCol("Range", pItem1, pItem2, b_weaponRange, @byteField, @formatNum)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -205,6 +209,53 @@ def _displayItemName(pItem)#1
|
||||
return 0
|
||||
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 _reloadWeapon(pl, pWeapon, echo)#1
|
||||
word item
|
||||
byte orig, n
|
||||
|
||||
isPlural = FALSE
|
||||
if !pWeapon; return 0; fin // if no weapon equipped, no reload possible
|
||||
|
||||
// If ammo type is null, it means weapon doesn't use ammo in traditional sense.
|
||||
if !pWeapon=>s_ammoKind
|
||||
pWeapon->b_clipCurrent = 1
|
||||
return 0
|
||||
fin
|
||||
|
||||
// Find matching ammo
|
||||
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))
|
||||
fin
|
||||
return 0
|
||||
fin
|
||||
|
||||
// Transfer ammo to weapon
|
||||
if pWeapon->b_clipSize
|
||||
n = min(item=>w_count, pWeapon->b_clipSize - pWeapon->b_clipCurrent)
|
||||
else
|
||||
n = min(item=>w_count, 1) // clipSize=0 implies auto-reloading weapon
|
||||
fin
|
||||
pWeapon->b_clipCurrent = pWeapon->b_clipCurrent + n
|
||||
item=>w_count = item=>w_count - n
|
||||
if item=>w_count == 0
|
||||
removeFromList(@pl=>p_items, item)
|
||||
fin
|
||||
if echo
|
||||
displayf3("\n%s reloads %s %s.\n", pl=>s_name, hisHerTheir(pl->c_gender), pWeapon=>s_name)
|
||||
fin
|
||||
return 0
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Boilerplate module initialization code
|
||||
return @funcTbl
|
||||
|
@ -11,6 +11,7 @@
|
||||
// Each module-exported function needs its own constant, 0..n (multiples of 2)
|
||||
const itemutil_displayItemStats = 0
|
||||
const itemutil_displayItemName = 2
|
||||
const itemutil_reloadWeapon = 4
|
||||
|
||||
const STATS_COL_1 = 45
|
||||
const STATS_COL_2 = 140
|
||||
|
@ -409,6 +409,11 @@ def showItemMenu(item)#0
|
||||
if isEquipped(item); rawDisplayStr("un-"); fin
|
||||
rawDisplayStr("E)quip, ")
|
||||
fin
|
||||
if type == TYPE_WEAPON
|
||||
if item->b_clipCurrent < item->b_clipSize
|
||||
rawDisplayStr("R)eload, ")
|
||||
fin
|
||||
fin
|
||||
rawDisplayStr("U)se, ")
|
||||
if isSplittable(item); rawDisplayStr("S)plit, "); fin
|
||||
if isJoinable(item); rawDisplayStr("J)oin, "); fin
|
||||
@ -667,6 +672,16 @@ def interactWithItem(player, item)#1
|
||||
return doTrade(player, item)
|
||||
fin
|
||||
break
|
||||
is 'R'
|
||||
if item->t_type == TYPE_WEAPON
|
||||
if item->b_clipCurrent < item->b_clipSize
|
||||
pItemutilModule()=>itemutil_reloadWeapon(player, item, FALSE)
|
||||
displayDone
|
||||
displayItems(item, NULL)
|
||||
ok = TRUE
|
||||
fin
|
||||
fin
|
||||
break
|
||||
// Split a stack
|
||||
is 'S'
|
||||
if isSplittable(item)
|
||||
|
Loading…
Reference in New Issue
Block a user