DIRECTORY FastBreak, Frame USING [GetReturnLink], 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], Process USING [GetPriority, Priority, SetPriority], ProcessPriorities USING [priorityClientHigh], Rope USING [ROPE], Runtime USING [GlobalFrame], SDDefs USING [sCallDebugger, SD, sInterrupt, sWorryCallDebugger], System USING [gmtEpoch, GreenwichMeanTime, SecondsSinceEpoch], Time USING [Current], UserTerminal USING [screenHeight, screenWidth, WaitForScanLine], ViewerClasses USING [Viewer], ViewerOps USING [DisablePainting, EnablePainting, FindViewer, GreyScreen, OpenIcon, PaintViewer, WaitForPaintingToFinish]; SpecialCache: MONITOR IMPORTS FastBreak, Frame, Graphics, GraphicsOps, Icons, Process, Runtime, System, Time, UserTerminal, 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, targetStart: CARD _ 0, targetEnd: CARD _ LAST[CARD]]; 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: System.GreenwichMeanTime _ Time.Current[]; viewer: ViewerClasses.Viewer _ ptr.viewer; seconds: CARD _ System.SecondsSinceEpoch[current]; IF viewer = NIL OR NOT viewer.iconic THEN RETURN; IF mine # NIL AND enabled AND seconds >= mine.targetStart 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; }; IF seconds < mine.targetEnd THEN DoIt[viewer]; }; }; ProcToCodeAndPC: PROC [proc: UNSPECIFIED] RETURNS [code: LONG POINTER _ NIL, pc: PrincOps.BytePC] = { gfh: PrincOps.GlobalFrameHandle _ LOOPHOLE[Runtime.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 [target: CARD _ 0, oneShot: BOOL _ FALSE, delta: CARD _ 360] = { 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 IF target = 0 THEN target _ System.SecondsSinceEpoch[Time.Current[]]; data _ NEW[LocalDataRep _ [ next: NIL, id: NIL, viewer: NIL, oneShot: oneShot, targetStart: target, targetEnd: target+delta]]; data.id _ FastBreak.SetFastBreak[code, pc, HandleCacheChange, LOOPHOLE[data]]; data.next _ setList; setList _ data; EXITS dont => {}; }; FindIt: PROC [name: ROPE, delta: CARD _ 0, 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[]; delta _ System.SecondsSinceEpoch[Time.Current[]] + delta; 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, targetStart: delta]]; 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 _ UserTerminal.screenWidth/2; vx: INTEGER _ (midWay - x)/initialSteps; y: INTEGER _ viewer.wy; oldPriority: Process.Priority _ Process.GetPriority[]; nextG: INTEGER _ invG; useIcon: BOOL _ viewer.icon < private; oldInterrupt: UNSPECIFIED _ SDDefs.SD[SDDefs.sInterrupt]; oldCallDebugger: UNSPECIFIED _ SDDefs.SD[SDDefs.sCallDebugger]; oldWorryCallDebugger: UNSPECIFIED _ SDDefs.SD[SDDefs.sWorryCallDebugger]; startTime: System.GreenwichMeanTime _ Time.Current[]; last: BOOL _ FALSE; maxX: INTEGER = UserTerminal.screenWidth - (IF pieces THEN pieceSize ELSE iconSize); minY: INTEGER = IF pieces THEN pieceSize/2 ELSE iconSize/2; maxY: INTEGER = UserTerminal.screenHeight; lastTime: INT _ maxTime; needErase: BOOL _ FALSE; IF NOT viewer.iconic THEN RETURN; IF lockup THEN { SDDefs.SD[SDDefs.sInterrupt] _ FlushCache; SDDefs.SD[SDDefs.sCallDebugger] _ FlushCache; SDDefs.SD[SDDefs.sWorryCallDebugger] _ FlushCache}; Setup[]; IF useIcon THEN Icons.DrawIcon[viewer.icon, iconCtx, 0, 0, viewer.name] ELSE viewer.class.paint[viewer, iconCtx, NIL, FALSE]; Process.SetPriority[ProcessPriorities.priorityClientHigh]; 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; UserTerminal.WaitForScanLine[0]; 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: System.GreenwichMeanTime _ Time.Current[]; delta: INT _ System.SecondsSinceEpoch[current] - System.SecondsSinceEpoch[startTime]; 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 UserTerminal.WaitForScanLine[0]; 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[]; IF lockup THEN { SDDefs.SD[SDDefs.sInterrupt] _ oldInterrupt; SDDefs.SD[SDDefs.sCallDebugger] _ oldCallDebugger; SDDefs.SD[SDDefs.sWorryCallDebugger] _ oldWorryCallDebugger}; }; FlushCache: PROC = { v: RECORD [a,b: UNSPECIFIED, state: PrincOps.StateVector]; v.state _ STATE; v.state.dest _ Frame.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. SpecialCache.mesa Russ Atkinson, July 1, 1983 5:30 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˜%—Jšœœ˜-Jšœœœ˜Jšœœ˜Jšœœœ"˜Ašœ˜ J˜1—Jšœœ ˜Jšœ œ.˜@Jšœœ ˜šœ ˜˜jJ˜———šœ˜šœ0˜7J˜7—Jšœ ˜Jšœœœ˜J˜šœœ˜Jšœœœœ˜—šœœœ˜Jšœœ˜Jšœ œ˜Jšœ œ˜J˜—Jšœœœœ˜J˜Jšœœ˜"Jšœœ˜Jšœœ˜Jšœ œœ˜Jšœœœ˜&Jšœœ˜ Jšœ œ˜JšœœÏc,˜?Jšœœœž'˜œ˜NJšœ˜Jšœ˜š˜J˜ —J˜J˜—š Ÿœœœ œœœ˜EJšœœœœ˜J˜:Jšœ œ˜'Jšœœœ˜J˜Jšœœ˜J˜J˜9Jš œ œœœœœ˜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šœ œ œ˜IJ˜5Jšœœœ˜Jš œœœœ œ ˜TJš œœœœ œ ˜;Jšœœ˜*Jšœ œ ˜Jšœ œœ˜J˜Jšœœœœ˜!J˜šœœ˜Jšœœ!˜*Jšœœ$˜-Jšœœ*˜3J˜—Jšœ"™"J˜šœ˜ Jšœ8˜˜BJ˜——šœœ˜Jšœ™J˜ šœ˜ šœ˜Jšœ@˜@—Jšœ>˜BJ˜——Jšœ˜—Jšœ œ˜'Jšœœ"œ˜CJšœ œ œ˜-Jšœ˜J˜—Jšœ™Jšœœ œ˜+Jšœœ˜*J˜!J˜$šœœ˜Jšœœ#˜,Jšœœ)˜2Jšœœ4˜=—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˜——…—(8w