Added support for arbitrary game flags, and most of stat increase/decrease.

This commit is contained in:
Martin Haye 2016-07-07 16:15:31 -07:00
parent 2eff48233f
commit df446bc38b
7 changed files with 204 additions and 34 deletions

View File

@ -96,8 +96,12 @@
<block type="interaction_give_item"></block>
<block type="interaction_take_item"></block>
<block type="interaction_has_item"></block>
<block type="interaction_get_stat"></block>
<block type="interaction_increase_stat"></block>
<block type="interaction_decrease_stat"></block>
<block type="interaction_get_flag"></block>
<block type="interaction_set_flag"></block>
<block type="interaction_clr_flag"></block>
</category>
<category id="customTypes" name="Custom Types">
</category>

View File

@ -580,7 +580,7 @@ if (typeof Mythos === "undefined") {
Blockly.Blocks['text_getboolean'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);
this.setColour(54);
this.setColour(Blockly.Blocks.logic.HUE);
this.appendDummyInput()
.appendField("Get Yes or No");
this.setOutput(true, "Boolean");
@ -618,12 +618,24 @@ if (typeof Mythos === "undefined") {
Blockly.Blocks['interaction_has_item'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);
this.setColour(54);
this.setColour(Blockly.Blocks.logic.HUE);
this.appendDummyInput()
.appendField("player has item")
.appendField(new Blockly.FieldTextInput(""), "NAME");
this.setOutput(true, "Boolean");
this.setTooltip('');
this.setTooltip('Check if player has a given item');
}
};
Blockly.Blocks['interaction_get_stat'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);
this.setColour(Blockly.Blocks.math.HUE);
this.appendDummyInput()
.appendField("player's")
.appendField(new Blockly.FieldTextInput(""), "NAME")
.appendField("stat");
this.setOutput(true, "Number");
this.setTooltip('Get player stat');
}
};
Blockly.Blocks['interaction_increase_stat'] = {
@ -633,10 +645,10 @@ if (typeof Mythos === "undefined") {
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendDummyInput()
.appendField("Increase player stat")
.appendField("Increase player's")
.appendField(new Blockly.FieldTextInput(""), "NAME")
.appendField("by")
.appendField(new Blockly.FieldTextInput("0"), "AMOUNT")
.appendField("stat by")
.appendField(new Blockly.FieldTextInput("0"), "AMOUNT");
this.setOutput(false);
this.setTooltip('Increase stat of player');
}
@ -648,14 +660,54 @@ if (typeof Mythos === "undefined") {
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendDummyInput()
.appendField("Decrease player stat")
.appendField("Decrease player's")
.appendField(new Blockly.FieldTextInput(""), "NAME")
.appendField("by")
.appendField(new Blockly.FieldTextInput("0"), "AMOUNT")
.appendField("stat by")
.appendField(new Blockly.FieldTextInput("0"), "AMOUNT");
this.setOutput(false);
this.setTooltip('Decrease stat of player');
}
};
Blockly.Blocks['interaction_get_flag'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);
this.setColour(Blockly.Blocks.logic.HUE);
this.appendDummyInput()
.appendField("game's")
.appendField(new Blockly.FieldTextInput(""), "NAME")
.appendField("flag is set");
this.setOutput(true, "Boolean");
this.setTooltip('Get game flag');
}
};
Blockly.Blocks['interaction_set_flag'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);
this.setColour(54);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendDummyInput()
.appendField("Set game's")
.appendField(new Blockly.FieldTextInput(""), "NAME")
.appendField("flag");
this.setOutput(false);
this.setTooltip('Set a game flag');
}
};
Blockly.Blocks['interaction_clr_flag'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);
this.setColour(54);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendDummyInput()
.appendField("Clear game's")
.appendField(new Blockly.FieldTextInput(""), "NAME")
.appendField("flag");
this.setOutput(false);
this.setTooltip('Clear a game flag');
}
};
Blockly.Blocks['graphics_set_portrait'] = {
init: function () {
this.setHelpUrl(Mythos.helpUrl);

View File

@ -2811,6 +2811,9 @@ end
case 'interaction_increase_stat':
case 'interaction_decrease_stat':
packChangeStat(blk); break
case 'interaction_set_flag':
case 'interaction_clr_flag':
packChangeFlag(blk); break
default:
printWarning "don't know how to pack block of type '${blk.@type}'"
}
@ -2886,7 +2889,53 @@ end
assert itemFunc : "Can't locate item '$name'"
outIndented("takeItemFromPlayer(${escapeString(name)})\n")
}
def nameToStat(name) {
switch (name.toLowerCase().trim()) {
case "intelligence": return "@S_INTELLIGENCE"; return
case "strength": return "@S_STRENGTH"; return
case "agility": return "@S_AGILITY"; return
case "stamina": return "@S_STAMINA"; return
case "spirit": return "@S_SPIRIT"; return
case "luck": return "@S_LUCK"; return
case "health": return "@S_HEALTH"; return
case "max health": return "@S_MAX_HEALTH"; return
case "aiming": return "@S_AIMING"; return
case "hand to hand": return "@S_HAND_TO_HAND"; return
case "dodging": return "@S_DODGING"; return
case "gold": return "@S_GOLD"; return
default: assert false : "Unrecognized stat '$name'"
}
}
def packChangeStat(blk)
{
def name = getSingle(blk.value, 'NAME').text()
def amount = getSingle(blk.value, 'AMOUNT').text().toInteger()
assert amount > 0 && amount < 32767
def stat = nameToStat(name)
outIndented("setStat(getStat($stat) ${blk.@type == 'interaction_increase_stat' ? '+' : '-'} $amount)\n")
}
def packGetStat(blk)
{
def name = getSingle(blk.field, 'NAME').text()
def stat = nameToStat(name)
out << "getStat($stat)"
}
def packGetFlag(blk)
{
def name = getSingle(blk.field, 'NAME').text()
out << "getGameFlag(${escapeString(name)})"
}
def packChangeFlag(blk)
{
def name = getSingle(blk.field, 'NAME').text()
outIndented("setGameFlag(${escapeString(name)}, ${blk.@type == 'interaction_set_flag' ? 1 : 0})\n")
}
def isStringExpr(blk)
{
return blk.@type == "text_getstring" || blk.@type == "text"
@ -2953,6 +3002,12 @@ end
case 'interaction_has_item':
packHasItem(blk)
break
case 'interaction_get_stat':
packGetStat(blk)
break
case 'interaction_get_flag':
packGetFlag(blk)
break
default:
assert false : "Expression type '${blk.@type}' not yet implemented."
}

View File

@ -23,10 +23,16 @@ import gamelib
predef addEncounterZone, showMapName, setMapWindow, makeModifier
predef addGold, countGold, payGold
predef calcPlayerArmor, diskActivity, rdkey, initHeap, scriptCombat
predef giveItemToPlayer, takeItemFromPlayer, playerHasItem, changePlayerStat
predef giveItemToPlayer, takeItemFromPlayer, playerHasItem, getStat, setStat
predef setGameFlag, getGameFlag
// Shared string constants
// First: attributes
byte[] S_INTELLIGENCE, S_STRENGTH, S_AGILITY, S_STAMINA, S_CHARISMA, S_SPIRIT, S_LUCK
byte[] S_HEALTH, S_AIMING, S_HAND_TO_HAND, S_DODGING, S_GOLD
byte[] S_HEALTH, S_MAX_HEALTH, S_AIMING, S_HAND_TO_HAND, S_DODGING, S_GOLD
// Next: common events
byte[] S_ENTER, S_USE
end

View File

@ -107,10 +107,13 @@ export byte[] S_CHARISMA = "charisma"
export byte[] S_SPIRIT = "spirit"
export byte[] S_LUCK = "luck"
export byte[] S_HEALTH = "health"
export byte[] S_MAX_HEALTH = "max health"
export byte[] S_AIMING = "aiming"
export byte[] S_HAND_TO_HAND = "hand-to-hand"
export byte[] S_HAND_TO_HAND = "hand to hand"
export byte[] S_DODGING = "dodging"
export byte[] S_GOLD = "gold"
export byte[] S_ENTER = "enter"
export byte[] S_USE = "use"
///////////////////////////////////////////////////////////////////////////////////////////////////
// Definitions used by assembly code
@ -2227,6 +2230,15 @@ export def payGold(amount)
return amount
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def scanForNamedObj(p_obj, name)
while p_obj
if streqi(p_obj=>s_name, name); return p_obj; fin
p_obj = p_obj=>p_nextObj
loop
return NULL
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def giveItemToPlayer(itemFunc)
word p_module, funcTbl, func, p_item
@ -2241,28 +2253,21 @@ export def giveItemToPlayer(itemFunc)
func = *(funcTbl + itemFunc)
p_item = func()
// Add the item to the player's inventory, and free up the item module
addToList(@global=>p_players=>p_items, p_item)
// Avoid giving duplicate items.
if !scanForNamedObj(global=>p_players=>p_items, p_item=>s_name)
addToList(@global=>p_players=>p_items, p_item)
fin
// Finished with the item module now.
mmgr(FREE_MEMORY, p_module)
end
def scanForItem(itemName)
word p_player
word p_item
p_player = global=>p_players // default to first player
p_item = p_player=>p_items
while p_item
if streqi(p_item=>s_name, itemName); return p_item; fin
p_item = p_item=>p_nextObj
loop
return FALSE
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def takeItemFromPlayer(itemName)
word p_player
word p_item
p_player = global=>p_players // default to first player
p_item = scanForItem(itemName)
p_item = scanForNamedObj(p_player=>p_items, itemName)
if p_item
removeFromList(@p_player=>p_items, p_item)
else
@ -2270,19 +2275,64 @@ export def takeItemFromPlayer(itemName)
fin
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def playerHasItem(itemName)
return scanForItem(itemName) <> NULL
return scanForNamedObj(itemName) <> NULL
end
export def changePlayerStat(statName, add)
///////////////////////////////////////////////////////////////////////////////////////////////////
export def getStat(statName)
word player
player = global=>p_players // default to first player
when statName
is @S_STRENGTH
global=>p_players->b_strength = max(0, min(255, global=>p_players->b_strength + add))
is @S_STRENGTH; return player->b_strength
otherwise
puts(statName); fatal("Unknown attr to incr/decr")
puts(statName); fatal("Unknown stat")
wend
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def clampByte(val)
return max(0, min(255, val))
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def setStat(statName, val)
word player
player = global=>p_players // default to first player
when statName
is @S_STRENGTH; player->b_strength = clampByte(val)
otherwise
puts(statName); fatal("Unknown stat")
wend
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def setGameFlag(flagName, val)
word p_flag
p_flag = scanForNamedObj(global=>p_gameFlags, flagName)
if p_flag
if val == 0 // setting flag to zero removes it
removeFromList(@global=>p_gameFlags, p_flag)
else
p_flag=>w_modValue = val
fin
elsif val <> 0
addToList(@global=>p_gameFlags, makeModifier(flagName, val))
fin
end
///////////////////////////////////////////////////////////////////////////////////////////////////
export def getGameFlag(flagName)
word p_flag
p_flag = scanForNamedObj(global=>p_gameFlags, flagName)
if p_flag
return p_flag=>w_modValue
else
return 0
fin
end
///////////////////////////////////////////////////////////////////////////////////////////////////
def startGame()
word p_module

View File

@ -9,7 +9,7 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
// Garbage collection pointer offsets within each type
byte typeTbl_Global[] = Global, p_players, p_enemyGroups, p_combatFirst, p_encounterZones, 0
byte typeTbl_Global[] = Global, p_players, p_enemyGroups, p_combatFirst, p_encounterZones, p_gameFlags, 0
byte typeTbl_Player[] = Player, p_nextObj, s_name, p_combatNext, p_skills, p_items, p_effects, 0
byte typeTbl_Modifier[] = Modifier, p_nextObj, s_name, 0
byte typeTbl_Effect[] = Effect, p_nextObj, s_name, 0

View File

@ -32,6 +32,9 @@ struc Global
// Heap size for restoring saved game
word w_heapSize
// General flags maintained by scripts. Linked list of Modifiers.
word p_gameFlags
end
const PLAYER_FLAG_NPC = $01