diff --git a/OutlawEditor/src/main/resources/mythos/mythos-editor/html/editor.html b/OutlawEditor/src/main/resources/mythos/mythos-editor/html/editor.html index 18747446..fa214cde 100644 --- a/OutlawEditor/src/main/resources/mythos/mythos-editor/html/editor.html +++ b/OutlawEditor/src/main/resources/mythos/mythos-editor/html/editor.html @@ -128,6 +128,7 @@ + @@ -138,6 +139,7 @@ + diff --git a/OutlawEditor/src/main/resources/mythos/mythos-editor/js/mythos_uncompressed.js b/OutlawEditor/src/main/resources/mythos/mythos-editor/js/mythos_uncompressed.js index 20b4e741..c1beb0ce 100644 --- a/OutlawEditor/src/main/resources/mythos/mythos-editor/js/mythos_uncompressed.js +++ b/OutlawEditor/src/main/resources/mythos/mythos-editor/js/mythos_uncompressed.js @@ -781,6 +781,20 @@ if (typeof Mythos === "undefined") { this.setTooltip('Clear a game flag'); } }; + Blockly.Blocks['interaction_pause'] = { + init: function () { + this.setHelpUrl(Mythos.helpUrl); + this.setColour(54); + this.setPreviousStatement(true); + this.setNextStatement(true); + this.appendDummyInput() + .appendField("Pause for") + .appendField(new Blockly.FieldTextInput("0.5"), "NUM") + .appendField("second(s)"); + this.setOutput(false); + this.setTooltip('Pause for a specified time'); + } + }; Blockly.Blocks['graphics_set_portrait'] = { init: function () { this.setHelpUrl(Mythos.helpUrl); @@ -861,6 +875,19 @@ if (typeof Mythos === "undefined") { this.setTooltip('Stop displaying a full screen image, return to map display'); } }; + Blockly.Blocks['graphics_intimate_mode'] = { + init: function () { + this.setHelpUrl(Mythos.helpUrl); + this.setColour(54); + this.setPreviousStatement(true); + this.setNextStatement(true); + this.appendDummyInput() + .appendField("Intimate mode") + .appendField(new Blockly.FieldDropdown([["begin", "1"], ["end", "0"]]), "FLAG"); + this.setOutput(false); + this.setTooltip('Begin or end intimate mode'); + } + }; } }; } diff --git a/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy b/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy index e02f8eb3..496cd4b7 100644 --- a/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy +++ b/Platform/Apple/tools/PackPartitions/src/org/badvision/A2PackPartitions.groovy @@ -2985,6 +2985,8 @@ end packSetAvatar(blk); break case 'graphics_swap_tile': packSwapTile(blk); break + case 'graphics_intimate_mode': + packIntimateMode(blk); break case 'variables_set': packVarSet(blk); break case 'interaction_give_item': @@ -3001,6 +3003,8 @@ end case 'interaction_set_flag': case 'interaction_clr_flag': packChangeFlag(blk); break + case 'interaction_pause': + packPause(blk); break default: printWarning "don't know how to pack block of type '${blk.@type}'" } @@ -3111,6 +3115,17 @@ end outIndented("setStat($stat, getStat($stat) ${blk.@type == 'interaction_increase_stat' ? '+' : '-'} $amount)\n") } + def packPause(blk) + { + def num = getSingle(blk.field, 'NUM').text() + assert num.toFloat() > 0 + def factor = 500 // approx counts per second + def time = (int)(num.toFloat() * factor) + if (time > 32767) + time = 32767 + outIndented("pause($time)\n") + } + def packGetStat(blk) { def name = getSingle(blk.field, 'NAME').text() @@ -3349,6 +3364,13 @@ end outIndented("scriptSwapTile($fromX, $fromY, $toX, $toY)\n") } + def packIntimateMode(blk) + { + def enableFlg = getSingle(blk.field, 'FLAG').text() + assert enableFlg == "0" || enableFlg == "1" + outIndented("setIntimateMode($enableFlg)\n") + } + def packSetSky(blk) { def color = getSingle(blk.field, 'COLOR').text().toInteger() diff --git a/Platform/Apple/virtual/src/plasma/gamelib.plh b/Platform/Apple/virtual/src/plasma/gamelib.plh index 3e473c33..15b7be6d 100644 --- a/Platform/Apple/virtual/src/plasma/gamelib.plh +++ b/Platform/Apple/virtual/src/plasma/gamelib.plh @@ -19,7 +19,7 @@ import gamelib predef displayChar, rawDisplayStr, displayStr, rightJustifyStr, rightJustifyNum, puts predef min, max, randomFromListFiltered, randomFromArray, scanForNamedObj predef countList, countListFiltered, addToList, removeFromList - predef beep, showParty, mmgr, setWindow1, setWindow2, setWindow3, reboot, brk + predef beep, showParty, mmgr, setWindow, setWindow1, setWindow2, setWindow3, reboot, brk predef encodeDice, rollDice, setPlural, getStringResponse predef streqi, strncpy, fatal, pause, tossStrings, charToUpper predef addEncounterZone, clearEncounterZones, showMapName, setMapWindow, getMapWindow @@ -27,8 +27,8 @@ import gamelib predef calcPlayerArmor, rdkey, initHeap, scriptCombat, makeModifier predef giveItemToPlayer, takeItemFromPlayer, playerHasItem, getStat, setStat predef setGameFlag, getGameFlag, scriptSetAvatar, parseDecWithDefault, readStr - predef addPlayerToParty, removePlayerFromParty, partyHasPlayer, loadFrameImg - predef scriptSwapTile + predef addPlayerToParty, removePlayerFromParty, partyHasPlayer, loadFrameImg, loadMainFrameImg + predef scriptSwapTile, setIntimateMode, fontCmd, setIntimateMode /////////// Shared string constants ////////////// diff --git a/Platform/Apple/virtual/src/plasma/gameloop.pla b/Platform/Apple/virtual/src/plasma/gameloop.pla index 89e9ab5e..7f1132d2 100644 --- a/Platform/Apple/virtual/src/plasma/gameloop.pla +++ b/Platform/Apple/virtual/src/plasma/gameloop.pla @@ -37,6 +37,7 @@ include "gen_items.plh" include "combat.plh" include "party.plh" include "diskops.plh" +include "intimate.plh" // NOTE: GLIB goes here! @@ -79,6 +80,7 @@ byte frameLoaded = 0 byte heapLocked = FALSE byte allowZoneInit = FALSE word curEngine = NULL +word pIntimate = NULL // Queue setMap / teleport / start_encounter, since otherwise script might be replaced while executing byte q_mapIs3D = 0 @@ -678,7 +680,7 @@ end /////////////////////////////////////////////////////////////////////////////////////////////////// // Use the font engine to clear the current text window. // Parameters: top, bottom, left, right -asm setWindow +export asm setWindow +asmPlasm_bank2 4 jmp SetWindow end @@ -1102,18 +1104,24 @@ export def loadFrameImg(img) fin // Load the image data into aux mem - auxMmgr(START_LOAD, 1) // partition 1 is where full screen images live - curFullscreenImg = auxMmgr(QUEUE_LOAD, img<<8 | RES_TYPE_SCREEN) - auxMmgr(FINISH_LOAD, 0) + if img + auxMmgr(START_LOAD, 1) // partition 1 is where full screen images live + curFullscreenImg = auxMmgr(QUEUE_LOAD, img<<8 | RES_TYPE_SCREEN) + auxMmgr(FINISH_LOAD, 0) + + anyAnims = TRUE // for now; might get cleared if we discover otherwise on advance + animDirCt = 1 + animPauseCt = ANIM_PAUSE_MAX + + // And show the first frame of the screen image + showAnimFrame() + else + curFullscreenImg = NULL + anyAnims = FALSE + fin + frameLoaded = img - anyAnims = TRUE // for now; might get cleared if we discover otherwise on advance - animDirCt = 1 - animPauseCt = ANIM_PAUSE_MAX - - // And show the first frame of the screen image - showAnimFrame() - // Do not render over the image needRender = FALSE end @@ -1147,6 +1155,7 @@ export def setMapWindow() setWindow(24, 169, 14, 140) // Top, Bottom, Left, Right fin end + export def getMapWindow(width, height) if frameLoaded == 3 // don't check mapIs3D, since we might be in an engine *width = 140-14 @@ -1156,16 +1165,20 @@ export def getMapWindow(width, height) *height = 169-24 fin end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +export def fontCmd(code, coord) + tabBuf[0] = 4 // length + tabBuf[1] = code + tabBuf[2] = (coord / 100) + '0' + tabBuf[3] = ((coord / 10) % 10) + '0' + tabBuf[4] = (coord % 10) + '0' + rawDisplayStr(@tabBuf) +end + /////////////////////////////////////////////////////////////////////////////////////////////////// export def rightJustifyStr(str, rightX) - word x - x = rightX - calcWidth(str) - tabBuf[0] = 4 // length - tabBuf[1] = 20 // Ctrl-T - tabBuf[2] = (x / 100) + '0' - tabBuf[3] = ((x / 10) % 10) + '0' - tabBuf[4] = (x % 10) + '0' - rawDisplayStr(@tabBuf) + fontCmd(20, rightX - calcWidth(str)) // 20=Ctrl-T rawDisplayStr(str) end @@ -1286,7 +1299,7 @@ def scanScripts(x, y) end /////////////////////////////////////////////////////////////////////////////////////////////////// -def loadMainFrameImg() +export def loadMainFrameImg() mmgr(START_LOAD, 1) // partition 1 is where code lives loadFrameImg(mapIs3D+2) if curFullscreenImg @@ -1681,9 +1694,13 @@ end // Called by scripts to display a string. We set the flag noting that something has been // displayed, then use an assembly routine to do the work. export def scriptDisplayStr(str) - textDrawn = TRUE - flipToPage1() - displayStr(str) + if pIntimate + pIntimate=>intimate_displayStr(str) + else + textDrawn = TRUE + flipToPage1() + displayStr(str) + fin // No: tossString() // Doesn't work here, because we need to toss strings in the *parent's* frame end @@ -2499,6 +2516,18 @@ export def getGameFlag(flagName) fin end +/////////////////////////////////////////////////////////////////////////////////////////////////// +export def setIntimateMode(enable) + if enable + pIntimate = loadEngine(MODULE_PARTY) + pIntimate=>intimate_setMode(enable) + else + pIntimate=>intimate_setMode(enable) + returnFromEngine() + pIntimate = NULL + fin +end + /////////////////////////////////////////////////////////////////////////////////////////////////// def startGame(ask) word p_module diff --git a/Platform/Apple/virtual/src/plasma/intimate.plh b/Platform/Apple/virtual/src/plasma/intimate.plh new file mode 100644 index 00000000..d2e68e0b --- /dev/null +++ b/Platform/Apple/virtual/src/plasma/intimate.plh @@ -0,0 +1,14 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1 +// (the "License"); you may not use this file except in compliance with the License. +// You may obtain a copy of the License at . +// Unless required by applicable law or agreed to in writing, software distributed under +// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +// ANY KIND, either express or implied. See the License for the specific language +// governing permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Each module-exported function needs its own constant, 0..n +const intimate_setMode = 0 +const intimate_displayStr = 2 +const intimate_swipeImg = 4 diff --git a/Platform/Apple/virtual/src/plasma/intimiate.pla b/Platform/Apple/virtual/src/plasma/intimiate.pla new file mode 100644 index 00000000..27e931f0 --- /dev/null +++ b/Platform/Apple/virtual/src/plasma/intimiate.pla @@ -0,0 +1,111 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1 +// (the "License"); you may not use this file except in compliance with the License. +// You may obtain a copy of the License at . +// Unless required by applicable law or agreed to in writing, software distributed under +// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +// ANY KIND, either express or implied. See the License for the specific language +// governing permissions and limitations under the License. +/////////////////////////////////////////////////////////////////////////////////////////////////// + +include "gamelib.plh" +include "globalDefs.plh" +include "playtype.plh" + +// This pointer is the root of all heap-tracked (and garbage collected) objects. +// See playtype.plh for definitions of all the datastructures and how they interconnect. +word global + +// Exported functions go here. First a predef for each one, then a table with function pointers +// in the same order as the constants are defined in the the header. +predef _intimate_setMode, _intimate_displayStr, _intimate_swipeImg +word[] funcTbl = @_intimate_setMode, @_intimate_displayStr, @_intimate_swipeImg + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Definitions used by assembly code +asm __defs + +; Use hi-bit ASCII for Apple II +!convtab "../../include/hiBitAscii.ct" + +; Headers +!source "../../include/global.i" +!source "../../include/plasma.i" +!source "../../include/mem.i" + +; General use +tmp = $2 +pTmp = $4 + +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// swipe(onLines, offLines, iterations) +asm swipe + +asmPlasm 3 + sta pTmp ; iterations + lda evalStkL+1,x + sta tmp+1 ; offLines + lda evalStkL+2,x + sta tmp ; onLines + clc ; doesn't change; for convenient branching +.lup1: + lda $C057 ; hi-res mode + ldy tmp ; onLines +.lup2: + ldx #10 ; 1 -> 6 cyc. 2 -> 11 cyc. n -> n*5+1 cyc. 10 -> 51 cyc +- dex + bne - + dey + beq + + pha + pla + bcc .lup2 ; always taken ++ lda $C056 ; lo-res mode + ldy tmp+1 ; offLines + nop +.lup3: + ldx #9 ; 1 -> 5 cyc. 2 -> 11 cyc. n -> n*5+1 cyc. 9 -> 46 cyc +- dex + bne - + dey + bne + + dec pTmp ; next iteration + bne .lup1 + rts ++ pha + pla + nop + nop + bcc .lup3 ; always taken +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Set up (or clear) intimate mode +def _intimate_setMode(enable) + if enable + loadFrameImg(NULL) // flip to page 1, unload textures, etc. + displayChar('N'-$40) // Set normal mode - clear all special modes (like underline, etc.) + setWindow(0, 192, 0, 280) // Top, Bottom, Left, Right + clearWindow() + else + loadMainFrameImg() + fontCmd(18, 0) // 18 = ctrl-R = ticker rate. 0=fastest + fin +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Display string on a blank screen, with blanking follow-up +def _intimate_displayStr(str) + fontCmd(20, 0) // 20 = ctrl-T = horizontal position + fontCmd(22, 50) // 22 = ctrl-V = vertical position + fontCmd(18, 20) // 18 = ctrl-R = ticker rate + displayStr(str) +end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Boilerplate module initialization code +global = getGlobals() +return @funcTbl +done