Foundations of Videogame Programming(2020)[Sanders[9798657300802]
 9798657300802

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

Foundations of Videogame Programming Code Repository Benjamin Sanders, M. S. July 30, 2020

2

3

Other Books by Benjamin Sanders

The Bible in Original Tongues In My Heart, On My Mind: Forty Days of Biblical Prayer Four Year Mission: My Prayer Journal The Psalms in Verse: A Guitarist’s Journal Allegory and Illustration in the Book of Genesis LARP Gameworld Design: Cartographer’s Journal Role-playing Games in Physics Write Your Own Adventure The Sanders Family Cookbook

All content herein Copyright (C) 2020 Benjamin Sanders. All rights reserved.

4

Contents I

Text-based Videogames

7

1 Adventure

9

2 Game of Life

47

3 Networked Chess

53

4 Threaded Network

67

II

73

2D Videogames

5 Asteroids

75

6 Zelda

III

109

2.5-D Videogames

151

7 Image Transformations

153

8 Formula One

159

IV

3D Videogames

181

9 Sauerbraten

183

5

6

Part I Text-based Videogames

7

Chapter 1 Adventure

License Copyright (c) 1991, 1993 The Regents of the University of California.

All rights reserved.

The game adventure was originally written in Fortran by Will Crowther and Don Woods. It was later translated to C and enhanced by Jim Gillogly. This code is derived from software contributed to Berkeley by Jim Gillogly at The Rand Corporation. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ‘‘AS IS’’ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 9

10

Foundations of Videogame Programming Code Repository

SUCH DAMAGE. ADVENTURE -- Jim Gillogly, Jul 1977 This program is a re-write of ADVENT, written in FORTRAN mostly by Don Woods of SAIL. In most places it is as nearly identical to the original as possible given the language and word-size differences. A few places, such as the message arrays and travel arrays were changed to reflect the smaller core size and word size. The labels of the original are reflected in this version, so that the comments of the fortran are still applicable here. The data file distributed with the fortran source is assumed to be called "glorkz" in the directory where the program is first run. The original FORTRAN version can be found at .

Makefile # #

$NetBSD : Makefile , v 1.14 2013/02/16 16:30:28 j m c n e i l l Exp $ @( # ) Makefile 8.1 ( Berkeley ) 6/12/93

PROG= adventure SRCS= main . c i n i t . c done . c save . c subr . c vocab . c wizard . c i o . c data . c crc .c MAN= adventure .6 HIDEGAME=hidegame CLEANFILES+=mkdata setup . l o data . c data . c : glorkz mkdata ${ MKTARGET CREATE} ./mkdata $ { .CURDIR}/ glorkz > data . c setup . l o : hdr . h mkdata : setup . l o ${ MKTARGET LINK} ${HOST LINK . c} −o $ { .TARGET} $ { .ALLSRC} . include

main.c /∗

$NetBSD : main . c , v 1.21 2009/08/25 06:56:52 dholland Exp $

#include #ifndef l i n t COPYRIGHT ( ”@( # ) Copyright ( c ) 1991, 1993\ The Regents o f the University o f C a l i f o r n i a . #endif /∗ not l i n t ∗/

∗/

A l l r i g h t s reserved . ” ) ;

#ifndef l i n t #if 0 s t a t i c char sccsid [ ] = ”@( # ) main . c 8.1 ( Berkeley ) 6/2/93” ; #e l s e RCSID ( ”$NetBSD : main . c , v 1.21 2009/08/25 06:56:52 dholland Exp $” ) ; #endif #endif /∗ not l i n t ∗/ /∗

Re−coding o f advent in C: main program ∗/

main.c

#include #include #include #include #include #include #include #include





” hdr . h” ” extern . h”

int main ( i n t argc , char ∗∗argv ) { int i; int rval , l l ; struct t e x t ∗kk ; /∗ revoke s e t g i d p r i v i l e g e s from dm ∗/ setgid ( getgid ( ) ) ; init ( ) ; /∗ I n i t i a l i z e everything ∗/ s i g n a l ( SIGINT , trapdel ) ; i f ( argc > 1) { /∗ Restore f i l e s p e c i f i e d ∗/ /∗ Restart i s l a b e l 8305 ( Fortran ) ∗/ i = r e s t o r e ( argv [ 1 ] ) ; /∗ See what we ’ ve got ∗/ switch ( i ) { case 0: /∗ The r e s t o r e worked f i n e ∗/ yea = Start ( ) ; k = null ; unlink ( argv [ 1 ] ) ; /∗ Don ’ t re−use the save ∗/ goto l8 ; /∗ Get where we ’ re going ∗/ case 1: /∗ Couldn ’ t open i t ∗/ errx ( 1 , ” can ’ t open f i l e ” ) ; /∗ So g i v e up ∗/ case 2: /∗ Oops −− f i l e was a l t e r e d ∗/ rspeak (202) ; /∗ You d i s s o l v e ∗/ exit ( 1 ) ; /∗ F i l e could be non−adventure ∗/ } /∗ So don ’ t unlink i t . ∗/ } startup ( ) ; /∗ prepare f o r a user ∗/ for ( ; ; ) { /∗ main command loop ( l a b e l 2) ∗/ i f ( newloc < 9 && newloc ! = 0 && i s c l o s i n g ) { rspeak (130) ; /∗ i f c l o s i n g leave only by ∗/ newloc = l o c ; /∗ main o f f i c e ∗/ i f ( ! panic ) clock2 = 15; panic = TRUE; } r v a l = fdwarf ( ) ; /∗ dwarf s t u f f ∗/ i f ( r v a l == 99) die ( 9 9 ) ; l2000 :

i f ( l o c == 0) die ( 9 9 ) ; /∗ l a b e l 2000 ∗/ kk = &s t e x t [ l o c ] ; i f ( ( abb [ l o c ] % abbnum) == 0 || kk−>seekadr == 0) kk = &l t e x t [ l o c ] ; i f ( ! forced ( l o c ) && dark ( ) ) { i f ( wasdark && pct ( 3 5 ) ) { die ( 9 0 ) ; goto l2000 ; } kk = &r t e x t [ 1 6 ] ; }

#if 0 l2001 : #endif i f ( t o t i n g ( bear ) ) rspeak (141) ; /∗ 2001 ∗/ speak ( kk ) ; k = 1; i f ( forced ( l o c ) ) goto l8 ; i f ( l o c == 33 && pct ( 2 5 ) && ! i s c l o s i n g ) rspeak ( 8 ) ; i f ( ! dark ( ) ) { abb [ l o c ] + + ; f o r ( i = a t l o c [ l o c ] ; i ! = 0; i = l i n k s [ i ] ) { /∗ 2004 ∗/ obj = i ; i f ( obj > 100) obj −= 100; i f ( obj == steps && t o t i n g ( nugget ) ) continue ; i f ( prop [ obj ] < 0) { i f ( closed ) continue ; prop [ obj ] = 0; i f ( obj == rug || obj == chain ) prop [ obj ] = 1; t a l l y −−; i f ( t a l l y == t a l l y 2 && t a l l y ! = 0) i f ( l i m i t > 35) l i m i t = 35;

} l l = prop [ obj ] ; /∗ 2006 ∗/ i f ( obj == steps && l o c == f i x e d [ steps ] ) l l = 1; pspeak ( obj , l l ) ; } /∗ 2008 ∗/ goto l2012 ; l2009 : k = 54; /∗ 2009 ∗/ l2010 : spk = k ; l2011 : rspeak ( spk ) ; } l2012 : verb = 0; /∗ 2012 ∗/ obj = 0; l2600 : checkhints ( ) ; /∗ to 2600−2602 ∗/ i f ( closed ) { i f ( prop [ oyster ] < 0 && t o t i n g ( oyster ) ) pspeak ( oyster , 1) ; f o r ( i = 1; i < 100; i ++) i f ( t o t i n g ( i ) && prop [ i ] < 0) /∗ 2604 ∗/ prop [ i ] = −1 − prop [ i ] ; } wasdark = dark ( ) ; /∗ 2605 ∗/ i f ( knfloc > 0 && knfloc ! = l o c ) knfloc = 1; g e t i n (&wd1, &wd2) ; i f ( delhit ) { /∗ user typed a DEL ∗/ d e l h i t = 0; /∗ r e s e t counter ∗/ copystr ( ” quit ” , wd1) ; /∗ pretend he ’ s q u i t t i n g ∗/ ∗wd2 = 0; } l2608 : i f ( ( foobar = −foobar ) > 0) foobar = 0; /∗ 2608 ∗/ /∗ should check here f o r ” magic mode” ∗/ turns ++; i f ( demo && turns >= SHORT) done ( 1 ) ; /∗ to 13000 ∗/ i f ( verb == say && ∗wd2 ! = 0) verb = 0; i f ( verb == say ) goto l4090 ; i f ( t a l l y == 0 && l o c >= 15 && l o c ! = 33) clock1−−; i f ( clock1 == 0) { closing ( ) ; /∗ to 10000 ∗/ goto l19999 ; } i f ( clock1 < 0) clock2−−; i f ( clock2 == 0) { caveclose ( ) ; /∗ to 11000 ∗/ continue ; /∗ back to 2 ∗/ } i f ( prop [ lamp ] == 1) l i m i t−−; i f ( l i m i t 0; j−−) i f ( f i x d [ j ] > 0) { drop ( j + 100, f i x d [ j ] ) ; drop ( j , plac [ j ] ) ; } f o r ( j = 100; j > 0; j−−) { fixed [ j ] = fixd [ j ] ; i f ( plac [ j ] ! = 0 && f i x d [ j ] c r c v a l >> 24 ˆ udata [ pos + + ] ) & 0 x f f ; i f ( x == 0) { x = c−>step ++; i f ( c−>step >= arraycount ( crctab ) ) { c−>step = 0; } } c−>c r c v a l = ( c−>c r c v a l c r c v a l ; }

io.c /∗

$NetBSD : i o . c , v 1.22 2009/08/25 06:56:52 dholland Exp $

∗/

#include #ifndef l i n t #if 0 s t a t i c char sccsid [ ] = ”@( # ) i o . c 8.1 ( Berkeley ) 5/31/93” ; #e l s e RCSID ( ”$NetBSD : i o . c , v 1.22 2009/08/25 06:56:52 dholland Exp $” ) ; #endif #endif /∗ not l i n t ∗/ /∗

Re−coding o f advent in C: f i l e i /o and user i /o ∗/

#include #include #include #include #include



” hdr . h”

0x18b74777 , 0x8f659eff , 0xd70dd2ee , 0x4969474d , 0x37d83bf0 , 0xbdbdf21c , 0xcdd70693 , 0x5d681b02 , 0x2d02ef8d

/∗ ∗ crc −− ∗ Compute a POSIX.2 checksum . This routine modified by Jim Gillogly ∗ to work on sequential data rather than on a f i l e . Initial call to ∗ c r c s t a r t i n i t i a l i z e s the sum, and subsequent c a l l s to crc update ∗ it . ∗/

#include ” extern . h” s t a t i c const uint32 t crctab [256] = { 0x7fffffff , 0x77073096 , 0xee0e612c , 0x990951ba , 0xe963a535 , 0x9e6495a3 , 0x0edb8832 , 0x97d2d988 , 0x09b64c2b , 0x7eb17cbd , 0x1db71064 , 0x6ab020f2 , 0xf3b97148 , 0x6ddde4eb , 0xf4d4b551 , 0x83d385c7 , 0xfd62f97a , 0x8a65c9ec , 0x14015c4f , 0x8d080df5 , 0x3b6e20c8 , 0x4c69105e , 0x3c03e4d1 , 0x4b04d447 , 0xd20d85fd , 0x42b2986c , 0xdbbbc9d6 , 0xacbcf940 , 0xdcd60dcf , 0xabd13d59 , 0x26d930ac , 0xbfd06116 , 0x21b4f4b5 , 0x56b3c423 , 0x2802b89e , 0x5f058808 , 0xc60cd9b2 , 0x58684c11 , 0xc1611dab , 0xb6662d3d , 0x98d220bc , 0xefd5102a , 0x71b18589 , 0xe8b8d433 , 0x7807c9a2 , 0x0f00f934 , 0x7f6a0dbb , 0x086d3d2d , 0x91646c97 , 0x1c6c6162 , 0x856530d8 , 0xf262004e , 0x8208f4c1 , 0xf50fc457 , 0x65b0d9c6 , 0xfcb9887c , 0x62dd1ddf , 0x15da2d49 , 0x4db26158 , 0x3ab551ce , 0xa3bc0074 , 0x3dd895d7 , 0xa4d1c46d , 0xd3d6f4fb , 0xad678846 , 0xda60b8d0 , 0x44042d73 , 0xdd0d7cc9 , 0x5005713c , 0x270241aa , 0x5768b525 , 0x206f85b3 , 0xb966d409 , 0x29d9c998 , 0xb0d09822 , 0xc7d7a8b4 , 0xb7bd5c3b , 0xc0ba6cad , 0xedb88320 , 0x74b1d29a , 0xead54739 , 0x9dd277af , 0xe3630b12 , 0x94643b84 , 0x0d6d6a3e , 0x9309ff9d , 0x0a00ae27 , 0x7d079eb1 , 0x1e01f268 , 0x6906c2fe , 0xf762575d , 0x6e6b06e7 , 0xfed41b76 , 0x89d32be0 , 0xf9b9df6f , 0x8ebeeff9 , 0x17b7be43 , 0xa1d1937e , 0x38d8c2c4 , 0x4fdff252 , 0x3fb506dd , 0x48b2364b , 0xd80d2bda , 0x41047a60 , 0xdf60efc3 , 0xa867df55 , 0xcb61b38c , 0xbc66831a , 0x256fd2a0 , 0xbb0b4703 , 0x220216b9 , 0x5505262f , 0x2bb45a92 , 0x5cb36a04 , 0xc2d7ffa7 , 0x5bdeae1d , 0x9b64c2b0 , 0xec63f226 , 0x9c0906a9 , 0xeb0e363f , 0x72076785 , 0xe2b87a14 , 0x7bb12bae , 0x0cb61b38 , 0x7cdcefb7 , 0x0bdbdf21 , 0x86d3d2d4 ,

0x1fda836e , 0x88085ae6 , 0xf862ae69 , 0x4e048354 , 0x3e6e77db , 0xa9bcae53 , 0xcabac28a , 0x54de5729 , 0x2a6f2b94 ,

#include ” extern . h” static static static static static static static static static

i n t next ( void ) ; void rdesc ( i n t ) ; void r d e f a u l t ( void ) ; void rhints ( void ) ; void r l i q ( void ) ; void r l o c s ( void ) ; i n t rnum( void ) ; void r t r a v ( void ) ; void rvoc ( void ) ;

/∗ get command from user ∗/ /∗ no prompt, usually ∗/ void g e t i n ( char ∗∗wrd1 , char ∗∗wrd2 ) { char ∗s ; s t a t i c char wd1buf [MAXSTR] , wd2buf [MAXSTR] ;

18 int

Foundations of Videogame Programming Code Repository f i r s t , numch, c ;

∗wrd1 = wd1buf ; /∗ return ptr to i n t e r n a l s t r ∗/ ∗wrd2 = wd2buf ; wd2buf [ 0 ] = 0; /∗ in case i t isn ’ t set here ∗/ f o r ( s = wd1buf , f i r s t = 1 , numch = 0 ; ; ) { c = getchar ( ) ; i f ( ( ∗ s = ( char ) c ) >= ’ A ’ && ∗s = MAXSTR) { /∗ s t r i n g too long ∗/ printf ( ” Give me a break ! ! \n” ) ; wd1buf [ 0 ] = wd2buf [ 0 ] = 0; FLUSHLINE; return ; } s ++; } }

mspeak ( z ) ; return ( r e s u l t ) ; } /∗ FILE ∗inbuf ,∗outbuf ; ∗/ s t a t i c char ∗i n p t r ;

