changeset 0:62966dd383ed default tip

initial
author Radomir Dopieralski <sheep-devel@sheep.art.pl>
date Sun, 08 Dec 2013 19:39:15 +0100
parents
children
files config.pas console.pas creature.pas editcfg/items.cfg editcfg/keys.cfg editcfg/levels.cfg editcfg/main.cfg editcfg/messages.cfg editcfg/monsters.cfg editcfg/rooms.cfg editcfg/tiles.cfg global.pas items.pas level.pas light.pas maps.pas parser.pas player.pas porting.pas r.pas save.pas
diffstat 21 files changed, 4445 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,435 @@
+{ Configuration reading routines. }
+
+UNIT Config;
+
+INTERFACE
+
+PROCEDURE ReadCfg;
+
+IMPLEMENTATION
+
+USES Global, Console, Parser, Porting;
+
+PROCEDURE ParseError;
+BEGIN
+        Txt(Concat('@rParse error at line @R',Num(actLine),'@r.'));
+        CASE errNum OF
+                PARSE_ERR_EOF: Txt('@RUnexpected end of file!');
+                PARSE_ERR_NAM: Txt('@RVariable name expected!');
+                PARSE_ERR_STR: Txt('@RString constant expected!');
+                PARSE_ERR_NUM: Txt('@RNumeric constant expected!');
+                PARSE_ERR_OPN: Txt('@RCan''t open/close file!');
+                ELSE Txt('@RUnknown error!');
+        END;
+	Msg('Press any key...');
+	GetKey;
+	ResetScr;
+	Halt(1);
+END;
+
+
+PROCEDURE ReadCfg;
+VAR tmpLine: WORD;
+
+
+PROCEDURE ReadMonsters(filename:STRING);
+VAR     f: CfgFile;
+        n: STRING;
+        i: BYTE;
+        p: CreatDef;
+
+BEGIN
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+        monsterlist:=NIL;
+        p:=NIL;
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='MONSTER' THEN BEGIN
+                        New(p);
+                        i:=ReadNumber(f);
+                        p^.id:=i;
+                        p^.nam:='';
+			p^.hp:=100;
+			p^.spd:=100;
+			p^.next:=monsterlist;
+			monsterlist:=p;
+                END ELSE
+                IF n='NAME'     THEN p^.nam:=ReadString(f) ELSE
+                IF n='HPMAX'     THEN p^.hp:=ReadNumber(f) ELSE
+                IF n='SPEED'     THEN p^.spd:=ReadNumber(f) ELSE		
+                IF n='LOOKS' THEN BEGIN
+                        n:=ReadString(f);
+                        p^.chr:=n[1];
+                        p^.atr:=ReadNumber(f);
+                END ELSE
+			BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+		IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+PROCEDURE ReadItems(filename:STRING);
+VAR     f: CfgFile;
+        n: STRING;
+        i: BYTE;
+        p: ItemDef;
+
+BEGIN
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+        itemlist:=NIL;
+        p:=NIL;
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='ITEM'     THEN BEGIN
+                        New(p);
+                        i:=ReadNumber(f);
+                        p^.id:=i;
+                        p^.flg:=[];
+                        p^.dsc:=' ';
+                        p^.unk:=i;
+                        p^.qnt:=1;
+                        p^.eqp:=0;
+			p^.wgt:=1;
+                        p^.next:=itemlist;
+                        itemlist:=p;
+                END ELSE
+                IF n='NAME'     THEN p^.nam:=ReadString(f) ELSE
+                IF n='DESC'     THEN p^.dsc:=ReadString(f) ELSE
+                IF n='LOOKS'    THEN BEGIN
+                        n:=ReadString(f);
+                        p^.chr:=n[1];
+                        p^.atr:=ReadNumber(f);
+                END ELSE
+                IF n='EQUIP'    THEN p^.eqp:=ReadNumber(f) ELSE
+                IF n='WEIGHT'   THEN p^.wgt:=ReadNumber(f) ELSE		
+                IF n='QUANTITY' THEN p^.qnt:=ReadNumber(f) ELSE
+                IF n='UNKNOWN'  THEN p^.unk:=ReadNumber(f) ELSE
+                IF n='MULTIPLE' THEN p^.flg:=p^.flg+[ITEM_MULTIPLE] ELSE
+                IF n='KNOWN'    THEN p^.flg:=p^.flg+[ITEM_KNOWN] ELSE
+                IF n='EMPTY'    THEN p^.flg:=p^.flg+[ITEM_EMPTY] ELSE
+                        BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+
+PROCEDURE ReadLevels(filename:STRING);
+VAR     f: CfgFile;
+        n: STRING;
+        x,y: INTEGER;
+        p: pLevel;
+        place: INTEGER;
+BEGIN
+
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+        place:=1;
+        levellist:=NIL;
+
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='LEVEL' THEN BEGIN
+                        New(p);
+                        p^.id:=ReadNumber(f);
+                        p^.erosion:=0;
+                        p^.next:=levellist;
+                        FOR x:=1 TO MAXROOMS DO BEGIN
+                                p^.rooms[x].rom:=0;
+                                p^.rooms[x].qnt:=255;
+                                p^.rooms[x].dor:=0;
+                                FOR y:=1 TO MAXROOMS DO p^.rooms[x].con[y]:=0;
+                        END;
+                        levellist:=p;
+                END ELSE
+                IF n='NAME' THEN p^.name:=ReadString(f) ELSE
+                IF n='ROOM' THEN BEGIN
+                        place:=ReadNumber(f);
+                        IF (place>MAXROOMS) OR (place<1) THEN place:=MAXROOMS;
+                        p^.rooms[place].rom:=ReadNumber(f);
+                END ELSE
+                IF n='DOOR' THEN p^.rooms[place].dor:=ReadNumber(f) ELSE
+                IF n='QUANTITY' THEN p^.rooms[place].qnt:=ReadNumber(f) ELSE
+                IF n='CONNECT' THEN BEGIN
+                        FOR x:=1 TO MAXROOMS DO
+                                p^.rooms[place].con[x]:=ReadNumber(f);
+                END ELSE
+                IF n='ERODE' THEN p^.erosion:=ReadNumber(f) ELSE
+                IF n='BACK' THEN FOR x:=0 TO 9 DO p^.back[x]:=ReadNumber(f) ELSE
+                IF n='MAP' THEN FOR y:=0 TO 3 DO FOR x:=0 TO 3 DO p^.map[x,y]:=ReadNumber(f) ELSE
+                        BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+PROCEDURE ReadRooms(filename:STRING);
+VAR     f: CfgFile;
+        n: STRING;
+        x,y: INTEGER;
+        t: ARRAY[0..255] OF BYTE;
+        p: pRoom;
+BEGIN
+        FOR x:=0 TO 255 DO t[x]:=0;
+
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+
+        roomlist:=NIL;
+
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='ROOM' THEN BEGIN
+                        New(p);
+                        p^.id:=ReadNumber(f);
+                        p^.flg:=[];
+                        FOR y:=0 TO 15 DO BEGIN
+                                n:=ReadString(f);
+                                FOR x:=0 TO 15 DO p^.map[x,y]:=t[Ord(n[x+1])];
+                        END;
+                        p^.next:=roomlist;
+                        roomlist:=p;
+                END ELSE
+                IF n='DOOR' THEN BEGIN IF p<>NIL THEN BEGIN
+                        p^.dor:=ReadNumber(f);
+                END END ELSE
+                IF n='EASYDOOR' THEN p^.flg:=p^.flg+[ROOM_EASYDOOR] ELSE
+                IF n='UNIQUE'   THEN p^.flg:=p^.flg+[ROOM_UNIQUE] ELSE
+                IF n='CHAR' THEN BEGIN
+                        n:=ReadString(f);
+                        t[Ord(n[1])]:=ReadNumber(f);
+                END ELSE
+                BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+PROCEDURE ReadKeys(filename:STRING);
+VAR     x: INTEGER;
+        n: STRING;
+        f: CfgFile;
+
+BEGIN
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+                IF n='KEY' THEN BEGIN
+                        x:=ReadNumber(f);
+                        n:=ReadString(f);
+                        IF x<=MAXCMD THEN BEGIN
+				IF (n[1]='~') AND (length(n)>1) THEN CASE n[2] OF
+					'~': n[1]:='~';
+					'A': n[1]:=KEYCHR_DIR1;
+					'B': n[1]:=KEYCHR_DIR2;
+					'C': n[1]:=KEYCHR_DIR3;
+					'D': n[1]:=KEYCHR_DIR4;
+					'E': n[1]:=KEYCHR_DIR5;
+					'F': n[1]:=KEYCHR_DIR6;
+					'G': n[1]:=KEYCHR_DIR7;
+					'H': n[1]:=KEYCHR_DIR8;
+					'I': n[1]:=KEYCHR_DIR9;
+					'n': n[1]:=KEYCHR_CR;
+					'b': n[1]:=KEYCHR_BS;
+					't': n[1]:=KEYCHR_TAB;
+				END;
+				Cmd[x]:=n[1];
+			END;
+		END ELSE
+                        BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+PROCEDURE ReadTiles(filename:STRING);
+VAR     n: STRING;
+        f: CfgFile;
+        p: TileDef;
+
+BEGIN
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+
+        tilelist:=NIL;
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='TILE' THEN BEGIN
+                        New(p);
+                        p^.id:=ReadNumber(f);
+                        p^.flg:=[];
+                        p^.vis:=5;
+                        p^.drp:=0;
+			p^.mov:=30;
+                        p^.next:=tilelist;
+                        tilelist:=p;
+                END ELSE
+                IF n='NAME' THEN BEGIN
+                        p^.nam:=ReadString(f);
+                END ELSE
+                IF n='LOOKS' THEN BEGIN
+                        n:=ReadString(f);
+                        p^.chr:=n[1];
+                        p^.atr:=ReadNumber(f);
+                END ELSE
+                IF n='CHANGETO' THEN p^.chn:=ReadNumber(f)      ELSE
+                IF n='VISION'   THEN p^.vis:=ReadNumber(f)      ELSE
+                IF n='MOVE'  	THEN p^.mov:=ReadNumber(f)      ELSE		
+                IF n='DESTROYTO' THEN p^.dst:=ReadNumber(f)     ELSE
+                IF n='DROPITEM' THEN p^.drp:=ReadNumber(f) ELSE
+                IF n='OPERATE'  THEN p^.flg:=p^.flg+[TILE_OPERATE] ELSE
+                IF n='ENTER'    THEN p^.flg:=p^.flg+[TILE_ENTER] ELSE
+                IF n='EXIT'     THEN p^.flg:=p^.flg+[TILE_EXIT] ELSE
+                IF n='SMARTDOOR' THEN p^.flg:=p^.flg+[TILE_SMARTDOOR] ELSE
+                IF n='FRAGILE'  THEN p^.flg:=p^.flg+[TILE_FRAGILE] ELSE
+                IF n='BURN'     THEN p^.flg:=p^.flg+[TILE_BURN] ELSE
+                IF n='SWIM'     THEN p^.flg:=p^.flg+[TILE_SWIM] ELSE
+                IF n='UPPER'    THEN p^.flg:=p^.flg+[TILE_UPPER] ELSE
+                IF n='ITEM'     THEN p^.flg:=p^.flg+[TILE_ITEM] ELSE
+                        BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+PROCEDURE ReadMessages(filename:STRING);
+VAR     n: STRING;
+        x,hl,dl,ml: INTEGER;
+        f: CfgFile;
+BEGIN
+        tmpLine:=actLine;;
+
+        OpenCfg(f,Concat(DATADIR,filename));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+
+        stat_string:='';
+        FOR hl:=0 TO MAXLONGSTRING DO BEGIN
+                help_string[hl]:='';
+                death_string[hl]:='';
+        END;
+        hl:=0;
+        dl:=0;
+	ml:=0;
+
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='STAT' THEN stat_string:=Concat(stat_string,'@n@m',ReadString(f)) ELSE
+                IF n='HELP' THEN BEGIN
+                        help_string[hl]:=ReadString(f);
+                        IF hl<MAXLONGSTRING THEN Inc(hl);
+                END ELSE
+                IF n='DEATH' THEN BEGIN
+                        death_string[dl]:=ReadString(f);
+                        IF dl<MAXLONGSTRING THEN Inc(dl);
+                END ELSE
+                IF n='MENU' THEN BEGIN
+                        menu_string[ml]:=ReadString(f);
+                        IF ml<MAXLONGSTRING THEN Inc(ml);
+                END ELSE
+                IF n='MSG' THEN BEGIN
+                        x:=ReadNumber(f);
+                        n:=ReadString(f);
+                        IF x<=MAXMSG THEN Msgs[x]:=n;
+                END ELSE
+                        BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+        actLine:=tmpLine;
+END;
+
+
+PROCEDURE ReadMain;
+VAR     n: STRING;
+        Pal: PalAry;
+        x: INTEGER;
+        f: CfgFile;
+
+BEGIN
+        OpenCfg(f,Concat(DATADIR,MAINCFG));
+        IF errNum<>PARSE_NOERROR THEN ParseError;
+
+
+        REPEAT
+                n:=ReadName(f);
+		IF n<>'END' THEN
+		IF n='SHOW' THEN Txt(ReadString(f)) ELSE
+		IF n='VERSION' THEN Txt(Concat('Version @M',VERSION,'@m.')) ELSE
+                IF n='KEYS' THEN ReadKeys(ReadString(f)) ELSE
+                IF n='TILES' THEN ReadTiles(ReadString(f)) ELSE
+{                IF n='TOWN' THEN ReadMap(ReadString(f)) ELSE	}
+                IF n='ROOMS' THEN ReadRooms(ReadString(f)) ELSE
+                IF n='LEVELS' THEN ReadLevels(ReadString(f)) ELSE
+                IF n='ITEMS' THEN ReadItems(ReadString(f)) ELSE
+                IF n='MONSTERS' THEN ReadMonsters(ReadString(f)) ELSE		
+                IF n='TEXT' THEN ReadMessages(ReadString(f)) ELSE
+                IF n='SHDCOLOR' THEN shadecolor:=ReadNumber(f) ELSE
+                IF n='MSGCOLOR' THEN MSGCOL:=ReadNumber(f) ELSE
+                IF n='SCROLL' THEN margin:=ReadNumber(f) ELSE		
+                IF n='PALETTE' THEN BEGIN
+                        FOR x:=0 TO 15 DO BEGIN
+                                Pal[x].r:=ReadNumber(f);
+                                Pal[x].g:=ReadNumber(f);
+                                Pal[x].b:=ReadNumber(f);
+                        END;
+                        ChPal(Pal);
+                END ELSE
+                IF n='ID' THEN pc.id:=ReadString(f) ELSE
+                IF n='LEVEL' THEN BEGIN
+                        pc.intown:=TRUE;
+                        pc.lev:=ReadNumber(f);
+                END ELSE
+                        BEGIN errNum:=PARSE_ERR_NAM; ParseError END;
+
+                IF errNum<>PARSE_NOERROR THEN ParseError;
+        UNTIL n='END';
+        CloseCfg(f);
+END;
+
+
+BEGIN
+        ReadMain;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/console.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,340 @@
+{ Display and input routines. }
+
+UNIT Console;
+
+INTERFACE
+
+USES Porting;
+
+CONST	MSGCOL:BYTE=6;	{ Default messages color. }
+
+PROCEDURE Msg(m:STRING);	{ Displays string as a message on the right of the screen. }
+PROCEDURE Txt(m:STRING);	{ Displays string as a text on the left of the screen. }
+PROCEDURE Stat(m:STRING);	{ Displays string in the upper right part of the screen. }
+PROCEDURE PrepScr;		{ Prepares screen (actually does nothing) }
+PROCEDURE ResetScr;		{ Brings the screen to previous condition. }
+PROCEDURE ClrMsg;		{ Clears the messages window. }
+PROCEDURE ClrTxt;		{ Clears the text/map window. }
+PROCEDURE PutChr(x,y: INTEGER; c:CHAR; a:BYTE);	{ Displays a character on the screen. }
+PROCEDURE Cursor(x,y: INTEGER);	{ Changes cursor position. }
+
+FUNCTION  GetKey:CHAR;		{ Reads a character from keyboard. }
+FUNCTION  GetString(l:BYTE):STRING;	{ Allows to input a string. L sets maximum string length. }
+
+FUNCTION  Number(n: INTEGER):STRING;	{ Converts number into a string, three characters long. }
+FUNCTION  Num(n: INTEGER):STRING;	{ Converts number into a string. }
+FUNCTION  Replace(s,a,b:STRING):STRING;	{ Replaces the first occurance of A in string S with B. }
+FUNCTION  Capitalize(s:STRING): STRING;	{ Changes the first letter in the string to upper case. }
+FUNCTION  Plural(s:STRING):STRING;	{ Replaces '@s' and makes proper plural form. }
+
+IMPLEMENTATION
+
+VAR	nnl: BOOLEAN;		{ No new line -- should next msg change line? }
+	line,txtline: INTEGER;
+
+FUNCTION Capitalize(s:STRING):STRING;
+VAR	t: STRING;
+BEGIN
+	IF s='' THEN Exit;
+	t:=s;
+	t[1]:=UpCase(t[1]);
+	Capitalize:=t;
+END;
+
+FUNCTION Plural(s:STRING):STRING;
+BEGIN
+	s:=Replace(s, 'y@s' , 'ies'  );
+	s:=Replace(s, 'fe@s', 'ves'  );
+	s:=Replace(s, 'ff@s', 'ves'  );
+	s:=Replace(s, 'ex@s', 'icies');
+	s:=Replace(s, 'va@s', 'vae'  );
+	s:=Replace(s, 's@s' , 'ses'  );
+	s:=Replace(s, '@s'  , 's'    );
+	
+	Plural:=s;
+END;
+
+FUNCTION Replace(s,a,b:STRING):STRING;
+VAR	d: INTEGER;
+BEGIN
+	d:=Pos(a,s);
+	Replace:=s;
+	IF d<=0 THEN Exit;
+	Delete(s,d,Length(a));
+	Insert(b,s,d);
+	Replace:=s;
+END;
+
+
+PROCEDURE PutChr(x,y: INTEGER;c: CHAR; a:BYTE);
+BEGIN
+	IF (NOT pal_changed) THEN BEGIN
+		IF (a=14) THEN a:=6;
+		IF (a=13) THEN a:=14;
+	END;
+	PutChar(x,y,c,a);
+END;
+
+PROCEDURE Cursor(x,y: INTEGER);
+BEGIN
+	GotoXY(x,y);
+END;
+
+PROCEDURE ClrMsg;
+VAR	x,y: INTEGER;
+BEGIN
+	FOR y:=5 TO 24 DO
+		FOR x:=50 TO 79 DO PutChar(x,y,' ',$07);
+	line:=0;
+	nnl:=TRUE;
+END;
+
+PROCEDURE Msg(m:STRING);
+VAR	i,p: INTEGER;
+	a,l: BYTE;
+
+PROCEDURE NewLine;
+BEGIN
+	IF line>=19 THEN ScrollWin(50,5,79,24)
+		    ELSE Inc(line);
+	i:=0;
+END;
+
+BEGIN
+	IF NOT nnl THEN NewLine ELSE BEGIN
+		FOR i:=50 TO 79 DO PutChar(i,line+5,' ',MSGCOL);
+		i:=0;
+	END;
+	nnl:=FALSE;
+	p:=1;
+	a:=MSGCOL;
+	l:=Length(m);
+	REPEAT
+		WHILE m[p]='@' DO BEGIN
+			Inc(p);
+			CASE m[p] OF
+				'd': a:=0;
+				'b': a:=1;
+				'g': a:=2;
+				'c': a:=3;
+				'r': a:=4;
+				'p': a:=5;
+				'o': a:=6;
+				'w': a:=7;
+				'D': a:=8;				
+				'B': a:=9;
+				'G': a:=10;				
+				'C': a:=11;
+				'R': a:=12;				
+				'P': a:=13;
+				'O': a:=14;				
+				'W': a:=15;
+				'm': a:=MSGCOL;	
+				'M': a:=MSGCOL XOR $08;
+				'n': NewLine;
+				'N': nnl:=TRUE;
+				'@': Break;
+			END;
+			Inc(p);
+		END;
+		IF p>l THEN Exit;
+		IF i>29 THEN NewLine;
+		PutChar(50+i,line+5,m[p],a);
+		Inc(i);
+		Inc(p);
+	UNTIL FALSE;
+END;
+
+PROCEDURE ClrTxt;
+VAR	x,y: INTEGER;
+BEGIN
+	FOR y:=0 TO 24 DO
+		FOR x:=0 TO 49 DO PutChar(x,y,' ',$07);
+	txtline:=-1;
+END;
+
+
+PROCEDURE Txt(m:STRING);
+VAR	i,p: INTEGER;
+	a,l: BYTE;
+
+PROCEDURE NewLine;
+BEGIN
+	IF txtline>=24 THEN ScrollWin(0,0,49,24)
+		       ELSE Inc(txtline);
+	i:=0;
+END;
+
+BEGIN
+	NewLine;
+	p:=1;
+	a:=MSGCOL;
+	l:=Length(m);
+	REPEAT
+		WHILE m[p]='@' DO BEGIN
+			Inc(p);
+			CASE m[p] OF
+				'd': a:=0;
+				'b': a:=1;
+				'g': a:=2;
+				'c': a:=3;
+				'r': a:=4;
+				'p': a:=5;
+				'o': a:=6;
+				'w': a:=7;
+				'D': a:=8;				
+				'B': a:=9;
+				'G': a:=10;				
+				'C': a:=11;
+				'R': a:=12;				
+				'P': a:=13;
+				'O': a:=14;				
+				'W': a:=15;
+				'm': a:=MSGCOL;	
+				'M': a:=MSGCOL XOR $08;
+				'n': NewLine;
+				'@': Break;
+			END;
+			Inc(p);
+		END;
+		IF p>l THEN Exit;
+		IF i>49 THEN NewLine;
+		PutChar(i,txtline,m[p],a);
+		Inc(i);
+		Inc(p);
+	UNTIL FALSE;
+END;
+
+FUNCTION GetString(l:BYTE):STRING;
+VAR	c: CHAR;
+	s: STRING;
+	i: INTEGER;
+	a: BYTE;
+
+PROCEDURE NewLine;
+BEGIN
+	IF line>=19 THEN ScrollWin(50,5,79,24)
+		    ELSE Inc(line);
+	i:=0;
+END;
+
+BEGIN
+	IF l=0 THEN Exit;
+	IF l>30 THEN l:=30;
+	
+	IF NOT nnl THEN NewLine ELSE BEGIN
+		FOR i:=50 TO 79 DO PutChar(i,line+5,' ',MSGCOL);
+		i:=0;
+	END;
+
+
+	a:=MSGCOL XOR $08;
+	nnl:=TRUE;
+
+	s:='';
+	i:=0;
+	REPEAT
+		GotoXY(50+i,line+5);
+		c:=GetKey;
+		IF (i<l) AND (c>=' ') AND (c<#127) THEN BEGIN
+			s:=Concat(s,c);
+			PutChar(50+i,line+5,c,a);
+			Inc(i);
+		END;
+		IF c=KEYCHR_BS THEN BEGIN
+			IF i>0 THEN Dec(i);
+			PutChar(50+i,line+5,' ',a);
+			s:=Copy(s,1,length(s)-1);
+		END;
+	UNTIL (c=KEYCHR_CR);
+	GetString:=s;
+END;
+
+PROCEDURE Stat(m:STRING);
+VAR	a: BYTE;
+	i,p: INTEGER;
+
+PROCEDURE NewLine;
+BEGIN
+	ScrollWin(50,0,79,4);
+	i:=0;
+END;
+
+BEGIN
+	NewLine;
+	p:=1;
+	a:=MSGCOL;
+	REPEAT
+		WHILE m[p]='@' DO BEGIN
+			Inc(p);
+			CASE m[p] OF
+				'd': a:=0;
+				'b': a:=1;
+				'g': a:=2;
+				'c': a:=3;
+				'r': a:=4;
+				'p': a:=5;
+				'o': a:=6;
+				'w': a:=7;
+				'D': a:=8;				
+				'B': a:=9;
+				'G': a:=10;				
+				'C': a:=11;
+				'R': a:=12;				
+				'P': a:=13;
+				'O': a:=14;				
+				'W': a:=15;
+				'm': a:=MSGCOL;
+				'M': a:=MSGCOL XOR $08;
+				'n': NewLine;
+				'v': ;
+				'@': Break;
+			END;
+			Inc(p);
+		END;
+		IF i>29 THEN NewLine;
+		PutChar(50+i,4,m[p],a);
+		Inc(p);
+		Inc(i);
+	UNTIL (p>Length(m));
+END;
+
+FUNCTION Number(n: INTEGER):STRING;
+VAR	s: STRING[3];
+BEGIN
+	Str(n:3,s);
+	Number:=s;
+END;
+
+FUNCTION Num(n: INTEGER):STRING;
+VAR	s: STRING;
+BEGIN
+	Str(n,s);
+	Num:=s;
+END;
+
+PROCEDURE PrepScr;
+VAR	x,y: INTEGER;
+BEGIN
+{	FOR y:=0 TO 24 DO
+		FOR x:=0 TO 79 DO PutChar(x,y,' ',$07);}
+END;
+
+PROCEDURE ResetScr;
+VAR i,x,y:BYTE;
+BEGIN
+	FOR y:=0 TO 24 DO FOR x:=0 TO 79 DO PutChar(x,y,' ',$07);
+	GotoXY(0,0);
+	ResetPal;
+END;
+
+FUNCTION GetKey:CHAR;
+BEGIN
+	GetKey:=GetChr;
+END;
+
+BEGIN
+	line:=0;
+	nnl:=TRUE;
+END.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/creature.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,155 @@
+{ Creature handling routines. }
+
+UNIT Creature;
+
+INTERFACE
+USES Global;
+
+FUNCTION  GenerateMonster(id:WORD): pCreat;
+PROCEDURE ShowMonster(m: pMap);
+PROCEDURE MoveMonster(x,y: INTEGER; creat:pCreat);
+PROCEDURE BulletFly(x1,y1,x2,y2: INTEGER);
+PROCEDURE MonsterAI(creat:pCreat);
+
+IMPLEMENTATION
+
+USES Console, Maps;
+
+
+PROCEDURE ShowMonster(m: pMap);
+BEGIN
+	Msg(Replace(msgs[5],'@v',m^.crt^.def^.nam));
+	Msg(Concat('@cHis hit points: @C',Num(m^.crt^.hp),'@c/@C',Num(m^.crt^.def^.hp)));
+	Msg(Concat('@cHis next move time: @C',Num(m^.crt^.mov)));
+	
+END;
+
+
+PROCEDURE MoveMonster(x,y: INTEGER; creat:pCreat);
+VAR	m,n: pMap;
+BEGIN
+	m:=GetMap(x,y);
+
+
+	IF creat=NIL THEN Exit;
+	IF m^.crt<>NIL THEN Exit;
+ 	IF (m^.ter^.mov>=100) THEN Exit;
+
+	n:=GetMap(creat^.x,creat^.y);
+	
+	n^.crt:=NIL;
+	m^.crt:=creat;
+	creat^.x:=x;
+	creat^.y:=y;
+
+	Inc(creat^.mov,m^.ter^.mov);
+END;
+
+
+FUNCTION GenerateMonster(id:WORD): pCreat;
+VAR	creat: pCreat;
+	monster: CreatDef;
+BEGIN
+	monster:=FindMonster(id);
+	New(creat);
+	creat^.x:=-1;	{ monster starts in Limbo }
+	creat^.def:=monster;
+	creat^.mov:=gametime;
+	creat^.hp:=creat^.def^.hp;
+	creat^.next:=allmonsters;
+	allmonsters:=creat;
+	GenerateMonster:=creat;	
+END;
+
+PROCEDURE MonsterAI(creat:pCreat);
+VAR	x,y: INTEGER;
+BEGIN
+	IF creat=NIL THEN Exit;
+
+	IF creat^.x<0 THEN Exit;
+	
+	x:=creat^.x;
+	y:=creat^.y;
+
+	IF (MAP_VISIBLE IN GetMap(x,y)^.flg) THEN BEGIN
+		IF (playchr^.x>x) AND (FreeToMove(GetMap(x+1,y))) THEN Inc(x);
+		IF (playchr^.x<x) AND (FreeToMove(GetMap(x-1,y))) THEN Dec(x);
+		IF (playchr^.y>y) AND (FreeToMove(GetMap(x,y+1))) THEN Inc(y);
+		IF (playchr^.y<y) AND (FreeToMove(GetMap(x,y-1))) THEN Dec(y);
+	END;
+	
+	IF (x<>creat^.x) OR (y<>creat^.y) THEN BEGIN
+		MoveMonster(x,y,creat);
+	END ELSE Inc(creat^.mov,50);
+END;
+
+PROCEDURE BulletFly(x1,y1,x2,y2: INTEGER);
+VAR     i,dx,dy,j,d, c1, c2,x, a1, a2,y, b1, b2: INTEGER;
+	m: pMap;
+BEGIN
+  dx:=Abs(x2-x1);
+  dy:=Abs(y2-y1);
+
+  IF dx>=dy THEN BEGIN
+      j:=dx+1;
+      d:=(dy*2)-dx;
+      c1:=dy*2;
+      c2:=(dy-dx)*2;
+      a1:=1;
+      a2:=1;
+      b1:=0;
+      b2:=1;
+  END ELSE BEGIN
+      j:=dy+1;
+      d:=(dx*2)-dy;
+      c1:=dx*2;
+      c2:=(dx-dy)*2;
+      a1:=0;
+      a2:=1;
+      b1:=1;
+      b2:=1;
+  END;
+
+  IF x1>x2 THEN BEGIN
+      a1:=-a1;
+      a2:=-a2;  
+  END;
+
+  IF y1>y2 THEN BEGIN
+      b1:=-b1;
+      b2:=-b2;
+  END;
+
+  x:=x1;
+  y:=y1;
+
+  IF (d < 0) THEN BEGIN
+          Inc(d,c1);
+          Inc(x,a1);
+          Inc(y,b1);
+  END ELSE BEGIN
+          Inc(d,c2);
+          Inc(x,a2);
+          Inc(y,b2);
+  END;
+
+  WHILE InMap(x,y) DO BEGIN
+      m:=GetMap(x,y);
+      IF m^.ter^.mov>=100 THEN BEGIN
+      	Demolish(m);
+      	Exit;
+      END;
+      
+      IF (d < 0) THEN BEGIN
+          Inc(d,c1);
+          Inc(x,a1);
+          Inc(y,b1);
+      END ELSE BEGIN
+          Inc(d,c2);
+          Inc(x,a2);
+          Inc(y,b2);
+      END;
+  END;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/items.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,115 @@
+#
+# This is items definition file.
+# ==============================
+#
+# Do not modify it unless you know what you are doing.
+# The parser is very sensitive to syntax errors (program may crash).
+#
+# Understandig:
+# -------------
+#
+# ITEM ItemID			- Begining of an entry.
+#	NAME ItemName		- Name of the item (@s marks plural 's', @a marks quantity).
+#	LOOKS Character Color	- Character and color to represent the item.
+#	UNKNOWN ItemID		- Looks like the other item when not identyfied.
+#	EQUIP Slot		- You can equip it into Slot.
+#
+#		Slot values:
+#			0 - Can't equip (default);
+#			1 - Pack;
+#			2 - Wear;
+#
+#	MULTIPLE 		- Allows items to stack
+#	KNOWN	 		- Already idetified
+#	EMPTY			- You can put an item into it.
+#
+
+# Special 'no item' item:
+# ---------------------
+
+ITEM 0
+	NAME 	"nothing"
+	DESC	"There is nothing here."
+	LOOKS 	"-" 7
+
+# Special 'many items' item:
+# --------------------------
+
+ITEM 1
+	NAME 	"@a pile@s of items"
+	DESC	"Several items are lying here."
+	LOOKS 	"%" 7
+	EMPTY
+
+# Testing items:
+# --------------
+
+
+ITEM 2
+	NAME	"@a strange berry@s"
+	LOOKS	"," 4
+	DESC	"Looks tasty..."
+	QUANTITY	5
+	KNOWN	MULTIPLE
+	WEIGHT	1
+
+ITEM 3
+	NAME	"@a berry@s of healing"
+	LOOKS	"," 4
+	DESC	"Smells nice, looks nice, tastes nice. It heals you."
+	QUANTITY	5
+	UNKNOWN	2
+	MULTIPLE
+	WEIGHT	1
+
+ITEM 4
+	NAME	"@a rock@s"
+	LOOKS	"\"" 8
+	DESC	"Small, grey rock with some sharp edges."
+	KNOWN MULTIPLE
+	WEIGHT	3
+
+ITEM 5
+	NAME	"@a space marine uniform@s"
+	LOOKS	"[" 2
+	DESC	"Green millitary uniform with some space marines insignias on it."
+	EQUIP	2
+	KNOWN
+	WEIGHT	15
+
+ITEM 6
+	NAME	"@a millitary backpack@s"
+	LOOKS	"%" 2
+	DESC	"Large green backpack."
+	EQUIP	1
+	KNOWN EMPTY
+	WEIGHT	20
+
+# Debris:
+# -------
+
+ITEM 10
+	NAME	"@a piece@s of junk"
+	LOOKS	"~" 11
+	QUANTITY	10
+	KNOWN MULTIPLE
+	WEIGHT	5
+
+ITEM 11
+	NAME	"@a pebble@s"
+	LOOKS	"\"" 8
+	QUANTITY	30
+	KNOWN MULTIPLE
+	WEIGHT	3
+
+ITEM 12
+	NAME	"@a piece@s of wood"
+	LOOKS	")" 14
+	QUANTITY	10
+	KNOWN MULTIPLE
+	WEIGHT	5
+
+# End of file.
+# ------------
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/keys.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,81 @@
+#
+# This is keyboard definition file.
+# =================================
+#
+#
+# Understanding:
+# --------------
+#
+# 	KEY CommandID Character
+#
+# Special keys:
+# -------------
+# ~~	- Tilde
+# ~A	- Keypad 1
+# ~B	- Keypad 2
+# ~C	- Keypad 3
+# ~D	- Keypad 4
+# ~E	- Keypad 5
+# ~F	- Keypad 6
+# ~G	- Keypad 7
+# ~H	- Keypad 8
+# ~I	- Keypad 9
+# ~b	- Backspace
+# ~t	- Tab
+# ~n	- Return
+#
+
+# Direction keys:
+# ---------------
+KEY	1 "~A"	# Direction 1 
+KEY	2 "~B"	# Direction 2 
+KEY	3 "~C"	# Direction 3 
+KEY	4 "~D"	# Direction 4 
+KEY	5 "."	# Direction 5 
+KEY	6 "~F"	# Direction 6 
+KEY	7 "~G"	# Direction 7 
+KEY	8 "~H"	# Direction 8 
+KEY	9 "~I"	# Direction 9 
+
+# Commands:
+# ---------
+
+KEY	10 "Q"	# Quit 
+KEY	11 "o"	# Operate 
+KEY	12 "l"	# Look 
+KEY	13 "?"	# Help 
+KEY	14 ">"	# Enter
+KEY	15 "e"	# Examine equipment
+KEY	16 ";"	# Pick up item
+KEY	17 "c"	# Character info
+KEY	18 ","	# Pack item
+
+KEY	19 "b"	# Bash
+KEY	20 "a"	# Aim weapon
+KEY	21 "z"	# Crouch
+KEY	22 "v"	# View skills
+KEY	23 "u"	# Use tool
+KEY	24 "i"	# Browse inventory
+
+KEY	25 "S"	# Save game
+
+# More key:
+# ---------
+
+KEY	29 " "	# More / Scroll page
+
+# Item commands:
+# --------------
+
+KEY	30 "c"	# Consume
+KEY	31 "h"	# Hold / Put held item
+KEY	32 "d"	# Drop
+KEY	33 "t"	# Throw
+KEY	34 "l"	# Loot
+KEY	35 "e"	# Equip
+KEY	36 "p"	# Put to pack
+
+# End of file.
+# ------------
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/levels.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,58 @@
+#
+# This is level shemes definition file.
+# =====================================
+#
+# Understanding:
+# --------------
+#
+#	LEVEL LevelID
+#	NAME LevelName		- Level name.
+#	ROOM PlaceID RoomID	- Number of place (1-10) and room to be put in that place.
+#	QUANTITY Quantity	- How many times can this place be generated on particular level. Default 255.
+#	CONNECT PlaceIDx10	- List of places to connect to. If first number is zero -- there will be only one entrance, unless you use EASYDOOR.
+#	DOOR TileID		- Tile to use as door in this place (0 for none).
+#	BACK TileID x10 	- Tiles to fill the map area with before digging rooms.
+#	MAP BackNumber x16      - Fraktal seed. Uses numbers from BACK positions.
+#	ERODE Probability	- Probability for fraktal tile to be destroyed.
+#
+
+# Some sample levels:
+# -------------------
+
+LEVEL 1			# Space base
+	NAME	"space base"
+
+	BACK	32 32	# large tree
+		32	# small tree
+		32      # large bush
+		32      # large bush		
+		32	# small bush
+		32	# grass
+		32	# grass 
+		32	# sand
+		32	# water
+
+	ERODE	0
+
+
+	ROOM		1 0		# entrance
+	CONNECT         3 0 0 0 0 0 0 0 0 0
+	QUANTITY	1
+	DOOR		11		# stone
+
+	ROOM		2 1		# corridor
+	CONNECT         2 3 0 0 4 4 4 0 0 0
+	DOOR		11		# stone
+	
+	ROOM		3 2		# bend
+	CONNECT         2 4 0 0 0 0 0 0 0 0
+	DOOR		83
+	
+	ROOM		4 3		# small room
+	CONNECT         2 2 2 4 4 4 0 0 0 0
+	DOOR		84
+
+# End of file.
+# ------------
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/main.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,83 @@
+#
+# This is main and temporary definitions file.
+# ============================================
+#
+
+# Colors:
+# -------
+
+MSGCOLOR	2	# Default messages color.
+SHDCOLOR	5	# Color of non visible parts of map.
+
+# Set color palette (remove this for non VGA drivers):
+# ----------------------------------------------------
+
+PALETTE
+	00 00 00	# Black
+	15 00 47	# Navy
+	07 31 00	# Green
+	00 31 31	# Cyan
+	47 00 00	# Red
+	31 23 31	# Purple
+	31 23 00	# Brown
+	39 39 39	# Grey
+	23 23 23	# Dark
+	31 31 63	# Blue
+	31 47 00	# Lime
+	07 47 47	# Light cyan
+	63 07 00	# Light red
+	63 39 00	# Yellow
+	47 31 00	# Light brown
+	63 63 63	# White
+
+# Load CFG files:
+# --------------- 
+
+#SHOW	"@P////////////////"
+#SHOW	"@D_   __  __   __ "
+#SHOW	"@D(_/ |_\\ |_) ( . "
+#SHOW	"@D | .| |.| \\. ~|."
+#SHOW	"@D '  '   '     ' "
+#SHOW	"@P////////////////"
+#SHOW	"@D  Yet Another   "
+#SHOW	"@D Roguelike Game "
+
+
+SHOW	""
+SHOW	"   @o|"
+SHOW	"   @O|"
+SHOW	"@o--@O-@P+@O-@o--"
+SHOW	"   @O|"
+SHOW	"   @o|"
+
+SHOW	"@MYet Another Roguelike Game"
+VERSION
+SHOW	"Reading configuration files@M:"
+SHOW	" @Mo@m Reading message strings@M..."
+TEXT	"messages.gz"
+SHOW	" @Mo@m Reading keys definitions@M..."
+KEYS	"keys.gz"
+SHOW	" @Mo@m Reading tiles definitions@M..."
+TILES	"tiles.gz"
+SHOW	" @Mo@m Reading room maps definitions@M..."
+ROOMS	"rooms.gz"
+SHOW	" @Mo@m Reading level shemes definitions@M..."
+LEVELS	"levels.gz"
+SHOW	" @Mo@m Reading items definitions@M..."
+ITEMS	"items.gz"
+SHOW	" @Mo@m Reading creatures definitions@M..."
+MONSTERS "monsters.gz"
+SHOW	"Initialization complete@M."
+
+# Player character defaults:
+# --------------------------
+
+ID		"Sheep"	# Players name
+LEVEL		1	# Level sheme
+SCROLL		8	# How far from screen edge to scroll.
+
+
+# End of file.
+# ------------
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/messages.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,145 @@
+#
+# Messages and other texts definition file.
+# =========================================
+#
+# Special characters:
+# -------------------
+#
+# Colors:
+#	@d - Black	@D - Dark
+#	@b - Navy	@B - Blue
+#	@g - Khaki	@G - Green
+#	@c - Cyan	@C - Light cyan
+#	@r - Red	@R - Light red
+#	@p - Purple	@P - Yellow  
+#	@o - Brown	@O - Orange
+#	@w - Grey	@W - White
+#	@m - Default	@M - Default bold
+#
+# Other:
+#	@n - New line.	@v - Variable.
+#	@N - No new line, no message stacking.
+#	@@ - '@' character.
+#
+# Status:
+#	@v - ID
+#	@1,@2,...,@0 - Stats
+#
+
+# Status lines (no more than 256 characters and 5 lines!):
+# --------------------------------------------------------
+
+STAT	"@P/////////// @DStatus@P ///////////"
+STAT	" @rID: @R@v@r Sta:@R@5@r Sta:@R@8"
+STAT	" @rHP: @R@1/@2@r  Sta:@R@6@r Sta:@R@9"
+STAT	" @rPW: @R@3/@4@r  Sta:@R@7@r Sta:@R@0"
+STAT	"@P////////// @DMessages@P //////////"
+
+# Help text (no more than MAXLONGSTRING lines!):
+# -----------------------------------
+
+HELP	"Keys:"
+HELP	" @MNumPad@m - Walk;"
+HELP	" @M.@m) Wait;"
+HELP	" @Mz@m) Crouch;"
+HELP	" @M>@m) Enter;"
+HELP	" @Mo@m) Operate;"
+HELP	" @Mb@m) Bash;"
+HELP	" @Ma@m) Aim weapon;"
+HELP	" @Me@m) Browse equipment;"
+HELP	" @Mi@m) Browse pack;"
+HELP	" @M;@m) Pick up an item;"
+HELP	" @M,@m) Put an item into pack;"
+HELP	" @Mc@m) Character info;"
+HELP	" @Mv@m) View skills;"
+HELP	" @Ml@m) Look;"
+HELP	" @MS@m) Save game;"
+HELP	" @MQ@m) Quit;"
+
+# Death text (no more...)
+# -----------------------
+
+DEATH	"@R   d'   @D.  @R`b.     @R(.  @D.  @R("
+DEATH	"@R   Yb  @wd8b @Rd^~@D,... @R`P @wd8b@R b"
+DEATH	"@R   `88.@wYP^.od888888bo.@w^YP@R,8b"
+DEATH	"@R    Y8b@w`'d888888888888b@w`'@Rd8P"
+DEATH	"@R )  d88 @wd88P^`Y88P'^Y88b @RYP'  "
+DEATH	"@Rd' ,88'@w;8P'   `88'   @w`Y8: @R`  ("
+DEATH	"@RP  d8P @wd8'     YP     @w`8b  @R) `"
+DEATH	"@R` ,88b @w88    @B+ @wdb @B+    @w88  @Rd  "
+DEATH	"@R  d888.@wY8.     P8     @w,8P@R,d' d"
+DEATH	"@R  8888b@w`8bo..,d'Pb..,od8'@Rd8 ,8"
+DEATH	"@R( `8888b-@w`^Y888,@D.@w888P^'@R-d88bd8"
+DEATH	"@R ) Y888'@wd8b@R,@D;@w888888:@R.@wd8b@R`88888"
+DEATH	"@Rd: :888.@wY8'@R/@wd888888b@R\\@w`8P@R,88888"
+DEATH	"@R8b.d888bood.@wYP@R.@wYP@R.@wYP@R,bood88888"
+DEATH	"@R88888888888booboodood888888888"
+
+# Main menu text (no more...)
+# -----------------------
+
+MENU	"@P//////////////////////////////"
+MENU	"@D888888888888888888888888888888"
+MENU	"@D8b  P' 8b   `88b  _`Y8'    d88"
+MENU	"@D88.   d88  ^ 888   _d8  C~~888"
+MENU	"@D8888  8~8  . 8~8  . Y~b ,  8~8"
+MENU	"@D8888,o888,o8o888,obod8888,o888"
+MENU	"@P//////////////////////////////"
+MENU	" @Mn@m) @MNew game@m;"
+MENU	" @Ml@m) @MLoad saved game@m;"
+MENU	" @Mq@m) @MQuit@m;"
+
+# Messages:
+# ---------
+
+MSG	0	"@NPress '@M?@m' for help."
+MSG	1	"@N@MAim where?"
+MSG	2	"You hit @M@v@m. "
+MSG	3	"You demolish @M@v@m."
+MSG	4	"@N@MLook where?"
+MSG	5	"There is @M@v@m here."
+MSG	6	"@N@MOperate what?"
+MSG	7	"Nothing to operate."
+MSG	8	"Nowhere to enter here."
+MSG	9	"There is no item."
+MSG	10	"@NCancelled."
+MSG	11	"Time passes..."
+MSG	12	"Entering @M@v@m now..."
+MSG	13	"You see @M@v@m lying here."
+MSG	14	"You can't see anything there."
+MSG	15	"You put @M@v@m into @M@1@m."
+MSG	16	"@N@MWhich item?"
+MSG	17	"You examine @M@v@m."
+MSG	18	"There is no room."
+MSG	19	"Strike @Mspace@m for more..."
+MSG	20	"You equip @M@v@m."
+MSG	21	"@N@MBash what?"
+MSG	22	"You are slowed down."
+MSG	23	"Ouch! It burns."
+MSG	24	"You swim."
+MSG	25	"You crawl."
+MSG	26	"You crouch."
+MSG	27	"You stand up."
+MSG	28	"Stand up first."
+MSG	29	"Contents of @M@v@m:"
+MSG	30	" @M@1@m) @M@v@m;"
+MSG	31	"You have no pack!"
+MSG	32	"You need free hands!"
+MSG	33	"It weights @M@v@m unit@s."
+MSG	34	"Saving game..."
+MSG	35	"Please enter your @MID@m:"
+
+# Item commands:
+# --------------
+
+MSG	40	" @Ml@m) @Mloot contents@m;"
+MSG	41	" @Mh@m) @Mhold@m;"
+MSG	42	" @Mh@m) @Mput held item in@m;"
+MSG	43	" @Md@m) @Mdrop@m;"
+MSG	44	" @Me@m) @Mequip@m;"
+MSG	45	" @Mp@m) @Mput into pack@m;"
+
+# End of file.
+# ------------
+
+END 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/monsters.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,37 @@
+#
+# This is monsters definition file.
+# =================================
+#
+#
+# Understanding:
+# --------------
+#
+# MONSTER MonsterID		- Begining of an entry.
+#	NAME MonsterName	- Name of the monster.
+#	LOOKS Character Color	- Looks.
+#	HPMAX HpMax		- Maximum number of hit points.
+#	SPEED Speed		- Monster speed.
+#
+#	
+# Special 'our hero' creature:
+# ----------------------------
+
+MONSTER 0
+	NAME	"player character"
+	LOOKS	"@" 15
+	HPMAX	100
+	SPEED	30
+
+# Testing creatures:
+# ------------------
+
+MONSTER 1
+	NAME	"dummy droid"
+	LOOKS	"d" 9
+	HPMAX	100
+	SPEED	10
+
+# End of file.
+# ------------
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/rooms.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,139 @@
+#
+# This is rooms definition file.
+# ==============================
+#
+# Understandig:
+# -------------
+#
+#	CHAR Character TileID		- Character represents that tile.
+#	ROOM RoomID MapString x16	- Rooms map. Each string must be 16 characters long.
+#	EASYDOOR			- Put door everywhere possible.
+#
+
+# Special tiles:
+# --------------
+
+CHAR	" " 0	# Empty
+CHAR	"x" 1	# Soft edge, door possible
+CHAR	"X" 2	# Hard edge, no door
+
+# Floors:
+# -------
+
+CHAR	"," 15	# Grass
+CHAR	":" 12	# Ground
+CHAR	";" 11	# Metal floor
+CHAR	"'" 13	# Sand
+
+# Walls:
+# ------
+
+CHAR	"%" 36	# Brick wall
+CHAR	"@" 35	# Wooden wall
+
+# Others:
+# -------
+
+CHAR	"*" 66	# Fountain
+CHAR	"d" 81	# Closed wooden door
+CHAR	"0" 3	# Entrance
+
+# Special starting room:
+# ----------------------
+
+ROOM 0	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"       x        "
+	"      x0x       "
+	"       x        "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+EASYDOOR
+
+# Other rooms;
+# ------------
+
+# Corridor
+ROOM 1	"                "
+	"                "
+	"                "
+	"                "
+	"      XxX       "
+	"      x;x       "
+	"      X;X       "
+	"     XX;XX      "
+	"      X;X       "
+	"      x;x       "
+	"      XxX       "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+EASYDOOR
+
+# Corridor bend
+ROOM 2	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"      XxX       "
+	"      x;x       "
+	"      XxX       "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+	"                "
+EASYDOOR
+
+# Room
+ROOM 3	"XxxxxxxxxxxxxxxX"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"x;;;;;;;;;;;;;;x"
+	"XxxxxxxxxxxxxxxX"
+
+# Room
+ROOM 4	"                "
+	"                "
+	"                "
+	"    XxxxxxX     "
+	"    x;;;;;x     "
+	"    x;;;;;x     "
+	"    x;;;;;x     "
+	"    x;;;;;x     "
+	"    x;;;;;x     "
+	"    x;;;;;x     "
+	"    x;;;;;x     "
+	"    XxxxxxX     "
+	"                "
+	"                "
+	"                "
+	"                "
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editcfg/tiles.cfg	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,565 @@
+#
+# This is tiles definition file.
+# ==============================
+#
+# Understanding:
+# --------------
+#
+#	TILE TileID		- Number of the tile (max 127).
+#	NAME TileName		- Name of the tile (max 36 letters).
+#	LOOKS Character Color   - Character and color to represent the tile.
+#	CHANGETO TileID		- What tile to change to when operating.
+#	DESTROYTO TileID	- What tile to change when destroyed (0 for undestructible).
+#	VISION Shade		- How much does it block light (Default 5, max 100, >=30 drops shadow).
+#	MOVE MoveCost		- Move cost of a tile. 100 for block.
+#	SWIM			- Liquid - can swim through it.
+#	BURN			- Burns.
+#	UPPER			- Upper ground.
+#	ENTER			- Can enter it.
+#	EXIT 			- Can exit thru it.
+#	OPERATE			- Operational.
+#	SMARTDOOR		- Changes character to	"-" when appropriate.
+#	FRAGILE 		- Bash it on move, easy to bash.
+#	ITEM			- An item can lie there.
+#
+
+# Special tiles:
+# --------------
+
+TILE 0
+	NAME		"nothing"
+	LOOKS		" " 7
+	 
+	VISION		100
+	MOVE		100
+	DESTROYTO	0
+
+TILE 1
+	NAME		"soft edge"
+	LOOKS		" " 7
+	MOVE		100
+	DESTROYTO	0
+
+TILE 2
+	NAME		"hard edge"
+	LOOKS		" " 7
+	MOVE		100
+	DESTROYTO	0
+	
+TILE 3
+	NAME		"a landing site"
+	LOOKS		"0" 9
+	MOVE		30
+	DESTROYTO	0
+	VISION		50
+	 ENTER
+
+TILE 4
+	NAME		"an exit ramp"
+	LOOKS		"0" 7
+	MOVE		30
+	DESTROYTO	0
+	ENTER
+
+# Floors:
+# -------
+
+TILE 10
+	NAME		"a piece of stone floor"
+	LOOKS		"." 7
+	MOVE		30
+	DESTROYTO	0
+	ITEM
+	
+TILE 11
+	NAME		"a piece of metal floor"
+	LOOKS		"." 11
+	MOVE		30
+	DESTROYTO	0
+	ITEM
+	
+TILE 12
+	NAME		"some ground"
+	LOOKS		"." 14
+	MOVE		30
+	DESTROYTO	0
+	ITEM
+	
+TILE 13
+	NAME		"some sand"
+	LOOKS		"." 13
+	MOVE		30
+	DESTROYTO	0
+	ITEM
+	
+TILE 14
+	NAME		"some snow"
+	LOOKS		"." 15
+	MOVE		30
+	DESTROYTO	12
+	ITEM
+	
+TILE 15
+	NAME		"a patch of grass"
+	LOOKS		"." 10
+	MOVE		30
+#	DESTROYTO	12
+	ITEM
+	
+TILE 16
+	NAME		"a bloody stain"
+	LOOKS		"." 12
+	MOVE		30
+	DESTROYTO	0	
+	ITEM	
+	
+# Unusual floors:
+# ---------------
+
+TILE 21
+	NAME		"a pool of water"
+	LOOKS		"=" 9
+	MOVE		50
+	DESTROYTO	0
+	SWIM
+	
+TILE 22
+	NAME		"a pool of lava"
+	LOOKS		"=" 12
+	MOVE		50
+	DESTROYTO	67
+	BURN
+	
+TILE 23
+	NAME		"a pool of slime"
+	LOOKS		"=" 10
+	MOVE		50
+	DESTROYTO	0
+	SWIM 
+
+TILE 24
+	NAME		"a pool of black mass"
+	LOOKS		"=" 8
+	MOVE		50
+	DESTROYTO	0
+	BURN
+
+TILE 25
+	NAME		"an ice sheet"
+	LOOKS		"=" 15
+	MOVE		50
+	DESTROYTO	21
+	 ITEM
+	
+TILE 26
+	NAME		"a quicksand"
+	LOOKS		"=" 13
+	MOVE		50
+	DESTROYTO	0
+	SWIM
+		
+TILE 27
+	NAME		"a metal grate"
+	LOOKS		"=" 3
+	MOVE		30
+	DESTROYTO	0	
+	
+# Walls:
+# ------
+
+TILE 30
+	NAME		"a solid rock"
+	LOOKS		"#" 8
+	MOVE		100
+	DESTROYTO	50
+	 
+	VISION		100
+	DROPITEM	11 	# Pebble
+	
+TILE 31
+	NAME		"a stone wall"
+	LOOKS		"#" 7
+	MOVE		100
+	DESTROYTO	50
+	 
+	VISION		100
+	DROPITEM	11 	# Pebble
+	
+TILE 32
+	NAME		"a metal wall"
+	LOOKS		"#" 3
+	MOVE		100
+	DESTROYTO	51
+	 
+	VISION		100
+	DROPITEM	10 	# Junk
+	
+TILE 33
+	NAME		"a glowing metal wall"
+	LOOKS		"#" 11
+	MOVE		100
+	DESTROYTO	51
+	 
+	VISION		100
+
+TILE 34
+	NAME		"an ice wall"
+	LOOKS		"#" 15
+	MOVE		100
+	DESTROYTO	53
+	 
+	VISION		100
+	
+TILE 35
+	NAME		"a wooden wall"
+	LOOKS		"#" 14
+	MOVE		100
+	DESTROYTO	57
+	 
+	VISION		100
+	DROPITEM	12	# Stick
+
+TILE 36
+	NAME		"a brick wall"
+	LOOKS		"#" 4
+	MOVE		100
+	DESTROYTO	52
+	 
+	VISION		100
+	
+
+TILE 37
+	NAME		"a wall with some ivy"
+	LOOKS		"#" 10
+	MOVE		100
+	DESTROYTO	50
+	 
+	VISION		100
+
+TILE 38
+	NAME		"a wall of soil"
+	LOOKS		"#" 6
+	MOVE		100
+	DESTROYTO	55
+	 
+	VISION		100
+
+TILE 39
+	NAME		"a wall of strange mass"
+	LOOKS		"#" 13
+	MOVE		100
+	DESTROYTO	12
+	 
+	VISION		100
+	
+# Demolished & upper ground:
+# --------------------------
+
+TILE 50
+	NAME		"a pile of rubble"
+	LOOKS		":" 7
+	UPPER 
+	VISION		30
+	MOVE		50
+	DESTROYTO	10
+
+TILE 51
+	NAME		"a pile of junk"
+	LOOKS		":" 11
+	MOVE		50
+	DESTROYTO	11
+	VISION		30
+	UPPER 
+
+TILE 52
+	NAME		"a pile of bricks"
+	LOOKS		":" 12
+	MOVE		50
+	DESTROYTO	12
+	VISION		30
+	UPPER 
+
+TILE 53
+	NAME		"a snow dune"
+	LOOKS		":" 15
+	MOVE		50
+	DESTROYTO	14
+	VISION		20
+	UPPER 
+
+TILE 54
+	NAME		"a sand dune"
+	LOOKS		":" 13
+	MOVE		50
+	DESTROYTO	13
+	VISION		20
+	UPPER 
+
+TILE 55
+	NAME		"a mound"
+	LOOKS		":" 14
+	MOVE		50
+	DESTROYTO	12
+	VISION		20
+	UPPER
+
+TILE 56
+	NAME		"a thicket"
+	LOOKS		":" 10
+	MOVE		50
+	DESTROYTO	15
+	VISION		10
+	
+	FRAGILE
+
+TILE 57
+	NAME		"a pile of wood"
+	LOOKS		":" 6
+	MOVE		50
+	DESTROYTO	12
+	VISION		30
+	 UPPER
+
+# Large obstacles:
+# ----------------
+
+TILE 60
+	NAME		"a large tree"
+	LOOKS		"*" 10
+	MOVE		100
+	DESTROYTO	61
+	VISION		70
+	
+
+TILE 61
+	NAME		"a small tree"
+	LOOKS		"*" 2
+	MOVE		100
+	DESTROYTO	70
+	
+	VISION		40
+
+TILE 62
+	NAME		"a boulder"
+	LOOKS		"*" 8
+	MOVE		100
+	DESTROYTO	50
+	
+	VISION		40
+
+TILE 63
+	NAME		"a large machine"
+	LOOKS		"*" 3
+	VISION		70
+	MOVE		100
+	DESTROYTO	51
+	
+
+TILE 64
+	NAME		"a large crystal"
+	LOOKS		"*" 15
+	MOVE		100
+	DESTROYTO	0
+	
+	VISION		30
+
+TILE 65
+	NAME		"a statue"
+	LOOKS		"*" 7
+	MOVE		100
+	DESTROYTO	50
+	
+
+TILE 66
+	NAME		"a fountain"
+	LOOKS		"*" 9
+	MOVE		70
+	DESTROYTO	0
+	SWIM  
+	VISION		30
+	
+
+TILE 67
+	NAME		"a large flame"
+	LOOKS		"*" 12
+	MOVE		70
+	DESTROYTO	0
+	VISION		30
+	BURN 
+
+# Small obstacles:
+# ----------------
+
+TILE 70
+	NAME		"a large bush"
+	LOOKS		"+" 10
+	VISION		40
+	
+	MOVE		100
+	DESTROYTO	71
+	FRAGILE
+
+TILE 71
+	NAME		"a small bush"
+	LOOKS		"+" 2
+	MOVE		100
+	DESTROYTO	56
+	FRAGILE
+	VISION		20
+
+TILE 73
+	NAME		"a small machine"
+	LOOKS		"+" 3
+	MOVE		100
+	DESTROYTO	51
+	VISION		100
+	
+
+TILE 74
+	NAME		"a small crystal"
+	LOOKS		"+" 15
+	MOVE		50
+	DESTROYTO	0
+	VISION		100
+	
+
+TILE 75
+	NAME		"a tombstone"
+	LOOKS		"+" 7
+	MOVE		50
+	DESTROYTO	50
+	VISION		100
+	
+
+TILE 76
+	NAME		"a terminal"
+	LOOKS		"+" 9
+	MOVE		100
+	DESTROYTO	51
+	VISION		100
+	OPERATE  
+
+# Doors:
+# ------
+
+TILE 80
+	NAME		"an opened wooden door"
+	LOOKS		"\\" 6
+	CHANGETO	81
+	MOVE		30
+	DESTROYTO	57
+	 OPERATE
+	DROPITEM	12	# Stick
+
+TILE 81
+	NAME		"a closed wooden door"
+	LOOKS		"|" 6
+	CHANGETO	80
+	MOVE		100
+	DESTROYTO	57
+	 
+	VISION		100
+	OPERATE SMARTDOOR
+	DROPITEM	12	# Stick
+
+TILE 82
+	NAME		"a locked wooden door"
+	LOOKS		"|" 6
+	CHANGETO	80
+	MOVE		100
+	DESTROYTO	57
+	 
+	VISION		100
+	OPERATE SMARTDOOR
+	DROPITEM	12	# Stick
+
+TILE 83
+	NAME		"an opened metal door"
+	LOOKS		"\\" 3
+	CHANGETO	84
+	MOVE		30
+	DESTROYTO	51
+	 OPERATE
+	DROPITEM	10	# Junk
+
+TILE 84
+	NAME		"a closed metal door"
+	LOOKS		"|" 3
+	CHANGETO	83
+	MOVE		100
+	DESTROYTO	51
+	 
+	VISION		100
+	OPERATE SMARTDOOR
+	DROPITEM	10	# Junk
+
+TILE 85
+	NAME		"a locked metal door"
+	LOOKS		"|" 3
+	CHANGETO	83
+	MOVE		100
+	DESTROYTO	51
+	 
+	VISION		100
+	OPERATE SMARTDOOR
+	DROPITEM	10	# Junk
+
+TILE 86
+	NAME		"an opened gate"
+	LOOKS		"\\" 8
+	CHANGETO	87
+	MOVE		30
+	DESTROYTO	51
+	OPERATE
+	DROPITEM	10	# Junk
+
+TILE 87
+	NAME		"a closed gate"
+	LOOKS		"|" 8
+	CHANGETO	86
+	MOVE		100
+	DESTROYTO	51
+	OPERATE SMARTDOOR
+	DROPITEM	10	# Junk
+
+TILE 88
+	NAME		"a locked gate"
+	LOOKS		"|" 8
+	CHANGETO	86
+	MOVE		100
+	DESTROYTO	51
+	OPERATE SMARTDOOR
+	DROPITEM	10	# Junk
+
+TILE 89
+	NAME		"an opened airlock"
+	LOOKS		"\\" 4
+	CHANGETO	90
+	MOVE		30
+	DESTROYTO	51
+	OPERATE 
+
+TILE 90
+	NAME		"a closed airlock"
+	LOOKS		"|" 4
+	CHANGETO	89
+	MOVE		100
+	DESTROYTO	51
+	VISION		100
+	OPERATE SMARTDOOR  
+	DROPITEM	10	# Junk
+
+TILE 91
+	NAME		"a ed airlock"
+	LOOKS		"|" 4
+	CHANGETO	89
+	MOVE		100
+	DESTROYTO	51
+	VISION		100
+	OPERATE SMARTDOOR  
+	DROPITEM	10	# Junk
+
+# End of file.
+# ------------
+
+END 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/global.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,348 @@
+{ Global variables, constants, types and functions. }
+
+UNIT Global;
+
+INTERFACE
+
+
+CONST	VERSION='0.09';
+
+	DATADIR='.\data\';
+	MAINCFG='main.gz';
+
+	{ map flags }
+	MAP_VISIBLE=0;	{ visible }
+	MAP_EXPLORED=1;	{ explored }
+
+	{ tile flags }
+	TILE_EXIT=0;	{ can be exited }
+	TILE_ENTER=1;	{ can be entered }
+	TILE_OPERATE=2;	{ can be operated }
+	TILE_SMARTDOOR=3; {changes character to '-' when wall nearby}
+	TILE_ITEM=4;	{ an item can be lying here }
+	TILE_FRAGILE=5;	{ bash down automatically }
+	TILE_BURN=6;	{ burns }
+	TILE_SWIM=7;	{ you have to swim }
+	TILE_UPPER=8;	{ upper ground }
+
+	{ item flags }
+	ITEM_MULTIPLE=0;
+	ITEM_KNOWN=1;
+	ITEM_EMPTY=2;	
+
+	{ room flags }
+	ROOM_EASYDOOR=0;
+	ROOM_UNIQUE=1;
+	
+	{ slot flags }
+	SLOT_KNOWN=0;
+
+	{ item classes }
+	CLASS_HAND=7;
+	CLASS_GUN =8;
+	CLASS_AMMO=9;
+	CLASS_HEAD=6;
+	CLASS_BODY=5;
+	CLASS_BACK=11;
+	CLASS_TOOL=1;
+	CLASS_FOOD=3;
+
+	LIGHT_EMPTY=0;	{ light values }
+	LIGHT_LIT=1;
+	LIGHT_DARK=2;
+
+	CMDNOTHING=0;	{ commands }
+	CMDSOUTHWEST=1;
+	CMDSOUTH=2;
+	CMDSOUTHEAST=3;
+	CMDWEST=4;
+	CMDHERE=5;
+	CMDEAST=6;
+	CMDNORTHWEST=7;
+	CMDNORTH=8;
+	CMDNORTHEAST=9;
+
+	CMDQUIT=10;
+	CMDOPERATE=11;
+	CMDLOOK=12;
+	CMDHELP=13;
+	CMDENTER=14;
+	CMDEXAM=15;
+	CMDPICKUP=16;
+	CMDINFO=17;
+	CMDPACK=18;
+
+	CMDBASH=19;
+	CMDAIM=20;
+	CMDCROUCH=21;
+	CMDSKILLS=22;
+	CMDTOOL=23;
+	CMDINVEN=24;
+	CMDSAVE=25;
+
+	CMDMORE=29;
+	
+	CMDCONSUME=30;
+	CMDUPINAIR=31;
+	CMDDROP=32;
+	CMDTHROW=33;
+	CMDLOOT=34;
+	CMDEQUIP=35;
+	CMDPUTTOPACK=36;
+
+	INV_HELD=0;
+	INV_PACK=1;
+	INV_WEAR=2;	
+
+	DIRX: ARRAY[0..9] OF INTEGER = (0,-1,0,1,-1,0,1,-1,0,1);	{ directions }
+	DIRY: ARRAY[0..9] OF INTEGER = (0,1,1,1,0,0,0,-1,-1,-1);
+
+	MAXCMD=64;	{ maximum number of commands }
+	MAXMSG=64;	{ maximum number of messages }
+
+	MAXLEVELS=32;	{ maximum number of level shemes }
+	MAXSKILLS=16;
+	MAXSLOT=2;	{ max number of slots in inventory }
+	MAXROOMS=10;	{ max number of rooms per level }
+
+	MAPXSIZE=24;	{ map size }
+	MAPYSIZE=63;
+
+	MAXLONGSTRING=20;
+
+	MARGIN:BYTE=7;	{ center how far from edge }
+
+	PILEITEM=1;	{ Special 'multiple items' item }
+
+TYPE	Bits=SET OF 0..7;
+	Flags= SET OF 0..15;
+
+	LongString=ARRAY[0..MAXLONGSTRING] OF STRING[47];
+	
+	TileDef=^TileDefRec;
+	TileDefRec=RECORD
+		id:  	BYTE;		{ tile id }
+		nam: 	STRING[36];	{ tile name }
+		chn: 	BYTE;		{ change to }
+		chr: 	CHAR;		{ character }
+		atr: 	BYTE;		{ attribute }
+		flg: 	Flags;		{ flags }
+		dst: 	BYTE;		{ destroy to }
+		vis: 	BYTE;		{ vision blocking }
+		drp: 	BYTE;		{ item to drop when destroyed }
+		mov:	BYTE;		{ move cost }
+		next: 	TileDef;	{ next in list }
+	END;
+
+	ItemDef=^ItemDefRec;
+	ItemDefRec=RECORD
+		id:  	WORD;		{ item id }
+		nam: 	STRING[36];	{ item name }
+		chr: 	CHAR;		{ character }
+		atr: 	BYTE;		{ attribute }
+		flg: 	Bits;		{ flags }
+		dsc: 	STRING;		{ item description }
+		unk: 	BYTE;		{ unknown looks }
+		qnt: 	WORD;		{ quantity/quality }
+		eqp: 	BYTE;		{ equip slot }
+		wgt:	BYTE;		{ item base weight }
+		next: 	ItemDef;	{ next in list }
+	END;
+
+	pItem=^ItemRec;
+	ItemSlot=^pItem;	
+	ItemRec=RECORD
+		def: 	ItemDef;	{ item type }
+		qnt: 	WORD;		{ quantity/quality }
+		flg: 	Bits;		{ flags }
+		con: 	pItem;		{ item contents }
+		next: 	pItem;		{ next item in list }
+	END;
+
+	CreatDef=^CreatDefRec;
+	CreatDefRec=RECORD
+		id:	WORD;
+		nam:	STRING[36];		
+		chr:	CHAR;
+		atr:	BYTE;
+		hp:	INTEGER;
+		spd:	INTEGER;
+		next:	CreatDef;
+	END;
+	
+	pCreat=^CreatRec;
+	CreatRec=RECORD				{ Creature record }
+		def:	CreatDef;		{ Creature type }
+		x,y:	INTEGER;		{ Position on map }
+		mov:	LONGINT;		{ last move time }
+		hp:	INTEGER;		{ hp left }		
+		next:	pCreat;			{ next creature in list }
+	END;
+	
+	pMap=^MapRec;
+	MapRec=RECORD
+		ter: 	TileDef;		{ terrain }
+		slt: 	pItem;			{ item slot }
+		crt:	pCreat;			{ creature }
+		flg: 	Bits;			{ flags }
+	END;
+
+	tMappa=ARRAY[0..MAPXSIZE,0..MAPYSIZE] OF MapRec;
+
+	pRoom=^RoomRec;
+	RoomRec=RECORD
+		id: 	BYTE;				{ room id }
+		map: 	ARRAY[0..15,0..15] OF BYTE;	{ room map }
+		dor: 	BYTE;				{ door tile id }
+		flg: 	Bits;				{ flags }
+		next: 	pRoom;				{ next in list }
+	END;
+
+	PlaceRec=RECORD
+		rom:	BYTE;				{ room id }
+		con:	ARRAY[1..MAXROOMS] OF BYTE;	{ places to connect to }
+		flg:	Bits;				{ flags }
+		dor:	BYTE;
+		qnt:	BYTE;
+	END;
+	Places=ARRAY[1..MAXROOMS] OF PlaceRec;
+
+	pLevel=^LevelRec;
+	LevelRec=RECORD
+		id: 	BYTE;				{ level id }
+		name: 	STRING[36];			{ level name }
+		back: 	ARRAY[0..9] OF BYTE;		{ background tiles }
+		map: 	ARRAY[0..3,0..3] OF BYTE;	{ map seed }
+		erosion: BYTE;				{ erosion }
+		next: 	pLevel;				{ next in list }		
+		rooms:	Places;
+	END;
+
+	SkillRec=RECORD
+		name: STRING[36];
+		val: BYTE;
+	END;
+	
+	PlayerRec=RECORD
+		id: 	STRING[8];			{ player name }
+		stats: 	ARRAY[0..9] OF INTEGER; 	{ stats }
+		skl: 	ARRAY[1..MAXSKILLS] OF SkillRec;{ skills }
+		inv:	ARRAY[0..MAXSLOT] OF pItem;	{ inventory }
+		lev: 	BYTE;				{ level sheme }
+		intown: BOOLEAN;			{ is pc in town }
+		crouch: BOOLEAN;			{ is pc crouching }
+	END;
+
+VAR	mappa: 	^tMappa;
+	cmd: 	ARRAY[0..MAXCMD] OF CHAR;
+	msgs: 	ARRAY[0..MAXMSG] OF STRING[47];
+	pc: 	PlayerRec;
+	tilelist:	TileDef;
+	itemlist:	ItemDef;
+	roomlist:	pRoom;
+	levellist:	pLevel;
+	monsterlist:	CreatDef;
+	allmonsters:	pCreat;
+	playchr:	pCreat;
+	
+	stat_string: 	STRING;
+	help_string: 	LongString;
+	death_string: 	LongString;	
+	menu_string:	LongString;
+	
+	shadecolor:	BYTE;	
+	gametime:	LONGINT;
+
+FUNCTION InMap(x,y: INTEGER): BOOLEAN;
+FUNCTION GetMap(x,y: INTEGER): pMap;
+FUNCTION FindTile(id: BYTE): TileDef;
+FUNCTION FindItem(id: BYTE): ItemDef;
+FUNCTION FindRoom(id:BYTE): pRoom;
+FUNCTION FindLevel(id:BYTE): pLevel;
+FUNCTION FindMonster(id: WORD): CreatDef;
+
+IMPLEMENTATION	
+
+FUNCTION InMap(x,y: INTEGER): BOOLEAN;
+BEGIN
+	InMap:=NOT((x<0)OR(x>MAPXSIZE)OR(y<0)OR(y>MAPYSIZE));
+END;
+
+FUNCTION GetMap(x,y: INTEGER): pMap;
+BEGIN
+	GetMap:=NIL;
+	IF (NOT InMap(x,y)) OR (mappa=NIL) THEN Exit;
+	GetMap:=@mappa^[x,y];
+END;
+
+FUNCTION FindItem(id: BYTE): ItemDef;
+VAR	p: ItemDef;
+BEGIN
+	p:=itemlist;
+	REPEAT
+		IF p^.id=id THEN BEGIN
+			FindItem:=p;
+			Exit;
+		END;
+		p:=p^.next;
+	UNTIL p=NIL;
+	FindItem:=itemlist;
+END;
+
+FUNCTION FindRoom(id:BYTE): pRoom;
+VAR	p: pRoom;
+BEGIN
+	p:=roomlist;
+	REPEAT
+		IF p^.id=id THEN BEGIN
+			FindRoom:=p;
+			Exit;
+		END;
+		p:=p^.next;
+	UNTIL p=NIL;
+	FindRoom:=roomlist;
+END;
+
+FUNCTION FindLevel(id:BYTE): pLevel;
+VAR	p: pLevel;
+BEGIN
+	p:=levellist;
+	REPEAT
+		IF p^.id=id THEN BEGIN
+			FindLevel:=p;
+			Exit;
+		END;
+		p:=p^.next;
+	UNTIL p=NIL;
+	FindLevel:=levellist;
+END;
+
+FUNCTION FindTile(id: BYTE): TileDef;
+VAR	p: TileDef;
+BEGIN
+	p:=tilelist;
+	REPEAT
+		IF p^.id=id THEN BEGIN
+			FindTile:=p;
+			Exit;
+		END;
+		p:=p^.next;
+	UNTIL p=NIL;
+	FindTile:=tilelist;
+END;
+
+FUNCTION FindMonster(id: WORD): CreatDef;
+VAR	p: CreatDef;
+BEGIN
+	p:=monsterlist;
+	REPEAT
+		IF p^.id=id THEN BEGIN
+			FindMonster:=p;
+			Exit;
+		END;
+		p:=p^.next;
+	UNTIL p=NIL;
+	FindMonster:=monsterlist;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/items.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,410 @@
+{ Items handling routines. }
+
+UNIT Items;
+
+INTERFACE
+
+USES Global;
+
+FUNCTION  GetItemWeight(what: ItemSlot): INTEGER;       { Counts the weight of an item. }
+FUNCTION  IsInThere(what,where: ItemSlot):BOOLEAN;      { Checks if item WHAT is somwhere inside item WHERE. }
+PROCEDURE GetItemLooks(VAR a:BYTE;VAR c:CHAR;what:ItemSlot);    { Sets A and C to fit items looks. }
+FUNCTION  GetItemDesc(what: ItemSlot): STRING;                  { Returns item description. }
+FUNCTION  ItemName(what: ItemSlot): STRING;                     { Returns the name of an item. }
+PROCEDURE ShowItem(what: ItemSlot);             { Tells what kind of item is there. }
+
+FUNCTION  GenerateItem(id:BYTE):pItem;          { Creates a new item from definitions. }
+PROCEDURE DestroyItem(what: ItemSlot);          { Destroys an item. }
+PROCEDURE MoveInto(what,where: ItemSlot);       { Tries to put item from WHAT into container in slot WHERE. }
+PROCEDURE MoveItem(what,where: ItemSlot);       { Tries to put item from WHAT into slot WHERE. }
+PROCEDURE DropItem(what,where: ItemSlot);       { Drops item from WHAT into slot WHERE, creating a pile if needed. }
+PROCEDURE PutToPack(what: ItemSlot);            { Tries to put an item into pack. }
+
+FUNCTION  ListItems(where: ItemSlot):ItemSlot;  { Lists all items in the container and picks one. }
+PROCEDURE SelectItem(what: ItemSlot);           { Shows item description,asks for action and performs it. }
+PROCEDURE CheckPile(where: ItemSlot);           { Destroys a pile if itsn't needed anymore. }
+PROCEDURE ExamInv;                              { Displays equipment. }
+
+IMPLEMENTATION
+
+USES Console;
+
+TYPE    pStack=^StackRec;
+        StackRec=RECORD
+                slt: pItem;
+                next: pStack;
+        END;
+
+VAR     stack: pStack;
+
+{ ------------------------------------------- Item information ---------- }
+
+PROCEDURE StackPush(what: pItem);       { Pushes an item entry on stack. }
+VAR     tmp: pStack;
+BEGIN
+        New(tmp);
+        tmp^.slt:=what;
+        tmp^.next:=stack;
+        stack:=tmp;
+END;
+
+PROCEDURE StackPop(VAR what: pItem);    { Pops an item entry from stack. }
+VAR     tmp: pStack;
+BEGIN
+        IF stack=NIL THEN Exit;
+        what:=stack^.slt;
+        tmp:=stack;
+        stack:=stack^.next;
+        Dispose(tmp);
+END;
+
+
+FUNCTION GetItemWeight(what: ItemSlot): INTEGER;        { Counts the weight of an item. }
+VAR     weight: INTEGER;
+        p: pItem;
+BEGIN
+        stack:=NIL;                                     { The stack is empty. }
+        weight:=what^^.def^.wgt*what^^.qnt;             { Base weight. }
+        StackPush(what^^.con);                          { Now we search all the tree. }
+        REPEAT
+                StackPop(p);
+                WHILE p<>NIL DO BEGIN
+                        Inc(weight,p^.def^.wgt*p^.qnt);
+                        IF p^.con<>NIL THEN StackPush(p^.con);
+                        p:=p^.next;
+                END;
+        UNTIL p=NIL;
+        GetItemWeight:=weight;
+END;
+
+FUNCTION IsInThere(what,where: ItemSlot):BOOLEAN;       { Checks if item WHAT is somwhere inside item WHERE. }
+VAR     p: pItem;
+BEGIN
+        IsInThere:=FALSE;
+        stack:=NIL;
+        StackPush(where^);
+        REPEAT
+                StackPop(p);
+                WHILE p<>NIL DO BEGIN
+                        IF p=what^ THEN IsInThere:=TRUE;
+                        IF p^.con<>NIL THEN StackPush(p^.con);
+                        p:=p^.next;
+                END;
+        UNTIL p=NIL;
+END;
+
+PROCEDURE GetItemLooks(VAR a:BYTE;VAR c:CHAR;what:ItemSlot);    { Sets A and C to fit items looks. }
+VAR     tmp: ItemDef;
+BEGIN
+        IF (SLOT_KNOWN IN what^^.flg) THEN tmp:=what^^.def
+                                      ELSE tmp:=FindItem(what^^.def^.unk);
+        c:=tmp^.chr;
+        a:=tmp^.atr;
+END;
+
+FUNCTION GetItemDesc(what: ItemSlot): STRING;                   { Returns item description. }
+BEGIN
+        IF (SLOT_KNOWN IN what^^.flg)OR(what^^.def^.unk=0) THEN { If item is known -- we return its description. }
+                GetItemDesc:=what^^.def^.dsc
+        ELSE    GetItemDesc:=FindItem(what^^.def^.unk)^.dsc;    { But if not, we return description of item type. }
+END;
+
+FUNCTION ItemName(what: ItemSlot): STRING;                      { Returns the name of an item. }
+VAR     s: STRING;
+BEGIN
+        ItemName:='';
+        IF (what^=NIL) THEN BEGIN                               { If there is nothing, we return 'nothing'. }
+                ItemName:=FindItem(0)^.nam;
+                Exit;
+        END;
+
+        IF (SLOT_KNOWN IN what^^.flg) THEN s:=what^^.def^.nam   { If item is known, we return its real name. }
+                                      ELSE s:=FindItem(what^^.def^.unk)^.nam;
+
+                              { When there are many items of the same kind, we tell how many. }
+        IF (ITEM_MULTIPLE IN what^^.def^.flg) AND (what^^.qnt>1) THEN
+                s:=Replace(Plural(s),'@a',Num(what^^.qnt))
+        ELSE BEGIN                                              { Elsewhen we add 'a' or 'an'. }
+                s:=Replace(s,'@a a','an a');
+                s:=Replace(s,'@a e','an e');
+                s:=Replace(s,'@a i','an i');
+                s:=Replace(s,'@a o','an o');
+                s:=Replace(s,'@a u','an u');
+                s:=Replace(s,'@a ' ,'a ');
+                s:=Replace(s,'@a'  ,'a');
+                s:=Replace(s,'@s','');
+        END;
+        ItemName:=s;
+END;
+
+PROCEDURE ShowItem(what: ItemSlot);             { Tells what kind of item is there. }
+BEGIN
+        IF what^=NIL THEN Exit;                 { If there is nothing -- we won't bother. }
+        Msg(Replace(msgs[13],'@v',ItemName(what)));
+END;
+
+{ ------------------------------------------- Item moving and creation -- }
+
+FUNCTION GenerateItem(id:BYTE):pItem;           { Creates a new item from definitions. }
+VAR     item: ItemDef;
+        tmp: pItem;
+BEGIN
+        New(tmp);                               { We make room for item. }
+        item:=FindItem(id);                     { We find according definitions. }
+        tmp^.def:=item;                         { We fill in all data necessary. }
+        tmp^.qnt:=item^.qnt+Random(item^.qnt);
+        tmp^.flg:=[];
+        tmp^.con:=NIL;
+        tmp^.next:=NIL;
+        IF (ITEM_KNOWN IN item^.flg) THEN tmp^.flg:=tmp^.flg+[SLOT_KNOWN];
+        GenerateItem:=tmp;                      { And we have brand new item. }
+END;
+
+PROCEDURE DestroyItem(what: ItemSlot);          { Destroys an item. }
+VAR     tmp: pItem;
+BEGIN
+        tmp:=what^;                             { We take item from any container it may be in. }
+        what^:=tmp^.next;                       { We update this container's list of items. }
+        Dispose(tmp);                           { And we relase memory. }
+END;
+
+PROCEDURE MoveInto(what,where: ItemSlot);       { Tries to put item from WHAT into container in slot WHERE. }
+VAR     tmp: pItem;
+BEGIN
+        IF IsInThere(where,what) THEN Exit;     { We dont want to put something into itself! }
+        tmp:=what^;                             { Now, we take item from any container it may be in. }
+        what^:=tmp^.next;                       { We update this container's list of items. }
+        tmp^.next:=where^^.con;                 { We put all items from WHERE behind our item. }
+        where^^.con:=tmp;                       { We put our item into item in slot WHERE. }
+END;
+
+PROCEDURE MoveItem(what,where: ItemSlot);       { Tries to put item from WHAT into slot WHERE. }
+VAR     tmp: pItem;
+BEGIN
+        IF where^<>NIL THEN Exit;               { Is there something already? }
+        tmp:=what^;                             { Now, we take item from any container it may be in. }
+        what^:=tmp^.next;                       { We update this container's list of items. }
+        tmp^.next:=NIL;                         { Our item is the only one here. }
+        where^:=tmp;                            { We put our item into slot WHERE. }
+END;
+
+PROCEDURE DropItem(what,where: ItemSlot);       { Drops item from WHAT into slot WHERE, creating a pile if needed. }
+VAR     tmp: ItemSlot;
+        p: pItem;
+BEGIN
+        IF where^=NIL THEN BEGIN                { If WHERE is empty, we simply put our item there. }
+                MoveItem(what,where);
+		Exit;
+        END;
+	
+        IF where^^.def^.id=PILEITEM THEN BEGIN  { If there is a pile already, we just add our item to the pile. }
+                MoveInto(what,where)
+        END ELSE BEGIN                          { If there is an item already... }
+		New(tmp);                       { We need 'third hand'. }
+		tmp^:=NIL;
+		MoveItem(where,tmp);            { We pick the item from the floor. }
+                p:=GenerateItem(PILEITEM);      { Then we create a pile... }
+                MoveItem(@p,where);             { And put it on the floor. }
+		MoveInto(tmp,where);		{ Then we put both items into the pile. }
+		MoveInto(what,where);
+                Dispose(tmp);                   { W don't need third hand anymore. }
+        END;
+END;
+
+PROCEDURE PutToPack(what: ItemSlot);            { Tries to put an item into pack. }
+BEGIN
+        IF (pc.inv[INV_PACK]=NIL) OR            { Have we any pack to put into? }
+           NOT (ITEM_EMPTY IN pc.inv[INV_PACK]^.def^.flg) THEN Exit;
+                                                { We inform the player about what we are doing. }
+        Msg(Replace(Replace(msgs[15],'@1',ItemName(@(pc.inv[INV_PACK]))),'@v',ItemName(what)));
+        MoveInto(what,@(pc.inv[INV_PACK]));     { And we do it. }
+END;
+
+{ ------------------------------------------- Menus and handling -------- }
+
+PROCEDURE CheckCmd(VAR a:INTEGER;c:CHAR;b:BYTE);{ Checks if key C belong to command B }
+BEGIN                                           { and sets A to this command if so. }
+        IF c=cmd[b] THEN a:=b;
+END;
+
+FUNCTION ListItems(where: ItemSlot):ItemSlot;   { Lists all items in the container and picks one. }
+VAR     p,page: ItemSlot;
+        c,k: CHAR;
+BEGIN
+        ListItems:=NIL;
+        ClrMsg;
+        p:=@(where^^.con);
+        REPEAT                                  { Tell what item we are looking into. }
+                Msg(Replace(msgs[29],'@v',ItemName(where)));
+
+                page:=p;                        { Mark the top of actual page. }
+                c:='a';                         { Show a-p items. }
+                WHILE (p^<>NIL) AND (c<='p') DO BEGIN
+                        Msg(Replace(Replace(msgs[30],'@1',c),'@v',ItemName(p)));
+                        Inc(c);
+                        p:=@(p^^.next);
+                END;
+                                                { Tell if there is more. }
+                IF (p^<>NIL) THEN Msg(msgs[19]);
+
+                k:=GetKey;                      { Get players choice. }
+                ClrMsg;                         { And find this item. }
+                IF (k>='a') AND (k<c) THEN BEGIN
+                        p:=page;
+                        c:='a';
+                        WHILE (c<>k) DO BEGIN
+                                Inc(c);
+                                p:=@(p^^.next);
+                        END;
+                        ListItems:=p;
+                END;
+                IF k<>cmd[CMDMORE] THEN Exit;   { If the player picked something -- we finish. }
+                IF p^=NIL THEN p:=@(where^^.con);
+        UNTIL FALSE;                            { And if not, we display another page. }
+END;
+
+PROCEDURE SelectItem(what: ItemSlot);           { Shows item description,asks for action and performs it. }
+VAR     c: CHAR;
+        l: INTEGER;
+        tmp: pItem;
+        s: STRING;
+
+        AllowLoot, AllowPutInto, AllowHold, AllowDrop, AllowPack: BOOLEAN;
+        WhereEquip: BYTE;
+
+BEGIN
+   REPEAT
+        IF (what=NIL) OR (what^=NIL) OR                 { We won't select an empty item nor pile. }
+           (what^^.def^.id=PILEITEM) THEN BEGIN
+                Msg(msgs[10]);
+                Exit;
+        END;
+
+        ClrMsg;
+        Msg(Replace(msgs[17],'@v',ItemName(what)));     { We show item's name and description. }
+        {IF (ITEM_KNOWN IN what^^.flg) THEN}
+        Msg(GetItemDesc(what));
+
+        l:=GetItemWeight(what);                         { We display item's weight. }
+        IF l=1 THEN s:=Replace(msgs[33],'@s','')
+               ELSE s:=Plural(msgs[33]);
+        Msg(Replace(s,'@v',Num(l)));
+
+        AllowHold:=FALSE;                               { Now we determine what actions can be performed. }
+        AllowPutInto:=FALSE;
+        AllowLoot:=FALSE;
+        AllowDrop:=FALSE;
+        AllowPack:=FALSE;
+        WhereEquip:=0;
+
+        IF (pc.inv[INV_PACK]<>NIL)AND                   { If we have pack and the item we have selected isn't that pack, }
+           (ITEM_EMPTY IN pc.inv[INV_PACK]^.def^.flg)AND{we can put our item into pack. }
+	   NOT(IsInThere(what,@(pc.inv[INV_PACK])))AND
+	   (pc.inv[INV_PACK]<>what^) THEN AllowPack:=TRUE;
+
+        IF pc.inv[INV_HELD]=NIL THEN AllowHold:=TRUE;   { If the player character is empty handed, we can hold something. }
+
+        IF (pc.inv[INV_HELD]<>NIL)AND			{ If the player holds something, and selected item is a container,
+							{ he can put held item in. }
+           NOT(IsInThere(what,@(pc.inv[INV_HELD])))AND  { But we have to make sure he won't put it into itself! }
+           (ITEM_EMPTY IN what^^.def^.flg) THEN AllowPutInto:=TRUE;
+
+        IF (what^^.con<>NIL) THEN AllowLoot:=TRUE;      { If it isn't empty, we can loot it. }
+
+							{ Dropping only when the item isn't on floor already. }
+	IF NOT(IsInThere(what,@(GetMap(playchr^.x,playchr^.y)^.slt))) THEN AllowDrop:=TRUE;
+
+        WhereEquip:=what^^.def^.eqp;                    { And we can equip is if it can be equipped. :) }
+
+        IF AllowHold    THEN Msg(msgs[41]);             { We display action names. }
+        IF AllowPutInto THEN Msg(msgs[42]);
+        IF WhereEquip>0 THEN Msg(msgs[44]);
+        IF AllowPack    THEN Msg(msgs[45]);
+        IF AllowLoot    THEN Msg(msgs[40]);
+        IF AllowDrop    THEN Msg(msgs[43]);
+
+        l:=CMDNOTHING;                                  { Ask for action. }
+        c:=GetKey;
+        ClrMsg;
+        IF AllowPack    THEN CheckCmd(l,c,CMDPUTTOPACK);
+        IF AllowLoot    THEN CheckCmd(l,c,CMDLOOT);
+        IF AllowHold    THEN CheckCmd(l,c,CMDUPINAIR);
+        IF AllowPutInto THEN CheckCmd(l,c,CMDUPINAIR);
+        IF WhereEquip>0 THEN CheckCmd(l,c,CMDEQUIP);
+        IF AllowDrop    THEN CheckCmd(l,c,CMDDROP);
+
+        CASE l OF                                       { Perform the action. }
+                CMDLOOT: BEGIN                          { We list items inside and wait allow to select an item. }
+                                what:=ListItems(what);
+                        END;
+                CMDPUTTOPACK: BEGIN
+                                PutToPack(what);        { Simple. }
+                                what:=NIL;              { We don't want to select this item again. }
+                        END;
+                CMDUPINAIR: IF AllowHold THEN BEGIN
+                                MoveItem(what,@(pc.inv[INV_HELD]));
+                                what:=NIL;
+                        END ELSE IF AllowPutInto THEN BEGIN
+                                MoveInto(@(pc.inv[INV_HELD]),what);
+                                Msg(Replace(Replace(msgs[15],'@1',ItemName(what)) ,'@v',ItemName(@(pc.inv[INV_HELD]))));
+                                what:=NIL;
+                        END;
+                CMDDROP:BEGIN
+                                DropItem(what,@(GetMap(playchr^.x,playchr^.y)^.slt));
+                                ShowItem(@(GetMap(playchr^.x,playchr^.y)^.slt));
+                                what:=NIL;
+                        END;
+                CMDEQUIP:BEGIN		{ If there is an item equipped and player character is empty handed, we hold equipped item. }
+                                IF pc.inv[WhereEquip]<>NIL THEN
+                                         IF pc.inv[INV_HELD]=NIL THEN MoveItem(@(pc.inv[WhereEquip]),@(pc.inv[INV_HELD]));
+
+                                                        { If the slot is free, we equip selected item. }
+                                IF pc.inv[WhereEquip]=NIL THEN MoveItem(what,@(pc.inv[WhereEquip]))
+                                                          ELSE Msg(msgs[32]);
+                                what:=NIL;
+                         END;
+                CMDNOTHING:BEGIN                        { If no action, we cancel selection. }
+                                Msg(msgs[10]);
+                                what:=NIL;
+                        END;
+        END;
+   UNTIL what=NIL;                                      { If the player haven't selected another item, we finish. }
+END;
+
+PROCEDURE CheckPile(where: ItemSlot);                   { Destroys a pile if itsn't needed anymore. }
+VAR     tmp: ItemSlot;
+BEGIN
+        IF where^=NIL THEN Exit;                        { If there is nothing there, we finish. }
+        IF where^^.def^.id<>PILEITEM THEN Exit;         { If there is no pile, we finish too. }
+
+        IF where^^.con=NIL THEN BEGIN                   { If the pile is empty, we simply destroy it. }
+                DestroyItem(where);
+                Exit;
+        END;
+        IF (where^^.con^.next=NIL) THEN BEGIN           { If there is only one item in the pile.. }
+		New(tmp);                               { We need 'third hand'. }
+		tmp^:=NIL;
+		MoveItem(@(where^^.con),tmp);           { We take the item out of pile. }
+                DestroyItem(where);                     { We destroy the pile. }
+                MoveItem(tmp,where);                    { Then we put the item on the floor. }
+                Dispose(tmp);                           { We don't need third hand. }
+        END;
+END;
+
+PROCEDURE ExamInv;                                      { Displays equipment. }
+VAR     c:CHAR;
+BEGIN
+        ClrMsg;
+        Msg(Concat('@Ma@m)HELD: @M',ItemName(@(pc.inv[INV_HELD]))));
+        Msg(Concat('@Mb@m)PACK: @M',ItemName(@(pc.inv[INV_PACK]))));
+        Msg(Concat('@Mc@m)WEAR: @M',ItemName(@(pc.inv[INV_WEAR]))));
+        c:=GetKey;
+        ClrMsg;
+        CASE c OF
+                'a': SelectItem(@pc.inv[INV_HELD]);
+                'b': SelectItem(@pc.inv[INV_PACK]);
+                'c': SelectItem(@pc.inv[INV_WEAR]);
+        END;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,368 @@
+{ Level generating routines. }
+
+{$Q+R+}
+
+UNIT Level;
+
+INTERFACE
+USES Global;
+
+	PROCEDURE GenerateLevel;
+
+IMPLEMENTATION
+
+USES Console, Items, Creature;
+
+CONST 	GEN_EMPTY=0;	{ level generator values }
+	GEN_DOOR=1;
+	GEN_OCCUPY=2;
+
+TYPE	TmpMap=ARRAY[0..MAPXSIZE,0..MAPYSIZE] OF BYTE;
+
+VAR	gen: TmpMap;
+	m:   TmpMap;
+
+PROCEDURE ClearMap;
+VAR   x,y: INTEGER;
+	m: pMap;
+	nothing: TileDef;
+BEGIN
+	nothing:=FindTile(0);
+	GetMap(playchr^.x,playchr^.y)^.crt:=NIL;
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO BEGIN
+			m:=GetMap(x,y);
+			IF m^.slt<>NIL THEN BEGIN
+				Dispose(m^.slt);				
+				m^.slt:=NIL;
+			END;
+			IF m^.crt<>NIL THEN BEGIN
+				Dispose(m^.crt);				
+				m^.crt:=NIL;
+			END;
+			m^.flg:=[];
+			m^.ter:=nothing;
+		END;
+	allmonsters:=NIL;
+END;
+
+PROCEDURE GenMap;
+VAR	x,y: INTEGER;
+BEGIN
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO BEGIN
+			GetMap(x,y)^.ter:=FindTile(m[x,y]);
+		END;
+END;
+
+PROCEDURE GenBack(lev: pLevel);
+VAR	r,i,s,x,y,a,b: INTEGER;
+	frak: TmpMap;
+
+BEGIN
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO	m[x,y]:=lev^.back[0];
+END;
+
+PROCEDURE Erode(lev:pLevel);
+VAR	x,y,r: INTEGER;
+BEGIN
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO
+			IF lev^.erosion>Random(100) THEN BEGIN
+				r:=FindTile(m[x,y])^.dst;
+				IF r>0 THEN m[x,y]:=r;
+			END;
+END;
+
+
+PROCEDURE GenLevel(lev:pLevel);
+
+VAR	r,i,j,p,x1,y1,x,y: INTEGER;
+	door: BYTE;
+	rom: pRoom;
+	place: BYTE;
+	pmap: tmpmap;	
+	tmpplaces: Places;
+
+FUNCTION TryRoom(x,y: INTEGER; rom: pRoom): BOOLEAN;
+VAR	x1,y1: INTEGER;
+
+
+BEGIN
+	IF rom=NIL THEN Exit;
+	TryRoom:=FALSE;
+	FOR y1:=0 TO 15 DO FOR x1:=0 TO 15 DO
+		IF (rom^.map[x1,y1]<>GEN_EMPTY) THEN BEGIN
+			IF (NOT InMap(x+x1,y+y1)) THEN Exit;
+			IF (gen[x+x1,y+y1]=GEN_OCCUPY) THEN Exit;
+		END;
+	TryRoom:=TRUE;
+END;
+
+PROCEDURE RotateRoom(rom:pRoom);
+VAR	x,y: INTEGER;
+	tmp: ARRAY[0..15,0..15] OF BYTE;
+BEGIN
+	FOR y:=0 TO 15 DO
+		FOR x:=0 TO 15 DO
+			tmp[x,y]:=rom^.map[y,15-x];
+	FOR y:=0 TO 15 DO
+		FOR x:=0 TO 15 DO
+			rom^.map[x,y]:=tmp[x,y];
+END;
+
+PROCEDURE PutDoor(x,y:INTEGER);
+VAR	p: INTEGER;
+
+BEGIN
+	gen[x,y]:=GEN_OCCUPY;
+	IF door=0 THEN Exit;
+	m[x,y]:=door;
+END;
+
+
+PROCEDURE PutRoom(x,y: INTEGER; rom: pRoom);
+VAR	x1,y1: INTEGER;
+BEGIN
+	IF rom=NIL THEN Exit;
+	IF tmpplaces[place].qnt>0 THEN Dec(tmpplaces[place].qnt);
+	door:=tmpplaces[place].dor;
+	FOR y1:=0 TO 15 DO FOR x1:=0 TO 15 DO
+		IF InMap(x+x1,y+y1) AND (gen[x+x1,y+y1]<>GEN_OCCUPY) THEN BEGIN
+			CASE rom^.map[x1,y1] OF
+				GEN_EMPTY: {nothing};
+				GEN_OCCUPY: gen[x+x1,y+y1]:=GEN_EMPTY;
+				GEN_DOOR: IF gen[x+x1,y+y1]=GEN_EMPTY THEN BEGIN
+						gen[x+x1,y+y1]:=GEN_DOOR;
+					  	pmap[x+x1,y+y1]:=place;
+					  END ELSE BEGIN
+						IF (ROOM_EASYDOOR IN rom^.flg) AND (gen[x+x1,y+y1]=GEN_DOOR) THEN PutDoor(x+x1,y+y1) ELSE 
+							gen[x+x1,y+y1]:=GEN_OCCUPY;
+					  END;
+				ELSE BEGIN
+					gen[x+x1,y+y1]:=GEN_OCCUPY;
+					m[x+x1,y+y1]:=rom^.map[x1,y1];
+				END;
+			END;
+		END;
+END;
+
+
+PROCEDURE NextRoom(x,y: INTEGER);
+VAR	a: INTEGER;
+BEGIN
+	a:=place;
+	place:=pmap[x1,y1];
+	REPEAT
+		Inc(a);
+		IF a>MAXROOMS THEN a:=1;
+	UNTIL (tmpplaces[place].con[a]<>0) AND (tmpplaces[tmpplaces[place].con[a]].qnt<>0);
+
+	place:=tmpplaces[place].con[a];
+	rom:=FindRoom(tmpplaces[place].rom);
+
+	a:=Random(100);
+	IF (a<70) THEN RotateRoom(rom);
+END;
+
+PROCEDURE RandomRoom(x,y: INTEGER);
+VAR	a: INTEGER;
+BEGIN
+	place:=pmap[x1,y1];
+	a:=Random(MAXROOMS)+1;
+	WHILE (tmpplaces[place].con[a]=0) OR (tmpplaces[tmpplaces[place].con[a]].qnt=0) DO BEGIN
+		Inc(a);
+		IF a>MAXROOMS THEN a:=1;
+	END;
+
+	place:=tmpplaces[place].con[a];
+	rom:=FindRoom(tmpplaces[place].rom);
+
+	a:=Random(100);
+	IF (a<70) THEN RotateRoom(rom);
+END;
+
+FUNCTION PickRoom: BOOLEAN;
+VAR	i,j,k,l: INTEGER;
+BEGIN
+    place:=pmap[x1,y1];
+    door:=tmpplaces[place].dor;
+
+    PickRoom:=FALSE;
+
+    IF tmpplaces[place].con[1]=0 THEN Exit;
+
+{    IF (gen[x1+1,y1]<>GEN_EMPTY) AND
+       (gen[x1-1,y1]<>GEN_EMPTY) AND
+       (gen[x1,y1+1]<>GEN_EMPTY) AND
+       (gen[x1,y1-1]<>GEN_EMPTY) THEN Exit;}
+
+    PickRoom:=TRUE;
+
+    RandomRoom(x1,y1);
+
+
+    FOR k:=1 TO 4 DO BEGIN
+	    x:=Random(15);
+	    y:=Random(15);	
+
+	    FOR j:=1 TO 2 DO BEGIN
+		i:=0;
+		REPEAT
+			Inc(x);
+			IF x>15 THEN BEGIN
+				x:=0;
+				Inc(y);
+				IF y>15 THEN y:=0;
+			END;
+			Inc(i);
+			IF (i>200) THEN BEGIN
+		                NextRoom(x1,y1);
+				x:=Random(15);
+				y:=Random(15);
+			END;
+		UNTIL (rom^.map[x,y]=GEN_DOOR);
+		IF TryRoom(x1-x,y1-y,rom) THEN Exit;
+	    	RotateRoom(rom);
+	    END;
+	    NextRoom(x1,y1);	    
+    END;
+    PickRoom:=FALSE;
+END;
+
+
+BEGIN
+	tmpplaces:=lev^.rooms;
+
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO BEGIN
+			gen[x,y]:=GEN_EMPTY;
+			pmap[x,y]:=0;
+		END;
+
+	place:=1;
+	rom:=FindRoom(tmpplaces[place].rom);
+	door:=rom^.dor;
+
+	
+	Msg('@cTrying first room...');
+	REPEAT
+
+		x:=Random(MAPXSIZE);
+		dec(x,8);
+		y:=Random(MAPYSIZE);
+		dec(y,8);
+		Msg(Concat('@cx=',Num(x),';y=',Num(y)));
+	UNTIL TryRoom(x,y,rom);
+	Msg('@cPutting first room...');
+	
+	PutRoom(x,y,rom);
+
+	
+	Msg('@cFirst room put...');
+	
+REPEAT
+	
+	x1:=Random(MAPXSIZE);
+	y1:=Random(MAPYSIZE);
+
+	i:=0;
+	r:=Random(4);
+	CASE r OF	
+		0:WHILE gen[x1,y1]<>GEN_DOOR DO BEGIN
+			Inc(x1);
+			IF x1>MAPXSIZE-1 THEN BEGIN
+				x1:=1;
+				Inc(y1);
+				IF y1>MAPYSIZE-1 THEN y1:=1;
+			END;
+			Inc(i);
+			IF i>MAPXSIZE*MAPYSIZE THEN BEGIN
+				
+				Exit;
+			END;
+		END;
+		1:WHILE gen[x1,y1]<>GEN_DOOR DO BEGIN
+			Dec(x1);
+			IF x1<1 THEN BEGIN
+				x1:=MAPXSIZE-1;
+				Dec(y1);
+				IF y1<1 THEN y1:=MAPYSIZE-1;
+			END;
+			Inc(i);
+			IF i>MAPXSIZE*MAPYSIZE THEN BEGIN
+				
+				Exit;
+			END;
+		END;
+		2:WHILE gen[x1,y1]<>GEN_DOOR DO BEGIN
+			Inc(y1);
+			IF y1>MAPYSIZE-1 THEN BEGIN
+				y1:=1;
+				Inc(x1);
+				IF x1>MAPXSIZE-1 THEN x1:=1;
+			END;
+			Inc(i);
+			IF i>MAPXSIZE*MAPYSIZE THEN  BEGIN
+				
+				Exit;
+			END;
+		END;
+		3: WHILE gen[x1,y1]<>GEN_DOOR DO BEGIN
+			Dec(y1);
+			IF y1<1 THEN BEGIN
+				y1:=MAPYSIZE-1;
+				Dec(x1);
+				IF x1<1 THEN x1:=MAPXSIZE-1;
+			END;
+			Inc(i);
+			IF i>MAPXSIZE*MAPYSIZE THEN  BEGIN
+				
+				Exit;
+			END;
+		END;
+	END;
+
+	Msg('@cPicking room...');
+
+	IF PickRoom THEN BEGIN
+		Msg('@cPutting room...');
+		PutDoor(x1,y1);
+		PutRoom(x1-x,y1-y,rom);	
+	END ELSE BEGIN
+		gen[x1,y1]:=GEN_EMPTY;
+	END;                     
+
+UNTIL FALSE;
+END;
+
+
+PROCEDURE GenerateLevel;
+VAR	x,y,i,a,b: INTEGER;
+	l: pLevel;
+	p: pCreat;
+BEGIN
+	ClearMap;
+	l:=FindLevel(pc.lev);
+	Msg(Replace(msgs[12],'@v',l^.name));	
+	GenBack(l);
+	Msg('@cGenerated back...');
+	GenLevel(l);
+	Msg('@cGenerated rooms...');
+	Erode(l);		
+	Msg('@cEroded...');
+	GenMap;
+
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO BEGIN
+			IF (TILE_ENTER IN GetMap(x,y)^.ter^.flg) THEN BEGIN
+				p:=playchr;
+				MoveMonster(x,y,p);
+			END;
+		END;
+	Inc(pc.lev);
+END;
+
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,165 @@
+{ Field of vision counting routines. }
+
+UNIT Light;
+
+INTERFACE
+
+PROCEDURE MakeLut;
+PROCEDURE ApplyFov(cx,cy: INTEGER);
+
+IMPLEMENTATION
+
+USES Global;
+
+CONST	LOS_LINES=127;
+VAR	lut: 	ARRAY[0..MAPXSIZE,0..MAPYSIZE,0..1] OF BYTE;
+
+
+FUNCTION Min(a,b: INTEGER): INTEGER;
+BEGIN
+	IF a<b THEN Min:=a ELSE Min:=b;
+END;
+
+FUNCTION Max(a,b: INTEGER): INTEGER;
+BEGIN
+	IF a>b THEN Max:=a ELSE Max:=b;
+END;
+
+
+PROCEDURE MakeLut;
+VAR	a,d,x,y,lx,ly,dx,dy,ile: INTEGER;
+	s,c,an: REAL;
+BEGIN
+
+	FOR x:=0 TO MAPXSIZE DO
+		FOR y:=0 TO MAPYSIZE DO BEGIN
+			lut[x,y][0]:=255;
+			lut[x,y][1]:=0;
+		END;
+
+	FOR a:=0 TO LOS_LINES DO BEGIN
+		an:=(a*PI)/(los_lines*2);
+		s:=Sin(an)/4;
+		c:=Cos(an)/4;
+		lx:=0;
+		ly:=0;
+		d:=0;
+		REPEAT
+			x:=Trunc(s*d);
+			y:=Trunc(c*d);
+			
+			dx:=(x-lx);
+			dy:=(y-ly);
+			IF (x<=MAPXSIZE) AND (y<=MAPYSIZE) THEN BEGIN
+				lut[x,y][0]:=Min(lut[x,y][0],a);
+				lut[x,y][1]:=Max(lut[x,y][0],a);
+			END;
+			Inc(d);
+		UNTIL (x>MAPXSIZE) OR (y>MAPYSIZE);
+	END;
+END;
+
+
+PROCEDURE ApplyFov(cx,cy: INTEGER);
+VAR	rays: ARRAY[0..LOS_LINES] OF BOOLEAN;
+	x,y: INTEGER;
+	i,f,t: BYTE;
+	bl: BOOLEAN;
+	pow: BOOLEAN;
+	m: pMap;
+
+BEGIN
+	FOR i:=0 TO LOS_LINES DO rays[i]:=TRUE;
+	
+	FOR y:=cy TO MAPYSIZE DO
+		FOR x:=cx TO MAPXSIZE DO BEGIN
+			m:=GetMap(x,y);
+			pow:=FALSE;
+
+			bl:=(m^.ter^.vis<50);
+			
+			f:=lut[x-cx,y-cy][0];
+			t:=lut[x-cx,y-cy][1];
+			
+			FOR i:=f TO t DO IF rays[i] THEN BEGIN
+				pow:=TRUE;
+				IF NOT bl THEN rays[i]:=FALSE;
+			END;
+
+			IF pow  THEN BEGIN
+				m^.flg:=m^.flg+[MAP_VISIBLE];
+				m^.flg:=m^.flg+[MAP_EXPLORED];
+			END ELSE m^.flg:=m^.flg-[MAP_VISIBLE];
+		END;
+
+	FOR i:=0 TO LOS_LINES DO rays[i]:=TRUE;
+	
+	FOR y:=cy DOWNTO 0 DO
+		FOR x:=cx TO MAPXSIZE DO BEGIN
+			m:=GetMap(x,y);
+			pow:=FALSE;
+
+			bl:=(m^.ter^.vis<50);
+			
+			f:=lut[x-cx,cy-y][0];
+			t:=lut[x-cx,cy-y][1];
+			
+			FOR i:=f TO t DO IF rays[i] THEN BEGIN
+				pow:=TRUE;
+				IF NOT bl THEN rays[i]:=FALSE;
+			END;
+
+			IF pow  THEN BEGIN
+				m^.flg:=m^.flg+[MAP_VISIBLE];
+				m^.flg:=m^.flg+[MAP_EXPLORED];
+			END ELSE m^.flg:=m^.flg-[MAP_VISIBLE];
+		END;
+
+	FOR i:=0 TO LOS_LINES DO rays[i]:=TRUE;
+	
+	FOR y:=cy TO MAPYSIZE DO
+		FOR x:=cx DOWNTO 0 DO BEGIN
+			m:=GetMap(x,y);
+
+			pow:=FALSE;   
+			bl:=(m^.ter^.vis<50);
+			
+			f:=lut[cx-x,y-cy][0];
+			t:=lut[cx-x,y-cy][1];
+			
+			FOR i:=f TO t DO IF rays[i] THEN BEGIN
+				pow:=TRUE;
+				IF NOT bl THEN rays[i]:=FALSE;
+			END;
+
+			IF pow  THEN BEGIN
+				m^.flg:=m^.flg+[MAP_VISIBLE];
+				m^.flg:=m^.flg+[MAP_EXPLORED];
+			END ELSE m^.flg:=m^.flg-[MAP_VISIBLE];
+		END;
+
+	FOR i:=0 TO LOS_LINES DO rays[i]:=TRUE;
+	
+	FOR y:=cy DOWNTO 0 DO
+		FOR x:=cx DOWNTO 0 DO BEGIN
+			m:=GetMap(x,y);
+			pow:=FALSE;
+
+			bl:=(m^.ter^.vis<50);
+			
+			f:=lut[cx-x,cy-y][0];
+			t:=lut[cx-x,cy-y][1];
+			
+			FOR i:=f TO t DO IF rays[i] THEN BEGIN
+				pow:=TRUE;
+				IF NOT bl THEN rays[i]:=FALSE;
+			END;
+
+			IF pow  THEN BEGIN
+				m^.flg:=m^.flg+[MAP_VISIBLE];
+				m^.flg:=m^.flg+[MAP_EXPLORED];
+			END ELSE m^.flg:=m^.flg-[MAP_VISIBLE];
+		END;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/maps.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,118 @@
+{ Map scrolling and display routines. }
+
+{$Q+R+}
+
+UNIT Maps;
+
+INTERFACE
+USES Global;
+
+VAR	  xMapShift, yMapShift: INTEGER;
+PROCEDURE Refresh;
+PROCEDURE CenterMap(x,y:INTEGER);
+PROCEDURE ReLight(px,py: INTEGER);
+PROCEDURE ShowPlayer(x,y: INTEGER);
+PROCEDURE Demolish(m: pMap);
+FUNCTION  FreeToMove(m: pMap): BOOLEAN;
+
+IMPLEMENTATION
+
+USES Console, Items, Light;
+
+FUNCTION FreeToMove(m: pMap): BOOLEAN;
+BEGIN
+	FreeToMove:=FALSE;
+	
+	IF m=NIL THEN Exit;
+	IF m^.crt<>NIL THEN Exit;
+	IF m^.ter^.mov>=100 THEN Exit;
+
+	FreeToMove:=TRUE;
+END;
+
+PROCEDURE ShowMap(x,y:INTEGER);
+VAR	a:BYTE;
+	c:CHAR;
+	m:pMap;
+BEGIN
+	IF NOT InMap(x,y) THEN BEGIN
+		PutChr(x-xMapShift,y-yMapShift,' ',$07);
+		Exit;
+	END;
+	m:=GetMap(x,y);
+	
+	IF (x-xMapShift<0) OR (x-xMapShift>49) OR (y-yMapShift<0) OR (y-yMapShift>24) THEN Exit;
+
+	a:=m^.ter^.atr;
+	c:=m^.ter^.chr;
+
+	IF (TILE_SMARTDOOR IN m^.ter^.flg) THEN
+		IF (x=0) OR (x=MAPXSIZE) OR
+		(GetMap(x-1,y)^.ter^.mov>=100) OR
+		(GetMap(x+1,y)^.ter^.mov>=100) THEN c:='-';
+
+	IF (m^.ter^.vis<30) AND (y>0)AND
+	   (GetMap(x,y-1)^.ter^.vis>=30) THEN BEGIN
+		CASE a OF
+			15: a:=7;
+			13: a:=14;
+			 8: a:=8;
+			 7: a:=8;
+			ELSE a:=a AND $F7;
+		END;
+	END;		
+
+
+	IF NOT(MAP_EXPLORED IN m^.flg) THEN c:=' ';
+
+	IF NOT(MAP_VISIBLE IN m^.flg) THEN a:=shadecolor ELSE BEGIN
+		IF (m^.slt<>NIL)
+		{AND (TILE_ITEM IN m^.ter^.flg)}
+			THEN GetItemLooks(a,c,@(m^.slt));
+		IF (m^.crt<>NIL) THEN BEGIN
+			a:=m^.crt^.def^.atr;
+			c:=m^.crt^.def^.chr;
+		END;
+	END;
+
+
+	PutChr(x-xMapShift,y-yMapShift,c,a);
+END;
+
+PROCEDURE Demolish(m: pMap);
+BEGIN
+	IF m^.ter^.dst=0 THEN Exit;
+	IF (m^.ter^.drp>0) AND (m^.slt=NIL) THEN BEGIN
+		m^.slt:=GenerateItem(m^.ter^.drp);
+	END;
+	m^.ter:=FindTile(m^.ter^.dst);
+END;
+
+PROCEDURE Refresh;
+VAR	x,y: INTEGER;
+BEGIN
+	FOR y:=0 TO 24 DO
+		FOR x:=0 TO 49 DO ShowMap(x+xMapShift,y+yMapShift);
+END;
+
+PROCEDURE CenterMap(x,y:INTEGER);
+BEGIN
+	xMapShift:=x-25;
+	yMapShift:=y-12;
+	Refresh;
+END;
+
+PROCEDURE ShowPlayer(x,y: INTEGER);
+BEGIN
+		IF NOT InMap(x,y) THEN Exit;
+		IF (x-xMapShift<MARGIN) OR (x-xMapShift>49-MARGIN) OR (y-yMapShift<MARGIN) OR (y-yMapShift>24-MARGIN) THEN CenterMap(x,y);
+		Cursor(x-xMapShift,y-yMapShift);
+END;
+
+PROCEDURE ReLight(px,py: INTEGER);
+BEGIN
+	ApplyFov(px,py);
+	Refresh;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,158 @@
+{ File i/o and parsing routines. }
+
+UNIT Parser;
+
+INTERFACE
+
+USES Gzio;
+
+CONST	REMCHAR='#';
+	REMEND=#13;
+	STRCHAR='"';
+	VRBCHAR='\';
+
+{ TYPE	CfgFile=FILE OF CHAR; }
+TYPE	CfgFile=gzFile;
+
+CONST	PARSE_NOERROR=0;
+	PARSE_ERR_EOF=1;
+	PARSE_ERR_NUM=2;
+	PARSE_ERR_STR=3;
+	PARSE_ERR_NAM=4;
+	PARSE_ERR_OPN=5;
+
+VAR	 errNum:BYTE;
+         actLine: WORD;
+FUNCTION ReadName(VAR f:CfgFile):STRING;
+FUNCTION ReadString(VAR f:CfgFile):STRING;
+FUNCTION ReadNumber(VAR f:CfgFile):INTEGER;
+PROCEDURE OpenCfg(VAR f:CfgFile; name: STRING);
+PROCEDURE CloseCfg(VAR f:CfgFile);
+
+IMPLEMENTATION
+
+CONST CHR_EOF=#26;
+
+PROCEDURE OpenCfg(VAR f:CfgFile; name: STRING);
+BEGIN
+	actLine:=1;
+	errNum:=PARSE_NOERROR;
+	
+	f:=gzOpen(name,'r');
+	IF f=NIL THEN BEGIN
+		errNum:=PARSE_ERR_OPN;
+		WriteLn('Can''t open ',name);
+	END;	
+END;
+
+PROCEDURE CloseCfg(VAR f:CfgFile);
+BEGIN
+	IF gzClose(f)>0 THEN errNum:=PARSE_ERR_OPN;	
+END;
+
+FUNCTION ReadChr(VAR f:CfgFile): CHAR;
+VAR	c: CHAR;
+	b: INTEGER;
+BEGIN
+	b:=gzGetC(f);
+	
+	IF (b<0) OR (b>255) OR (c=CHR_EOF) THEN BEGIN
+		errNum:=PARSE_ERR_EOF;
+		c:=CHR_EOF;
+	END ELSE c:=Chr(b);
+	
+	IF c=#13 THEN Inc(actLine);
+	ReadChr:=c;
+END;
+
+FUNCTION IsEmpty(c:CHAR):BOOLEAN;
+BEGIN
+	IsEmpty:=(c=' ') OR (c=#9) OR (c=#13) OR (c=#10) OR (c=CHR_EOF);
+END;
+
+FUNCTION ReadName(VAR f:CfgFile):STRING;
+VAR	s: STRING;
+	c: CHAR;
+BEGIN
+	ReadName:='';
+	REPEAT
+		c:=ReadChr(f);
+		IF c=REMCHAR THEN BEGIN
+			REPEAT
+				c:=ReadChr(f);
+			UNTIL (c=REMEND) OR (c=CHR_EOF);
+			IF (c<>CHR_EOF) THEN c:=' ';
+		END;
+	UNTIL (NOT IsEmpty(c)) OR (c=CHR_EOF);
+	s:='';
+	WHILE NOT IsEmpty(c) DO BEGIN
+		s:=Concat(s,UpCase(c));
+		c:=ReadChr(f);
+	END;
+	IF s='' THEN errNum:=PARSE_ERR_NAM;
+	ReadName:=s;
+END;
+
+FUNCTION ReadString(VAR f:CfgFile):STRING;
+VAR	s: STRING;
+	c: CHAR;
+BEGIN
+	ReadString:='';
+	REPEAT
+		c:=ReadChr(f);
+		IF c=REMCHAR THEN BEGIN
+			REPEAT
+				c:=ReadChr(f);
+			UNTIL (c=REMEND) OR (c=CHR_EOF);
+			IF (c<>CHR_EOF) THEN c:=' ';
+		END;
+	UNTIL (NOT IsEmpty(c)) OR (c=CHR_EOF);
+	s:='';
+	IF c<>STRCHAR THEN BEGIN
+		errNum:=PARSE_ERR_STR;
+	END ELSE BEGIN
+		REPEAT
+			c:=ReadChr(f);
+			IF c=STRCHAR THEN Break;
+			IF c=#13 THEN BEGIN
+				ErrNum:=PARSE_ERR_STR;
+				Exit;
+			END;
+			IF c=CHR_EOF THEN Exit;
+			IF c=VRBCHAR THEN BEGIN
+				c:=ReadChr(f);
+			END;
+			s:=Concat(s,c);
+		UNTIL FALSE;
+	END;
+	ReadString:=s;
+END;
+
+FUNCTION ReadNumber(VAR f:CfgFile):INTEGER;
+VAR	s: STRING;
+	c: CHAR;
+	i,j: INTEGER;
+BEGIN
+	ReadNumber:=0;
+	REPEAT
+		c:=ReadChr(f);
+		IF c=REMCHAR THEN BEGIN
+			REPEAT
+				c:=ReadChr(f);
+			UNTIL (c=REMEND) OR (c=CHR_EOF);
+			IF (c<>CHR_EOF) THEN c:=' ';
+		END;
+	UNTIL (NOT IsEmpty(c)) OR (c=CHR_EOF);
+	s:='';
+	WHILE NOT IsEmpty(c) DO BEGIN
+		s:=Concat(s,UpCase(c));
+		c:=ReadChr(f);
+	END;
+	Val(s,i,j);
+	IF j=0 THEN ReadNumber:=i
+		ELSE BEGIN
+			errNum:=PARSE_ERR_NUM;
+		END;
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/player.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,374 @@
+{ Player character handling routines. }
+
+UNIT Player;
+
+INTERFACE
+
+PROCEDURE Play;
+PROCEDURE GeneratePlayer;
+PROCEDURE ShowStats;
+
+IMPLEMENTATION
+
+USES Global, Console, Level, Items, Maps, Creature, Save, Porting;
+
+PROCEDURE CheckCmd(VAR a:INTEGER;c:CHAR;b:BYTE);
+BEGIN
+	IF c=cmd[b] THEN a:=b;
+END;
+
+
+PROCEDURE ShowStats;
+VAR	s: STRING;
+	n: STRING[8];
+BEGIN
+	s:=stat_string;
+	n:=playchr^.def^.nam+'        ';
+	s:=Replace(s,'@v',n);
+	s:=Replace(s,'@1',Number(playchr^.hp));
+	s:=Replace(s,'@2',Number(playchr^.def^.hp));
+	s:=Replace(s,'@3',Number(pc.stats[2]));	
+	s:=Replace(s,'@4',Number(pc.stats[3]));
+	s:=Replace(s,'@5',Number(pc.stats[4]));
+	s:=Replace(s,'@6',Number(pc.stats[5]));	
+	s:=Replace(s,'@7',Number(pc.stats[6]));
+	s:=Replace(s,'@8',Number(pc.stats[7]));
+	s:=Replace(s,'@9',Number(pc.stats[8]));
+	s:=Replace(s,'@0',Number(pc.stats[9]));
+	Stat(s);
+END;
+
+
+PROCEDURE Aim(VAR x,y: INTEGER; near:BOOLEAN);
+VAR	c: CHAR;
+	b,nx,ny: INTEGER;
+BEGIN
+	IF NOT InMap(x,y) THEN Exit;
+	REPEAT
+		GotoXY(x-xMapShift,y-yMapShift);
+		c:=GetKey;
+		b:=CMDNOTHING;
+		CheckCmd(b,c,CMDSOUTHWEST);
+		CheckCmd(b,c,CMDSOUTHWEST);
+		CheckCmd(b,c,CMDSOUTH);
+		CheckCmd(b,c,CMDSOUTHEAST);
+		CheckCmd(b,c,CMDWEST);
+		CheckCmd(b,c,CMDEAST);
+		CheckCmd(b,c,CMDNORTHWEST);
+		CheckCmd(b,c,CMDNORTH);
+	   	CheckCmd(b,c,CMDNORTHEAST);
+		IF b=CMDNOTHING THEN Exit;
+		IF InMap(x+DIRX[b],y+DIRY[b])  AND
+			(x-xMapShift+DIRX[b]>0 ) AND
+			(x-xMapShift+DIRX[b]<49) AND
+			(y-yMapShift+DIRY[b]>0 ) AND
+			(y-yMapShift+DIRY[b]<24) THEN BEGIN;
+				Inc(x,DIRX[b]);
+				Inc(y,DIRY[b]);
+		END;
+		IF (x-xMapShift<MARGIN) OR (x-xMapShift>49-MARGIN) OR (y-yMapShift<MARGIN) OR (y-yMapShift>24-MARGIN) THEN CenterMap(x,y);
+	UNTIL near;
+END;
+
+PROCEDURE Wait(t:INTEGER);
+BEGIN
+{	IF (TILE_BURN IN GetMap(playchr^.x,playchr^.y)^.ter^.flg) THEN BEGIN
+		Msg(msgs[23]);
+	END;
+
+	IF (TILE_SWIM IN GetMap(playchr^.x,playchr^.y)^.ter^.flg) THEN BEGIN
+		Msg(msgs[24]);
+	END;}
+
+	Inc(playchr^.mov,t);
+END;
+
+PROCEDURE DoWait;
+BEGIN
+	Msg(msgs[11]);
+	CenterMap(playchr^.x,playchr^.y);
+	Wait(50);
+END;
+
+PROCEDURE DoBash(x,y: INTEGER);
+VAR	m: pMap;
+BEGIN
+	IF pc.crouch THEN BEGIN
+		Msg(msgs[28]);
+		Exit;
+	END;
+
+	m:=GetMap(x,y);
+
+	IF m^.crt<>NIL THEN BEGIN
+		Msg(Replace(msgs[2],'@v',m^.crt^.def^.nam));
+	END ELSE BEGIN
+		Msg(Replace(msgs[3],'@v',m^.ter^.nam));
+		Demolish(m);
+		Wait(100);
+	END;
+END;
+
+
+PROCEDURE DoOperate(x,y: INTEGER);
+VAR	m: pMap;
+BEGIN
+	m:=GetMap(x,y);
+	
+	IF NOT (TILE_OPERATE IN m^.ter^.flg) THEN BEGIN
+		Msg(msgs[7]);
+		Exit;
+	END;
+	IF m^.ter^.chn>0 THEN BEGIN
+		m^.ter:=FindTile(m^.ter^.chn);
+
+		Wait(60);
+	END;
+END;
+
+PROCEDURE DoWalk(x,y: INTEGER);
+BEGIN
+	IF NOT InMap(x,y) THEN Exit;
+	IF (GetMap(x,y)^.ter^.mov>=100) THEN Exit;
+	IF pc.crouch THEN BEGIN
+		Msg(msgs[25]);
+		Wait(50);
+	END;
+	MoveMonster(x,y,playchr);
+	ShowItem(@(GetMap(x,y)^.slt));
+END;
+
+PROCEDURE DoLook(x,y: INTEGER);
+VAR	m: pMap;
+BEGIN
+	m:=GetMap(x,y);
+	IF (MAP_EXPLORED IN m^.flg) THEN Msg(Replace(msgs[5],'@v',m^.ter^.nam))
+		ELSE Msg(msgs[14]);	
+	IF (MAP_VISIBLE  IN m^.flg) AND (m^.slt<>NIL) THEN ShowItem(@(m^.slt));
+	IF (MAP_VISIBLE  IN m^.flg) AND (m^.crt<>NIL) THEN ShowMonster(m);
+END;
+
+
+PROCEDURE DoEnter;
+BEGIN
+	IF NOT (TILE_ENTER IN GetMap(playchr^.x,playchr^.y)^.ter^.flg) THEN BEGIN
+		Msg(msgs[8]);
+		Exit;
+	END;
+	GenerateLevel;
+
+	{IF pc.intown THEN GenerateLevel ELSE TownMap;
+	pc.intown:=NOT pc.intown;}
+
+	
+	CenterMap(playchr^.x,playchr^.y);
+END;
+
+PROCEDURE DoInfo;
+VAR	s: STRING;
+	l: LONGINT;
+BEGIN
+	l:=MemAvail;
+	Str(l,s);
+	Msg(Concat('Memory: @M',s));
+	Msg(Concat('Time: @M',Num(gametime)));
+END;
+
+
+PROCEDURE DoHelp;
+VAR l: INTEGER;
+BEGIN
+	FOR l:=0 TO MAXLONGSTRING DO
+		IF help_string[l]<>'' THEN Msg(help_string[l]);
+END;
+
+PROCEDURE DoDie;
+VAR l: INTEGER;
+BEGIN
+	FOR l:=0 TO MAXLONGSTRING DO
+		IF death_string[l]<>'' THEN Msg(death_string[l]);
+END;
+
+PROCEDURE DoSkills;
+BEGIN
+	Msg('Skills...');
+END;
+
+PROCEDURE DoCrouch;
+BEGIN
+	IF pc.crouch THEN BEGIN
+		pc.crouch:=FALSE;
+	   	Msg(msgs[27]);
+	   	Wait(50);
+	END ELSE BEGIN
+		pc.crouch:=TRUE;
+	   	Msg(msgs[26]);
+	   	Wait(50);
+	END;
+END;
+
+PROCEDURE DoPickup;
+VAR	m:pMap;
+BEGIN
+	m:=GetMap(playchr^.x,playchr^.y);
+	IF m^.slt=NIL THEN BEGIN
+		Msg(msgs[9]);
+		Exit;
+	END;
+
+	IF m^.slt^.def^.id=PILEITEM THEN BEGIN
+		SelectItem(ListItems(@(m^.slt)));
+		CheckPile(@(m^.slt));
+	END ELSE BEGIN
+		SelectItem(@(m^.slt));
+	END;
+END;
+
+PROCEDURE DoPack;
+VAR	m:pMap;
+BEGIN
+	m:=GetMap(playchr^.x,playchr^.y);
+	
+	IF m^.slt=NIL THEN BEGIN
+		Msg(msgs[9]);
+		Exit;
+	END;
+
+	IF m^.slt^.def^.id=PILEITEM THEN BEGIN
+		PutToPack(ListItems(@m^.slt));
+		CheckPile(@(m^.slt));
+	END ELSE BEGIN
+		PutToPack(@(m^.slt));
+	END;
+END;
+
+PROCEDURE DoShoot(x,y: INTEGER);
+BEGIN
+	BulletFly(playchr^.x,playchr^.y,x,y);
+END;
+
+PROCEDURE Play;
+VAR	c: CHAR;
+	x,y,d: INTEGER;
+	s: STRING;
+
+BEGIN
+		ReLight(playchr^.x,playchr^.y);
+
+		ShowPlayer(playchr^.x,playchr^.y);
+
+		c:=GetKey;
+		y:=CMDNOTHING;
+		CheckCmd(y,c,CMDSOUTHWEST);
+		CheckCmd(y,c,CMDSOUTHWEST);
+		CheckCmd(y,c,CMDSOUTH);
+		CheckCmd(y,c,CMDSOUTHEAST);
+		CheckCmd(y,c,CMDWEST);
+		CheckCmd(y,c,CMDEAST);
+		CheckCmd(y,c,CMDNORTHWEST);
+		CheckCmd(y,c,CMDNORTH);
+	   	CheckCmd(y,c,CMDNORTHEAST);
+	
+		CheckCmd(y,c,CMDHERE);
+		CheckCmd(y,c,CMDLOOK);
+		CheckCmd(y,c,CMDOPERATE);
+		CheckCmd(y,c,CMDBASH);
+		CheckCmd(y,c,CMDENTER);
+		CheckCmd(y,c,CMDPICKUP);
+		CheckCmd(y,c,CMDEXAM);
+		CheckCmd(y,c,CMDINFO);
+		CheckCmd(y,c,CMDCROUCH);
+		CheckCmd(y,c,CMDPACK);
+		CheckCmd(y,c,CMDINVEN);
+		CheckCmd(y,c,CMDSKILLS);
+		CheckCmd(y,c,CMDAIM);
+
+		CheckCmd(y,c,CMDQUIT);
+		CheckCmd(y,c,CMDHELP);
+		CheckCmd(y,c,CMDSAVE);
+		
+		CASE y OF
+			CMDSAVE: SaveGame;
+			CMDQUIT:BEGIN
+					DoDie;
+					GetKey;
+					ResetScr;
+					HALT;
+				END;
+			CMDNOTHING: Msg(msgs[0]);
+CMDSOUTHWEST,CMDSOUTH,CMDSOUTHEAST,CMDWEST,CMDEAST,CMDNORTHWEST,CMDNORTH,CMDNORTHEAST: BEGIN
+					x:=playchr^.x+DIRX[y];
+					y:=playchr^.y+DIRY[y];
+					IF InMap(x,y) THEN BEGIN
+						IF  GetMap(x,y)^.crt<>NIL THEN DoBash(x,y)
+						ELSE BEGIN
+							IF (GetMap(x,y)^.ter^.mov>=100) THEN BEGIN
+								IF (TILE_OPERATE IN GetMap(x,y)^.ter^.flg) THEN DoOperate(x,y) ELSE
+									IF (TILE_FRAGILE IN GetMap(x,y)^.ter^.flg) AND NOT pc.crouch THEN DoBash(x,y);
+							END ELSE DoWalk(x,y);
+						END;
+					END;
+				END;
+			CMDHERE:DoWait;
+			CMDHELP:DoHelp;
+			CMDLOOK:BEGIN
+					Msg(msgs[4]);
+					x:=playchr^.x;
+					y:=playchr^.y;
+					Aim(x,y,FALSE);
+					IF (x=playchr^.x) AND (y=playchr^.y) THEN Msg(msgs[10])
+						ELSE DoLook(x,y);
+				END;
+			CMDOPERATE:BEGIN
+					Msg(msgs[6]);
+					x:=playchr^.x;
+					y:=playchr^.y;
+					Aim(x,y,TRUE);
+					IF (x=playchr^.x) AND (y=playchr^.y) THEN Msg(msgs[10])
+						ELSE DoOperate(x,y);
+				   END;
+			CMDBASH:   BEGIN
+					Msg(msgs[21]);
+					x:=playchr^.x;
+					y:=playchr^.y;
+					Aim(x,y,TRUE);
+				       	IF (x=playchr^.x) AND (y=playchr^.y) THEN Msg(msgs[10])
+						ELSE DoBash(x,y);
+				   END;
+			CMDENTER:  DoEnter;
+			CMDEXAM:   ExamInv;
+			CMDPICKUP: DoPickup;
+			CMDINFO:   DoInfo;
+			CMDCROUCH: DoCrouch;
+			CMDSKILLS: DoSkills;
+			CMDPACK: IF (pc.inv[1]<>NIL) AND (ITEM_EMPTY IN pc.inv[1]^.def^.flg) THEN DoPack
+			 							             ELSE Msg(msgs[31]);
+			CMDINVEN: IF (pc.inv[1]<>NIL) AND (ITEM_EMPTY IN pc.inv[1]^.def^.flg) THEN BEGIN
+					IF pc.inv[1]^.con<>NIL THEN SelectItem(ListItems(@pc.inv[1]))
+							       ELSE Msg(msgs[9]);
+				  END ELSE Msg(msgs[31]);
+				  
+			CMDAIM:	   BEGIN
+				   	Msg(msgs[1]);
+					x:=playchr^.x;
+					y:=playchr^.y;
+					Aim(x,y,FALSE);
+					IF (x=playchr^.x) AND (y=playchr^.y) THEN Msg(msgs[10])
+						ELSE DoShoot(x,y);
+				   END;
+		END;
+END;
+
+
+PROCEDURE GeneratePlayer;
+VAR	s:STRING;
+BEGIN
+	playchr:=GenerateMonster(0);
+	Msg(msgs[35]);
+	REPEAT
+		s:=GetString(8);
+	UNTIL s<>'';
+	playchr^.def^.nam:=Capitalize(s);
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/porting.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,167 @@
+{ All system-dependant procedures should be here. }
+
+UNIT Porting;
+
+INTERFACE
+
+CONST	pal_changed:BOOLEAN=FALSE;	{ Is palette changed? }
+
+	KEYCHR_DIR1=#131;		{ Key codes for special keys. }
+	KEYCHR_DIR2=#132;
+	KEYCHR_DIR3=#133;
+	KEYCHR_DIR4=#134;
+	KEYCHR_DIR5=#135;
+	KEYCHR_DIR6=#136;
+	KEYCHR_DIR7=#137;
+	KEYCHR_DIR8=#138;
+	KEYCHR_DIR9=#139;	
+	KEYCHR_CR=#13;
+	KEYCHR_BS=#8;
+	KEYCHR_TAB=#9;
+
+TYPE 	PalAry=ARRAY[0..15] OF RECORD r,g,b:BYTE END;
+
+PROCEDURE PutChar(x,y:BYTE;chr:CHAR;atr:BYTE);	{ Displays specified character on the screen. }
+PROCEDURE GotoXY(x,y:BYTE);			{ Moves cursor. }
+FUNCTION  GetChr: CHAR;				{ Reads a key from standard input. }
+PROCEDURE ChPal(Pal:PalAry);			{ Changes color palette, remembers the old one. }
+PROCEDURE ResetPal;				{ Changes palette to the old one. }
+PROCEDURE ScrollWin(x1,y1,x2,y2:BYTE);		{ Scrolls part of screen. }
+
+IMPLEMENTATION
+
+TYPE	ScrChr=RECORD
+		chr: CHAR;
+		atr: BYTE;
+	END;
+
+VAR	Screen: ARRAY[0..24,0..79] OF ScrChr ABSOLUTE $B800:0000;	{ Video memory. }
+	OldPal: ARRAY[0..15] OF BYTE;
+	OldRGB: ARRAY[0..15] OF RECORD r,g,b: BYTE END;
+
+PROCEDURE SetPal(i:WORD;p:BYTE);ASSEMBLER;
+ASM
+	MOV AH, 10h
+	MOV AL, 00h
+	MOV BX, i
+	MOV BH, p
+	INT 10h
+END;
+
+FUNCTION GetPal(i:BYTE):BYTE;ASSEMBLER;
+ASM
+	MOV AH, 10h
+	MOV AL, 07h
+	MOV BL, i
+	INT 10h
+	MOV AL,BH
+END;
+
+PROCEDURE GetRGB(i:WORD; VAR r,g,b: BYTE);
+VAR	sr,sg,sb: BYTE;
+BEGIN
+	ASM
+		MOV AH, 10h
+		MOV AL, 15h
+		MOV BX, i
+		INT 10h
+		MOV sr, DH
+		MOV sg, CH
+		MOV sb, CL
+	END;
+	r:=sr;
+	g:=sg;
+	b:=sb;
+END;
+
+PROCEDURE SetRGB(i:WORD;r,g,b:BYTE);ASSEMBLER;
+ASM
+	MOV AH, 10h
+	MOV AL, 10h
+	MOV BX, i
+	MOV DH, r
+	MOV CH, g
+	MOV CL, b
+	INT 10h
+END;
+
+FUNCTION GetChr: CHAR;
+VAR	l:CHAR;
+	h:BYTE;
+BEGIN
+	ASM
+		MOV AH,00h
+		INT 16h
+		MOV l,AL
+		MOV h,AH
+	END;
+	IF l=#0 THEN CASE h OF
+		71: l:=KEYCHR_DIR7;
+		72: l:=KEYCHR_DIR8;
+		73: l:=KEYCHR_DIR9;
+
+		75: l:=KEYCHR_DIR4;
+		76: l:=KEYCHR_DIR5;
+		77: l:=KEYCHR_DIR6;
+
+		79: l:=KEYCHR_DIR1;
+		80: l:=KEYCHR_DIR2;
+		81: l:=KEYCHR_DIR3;
+	END;
+	GetChr:=l;
+END;
+
+PROCEDURE PutChar(x,y:BYTE;chr:CHAR;atr:BYTE);
+BEGIN
+	IF (x>79) OR (y>24) THEN Exit;
+	Screen[y,x].chr:=chr;
+	Screen[y,x].atr:=atr;
+END;
+
+PROCEDURE GotoXY(x,y:BYTE);
+BEGIN
+	IF (x>79) OR (y>24) THEN Exit;
+	ASM
+		MOV AH,02h
+		MOV BH,00h
+		MOV DL,x
+		MOV DH,y
+		INT 10h
+	END;
+END;
+
+PROCEDURE ChPal(Pal:PalAry);
+VAR i: BYTE;
+BEGIN
+	pal_changed:=TRUE;
+	FOR i:=0 TO 15 DO BEGIN
+		OldPal[i]:=GetPal(i);
+		SetPal(i,i);
+		GetRGB(i,OldRGB[i].r,OldRGB[i].g,OldRGB[i].b);
+		SetRGB(i,Pal[i].r,Pal[i].g,Pal[i].b);
+	END;
+END;
+
+PROCEDURE ResetPal;
+VAR	i:INTEGER;
+BEGIN
+	IF NOT pal_changed THEN Exit;
+	FOR i:=0 TO 15 DO BEGIN
+		SetPal(i,OldPal[i]);
+		SetRGB(i,OldRGB[i].r,OldRGB[i].g,OldRGB[i].b);
+	END;
+END;
+
+PROCEDURE ScrollWin(x1,y1,x2,y2:BYTE); ASSEMBLER;
+ASM			
+	MOV AH,06h
+	MOV AL,01h
+	MOV BH,$07;
+	MOV CL,x1
+	MOV CH,y1
+	MOV DL,x2
+	MOV DH,y2
+	INT 10h
+END;
+
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/r.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,82 @@
+{ Main loop. }
+
+USES Global, Config, Console, Level, Light, Player, Creature, Save;
+
+PROCEDURE FillNills;
+VAR	x,y: INTEGER;
+	m: pMap;
+BEGIN
+	New(mappa);
+	FOR y:=0 TO MAPYSIZE DO
+		FOR x:=0 TO MAPXSIZE DO	BEGIN
+			m:=GetMap(x,y);
+			m^.slt:=NIL;
+			m^.crt:=NIL;
+		END;
+	FOR x:=0 TO MAXSLOT DO pc.inv[x]:=NIL;
+	allmonsters:=NIL;
+	playchr:=NIL;
+	gametime:=0;
+END;
+
+PROCEDURE HandleMonsters;
+VAR	creat: pCreat;
+	i: INTEGER;
+BEGIN
+	playchr^.mov:=0;
+	Play;
+	Inc(gametime,playchr^.mov);
+
+	creat:=allmonsters;
+	WHILE creat<>NIL DO BEGIN
+		i:=0;
+		WHILE (creat^.mov<=gametime)AND (i<2) DO BEGIN
+			MonsterAI(creat);
+			Inc(i);
+		END;
+		creat:=creat^.next;
+	END;
+END;
+
+PROCEDURE NewGame;
+BEGIN
+	GeneratePlayer;
+	GenerateLevel;
+{	TownMap;}
+END;
+
+PROCEDURE MainMenu;
+VAR	l: INTEGER;
+	c: CHAR;
+BEGIN
+	Cursor(79,0);
+	FOR l:=0 TO MAXLONGSTRING DO
+		IF menu_string[l]<>'' THEN Msg(menu_string[l]);
+	REPEAT
+		c:=GetKey;
+	UNTIL (c='n')OR(c='q'); { OR (c='l') }
+	ClrMsg;	
+	CASE c OF
+		'n':NewGame;
+		'l':LoadGame;		
+		'q':BEGIN
+			ResetScr;
+			Halt;
+		END;
+	END;
+END;
+
+BEGIN
+	Randomize;
+	FillNills;
+	PrepScr;
+	ClrMsg;
+	ClrTxt;
+	MakeLut;
+	ReadCfg;
+	MainMenu;
+	ShowStats;
+	REPEAT
+		HandleMonsters;
+	UNTIL FALSE;
+END.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/save.pas	Sun Dec 08 19:39:15 2013 +0100
@@ -0,0 +1,102 @@
+{ Save and load routines. }
+
+UNIT save;
+
+INTERFACE
+
+USES Global;
+
+PROCEDURE SaveGame;
+PROCEDURE LoadGame;
+
+IMPLEMENTATION
+
+USES Gzio, Strings, Console;
+
+CONST	NL=#13+#10;
+
+VAR	f: GzFile;
+
+PROCEDURE Sav(s:STRING);
+VAR	t: pChar;
+BEGIN
+	s:=Concat(s,NL);
+	GzWrite(f,@(s[1]),Length(s));
+END;
+
+PROCEDURE SavePlayer;
+BEGIN
+	Sav('# Player character info:');
+	Sav('# ----------------------');
+	Sav(Concat('CHAR_ID ',playchr^.def^.nam));
+	Sav(Concat('CHAR_HP ',Num(playchr^.hp),' ',Num(playchr^.def^.hp)));
+	Sav(Concat('CHAR_POSITION ',Num(playchr^.x),' ',Num(playchr^.y)));
+END;
+
+PROCEDURE SaveLevel;
+BEGIN
+	Sav('# Level info:');
+	Sav('# -----------');
+
+END;
+
+PROCEDURE SaveKnowledge;
+BEGIN
+	Sav('# Items knowledge:');
+	Sav('# -----------');
+END;
+
+PROCEDURE SaveItems;
+BEGIN
+	Sav('# Items info:');
+	Sav('# -----------');
+END;
+
+PROCEDURE SaveMonsters;
+VAR	p: pCreat;
+BEGIN
+	Sav('# Creatures info:');
+	Sav('# ---------------');
+	p:=allmonsters;
+	WHILE p<>NIL DO BEGIN
+		Sav(Concat('MONSTER ',Num(p^.def^.id),' # ',p^.def^.nam));
+		Sav(Concat('MON_POSITION ',Num(p^.x),' ',Num(p^.x)));
+		Sav(Concat('MON_HP ',Num(p^.hp)));
+		Sav(Concat('MON_NEXTMOVE ',Num(p^.mov)));
+		p:=p^.next;
+	END;
+END;
+
+
+PROCEDURE SaveGame;
+BEGIN
+	Msg(msgs[34]);
+	
+	f:=GzOpen('savegame.gz','wf');
+	IF f=NIL THEN Exit;
+
+	Sav('# This is save file.');
+	Sav('# ==================');
+	
+	Sav(Concat('VERSION "',VERSION,'"'));
+
+	SavePlayer;
+	SaveKnowledge;
+	SaveItems;
+	SaveMonsters;
+	SaveLevel;
+
+		
+	Sav('# End of file.');
+	Sav('# ------------');
+	Sav('END');	
+	
+	GzFlush(f,1);
+	GzClose(f);
+END;
+
+PROCEDURE LoadGame;
+BEGIN
+END;
+
+END.
\ No newline at end of file