Handouts:
Assignment #4
Assignment #3 Answers
Class Notes, Chapter 20
Exercises:
struct object { char name[MAXNAME]; unsigned int attrs; struct object *contents; /* contents (if container) */ struct object *lnext; /* next in list of contained objects */ /* (i.e. in this object's container) */ char *desc; /* long description */ }; #define CONTAINER 0x0001 #define CLOSABLE 0x0002 #define OPEN 0x0004 #define HEAVY 0x0008 #define BROKEN 0x0010 #define TOOL 0x0020 #define SOFT 0x0040 #define SHARP 0x0080 #define LOCK 0x0100 #define KEY 0x0200 #define LOCKED 0x0400 #define TRANSPARENT 0x0800 #define IMMOBILE 0x1000 #define Iscontainer(o) ((o)->attrs & CONTAINER) #define Isopen(o) ((o)->attrs & OPEN)(This code is in the file game.xh in the week4 subdirectory, although the copy there is missing the new desc field for objects.)
else if(strcmp(verb, "open") == 0) { if(objp == NULL) { printf("You must tell me what to open.\n"); return FALSE; } if(Isopen(objp)) { printf("The %s is already open.\n", objp->name); return FALSE; } if(!(objp->attrs & CLOSABLE)) { printf("You can't open the %s.\n", objp->name); return FALSE; } objp->attrs |= OPEN; printf("The %s is now open.\n", objp->name); } else if(strcmp(verb, "close") == 0) { if(objp == NULL) { printf("You must tell me what to close.\n"); return FALSE; } if(!(objp->attrs & CLOSABLE)) { printf("You can't close the %s.\n", objp->name); return FALSE; } if(!Isopen(objp)) { printf("The %s is already closed.\n", objp->name); return FALSE; } objp->attrs &= ~OPEN; printf("The %s is now closed.\n", objp->name); } else if(strcmp(verb, "put") == 0) { if(objp == NULL) { printf("You must tell me what to put.\n"); return FALSE; } if(!contains(player->contents, objp)) { printf("You don't have the %s.\n", objp->name); return FALSE; } if(cmd->preposition == NULL || strcmp(cmd->preposition, "in") != 0 || cmd->xobject == NULL) { printf("You must tell me where to put the %s.\n", objp->name); return FALSE; } if(!Iscontainer(cmd->xobject)) { printf("You can't put things in the %s.\n", cmd->xobject->name); return FALSE; } if((cmd->xobject->attrs & CLOSABLE) && !Isopen(cmd->xobject)) { printf("The %s is closed.\n", cmd->xobject->name); return FALSE; } if(!putobject(player, objp, cmd->xobject)) { /* shouldn't happen */ printf("You can't put the %s in the %s!\n", objp->name, cmd->xobject->name); return FALSE; } printf("Now the %s is in the %s.\n", objp->name, cmd->xobject->name); }(This code is in the file week4/commands.xc.)
struct object * newobject(char *name) { struct object *objp; if(nobjects >= MAXOBJECTS) { fprintf(stderr, "too many objects\n"); exit(1); } objp = &objects[nobjects++]; strcpy(objp->name, name); objp->lnext = NULL; objp->attrs = 0; objp->contents = NULL; return objp; }Here is the new putobject function, for object.c. (It's in week4/object.xc.)
/* transfer object from actor to container */ putobject(struct actor *actp, struct object *objp, struct object *container) { struct object *lp; struct object *prevlp = NULL; for(lp = actp->contents; lp != NULL; lp = lp->lnext) { if(lp == objp) /* found it */ { /* splice out of actor's list */ if(lp == actp->contents) /* head of list */ actp->contents = lp->lnext; else prevlp->lnext = lp->lnext; /* splice into container's list */ lp->lnext = container->contents; container->contents = lp; return TRUE; } prevlp = lp; } /* didn't find it (error) */ return FALSE; }Here is new code for the parsedatafile function in io.c, to read attributes for objects:
else if(strcmp(av[0], "attribute") == 0) { if(currentobject == NULL) continue; if(strcmp(av[1], "container") == 0) currentobject->attrs |= CONTAINER; else if(strcmp(av[1], "closable") == 0) currentobject->attrs |= CLOSABLE; else if(strcmp(av[1], "open") == 0) currentobject->attrs |= OPEN; else if(strcmp(av[1], "heavy") == 0) currentobject->attrs |= HEAVY; else if(strcmp(av[1], "soft") == 0) currentobject->attrs |= SOFT; else if(strcmp(av[1], "sharp") == 0) currentobject->attrs |= SHARP; }(This code is incomplete; at some point you'll have to add cases for the other attributes defined in game.h.)
else if(strcmp(verb, "break") == 0) { if(objp == NULL) { printf("You must tell me what to break.\n"); return FALSE; } if(cmd->preposition == NULL || strcmp(cmd->preposition, "with") != 0 || cmd->xobject == NULL) { printf("You must tell me what to break with.\n"); return FALSE; } if(!contains(player->contents, cmd->xobject)) { printf("You have no %s.\n", cmd->xobject->name); return FALSE; } if(!(cmd->xobject->attrs & HEAVY)) { printf("I don't think the %s is heavy enough to break things with.\n", cmd->xobject->name); return FALSE; } objp->attrs |= BROKEN; printf("Oh, dear. Now the %s is broken.\n", objp->name); } else if(strcmp(verb, "cut") == 0) { if(objp == NULL) { printf("You must tell me what to cut.\n"); return FALSE; } if(cmd->preposition == NULL || strcmp(cmd->preposition, "with") != 0 || cmd->xobject == NULL) { printf("You must tell me what to cut with.\n"); return FALSE; } if(!contains(player->contents, cmd->xobject)) { printf("You have no %s.\n", cmd->xobject->name); return FALSE; } if(!(cmd->xobject->attrs & SHARP)) { printf("I don't think the %s is sharp enough to cut things with.\n", cmd->xobject->name); return FALSE; } if(!(objp->attrs & SOFT)) { printf("I don't think you can cut the %s with the %s.\n", objp->name, cmd->xobject->name); return FALSE; } printf("The %s is now cut in two.\n", objp->name); }Try to get all of this code integrated, compiled, and working. You will probably have to add a few prototypes to game.h.
attribute heavyjust after the line
object hammerMake the kettle a container by adding the line
attribute containerjust after the line
object kettleAdd a knife object by adding the lines
object knife attribute sharpin one of the rooms. Add a box object by adding the lines
object box attribute closableNow you should be able to break things with the hammer, and put things into the kettle or box (once you open the box). The knife won't cut things unless they're soft, so add an object with
attribute softand try cutting it with the knife. Once you put things into containers, they'll seem to disappear; we'll fix that in the next two exercises.
findobj2(actp->contents, name);and
findobj2(actp->location->contents, name);Ideally, your scheme should work even to find objects within objects within objects (or deeper); this will involve recursive calls to findobj2.
This page by Steve Summit // Copyright 1995-9 // mail feedback