DIRECTORY BasicTime, FastBreak, Graphics USING [black, Context, DrawBox, NewContext, SetColor, SetCP, SetPaintMode, white], GraphicsOps USING [BitmapRef, BitmapRep, Context, DrawBitmap, NewBitmap, NewContextFromBitmap], Icons USING [DrawIcon], PrincOps USING [BytePC, ControlLink, CSegPrefix, GlobalFrameHandle, NullLink, StateVector], PrincOpsUtils USING [GetReturnLink, GlobalFrame], Process USING [GetPriority, Priority, priorityClient3, SetPriority], Rope USING [ROPE], Terminal USING [Current, WaitForBWVerticalRetrace], ViewerClasses USING [Viewer], ViewerOps USING [DisablePainting, EnablePainting, FindViewer, GreyScreen, OpenIcon, PaintViewer, WaitForPaintingToFinish]; LutherWatcherSpecialCache: MONITOR -- Russ's SpecialCache, cloned. IMPORTS BasicTime, FastBreak, Graphics, GraphicsOps, Icons, PrincOpsUtils, Process, Terminal, ViewerOps SHARES ViewerOps = BEGIN OPEN Rope; MapSeq: TYPE = RECORD [SEQUENCE len: NAT OF Map]; Map: TYPE = RECORD [ x0, y0: CARDINAL _ 0, xpos,ypos: INTEGER _ 0, xvel,yvel: INTEGER _ 0]; CARD: TYPE = LONG CARDINAL; base: GraphicsOps.BitmapRef _ NIL; blinks: INTEGER _ 4; ctx: Graphics.Context _ NIL; enabled: BOOL _ TRUE; hack: REF GraphicsOps.BitmapRep _ NIL; iconCtx: Graphics.Context _ NIL; iconSize: INTEGER = 64; invG: INTEGER _ 2; -- number of steps between gravity increment lockup: BOOL _ TRUE; -- TRUE for production, FALSE for debug maps: REF MapSeq _ NEW[MapSeq[64]]; maxTime: INT _ 32; -- don't hog the world for more than about this many seconds minYvel: INTEGER _ 3; pieces: BOOL _ TRUE; pieceSize: NAT _ 24; scale: INTEGER _ 1; scanLines: INTEGER _ 0; seedMod: INTEGER _ 64; swapPiecesFlag: BOOL _ FALSE; setList: LocalData _ NIL; initialSteps: INTEGER = 80; bouncingBottom: BOOL _ TRUE; bouncingTop: BOOL _ TRUE; bouncingSides: BOOL _ TRUE; absorbing: NAT _ 7; LocalData: TYPE = REF LocalDataRep; LocalDataRep: TYPE = RECORD [ next: LocalData _ NIL, id: FastBreak.FastBreakId _ NIL, viewer: ViewerClasses.Viewer _ NIL, oneShot: BOOL _ TRUE]; FrameType: TYPE = RECORD [w0,w1,w2,w3: CARDINAL, viewer: ViewerClasses.Viewer]; HandleCacheChange: FastBreak.FastBreakProc = TRUSTED { mine: LocalData _ LOOPHOLE[data]; ptr: POINTER TO FrameType _ LOOPHOLE[frame]; current: BasicTime.Pulses _ BasicTime.GetClockPulses[]; viewer: ViewerClasses.Viewer _ ptr.viewer; IF viewer = NIL OR NOT viewer.iconic THEN RETURN; IF mine # NIL AND enabled AND mine.id # NIL AND (mine.viewer = NIL OR viewer = mine.viewer) THEN { IF mine.oneShot THEN { [] _ FastBreak.ClearFastBreak[mine.id, HandleCacheChange, data]; mine.id _ NIL; }; DoIt[viewer]; }; }; ProcToCodeAndPC: PROC [proc: UNSPECIFIED] RETURNS [code: LONG POINTER _ NIL, pc: PrincOps.BytePC] = { gfh: PrincOps.GlobalFrameHandle _ LOOPHOLE[PrincOpsUtils.GlobalFrame[proc]]; pc _ [0]; IF gfh # NIL THEN { ep: CARDINAL _ LOOPHOLE[proc, PrincOps.ControlLink].ep; ev: LONG POINTER TO PrincOps.CSegPrefix _ LOOPHOLE[gfh.code.longbase]; pc _ [ev.entry[ep].initialpc*2]; code _ ev; }; }; FindAny: PROC [oneShot: BOOL _ FALSE] = { ENABLE ANY => GO TO dont; proc: UNSPECIFIED _ ViewerOps.OpenIcon; code: LONG POINTER; pc: PrincOps.BytePC; data: LocalData _ NIL; Setup[]; [code, pc] _ ProcToCodeAndPC[proc]; pc _ [pc+5]; -- crock! to get at frame after arguments data _ NEW[LocalDataRep _ [ next: NIL, id: NIL, viewer: NIL, oneShot: oneShot]]; data.id _ FastBreak.SetFastBreak[code, pc, HandleCacheChange, LOOPHOLE[data]]; data.next _ setList; setList _ data; EXITS dont => {}; }; FindIt: PROC [name: ROPE, oneShot: BOOL _ FALSE] = { ENABLE ANY => GO TO dont; viewer: ViewerClasses.Viewer _ ViewerOps.FindViewer[name]; proc: UNSPECIFIED _ ViewerOps.OpenIcon; code: LONG POINTER; pc: PrincOps.BytePC; data: LocalData _ NIL; Setup[]; IF viewer = NIL OR NOT viewer.iconic THEN RETURN; [code, pc] _ ProcToCodeAndPC[proc]; pc _ [pc+5]; -- crock! to get at frame after arguments data _ NEW[LocalDataRep _ [ next: NIL, id: NIL, viewer: viewer, oneShot: oneShot]]; data.id _ FastBreak.SetFastBreak[code, pc, HandleCacheChange, LOOPHOLE[data]]; data.next _ setList; setList _ data; EXITS dont => {}; }; NameIt: PROC [name: ROPE] = { viewer: ViewerClasses.Viewer _ ViewerOps.FindViewer[name]; IF viewer = NIL OR NOT viewer.iconic THEN RETURN; DoIt[viewer]; ViewerOps.PaintViewer[viewer, all]; }; DoIt: PROC [viewer: ViewerClasses.Viewer] = { x: INTEGER _ viewer.wx; midWay: INTEGER _ Terminal.Current[].bwWidth/2; vx: INTEGER _ (midWay - x)/initialSteps; y: INTEGER _ viewer.wy; oldPriority: Process.Priority _ Process.GetPriority[]; nextG: INTEGER _ invG; useIcon: BOOL _ viewer.icon < private; startTime: BasicTime.GMT _ BasicTime.Now[]; last: BOOL _ FALSE; maxX: INTEGER = Terminal.Current[].bwWidth - (IF pieces THEN pieceSize ELSE iconSize); minY: INTEGER = IF pieces THEN pieceSize/2 ELSE iconSize/2; maxY: INTEGER = Terminal.Current[].bwHeight; lastTime: INT _ maxTime; needErase: BOOL _ FALSE; IF NOT viewer.iconic THEN RETURN; Setup[]; IF useIcon THEN Icons.DrawIcon[viewer.icon, iconCtx, 0, 0, viewer.name] ELSE viewer.class.paint[viewer, iconCtx, NIL, FALSE]; Process.SetPriority[Process.priorityClient3]; ViewerOps.WaitForPaintingToFinish[]; ViewerOps.GreyScreen[x, y, iconSize, iconSize, FALSE, TRUE]; -- wipe out the old icon IF lockup THEN { ViewerOps.DisablePainting[]; ViewerOps.WaitForPaintingToFinish[]}; SELECT vx FROM < 0 => vx _ vx - 1; > 0 => vx _ vx + 1; ENDCASE; DO oldX: INTEGER _ x; oldY: INTEGER _ y; last: BOOL _ FALSE; x _ x + vx; y _ y + 2; SELECT vx FROM > 0 => IF x > midWay THEN x _ midWay; < 0 => IF x < midWay THEN x _ midWay; ENDCASE; IF x = midWay OR y > 500 THEN last _ TRUE ELSE { Graphics.SetCP[ctx, x, y+iconSize]; GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0]; }; IF needErase THEN { Graphics.SetCP[ctx, oldX, oldY+iconSize]; GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0]; }; needErase _ TRUE; Terminal.WaitForBWVerticalRetrace[Terminal.Current[]]; IF last THEN EXIT; ENDLOOP; FOR i: NAT IN [0..maps.len) DO map: Map _ maps[i]; map.xpos _ map.xpos + x; map.ypos _ map.ypos + y + iconSize; maps[i] _ map; ENDLOOP; FOR i: NAT IN [0..4800) WHILE NOT last DO current: BasicTime.GMT _ BasicTime.Now[]; delta: INT _ BasicTime.Period[from: startTime, to: current]; moving: NAT _ maps.len; above: NAT _ moving; last _ delta > lastTime; FOR j: NAT IN [0..moving) DO map: Map _ maps[j]; oldX: INTEGER _ map.xpos; oldY: INTEGER _ map.ypos; IF nextG = i THEN map.yvel _ map.yvel - 1; map.xpos _ oldX + map.xvel; map.ypos _ oldY + map.yvel; IF bouncingSides THEN SELECT map.xpos FROM <= 0 => {map.xvel _ -(map.xvel*3)/absorbing; map.xpos _ 0}; >= maxX => {map.xvel _ -(map.xvel*3)/absorbing; map.xpos _ maxX}; ENDCASE; IF bouncingBottom THEN IF map.ypos <= minY THEN { map.yvel _ -(map.yvel*3)/absorbing; map.ypos _ minY; IF map.yvel = 0 AND map.ypos = minY AND (i MOD 16) = 0 THEN SELECT map.xvel FROM < 0 => map.xvel _ map.xvel + 1; > 0 => map.xvel _ map.xvel - 1; ENDCASE; IF map.yvel = 0 AND map.xvel = 0 THEN moving _ moving - 1; }; IF bouncingTop THEN IF map.ypos >= maxY THEN { map.yvel _ -(map.yvel*3)/absorbing; map.ypos _ maxY}; IF map.ypos < minY THEN above _ above - 1; maps[j] _ map; IF NOT last THEN { Graphics.SetCP[ctx, map.xpos, map.ypos]; IF pieces THEN GraphicsOps.DrawBitmap[ ctx, base, pieceSize, pieceSize, map.x0, map.y0, map.x0, map.y0] ELSE GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0]}; IF i # 0 THEN { Graphics.SetCP[ctx, oldX, oldY]; IF pieces THEN GraphicsOps.DrawBitmap[ ctx, base, pieceSize, pieceSize, map.x0, map.y0, map.x0, map.y0] ELSE GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0]}; ENDLOOP; IF nextG = i THEN nextG _ nextG + invG; THROUGH [0..scanLines) DO Terminal.WaitForBWVerticalRetrace[Terminal.Current[]]; ENDLOOP; IF moving = 0 OR above = 0 THEN lastTime _ 0; ENDLOOP; IF swapPiecesFlag THEN pieces _ NOT pieces; IF lockup THEN ViewerOps.EnablePainting[]; Process.SetPriority[oldPriority]; ViewerOps.WaitForPaintingToFinish[]; }; FlushCache: PROC = { v: RECORD [a,b: UNSPECIFIED, state: PrincOps.StateVector]; v.state _ STATE; v.state.dest _ PrincOpsUtils.GetReturnLink[]; v.state.source _ PrincOps.NullLink; v.state.stkptr _ 0; RETURN WITH v.state; }; Setup: ENTRY PROC = { ENABLE UNWIND => NULL; IF ctx = NIL THEN { ctx _ Graphics.NewContext[]; Graphics.SetColor[ctx, Graphics.black]; [] _ Graphics.SetPaintMode[ctx, invert]}; IF base = NIL THEN { base _ GraphicsOps.NewBitmap[iconSize, iconSize]; hack _ LOOPHOLE[base]}; iconCtx _ GraphicsOps.NewContextFromBitmap[base]; [] _ Graphics.SetPaintMode[iconCtx, opaque]; Graphics.SetColor[iconCtx, Graphics.white]; Graphics.DrawBox[iconCtx, [0, 0, 64, 64]]; Graphics.SetColor[iconCtx, Graphics.black]; FOR i: NAT IN [0..maps.len) DO row: INTEGER _ i / 8; col: INTEGER _ i MOD 8; sum: INTEGER _ row + col; xvel: INTEGER _ (seedMod/2 - GenRandom[]) * scale; yvel: INTEGER _ (GenRandom[] + minYvel) * scale; x0: INTEGER _ col * 8; y0: INTEGER _ row * 8; maps[i] _ [x0: x0, y0: y0, xpos: x0, ypos: y0, xvel: xvel, yvel: yvel]; ENDLOOP; }; seed: CARDINAL _ 123456B; GenRandom: PROC RETURNS [INTEGER] = { seed _ seed * 17 + 174653B; RETURN [(seed / 256) MOD seedMod]; }; END.  LutherWatcherSpecialCache.mesa Russ Atkinson, January 6, 1984 6:50 pm Special accelerator cache for BugBane only! [data: FastBreakData, frame: PrincOps.FrameHandle, sv: PrincOps.SVPointer] RETURNS [useOldBreak: BOOL _ FALSE] load the bitmaps with the patterns move icon to the center step the position XOR in the new image XOR out the original image init the maps to point at the icon and to have the correct positions explode the icon in steps loop each bitmap step the position apply a gravity step friction, of a sort XOR in the new image XOR out the original image cleanup takes any # of arguments and flushes them returns pseudo-random number in [0..seedMod) Ê á˜šœ™Jšœ&™&—J˜Jšœ+™+J˜šÏk ˜ Jšœ ˜ Jšœ ˜ šœ ˜J˜L—šœ ˜J˜M—Jšœœ ˜šœ ˜J˜L—Jšœœ˜1Jšœœ7˜DJšœœœ˜Jšœ œ%˜3Jšœœ ˜šœ ˜˜jJ˜———šœÏc!˜Cš˜Jšœ_˜_—Jšœ ˜Jšœœœ˜J˜šœœ˜Jšœœœœ˜—šœœœ˜Jšœœ˜Jšœ œ˜Jšœ œ˜J˜—Jšœœœœ˜J˜Jšœœ˜"Jšœœ˜Jšœœ˜Jšœ œœ˜Jšœœœ˜&Jšœœ˜ Jšœ œ˜Jšœœž,˜?Jšœœœž'˜œ˜NJšœ˜Jšœ˜š˜J˜ —J˜J˜—š Ÿœœœ œœ˜4Jšœœœœ˜J˜:Jšœ œ˜'Jšœœœ˜J˜Jšœœ˜J˜Jš œ œœœœœ˜1J˜#Jšœ ž)˜6šœœ˜Jšœœœ˜#Jšœ˜—Jšœ>œ˜NJšœ˜Jšœ˜š˜J˜ —J˜J˜—šŸœœœ˜J˜:Jš œ œœœœœ˜1J˜ Jšœ#˜#J˜J˜—šŸœœ#˜-Jšœœ ˜Jšœœ ˜/Jšœœ˜(Jšœœ ˜J˜6Jšœœ˜Jšœ œ˜&Jšœœ˜+Jšœœœ˜Jš œœ!œœ œ ˜VJš œœœœ œ ˜;Jšœœ˜,Jšœ œ ˜Jšœ œœ˜J˜Jšœœœœ˜!J˜Jšœ"™"J˜šœ˜ Jšœ8˜˜BJ˜——šœœ˜Jšœ™J˜ šœ˜ šœ˜Jšœ@˜@—Jšœ>˜BJ˜——Jšœ˜—Jšœ œ˜'šœ˜Jšœ6˜6Jšœ˜—Jšœ œ œ˜-Jšœ˜J˜—Jšœ™Jšœœ œ˜+Jšœœ˜*J˜!J˜$J˜J˜—šŸ œœ˜Jšœ)™)Jšœœ œ˜:Jšœ œ˜J˜-J˜#J˜Jšœœ ˜J˜J˜—šŸœœœ˜Jšœœœ˜šœœœ˜Jšœ˜J˜'J˜)—šœœœ˜Jšœ1˜1Jšœœ˜—J˜1J˜,J˜+J˜*J˜+šœœœ˜Jšœœ ˜Jšœœœ˜Jšœœ ˜Jšœœ%˜2Jšœœ#˜0Jšœœ ˜Jšœœ ˜J˜GJšœ˜—J˜J˜—Jšœœ ˜šŸ œœœœ˜%Jšœ,™,J˜Jšœœ ˜"J˜J˜—Jšœ˜J˜J˜——…—#Ê3K