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 = BEGIN OPEN FootballInternal, FootballMaster; timer: CONDITION; delay: CARDINAL _ 1; Init: PROC = BEGIN current _ NEW[PlayRec _ []]; planned _ NEW[PlayRec _ []]; END; WritePlayBook: PUBLIC PROC[name: Rope.ROPE] = TRUSTED BEGIN 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]]; END; WritePlay: PROC[stream: IO.STREAM, play: Play] = BEGIN 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"]]; END; PositionName: PROC[player: Position] RETURNS[Rope.ROPE] = BEGIN 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"]; END; ReadPlayBook: PUBLIC PROC[name: Rope.ROPE] = TRUSTED BEGIN 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."]; END; ReadCommand: PROC[stream: IO.STREAM, ball: BOOLEAN_FALSE] RETURNS[Command] = BEGIN 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]]; END; SavePlay: PUBLIC PROC[side: Side, name: Rope.ROPE, setUp: BOOL] = BEGIN new: Play _ NEW[PlayRec _ []]; new^ _ IF setUp THEN current^ ELSE planned^; new.setUp _ setUp; new.side _ side; new.name _ name; AddPlay[new]; END; AddPlay: PROC[new: Play] = BEGIN 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]; END; FindEntry: PROC[menu: Menus.Menu, name: Rope.ROPE, line: Menus.MenuLine] RETURNS[entry: Menus.MenuEntry] = BEGIN FOR entry _ menu.lines[line], entry.link WHILE entry # NIL DO IF Rope.Equal[entry.name, name] THEN RETURN; ENDLOOP; END; Translate: PROC[target: Target, team: Team] RETURNS[Target] = BEGIN 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]]]; END; SetPlay: Menus.ClickProc = TRUSTED BEGIN 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[]}; END; current: Play; planned: PUBLIC Play; SetCommand: PUBLIC PROC[player: Position, command: Command, setUp: BOOL _ FALSE] = BEGIN 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; END; Index: PROC[player: Position] RETURNS[CARDINAL] = BEGIN IF TeamOf[player] = home THEN RETURN[LOOPHOLE[Add[player, -1]]] ELSE RETURN[LOOPHOLE[Add[player, -7]]]; END; carrier: Position _ ball; state: State _ offField; Wait: ENTRY PROCEDURE[i: CARDINAL] = BEGIN DO IF i = 0 THEN EXIT ELSE i _ i - 1; WAIT timer; ENDLOOP; END; Control: PUBLIC PROC = BEGIN 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; END; GetCommand: PROC[player: Player, game: Game] RETURNS[action: Action, target: Target] = BEGIN 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]]]; END; Blocked: PROC[player: Player, p2y: REAL] RETURNS[BOOLEAN] = INLINE BEGIN 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]; END; CenterReady: PROC RETURNS[BOOLEAN] = INLINE BEGIN center: Position = IF game.offense = home THEN HC ELSE VC; RETURN[ABS[game.player[center].x - game.scrimmage] < 2]; END; Convert: PROC[pos: Position] RETURNS[Position] = INLINE BEGIN IF pos IN HomeTeam THEN RETURN[Add[pos, 6]]; IF pos IN VisitorsTeam THEN RETURN[Add[pos, -6]]; RETURN[pos]; END; 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] = BEGIN 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]; END; GetOffField: PROC[team: Team] RETURNS[Commands] = INLINE {RETURN[IF team = home THEN offField1 ELSE offField2]}; InitializePlays: PROC = BEGIN 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]; END; Init[]; END . . . \FootballPlays.mesa Last Edited by: Maxwell, March 15, 1983 8:21 am Last Edited by: Spreitzer, May 1, 1984 11:00:35 pm PDT Last Edited by: Rumph, May 15, 1984 12:08:07 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˜Icodešœ™Kšœ/™/K™6J™3K˜šΟk ˜ Kšœœ˜Kšœœ1˜GK˜Kšœ œ˜!KšœœXœœ˜sKšœœc˜nKšœœ˜+Kšœœ˜Kšœœ ˜Kšœœœ˜!Kšœœ˜Kšœ œ˜'Kšœ œ˜&K˜—K˜šœœ˜šœ˜Kšœ2œ˜6Kšœ+œ˜F—Kšœ˜Kšœ˜Kšœœ"˜,K˜—K˜Kšœ œ˜Kšœœ˜K˜šΟnœœ˜ Kš˜Kšœ œ˜Kšœ œ˜Kšœ˜K˜K˜—K™KšœB™BKšœ ™ KšœB™BK˜šž œœœ œ˜-Kšœœœœ˜Kšœœ,œ˜?Kšœœœ˜Kšœœœ˜!Kšœ*œ˜0K˜K˜Kšœ œ˜%K˜0K˜JK˜IK˜6K˜@K˜lšœœ˜6šœ;œ œ˜RKšœœ˜,Kšœ˜—Kšœ˜—K˜K˜KšœDœ˜LKšœ˜K˜—šž œœ œœ˜0Kšœœœ˜K˜K˜K˜(Kšœœœ œ˜KKšœœ œ œ˜Gšœœœ˜šœœ˜Kšœ œœœ˜/K˜K˜Kšœœœ˜K˜šœ˜Kšœ!œ˜8K˜!K˜"——šœ˜K˜"K˜ Kšœœœ œ ˜NK˜"K˜"Kšœœ˜—Kšœœ$˜Bšœ œ˜K˜K˜$šœ œ˜Kšœ˜ KšœC˜G—K˜QKšœœ˜—Kšœ˜—K˜Kšœ˜K˜—šž œœœœ˜9Kš˜šœ˜Kšœœœ˜Kšœœœ˜Kšœœœ˜Kšœœœ˜Kšœœœ˜Kšœœœ˜Kšœœ ˜—Kšœ˜K˜—šž œœœ œ˜,Kšœ˜ Kšœœ,œ˜?K˜ Kšœœ˜Kšœœœ˜Kšœœœ˜!Kšœ,œ˜2K˜K˜Kšœœ˜šœ˜Kšœœœ˜KšœΟc˜9Kšœ œœ˜Kšœœ˜-šœœ˜Kšœœ˜ K˜BK˜BK˜BK˜BK˜BK˜CKšœ=œ˜Cšœ˜ Kš œœœ œœ˜5Kšœœ˜K˜Kšœ-˜-Kšœ œ˜;Kšœ-˜-Kšœœœ˜6——Kšœ˜—Kš œœœ œœ˜5K˜ K˜Kšœ˜K˜—šž œœ œœœœœ ˜LKš˜Kšœ œ˜K˜K˜ šœ˜Kšœ-˜-šœœ˜Kšœœ˜7K˜-K˜-K˜)Kšœœœ˜8Kšœœœ˜8K˜/Kšœœœ˜8K˜5Kš œ,œœœœœ˜QKš œ,œœœœœ˜QKš œ,œœœœœ˜QKš œ,œœœœœ˜QKš œ,œœœœœ˜QKš œ+œœœœœ˜Nšœ(œ˜0K˜K˜K˜—Kšœ˜—Kšœ˜—Kšœ˜Kšœ˜ K˜—K™KšœB™BKšœ™KšœB™BK˜š žœœœœ œ˜AKš˜Kšœ œ˜Kšœœœ œ ˜,K˜K˜K˜K˜ Kšœ˜K˜—šžœœ ˜Kš˜K˜K˜Kšœ œœ˜)šœœœ˜Kšœ(œœ˜4K˜CKšœ˜—Kšœ!œ6˜]Kš œœ œœœœœ˜DK˜/Kšœ œœœ˜5K˜2K˜0K˜'Kšœ˜K˜—šž œœœ˜IKšœ˜!Kš˜šœ&œ œ˜=Kšœœœ˜,Kšœ˜—Kšœ˜K˜—šž œœœ ˜=Kš˜Kšœœ˜šœ œ˜˜ K˜K˜;—Kšœ˜—Kšœ˜Kšœ˜K˜—šœ˜Kš ˜ K˜ Kšœ œ˜%Kšœœœœ˜šœ œ˜K˜K˜/Kšœ œœœ˜Kšœœœ˜&Kšœ+œ˜0K˜'Kšœ˜ —K˜!Kš œœ œœ œ ˜CK˜ Kšœœ˜9Kšœ œœ˜K˜šœœœ˜:KšœFœ˜LK˜—šœœœ˜:KšœKœ˜QK˜—Kšœ˜K˜—K™KšœB™BKšœ™KšœB™BK˜K˜Kšœ œ˜K˜š ž œœœ,œœ˜RKš˜Kš œ œœœ œ ˜EKšœ™Kšœœœœ˜EKšœ$™$šœœ˜K˜šœœ˜"Kšœœœœ˜?——Kšœ™Kšœœœœ˜8Kš œœœœœ˜LKšœ&™&š œœœœœ˜:K˜(Kšœ˜—Kšœ™K˜&Kšœ˜K˜—šžœœœœ˜2Kš˜šœ˜Kšœœœ˜&Kšœœœ˜'—Kšœ˜K˜—K™KšœB™BK™KšœB™BK˜K˜K˜K˜šžœœ œœ˜$Kš˜Kšœœœœœ œœ˜:Kšœ˜K˜—šžœœœ˜Kš œœœœœ˜2K˜Kšœœ˜+K˜K˜K˜šœ ˜K˜5šœœœ ˜1K˜3˜ K˜%šœ˜Kšœœ˜3Kšœœ˜4——K˜Kšœ˜—šœœœ˜Kš œœœœœœ˜DK˜DKšœ˜—K˜K˜Kšœ œœ'œ ˜LKšœ˜—Kšœ˜K˜—šž œœ˜-Kšœ#˜*Kš˜Kšœœ˜ Kšœ ˜Kšœœ˜Kšœ,™,Kš œœœœœœ˜/šœœœ˜4Kšœœœ˜4—Kšœ#™#š œœ œ œœœ ˜Pšœœ œ ˜"Kšœœœ˜"šœ1˜3Kšœ%˜)—Kšœ˜ ——šœœœ˜5šœ œ ˜Kšœœœ˜"šœ1˜3Kšœ&˜*Kšœ&˜*—Kšœ˜ ——šœœœ˜5šœ œ ˜K˜$Kšœ˜ ——KšœT™Tšœœ$˜EKšœœ.˜J—K˜K˜(K˜(Kšœœœœ˜>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˜—š žœœœœœ˜;Kšœ˜ šœ œ ˜Kšœœœ˜!Kšœ%œœ˜1Kšœœ*œœ˜:Kšœœœœ˜HKšœœœœ˜HKšœœ˜Kšœ˜—Kšœœ˜Kšœ˜K˜—š ž œœœœœ˜,Kš˜Kš œœœœœœ˜:Kšœœ.˜8Kšœ˜K˜—šžœœœ ˜0Kšœ˜ Kšœœ œœ˜,Kšœœœœ˜1Kšœ˜ Kšœ˜K˜—šžœ œœœ ˜;Kš œœœœœ˜2K˜—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š˜šœœ˜šœ"œ˜=Kšœœœœ˜I—šœ"œ˜=Kšœœœœ˜I—Kš œœœœ œ ˜D—Kšœ˜K˜—šž œœ œ ˜2Kš œœœ œ œ ˜>K˜—šžœœ˜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˜—…—Kœfœ