/∗ Pointer i n t o v i r t u a l disk

s t a t i c i n t outsw = 0; s t a t i c const char ; s t a t i c const char

∗/ ∗/

/∗ putting s t u f f to data f i l e ?

iotape [ ] = ”Ax3F’\003tt$8h\315qer∗h\017nGKrX\207:! l ” ∗tape = iotape ;

/∗ next v i r t u a l char , bump adr static int next ( void ) { int ch ;

∗/

/∗ pointer to encryption tape

∗/

ch = (∗ i n p t r ˆ random ( ) ) & 0xFF ; /∗ Decrypt input data ∗/ i f ( outsw ) { /∗ putting data in tmp f i l e ∗/ i f (∗ tape == 0) tape = iotape ; /∗ rewind encryption tape ∗/ ∗i n p t r = ch ˆ ∗tape ++; /∗ re−encrypt and replace value ∗/ } i n p t r ++; return ( ch ) ; } s t a t i c char breakch ;

/∗ t e l l which char ended rnum

∗/

/∗ ” read ” data from v i r t u a l f i l e ∗/ void rdata ( void ) { int sect ; char ch ; inptr = d a t a f i l e ; srandom (SEED) ;

/∗ Pointer to v i r t u a l data f i l e ∗/ /∗ which i s l i g h t l y encrypted . ∗/

} /∗ confirm with rspeak ∗/ int yes ( i n t x , i n t y , i n t z ) { int r e s u l t = TRUE; /∗ p a c i f y gcc ∗/ int ch ; for ( ; ; ) { rspeak ( x ) ; /∗ t e l l him what we want ∗/ i f ( ( ch = getchar ( ) ) == ’ y ’ ) r e s u l t = TRUE; else i f ( ch == ’ n ’ ) r e s u l t = FALSE; else i f ( ch == EOF) { printf ( ” user closed input stream , q u i t t i n g . . . \ n” ) ; exit ( 0 ) ; } FLUSHLINE; i f ( ch == ’ y ’ || ch == ’ n ’ ) break ; printf ( ” Please answer the question .\n” ) ; } i f ( r e s u l t == TRUE) rspeak ( y ) ; i f ( r e s u l t == FALSE ) rspeak ( z ) ; return ( r e s u l t ) ; } /∗ confirm with mspeak ∗/ int yesm ( i n t x , i n t y , i n t z ) { int r e s u l t = TRUE; /∗ p a c i f y gcc ∗/ int ch ; for ( ; ; ) { mspeak ( x ) ; /∗ t e l l him what we want ∗/ i f ( ( ch = getchar ( ) ) == ’ y ’ ) r e s u l t = TRUE; else i f ( ch == ’ n ’ ) r e s u l t = FALSE; else i f ( ch == EOF) { printf ( ” user closed input stream , q u i t t i n g . . . \ n” ) ; exit ( 0 ) ; } FLUSHLINE; i f ( ch == ’ y ’ || ch == ’ n ’ ) break ; printf ( ” Please answer the question .\n” ) ; } i f ( r e s u l t == TRUE) mspeak ( y ) ; i f ( r e s u l t == FALSE )

classes = 1; for ( ; ; ) { /∗ read data sections ∗/ sect = next ( ) − ’ 0 ’ ; /∗ 1s t d i g i t o f section number ∗/ # i f d e f VERBOSE printf ( ” Section %c ” , sect + ’ 0 ’ ) ; #endif i f ( ( ch = next ( ) ) ! = LF ) { /∗ i s there a second d i g i t ? FLUSHLF; # i f d e f VERBOSE putchar ( ch ) ; #endif sect = 10 ∗ sect + ch − ’ 0 ’ ; } # i f d e f VERBOSE putchar ( ’ \n ’ ) ; #endif switch ( sect ) { case 0: /∗ f i n i s h e d reading database ∗/ return ; case 1: /∗ long form descriptions ∗/ rdesc ( 1 ) ; break ; case 2: /∗ short form descriptions ∗/ rdesc ( 2 ) ; break ; case 3: /∗ t r a v e l t a b l e ∗/ rtrav ( ) ; break ; case 4: /∗ vocabulary ∗/ rvoc ( ) ; break ; case 5: /∗ o b j e c t descriptions ∗/ rdesc ( 5 ) ; break ; case 6: /∗ a r b i t r a r y messages ∗/ rdesc ( 6 ) ; break ; case 7: /∗ o b j e c t l o c a t i o n s ∗/ rlocs ( ) ; break ; case 8: /∗ action defaults ∗/ rdefault ( ) ; break ; case 9: /∗ l i q u i d assets ∗/ rliq () ; break ; case 10: /∗ class messages ∗/ rdesc ( 1 0 ) ; break ; case 11: /∗ hints ∗/ rhints ( ) ; break ; case 12: /∗ magic messages ∗/

∗/

io.c rdesc ( 1 2 ) ; break ; default : printf ( ” I n v a l i d data section number : %d\n” , sect ) ; for ( ; ; ) putchar ( next ( ) ) ; } i f ( breakch ! = LF ) /∗ routines return a f t e r ”−1” ∗/ FLUSHLF; }

