DIRECTORY Commander USING [Handle, CommandProc, Register], Convert USING [RopeFromInt], FootballInternal, FootballMaster, FootballMasterRpcControl USING [ImportInterface], FS USING [ExpandName], Imager USING [black, Context, MaskBox, MaskRectangle, MaskVector, Rectangle, SetColor, SetFont, SetGray, SetXY, ShowChar, TranslateT, white], ImagerBackdoor USING [GetBounds, invert], ImagerColor USING [ColorFromAtom], InputFocus USING [SetInputFocus], IO USING [Close, RopeFromROS, GetTokenRope, int, PutF, RIS, ROS, STREAM, EndOfStream], Menus USING [ClickProc, CreateEntry, CreateMenu, InsertMenuEntry, Menu], MessageWindow USING[Append, Blink, Clear], Process USING [Detach, SetTimeout], Real USING [RoundI], Rope USING [Cat, Find, FromChar, InlineLength, InlineFetch, Length, ROPE, Substr], RPC USING [ImportFailed], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords, TIPTable], UserCredentials USING [Get], VFonts USING [defaultFont], ViewerClasses USING [DestroyProc, ModifyProc, NotifyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [BlinkViewer, CreateViewer, OpenIcon, RegisterViewerClass, SetMenu], ViewerTools USING [GetSelectionContents, MakeNewTextViewer]; FootballViewer: MONITOR IMPORTS Commander, Convert, FootballInternal, FootballMaster, FootballMasterRpcControl, FS, Imager, ImagerBackdoor, ImagerColor, InputFocus, IO, Menus, MessageWindow, Process, Real, Rope, RPC, TIPUser, UserCredentials, VFonts, ViewerOps, ViewerTools EXPORTS FootballInternal = { OPEN FootballInternal, FootballMaster; ROPE: TYPE = Rope.ROPE; game: PUBLIC Game; myTeam: PUBLIC Team; displayLine: INTEGER _ 20; viewer: PUBLIC ViewerClasses.Viewer; shadow: ARRAY Position OF RECORD[oldX, oldY: REAL, char: CHAR]; docName: ROPE _ FS.ExpandName["FootballDoc.Tioga"].fullFName; menu: Menus.Menu; imported: BOOL _ FALSE; selected: PUBLIC Position _ none; setUp: BOOL _ FALSE; deltaX: REAL; deltaY: REAL = 50; lastState: State; lastPaintedHeight: INTEGER _ 0; lastTime: INTEGER _ 0; penaltyState: PenaltyState _ none; timeouts: ARRAY Team OF INTEGER _ [4,4]; penalties: ARRAY Team OF Penalty _ [none, none]; oldScore: ARRAY Team OF INTEGER _ [0, 0]; timer: CONDITION; yard: INTEGER _ 6; grey: CARDINAL _ 055132B; black: CARDINAL _ 177777B; statsX: REAL _ 37*yard; statsY: REAL _ 100 + fieldWidth*yard; scoreboard: Imager.Rectangle = [x: statsX - 30, y: statsY - 65, w: 330, h: 95]; old: ARRAY [0..6] OF Pattern; Pattern: TYPE = RECORD[x1, y1, x2, y2: REAL, command: Command]; d: REAL _ 4; block: REAL _ 2.5; zone: REAL _ 10; Initialize: PROC = { Process.SetTimeout[@timer, 1]; game _ NEW[GameRec _ []]; FOR i: Position IN Players DO game.player[i].position _ i; ENDLOOP; CreateMenu[]; MakeFootballClass[]; Commander.Register[key: "Football", proc: Create, doc: "Football arcade game."]; }; CreateMenu: PROC = { menu _ Menus.CreateMenu[4]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["DisableDelayOfGame", MyCommand, $DisableDelayOfGame]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["Decline", MyCommand, $Decline]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["Accept", MyCommand, $Accept]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["TimeOut", MyCommand, $TimeOut]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["Kick", MyCommand, $Kick]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["Pass", MyCommand, $Pass]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["Hike", MyCommand, $Hike]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry[name: "WritePlays", proc: PlayBook, clientData: $Write, guarded: TRUE]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["ReadPlays", PlayBook, $Read]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["SavePlay", MySave]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["SaveSetUp", MySave, $SetUp]]; Menus.InsertMenuEntry[menu, Menus.CreateEntry["Help", MyCommand, $Help]]; }; MySave: Menus.ClickProc = TRUSTED {FootballInternal.SavePlay[ side: IF game.offense = myTeam THEN offense ELSE defense, name: ViewerTools.GetSelectionContents[], setUp: clientData = $SetUp]; }; MyCommand: Menus.ClickProc = TRUSTED { TipMe[NIL, LIST[clientData]]; }; PlayBook: Menus.ClickProc = TRUSTED { name: ROPE _ ViewerTools.GetSelectionContents[]; IF name.Length[] < 2 THEN { name _ UserCredentials.Get[].name; name _ Rope.Substr[name, 0, Rope.Find[name, "."]]; name _ Rope.Cat[name, ".plays"]}; IF clientData = $Read THEN FootballInternal.ReadPlayBook[name] ELSE FootballInternal.WritePlayBook[name]; }; Create: SAFE PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] --Commander.CommandProc-- = TRUSTED { self: ROPE; remote, local: ROPE _ NIL; failed: BOOL _ FALSE; commandLineStream: IO.STREAM _ IO.RIS[cmd.commandLine]; self _ UserCredentials.Get[].name; remote _ IO.GetTokenRope[commandLineStream !IO.EndOfStream => CONTINUE].token; IF remote.Length[] # 0 THEN local _ IO.GetTokenRope[commandLineStream !IO.EndOfStream => CONTINUE].token; IF remote.Length[] = 0 THEN remote _ self; IF local.Length[] = 0 THEN local _ self; IF ~imported THEN { myTeam _ visitors; FOR i: CARDINAL IN [0..2) DO failed _ FALSE; FootballMasterRpcControl.ImportInterface [ interfaceName: [instance: remote] ! RPC.ImportFailed => {failed _ TRUE; CONTINUE}]; IF failed AND Rope.Find[remote, "."] < 0 THEN remote _ Rope.Cat[remote, ".pa"] ELSE EXIT; ENDLOOP; IF failed THEN { failed _ FALSE; myTeam _ home; FootballInternal.StartServer[local]; FootballMasterRpcControl.ImportInterface [ interfaceName: [instance: local] ! RPC.ImportFailed => {failed _ TRUE; CONTINUE}]; IF failed THEN RETURN[$Failure, "couldn't import self!!!"]; }; imported _ TRUE; }; IF viewer = NIL OR viewer.destroyed THEN { newProcess: BOOL _ viewer = NIL; viewer _ ViewerOps.CreateViewer[ flavor: $Football, info: [ name: "Football", iconic: TRUE, data: NIL, scrollable: FALSE], paint: FALSE]; ViewerOps.SetMenu[viewer, menu, FALSE]; ViewerOps.OpenIcon[viewer]; IF newProcess THEN Process.Detach[FORK FootballInternal.Control[]]}; RETURN[$Success]; }; MakeFootballClass: PROC = { tipTable: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["Football.tip"]; viewerClass: ViewerClasses.ViewerClass _ NEW[ ViewerClasses.ViewerClassRec _ [paint: PaintMe, -- called whenever the Viewer should repaint notify: TipMe, -- TIP input events modify: Noop, -- InputFocus changes reported through here destroy: DestroyMe, -- called before Viewer structures freed on destroy op scroll: NIL, -- document scrolling icon: document, -- picture to display when small tipTable: tipTable, -- could be moved into Viewer instance if needed cursor: crossHairsCircle -- standard cursor when mouse is in viewer ]]; ViewerOps.RegisterViewerClass[$Football, viewerClass]; }; Noop: ViewerClasses.ModifyProc = TRUSTED {}; DestroyMe: ViewerClasses.DestroyProc = TRUSTED { FootballInternal.StopServer[]; }; TipMe: ViewerClasses.NotifyProc = TRUSTED { x, y: REAL _ 1000; InputFocus.SetInputFocus[self]; FOR input _ input, input.rest DO IF input = NIL THEN EXIT; WITH input.first SELECT FROM z: TIPUser.TIPScreenCoords => {[x, y] _ Translate[z.mouseX, z.mouseY]; LOOP}; ENDCASE; SELECT input.first FROM $Help => [] _ ViewerTools.MakeNewTextViewer[[name: docName, file: docName, iconic: FALSE]]; $Accept => { FootballMaster.PenaltyResponse[myTeam, TRUE]; MessageWindow.Clear[]}; $Decline => { FootballMaster.PenaltyResponse[myTeam, FALSE]; MessageWindow.Clear[]}; $Hike => FootballMaster.Hike[myTeam]; $TimeOut => FootballMaster.TimeOut[myTeam]; $Pass => IF x = 1000 THEN SetCommand[ball, [pass, [null[]]]] -- defaults location ELSE SetCommand[ball, [pass, [absolute[x, y]]]]; $Kick => IF x = 1000 THEN SetCommand[ball, [kick, [goal[]]]] ELSE SetCommand[ball, [kick, [absolute[x, y]]]]; $DoIt => SELECT game.state FROM setUp => FootballMaster.Hike[myTeam] ENDCASE => SetCommand[ball, [pass, [null[]]]]; $Select => selected _ Select[x, y, myTeam, 10]; $Deselect => selected _ none; $SetUp => IF selected # none THEN SetCommand[selected, [run, [absolute[x, y]]], TRUE]; $Run => IF selected # none THEN SetCommand[selected, [run, [absolute[x, y]]]]; $Block => { target: Position _ Select[x, y, Opponent[myTeam], 1]; IF selected = none THEN RETURN; IF target = selected THEN target _ none; IF target = none THEN SetCommand[selected, [block, [absolute[x, y]]]] ELSE SetCommand[selected, [block, [player[target]]]]}; $BlockDefault => IF selected # none THEN SetCommand[selected, [block, [player[none]]]]; $Stop => IF selected # none THEN SetCommand[selected, [stop, [null[]]]]; $Freeze => IF selected # none THEN SetCommand[selected, [stop, [null[]]], TRUE]; $DisableDelayOfGame => FootballMaster.DisableDelayOfGame[]; ENDCASE; ENDLOOP; }; Translate: PROC[x, y: REAL] RETURNS[REAL, REAL] = { x _ x - deltaX; y _ y - deltaY; RETURN[x/yard, y/yard]; }; Select: PROC[x, y: REAL, team: Team, delta: REAL _ 1000] RETURNS[player: Position] = { min, temp: REAL _ 1000; FOR i: Position IN Players DO IF TeamOf[i] # team THEN LOOP; temp _ ABS[game.player[i].x - x] + ABS[game.player[i].y - y]; IF temp < min THEN {min _ temp; player _ i}; ENDLOOP; IF min > delta THEN player _ none; }; PaintMe: ViewerClasses.PaintProc = TRUSTED { new: INTEGER; clock: INTEGER _ MAX[0, game.clock]; fieldErased: BOOL _ FALSE; scoreboardErased: BOOL _ FALSE; IF self.iconic OR self.destroyed THEN RETURN; IF self.wh # lastPaintedHeight THEN { whatChanged _ NIL; lastPaintedHeight _ self.wh; }; Imager.SetFont[context, VFonts.defaultFont]; new _ GetDisplayLine[Real.RoundI[game.player[game.ballCarrier].x], displayLine, self.cw/yard]; deltaX _ self.cw/2 - new*yard; Imager.TranslateT[context, [deltaX, deltaY]]; fieldErased _ (new # displayLine) OR whatChanged = NIL; IF fieldErased THEN DisplayField[context, whatChanged # NIL]; scoreboardErased _ (game.state = huddle AND lastState # huddle) OR (game.state = offField AND lastState # offField) OR game.timeouts # timeouts OR game.penalties # penalties OR game.score # oldScore OR game.penaltyState # penaltyState OR fieldErased; IF scoreboardErased THEN DisplayStats[context, ~fieldErased]; IF scoreboardErased OR (clock # lastTime) THEN DisplayClock[context, clock, ~scoreboardErased]; Imager.SetColor[context, ImagerBackdoor.invert]; IF fieldErased OR (game.state = option AND lastState # option) THEN ErasePlay[context, ~fieldErased]; IF game.state < option THEN DisplayPlay[context]; FOR i: Position IN Players DO DisplayPlayer[context, @game.player[i], ~fieldErased]; ENDLOOP; DisplayBall[context, ~fieldErased]; [] _ Imager.SetColor[context, Imager.black]; IF game.penalties # penalties AND game.penalties # [none, none] THEN Flash[self]; IF game.penaltyState # penaltyState AND game.penaltyState = asking AND game.penalties[Opponent[myTeam]] # none THEN { MessageWindow.Append["Please accept or decline penalty.", TRUE]; MessageWindow.Blink[]; }; lastTime _ clock; displayLine _ new; lastState _ game.state; oldScore _ game.score; timeouts _ game.timeouts; penalties _ game.penalties; penaltyState _ game.penaltyState; }; Flash: ENTRY PROC[viewer: ViewerClasses.Viewer] = { ViewerOps.BlinkViewer[viewer]; }; Erase: PROC [context: Imager.Context, rect: Imager.Rectangle] = { IF viewer.column = color THEN Imager.SetColor[context, ImagerColor.ColorFromAtom[$Green]] ELSE Imager.SetColor[context, Imager.white]; Imager.MaskRectangle[context, rect]; Imager.SetColor[context, Imager.black]; }; GetDisplayLine: PROC[ballX, displayLine, screenWidth: INTEGER] RETURNS[INTEGER] = { SELECT TRUE FROM displayLine - ballX > screenWidth/2 => displayLine _ MIN[MAX[ballX, 0], 100]; displayLine - ballX > screenWidth/2 - 5 => displayLine _ screenWidth/2 - 5 + ballX; ballX - displayLine > screenWidth/2 => displayLine _ MIN[MAX[ballX, 0], 100]; ballX - displayLine > screenWidth/2 - 5 => displayLine _ ballX - screenWidth/2 + 5; ENDCASE; IF displayLine + 10 < screenWidth/2 THEN displayLine _ - 10 + screenWidth/2; IF 100 - displayLine + 10 < screenWidth/2 THEN displayLine _ 100 + 10 - screenWidth/2; RETURN[displayLine]; }; DisplayField: PROC[context: Imager.Context, erase: BOOL] = { x, y: REAL; rope: ROPE; IF erase THEN Erase[context, ImagerBackdoor.GetBounds[context]]; IF viewer.column = color THEN { Imager.SetColor[context, ImagerColor.ColorFromAtom[$Green]]; Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context]]; Imager.SetColor[context, Imager.white]; }; y _ fieldWidth*yard; DrawLine[context, -10*yard, 0, 110*yard, 0]; DrawLine[context, -10*yard, fieldWidth*yard, 110*yard, fieldWidth*yard]; DrawLine[context, -10*yard, 0, -10*yard, y]; DrawLine[context, 110*yard, 0, 110*yard, y]; FOR i: INTEGER IN [0..10] DO x _ i*10*yard; y _ fieldWidth*yard; DrawLine[context, x, 0, x, y]; DrawLine[context, x-3, y/3, x+3, y/3]; DrawLine[context, x-3, 2*y/3, x+3, 2*y/3]; IF i = 0 OR i = 10 THEN rope _ Rope.FromChar['G] ELSE rope _ Convert.RopeFromInt[MIN[100-i*10, i*10]]; DrawRope[context, rope, x-5, y+5]; DrawRope[context, rope, x-5, -15]; ENDLOOP; IF viewer.column # color THEN { Imager.SetGray[context, 0.5]; Imager.MaskBox[context, [-10*yard, 0, 0, fieldWidth*yard]]; Imager.MaskBox[context, [100*yard, 0, 110*yard, fieldWidth*yard]]; Imager.SetGray[context, black]; }; }; DisplayStats: PROC[context: Imager.Context, erase: BOOL] = { number: ROPE; IF erase THEN Erase[context, scoreboard]; MessageWindow.Clear[]; -- remove any messages. IF myTeam = home THEN DrawRope[context, "(home)", statsX+82, statsY+15] ELSE DrawRope[context, "(visitors)", statsX+75, statsY+15]; Imager.SetXY[context, [statsX, statsY]]; IF game.offense = home THEN MyShowRope[context, "HOME* "] ELSE MyShowRope[context, "HOME "]; SELECT game.quarter FROM 1 => MyShowRope[context, " First Quarter "]; 2 => MyShowRope[context, " Second Quarter "]; 3 => MyShowRope[context, " Third Quarter "]; 4 => MyShowRope[context, " Fourth Quarter "]; 5 => MyShowRope[context, " Game Over "]; ENDCASE => ERROR; IF game.offense = visitors THEN MyShowRope[context, "VISITORS* "] ELSE MyShowRope[context, "VISITORS "]; number _ Convert.RopeFromInt[game.score[home]]; DrawRope[context, number, statsX+20, statsY-15]; number _ Convert.RopeFromInt[game.score[visitors]]; DrawRope[context, number, statsX+185, statsY-15]; number _ Convert.RopeFromInt[game.timeouts[home]]; DrawRope[context, number, statsX+20, statsY-30]; DrawRope[context, " - timeouts - ", statsX+60, statsY-30]; number _ Convert.RopeFromInt[game.timeouts[visitors]]; DrawRope[context, number, statsX+185, statsY-30]; SELECT game.down FROM 1 => number _ "first down and "; 2 => number _ "second down and "; 3 => number _ "third down and "; 4 => number _ "fourth down and "; ENDCASE => number _ ">>>> down and "; DrawRope[context, number, statsX-20, statsY-45]; IF game.firstDownMarker <= 0 OR game.firstDownMarker >= 100 THEN number _ "goal" ELSE {toGo: INTEGER; toGo _ Real.RoundI[ABS[game.scrimmage-game.firstDownMarker]]; number _ IF toGo < 1 THEN "inches" ELSE Convert.RopeFromInt[toGo]}; MyShowRope[context, number]; MyShowRope[context, " to go on the "]; number _ Convert.RopeFromInt[ MIN[Real.RoundI[game.scrimmage], Real.RoundI[100-game.scrimmage]]]; MyShowRope[context, number]; MyShowRope[context, " yard line."]; Imager.SetXY[context, [statsX - 20, statsY - 60]]; IF game.penalties # [none, none] THEN {DisplayPenalties[context]; RETURN}; Imager.SetXY[context, [statsX + 60, statsY - 60]]; SELECT game.score[home] - oldScore[home] FROM 7 => FlashMessage["TOUCHDOWN! "]; 3 => FlashMessage["FIELD GOAL! "]; 2 => FlashMessage["SAFETY! "]; ENDCASE; SELECT game.score[visitors] - oldScore[visitors] FROM 7 => FlashMessage["TOUCHDOWN! "]; 3 => FlashMessage["FIELD GOAL! "]; 2 => FlashMessage["SAFETY! "]; ENDCASE; }; DisplayPenalties: PROC[context: Imager.Context] = { DisplayPenalty[context, game.penalties[home], home]; IF game.penalties[visitors] # none THEN { IF game.penalties[home] # none THEN MyShowRope[context, " and "]; DisplayPenalty[context, game.penalties[visitors], visitors]}; MyShowRope[context, ": "]; SELECT game.penaltyState FROM accepted => MyShowRope[context, "ACCEPTED."]; declined => MyShowRope[context, "DECLINED."]; canceled => MyShowRope[context, "CANCELED."]; ENDCASE; }; DisplayPenalty: PROC[context: Imager.Context, penalty: Penalty, team: Team] = { SELECT penalty FROM none => RETURN; offSides => MyShowRope[context, "offsides "]; forwardPass => MyShowRope[context, "illegal forward pass "]; grounding => MyShowRope[context, "intentional grounding "]; delayOfGame => MyShowRope[context, "delay of game "]; ENDCASE => MyShowRope[context, "illegal procedure "]; SELECT team FROM home => MyShowRope[context, "against home"]; visitors => MyShowRope[context, "against visitors"]; ENDCASE; }; DisplayClock: PROC[context: Imager.Context, clock: INTEGER, erase: BOOL] = { stream: IO.STREAM _ IO.ROS[]; IF erase THEN Erase[context, [statsX+89, statsY-16, 60, 12]]; stream.PutF["%2d:%02d", IO.int[clock/60], IO.int[clock MOD 60]]; DrawRope[context, IO.RopeFromROS[stream], statsX+90, statsY-15]; stream.Close[]; }; DisplayPlayer: PROC[context: Imager.Context, player: Player, erase: BOOL] = { i: Position; x, y: REAL; same: BOOL; char: CHAR; i _ player.position; x _ Real.RoundI[player.x*yard]; y _ Real.RoundI[player.y*yard]; char _ IF TeamOf[i] = home THEN 'O ELSE 'X; same _ (x = shadow[i].oldX AND y = shadow[i].oldY AND char = shadow[i].char); IF erase AND same THEN RETURN; IF erase AND ~same THEN DrawChar[context, shadow[i].char, shadow[i].oldX, shadow[i].oldY]; DrawChar[context, char, x, y]; shadow[i].oldX _ x; shadow[i].oldY _ y; shadow[i].char _ char; }; DisplayBall: PROC[context: Imager.Context, erase: BOOL] = { x, y: REAL; same: BOOL; x _ Real.RoundI[game.player[game.ballCarrier].x*yard]; y _ Real.RoundI[game.player[game.ballCarrier].y*yard]; same _ (x = shadow[ball].oldX AND y = shadow[ball].oldY); IF erase AND same THEN RETURN; IF erase AND ~same THEN DrawChar[context, '*, shadow[ball].oldX, shadow[ball].oldY]; DrawChar[context, '*, x, y]; shadow[ball].oldX _ x; shadow[ball].oldY _ y; }; FlashMessage: PROC[message: ROPE] = { MessageWindow.Append[message, TRUE]; MessageWindow.Blink[]; }; DrawLine: PROC[context: Imager.Context, x1, y1, x2, y2: REAL] = INLINE { Imager.MaskVector[context, [x1, y1], [x2, y2]]; }; DrawChar: PROC[context: Imager.Context, char: CHAR, x, y: REAL] = INLINE { Imager.SetXY[context, [x, y]]; Imager.ShowChar[context, char]; }; DrawRope: PROC[context: Imager.Context, rope: ROPE, x, y: REAL] = INLINE { Imager.SetXY[context, [x, y]]; MyShowRope[context, rope]; }; MyShowRope: PROC[context: Imager.Context, rope: ROPE] = { FOR i: INT IN [0..Rope.InlineLength[rope]) DO Imager.ShowChar[context, Rope.InlineFetch[rope, i]]; ENDLOOP; }; ErasePlay: PROC[context: Imager.Context, erase: BOOL] = { FOR i: CARDINAL IN [0..6] DO IF erase THEN DrawPattern[context, old[i]]; old[i] _ [0, 0, 0, 0, [stop, [null[ ]]]]; ENDLOOP; }; DisplayPlay: PROC[context: Imager.Context] = { new: Pattern; FOR i: CARDINAL IN [0..6) DO new.command _ planned.commands[i]; new.x1 _ game.player[Add[IF myTeam = home THEN HQB ELSE VQB, i]].x; new.y1 _ game.player[Add[IF myTeam = home THEN HQB ELSE VQB, i]].y; [new.x2, new.y2] _ GetTarget[new.command.target, new.y1]; IF Equal[old[i], new] THEN LOOP; DrawPattern[context, old[i]]; DrawPattern[context, new]; old[i] _ new; ENDLOOP; new.command _ planned.ball; new.x1 _ new.y1 _ 0; [new.x2, new.y2] _ GetTarget[planned.ball.target, game.player[ball].y]; IF Equal[old[6], new] THEN RETURN; DrawPattern[context, old[6]]; DrawPattern[context, new]; old[6] _ new; }; DrawPattern: PROC[context: Imager.Context, p: Pattern] = { r: REAL _ 1; IF p.command.target = [player[ball]] THEN RETURN; SELECT p.command.action FROM stop => RETURN; pass, kick => {DrawChar[context, '+, p.x2*yard, p.y2*yard]; RETURN}; ENDCASE => DrawLine[context, p.x1*yard+d, p.y1*yard+d, p.x2*yard+d, p.y2*yard+d]; SELECT p.command.target.type FROM player => { DrawLine[context, (p.x2-r)*yard+d, p.y2*yard+d, p.x2*yard+d, (p.y2+r)*yard+d]; DrawLine[context, (p.x2+r)*yard+d, p.y2*yard+d, p.x2*yard+d, (p.y2+r)*yard+d]; DrawLine[context, (p.x2-r)*yard+d, p.y2*yard+d, p.x2*yard+d, (p.y2-r)*yard+d]; DrawLine[context, (p.x2+r)*yard+d, p.y2*yard+d, p.x2*yard+d, (p.y2-r)*yard+d]}; relative, absolute => { IF p.command.action = run THEN { DrawChar[context, 'o, p.x2*yard+2, p.y2*yard+2]; RETURN}; IF game.offense # myTeam THEN r _ zone ELSE r _ block; DrawLine[context, (p.x2-r)*yard+d, (p.y2-r)*yard+d, (p.x2-r)*yard+d, (p.y2+r)*yard+d]; DrawLine[context, (p.x2-r)*yard+d, (p.y2+r)*yard+d, (p.x2+r)*yard+d, (p.y2+r)*yard+d]; DrawLine[context, (p.x2+r)*yard+d, (p.y2+r)*yard+d, (p.x2+r)*yard+d, (p.y2-r)*yard+d]; DrawLine[context, (p.x2+r)*yard+d, (p.y2-r)*yard+d, (p.x2-r)*yard+d, (p.y2-r)*yard+d]}; ENDCASE; }; GetTarget: PROC[target: Target, oldY: REAL] RETURNS[x, y: REAL] = { goal: INTEGER _ Goal[Opponent[myTeam], game.quarter]; WITH t: target SELECT FROM player => RETURN[game.player[t.position].x, game.player[t.position].y]; relative => RETURN[ game.scrimmage + (IF goal > 50 THEN t.x ELSE - t.x), fieldWidth/2 + t.y]; absolute => RETURN[t.x, t.y]; goal => RETURN[goal, oldY]; ENDCASE => RETURN[0, 0]; }; Equal: PROC[a, b: Pattern] RETURNS[BOOL] = INLINE { IF a.x1 # b.x1 THEN RETURN[FALSE]; IF a.x2 # b.x2 THEN RETURN[FALSE]; IF a.y1 # b.y1 THEN RETURN[FALSE]; IF a.y2 # b.y2 THEN RETURN[FALSE]; IF a.command.action # b.command.action THEN RETURN[FALSE]; WITH t: a.command.target SELECT FROM null => IF b.command.target # t THEN RETURN[FALSE]; goal => IF b.command.target # t THEN RETURN[FALSE]; player => IF b.command.target # t THEN RETURN[FALSE]; relative => IF b.command.target # t THEN RETURN[FALSE]; absolute => IF b.command.target # t THEN RETURN[FALSE]; ENDCASE => ERROR; RETURN[TRUE]; }; Add: PROC[p: Position, i: INTEGER] RETURNS[Position] = INLINE { RETURN[LOOPHOLE[LOOPHOLE[p, INTEGER]+i]]; }; Initialize[]; } . . . rFootballViewer.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. John Maxwell on: January 28, 1983 11:20 am Spreitzer, May 1, 1984 11:42:52 pm PDT Russ Atkinson (RRA) August 14, 1985 6:57:08 pm PDT Global variables Initialization routines Viewers Class Interface coordSys: top, remove the player from the game [self: Viewer, input: LIST OF REF ANY] N.B. Called at Process.priorityForeground! select out the coordinates select an atom offField => FootballMaster.KickOff[myTeam]; IF (input.rest = NIL OR input.rest.first # $Deselect) AND ABS[game.player[selected].x - x] < 3 AND ABS[game.player[selected].y - y] < 3 THEN RETURN; Viewers Paint Proc [self: ViewerClasses.Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] Display Procedures (home) HOME* First Quarter VISITORS 7 7:14 14 4 - timeouts - 4 first down and goal on the 4 first line second line (clock drawn separately) third line fourth line display status Displaying the planned play assumes that the paintMode is 'invert' assumes that the paintMode is 'invert' assumes that the paintMode is 'invert' Κ~– "cedar" style˜codešœ™Kšœ Οmœ1™Kšœ‘˜&Kšœ‘+˜;Kšœ‘6˜KKšœ žœ‘˜#Kšœ‘ ˜1Kšœ‘0˜DKšœ™Kšœ‘*˜DK˜———K˜6Kšœ˜—K˜Kš œžœ˜,K˜š  œžœ˜0Kšœ™Kšœ˜Kšœ˜K˜—š œžœ˜+Kšœ&™&Kšœ+™+Kšœžœ˜K˜šžœž˜ Kšžœ žœžœžœ˜Kšœ™šžœ žœž˜KšœGžœ˜MKšžœ˜—Kšœ™šžœ ž˜KšœSžœ˜[˜ Kšœ'žœ˜-K˜—˜ Kšœ'žœ˜.K˜—K˜%K˜+šœ žœ ˜Kšžœ$‘˜Kšœžœžœ žœ˜@Kšœžœ,˜@K˜Kšœ˜K˜—šŸ œžœ1žœ˜MK˜ Kšœžœ˜ Kšœžœ˜ Kšœžœ˜ K˜K˜K˜Kšœžœžœžœ˜+Kšœžœžœ˜MKšžœžœžœžœ˜KšžœžœžœC˜ZKšœ˜K˜K˜K˜Kšœ˜K˜—šŸ œžœ!žœ˜;Kšœžœ˜ Kšœžœ˜ K˜6K˜6Kšœžœ˜9Kšžœžœžœžœ˜šžœžœžœ˜*K˜*—Kšœ˜K˜K˜Kšœ˜K˜—šŸ œžœ žœ˜%Kšœžœ˜$K˜K˜K˜—šŸœžœ*žœžœ˜HKšœ/˜/Kšœ˜K˜—š Ÿœžœ žœžœžœ˜JKšœ˜Kšœ˜Kšœ˜K˜—š Ÿœžœ žœžœžœ˜JKšœ˜Kšœ˜Kšœ˜K˜—šŸ œžœ žœ˜9šžœžœžœž˜-Kšœ4˜4Kšžœ˜—Kšœ˜——šœ™šŸ œžœ!žœ˜9Kšœ&™&šžœžœžœž˜Kšžœžœ˜,K˜*Kšžœ˜—Kšœ˜K˜—šŸ œžœ˜.Kšœ&™&K˜ šžœžœžœž˜K˜"Kš œžœžœžœžœžœ˜CKš œžœžœžœžœžœ˜CK˜9Kšžœžœžœ˜ K˜K˜K˜ Kšžœ˜—K˜K˜K˜GKšžœžœžœ˜"K˜K˜K˜ Kšœ˜K˜—šŸ œžœ)˜:Kšœ&™&Kšœžœ˜ Kšžœ#žœžœ˜1šžœž˜Kšœžœ˜Kšœ<žœ˜DKšžœJ˜Q—šžœž˜!˜ K˜NK˜NK˜NK˜O—˜šžœžœ˜ Kšœ1žœ˜9—Kšžœžœ žœ ˜6K˜VK˜VK˜VK˜WKšžœ˜——Kšœ˜K˜—š Ÿ œžœžœžœžœ˜CKšœžœ(˜5šžœ žœž˜Kšœ žœ7˜Gšœ žœ˜Kšœžœ žœžœ ˜5K˜—Kšœ žœ ˜Kšœžœ ˜Kšžœžœ˜—Kšœ˜K˜—š Ÿœžœžœžœžœ˜3Kšžœ žœžœžœ˜"Kšžœ žœžœžœ˜"Kšžœ žœžœžœ˜"Kšžœ žœžœžœ˜"Kšžœ%žœžœžœ˜:šžœžœž˜$Kš œžœžœžœžœ˜3Kš œžœžœžœžœ˜3Kš œ žœžœžœžœ˜5Kš œ žœžœžœžœ˜7Kš œ žœžœžœžœ˜7Kšžœžœ˜—Kšžœžœ˜ Kšœ˜K˜—š Ÿœžœžœžœ žœ˜?Kšžœžœžœžœ˜)Kšœ˜K˜—K˜—K˜ K˜Kšœ˜K˜K˜K˜K˜K˜—…—ULq<