Mercurial > rg
diff items.pas @ 0:62966dd383ed default tip
initial
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Sun, 08 Dec 2013 19:39:15 +0100 |
| parents | |
| children |
line wrap: on
line diff
--- /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