19

/∗ read t r a v e l t a b l e ∗/ s t a t i c void r t r a v ( void ) { int locc ; struct t r a v l i s t ∗t = NULL; char ∗s ; char buf [ 1 2 ] ; int len , m, n , e n t r i e s = 0;

} s t a t i c char nbf [ 1 2 ] ; /∗ read i n i t i a l l o c a t i o n num ∗/ static int rnum( void ) { char ∗s ; tape = iotape ; /∗ r e s t a r t encryption tape ∗/ f o r ( s = nbf , ∗s = 0 ; ; s ++) i f ( ( ∗ s = next ( ) ) == TAB || ∗s == ’\n ’ || ∗s == LF ) break ; breakch = ∗s ; /∗ save char f o r r t r a v ( ) ∗/ ∗s = 0; /∗ got the number as a s c i i ∗/ i f ( nbf [ 0 ] == ’ − ’) return (−1) ; /∗ end o f data ∗/ return ( a t o i ( nbf ) ) ; /∗ convert i t to i n t e g e r ∗/ } s t a t i c char ∗seekhere ; /∗ read description−format msgs ∗/ s t a t i c void rdesc ( i n t sect ) { int locc ; char ∗seekstart , ∗maystart ; seekhere = i n p t r ; /∗ Where are we in v i r t u a l f i l e ? ∗/ outsw = 1; /∗ these msgs go i n t o tmp f i l e ∗/ f o r ( o l d l o c = −1, seekstart = seekhere ; ; ) { maystart = i n p t r ; /∗ maybe s t a r t i n g new entry ∗/ i f ( ( l o c c = rnum ( ) ) ! = o l d l o c && o l d l o c >= 0 /∗ f i n i s h e d msg ∗/ /∗ unless sect 5 ∗/ && ! ( sect == 5 && ( l o c c == 0 || l o c c >= 100) ) ) { switch ( sect ) { /∗ now put i t i n t o r i g h t t a b l e ∗/ case 1:/∗ long descriptions ∗/ l t e x t [ o l d l o c ] . seekadr = seekhere ; l t e x t [ o l d l o c ] . t x t l e n = maystart − seekstart ; break ; case 2:/∗ short descriptions ∗/ s t e x t [ o l d l o c ] . seekadr = seekhere ; s t e x t [ o l d l o c ] . t x t l e n = maystart − seekstart ; break ; case 5:/∗ o b j e c t descriptions ∗/ ptext [ o l d l o c ] . seekadr = seekhere ; ptext [ o l d l o c ] . t x t l e n = maystart − seekstart ; break ; case 6:/∗ random messages ∗/ i f ( o l d l o c >= RTXSIZE ) errx ( 1 , ” Too many random msgs” ) ; r t e x t [ o l d l o c ] . seekadr = seekhere ; r t e x t [ o l d l o c ] . t x t l e n = maystart − seekstart ; break ; case 10: /∗ class messages ∗/ c t e x t [ classes ] . seekadr = seekhere ; c t e x t [ classes ] . t x t l e n = maystart − seekstart ; cval [ classes ++] = o l d l o c ; break ; case 12: /∗ magic messages ∗/ i f ( o l d l o c >= MAGSIZE) errx ( 1 , ” Too many magic msgs” ) ; mtext [ o l d l o c ] . seekadr = seekhere ; mtext [ o l d l o c ] . t x t l e n = maystart − seekstart ; break ; default : errx ( 1 , ” rdesc c a l l e d with bad section ” ) ; } seekhere += maystart − seekstart ; } i f ( l o c c < 0) { outsw = 0; /∗ turn o f f output ∗/ seekhere += 3; /∗ −1 ∗/ return ; } i f ( sect ! = 5 || ( lo c c > 0 && l o c c < 100) ) { i f ( oldloc != locc ) /∗ s t a r t i n g a new message ∗/ seekstart = maystart ; oldloc = locc ; } FLUSHLF; /∗ scan the l i n e ∗/ } }

f o r ( o l d l o c = −1;;) { /∗ get another l i n e ∗/ /∗ end o f entry ∗/ i f ( ( l o c c = rnum ( ) ) ! = o l d l o c && o l d l o c >= 0 && t ) { t−>next = 0; /∗ terminate the old entry ∗/ /∗ printf ( ”%d:%d e n t r i e s\n” , oldloc , e n t r i e s ) ; ∗/ /∗ t w r i t e ( o l d l o c ) ; ∗/ } i f ( l o c c == −1) return ; i f ( locc != oldloc ) { /∗ g e t t i n g a new entry ∗/ t = t r a v e l [ l o c c ] = c a l l o c ( 1 , s i z e o f (∗ t ) ) ; i f ( t == NULL) e r r ( 1 , NULL) ; /∗ printf ( ”New t r a v e l l i s t f o r %d\n” , l o c c ) ; ∗/ e n t r i e s = 0; oldloc = locc ; } f o r ( s = buf ; ; s ++) /∗ get the newloc number /ASCII ∗/ i f ( ( ∗ s = next ( ) ) == TAB || ∗s == LF ) break ; ∗s = 0; len = length ( buf ) − 1; /∗ quad long number handling ∗/ /∗ printf ( ” Newloc : %s (%d chars )\n” , buf , len ) ; ∗/ i f ( len < 4) { /∗ no ”m” conditions ∗/ m = 0; n = a t o i ( buf ) ; /∗ newloc mod 1000 = newloc ∗/ } else { /∗ a long i n t e g e r ∗/ n = a t o i ( buf + len − 3) ; buf [ len − 3] = 0; /∗ terminate newloc/1000 ∗/ m = a t o i ( buf ) ; } while ( breakch ! = LF ) { /∗ only do one l i n e at a time ∗/ i f ( t == NULL) abort ( ) ; i f ( e n t r i e s ++) { t−>next = c a l l o c ( 1 , s i z e o f (∗ t ) ) ; i f ( t−>next == NULL) e r r ( 1 , NULL) ; t = t−>next ; } t−>tverb = rnum ( ) ; /∗ get verb from the f i l e ∗/ t−>t l o c = n ; /∗ t a b l e entry mod 1000 ∗/ t−>conditions = m; /∗ t a b l e entry / 1000 ∗/ /∗ printf ( ” entry %d f o r %d\n” , entries , l o c c ) ; ∗/ } } } # i f d e f DEBUG /∗ t r a v e l options from t h i s l o c ∗/ void t w r i t e ( i n t loq ) { struct t r a v l i s t ∗t ; printf ( ” I f ” ) ; speak(& l t e x t [ loq ] ) ; printf ( ” then\n” ) ; f o r ( t = t r a v e l [ loq ] ; t ! = 0; t = t−>next ) { printf ( ” verb %d takes you to ” , t−>tverb ) ; i f ( t−>t l o c t l o c ] ) ; else i f ( t−>t l o c t l o c − 300) ; else rspeak ( t−>t l o c − 500) ; printf ( ” under conditions %d\n” , t−>conditions ) ; } } #endif /∗ DEBUG ∗/ /∗ read the vocabulary ∗/ s t a t i c void rvoc ( void ) { char ∗s ; int idx ; char buf [ 6 ] ; for ( ; ; ) { idx = rnum ( ) ; i f ( idx < 0) break ; f o r ( s = buf , ∗s = 0 ; ; s ++)

