📄 madvent.asm
字号:
repeat MaxWeight
local NotThisOne
cmp bx, [di+ItemCnt]
jne NotThisOne
mov word ptr [di+ItemCnt], NULL
ret
NotThisOne:
ItemCnt = ItemCnt+2
endm
ret
RemoveItem endp
; InsertItem- BX contains a pointer to an item, DI contains a pointer to
; and item list. This routine searches through the list for
; the first empty spot and copies the value in BX to that point.
; It returns the carry set if it succeeds. It returns the
; carry clear if there are no empty spots available.
InsertItem proc
ItemCnt = 0
repeat MaxWeight
local NotThisOne
cmp word ptr [di+ItemCnt], 0
jne NotThisOne
mov [di+ItemCnt], bx
stc
ret
NotThisOne:
ItemCnt = ItemCnt+2
endm
clc
ret
InsertItem endp
; LongDesc- Long description of an item.
; DI points at an item - print the long description of it.
LongDesc proc
push di
test di, di
jz NoDescription
mov di, [di].item.LongDesc
puts
putcr
NoDescription: pop di
ret
LongDesc endp
; ShortDesc- Print the short description of an object.
; DI points at an item (possibly NULL). Print the short description for it.
ShortDesc proc
push di
test di, di
jz NoDescription
mov di, [di].item.ShortDesc
puts
putcr
NoDescription: pop di
ret
ShortDesc endp
; Describe: "CurRoom" points at the current room. Describe it and its
; contents.
Describe proc
push es
push bx
push di
mov di, ds
mov es, di
mov bx, CurRoom
mov di, [bx].room.Description
print
byte "You are currently ",0
puts
putcr
print
byte "Here you find the following:",cr,lf,0
; For each possible item in the room, print out the long description
; of that item. The repeat macro generates a code sequence for each
; possible item that could be in this room.
ItemCnt = 0
repeat MaxWeight
mov di, [bx].room.ItemList[ItemCnt]
call LongDesc
ItemCnt = ItemCnt+2
endm
pop di
pop bx
pop es
ret
Describe endp
; Here is the main program, which actually plays the game.
Main proc
mov ax, dseg
mov ds, ax
mov es, ax
meminit
print
byte cr,lf,lf,lf,lf,lf
byte "Welcome to ",'"MADVENTURE"',cr,lf
byte 'If you need help, type the command "HELP"'
byte cr,lf,0
RoomLoop: dec CurScore ;One point for each move.
jnz NotOverYet
; If they made too many moves without dropping anything properly, boot them
; out of the game.
print
byte "WHOA! You lost! You get to join the legions of "
byte "the totally lame",cr,lf
byte 'who have failed at "MADVENTURE"',cr,lf,0
jmp Quit
; Okay, tell 'em where they are and get a new command from them.
NotOverYet: putcr
call Describe
print
byte cr,lf
byte "Command: ",0
lesi InputLine
gets
strupr ;Ignore case by converting to U.C.
; Okay, process the command. Note that we don't actually check to see
; if there is a properly formed sentence. Instead, we just look to see
; if any important keywords are on the line. If they are, the pattern
; matching routines load the appropriate values into the noun and verb
; variables (nouns: north=1, south=2, east=3, west=4, lime=5, beer=6,
; card=7, sign=8, program=9, homework=10, money=11, form=12, coupon=13;
; verbs: go=1, get=2, drop=3, inventory=4, quit=5, help=6).
;
; This code uses the noun and verb variables as indexes into a two
; dimensional array whose elements contain the address of the code
; to process the given command. If a given command does not make
; any sense (e.g., "go coupon") the entry in the table points at the
; bad command code.
mov Noun, 0
mov Verb, 0
mov NounPtr, 0
ldxi VerbPat
xor cx, cx
match
lesi InputLine
ldxi NounPat
xor cx, cx
match
; Okay, index into the command table and jump to the appropriate
; handler. Note that we will cheat and use a 14x8 array. There
; are really only seven verbs, not eight. But using eight makes
; things easier since it is easier to multiply by eight than seven.
mov si, CurRoom ;The commands expect this here.
mov bx, Noun
shl bx, 3 ;Multiply by eight.
add bx, Verb
shl bx, 1 ;Multiply by two - word table.
jmp cseg:jmptbl[bx]
; The following table contains the noun x verb cross product.
; The verb values (in each row) are the following:
;
; NONE GO GET DROP INVNTRY QUIT HELP unused
; 0 1 2 3 4 5 6 7
;
; There is one row for each noun (plus row zero, corresponding to no
; noun found on line).
jmptbl word Bad ;No noun, no verb
word Bad ;No noun, GO
word Bad ;No noun, GET
word Bad ;No noun, DROP
word DoInventory ;No noun, INVENTORY
word QuitGame ;No noun, QUIT
word DoHelp ;No noun, HELP
word Bad ;N/A
NorthCmds word Bad, GoNorth, Bad, Bad, Bad, Bad, Bad, Bad
SouthCmds word Bad, GoSouth, Bad, Bad, Bad, Bad, Bad, Bad
EastCmds word Bad, GoEast, Bad, Bad, Bad, Bad, Bad, Bad
WestCmds word Bad, GoWest, Bad, Bad, Bad, Bad, Bad, Bad
LimeCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
BeerCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
CardCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
SignCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
ProgramCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
HomeworkCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
MoneyCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
FormCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
CouponCmds word Bad, Bad, GetItem, DropItem, Bad, Bad, Bad, Bad
; If the user enters a command we don't know how to process, print an
; appropriate error message down here.
Bad: printf
byte "I'm sorry, I don't understand how to '%s'\n",0
dword InputLine
jmp NotOverYet
; Handle the movement commands here.
; Movements are easy, all we've got to do is fetch the NORTH, SOUTH,
; EAST, or WEST pointer from the current room's data structure and
; set the current room to that address. The only catch is that some
; moves are not legal. Such moves have a NULL (zero) in the direction
; field. A quick check for this case handles illegal moves.
GoNorth: mov si, [si].room.North
jmp MoveMe
GoSouth: mov si, [si].room.South
jmp MoveMe
GoEast: mov si, [si].room.East
jmp MoveMe
GoWest: mov si, [si].room.West
MoveMe: test si, si ;See if move allowed.
jnz SetCurRoom
printf
byte "Sorry, you cannot go in this direction."
byte cr, lf, 0
jmp RoomLoop
SetCurRoom: mov CurRoom, si ;Move to new room.
jmp RoomLoop
; Handle the GetItem command down here. At this time the user
; has entered GET and some noun that the player can pick up.
; First, we will make sure that item is in this room.
; Then we will check to make sure that picking up this object
; won't overload the player. If these two conditions are met,
; we'll transfer the object from the room to the player.
GetItem: mov bx, NounPtr ;Ptr to item user wants.
mov si, CurRoom
lea di, [si].room.ItemList ;Ptr to item list in di.
call CheckPresence ;See if in room.
jc GotTheItem
printf
byte "Sorry, that item is not available here."
byte cr, lf, 0
jmp RoomLoop
; Okay, see if picking up this object will overload the player.
GotTheItem: mov ax, [bx].Item.Weight
add ax, CurWeight
cmp ax, MaxWeight
jbe WeightOkay
printf
byte "Sorry, you are already carrying too many items "
byte "to safely carry\nthat object\n",0
jmp RoomLoop
; Okay, everything's cool, transfer the object from the room to the user.
WeightOkay: mov CurWeight, ax ;Save new weight.
call RemoveItem ;Remove item from room.
lea di, ItemsOnHand ;Ptr to player's list.
call InsertItem
jmp RoomLoop
; Handle dropped objects down here.
DropItem: lea di, ItemsOnHand ;See if the user has
mov bx, NounPtr ; this item on hand.
call CheckPresence
jc CanDropIt1
printf
byte "You are not currently holding that item\n",0
jmp RoomLoop
; Okay, let's see if this is the magic room where this item is
; supposed to be dropped. If so, award the user some points for
; properly figuring this out.
CanDropIt1: mov ax, [bx].item.key
cmp ax, CurRoom
jne JustDropIt
; Okay, success! Print the winning message for this object.
mov di, [bx].item.WinDesc
puts
putcr
; Award the user some points.
mov ax, [bx].item.value
add CurScore, ax
; Since the user dropped it, they can carry more things now.
mov ax, [bx].item.Weight
sub CurWeight, ax
; Okay, take this from the user's list.
lea di, ItemsOnHand
call RemoveItem
; Keep track of how may objects the user has successfully dropped.
; When this counter hits zero, the game is over.
dec TotalCounter
jnz RoomLoop
printf
byte "Well, you've found where everything goes "
byte "and your score is %d.\n"
byte "You might want to play again and see if "
byte "you can get a better score.\n",0
dword CurScore
jmp Quit
; If this isn't the room where this object belongs, just drop the thing
; off. If this object won't fit in this room, ignore the drop command.
JustDropIt: mov di, CurRoom
lea di, [di].room.ItemList
call InsertItem
jc DroppedItem
printf
byte "There is insufficient room to leave "
byte "that item here.\n",0
jmp RoomLoop
; If they can drop it, do so. Don't forget we've just unburdened the
; user so we need to deduct the weight of this object from what the
; user is currently carrying.
DroppedItem: lea di, ItemsOnHand
call RemoveItem
mov ax, [bx].item.Weight
sub CurWeight, ax
jmp RoomLoop
; If the user enters the INVENTORY command, print out the objects on hand
DoInventory: printf
byte "You currently have the following items in your "
byte "possession:",cr,lf,0
mov di, ItemsOnHand[0]
call ShortDesc
mov di, ItemsOnHand[2]
call ShortDesc
mov di, ItemsOnHand[4]
call ShortDesc
mov di, ItemsOnHand[6]
call ShortDesc
printf
byte "\nCurrent score: %d\n"
byte "Carrying ability: %d/4\n\n",0
dword CurScore,CurWeight
inc CurScore ;This command is free.
jmp RoomLoop
; If the user requests help, provide it here.
DoHelp: printf
byte "List of commands:",cr,lf,lf
byte "GO {NORTH, EAST, WEST, SOUTH}",cr,lf
byte "{GET, DROP} {LIME, BEER, CARD, SIGN, PROGRAM, "
byte "HOMEWORK, MONEY, FORM, COUPON}",cr,lf
byte "SHOW INVENTORY",cr,lf
byte "QUIT GAME",cr,lf
byte "HELP ME",cr,lf,lf
byte "Each command costs you one point.",cr,lf
byte "You accumulate points by picking up objects and "
byte "dropping them in their",cr,lf
byte " appropriate locations.",cr,lf
byte "If you drop an item in its proper location, it "
byte "disappears from the game.",cr,lf
byte "The game is over if your score drops to zero or "
byte "you properly place",cr,lf
byte " all items.",cr,lf
byte 0
jmp RoomLoop
; If they quit prematurely, let 'em know what a wimp they are!
QuitGame: printf
byte "So long, your score is %d and there are "
byte "still %d objects unplaced\n",0
dword CurScore, TotalCounter
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk db 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -