mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-02-24 00:29:12 +00:00
Good progress on implementing encounter zones.
This commit is contained in:
parent
510385ccd3
commit
d17ef502e3
@ -67,6 +67,7 @@
|
||||
<block type="events_move_backward"></block>
|
||||
<block type="events_set_sky"></block>
|
||||
<block type="events_set_ground"></block>
|
||||
<block type="events_add_encounter_zone"></block>
|
||||
</category>
|
||||
<category name="Text">
|
||||
<block type="text_window"></block>
|
||||
|
@ -369,6 +369,28 @@ if (typeof Mythos === "undefined") {
|
||||
this.setTooltip('Set color of the ground');
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['events_add_encounter_zone'] = {
|
||||
init: function () {
|
||||
this.setHelpUrl(Mythos.helpUrl);
|
||||
this.setColour(54);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.appendDummyInput()
|
||||
.appendField("Add encounter zone for enemy code")
|
||||
.appendField(new Blockly.FieldTextInput(""), "CODE")
|
||||
.appendField('at X=')
|
||||
.appendField(new Blockly.FieldTextInput("0"), "X")
|
||||
.appendField('Y=')
|
||||
.appendField(new Blockly.FieldTextInput("0"), "Y")
|
||||
.appendField('with max dist')
|
||||
.appendField(new Blockly.FieldTextInput("0"), "MAXDIST")
|
||||
.appendField('(0=inf), and chance')
|
||||
.appendField(new Blockly.FieldTextInput("0.0"), "CHANCE")
|
||||
.appendField('%');
|
||||
this.setOutput(false);
|
||||
this.setTooltip('Add an encounter zone');
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['text_window'] = {
|
||||
init: function () {
|
||||
this.setHelpUrl(Mythos.helpUrl);
|
||||
|
@ -883,9 +883,11 @@ class PackPartitions
|
||||
def name = mapEl.@name ?: "map$num"
|
||||
def num = mapNames[name][1]
|
||||
//println "Packing 2D map #$num named '$name'."
|
||||
withContext("map '$name'") {
|
||||
def rows = parseMap(mapEl, tileEls)
|
||||
write2DMap(name, mapEl, rows)
|
||||
}
|
||||
}
|
||||
|
||||
def pack3DMap(mapEl, tileEls)
|
||||
{
|
||||
@ -1769,7 +1771,8 @@ class PackPartitions
|
||||
"${range.replace("'", "").toInteger()}, " +
|
||||
"${chanceToHit.toInteger()}, " +
|
||||
"${parseDice(damage)}, " +
|
||||
"${parseDice(groupSize)})")
|
||||
"${parseDice(groupSize)}, " +
|
||||
"\"$mapCode\")")
|
||||
out.println("end")
|
||||
}
|
||||
|
||||
@ -2137,8 +2140,8 @@ class PackPartitions
|
||||
(!yRange || trig.@y.toInteger() in yRange) })
|
||||
{
|
||||
scripts << script
|
||||
scriptNames[script] = (name == null) ? "trig_$idx" : "sc_${humanNameToSymbol(name, false)}"
|
||||
}
|
||||
scriptNames[script] = (name == null) ? "trig_$idx" : "sc_${humanNameToSymbol(name, false)}"
|
||||
}
|
||||
|
||||
// Even if there were no scripts, we still need an init to display
|
||||
@ -2224,6 +2227,8 @@ class PackPartitions
|
||||
packSetSky(blk); break
|
||||
case 'events_set_ground':
|
||||
packSetGround(blk); break
|
||||
case 'events_add_encounter_zone':
|
||||
packAddEncounterZone(blk); break
|
||||
case 'events_teleport':
|
||||
packTeleport(blk); break
|
||||
case 'events_move_backward':
|
||||
@ -2426,6 +2431,25 @@ class PackPartitions
|
||||
outIndented("setGround($color)\n")
|
||||
}
|
||||
|
||||
def packAddEncounterZone(blk)
|
||||
{
|
||||
assert blk.field.size() == 5
|
||||
assert blk.field[0].@name == 'CODE'
|
||||
assert blk.field[1].@name == 'X'
|
||||
assert blk.field[2].@name == 'Y'
|
||||
assert blk.field[3].@name == 'MAXDIST'
|
||||
assert blk.field[4].@name == 'CHANCE'
|
||||
def code = blk.field[0].text()
|
||||
def x = blk.field[1].text().toInteger()
|
||||
def y = blk.field[2].text().toInteger()
|
||||
def maxDist = blk.field[3].text().toInteger()
|
||||
def chance = (int)(blk.field[4].text().toFloat() * 10.0)
|
||||
assert chance > 0 && chance <= 1000
|
||||
outIndented("addEncounterZone(")
|
||||
emitString(code)
|
||||
out << ", $x, $y, $maxDist, $chance)\n"
|
||||
}
|
||||
|
||||
def packTeleport(blk)
|
||||
{
|
||||
assert blk.field.size() == 3
|
||||
@ -2495,13 +2519,11 @@ class PackPartitions
|
||||
out << "byte = \$FF\n\n"
|
||||
}
|
||||
|
||||
def makeInit(mapName, scripts, maxX, maxY)
|
||||
def makeInit(mapName, script, maxX, maxY)
|
||||
{
|
||||
// Emit the code the user has stored for the init script.
|
||||
scripts.each { script ->
|
||||
if (script.block.size() == 1)
|
||||
packBlock(getSingle(getSingle(script.block, null, 'procedures_defreturn').statement, 'STACK'))
|
||||
}
|
||||
// Emit the code the user has stored for the init script (if any)
|
||||
if (script)
|
||||
packScript(script)
|
||||
|
||||
// Set up the pointer to global vars
|
||||
out << "global = getGlobals()\n"
|
||||
@ -2510,6 +2532,10 @@ class PackPartitions
|
||||
def shortName = mapName.replaceAll(/[\s-]*[23][dD][-0-9]*$/, '').take(16)
|
||||
out << "setScriptInfo(\"$shortName\", @triggerTbl, $maxX, $maxY)\n"
|
||||
|
||||
// Call init script if one was defined
|
||||
if (script)
|
||||
out << "sc_${humanNameToSymbol(getScriptName(script), false)}()\n"
|
||||
|
||||
// All done with the init function.
|
||||
out << "done\n"
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
const FALSE = 0
|
||||
const TRUE = 1
|
||||
const NULL = 0
|
||||
const INT_MAX = 32767
|
||||
const INT_MIN = -32768
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory manager definitions
|
||||
@ -102,7 +104,7 @@ const setPlural = gameLibVecs + 3*43
|
||||
const makeEnemy = gameLibVecs + 3*44
|
||||
const getStringResponse = gameLibVecs + 3*45
|
||||
const strcmpi = gameLibVecs + 3*46
|
||||
const FUNCN47 = gameLibVecs + 3*47
|
||||
const addEncounterZone = gameLibVecs + 3*47
|
||||
const FUNCN48 = gameLibVecs + 3*48
|
||||
const FUNCN49 = gameLibVecs + 3*49
|
||||
const FUNCN50 = gameLibVecs + 3*50
|
||||
|
@ -106,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, _makeEnemy, _getStringResponse, _strcmpi
|
||||
predef _setPlural, _makeEnemy, _getStringResponse, _strcmpi, _addEncounterZone
|
||||
|
||||
word gameLib_addrs = @_setScriptInfo, @_scriptDisplayStr, @_scriptDisplayStrNL, @_getYN
|
||||
word = @_queue_setMap, @_setSky, @_setGround, @_queue_teleport, @_setPortrait, @_clearPortrait
|
||||
@ -119,7 +119,7 @@ word = @_puts, @_min, @_max
|
||||
word = @_countList, @_countListFiltered, @_randomFromListFiltered, @_addToList, @_beep
|
||||
word = @_showParty, @_mmgr, @_setWindow1, @_setWindow2, @_setWindow3
|
||||
word = @_reboot, @_brk, @_encodeDice, @_rollDice
|
||||
word = @_setPlural, @_makeEnemy, @_getStringResponse, @_strcmpi
|
||||
word = @_setPlural, @_makeEnemy, @_getStringResponse, @_strcmpi, @_addEncounterZone
|
||||
|
||||
word = 0 // end of library functions
|
||||
|
||||
@ -818,6 +818,16 @@ def _min(a, b)
|
||||
fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Return the absolute value of a number
|
||||
def abs(n)
|
||||
if n < 0
|
||||
return -n
|
||||
else
|
||||
return n
|
||||
fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Read a string from the keyboard using the font manager, and intern it to the heap.
|
||||
def _getStringResponse()
|
||||
@ -1161,6 +1171,10 @@ def initMap(x, y, dir)
|
||||
loadFrameImg()
|
||||
mmgr(FINISH_LOAD, 1) // 1 = keep open
|
||||
|
||||
// Clear the list of encounter zones
|
||||
global=>p_encounterZones = NULL
|
||||
printf1("Cleared zones: $%x\n", global=>p_encounterZones)
|
||||
|
||||
// Start up the display engine with map data and starting position. This will also load and
|
||||
// init the script module, if any, which will end up calling us back at the setScriptInfo
|
||||
triggerTbl = NULL
|
||||
@ -1173,23 +1187,53 @@ def initMap(x, y, dir)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Check for script(s) attached to the current location, and call them if there are any.
|
||||
def checkScripts()
|
||||
word x
|
||||
word y
|
||||
// Check for a random encounter at this position
|
||||
def checkEncounter(x, y)
|
||||
word p
|
||||
word p_bestZone, bestDist
|
||||
word d
|
||||
|
||||
// Find the zone that's closest, but not too far.
|
||||
bestDist = INT_MAX
|
||||
p_bestZone = NULL
|
||||
p = global=>p_encounterZones
|
||||
while p
|
||||
d = min(abs(x - p=>w_encX), abs(y - p=>w_encY))
|
||||
if d < bestDist and (p=>w_encMaxDist == 0 or d < p=>w_encMaxDist))
|
||||
p_bestZone = p
|
||||
bestDist = d
|
||||
fin
|
||||
p = p=>p_nextObj
|
||||
loop
|
||||
|
||||
// Roll for an encounter in the zone. If none, get out early.
|
||||
d = rand16() % 1000
|
||||
if p_bestZone and d < p_bestZone=>w_encChance
|
||||
// Encounter!
|
||||
setWindow2()
|
||||
clearWindow()
|
||||
displayf1("Encounter! %s\n", p_bestZone=>s_name)
|
||||
getYN()
|
||||
clearWindow()
|
||||
fin
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Check for script(s) attached to the given location, and call them if there are any.
|
||||
// Returns TRUE if any were triggered.
|
||||
def checkScripts(x, y)
|
||||
word p
|
||||
word pNext
|
||||
word script
|
||||
byte anyTriggered
|
||||
|
||||
if !triggerTbl; return; fin
|
||||
setWindow2()
|
||||
getPos(@x, @y)
|
||||
anyTriggered = FALSE
|
||||
x = x - triggerOriginX
|
||||
y = y - triggerOriginY
|
||||
p = triggerTbl
|
||||
while TRUE
|
||||
while p
|
||||
if ^p == $FF
|
||||
return
|
||||
break
|
||||
fin
|
||||
pNext = p + p->1
|
||||
if ^p == y
|
||||
@ -1197,13 +1241,17 @@ def checkScripts()
|
||||
while p < pNext
|
||||
if x == ^p
|
||||
script = p=>1
|
||||
setWindow2()
|
||||
script()
|
||||
anyTriggered = TRUE
|
||||
fin
|
||||
p = p + 3
|
||||
loop
|
||||
fin
|
||||
p = pNext
|
||||
loop
|
||||
printf1("anyTriggered=%d\n", anyTriggered)
|
||||
return anyTriggered
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1232,6 +1280,7 @@ end
|
||||
// Advance one step forward (3D maps only)
|
||||
def moveForward()
|
||||
byte val
|
||||
word x, y
|
||||
val = advance()
|
||||
|
||||
// If not blocked, render at the new position.
|
||||
@ -1251,8 +1300,13 @@ def moveForward()
|
||||
fin
|
||||
|
||||
// If there are script(s) on the new tile, run them.
|
||||
getPos(@x, @y)
|
||||
if val == 3
|
||||
checkScripts()
|
||||
if (!checkScripts(x, y))
|
||||
checkEncounter(x, y)
|
||||
fin
|
||||
else
|
||||
checkEncounter(x, y)
|
||||
fin
|
||||
end
|
||||
|
||||
@ -1792,7 +1846,7 @@ def restoreMapPos()
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def _makeEnemy(name, healthDice, image0, image1, attackType, attackText, attackRange, chanceToHit, dmg, groupSize)
|
||||
def _makeEnemy(name, healthDice, image0, image1, attackType, attackText, attackRange, chanceToHit, dmg, groupSize, code)
|
||||
word p; p = mmgr(HEAP_ALLOC, TYPE_ENEMY)
|
||||
p=>s_name = mmgr(HEAP_INTERN, name)
|
||||
p=>w_health = rollDice(healthDice) // 4d6
|
||||
@ -1807,9 +1861,22 @@ def _makeEnemy(name, healthDice, image0, image1, attackType, attackText, attackR
|
||||
p->b_chanceToHit = chanceToHit
|
||||
p=>r_enemyDmg = dmg
|
||||
p=>r_groupSize = groupSize
|
||||
p=>s_enemyCode = mmgr(HEAP_INTERN, code)
|
||||
return p
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def _addEncounterZone(code, x, y, dist, chance)
|
||||
word p; p = mmgr(HEAP_ALLOC, TYPE_ENCOUNTER_ZONE)
|
||||
p=>s_name = mmgr(HEAP_INTERN, code)
|
||||
p=>w_encX = x
|
||||
p=>w_encY = y
|
||||
p=>w_encMaxDist = dist
|
||||
p=>w_encChance = chance
|
||||
addToList(@global=>p_encounterZones, p)
|
||||
printf1("Added zone: $%x\n", global=>p_encounterZones)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def _strcmpi(a, b)
|
||||
word limit, lenDiff, diff
|
||||
|
@ -8,7 +8,7 @@
|
||||
// governing permissions and limitations under the License.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
byte typeTbl_Global[] = Global, p_players, p_enemyGroups, p_combatFirst, 0
|
||||
byte typeTbl_Global[] = Global, p_players, p_enemyGroups, p_combatFirst, p_encounterZones, 0
|
||||
byte typeTbl_Player[] = Player, p_nextObj, s_name, p_combatNext, p_skills, p_items, p_buffs, p_debuffs, 0
|
||||
byte typeTbl_Modifier[] = Modifier, p_nextObj, 0
|
||||
byte typeTbl_Effect[] = Effect, p_nextObj, s_effectDescrip, 0
|
||||
@ -18,9 +18,11 @@ byte typeTbl_Armor[] = Armor, p_nextObj, s_name, p_modifiers, 0
|
||||
byte typeTbl_Stuff[] = Stuff, p_nextObj, s_name, 0
|
||||
byte typeTbl_Enemy[] = Enemy, p_nextObj, s_name, p_combatNext, s_attackText, 0
|
||||
byte typeTbl_EnemyGroup[] = EnemyGroup, p_nextObj, p_enemies, 0
|
||||
byte typeTbl_EncounterZone[] = EncounterZone, p_nextObj, s_name, 0
|
||||
|
||||
word typeTbls = @typeTbl_Global, @typeTbl_Player, @typeTbl_Modifier, @typeTbl_Effect, @typeTbl_Item
|
||||
word = @typeTbl_Weapon, @typeTbl_Armor, @typeTbl_Stuff, @typeTbl_Enemy, @typeTbl_EnemyGroup
|
||||
word = @typeTbl_EncounterZone
|
||||
word = 0
|
||||
|
||||
byte[] kind_bow_str = "bow(s)"
|
||||
|
@ -17,6 +17,7 @@ struc Global
|
||||
word p_players
|
||||
word p_enemyGroups
|
||||
word p_combatFirst
|
||||
word p_encounterZones
|
||||
|
||||
// Map position
|
||||
byte b_mapIs3D
|
||||
@ -170,6 +171,7 @@ struc Enemy
|
||||
byte b_chanceToHit
|
||||
word r_enemyDmg // 3 hex digits: num dice, die size, add. E.g. $361 = 3d6+1
|
||||
word r_groupSize // number encountered, as 3 hex digits for dice
|
||||
word s_enemyCode
|
||||
end
|
||||
|
||||
const TYPE_ENEMY_GROUP = $89
|
||||
@ -180,6 +182,17 @@ struc EnemyGroup
|
||||
byte b_enemyGroupRange
|
||||
end
|
||||
|
||||
const TYPE_ENCOUNTER_ZONE = $8A
|
||||
struc EncounterZone
|
||||
byte t_type
|
||||
word p_nextObj
|
||||
word s_name // enemy code
|
||||
word w_encX
|
||||
word w_encY
|
||||
word w_encMaxDist
|
||||
word w_encChance
|
||||
end
|
||||
|
||||
// Weapon kinds
|
||||
const KIND_BOW = 1;
|
||||
const KIND_BLADE = 2;
|
||||
|
Loading…
x
Reference in New Issue
Block a user