/∗ get the word

∗/

20

Foundations of Videogame Programming Code Repository i f ( ( ∗ s = next ( ) ) == TAB || ∗s == ’\n ’ || ∗s == LF || ∗s == ’ ’ ) break ; /∗ terminate word with newline , LF , tab , blank ∗/ i f (∗s ! = ’\n ’ && ∗s ! = LF ) FLUSHLF;/∗ can be comments ∗/ ∗s = 0; /∗ printf ( ”\”%s\”=%d\n” , buf , idx ) ; ∗/ vocab ( buf , −2, idx ) ;

void mspeak ( i n t msg ) { i f ( msg ! = 0) speak(&mtext [ msg ] ) ; }

/∗ read , decrypt , and print a message ( not ptext ) ∗/ /∗ msg i s a pointer to seek address and length o f mess ∗/ void speak ( const struct t e x t ∗msg ) { char ∗s , n o n f i r s t ;

} /∗ }

prht ( ) ;

∗/

/∗ i n i t i a l o b j e c t l o c a t i o n s ∗/ s t a t i c void r l o c s ( void ) { for ( ; ; ) { i f ( ( obj = rnum ( ) ) < 0) break ; plac [ obj ] = rnum ( ) ; /∗ i n i t i a l l o c f o r t h i s obj i f ( breakch == TAB) /∗ there ’ s another entry f i x d [ obj ] = rnum ( ) ; else f i x d [ obj ] = 0; } } /∗ d e f a u l t verb messages s t a t i c void r d e f a u l t ( void ) { for ( ; ; ) { i f ( ( verb = rnum ( ) ) < 0) break ; actspeak [ verb ] = rnum ( ) ; } }

s = msg−>seekadr ; n o n f i r s t = 0; while ( s − msg−>seekadr < msg−>t x t l e n ) { /∗ read a l i n e at a time ∗/ tape = iotape ; /∗ r e s t a r t decryption tape ∗/ while ( ( ∗ s++ ˆ ∗tape ++) ! = TAB) ; /∗ read past l o c num ∗/ /∗ assume tape i s longer than l o c a t i o n number ∗/ /∗ plus the lookahead put together ∗/ i f ( ( ∗ s ˆ ∗tape ) == ’>’ && ( ∗ ( s + 1) ˆ ∗( tape + 1) ) == ’ $ ’ && ( ∗ ( s + 2) ˆ ∗( tape + 2) ) == ’ < ’) break ; i f ( b l k l i n && ! n o n f i r s t ++) putchar ( ’ \n ’ ) ; do { i f (∗ tape == 0) tape = iotape ; /∗ rewind decryp tape ∗/ putchar(∗s ˆ ∗tape ) ; } while ( ( ∗ s++ ˆ ∗tape ++) ! = LF ) ; /∗ b e t t e r end with LF ∗/ }

∗/ ∗/

∗/

/∗ l i q u i d assets &c : cond b i t s ∗/ s t a t i c void r l i q ( void ) { int bitnum ; for ( ; ; ) { /∗ read new b i t l i s t i f ( ( bitnum = rnum ( ) ) < 0) break ; for ( ; ; ) { /∗ read l o c s f o r b i t s i n t n = rnum ( ) ; i f ( n < 0) break ; cond [ n ] |= s e t b i t [ bitnum ] ; i f ( breakch == LF ) break ; } } }

}

∗/

/∗ read , decrypt and print a ptext message ∗/ /∗ msg i s the number o f a l l the p msgs f o r t h i s place ∗/ /∗ assumes o b j e c t 1 doesn ’ t have prop 1 , obj 2 no prop 2 &c ∗/ void pspeak ( i n t m, i n t skip ) { char ∗s , n o n f i r s t ; char ∗numst ; struct t e x t ∗msg; char ∗tbuf ;

∗/

msg = &ptext [m] ; i f ( ( tbuf = ( char ∗) malloc ( msg−>t x t l e n + 1) ) == NULL) e r r ( 1 , NULL) ; memcpy( tbuf , msg−>seekadr , msg−>t x t l e n + 1) ; /∗ Room to null ∗/ s = tbuf ; n o n f i r s t = 0; while ( s − tbuf < msg−>t x t l e n ) { /∗ read l i n e at a time ∗/ tape = iotape ; /∗ r e s t a r t decryption tape ∗/ f o r ( numst = s ; (∗s ˆ= ∗tape ++) ! = TAB; s ++) ; /∗ get number /∗ Temporarily trash the s t r i n g ( cringe ) ∗/ ∗s++ = 0; /∗ decrypting number within the s t r i n g

s t a t i c void rhints ( void ) { int hintnum , i ; hintmax = 0; for ( ; ; ) { i f ( ( hintnum = rnum ( ) ) < 0) break ; f o r ( i = 1; i < 5; i ++) hints [ hintnum ] [ i ] = rnum ( ) ; i f ( hintnum > hintmax ) hintmax = hintnum ; } }

∗/

i f ( a t o i ( numst ) ! = 100 ∗ skip && skip >= 0) { while ( ( ∗ s++ ˆ ∗tape ++) ! = LF ) /∗ flush the l i n e ∗/ i f (∗ tape == 0) tape = iotape ; continue ; } i f ( ( ∗ s ˆ ∗tape ) == ’>’ && ( ∗ ( s + 1) ˆ ∗( tape + 1) ) == ’ $ ’ && ( ∗ ( s + 2) ˆ ∗( tape + 2) ) == ’ < ’) break ; i f ( b l k l i n && ! n o n f i r s t ++) putchar ( ’ \n ’ ) ; do { i f (∗ tape == 0) tape = iotape ; putchar(∗s ˆ ∗tape ) ; } while ( ( ∗ s++ ˆ ∗tape ++) ! = LF ) ; /∗ b e t t e r end with LF ∗/ i f ( skip < 0) break ;

void rspeak ( i n t msg ) { i f ( msg ! = 0) speak(& r t e x t [ msg ] ) ; }

} f r e e ( tbuf ) ; }

save.c

∗/

save.c /∗

$NetBSD : save . c , v 1.14 2014/03/22 22:04:40 dholland Exp $

∗/

”Hmm. The name \”%s\” appears to be magically blocked .\n” , name) ; return NULL;

#include #ifndef l i n t #if 0 s t a t i c char sccsid [ ] = ”@( # ) save . c 8.1 ( Berkeley ) 5/31/93” ; #e l s e RCSID ( ”$NetBSD : save . c , v 1.14 2014/03/22 22:04:40 dholland Exp $” ) ; #endif #endif /∗ not l i n t ∗/ #include #include #include #include #include #include #include





