[Ivy]<Spreitzer>Top>MazeWar.df=>MazeWarPlayerImpl2.Mesa
Last Edited by: Spreitzer, August 21, 1984 7:06:10 pm PDT
DIRECTORY
Atom, Commander, Containers, FS, Graphics, GraphicsOps, IO, IOClasses, Labels, MazeWarFinder, MazeWarFinderRpcControl, MazeWarPlayer, MazeWarPlayerInsides, MazeWarPlayerRpcControl, MessageWindow, OrderedSymbolTableRef, Process, PupDefs, Random, Rope, RPC, UserCredentials, ViewerClasses, ViewerOps;
MazeWarPlayerImpl2:
CEDAR
MONITOR
IMPORTS Atom, Commander, Containers, FS, Graphics, GraphicsOps, IO, IOClasses, Labels, MazeWarFinder, MazeWarFinderRpcControl, MazeWarPlayerInsides, MazeWarPlayerRpcControl, MessageWindow, OSTR:OrderedSymbolTableRef, Process, PupDefs, Random, Rope, RPC, UserCredentials, ViewerOps
EXPORTS MazeWarPlayer, MazeWarPlayerInsides =
INVARIANT
No clippable paints are going on.
BEGIN OPEN MazeWarPlayerInsides;
myself: PUBLIC Player ← NIL;
myAddr: PUBLIC PupDefs.PupAddress;
playerNumber: PUBLIC CARDINAL ← 47;
myInstance: PUBLIC ROPE ← "??";
topviews: PUBLIC ARRAY Angle OF Bitmap ← ALL[NIL];
exportedPlayer: PUBLIC BOOLEAN ← FALSE;
defaultPlayerPics: PUBLIC PlayerPics ← NEW [PlayerPicsRep ← [NIL, ALL[ALL[NIL]]]];
pieces: PUBLIC ARRAY [0 .. MaxDistance] OF ARRAY Piece OF LocatedBitmap ← ALL[ALL[[]]];
shownPlayers: PUBLIC PlayerList ← NIL;
MakeNewPlayer:
PUBLIC
PROC [name, instance, picsSource, mazeSource:
ROPE]
RETURNS [errmsg:
ROPE ←
NIL] =
BEGIN
mv: MazeView;
id: PlayerId ← Random.Choose[FIRST[INTEGER], LAST[INTEGER]];
userName, password, mazeRope: ROPE;
failure: BOOLEAN ← FALSE;
pp: PlayerPics;
mazeStreamIn, mazeStreamOut: IO.STREAM;
mazeStreamIn ← FS.StreamOpen[fileName: mazeSource ! FS.Error => {errmsg ← IO.PutFR["Unable to open maze source because %g", IO.rope[error.explanation]]; failure ← TRUE; CONTINUE}];
IF failure THEN RETURN;
[] ← mazeStreamIn.SkipWhitespace[flushComments: FALSE];
mazeStreamOut ← IO.ROS[];
IOClasses.Copy[from: mazeStreamIn, to: mazeStreamOut, closeFrom: TRUE, closeTo: FALSE];
mazeRope ← mazeStreamOut.RopeFromROS[];
pp ← GetPlayerPics[picsSource !
FS.Error => {errmsg ← error.explanation; failure ← TRUE; CONTINUE}];
IF failure THEN RETURN;
[mv, errmsg] ← MazeFromRope[mazeRope];
IF errmsg.Length[] > 0 THEN RETURN;
myself ← Plop[mv, id, name, instance, pp];
ViewMaze[myself, [iconic: TRUE, name: name]];
AddScoring[myself, myself];
[userName, password] ← UserCredentials.Get[];
TRUSTED {MazeWarPlayerRpcControl.ExportInterface[
interfaceName: [instance: instance],
user: userName,
password: RPC.MakeKey[password]]};
exportedPlayer ← TRUE;
TRUSTED {Process.Detach[FORK StayAlive[myself]]};
END;
debugImport: BOOLEAN ← FALSE;
importFailures: LIST OF CARDINAL ← NIL;
exportedFinder: BOOLEAN ← FALSE;
disabled: BOOL ← FALSE;
finderID: BasicPlayer;
StayAlive:
PROC [p: Player] =
BEGIN ENABLE UNWIND => {IF p.destroyed THEN myself ← NIL};
TRUSTED {Process.SetPriority[Process.priorityBackground]};
FOR age:
CARDINAL ← 0, age + 1
WHILE
NOT p.destroyed
DO
ok: BOOLEAN ← TRUE;
IF
NOT disabled
THEN {
MazeWarFinderRpcControl.ImportInterface[interfaceName: [instance: "MazeWar.Auto"] !RPC.ImportFailed => {ok ← FALSE; CONTINUE}];
IF debugImport
THEN {
MessageWindow.Append[IO.PutFR["Import %g at age %g", IO.bool[ok], IO.card[age]], TRUE];
IF NOT ok THEN importFailures ← CONS[age, importFailures]};
IF ok
THEN {
players: BasicPlayerList;
TRUSTED {
finderID ← MazeWarFinder.GetFinderID[!RPC.CallFailed => {ok ← FALSE; CONTINUE}];
IF ok THEN MazeWarFinder.TakePlayer[[myself.instanceName, myself.id] !RPC.CallFailed => {ok ← FALSE; CONTINUE}];
IF ok THEN players ← MazeWarFinder.ListPlayers[!RPC.CallFailed => {ok ← FALSE; CONTINUE}]};
IF ok
THEN {
FOR players ← players, players.rest
WHILE players #
NIL
DO
q: Player ← EnsurePlayer[players.first];
IF q #
NIL
AND
NOT q.instanceName.Equal[players.first.instance]
THEN
MessageWindow.Append["Random number collision", TRUE];
ENDLOOP;
};
MazeWarFinderRpcControl.UnimportInterface[];
}
ELSE {
IF exportedFinder
THEN
{MazeWarFinderRpcControl.UnexportInterface[]; exportedFinder ← FALSE};
TRUSTED {MazeWarFinderRpcControl.ExportInterface[
interfaceName: [instance: "MazeWar.Auto"],
user: "MazeWar.Auto",
password: RPC.MakeKey["MazeWar"]]};
exportedFinder ← TRUE;
};
};
Delay[age];
ENDLOOP;
IF exportedFinder
THEN
{MazeWarFinderRpcControl.UnexportInterface[]; exportedFinder ← FALSE};
myself ← NIL;
END;
WhoAmI:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN
p: Player ← myself;
IF p = NIL THEN RETURN [$Failure, "Not playing"] ELSE cmd.out.PutF["\"%q\" %g\n", IO.rope[p.instanceName], IO.int[p.id]];
END;
Contact:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN
Parse:
PROC = {
bp.instance ← in.GetRopeLiteral[];
bp.id ← in.GetInt[];
};
bp: BasicPlayer;
in: IO.STREAM ← IO.RIS[cmd.commandLine];
ok: BOOL ← TRUE;
IF myself = NIL THEN RETURN [$Failure, "Not playing"];
Parse[!
IO.Error,
IO.EndOfStream => {
ok ← FALSE;
CONTINUE}];
IF ok THEN [] ← EnsurePlayer[bp] ELSE RETURN [$Failure, "Syntax error; say: MazeWarContact \"nn#mmm#ss\" iiiii\n"];
END;
Delay:
PROC [age:
CARDINAL] =
BEGIN
center: CARDINAL ← (IF age < 3 THEN 4 ELSE IF age < 16 THEN 16 ELSE 256) * Process.SecondsToTicks[1];
wait: CARDINAL ← Random.Choose[center/2, 3*center/2];
Process.Pause[wait];
END;
MazeFromRope:
PROC [rope:
ROPE]
RETURNS [mv: MazeView, errmsg:
ROPE ←
NIL] =
BEGIN
Check:
PROC [row, col, drow, dcol:
INTEGER]
RETURNS [bad:
BOOLEAN ←
FALSE] =
BEGIN
index: INTEGER ← Index[mv, row-drow, col-dcol];
di: INTEGER ← Direction[mv, drow, dcol];
IF
NOT mv.squares[index].open
THEN
BEGIN
d: INTEGER ← 0;
FOR index ← index+di, index+di WHILE mv.squares[index].open DO d ← d + 1 ENDLOOP;
IF d > MaxDistance+1 THEN {errmsg ← IO.PutFR["Maze has open distance too long (> %g)", IO.int[MaxDistance+1]]; RETURN[TRUE]};
END;
END;
rl: INT ← rope.Length[];
cols: INTEGER ← rope.Find["\n"];
rows: INTEGER ← rl/(cols+1);
IF rows*(cols+1) # rl THEN RETURN [NIL, "Maze description not properly punctuated with newlines"];
mv ← NEW [MazeViewRep[rows*cols]];
mv.asRope ← rope;
mv.rows ← rows;
mv.cols ← cols;
FOR row:
INTEGER
IN [0 .. rows)
DO
FOR col:
INTEGER
IN [0 .. cols)
DO
char: CHAR ← rope.Fetch[row*(cols+1)+col];
index: INTEGER ← Index[mv, row, col];
mv.squares[index] ← [];
SELECT char
FROM
'X => mv.squares[index].open ← FALSE;
'. => mv.squares[index].open ← TRUE;
ENDCASE => RETURN [NIL, IO.PutFR["Bad character in maze: 0%bC", IO.char[char]]];
IF mv.squares[index].open AND (row = 0 OR row = rows-1 OR col = 0 OR col = cols-1) THEN RETURN [NIL, IO.PutFR["Gap in border"]];
ENDLOOP;
ENDLOOP;
FOR row:
INTEGER
IN (0 .. rows-1)
DO
FOR col:
INTEGER
IN (0 .. cols-1)
DO
IF Check[row, col, 0, 1] THEN RETURN;
IF Check[row, col, 1, 0] THEN RETURN;
ENDLOOP;
ENDLOOP;
mv.topX ← innerBorder + w - tvd*cols/2;
mv.topY ← innerBorder + tvd*rows;
mv.inY ← w + hallTopSep;
mv.inX ← tvd*cols/2;
END;
hallTopSep: INTEGER ← 3;
scoreTopSep: INTEGER ← 5;
scoreSep: INTEGER ← 1;
innerBorder: INTEGER ← 2;
Plop:
PROC [mv: MazeView, id: PlayerId, name, instance:
ROPE, pp: PlayerPics]
RETURNS [p: Player] =
BEGIN
row, col: INTEGER;
[row, col] ← PickAPlace[mv];
p ← AddPlayerAt[mv, NIL, instance, id, name, row, col, 0, 0, pp];
END;
PickAPlace:
PUBLIC
PROC [mv: MazeView]
RETURNS [row, col:
INTEGER] =
BEGIN
me: INTEGER;
DO
row ← Random.Choose[0, mv.rows-1];
col ← Random.Choose[0, mv.cols-1];
me ← Index[mv, row, col];
IF mv.squares[me].open THEN RETURN;
ENDLOOP;
END;
ViewMaze:
PROC [p: Player, viewerInit: ViewerClasses.ViewerRec] =
BEGIN
IF viewerInit.icon = unInit THEN viewerInit.icon ← mazeWarriorIcon;
p.mv.container ← Containers.Create[info: viewerInit, paint: FALSE];
p.mv.maze ← ViewerOps.CreateViewer[flavor: mazeViewerFlavor, info: [parent: p.mv.container, wx: 10, wy: 10, ww: 100, wh: 100, data: p, border: FALSE], paint: FALSE];
ViewerOps.MoveViewer[
viewer: p.mv.maze,
x: p.mv.maze.wx,
y: p.mv.maze.wy,
w: 2*(w+innerBorder) + p.mv.maze.ww - p.mv.maze.cw,
h: 2*(w+innerBorder) + hallTopSep + tvd*p.mv.rows + p.mv.maze.wh - p.mv.maze.ch,
paint: FALSE];
END;
IncrPaint:
PUBLIC
PROC [p: Player] = {
IF p.shot THEN TRUSTED {Process.Detach[FORK ReallyIncrPaint[p]]}
ELSE ReallyIncrPaint[p]};
ReallyIncrPaint:
PROC [p: Player] = {
InnerPaint:
ENTRY
PROC = {
ViewerOps.PaintViewer[viewer: p.mv.maze, hint: client, clearClient: FALSE, whatChanged: p];
};
IF p # myself
OR
NOT clippable
THEN
ViewerOps.PaintViewer[viewer: p.mv.maze, hint: client, clearClient: FALSE, whatChanged: p]
ELSE {
paints ← paints + 1;
InnerPaint[!UNWIND => paints ← paints - 1];
paints ← paints - 1};
};
AddScoring:
PUBLIC
PROC [vp, p: Player] =
BEGIN
mv: MazeView ← p.mv;
y: INTEGER ← vp.mv.maze.wy + vp.mv.maze.wh + scoreTopSep;
p.nameLabel ← Labels.Create[info: [parent: mv.container, name: p.name, border: FALSE], paint: FALSE];
p.scoreLabel ← Labels.Create[info: [parent: mv.container, name: "-65,535", border: FALSE], paint: FALSE];
Labels.Set[p.scoreLabel, IO.PutFR["%6g", IO.int[p.score]], FALSE];
Labels.SetDisplayStyle[p.nameLabel, IF Visibility[vp, p] > 0 THEN $WhiteOnBlack ELSE $BlackOnWhite, FALSE];
FOR pl: PlayerList ← mv.players, pl.rest
WHILE pl #
NIL
DO
n: Viewer ← pl.first.nameLabel;
v: Viewer ← pl.first.scoreLabel;
ViewerOps.MoveViewer[viewer: n, x: mv.maze.wx, y: y, w: n.ww, h: n.wh, paint: FALSE];
ViewerOps.MoveViewer[viewer: v, x: mv.maze.wx + mv.maze.ww - v.ww, y: y, w: v.ww, h: v.wh, paint: FALSE];
y ← MAX[n.wy+n.wh, v.wy+v.wh] + scoreSep;
ENDLOOP;
END;
DrawHall:
PUBLIC
PROC [context: Context, mv: MazeView, row, col, drow, dcol:
INTEGER, angle: Angle] =
BEGIN
Line:
PROC [a, b: Pt3] =
INLINE {
Graphics.SetCP[context, a.x/a.z, a.y/a.z];
Graphics.DrawTo[context, b.x/b.z, b.y/b.z]};
DoIt:
PROC = {
Blt:
PROC [piece: Piece] = {
lb: LocatedBitmap ← pieces[d][piece];
GraphicsOps.DrawBitmap[self: context, bitmap: lb.bitmap, w: lb.bitmap.width, h: lb.bitmap.height, x: 0, y: 0, xorigin: lb.xorigin, yorigin: lb.yorigin];
};
DrawPlayers:
PROC = {
Graphics.SetCP[context, 0, 0];
[] ← Graphics.SetPaintMode[context, invert];
FOR pl: PlayerList ← shownPlayers, pl.rest
WHILE pl #
NIL
DO
b: Bitmap ← pl.first.pics.pics[pl.first.sdistance][(pl.first.sangle+4-angle) MOD 4];
GraphicsOps.DrawBitmap[self: context, bitmap: b, w: b.width, h: b.height, x: 0, y: 0, xorigin: b.width/2, yorigin: b.height/2];
ENDLOOP;
};
me, di, left, right, d, crow, ccol: INTEGER;
f, b: Number;
mes, lefts, rights: Square;
di ← Direction[mv, drow, dcol];
left ← Direction[mv, -dcol, drow];
right ← Direction[mv, dcol, -drow];
crow ← row;
ccol ← col;
mes ← mv.squares[me ← Index[mv, row, col]];
f ← z1;
b ← hither;
[] ← Graphics.SetPaintMode[context, opaque];
Graphics.SetColor[context, Graphics.white];
Graphics.DrawBox[context, [-w, -w, w, w]];
Graphics.SetColor[context, Graphics.black];
Graphics.SetCP[context, w, w];
Graphics.DrawTo[context, w, -w];
Graphics.DrawTo[context, -w, -w];
Graphics.DrawTo[context, -w, w];
Graphics.DrawTo[context, w, w];
IF NOT mes.open THEN RETURN;
lefts ← mv.squares[me + left];
rights ← mv.squares[me + right];
IF blt
THEN {
Graphics.SetCP[context, 0, 0];
[] ← Graphics.SetPaintMode[context, transparent]};
d ← 0;
WHILE mes.open
DO
nu: INTEGER ← me + di;
fls: Square ← mv.squares[nu + left];
frs: Square ← mv.squares[nu + right];
fs: Square ← mv.squares[nu];
r2: Number ← f*r/b;
IF paints > 1 AND clippable THEN RETURN;
IF
NOT lefts.open
THEN {
IF blt THEN Blt[LeftFilled]
ELSE {
Line[[-r, r, f], [-r, r, b]];
Line[[-r, -r, f], [-r, -r, b]]}}
ELSE
IF
NOT fls.open
THEN {
IF blt THEN Blt[LeftGap]
ELSE {
Line[[-r2, r, f], [-r, r, f]];
Line[[-r2, -r, f], [-r, -r, f]]}};
IF (
IF fs.open
THEN lefts.open # fls.open
ELSE
IF lefts.open
THEN fls.open
ELSE
TRUE)
THEN {
IF blt THEN Blt[LeftEdge] ELSE Line[[-r, r, f], [-r, -r, f]]};
IF
NOT rights.open
THEN {
IF blt THEN Blt[RightFilled]
ELSE {
Line[[ r, r, f], [ r, r, b]];
Line[[ r, -r, f], [ r, -r, b]]}}
ELSE
IF
NOT frs.open
THEN {
IF blt THEN Blt[RightGap]
ELSE {
Line[[ r2, r, f], [ r, r, f]];
Line[[ r2, -r, f], [ r, -r, f]]}};
IF (
IF fs.open
THEN rights.open # frs.open
ELSE
IF rights.open
THEN frs.open
ELSE
TRUE)
THEN {
IF blt THEN Blt[RightEdge] ELSE Line[[r, r, f], [r, -r, f]]};
b ← f;
f ← f + dz;
d ← d + 1;
me ← nu;
mes ← fs;
lefts ← fls;
rights ← frs;
crow ← crow + drow;
ccol ← ccol + dcol;
ENDLOOP;
d ← d - 1;
IF blt THEN Blt[HorEdges]
ELSE {
Line[[-r, r, b], [r, r, b]];
Line[[-r, -r, b], [r, -r, b]]};
CallUnderMonitor1[DrawPlayers];
};
mark: BasicTime.Pulses;
IF hallHist # NIL THEN mark ← BasicTime.GetClockPulses[];
DoIt[];
IF hallHist # NIL THEN hallHist.Increment[ BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[] - mark]/5000];
END;
hallHist: Histograms.Histogram;
hallHistViewer: Viewer;
HistHall: PROC =
BEGIN
hallHist ← Histograms.NewHistogram[];
hallHistViewer ← hallHist.ShowIn[name: "Hall Paint Times/(.005 sec)"];
END;
AddPlayerAt:
PUBLIC
PROC [mv: MazeView, ir: PlayerInterface, instanceName:
ROPE, id: PlayerId, name:
ROPE, row, col:
INTEGER, angle: Angle, score:
INTEGER, pp: PlayerPics]
RETURNS [p: Player] =
BEGIN
me: INTEGER ← Index[mv, row, col];
p ← NEW [PlayerRep ← [mv: mv, ir: ir, instanceName: instanceName, id: id, row: row, col: col, angle: angle, peek: 0, score: score, name: name, pics: pp]];
mv.squares[me].occupants ← CONS[p, mv.squares[me].occupants];
mv.players ← CONS[p, mv.players];
END;
Rotate:
PROC [x, y:
REAL, angle: Angle]
RETURNS [rx, ry:
REAL] =
BEGIN
IF angle >= 2 THEN {x ← -x; y ← -y; angle ← angle-2};
IF angle = 0 THEN RETURN [x, y];
RETURN [-y, x];
END;
picsTable: OSTR.Table ← OSTR.CreateTable[ComparePix];
ComparePix:
OSTR.CompareProc
--PROC [r1, r2: Item] RETURNS [Comparison]-- =
BEGIN
k1, k2: ROPE;
WITH r1
SELECT
FROM
r: ROPE => k1 ← r;
pp: PlayerPics => k1 ← pp.name;
ENDCASE => ERROR;
WITH r2
SELECT
FROM
r: ROPE => k2 ← r;
pp: PlayerPics => k2 ← pp.name;
ENDCASE => ERROR;
RETURN [k1.Compare[s2: k2, case: FALSE]];
END;
LosePlayerPics: PUBLIC ENTRY PROC [root: ROPE] = {[] ← picsTable.Delete[root]};
GetPlayerPics:
PUBLIC
PROC [root:
ROPE]
RETURNS [pp: PlayerPics] =
BEGIN
IF root.Length[] < 1 OR root.Equal["default", FALSE] THEN RETURN [defaultPlayerPics]; no more--
pp ← NARROW[picsTable.Lookup[root]];
IF pp =
NIL
THEN {
newPics: PlayerPics ← ReadPlayerPics[root];
Insert:
ENTRY
PROC = {
pp ← NARROW[picsTable.Lookup[root]];
IF pp = NIL THEN picsTable.Insert[pp ← newPics]};
Insert[];
};
END;
ReadPlayerPics:
PROC [root:
ROPE]
RETURNS [pp: PlayerPics] =
BEGIN
negate: BOOLEAN ← '- = root.Fetch[0];
IF myself # NIL THEN myself.pausing ← TRUE;
MessageWindow.Append[Rope.Cat["Patience... loading images from ", root, " ..."], TRUE];
pp ← NEW [PlayerPicsRep ← [root, ALL[ALL[NIL]]]];
IF negate THEN root ← root.Substr[1, root.Length[]-1];
FOR a: Angle
IN Angle
DO
image: GraphicsOps.ImageRef;
xmin,ymin,xmax,ymax, imageSize, cx, cy: REAL;
image ← GraphicsOps.NewAisImage[root.Cat[suffixes[a]]];
[xmin,ymin,xmax,ymax] ← GraphicsOps.ImageBox[image];
imageSize ← MAX[xmax-xmin, ymax-ymin];
cx ← (xmin+xmax)/2;
cy ← (ymin+ymax)/2;
FOR d:
INTEGER
IN [1 .. MaxDistance]
DO
rd: INTEGER ← r/(z1+(d-1)*dz);
scale: REAL ← 2*rd/imageSize;
context: Graphics.Context;
mark: Graphics.Mark;
pp.pics[d][a] ← GraphicsOps.NewBitmap[width: rd*2, height: rd*2];
context ← GraphicsOps.NewContextFromBitmap[pp.pics[d][a]];
Graphics.Translate[context, rd, rd];
IF negate
THEN {
Graphics.DrawBox[context, [-rd, -rd, rd, rd]];
mark ← Graphics.Save[context]};
Graphics.Scale[context, scale, scale];
Graphics.Translate[context, -cx, -cy];
Graphics.SetCP[context, 0, 0];
Graphics.DrawImage[context, image];
IF negate
THEN {
Graphics.Restore[context, mark];
[] ← Graphics.SetPaintMode[context, invert];
Graphics.DrawBox[context, [-rd, -rd, rd, rd]]};
ENDLOOP;
ENDLOOP;
MessageWindow.Append[" done", FALSE];
IF myself # NIL THEN myself.pausing ← FALSE;
END;
suffixes: ARRAY Angle OF ROPE ← ["Back.ais", "Right.ais", "Front.ais", "Left.ais"];
runMess: ROPE ← NIL;
runError: BOOLEAN ← FALSE;
Setup:
PROC =
BEGIN
arrowPath: Graphics.Path ← Graphics.NewPath[8];
pp: Graphics.Path ← Graphics.NewPath[8];
f, b: Number;
count: REF CARDINAL ← NARROW[Atom.GetProp[atom: $MazeWar, prop: $PlayerCount]];
playerRope: ROPE ← NIL;
IF count = NIL THEN Atom.PutProp[atom: $MazeWar, prop: $PlayerCount, val: count ← NEW [CARDINAL ← 0]];
count^ ← playerNumber ← count^ + 1;
TRUSTED {myAddr ← PupDefs.GetLocalPupAddress[[0, 0], [[0], [0], [0, 0]]]};
myInstance ← IO.PutFR["%b#%b#%b", IO.card[myAddr.net], IO.card[myAddr.host], IO.card[playerNumber]];
IF playerNumber # 1 THEN playerRope ← IO.PutFR["%g", IO.card[playerNumber]];
[runMess, runError] ← CommandTool.Run["/Ivy/Spreitzer/Games/MazeWarCommon.BCD"];
[] ← Random.Init[seed: -1];
{q: REAL = 2; q2: REAL = 5;
Graphics.MoveTo[arrowPath, tvd/q, 0];
Graphics.LineTo[arrowPath, 0, tvd/q];
Graphics.LineTo[arrowPath, 0, tvd/q2];
Graphics.LineTo[arrowPath, -tvd/q, tvd/q2];
Graphics.LineTo[arrowPath, -tvd/q, -tvd/q2];
Graphics.LineTo[arrowPath, 0, -tvd/q2];
Graphics.LineTo[arrowPath, 0, -tvd/q];
Graphics.LineTo[arrowPath, tvd/q, 0];
};
FOR a: Angle
IN Angle
DO
context: Context;
topviews[a] ← GraphicsOps.NewBitmap[tvd, tvd];
context ← GraphicsOps.NewContextFromBitmap[topviews[a]];
Graphics.Translate[context, tvd/2, tvd/2];
Graphics.Rotate[context, a*-90];
Graphics.DrawArea[context, arrowPath];
--no more need for arrows, so commented out--
FOR d: INTEGER IN [1 .. MaxDistance] DO
Draw: PROC [x, z: REAL] =
BEGIN
y: REAL;
[z, x] ← Rotate[z, x, a];
z ← ((z+1)*dz/2 + (d-1)*dz + z1)/r;
y ← -1/z;
x ← x/z;
Graphics.LineTo[pp, x, y];
END;
Move: PROC [x, z: REAL] =
BEGIN
y: REAL;
[z, x] ← Rotate[z, x, a];
z ← ((z+1)*dz/2 + (d-1)*dz + z1)/r;
y ← -1/z;
x ← x/z;
Graphics.MoveTo[pp, x, y];
END;
context: Context;
rd: INTEGER ← (s + d-1)/d;
defaultPlayerPics.pics[d][a] ← GraphicsOps.NewBitmap[width: rd*2, height: rd*2];
context ← GraphicsOps.NewContextFromBitmap[defaultPlayerPics.pics[d][a]];
Graphics.Translate[context, rd, rd];
Move[0, 1];
Draw[-1, 0];
Draw[-.5, 0];
Draw[-.5, -1];
Draw[.5, -1];
Draw[.5, 0];
Draw[1, 0];
Draw[0, 1];
Graphics.DrawArea[context, pp];
ENDLOOP;
ENDLOOP;
f ← z1;
b ← hither;
FOR d:
INTEGER
IN [0 .. MaxDistance]
DO
Start:
PROC [piece: Piece] = {
rmin: Number ← r/f;
rmax: Number ← r/b;
bounds: Box;
bounds ←
SELECT piece
FROM
LeftFilled => [-rmax, -rmax, -rmin, rmax],
LeftGap => [-rmax, -rmin, -rmin, rmin],
LeftEdge => [-rmin, -rmin, -rmin, rmin],
RightFilled => [rmin, -rmax, rmax, rmax],
RightGap => [rmin, -rmin, rmax, rmin],
RightEdge => [rmin, -rmin, rmin, rmin],
HorEdges => [-rmin, -rmin, rmin, rmin],
ENDCASE => ERROR;
bounds.xmin ← bounds.xmin - 1;
bounds.ymin ← bounds.ymin - 1;
bounds.xmax ← bounds.xmax + 1;
bounds.ymax ← bounds.ymax + 1;
pieces[d][piece] ← [
bitmap: GraphicsOps.NewBitmap[
width: bounds.xmax-bounds.xmin,
height: bounds.ymax-bounds.ymin],
xorigin: -bounds.xmin,
yorigin: bounds.ymax];
context ← GraphicsOps.NewContextFromBitmap[pieces[d][piece].bitmap];
Graphics.Translate[context, -bounds.xmin, -bounds.ymin];
};
Line:
PROC [a, b: Pt3] =
INLINE {
Graphics.SetCP[context, a.x/a.z, a.y/a.z];
Graphics.DrawTo[context, b.x/b.z, b.y/b.z]};
context: Graphics.Context;
r2: Number ← f*r/b;
Start[LeftFilled]; Line[[-r, r, f], [-r, r, b]]; Line[[-r, -r, f], [-r, -r, b]];
Start[LeftGap]; Line[[-r2, r, f], [-r, r, f]]; Line[[-r2, -r, f], [-r, -r, f]];
Start[LeftEdge]; Line[[-r, r, f], [-r, -r, f]];
Start[RightFilled]; Line[[ r, r, f], [ r, r, b]]; Line[[ r, -r, f], [ r, -r, b]];
Start[RightGap]; Line[[ r2, r, f], [ r, r, f]]; Line[[ r2, -r, f], [ r, -r, f]];
Start[RightEdge]; Line[[r, r, f], [r, -r, f]];
Start[HorEdges]; Line[[-r, r, f], [r, r, f]]; Line[[-r, -r, f], [r, -r, f]];
b ← f;
f ← f + dz;
ENDLOOP;
ViewerOps.RegisterViewerClass[flavor: mazeViewerFlavor, class: mazeViewerClass];
Commander.Register[key: Rope.Cat["MazeWar", playerRope], proc: StartPlayer, doc: "starts playing maze war; see MazeWarDoc.Tioga for possible command line arguments"];
Commander.Register[key: Rope.Cat["MazeWarStop", playerRope], proc: StopPlayer, doc: "exits maze war game"];
Commander.Register[key: Rope.Cat["WhoAmI", playerRope], proc: WhoAmI, doc: "gives your MazeWar identification"];
Commander.Register[key: Rope.Cat["MazeWarContact", playerRope], proc: Contact, doc: "MazeWarContact \"nn#mmm#ss\" iiiii makes contact with that MazeWar player"];
END;
Box: TYPE = RECORD [xmin, ymin, xmax, ymax: Number];
StupidFuckingWarnings: PUBLIC SIGNAL [ATOM] = CODE;
Setup[];
END.