/* * ROOM.C: * * Room routines. * * Copyright (C) 1991, 1992, 1993 Brett J. Vickers * */ #include "mstruct.h" #include "mextern.h" /**********************************************************************/ /* add_ply_rom */ /**********************************************************************/ /* This function is called to add a player to a room. It inserts the */ /* player into the room's linked player list, alphabetically. Also, */ /* the player's room pointer is updated. */ void add_ply_rom(ply_ptr, rom_ptr) creature *ply_ptr; room *rom_ptr; { ctag *cg, *cp, *temp, *prev; ply_ptr->parent_rom = rom_ptr; ply_ptr->rom_num = rom_ptr->rom_num; rom_ptr->beenhere++; cg = (ctag *)malloc(sizeof(ctag)); if(!cg) merror("add_ply_rom", FATAL); cg->crt = ply_ptr; cg->next_tag = 0; if(!F_ISSET(ply_ptr, PDMINV) && !F_ISSET(ply_ptr, PHIDDN)) { broadcast_rom(ply_ptr->fd, ply_ptr->rom_num, "%M just arrived.", ply_ptr); } add_permcrt_rom(rom_ptr); add_permobj_rom(rom_ptr); check_exits(rom_ptr); display_rom(ply_ptr, rom_ptr); if(!rom_ptr->first_ply) { rom_ptr->first_ply = cg; cp = rom_ptr->first_mon; while(cp) { add_active(cp->crt); cp = cp->next_tag; } return; } temp = rom_ptr->first_ply; if(strcmp(temp->crt->name, ply_ptr->name) > 0) { cg->next_tag = temp; rom_ptr->first_ply = cg; return; } while(temp) { if(strcmp(temp->crt->name, ply_ptr->name) > 0) break; prev = temp; temp = temp->next_tag; } cg->next_tag = prev->next_tag; prev->next_tag = cg; } /**********************************************************************/ /* del_ply_rom */ /**********************************************************************/ /* This function removes a player from a room's linked list of players. */ /* It also resets the player's room pointer. */ void del_ply_rom(ply_ptr, rom_ptr) creature *ply_ptr; room *rom_ptr; { ctag *cp, *temp, *prev; ply_ptr->parent_rom = 0; if(rom_ptr->first_ply->crt == ply_ptr) { temp = rom_ptr->first_ply->next_tag; free(rom_ptr->first_ply); rom_ptr->first_ply = temp; if(!temp) { cp = rom_ptr->first_mon; while(cp) { del_active(cp->crt); cp = cp->next_tag; } } return; } prev = rom_ptr->first_ply; temp = prev->next_tag; while(temp) { if(temp->crt == ply_ptr) { prev->next_tag = temp->next_tag; free(temp); return; } prev = temp; temp = temp->next_tag; } } /**********************************************************************/ /* add_obj_rom */ /**********************************************************************/ /* This function adds the object pointed to by the first parameter to */ /* the object list of the room pointed to by the second parameter. */ /* The object is added alphabetically to the room. */ void add_obj_rom(obj_ptr, rom_ptr) object *obj_ptr; room *rom_ptr; { otag *op, *temp, *prev; int num; obj_ptr->parent_rom = rom_ptr; obj_ptr->parent_obj = 0; obj_ptr->parent_crt = 0; op = (otag *)malloc(sizeof(otag)); if(!op) merror("add_obj_rom", FATAL); op->obj = obj_ptr; op->next_tag = 0; if(!rom_ptr->first_obj) { rom_ptr->first_obj = op; return; } prev = temp = rom_ptr->first_obj; if(strcmp(temp->obj->name, obj_ptr->name) > 0 || (!strcmp(temp->obj->name, obj_ptr->name) && temp->obj->adjustment > obj_ptr->adjustment)) { op->next_tag = temp; rom_ptr->first_obj = op; return; } while(temp) { if(strcmp(temp->obj->name, obj_ptr->name) > 0 || (!strcmp(temp->obj->name, obj_ptr->name) && temp->obj->adjustment > obj_ptr->adjustment)) break; prev = temp; temp = temp->next_tag; } op->next_tag = prev->next_tag; prev->next_tag = op; } /**********************************************************************/ /* del_obj_rom */ /**********************************************************************/ /* This function removes the object pointer to by the first parameter */ /* from the room pointed to by the second. */ void del_obj_rom(obj_ptr, rom_ptr) object *obj_ptr; room *rom_ptr; { otag *temp, *prev; obj_ptr->parent_rom = 0; if(rom_ptr->first_obj->obj == obj_ptr) { temp = rom_ptr->first_obj->next_tag; free(rom_ptr->first_obj); rom_ptr->first_obj = temp; return; } prev = rom_ptr->first_obj; temp = prev->next_tag; while(temp) { if(temp->obj == obj_ptr) { prev->next_tag = temp->next_tag; free(temp); return; } prev = temp; temp = temp->next_tag; } } /**********************************************************************/ /* add_crt_rom */ /**********************************************************************/ /* This function adds the monster pointed to by the first parameter to */ /* the room pointed to by the second. The third parameter determines */ /* how the people in the room should be notified. If it is equal to */ /* zero, then no one will be notified that a monster entered the room. */ /* If it is non-zero, then the room will be told that "num" monsters */ /* of that name entered the room. */ void add_crt_rom(crt_ptr, rom_ptr, num) creature *crt_ptr; room *rom_ptr; int num; { ctag *cg, *temp, *prev; char str[160]; crt_ptr->parent_rom = rom_ptr; crt_ptr->rom_num = rom_ptr->rom_num; cg = (ctag *)malloc(sizeof(ctag)); if(!cg) merror("add_crt_rom", FATAL); cg->crt = crt_ptr; cg->next_tag = 0; sprintf(str, "%%%dM just arrived.", num); if(!F_ISSET(crt_ptr, MINVIS) && !F_ISSET(crt_ptr, MPERMT) && num) broadcast_rom(crt_ptr->fd, crt_ptr->rom_num, str, crt_ptr); if(!rom_ptr->first_mon) { rom_ptr->first_mon = cg; return; } temp = rom_ptr->first_mon; if(strcmp(temp->crt->name, crt_ptr->name) > 0) { cg->next_tag = temp; rom_ptr->first_mon = cg; return; } while(temp) { if(strcmp(temp->crt->name, crt_ptr->name) > 0) break; prev = temp; temp = temp->next_tag; } cg->next_tag = prev->next_tag; prev->next_tag = cg; } /**********************************************************************/ /* del_crt_rom */ /**********************************************************************/ /* This function removes the monster pointed to by the first parameter */ /* from the room pointed to by the second. */ void del_crt_rom(crt_ptr, rom_ptr) creature *crt_ptr; room *rom_ptr; { ctag *temp, *prev; crt_ptr->parent_rom = 0; crt_ptr->rom_num = 0; if(rom_ptr->first_mon->crt == crt_ptr) { temp = rom_ptr->first_mon->next_tag; free(rom_ptr->first_mon); rom_ptr->first_mon = temp; return; } prev = rom_ptr->first_mon; temp = prev->next_tag; while(temp) { if(temp->crt == crt_ptr) { prev->next_tag = temp->next_tag; free(temp); return; } prev = temp; temp = temp->next_tag; } } /**********************************************************************/ /* add_permcrt_rom */ /**********************************************************************/ /* This function checks a room to see if any permanent monsters need to */ /* be loaded. If so, the monsters are loaded to the room, and their */ /* permanent flag is set. */ void add_permcrt_rom(rom_ptr) room *rom_ptr; { short checklist[10]; creature *crt_ptr; object *obj_ptr; ctag *cp; long t; int h, i, j, k, l, m, n; t = time(0); for(i=0; i<10; i++) checklist[i] = 0; for(i=0; i<10; i++) { if(checklist[i]) continue; if(!rom_ptr->perm_mon[i].misc) continue; if(rom_ptr->perm_mon[i].ltime + rom_ptr->perm_mon[i].interval > t) continue; n = 1; for(j=i+1; j<10; j++) if(rom_ptr->perm_mon[i].misc == rom_ptr->perm_mon[j].misc && (rom_ptr->perm_mon[j].ltime + rom_ptr->perm_mon[j].interval) < t) { n++; checklist[j] = 1; } if(load_crt(rom_ptr->perm_mon[i].misc, &crt_ptr) < 0) continue; cp = rom_ptr->first_mon; m = 0; while(cp) { if(F_ISSET(cp->crt, MPERMT) && !strcmp(cp->crt->name, crt_ptr->name)) m++; cp = cp->next_tag; } free_crt(crt_ptr); for(j=0; j<n-m; j++) { l = load_crt(rom_ptr->perm_mon[i].misc, &crt_ptr); if(l < 0) continue; l = mrand(1,100); if(l<90) l=1; else if(l<96) l=2; else l=3; for(k=0; k<l; k++) { h = mrand(0,9); if(crt_ptr->carry[h]) { h = load_obj(crt_ptr->carry[h], &obj_ptr); if(F_ISSET(obj_ptr, ORENCH)) rand_enchant(obj_ptr); if(h > -1) add_obj_crt(obj_ptr, crt_ptr); } } if(!F_ISSET(crt_ptr, MNRGLD) && crt_ptr->gold) crt_ptr->gold = mrand(crt_ptr->gold/10, crt_ptr->gold); F_SET(crt_ptr, MPERMT); add_crt_rom(crt_ptr, rom_ptr); if(rom_ptr->first_ply) add_active(crt_ptr); } } } /**********************************************************************/ /* add_permobj_rom */ /**********************************************************************/ /* This function checks a room to see if any permanent objects need to */ /* be loaded. If so, the objects are loaded to the room, and their */ /* permanent flag is set. */ void add_permobj_rom(rom_ptr) room *rom_ptr; { short checklist[10]; object *obj_ptr; otag *op; long t; int i, j, m, n; t = time(0); for(i=0; i<10; i++) checklist[i] = 0; for(i=0; i<10; i++) { if(checklist[i]) continue; if(!rom_ptr->perm_obj[i].misc) continue; if(rom_ptr->perm_obj[i].ltime + rom_ptr->perm_obj[i].interval > t) continue; n = 1; for(j=i+1; j<10; j++) if(rom_ptr->perm_obj[i].misc == rom_ptr->perm_obj[j].misc && (rom_ptr->perm_obj[j].ltime + rom_ptr->perm_obj[j].interval) < t) { n++; checklist[j] = 1; } if(load_obj(rom_ptr->perm_obj[i].misc, &obj_ptr) < 0) continue; op = rom_ptr->first_obj; m = 0; while(op) { if(F_ISSET(op->obj, OPERMT) && !strcmp(op->obj->name, obj_ptr->name)) m++; op = op->next_tag; } free_obj(obj_ptr); for(j=0; j<n-m; j++) { if(load_obj(rom_ptr->perm_obj[i].misc, &obj_ptr) < 0) continue; if(F_ISSET(obj_ptr, ORENCH)) rand_enchant(obj_ptr); F_SET(obj_ptr, OPERMT); add_obj_rom(obj_ptr, rom_ptr); } } } /**********************************************************************/ /* check_exits */ /**********************************************************************/ /* This function checks the status of the exits in a room. If any of */ /* the exits are closable or lockable, and the correct time interval */ /* has occurred since the last opening/unlocking, then the doors are */ /* re-shut/re-closed. */ void check_exits(rom_ptr) room *rom_ptr; { xtag *xp; int tmp; long t; t = time(0); xp = rom_ptr->first_ext; while(xp) { if(F_ISSET(xp->ext, XLOCKS) && (xp->ext->ltime.ltime + xp->ext->ltime.interval) < t) { F_SET(xp->ext, XLOCKD); F_SET(xp->ext, XCLOSD); } else if(F_ISSET(xp->ext, XCLOSS) && (xp->ext->ltime.ltime + xp->ext->ltime.interval) < t) F_SET(xp->ext, XCLOSD); xp = xp->next_tag; } } /**********************************************************************/ /* display_rom */ /**********************************************************************/ /* This function displays the descriptions of a room, all the players */ /* in a room, all the monsters in a room, all the objects in a room, */ /* and all the exits in a room. That is, unless they are not visible */ /* or the room is dark. */ void display_rom(ply_ptr, rom_ptr) creature *ply_ptr; room *rom_ptr; { xtag *xp; ctag *cp; otag *op; creature *crt_ptr; char str[2048]; int fd, n=0, m, t, light = 0; fd = ply_ptr->fd; print(fd, "\n"); t = Time%24L; if(F_ISSET(ply_ptr, PBLIND) || F_ISSET(rom_ptr, RDARKR) || (F_ISSET(rom_ptr, RDARKN) && (t<6 || t>20))) { if(!has_light(ply_ptr)) { cp = rom_ptr->first_ply; while(cp) { if(has_light(cp->crt)) { light = 1; break; } cp = cp->next_tag; } if(ply_ptr->race == ELF || ply_ptr->race == DWARF || ply_ptr->class >= CARETAKER) light = 1; } else light = 1; if(!light || F_ISSET(ply_ptr, PBLIND)) { ANSI(fd, RED); if(F_ISSET(ply_ptr, PBLIND)) print(fd, "You're blind!\n"); ANSI(fd, YELLOW); print(fd, "It's too dark to see.\n"); ANSI(fd, WHITE); return; } } if(!F_ISSET(ply_ptr, PNORNM)) { ANSI(fd, CYAN); print(fd, "%s\n\n", rom_ptr->name); ANSI(fd, WHITE); } if(!F_ISSET(ply_ptr, PNOSDS) && rom_ptr->short_desc) print(fd, "%s\n", rom_ptr->short_desc); if(!F_ISSET(ply_ptr, PNOLDS) && rom_ptr->long_desc) print(fd, "%s\n", rom_ptr->long_desc); if(!F_ISSET(ply_ptr, PNOEXT)) { n=0; str[0] = 0; strcat(str, "Obvious exits: "); xp = rom_ptr->first_ext; while(xp) { if(!F_ISSET(xp->ext, XSECRT) && !F_ISSET(xp->ext, XNOSEE) && (F_ISSET(ply_ptr, PDINVI) ? 1:!F_ISSET(xp->ext, XINVIS))) { strcat(str, xp->ext->name); strcat(str, ", "); n++; } xp = xp->next_tag; } if(!n) strcat(str, "none"); else str[strlen(str)-2] = 0; ANSI(fd, GREEN); print(fd, "%s.\n", str); ANSI(fd, WHITE); } cp = rom_ptr->first_ply; n=0; str[0]=0; strcat(str, "You see "); while(cp) { if((F_ISSET(ply_ptr, PDINVI) ? 1:!F_ISSET(cp->crt, PINVIS)) && !F_ISSET(cp->crt, PHIDDN) && !(ply_ptr->class < DM && F_ISSET(cp->crt, PDMINV)) && cp->crt != ply_ptr) { strcat(str, cp->crt->name); strcat(str, ", "); n++; } cp = cp->next_tag; } if(n) { str[strlen(str)-2] = 0; ANSI(fd, CYAN); print(fd, "%s.\n", str); ANSI(fd, WHITE); } cp = rom_ptr->first_mon; n=0; str[0]=0; strcat(str, "You see "); while(cp) { if((F_ISSET(ply_ptr, PDINVI) ? 1:!F_ISSET(cp->crt, MINVIS)) && !F_ISSET(cp->crt, MHIDDN)) { m=1; while(cp->next_tag) { if(!strcmp(cp->next_tag->crt->name, cp->crt->name) && (F_ISSET(ply_ptr, PDINVI) ? 1:!F_ISSET(cp->next_tag->crt, MINVIS)) && !F_ISSET(cp->next_tag->crt, MHIDDN)) { m++; cp = cp->next_tag; } else break; } strcat(str, crt_str(cp->crt, m, 0)); strcat(str, ", "); n++; } cp = cp->next_tag; } if(n) { str[strlen(str)-2] = 0; print(fd, "%s.\n", str); } str[0]=0; strcat(str, "You see "); n = list_obj(&str[8], ply_ptr, rom_ptr->first_obj); if(n) print(fd, "%s.\n", str); cp = rom_ptr->first_mon; while(cp) { if(cp->crt->first_enm) { crt_ptr = find_crt(ply_ptr, rom_ptr->first_ply, cp->crt->first_enm->enemy, 1); if(crt_ptr == ply_ptr) print(fd, "%M is attacking you.\n", cp->crt); else if(crt_ptr) print(fd, "%M is attacking %m.\n", cp->crt, crt_ptr); } cp = cp->next_tag; } print(fd, "\n"); } /**********************************************************************/ /* find_ext */ /**********************************************************************/ /* This function attempts to find the exit specified by the given string */ /* and value by looking through the exit list headed by the second para- */ /* meter. If found, a pointer to the exit is returned. */ exit_ *find_ext(ply_ptr, first_xt, str, val) creature *ply_ptr; xtag *first_xt; char *str; int val; { xtag *xp; int match = 0, found = 0; xp = first_xt; while(xp) { if(!strncmp(xp->ext->name, str, strlen(str)) && (!F_ISSET(xp->ext, XNOSEE)) && (F_ISSET(ply_ptr, PDINVI) ? 1:!F_ISSET(xp->ext, XINVIS))) match++; if(match == val) { found = 1; break; } xp = xp->next_tag; } if(!found) return(0); return(xp->ext); } /**********************************************************************/ /* check_traps */ /**********************************************************************/ /* This function checks a room to see if there are any traps and whether */ /* the player pointed to by the first parameter fell into any of them. */ void check_traps(ply_ptr, rom_ptr) creature *ply_ptr; room *rom_ptr; { room *new_rom; ctag *cp; creature *tmp_crt; int i, dmg, fd; if(!rom_ptr->trap) { F_CLR(ply_ptr, PPREPA); return; } switch(rom_ptr->trap){ case TRAP_PIT: case TRAP_DART: case TRAP_BLOCK: case TRAP_NAKED: case TRAP_ALARM: if(F_ISSET(ply_ptr, PPREPA) && mrand(1,20) < ply_ptr->dexterity) { F_CLR(ply_ptr, PPREPA); return; } F_CLR(ply_ptr, PPREPA); if(mrand(1,100) < ply_ptr->dexterity) return; break; case TRAP_MPDAM: case TRAP_RMSPL: if(F_ISSET(ply_ptr, PPREPA) && mrand(1,25) < (ply_ptr->intelligence)) { F_CLR(ply_ptr, PPREPA); return; } F_CLR(ply_ptr, PPREPA); if(mrand(1,100) < ply_ptr->intelligence) return; break; default: return; } fd = ply_ptr->fd; switch (rom_ptr->trap){ case TRAP_PIT: if(!F_ISSET(ply_ptr, PLEVIT)){ print(fd, "You fell into a pit trap!\n"); broadcast_rom(fd, ply_ptr->rom_num, "%M fell into a pit trap!", ply_ptr); del_ply_rom(ply_ptr, rom_ptr); load_rom(rom_ptr->trapexit, &new_rom); add_ply_rom(ply_ptr, new_rom); dmg = mrand(1,15); print(fd, "You lost %d hit points.\n", dmg); ply_ptr->hpcur -= dmg; if(ply_ptr->hpcur < 1) die(ply_ptr, ply_ptr); } break; case TRAP_DART: print(fd, "You triggered a hidden dart!\n"); broadcast_rom(fd, ply_ptr->rom_num, "%M gets hit by a hidden dart.", ply_ptr); dmg = mrand(1,10); print(fd, "You lost %d hit points.\n", dmg); F_SET(ply_ptr, PPOISN); ply_ptr->hpcur -= dmg; if(ply_ptr->hpcur < 1) die(ply_ptr, ply_ptr); break; case TRAP_BLOCK: print(fd, "You triggered a falling block!\n"); broadcast_rom(fd, ply_ptr->rom_num, "A large block falls on %m.", ply_ptr); dmg = ply_ptr->hpmax / 2; print(fd, "You lost %d hit points.\n", dmg); ply_ptr->hpcur -= dmg; if(ply_ptr->hpcur < 1) die(ply_ptr, ply_ptr); break; case TRAP_MPDAM: print(fd, "You feel an exploding force in your mind!\n"); broadcast_rom(fd, ply_ptr->rom_num, "An energy bolts strikes %m.", ply_ptr); dmg = MIN(ply_ptr->mpcur,ply_ptr->mpmax / 2); print(fd, "You lost %d magic points.\n", dmg); ply_ptr->mpcur -= dmg; dmg = mrand(1,6); ply_ptr->hpcur -= dmg; print(fd, "You lost %d hit points.\n", dmg); if(ply_ptr->hpcur < 1) die(ply_ptr, ply_ptr); break; case TRAP_RMSPL: print(fd, "A foul smelling charcoal cloud surrounds you.\n"); print(fd, "Your magic begins to dissolve.\n"); broadcast_rom(fd, ply_ptr->rom_num, "A charcoal cloud surrounds %m.", ply_ptr); ply_ptr->lasttime[LT_PROTE].interval = ply_ptr->lasttime[LT_BLESS].interval = ply_ptr->lasttime[LT_RFIRE].interval = ply_ptr->lasttime[LT_RCOLD].interval = ply_ptr->lasttime[LT_BRWAT].interval = ply_ptr->lasttime[LT_SSHLD].interval = ply_ptr->lasttime[LT_RMAGI].interval = ply_ptr->lasttime[LT_LIGHT].interval = ply_ptr->lasttime[LT_DINVI].interval = ply_ptr->lasttime[LT_INVIS].interval = ply_ptr->lasttime[LT_KNOWA].interval = ply_ptr->lasttime[LT_DMAGI].interval = 0; break; case TRAP_NAKED: print(fd, "You are covered in oozing green slime.\n"); print(fd, "All your possessions dissolve away.\n"); broadcast_rom(fd, ply_ptr->rom_num, "A oozing green slime envelops %m.", ply_ptr); lose_all(ply_ptr); break; case TRAP_ALARM: print(fd, "You set off an alarm!\n"); print(fd, "You hope there aren't any guards around.\n\n"); broadcast_rom(fd, ply_ptr->rom_num, "%M sets off an alarm!\n", ply_ptr); load_rom(rom_ptr->trapexit, &new_rom); add_permcrt_rom(new_rom); cp = new_rom->first_mon; while(cp) { tmp_crt = cp->crt; cp = cp->next_tag; if(F_ISSET(tmp_crt, MPERMT)){ if(new_rom->first_ply) broadcast_rom(tmp_crt->fd, tmp_crt->rom_num, "%M hears an alarm and leaves to investigate.",tmp_crt); else add_active(tmp_crt); F_CLR(tmp_crt,MPERMT); F_SET(tmp_crt,MAGGRE); die_perm_crt(tmp_crt); del_crt_rom(tmp_crt, new_rom); add_crt_rom(tmp_crt, rom_ptr, 1); broadcast_rom(tmp_crt->fd, tmp_crt->rom_num, "%M comes to investigate the alarm.", tmp_crt); } } break; } return; } /**********************************************************************/ /* count_ply */ /**********************************************************************/ /* This function counts the number of (non-DM-invisible) players in a */ /* room and returns that number. */ int count_vis_ply(rom_ptr) room *rom_ptr; { ctag *cp; int num = 0; cp = rom_ptr->first_ply; while(cp) { if(!F_ISSET(cp->crt, PDMINV)) num++; cp = cp->next_tag; } return num; }