#include ” hdr . h” #include ” extern . h” struct s a v e f i l e { FILE ∗f ; const char ∗name; bool warned ; s i z e t bintextpos ; uint32 t key ; struct c r c s t a t e crc ; unsigned char pad [ 8 ] ; unsigned padpos ; }; #define BINTEXT WIDTH 60 #define FORMAT VERSION 2 #define FORMAT VERSION NOSUM 1 s t a t i c const char header [ ] = ” Adventure save f i l e \n” ;

} sf−>name = name; sf−>warned = f a l s e ; sf−>bintextpos = 0; sf−>key = 0; c r c s t a r t (& sf−>crc ) ; memset ( sf−>pad , 0 , s i z e o f ( sf−>pad ) ) ; sf−>padpos = 0; return s f ; } /∗ ∗ Raw read . ∗/ static int s a v e f i l e r a w r e a d ( struct s a v e f i l e ∗sf , void ∗data , s i z e t len ) { s i z e t result ; r e s u l t = fread ( data , 1 , len , sf−>f ) ; i f ( r e s u l t ! = len || f e r r o r ( sf−>f ) ) { f p r i n t f ( stderr , ”Oops : e r r o r reading %s.\n” , sf−>name) ; sf−>warned = true ; return 1; } return 0; } /∗ ∗ Raw write . ∗/ static int s a v e f i l e r a w w r i t e ( struct s a v e f i l e ∗sf , const void ∗data , s i z e t len ) { s i z e t result ;

//////////////////////////////////////////////////////////// // base16 output encoding

r e s u l t = f w r i t e ( data , 1 , len , sf−>f ) ; i f ( r e s u l t ! = len || f e r r o r ( sf−>f ) ) { f p r i n t f ( stderr , ”Oops : e r r o r w r i t i n g %s.\n” , sf−>name) ; sf−>warned = true ; return 1; } return 0;

/∗ ∗ Map 16 plain values i n t o 90 coded values and back . ∗/ s t a t i c const char coding [ 9 0 ] = ”Db.GOyT]7 a6zpF ( c∗5H9oK˜ 0 [WVAg&kR ) ml, 2 ˆ q−1Y3v+ ” ”X/=JirZL$C> N?:}B{dfnsxUbintextpos > 0) { s a v e f i l e r a w w r i t e ( sf , ”\n” , 1) ; } r e t = 0; i f ( f c l o s e ( sf−>f ) ) { i f ( ! sf−>warned ) { f p r i n t f ( stderr , ”Oops : e r r o r on %s.\n” , sf−>name) ; } r e t = 1; } free ( sf ) ; return r e t ;

} s t a t i c char w r i t e l e t t e r ( unsigned char nibble ) { unsigned code ; assert ( nibble < 16) ; do { code = (16 ∗ ( random ( ) % 6) ) + nibble ; } while ( code >= 90) ; return coding [ code ] ; } //////////////////////////////////////////////////////////// // s a v e f i l e /∗ ∗ Open a s a v e f i l e . ∗/ s t a t i c struct s a v e f i l e ∗ s a v e f i l e o p e n ( const char ∗name, bool f o r w r i t e ) { struct s a v e f i l e ∗s f ; s f = malloc ( s i z e o f (∗ s f ) ) ; i f ( s f == NULL) { return NULL; } sf−>f = fopen ( name, f o r w r i t e ? ”w” : ” r ” ) ; i f ( sf−>f == NULL) { free ( sf ) ; f p r i n t f ( stderr ,

21

} /∗ ∗ Read encoded binary data , discarding any whitespace that appears . ∗/ static int s a v e f i l e b i n t e x t r e a d ( struct s a v e f i l e ∗sf , void ∗data , s i z e t len ) { s i z e t pos ; unsigned char ∗udata ; i n t ch ; udata pos = while ch if

= data ; 0; ( pos < len ) { = f g e t c ( sf−>f ) ; ( ch == EOF || f e r r o r ( sf−>f ) ) { f p r i n t f ( stderr , ”Oops : e r r o r reading %s.\n” , sf−>name) ; sf−>warned = true ; return 1;

} i f ( ch == ’ ’ || ch == ’\ t ’ || ch == ’\ r ’ || ch == ’\n ’ ) { continue ; } udata [ pos ++] = ch ;

22

Foundations of Videogame Programming Code Repository

} return 0;

return 1; } return 0;

} } /∗ ∗ Read binary data , decoding from t e x t using r e a d l e t t e r ( ) . ∗/ static int s a v e f i l e b i n r e a d ( struct s a v e f i l e ∗sf , void ∗data , s i z e t len ) { unsigned char buf [ 6 4 ] ; unsigned char ∗udata ; unsigned char val1 , val2 ; s i z e t pos , amt , i ; udata = data ; pos = 0; while ( pos < len ) { amt = len − pos ; i f ( amt > s i z e o f ( buf ) / 2) { amt = s i z e o f ( buf ) / 2; } i f ( s a v e f i l e b i n t e x t r e a d ( sf , buf , amt∗2) ) { return 1; } f o r ( i =0; ibintextpos ; i f ( amt > len − pos ) { amt = len − pos ; } i f ( s a v e f i l e r a w w r i t e ( sf , udata + pos , amt ) ) { return 1; } pos += amt ; sf−>bintextpos += amt ; i f ( sf−>bintextpos >= BINTEXT WIDTH ) { s a v e f i l e r a w w r i t e ( sf , ”\n” , 1) ; sf−>bintextpos = 0; } } return 0;

udata = data ; pos = 0; bpos = 0; while ( pos < len ) { byte = udata [ pos + + ] ; buf [ bpos++] = w r i t e l e t t e r ( byte >> 4) ; buf [ bpos++] = w r i t e l e t t e r ( byte & 0x f ) ; i f ( bpos >= s i z e o f ( buf ) ) { i f ( s a v e f i l e b i n t e x t w r i t e ( sf , buf , bpos ) ) { return 1; } bpos = 0; } } i f ( s a v e f i l e b i n t e x t w r i t e ( sf , buf , bpos ) ) {

∗uval ;

uval = ( unsigned char ∗)&v a l ; valpos = 0; f o r ( i =0; i= s i z e o f ( v a l ) ) { valpos = 0; } } } /∗ ∗ Set the ” encryption ” key . ∗/ s t a t i c void s a v e f i l e k e y ( struct s a v e f i l e ∗sf , uint32 t key ) { sf−>key = 0; c r c s t a r t (& sf−>crc ) ; hash(& sf−>key , s i z e o f ( sf−>key ) , sf−>pad , s i z e o f ( sf−>pad ) ) ; sf−>padpos = 0; } /∗ ∗ Get an ” encryption ” pad byte . This forms a stream ” cipher ” that we ∗ xor with the p l a i n t e x t save data . ∗/ s t a t i c unsigned char s a v e f i l e g e t p a d ( struct s a v e f i l e ∗s f ) { unsigned char r e t ; r e t = sf−>pad [ sf−>padpos + + ] ; i f ( sf−>padpos >= s i z e o f ( sf−>pad ) ) { hash ( sf−>pad , s i z e o f ( sf−>pad ) , sf−>pad , s i z e o f ( sf−>pad ) ) ; sf−>padpos = 0; } return r e t ;

} /∗ ∗ Write binary data , encoding as t e x t using w r i t e l e t t e r ( ) . ∗/ static int s a v e f i l e b i n w r i t e ( struct s a v e f i l e ∗sf , const void ∗data , s i z e t len ) { unsigned char buf [ 6 4 ] ; const unsigned char ∗udata ; s i z e t pos , bpos ; unsigned char byte ;

s i z e t datalen , unsigned char ∗out , s i z e t outlen ) ∗udata ;

udata = data ; v a l = 0; f o r ( i =0; i 60) ; v a l += udata [ i ] ˆ 0xbeefU ; }

} /∗ ∗ Write encoded binary data , i n s e r t i n g newlines to get a neatly ∗ formatted block . ∗/ static int s a v e f i l e b i n t e x t w r i t e ( struct s a v e f i l e ∗sf , const void ∗data , s i z e t len ) { s i z e t pos , amt ; const unsigned char ∗udata ;

buf [ 0 . . buflen ] . Note : buf and outhash may overlap .

} /∗ ∗ Read ” encrypted ” data . ∗/ static int s a v e f i l e c r e a d ( struct s a v e f i l e ∗sf , void ∗data , s i z e t len ) { char buf [ 6 4 ] ; unsigned char ∗udata ; s i z e t pos , amt , i ; unsigned char ch ; udata = data ; pos = 0; while ( pos < len ) { amt = len − pos ; i f ( amt > s i z e o f ( buf ) ) { amt = s i z e o f ( buf ) ; } i f ( s a v e f i l e b i n r e a d ( sf , buf , amt ) ) { return 1; } f o r ( i =0; icrc , data , len ) ; return 0; } /∗ ∗ Write ” encrypted ” data . ∗/ static int s a v e f i l e c w r i t e ( struct s a v e f i l e ∗sf , const void ∗data , s i z e t len ) { char buf [ 6 4 ] ; const unsigned char ∗udata ; s i z e t pos , amt , i ; unsigned char ch ;

{NULL, 0} };

udata = data ; pos = 0; while ( pos < len ) { amt = len − pos ; i f ( amt > s i z e o f ( buf ) ) { amt = s i z e o f ( buf ) ; } f o r ( i =0; icrc , data , len ) ; return 0;

static int compat restore ( const char ∗ i n f i l e ) { FILE ∗in ; const struct compat saveinfo ∗p ; char ∗s ; long sum, cksum = 0; size t i ; struct c r c s t a t e crc ; i f ( ( in = fopen ( i n f i l e , ” rb ” ) ) == NULL) { f p r i n t f ( stderr , ”Hmm. The f i l e \”%s\” appears to be magically blocked .\n” , infile ) ; return 1; } fread (&sum, s i z e o f (sum) , 1 , in ) ; /∗ Get the seed ∗/ srandom ( ( i n t ) sum) ; f o r ( p = compat savearray ; p−>address ! = NULL; p++) { fread ( p−>address , p−>width , 1 , in ) ; f o r ( s = p−>address , i = 0; i < p−>width ; i ++ , s ++) ∗s = (∗s ˆ random ( ) ) & 0xFF ; /∗ L i g h t l y decrypt ∗/ } f c l o s e ( in ) ;

} //////////////////////////////////////////////////////////// // compat f o r old save f i l e s struct compat saveinfo { void ∗address ; s i z e t width ; }; s t a t i c const struct compat saveinfo compat savearray [ ] = { {&abbnum, s i z e o f (abbnum) }, {&attack , s i z e o f ( attack ) }, {&b l k l i n , s i z e o f ( b l k l i n ) }, {&bonus , s i z e o f ( bonus ) }, {&chloc , s i z e o f ( chloc ) }, {&chloc2 , s i z e o f ( chloc2 ) }, {&clock1 , s i z e o f ( clock1 ) }, {&clock2 , s i z e o f ( clock2 ) }, {&closed , s i z e o f ( closed ) }, {&i s c l o s i n g , s i z e o f ( i s c l o s i n g ) }, {&d a l t l o c , s i z e o f ( d a l t l o c ) }, {&demo, s i z e o f ( demo ) }, {&d e t a i l , s i z e o f ( d e t a i l ) }, {&dflag , s i z e o f ( d f l a g ) }, {&d k i l l , s i z e o f ( d k i l l ) }, {&dtotal , s i z e o f ( d t o t a l ) }, {&foobar , s i z e o f ( foobar ) }, {&gaveup , s i z e o f ( gaveup ) }, {&holding , s i z e o f ( holding ) }, {&iwest , s i z e o f ( iwest ) }, {&k , s i z e o f ( k ) }, {&k2 , s i z e o f ( k2 ) }, {&knfloc , s i z e o f ( knfloc ) }, {&kq , s i z e o f ( kq ) }, {&latency , s i z e o f ( latency ) }, {&l i m i t , s i z e o f ( l i m i t ) }, {&lmwarn , s i z e o f ( lmwarn ) }, {&loc , s i z e o f ( l o c ) }, {&maxdie , s i z e o f ( maxdie ) }, {&maxscore , s i z e o f ( maxscore ) }, {&newloc , s i z e o f ( newloc ) }, {&numdie , s i z e o f ( numdie ) }, {&obj , s i z e o f ( obj ) }, {&oldloc2 , s i z e o f ( oldloc2 ) }, {&oldloc , s i z e o f ( o l d l o c ) }, {&panic , s i z e o f ( panic ) }, {&saveday , s i z e o f ( saveday ) }, {&savet , s i z e o f ( savet ) }, {&scoring , s i z e o f ( scoring ) }, {&spk , s i z e o f ( spk ) }, {&stick , s i z e o f ( s t i c k ) }, {&t a l l y , s i z e o f ( t a l l y ) }, {&t a l l y 2 , s i z e o f ( t a l l y 2 ) },

c r c s t a r t (& crc ) ; /∗ See i f she cheated ∗/ f o r ( p = compat savearray ; p−>address ! = NULL; p++) crc add (&crc , p−>address , p−>width ) ; cksum = c r c g e t (& crc ) ; i f (sum ! = cksum ) /∗ Tsk tsk ∗/ return 2; /∗ Altered the f i l e ∗/ /∗ We successfully restored , so t h i s r e a l l y was a save f i l e ∗/ /∗ ∗ The above code loads these from disk even though they ’ re ∗ pointers . Null them out and hope we don ’ t crash on them ∗ l a t e r ; that ’ s b e t t e r than having them be garbage . ∗/ tkk = NULL; wd1 = NULL; wd2 = NULL; return 0; } //////////////////////////////////////////////////////////// // save + r e s t o r e s t a t i c i n t ∗const s a v e i n t s [ ] = { &abbnum, &attack , &b l k l i n , &bonus , &chloc , &chloc2 , &clock1 , &clock2 , &closed , &i s c l o s i n g , &d a l t l o c , &demo, &d e t a i l , &dflag , &d k i l l , &dtotal , &foobar , &gaveup , &holding , &iwest , &k , &k2 , &knfloc , &kq ,

24

Foundations of Videogame Programming Code Repository

&latency , &l i m i t , &lmwarn , &loc , &maxdie , &maxscore , &newloc , &numdie , &obj , &oldloc2 , &oldloc , &panic , &saveday , &savet , &scoring , &spk , &stick , &t a l l y , &t a l l y 2 , &turns , &verb , &wasdark , &yea ,

return 1; } /∗ other parts o f the code may depend on us doing t h i s here ∗/ srandom ( key ) ; s a v e f i l e k e y ( sf , key ) ; /∗ ∗ Integers ∗/ f o r ( i =0; i= 15) || ( dloc [ i ] == l o c || odloc [ i ] == l o c ) ; i f ( ! dseen [ i ] ) continue ; /∗ i . e . goto 6030 ∗/ dloc [ i ] = l o c ; i f ( i == 6) { /∗ pirate ’ s spotted him ∗/ i f ( l o c == chloc || prop [ chest ] >= 0) continue ; k = 0; f o r ( j = 50; j tverb ; /∗ k back to verb tkk = t r a v e l [ l o c ] ; return ( 9 ) ; } i f ( l l t l o c ) tk2 = tkk ; }

