DIRECTORY FS USING [StreamOpen, Error], FootballInternal USING [game, myTeam, Play, PlayRec, selected, viewer], FootballMaster, InputFocus USING [SetInputFocus], IO USING [Close, int, EndOf, EndOfStream, GetInt, GetLineRope, GetTokenRope, IDProc, Put, PutF, RIS, rope, STREAM], Menus USING [AppendMenuEntry, ClickProc, CreateEntry, FindEntry, Menu, MenuEntry, MenuLine, ReplaceMenuEntry], MessageWindow USING [Append, Blink, Clear], Process USING [SetTimeout], Real USING [RoundI], Rope USING [Equal, Length, ROPE], RPC USING [CallFailed], ViewerOps USING [PaintViewer, SetMenu], ViewerTools USING [MakeNewTextViewer]; FootballPlays: MONITOR IMPORTS FS, FootballInternal, FootballMaster, InputFocus, IO, Menus, MessageWindow, Process, Real, Rope, RPC, ViewerOps, ViewerTools EXPORTS FootballInternal SHARES Menus = { OPEN FootballInternal, FootballMaster; timer: CONDITION; delay: CARDINAL _ 1; Init: PROC = { current _ NEW[PlayRec _ []]; planned _ NEW[PlayRec _ []]; }; WritePlayBook: PUBLIC PROC[name: Rope.ROPE] = TRUSTED { OPEN IO; ENABLE FS.Error => {MessageWindow.Append["failed."]; CONTINUE}; stream: IO.STREAM; IF name.Length[] = 0 THEN RETURN; MessageWindow.Append["Writing plays on ", TRUE]; MessageWindow.Append[name]; MessageWindow.Append[". . . "]; stream _ FS.StreamOpen[name, create]; stream.Put[rope["-- "], rope[name], rope["\n"]]; stream.Put[rope["-- playname: {offensive | defensive} {setup | play}\n"]]; stream.Put[rope["-- {player}: {stop | run | block | guard} {target}\n"]]; stream.Put[rope["-- ball: {pass | kick} {target}\n"]]; stream.Put[rope["-- player = {QB | LE | RE | LG | RG | C}\n"]]; stream.Put[rope["-- target = {null | goal | ball | {player} | location x y (relative to scrimmage)}\n\n"]]; FOR i: Menus.MenuLine IN [1..viewer.menu.linesUsed) DO FOR entry: Menus.MenuEntry _ viewer.menu.lines[i], entry.link WHILE entry # NIL DO WritePlay[stream, NARROW[entry.clientData]]; ENDLOOP; ENDLOOP; stream.Close[]; MessageWindow.Append["done."]; [] _ ViewerTools.MakeNewTextViewer[[name: name, file: name, iconic: FALSE]]; }; WritePlay: PROC[stream: IO.STREAM, play: Play] = { OPEN IO, Real; action: Action; target: Target; stream.Put[rope[play.name], rope[": "]]; stream.Put[rope[IF play.side = offense THEN "offensive" ELSE "defensive"]]; stream.Put[rope[IF play.setUp THEN " setup" ELSE " play"], rope["\n"]]; FOR i: CARDINAL IN [0..6] DO IF i = 6 THEN { IF play.setUp OR play.side = defense THEN LOOP; action _ play.ball.action; target _ play.ball.target; IF action = stop THEN LOOP; stream.Put[rope["ball:"]]} ELSE { stream.Put[rope[PositionName[Add[HQB, i]]], rope[":"]]; action _ play.commands[i].action; target _ play.commands[i].target}; SELECT action FROM stop => stream.Put[rope[" stop"]]; run => stream.Put[rope[" run"]]; block => stream.Put[rope[IF play.side = offense THEN " block" ELSE " guard"]]; pass => stream.Put[rope[" pass"]]; kick => stream.Put[rope[" kick"]]; ENDCASE => ERROR; IF target.type = absolute THEN target _ Translate[target, myTeam]; WITH t: target SELECT FROM null => stream.Put[rope["\n"]]; goal => stream.Put[rope[" goal\n"]]; player => IF t.position = ball THEN stream.Put[rope[" ball\n"]] ELSE stream.Put[rope[" "], rope[PositionName[t.position]], rope["\n"]]; relative => stream.PutF[" location %g %g\n", int[RoundI[t.x]], int[RoundI[t.y]]]; ENDCASE => ERROR; ENDLOOP; stream.Put[rope["\n"]]; }; PositionName: PROC[player: Position] RETURNS[Rope.ROPE] = { SELECT player FROM VQB, HQB => RETURN["QB"]; VLE, HLE => RETURN["LE"]; VRE, HRE => RETURN["RE"]; VLG, HLG => RETURN["LG"]; VRG, HRG => RETURN["RG"]; VC, HC => RETURN["C"]; ENDCASE => RETURN["ball"]; }; ReadPlayBook: PUBLIC PROC[name: Rope.ROPE] = TRUSTED { ENABLE FS.Error => {MessageWindow.Append["failed."]; CONTINUE}; play: Play; line, token: Rope.ROPE; stream, file: IO.STREAM; IF name.Length[] = 0 THEN RETURN; MessageWindow.Append["Reading plays from ", TRUE]; MessageWindow.Append[name]; MessageWindow.Append[". . . "]; file _ FS.StreamOpen[name]; WHILE ~file.EndOf[] DO ENABLE IO.EndOfStream => LOOP; line _ file.GetLineRope[]; -- reads but doesn't return CR stream _ IO.RIS[line, stream]; token _ stream.GetTokenRope[IO.IDProc].token; SELECT TRUE FROM Rope.Equal[token, "--"] => LOOP; Rope.Equal[token, "QB"] => play.commands[0] _ ReadCommand[stream]; Rope.Equal[token, "LE"] => play.commands[1] _ ReadCommand[stream]; Rope.Equal[token, "RE"] => play.commands[2] _ ReadCommand[stream]; Rope.Equal[token, "LG"] => play.commands[3] _ ReadCommand[stream]; Rope.Equal[token, "RG"] => play.commands[4] _ ReadCommand[stream]; Rope.Equal[token, "C"] => play.commands[5] _ ReadCommand[stream]; Rope.Equal[token, "ball"] => play.ball _ ReadCommand[stream, TRUE]; ENDCASE => { IF play # NIL AND play.name # NIL THEN AddPlay[play]; play _ NEW[PlayRec _ []]; play.name _ token; token _ stream.GetTokenRope[IO.IDProc].token; IF Rope.Equal[token, "defensive"] THEN play.side _ defense; token _ stream.GetTokenRope[IO.IDProc].token; IF Rope.Equal[token, "play"] THEN play.setUp _ FALSE}; ENDLOOP; IF play # NIL AND play.name # NIL THEN AddPlay[play]; file.Close[]; MessageWindow.Append["done."]; }; ReadCommand: PROC[stream: IO.STREAM, ball: BOOLEAN_FALSE] RETURNS[Command] = { token: Rope.ROPE; action: Action _ block; target: Target _ [player[ball]]; WHILE ~stream.EndOf[] DO token _ stream.GetTokenRope[IO.IDProc].token; SELECT TRUE FROM Rope.Equal[token, "stop"] => RETURN[[stop, [null[ ]]]]; Rope.Equal[token, "block"] => action _ block; Rope.Equal[token, "guard"] => action _ block; Rope.Equal[token, "run"] => action _ run; Rope.Equal[token, "pass"] => IF ball THEN action _ pass; Rope.Equal[token, "kick"] => IF ball THEN action _ kick; Rope.Equal[token, "goal"] => target _ [goal[]]; Rope.Equal[token, "kick"] => IF ball THEN action _ kick; Rope.Equal[token, "ball"] => target _ [player[ball]]; Rope.Equal[token, "QB"] => target _ [player[IF myTeam = home THEN VQB ELSE HQB]]; Rope.Equal[token, "LE"] => target _ [player[IF myTeam = home THEN VLE ELSE HLE]]; Rope.Equal[token, "RE"] => target _ [player[IF myTeam = home THEN VRE ELSE HRE]]; Rope.Equal[token, "LG"] => target _ [player[IF myTeam = home THEN VLG ELSE HLG]]; Rope.Equal[token, "RG"] => target _ [player[IF myTeam = home THEN VRG ELSE HRG]]; Rope.Equal[token, "C"] => target _ [player[IF myTeam = home THEN VC ELSE HC]]; Rope.Equal[token, "location"] => {x, y: INTEGER; x _ stream.GetInt[]; y _ stream.GetInt[]; target _ [relative[x, y]]}; ENDCASE; ENDLOOP; RETURN[[action, target]]; }; SavePlay: PUBLIC PROC[side: Side, name: Rope.ROPE, setUp: BOOL] = { new: Play _ NEW[PlayRec _ []]; new^ _ IF setUp THEN current^ ELSE planned^; new.setUp _ setUp; new.side _ side; new.name _ name; AddPlay[new]; }; AddPlay: PROC[new: Play] = { line: Menus.MenuLine; entry: Menus.MenuEntry; IF new.name = NIL THEN new.name _ "Play"; FOR i: CARDINAL IN [0..6) DO IF new.commands[i].target.type # absolute THEN LOOP; new.commands[i].target _ Translate[new.commands[i].target, myTeam]; ENDLOOP; IF new.ball.target.type = absolute THEN new.ball.target _ Translate[new.ball.target, myTeam]; line _ IF new.setUp THEN 1 ELSE IF new.side = offense THEN 2 ELSE 3; entry _ FindEntry[viewer.menu, new.name, line]; IF entry # NIL THEN {entry.clientData _ new; RETURN}; entry _ Menus.CreateEntry[new.name, SetPlay, new]; Menus.AppendMenuEntry[viewer.menu, entry, line]; ViewerOps.SetMenu[viewer, viewer.menu]; }; FindEntry: PROC[menu: Menus.Menu, name: Rope.ROPE, line: Menus.MenuLine] RETURNS[entry: Menus.MenuEntry] = { FOR entry _ menu.lines[line], entry.link WHILE entry # NIL DO IF Rope.Equal[entry.name, name] THEN RETURN; ENDLOOP; }; Translate: PROC[target: Target, team: Team] RETURNS[Target] = { x, y: REAL _ 0; WITH t: target SELECT FROM absolute => { y _ t.y - fieldWidth/2; x _ (t.x - game.scrimmage)*Direction[team, game.quarter]}; ENDCASE; RETURN[[relative[x, y]]]; }; SetPlay: Menus.ClickProc = TRUSTED { old: Play; new: Play _ NARROW[clientData, Play]; IF new = NIL THEN RETURN; IF control THEN { entry: Menus.MenuEntry; entry _ Menus.FindEntry[viewer.menu, new.name]; IF entry = NIL THEN RETURN; IF entry.clientData # new THEN RETURN; Menus.ReplaceMenuEntry[viewer.menu, entry, NIL]; ViewerOps.SetMenu[viewer, viewer.menu]; RETURN}; InputFocus.SetInputFocus[viewer]; old _ IF new.setUp OR game.state > setUp THEN current ELSE planned; old^ _ new^; IF game.state < option THEN FootballMaster.SetUp[myTeam]; IF old.setUp THEN RETURN; MessageWindow.Clear[]; IF (new.side = defense) AND (myTeam = game.offense) THEN { MessageWindow.Append["You have the ball. Select an offensive play.", TRUE]; MessageWindow.Blink[]}; IF (new.side = offense) AND (myTeam # game.offense) THEN { MessageWindow.Append["You don't have the ball. Select a defensive play.", TRUE]; MessageWindow.Blink[]}; }; current: Play; planned: PUBLIC Play; SetCommand: PUBLIC PROC[player: Position, command: Command, setUp: BOOL _ FALSE] = { old: Play _ IF game.state > setUp OR setUp THEN current ELSE planned; IF player = ball AND old = planned THEN {old.ball _ command; RETURN}; IF player = ball THEN { player _ game.ballCarrier; IF command.target = [null[]] THEN IF old.ball.action # stop THEN command _ old.ball ELSE RETURN}; IF player = ball OR TeamOf[player] # myTeam THEN RETURN; IF command.action IN [pass..kick] AND player # game.ballCarrier THEN RETURN; IF command.action = kick THEN FOR i: CARDINAL IN [0..6) DO old.commands[i] _ [run, [player[ball]]]; ENDLOOP; old.commands[Index[player]] _ command; }; Index: PROC[player: Position] RETURNS[CARDINAL] = { IF TeamOf[player] = home THEN RETURN[LOOPHOLE[Add[player, -1]]] ELSE RETURN[LOOPHOLE[Add[player, -7]]]; }; carrier: Position _ ball; state: State _ offField; Wait: ENTRY PROCEDURE[i: CARDINAL] = { DO IF i = 0 THEN EXIT ELSE i _ i - 1; WAIT timer; ENDLOOP; }; Control: PUBLIC PROC = { ENABLE RPC.CallFailed => CHECKED {CONTINUE}; player: Player; commands: Commands _ ALL[[stop, [null[]]]]; Process.SetTimeout[@timer, 1]; InitializePlays[]; FootballMaster.KickOff[myTeam]; DO Wait[delay]; game^ _ FootballMaster.SetCommands[myTeam, commands]; IF game.state # state THEN SELECT game.state FROM offField => current.commands _ GetOffField[myTeam]; huddle => { current.commands _ GetHuddle[myTeam]; IF game.offense = myTeam THEN planned.commands _ ALL[[block, [player[all]]]] ELSE planned.commands _ ALL[[run, [player[ball]]]]}; option => current^ _ planned^; ENDCASE; FOR i: CARDINAL IN [0..6) DO player _ @game.player[Add[IF myTeam = home THEN HQB ELSE VQB, i]]; [commands[i].action, commands[i].target] _ GetCommand[player, game]; ENDLOOP; state _ game.state; carrier _ game.ballCarrier; IF viewer # NIL THEN ViewerOps.PaintViewer[viewer, client, FALSE, $Players]; ENDLOOP; }; GetCommand: PROC[player: Player, game: Game] RETURNS[action: Action, target: Target] = { x, y: REAL; OQB: Position; index: CARDINAL; OQB _ IF game.offense = home THEN HQB ELSE VQB; IF player.position = OQB AND game.state = option AND game.ballCarrier = none THEN RETURN[stop, [null[]]]; IF game.state # state AND game.state IN [pass..run] AND state NOT IN [pass..run] THEN FOR i: Position IN Players DO IF i = game.ballCarrier THEN LOOP; IF TeamOf[game.player[i].position] # game.possessor THEN SetCommand[i, [run, [player[ball]]]] ENDLOOP; IF game.state # state AND game.state = turnover THEN FOR i: Position IN Players DO IF i = game.ballCarrier THEN LOOP; IF TeamOf[game.player[i].position] = game.possessor THEN SetCommand[i, [block, [player[all]]]] ELSE SetCommand[i, [run, [player[ball]]]]; ENDLOOP; IF game.state # state AND game.state = liveBall THEN FOR i: Position IN Players DO SetCommand[i, [run, [player[ball]]]] ENDLOOP; IF game.ballCarrier # carrier AND player.position = game.ballCarrier AND game.state # option THEN SetCommand[player.position, [run, [goal[]]]]; index _ Index[player.position]; action _ current.commands[index].action; target _ current.commands[index].target; IF selected # none AND player.position = selected THEN RETURN; WITH t: target SELECT FROM relative => { y _ t.y + fieldWidth/2; x _ game.scrimmage + t.x*Direction[TeamOf[player.position], game.quarter]}; absolute => {x _ t.x; y _ t.y}; ENDCASE => RETURN; IF game.state < option AND myTeam # game.offense AND current.commands[Index[player.position]].action # stop THEN WITH t: planned.commands[index].target SELECT FROM player => { dy: REAL; p2: Player = @game.player[t.position]; IF ~CenterReady[] OR t.position = ball THEN RETURN; IF ABS[player.x - game.scrimmage] > 3.5 THEN RETURN; dy _ ABS[player.y - p2.y]; IF dy < 3.5 AND ABS[player.dy] < .05 THEN RETURN; -- don't move IF dy < 10 AND p2.dy > .5 AND p2.y < player.y THEN RETURN; -- moving toward me IF dy < 10 AND p2.dy < -.5 AND p2.y > player.y THEN RETURN; -- moving toward me IF Blocked[player, p2.y] THEN IF ABS[player.x - game.scrimmage] < 2.9 THEN target _ [relative[-3, player.y - fieldWidth/2]] ELSE target _ [relative[-3, p2.y - fieldWidth/2]] ELSE target _ [relative[-1, p2.y - fieldWidth/2]]; current.commands[Index[player.position]] _ [run, target]}; ENDCASE; IF action # run OR game.state < option THEN RETURN; IF ABS[player.x - x] < .5 AND ABS[player.y - y] < .5 THEN SELECT TRUE FROM player.position = game.ballCarrier AND player.position = OQB => NULL; player.position = game.ballCarrier => SetCommand[player.position, [run, [goal[]]]]; TeamOf[player.position] # game.possessor => SetCommand[player.position, [run, [player[ball]]]]; game.state = run => SetCommand[player.position, [block, [player[ball]]]]; game.state = pass => SetCommand[player.position, [run, [player[ball]]]]; ENDCASE; RETURN[action, [absolute[x, y]]]; }; Blocked: PROC[player: Player, p2y: REAL] RETURNS [BOOLEAN] = INLINE { FOR i: Position IN Players DO IF i = player.position THEN LOOP; IF TeamOf[i] # TeamOf[player.position] THEN LOOP; IF ABS[game.player[i].x - game.scrimmage] > 1.5 THEN LOOP; IF player.y+1 < game.player[i].y AND p2y+1 < game.player[i].y THEN LOOP; IF player.y > game.player[i].y+1 AND p2y > game.player[i].y+1 THEN LOOP; RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; CenterReady: PROC RETURNS[BOOLEAN] = INLINE { center: Position = IF game.offense = home THEN HC ELSE VC; RETURN[ABS[game.player[center].x - game.scrimmage] < 2]; }; Convert: PROC[pos: Position] RETURNS[Position] = INLINE { IF pos IN HomeTeam THEN RETURN[Add[pos, 6]]; IF pos IN VisitorsTeam THEN RETURN[Add[pos, -6]]; RETURN[pos]; }; Add: PROCEDURE[p: Position, i: INTEGER] RETURNS[Position] = INLINE { RETURN[LOOPHOLE[LOOPHOLE[p, INTEGER]+i]]; }; OHuddle: Commands = [ [run, [relative[-18, 0]]], [run, [relative[-16, -4]]], [run, [relative[-16, 4]]], [run, [relative[-14, -4]]], [run, [relative[-14, 4]]], [run, [relative[-12, 0]]]]; DHuddle: Commands = [ [run, [relative[-18, 0]]], [run, [relative[-16, -4]]], [run, [relative[-16, 4]]], [run, [relative[-14, -4]]], [run, [relative[-14, 4]]], [run, [relative[-14, 0]]]]; LOEndZoneHuddle: Commands = [ [run, [absolute[-8, 26]]], [run, [absolute[-6, 22]]], [run, [absolute[-6, 30]]], [run, [absolute[-4, 22]]], [run, [absolute[-4, 30]]], [run, [absolute[-2, 26]]]]; LDEndZoneHuddle: Commands = [ [run, [absolute[-8, 26]]], [run, [absolute[-6, 22]]], [run, [absolute[-6, 30]]], [run, [absolute[-4, 22]]], [run, [absolute[-4, 30]]], [run, [absolute[-4, 26]]]]; ROEndZoneHuddle: Commands = [ [run, [absolute[108, 26]]], [run, [absolute[106, 22]]], [run, [absolute[106, 30]]], [run, [absolute[104, 22]]], [run, [absolute[104, 30]]], [run, [absolute[102, 26]]]]; RDEndZoneHuddle: Commands = [ [run, [absolute[108, 26]]], [run, [absolute[106, 22]]], [run, [absolute[106, 30]]], [run, [absolute[104, 22]]], [run, [absolute[104, 30]]], [run, [absolute[104, 26]]]]; offField1: Commands = [ [run, [absolute[23, 55]]], [run, [absolute[26, 55]]], [run, [absolute[29, 55]]], [run, [absolute[32, 55]]], [run, [absolute[35, 55]]], [run, [absolute[38, 55]]]]; offField2: Commands = [ [run, [absolute[77, -5]]], [run, [absolute[74, -5]]], [run, [absolute[71, -5]]], [run, [absolute[68, -5]]], [run, [absolute[65, -5]]], [run, [absolute[62, -5]]]]; GetHuddle: PROC[team: Team] RETURNS[commands: Commands] = { SELECT TRUE FROM Direction[team, game.quarter] = 1 AND game.scrimmage < 10 => RETURN[IF team = game.offense THEN LOEndZoneHuddle ELSE LDEndZoneHuddle]; Direction[team, game.quarter] =-1 AND game.scrimmage > 90 => RETURN[IF team = game.offense THEN ROEndZoneHuddle ELSE RDEndZoneHuddle]; ENDCASE => RETURN[IF team = game.offense THEN OHuddle ELSE DHuddle]; }; GetOffField: PROC[team: Team] RETURNS[Commands] = INLINE { RETURN[IF team = home THEN offField1 ELSE offField2]; }; InitializePlays: PROC = { current.commands _ [ [run, [relative[-3, 0]]], [run, [relative[-1, -8]]], [run, [relative[-1, 8]]], [run, [relative[-1, -4]]], [run, [relative[-1, 4]]], [run, [relative[-1, 0]]]]; SavePlay[offense, "5-1", TRUE]; current.commands _ [ [run, [relative[-1, -2]]], [run, [relative[-6, -2]]], [run, [relative[-6, 2]]], [run, [relative[-1, -6]]], [run, [relative[-1, 6]]], [run, [relative[-1, 2]]]]; SavePlay[offense, "4-2", TRUE]; current.commands _ [ [run, [relative[-45, 0]]], [run, [relative[-1, -8]]], [run, [relative[-1, 8]]], [run, [relative[-1, -4]]], [run, [relative[-1, 4]]], [run, [relative[-1, 0]]]]; SavePlay[offense, "punt-reception", TRUE]; planned.commands _ [ [run, [relative[5, -4]]], [block, [player[all]]], [block, [player[all]]], [block, [player[all]]], [block, [player[all]]], [block, [player[all]]]]; SavePlay[offense, "UpTheMiddle", FALSE]; planned.commands _ [ [run, [relative[-10, 3]]], [block, [player[all]]], [run, [relative[10, 10]]], [block, [player[all]]], [block, [player[all]]], [block, [player[all]]]]; planned.ball _ [pass, [relative[10, 10]]]; SavePlay[offense, "ShortPassTop", FALSE]; planned.commands _ [ [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]]; SavePlay[defense, "Rush", FALSE]; IF myTeam = home THEN planned.commands _ [ [run, [player[ball]]], [run, [player[VLE]]], [run, [player[VRE]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]]; IF myTeam = visitors THEN planned.commands _ [ [run, [player[ball]]], [run, [player[HLE]]], [run, [player[HRE]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]]; SavePlay[defense, "GuardEnds", FALSE]; IF myTeam = home THEN planned.commands _ [ [run, [player[VQB]]], [run, [player[VLE]]], [run, [player[VRE]]], [run, [player[VLG]]], [run, [player[VRG]]], [run, [player[VC]]]]; IF myTeam = visitors THEN planned.commands _ [ [run, [player[HQB]]], [run, [player[HLE]]], [run, [player[HRE]]], [run, [player[HLG]]], [run, [player[HRG]]], [run, [player[HC]]]]; SavePlay[defense, "ManToMan", FALSE]; planned.commands _ [ [run, [player[ball]]], [block, [relative[-10, -15]]], [block, [relative[-10, 15]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]]; SavePlay[defense, "Zone", FALSE]; planned.commands _ [ [stop, [null[]]], [block, [player[ball]]], [block, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]]; SavePlay[defense, "punt-reception", FALSE]; current.commands _ GetOffField[myTeam]; }; Init[]; } . . . œFootballPlays.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Maxwell, March 15, 1983 8:21 am Spreitzer, May 1, 1984 11:00:35 pm PDT Rumph, May 15, 1984 12:08:07 pm PDT Russ Atkinson (RRA) August 13, 1985 12:55:44 pm PDT ****************************************************************** playBooks ****************************************************************** ****************************************************************** preplanned plays ****************************************************************** ****************************************************************** interactive user commands ****************************************************************** set a default pass should we use the default pass/kick? is this legal? move all of the players down the field set the new command ****************************************************************** interface with control module ****************************************************************** QB shouldn't move until the ball gets to him check for interesting state changes if the ball is caught anytime but the hike, the receiver should run towards the goal translate location relative to scrimmage line follow split ends have we reached our target? ****************************************************************** simple plays ****************************************************************** offensive plays defensive plays Κν– "cedar" style˜codešœ™Kšœ Οmœ1™Kšœ-™-šžœ žœž˜˜ K˜K˜K—K˜Kšžœžœ˜—Kšœ™šžœžœ˜1Kšžœ8žœ˜@—šžœ#žœž˜2˜ Kšœžœ˜ K˜&Kšžœžœžœžœ˜3Kšžœžœ"žœžœ˜4Kšœžœ˜Kš žœ žœžœžœžœ  ˜?Kš žœ žœ žœžœžœ ˜NKš žœ žœ žœžœžœ ˜Ošžœ˜šžœžœžœ!˜,Kšžœ1˜5Kšžœ-˜1—Kšžœ/˜3—K˜:Kšžœ˜ ——Kšžœžœžœžœ˜3Kšœ™šžœžœžœžœžœžœžœž˜JKšœ#žœžœžœ˜E˜&K˜-—˜,K˜3—K˜IK˜HKšžœ˜—Kšžœ˜!Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜Ešžœ žœ ž˜Kšžœžœžœ˜!Kšžœ%žœžœ˜1Kšžœžœ*žœžœ˜:Kšžœžœžœžœ˜HKšžœžœžœžœ˜HKšžœžœ˜Kšžœ˜—Kšžœžœ˜Kšœ˜K˜—š Ÿ œžœžœžœžœ˜-Kš œžœžœžœžœžœ˜:Kšžœžœ.˜8Kšœ˜K˜—šŸœžœžœ žœ˜9Kšžœžœ žœžœ˜,Kšžœžœžœžœ˜1Kšžœ˜ Kšœ˜K˜—š Ÿœž œžœžœ žœ˜DKšžœžœžœžœ˜)Kšœ˜K˜—K™KšœB™BKšœ ™ KšœB™BK˜˜K˜RK˜RK˜—˜K˜RK˜RK˜—˜K˜QK˜QK˜—˜K˜QK˜QK˜—˜K˜TK˜TK˜—˜K˜TK˜TK˜—˜K˜QK˜QK˜—˜K˜QK˜QK˜—K˜šŸ œžœ žœ˜;šžœžœž˜šœ"žœ˜=Kšžœžœžœžœ˜I—šœ"žœ˜=Kšžœžœžœžœ˜I—Kš žœžœžœžœ žœ ˜D—Kšœ˜K˜—šŸ œžœ žœ žœ˜;Kšžœžœ žœ žœ ˜5Kšœ˜K˜—šŸœžœ˜˜K˜NK˜O—Kšœžœ˜˜K˜OK˜O—Kšœžœ˜˜K˜OK˜O—Kšœ$žœ˜*Kšœ™˜K˜IK˜H—Kšœ!žœ˜(˜K˜MK˜H—K˜*Kšœ"žœ˜)Kšœ™˜K˜DK˜E—Kšœžœ˜!šžœžœ˜*Kšœ%žœžœ˜BK˜E—šžœžœ˜.Kšœ%žœžœ˜BK˜E—Kšœžœ˜&šžœžœ˜*Kšœžœžœžœ˜AKšœžœžœžœ˜A—šžœžœ˜.Kšœžœžœžœ˜AKšœžœžœžœ˜A—Kšœžœ˜%˜K˜SK˜E—Kšœžœ˜!˜K˜CK˜E—Kšœ$žœ˜+K˜'Kšœ˜K˜—K˜K˜K˜Kšœ˜K˜K˜K˜—…—KeŸ