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