∗/

∗/

} tkk = tk2 ; /∗ 23 i f ( tkk ! = 0) { k = tkk−>tverb ; tkk = t r a v e l [ l o c ] ; return ( 9 ) ; } rspeak (140) ; return ( 2 ) ;

∗/

∗/

∗/

} /∗ 30000 ∗/ static int s p e c i a l s ( void ) { switch ( newloc −= 300) { case 1: /∗ 30100 ∗/ newloc = 99 + 100 − l o c ; i f ( holding == 0 || ( holding == 1 && t o t i n g ( emerald ) ) ) return ( 2 ) ; newloc = l o c ; rspeak (117) ; return ( 2 ) ; case 2: /∗ 30200 ∗/ drop ( emerald , l o c ) ; return ( 1 2 ) ; case 3: /∗ to 30300 ∗/ return ( t r b r i d g e ( ) ) ; default : bug ( 2 9 ) ; } }

l9 : f o r ( ; tkk ! = 0; tkk = tkk−>next ) i f ( tkk−>tverb == 1 || tkk−>tverb == k ) break ; i f ( tkk == 0) { badmove ( ) ; return ( 2 ) ; } l11 : l l 1 = tkk−>conditions ; /∗ 11 ∗/ l l 2 = tkk−>t l o c ; newloc = l l 1 ; /∗ newloc=conditions ∗/ k = newloc % 100; /∗ k used f o r prob ∗/ i f ( newloc conditions ! = l l 1 ) break ; i f ( tkk == 0) bug ( 2 5 ) ; goto l11 ; } /∗ 20 ∗/ static int mback ( void ) { struct t r a v l i s t ∗tk2 , ∗j ; int ll ; i f ( forced ( k = o l d l o c ) ) k = oldloc2 ; /∗ k= l o c a t i o n oldloc2 = o l d l o c ; oldloc = loc ; tk2 = 0; i f ( k == l o c ) { rspeak ( 9 1 ) ; return ( 2 ) ; } f o r ( ; tkk ! = 0; tkk = tkk−>next ) { l l = tkk−>t l o c ;

27

/∗ 30300 ∗/ static int t r b r i d g e ( void ) { i f ( prop [ t r o l l ] == 1) { pspeak ( t r o l l , 1) ; prop [ t r o l l ] = 0; move ( t r o l l 2 , 0) ; move ( t r o l l 2 + 100, 0) ; move ( t r o l l , plac [ t r o l l ] ) ; move ( t r o l l + 100, f i x d [ t r o l l ] ) ; j u g g l e ( chasm ) ; newloc = l o c ; return ( 2 ) ; } newloc = plac [ t r o l l ] + f i x d [ t r o l l ] − l o c ; i f ( prop [ t r o l l ] == 0) prop [ t r o l l ] = 1; i f ( ! t o t i n g ( bear ) ) return ( 2 ) ; rspeak (162) ; prop [ chasm ] = 1; prop [ t r o l l ] = 2; drop ( bear , newloc ) ; f i x e d [ bear ] = −1; prop [ bear ] = 3; i f ( prop [ spices ] < 0) t a l l y 2 ++; oldloc2 = newloc ; return ( 9 9 ) ; }

∗/

/∗ 21

∗/

/∗ 20 ∗/ s t a t i c void badmove ( void ) { spk = 12; i f ( k >= 43 && k 100) return (8000) ; i f ( obj == 0) { i f ( here ( bird ) && verb ! = throw ) obj = bird ; i f ( here ( clam ) || here ( oyster ) ) obj = 100 ∗ obj + clam ; i f ( obj > 100) return (8000) ; } } i f ( obj == bird ) { /∗ 9124 ∗/ spk = 137; i f ( closed ) return (2011) ; destroy ( bird ) ; prop [ bird ] = 0; i f ( place [ snake ] == plac [ snake ] ) t a l l y 2 ++; spk = 45; } i f ( obj == 0) spk = 44; /∗ 9125 ∗/ i f ( obj == clam || obj == oyster ) spk = 150; i f ( obj == snake ) spk = 46; i f ( obj == dwarf ) spk = 49; i f ( obj == dwarf && closed ) return (19000) ; i f ( obj == dragon ) spk = 147; i f ( obj == t r o l l ) spk = 157; i f ( obj == bear ) spk = 165 + ( prop [ bear ] + 1) / 2; i f ( obj ! = dragon || prop [ dragon ] ! = 0) return (2011) ; rspeak ( 4 9 ) ; verb = 0; obj = 0; g e t i n (&wd1, &wd2) ; i f ( ! weq ( wd1, ” y ” ) && ! weq ( wd1, ” yes ” ) ) return (2608) ; pspeak ( dragon , 1) ; prop [ dragon ] = 2; prop [ rug ] = 0; k = ( plac [ dragon ] + f i x d [ dragon ] ) / 2; move ( dragon + 100, −1) ; move ( rug + 100, 0) ; move ( dragon , k ) ; move ( rug , k ) ; f o r ( obj = 1; obj = 50 && obj atab ; ∗s ; ) ∗t ++ = ∗s++ ˆ ’ = ’ ; ∗t = 0 ˆ ’ = ’ ; /∗ encrypt s l i g h t l y to thwart core reader ∗/ /∗ printf ( ” Stored \”%s\” (%d ch ) as entry %d\n” , ∗/ /∗ word , length ( word ) , adr ) ; ∗/ return ( 0 ) ; /∗ entry unused ∗/ case −1: /∗ looking up user word ∗/ i f ( h−>v a l == 0) return (−1) ; /∗ not found ∗/ f o r ( s = word , t = h−>atab ; ∗t ˆ ’ = ’ ; ) i f ( ( ∗ s++ ˆ ’ = ’ ) ! = ∗t ++) goto exitloop2 ; i f ( ( ∗ s ˆ ’ = ’ ) ! = ∗t && s − word < 5) goto exitloop2 ; /∗ the word matched o . k . ∗/ return ( h−>v a l ) ; default : /∗ looking up known word ∗/ i f ( h−>v a l == 0) errx ( 1 , ” Unable to f i n d %s in vocab ” , word ) ; f o r ( s = word , t = h−>atab ; ∗t ˆ ’ = ’ ; ) i f ( ( ∗ s++ ˆ ’ = ’ ) ! = ∗t ++) goto exitloop2 ; /∗ the word matched o . k . ∗/ i f ( h−>v a l / 1000 ! = type ) continue ; return ( h−>v a l % 1000) ; } exitloop2 : /∗ hashed entry does not match i f ( adr + 1 == hash || hash == 0) errx ( 1 , ”Hash t a b l e overflow ” ) ; } } /∗ print hash t a b l e ( f o r debugging ) static unused void prht ( void ) { int i, j, l; char ∗c ; struct hashtab ∗h ; f o r ( i = 0; i < HTSIZE / 10 + 1; i ++) { printf ( ”%4d” , i ∗ 10) ; f o r ( j = 0; j < 10; j ++) { i f ( i ∗ 10 + j >= HTSIZE ) break ; h = &voc [ i ∗ 10 + j ] ; putchar ( ’ ’ ) ; i f ( h−>v a l == 0) { printf ( ”−−−−−” ) ; continue ;

∗/

∗/

∗/

32

Foundations of Videogame Programming Code Repository } f o r ( l = 0 , c = h−>atab ; l < 5; l ++) i f ((∗ c ˆ ’ = ’ ) ) putchar(∗c++ ˆ ’ = ’ ) ; else

putchar ( ’ } putchar ( ’ \n ’ ) ;

’) ;

} }

wizard.c /∗

$NetBSD : wizard . c , v 1.16 2012/10/12 15:41:10 dholland Exp $

∗/

delay , delay == 1 ? ” ” : ” s ” ) ; i f ( delay tm yday + 365 ∗ ( tptr−>tm year − 77) + ( tptr−>tm year − 77) / 4 − ( tptr−>tm year − 1) / 100 + ( tptr−>tm year + 299) / 400) ; /∗ bug : t h i s w i l l overflow in the year 2066 AD ( with 16 b i t i n t ) ∗/ /∗ i t w i l l be a t t r i b u t e d to Wm the C’ s m i l l e n i a l c e l e b r a t i o n ∗/ /∗ and minutes since midnite ∗/ ∗t = tptr−>tm hour ∗ 60 + tptr−>tm min ; /∗ p r e t t y painless ∗/

} /∗ not as complex as advent/10 ( f o r now ) static int wizard ( void ) { char ∗word , ∗x ; i f ( ! yesm(16 , 0 , 7) ) return ( FALSE ) ; mspeak( 1 7 ) ; g e t i n (&word , &x ) ; i f ( ! weq ( word , magic ) ) { mspeak( 2 0 ) ; return ( FALSE ) ; } mspeak( 1 9 ) ; return (TRUE) ; } void ciao ( void ) { char fname [ 8 0 ] ; s i z e t pos ; printf ( ”What would you l i k e to c a l l the saved version?\n” ) ; /∗ XXX − should use f g e t l n to avoid a r b i t r a r y l i m i t ∗/ f o r ( pos = 0; pos < s i z e o f ( fname ) − 1; pos ++) { i n t ch ; ch = getchar ( ) ; i f ( ch == ’\n ’ || ch == EOF) break ; fname [ pos ] = ch ; } fname [ pos ] = ’ \ 0 ’ ; i f ( save ( fname ) ! = 0) return ; /∗ Save f a i l e d ∗/ printf ( ” To resume , say \” adventure %s\” .\n” , fname ) ; printf ( ”\” With these rooms I might now have been f a m i l i a r l y ” ) ; p r i n t f ( ” acquainted .\ ”\n” ) ; exit ( 0 ) ;

s t a t i c char magic [ 6 ] ; void poof ( void ) { strcpy ( magic , DECR( ’ d ’ , latency = 45; }

’w’ ,

’a ’ ,

’r ’ ,

’f ’) ) ;

int Start ( void ) { int d , t , delay ; datime(&d , &t ) ; delay = ( d − saveday ) ∗ 1440 + ( t − savet ) ; ∗ month ∗/

}

/∗ good f o r about a

i f ( delay >= latency ) { saved = −1; return ( FALSE ) ; } printf ( ” This adventure was suspended a mere %d minute%s ago . ” ,

done.c

∗/

int ran ( i n t range ) { long i; i = rand ( ) % range ; return ( i ) ; }

hdr.h /∗

$NetBSD : done . c , v 1.10 2009/08/25 06:56:52 dholland Exp $

∗/

#include #ifndef l i n t #if 0 s t a t i c char sccsid [ ] = ”@( # ) done . c 8.1 ( Berkeley ) 5/31/93” ; #e l s e RCSID ( ”$NetBSD : done . c , v 1.10 2009/08/25 06:56:52 dholland Exp $” ) ; #endif #endif /∗ not l i n t ∗/ /∗

Re−coding o f advent in C: termination routines ∗/

#include #include #include #include

” hdr . h” ” extern . h”

int score ( void ) { /∗ s o r t o f l i k e 20000 ∗/ int myscore , i ; maxscore = myscore = 0; f o r ( i = 50; i chest ) k = 16; i f ( prop [ i ] >= 0) myscore += 2; i f ( place [ i ] == 3 && prop [ i ] == 0) myscore += k − 2; maxscore += k ; } myscore += ( maxdie − numdie ) ∗ 10; maxscore += maxdie ∗ 10; i f ( ! ( scoring || gaveup ) ) myscore += 4; maxscore += 4; i f ( d f l a g ! = 0) myscore += 25; maxscore += 25; if ( isclosing ) myscore += 25; maxscore += 25; i f ( closed ) { i f ( bonus == 0) myscore += 10; i f ( bonus == 135) myscore += 25; i f ( bonus == 134) myscore += 30; i f ( bonus == 133) myscore += 45; } maxscore += 45; i f ( place [ magazine ] == 108) myscore++; maxscore++; myscore += 2; maxscore += 2; f o r ( i = 1; i = 1; i−−) { i f ( ! toting ( i ) ) continue ; k = oldloc2 ; i f ( i == lamp ) k = 1; drop ( i , k ) ; } l o c = 3; oldloc = loc ; }

hdr.h /∗

$NetBSD : hdr . h , v 1.13 2009/08/25 06:56:52 dholland Exp $

∗/

/∗ hdr . h : included by c advent f i l e s ∗/ #include extern v o l a t i l e s i g a t o m i c t d e l h i t ; extern i n t yea ; extern char d a t a f i l e [ ] ; /∗ V i r t u a l data f i l e ∗/ #define TAB 011 #define LF 012 #define FLUSHLINE do { i n t f l u s h l i n e c h ; while ( ( f l u s h l i n e c h = getchar ( ) ) != EOF && f l u s h l i n e c h != ’\n ’ ) ; } while ( 0 )

#define FLUSHLF extern extern extern extern extern

while ( next ( ) !=LF )

int loc , newloc , oldloc , oldloc2 , wasdark , gaveup , kq , k , k2 ; char ∗wd1, ∗wd2; /∗ the complete words ∗/ int verb , obj , spk ; int blklin ; int saveday , savet , maxscore , latency ;

#define SHORT 50 #define MAXSTR

/∗ How short i s a demo game? ∗/

20

#define HTSIZE 512 extern struct hashtab {

/∗ max length o f user ’ s words ∗/ /∗ max number o f vocab words ∗/ /∗ hash t a b l e f o r vocabulary ∗/

34

Foundations of Videogame Programming Code Repository

int val ; /∗ word type &index ( ktab ) ∗/ char ∗atab ; /∗ pointer to actual s t r i n g ∗/ } voc [ HTSIZE ] ; #define SEED 1815622 /∗ ” Encryption ” seed ∗/

int int

extern extern extern

int int int

hintmax ; hints [ 2 0 ] [ 5 ] ; /∗ i n f o on hints ∗/ hinted [ 2 0 ] , h i n t l c [ 2 0 ] ;

extern extern

int int

place [ 1 0 1 ] , prop [ 1 0 1 ] , l i n k s [ 2 0 1 ] ; abb [ LOCSIZE ] ;

/∗ random t e x t messages ∗/

extern

int

/∗ magic messages ∗/

#define FALSE #define TRUE

struct t e x t { char ∗seekadr;/∗ Msg s t a r t in v i r t u a l disk ∗/ int txtlen ; /∗ length o f msg s t a r t i n g here ∗/ }; #define RTXSIZE 205 extern struct t e x t r t e x t [ RTXSIZE ] ; #define MAGSIZE 35 extern struct t e x t mtext [MAGSIZE ] ;

extern

extern int classes ; #define CLSMAX 12 extern struct t e x t c t e x t [CLSMAX] ; extern int cval [CLSMAX] ; extern

/∗ classes o f adventurer ∗/

/∗ o b j e c t descriptions ∗/

struct t e x t ptext [ 1 0 1 ] ;

/∗ various condition b i t s ∗/

extern extern

#define LOCSIZE 141 /∗ number o f l o c a t i o n s ∗/ extern struct t e x t l t e x t [ LOCSIZE ] ; /∗ long l o c description ∗/ extern struct t e x t s t e x t [ LOCSIZE ] ; /∗ short l o c descriptions ∗/ extern struct t r a v l i s t { /∗ direcs & conditions o f t r a v e l ∗/ struct t r a v l i s t ∗next ; /∗ ptr to next l i s t entry ∗/ int conditions ; /∗ m in writeup ( newloc / 1000) ∗/ int tloc ; /∗ n in writeup ( newloc % 1000) ∗/ int tverb ; /∗ the verb that takes you there ∗/ } ∗t r a v e l [ LOCSIZE ] , ∗tkk ; /∗ t r a v e l i s c l o s e r to keys ( . . . ) ∗/ extern

int

a t l o c [ LOCSIZE ] ;

extern extern

int int

plac [ 1 0 1 ] ; /∗ i n i t i a l o b j e c t placement ∗/ fixd [101] , fixed [101]; /∗ l o c a t i o n f i x e d ? ∗/

extern

int

actspeak [ 3 5 ] ;

extern

extern extern

cond [ LOCSIZE ] ; setbit [16];

/∗ b i t defn masks 1 , 2 , 4 , . . . ∗/

maxtrs , t a l l y , t a l l y 2 ;

/∗ treasure values ∗/

0 1

int keys , lamp , grate , cage , rod , rod2 , steps , /∗ mnemonics ∗/ bird , door , pillow , snake , f i s s u r e , t a b l e t , clam , oyster , magazine , dwarf , knife , food , b o t t l e , water , o i l , plant , plant2 , axe , mirror , dragon , chasm, t r o l l , t r o l l 2 , bear , message , vend , batter , nugget , coins , chest , eggs , t r i d e n t , vase , emerald , pyramid , pearl , rug , chain , spices , back , look , cave , null , entrance , depression , /∗enter , stream , pour,∗/ say , lock , throw , find , invent ; int chloc , chloc2 , dseen [ 7 ] , dloc [ 7 ] , odloc [ 7 ] , dflag , d a l t l o c ; int int and

/∗ dwarf s t u f f ∗/

tk [ 2 1 ] , stick , dtotal , attack ; turns , lmwarn , iwest , knfloc , d e t a i l ,

/∗ various f l a g s

∗ counters ∗/ abbnum, maxdie , numdie , holding , d k i l l , foobar , bonus , clock1 , clock2 , saved , i s c l o s i n g , panic , closed , scoring ; extern

int

demo, l i m i t ;

/∗ r t e x t msg f o r verb ∗/ #define DECR( a , b , c , d , e ) decr ( a+ ’ + ’ , b+’−’, c + ’ # ’ ,d+ ’& ’ , e + ’% ’)

extern.h /∗

$NetBSD : extern . h , v 1.16 2012/01/08 18:17:41 dholland Exp $

#include #include /∗ crc . c ∗/ struct c r c s t a t e { uint32 t c r c v a l ; unsigned step ; }; void c r c s t a r t ( struct c r c s t a t e ∗) ; void crc add ( struct c r c s t a t e ∗, const void ∗, s i z e t ) ; uint32 t c r c g e t ( struct c r c s t a t e ∗) ; /∗ done . c ∗/ i n t score ( void ) ; void done ( i n t ) dead ; void die ( i n t ) ; /∗ i n i t . c ∗/ void i n i t ( void ) ; char ∗decr ( int , int , int , int , i n t ) ; void trapdel ( i n t ) ; void startup ( void ) ; /∗ i o . c ∗/ void g e t i n ( char ∗∗, char ∗∗) ; i n t yes ( int , int , i n t ) ; i n t yesm ( int , int , i n t ) ; void rdata ( void ) ; # i f d e f DEBUG void t w r i t e ( i n t ) ; #endif void rspeak ( i n t ) ; void mspeak ( i n t ) ; struct t e x t ; void speak ( const struct t e x t ∗) ; void pspeak ( int , i n t ) ; /∗ save . c ∗/ i n t save ( const char ∗) ; i n t r e s t o r e ( const char ∗) ;

∗/

/∗ subr . c ∗/ int toting ( int ) ; i n t here ( i n t ) ; i n t at ( i n t ) ; i n t l i q ( void ) ; int liqloc ( int ) ; i n t forced ( i n t ) ; i n t dark ( void ) ; i n t pct ( i n t ) ; i n t fdwarf ( void ) ; i n t march ( void ) ; dead ; void bug ( i n t ) void checkhints ( void ) ; i n t trsay ( void ) ; i n t trtake ( void ) ; i n t trdrop ( void ) ; i n t tropen ( void ) ; i n t t r k i l l ( void ) ; i n t t r t o s s ( void ) ; i n t t r f e e d ( void ) ; i n t t r f i l l ( void ) ; void c l o s i n g ( void ) ; void caveclose ( void ) ; /∗ vocab . c ∗/ void destroy ( i n t ) ; void j u g g l e ( i n t ) ; void move ( int , i n t ) ; i n t put ( int , int , i n t ) ; void carry ( int , i n t ) ; void drop ( int , i n t ) ; i n t vocab ( const char ∗, int , i n t ) ; /∗ These three used to be functions in vocab . c ∗/ #define copystr ( src , dest ) strcpy ( ( dest ) , ( src ) ) #define weq ( str1 , s t r 2 ) ( ! strncmp ( ( s t r 1 ) , ( s t r 2 ) , 5 ) ) #define length ( s t r ) ( strlen ( ( str ) ) + 1) /∗ wizard . c ∗/ void datime ( i n t ∗, i n t ∗) ; void poof ( void ) ; i n t Start ( void ) ; void ciao ( void ) ; i n t ran ( i n t ) ;

adventure.6

35

adventure.6 .\ ” .\ ” .\ ” .\ ” .Dd . Dt . Os . Sh .Nm .Nd . Sh .Nm

$NetBSD : adventure . 6 , v 1.4 2003/08/07 09:36:50 agc Exp $ @( # ) adventure .6 8.1 ( Berkeley ) 5/31/93 May 31, 1993 ADVENTURE 6 NAME adventure an exploration game SYNOPSIS

.Op saved−f i l e . Sh DESCRIPTION The o b j e c t o f the game i s to l o c a t e and explore Colossal Cave , f i n d the treasures hidden there , and bring them back to the building with you . The program i s s e l f−d e s c r i p t i v e to a point , but part o f the game i s to discover i t s rules . . Pp To terminate a game, ente