/************************************************************************ Realms of Aurealis James Rhone aka Vall of RoA roomact.c Procs related to rooms... ******** Heavily modified and expanded ******** ******** 100% Completely Original Code ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** Heavily modified and expanded ******** ******** 100% Completely Original Code ******** All rights reserved henceforth. Please note that no guarantees are associated with any code from Realms of Aurealis. All code which has been released to the general public has been done so with an 'as is' pretense. RoA is based on both Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well as the RoA license. *** Read, Learn, Understand, Improve *** *************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structures.h" #include "utils.h" #include "db.h" #include "comm.h" #include "interpreter.h" #include "acmd.h" #include "handler.h" #include "magic.h" #include "bard.h" #include "house.h" #include "fight.h" #include "affect.h" #include "lists.h" #include "objsave.h" #include "darkenelf.h" /* ext vars */ extern int rev_dir[]; extern char *rev_dir_str[]; extern char *dirs[]; /* find these in nature.c */ extern void do_room_wind(int i); extern void do_room_drift(int i); extern void send_soundfile_to_client(dsdata *d, char *sname); extern void do_room_rproc(rmdata *r); // internally used int check_room_affects(chdata *ch, int room); void room_affect_update(int room); void null_char_room_affects(chdata *ch); // for each client connection... check room sound status for resend void check_room_music(void) { dsdata *d; for (d = descriptor_list; d;d=d->next) if (D_CHECK(d) && HAS_CLIENT(d) && d->room_stimer > -1) { d->room_stimer--; if (d->room_stimer == 0) { int toroom; int vroom; toroom = d->character->in_room; if (INVALID_ROOM(toroom)) continue; // use vnums for consistency... vroom = world[toroom].number; // if sound file is gone or not in the same room... reset if (!world[toroom].sound_file || vroom != d->music_room) { d->room_stimer = -1; d->music_room = -1; continue; } // else, send it and set the #s send_soundfile_to_client(d, world[toroom].sound_file); d->room_stimer = world[toroom].music_timer; d->music_room = vroom; } } } /* formerly hard wired */ void do_room_dump(chdata *ch, obdata *obj) { obdata *o, *tmp_o; int value = 0; extern int gain_exp(chdata *ch, int value); if (ch->in_room <= NOWHERE) { log("SYSERR: nowhere sent to dump"); return; } for (o = world[ch->in_room].contents; o; o = tmp_o) { tmp_o = o->next_content; extract_obj(o); } o = obj; value = MAX(1, MIN(50, o->cost / 10)); extract_obj(o); if (value) { act("You have been rewarded.", FALSE, ch, 0, 0, TO_CHAR); if (GET_LEVEL(ch) < 3) gain_exp(ch, value); else GET_GOLD(ch) += value; } return; } SPECIAL(pet_shops) { char buf[MAX_STRING_LENGTH], pet_name[256]; int pet_room; chdata *pet; pet_room = ch->in_room + 1; if (cmd == 63) { /* List */ send_to_char("Available pets are:\n\r", ch); for (pet = world[pet_room].people; pet; pet = pet->next_in_room) { sprintf(buf, "%8d - %s\n\r", 3 * GET_EXP(pet), pet->player.short_descr); send_to_char(buf, ch); } return(TRUE); } else if (cmd == 60) { /* Buy */ arg = one_argument(arg, buf); arg = one_argument(arg, pet_name); /* Pet_Name is for later use when I feel like it */ if (!(pet = get_char_room(buf, pet_room))) { send_to_char("There is no such pet!\n\r", ch); return(TRUE); } if (GET_GOLD(ch) < (GET_EXP(pet) * 3)) { send_to_char("You don't have enough money!\n\r", ch); return(TRUE); } GET_GOLD(ch) -= GET_EXP(pet) * 3; pet = read_mobile(pet->nr, REAL); GET_EXP(pet) = 0; SET_BIT(pet->specials.affected_by, AFF_CHARM); if (*pet_name) { sprintf(buf, "%s %s", pet->player.name, pet_name); pet->player.name = str_dup(buf); sprintf(buf, "%sA small sign on a chain around the neck says 'My Name is %s'\n\r", pet->player.description, pet_name); pet->player.description = str_dup(buf); } char_to_room(pet, ch->in_room); add_follower(pet, ch); /* Be certain that pet's can't get/carry/use/weild/wear items */ IS_CARRYING_W(pet) = 1000; IS_CARRYING_N(pet) = 100; send_to_char("May you enjoy your pet.\n\r", ch); act("$n buys $N as a pet.", FALSE, ch, 0, pet, TO_ROOM); return(TRUE); } /* All commands except list and buy */ return(FALSE); } /* display one of the randoms defined by players -roa */ void do_room_random(int room) { int num; if (room == NOWHERE) return; if (number(0,1)) { num = number(0, 4); // pick a number 0 - 4 (5 total possibilities) if (world[room].randoms[num] && *world[room].randoms[num] != '&') send_to_room_not_busy(world[room].randoms[num], room); } } void do_room_portal(int room) { chdata *ch; chdata *next_ch; BOOL found = FALSE; byte num; int i, single = 0; for (i = 0, num = 0; i<4; i++) if (RPORTAL(room, i) > 0) { found = TRUE; num++; single = i; } if (!found) return; /* nowhere to portal to */ if (num == 1) /* tele to one room only */ { for (ch = world[room].people; ch; ch=next_ch) { next_ch = ch->next_in_room; if (IS_PC(ch) && (real_room(RPORTAL(room, single)) > 0)) { char_from_room(ch); char_to_room(ch, real_room(RPORTAL(room, single))); act("$n appears amidst a brilliant flash of light.", FALSE, ch, 0, 0, TO_ROOM); do_look_at_room(ch, 0, 0); if (check_room_affects(ch, ch->in_room) == CHAR_DIED) return; if (check_death_trap(ch, NULL)) return; } } } else /* its a random teleport */ { for (ch = world[room].people; ch; ch=next_ch) { next_ch = ch->next_in_room; single = number(0,3); if (IS_PC(ch) && (real_room(RPORTAL(room, single)) > 0)) { char_from_room(ch); char_to_room(ch, real_room(RPORTAL(room, single))); act("$n appears amidst a brilliant flash of light!", FALSE, ch, 0, 0, TO_ROOM); do_look_at_room(ch, 0, 0); if (check_room_affects(ch, ch->in_room) == CHAR_DIED) return; if (check_death_trap(ch, NULL)) return; } } } } #define IS_DT(rm) (ROOM_FLAGGED((rm), DEATH) || ROOM_FLAGGED((rm),FLY_DEATH)) void do_room_alter(int room) { chdata *ch, *next_ch; BOOL hit = FALSE, mana = FALSE, move = FALSE; BOOL decrease = world[room].alter_type; int amount; if (IS_DT(room)) return; if (world[room].numdice < 1 || world[room].sizedice < 1) return; if (ROOM_FLAGGED(room, ALTERHIT)) hit = TRUE; if (ROOM_FLAGGED(room, ALTERMANA)) mana = TRUE; if (ROOM_FLAGGED(room, ALTERMOVE)) move = TRUE; if (!hit && !mana && !move) return; for(ch = world[room].people; ch; ch=next_ch) { next_ch = ch->next_in_room; if (IS_PC(ch)) { amount = dice(world[room].numdice, world[room].sizedice); if (hit && GET_HIT(ch) > 0) if (decrease) GET_HIT(ch) -= amount; else GET_HIT(ch) += amount; if (mana) if (decrease) GET_MANA(ch) -= amount; else GET_MANA(ch) += amount; if (move) if (decrease) GET_MOVE(ch) -= amount; else GET_MOVE(ch) += amount; GET_HIT(ch) = MIN(GET_HIT(ch), GET_MAX_HIT(ch)); GET_HIT(ch) = MAX(0, GET_HIT(ch)); GET_MANA(ch) = MIN(GET_MANA(ch), GET_MAX_MANA(ch)); GET_MANA(ch) = MAX(0, GET_MANA(ch)); GET_MOVE(ch) = MIN(GET_MOVE(ch), GET_MAX_MOVE(ch)); GET_MOVE(ch) = MAX(0, GET_MOVE(ch)); update_pos(ch); if (FIGHTING(ch) && GET_HIT(ch) <= 0) stop_fighting(ch); } } } #define TOROOM(x, y) (DIR(x, y)->to_room) // park a transport room at dock, send messages, check next port int transport_dock(int room) { int orig_port; world[room].wait_time = world[room].dock_wait; if (world[room].randoms[4] && *world[room].randoms[4]) send_to_room_not_busy(world[room].randoms[4], room); else send_to_room_not_busy("LUCY!!! WE'RE HOME!!!",room); /* now find next avail port */ orig_port = world[room].to_port; /* save orig port */ if ((world[room].to_port++) > 3) world[room].to_port = 0; while (world[room].portals[(int)world[room].to_port] <= 0) { world[room].to_port++; if (world[room].to_port > 3) world[room].to_port = 0; if (world[room].to_port == orig_port) { sprintf(buf, "SYSERR: Room #%d, not enough ports (case2 transport)", world[room].number); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; } } return TRUE; } // room moves from src to trg in the dir direction int transport_travel(int room, int dir, int src, int trg) { chdata *ch; /* set new location to vnum of dir_option */ world[room].location = world[TOROOM(src,dir)].number; /* we still travelling */ /* how long to wait during travel */ world[room].wait_time = world[room].travel_wait; /* now erase our trail */ world[src].trans_present = -1; /* lucy, we home... */ world[trg].trans_present = world[room].number; if (world[room].randoms[1] && *world[room].randoms[1]) sprintf(buf1, "%s",world[room].randoms[1]); else sprintf(buf1, "%s",world[room].name); sprintf(buf, "%s moves %s.", buf1, dirs[dir]); send_to_room_not_busy(buf, src); if (world[room].randoms[3] && *world[room].randoms[3]) sprintf(buf, "%s %s.", world[room].randoms[3], dirs[dir]); send_to_room_not_busy(buf, room); sprintf(buf, "%s arrives from %s.", buf1, rev_dir_str[dir]); send_to_room_not_busy(buf, trg); /* have everybody do_look here perhaps */ for (ch = world[room].people; ch; ch = ch->next_in_room) { ch->in_room = trg; do_look_at_room(ch,0,-1); ch->in_room = room; } return TRUE; } // move trannie from one room to another int move_transport_room(int room) { int src, trg, curr, dir; extern int find_first_step_terrain(int src, int trg); int zone = world[room].zone; if (ZONE_IDLE(zone) && ZONE_FREED(zone)) return FALSE; src = real_room(world[room].location); if (src < 0) { mudlog("SYSERR: src room not valid, move_transport_room, graph.c", BRF, LEV_IMM, TRUE); return FALSE; } curr = world[room].to_port; /* note can only be 0 - 3 */ if (curr < 0 || curr > 3) { mudlog("SYSERR: invalid to_port room, move_transport, graph.c", BRF, LEV_IMM, TRUE); return FALSE; } trg = real_room(RPORTAL(room, curr)); if (trg < 0) { mudlog("SYSERR: trg room not valid, move_transport_room, graph.c",BRF, LEV_IMM, TRUE); return FALSE; } dir = find_first_step_terrain(src, trg); switch(dir) { case BFS_ERROR: sprintf(buf, "SYSERR: Room #%d, BFS_ERROR (case1 transport)", world[room].number); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; break; case BFS_ALREADY_THERE: if (world[room].wait_time > 0) { world[room].wait_time--; return TRUE; } return (transport_dock(room)); break; case BFS_NO_PATH: sprintf(buf, "SYSERR: Room #%d, BFS_NO_PATH ", world[room].number); mudlog(buf, BRF, LEV_IMM, FALSE); return FALSE; break; default: // ok, take next step, check if arrived if (world[room].wait_time) { world[room].wait_time--; return TRUE; } /* check it */ if ((trg = real_room(world[TOROOM(src, dir)].number)) < 0) { log("SYSERR: trg room not valid, move_transport_room, graph.c"); return FALSE; } // move once transport_travel(room, dir, src, trg); // if we're there, dock it, set up next port if (trg == real_room(RPORTAL(room, (int) world[room].to_port))) return (transport_dock(room)); return TRUE; break; } } void close_door(int orig, int i) { int room; if (DIR(orig, i) && EXIT_ISDOOR(DIR(orig, i)) && EXIT_OPEN(DIR(orig, i))) { FLAG_EXIT(DIR(orig, i), EX_CLOSED); for (room = 0; room < top_of_world; room++) if (DIR(room, rev_dir[i]) && EXIT_ISDOOR(DIR(room, rev_dir[i])) && EXIT_OPEN(DIR(room, rev_dir[i])) && DIR(room, rev_dir[i])->to_room == orig) { FLAG_EXIT(DIR(room, rev_dir[i]), EX_CLOSED); sprintf(buf, "The direction %s has closed.",dirs[rev_dir[i]]); send_to_room_not_busy(buf, room); } } } void lock_door(int orig, int i) { int room; if (DIR(orig, i) && EXIT_ISDOOR(DIR(orig, i)) && !EXIT_OPEN(DIR(orig, i))) { FLAG_EXIT(DIR(orig, i), EX_LOCKED); for (room = 0; room < top_of_world; room++) if (DIR(room, rev_dir[i]) && EXIT_ISDOOR(DIR(room, rev_dir[i])) && !EXIT_OPEN(DIR(room, rev_dir[i])) && DIR(room, rev_dir[i])->to_room == orig) { FLAG_EXIT(DIR(room, rev_dir[i]), EX_LOCKED); } } } void do_exit_autoshut(int room) { int i; for (i = 0; i < NUM_OF_DIRS; i++) if (DIR(room, i) && EXIT_ISDOOR(DIR(room, i)) && EXIT_OPEN(DIR(room, i)) && EXIT_FLAGGED(DIR(room, i), EX_AUTOSHUT) && !EXIT_JAMMED(DIR(room, i))) { close_door(room, i); if (EXIT_FLAGGED(DIR(room, i), EX_AUTOLOCK)) lock_door(room, i); sprintf(buf, "The direction %s has closed.",dirs[i]); send_to_room_not_busy(buf, room); } } // portal all ppl to their loadroom (used to be hard wired into 1904 newbie area) 5/23/98 -jtrhone void do_hometown_portal(int i) { chdata *ch, *next_ch; for (ch = world[i].people; ch; ch=next_ch) { next_ch = ch->next_in_room; if (IS_PC(ch) && !IS_IMMORTAL(ch)) { if (real_room(GET_LOADROOM(ch)) >= 0) { send_to_char("You feel your very soul being shifted to another place!\n\r",ch); char_from_room(ch); char_to_room(ch, real_room(GET_LOADROOM(ch))); do_save(ch, "", 0, 0); do_look_at_room(ch, 0, 0); check_room_affects(ch, ch->in_room); } } } } /* control various room aspects */ // add rprocs 6/5/98 -jtrhone void room_activity(BOOL dtime) { int i; chdata *ch, *next_ch; int tmp; /* do the drifting and tumbling stuff RoA*/ for (i = 0; i < top_of_world; i++) { if (ZONE_FLAGGED(world[i].zone, Z_IDLE)) continue; // if we at dtime, only update dtime rooms if (dtime && !ROOM_FLAGGED2(i, RPROC_DTIME)) continue; // if any room affects, and ppl in it, do an update if (world[i].people && world[i].room_affects) room_affect_update(i); if (world[i].people && ROOM_FLAGGED(i, RANDOM)) do_room_random(i); /* for random rooms */ /* room can't be in an idle zone */ if (ROOM_FLAGGED2(i, TRANSPORT)) { if (!(tmp = move_transport_room(i))) { sprintf(buf, "SYSERR: Transport failure, room #%d.", world[i].number); mudlog(buf, BRF, LEV_IMM, FALSE); continue; /* next room pleez */ } } else /* we use the same integers here, so must be one or the other */ if (world[i].people && ROOM_FLAGGED(i, PORTAL)) do_room_portal(i); /* for portal rooms */ if (world[i].people && ROOM_FLAGGED(i, ALTERHIT | ALTERMOVE | ALTERMANA)) do_room_alter(i); if (ROOM_FLAGGED(i, WINDY)) do_room_wind(i); /* air stuff */ if (world[i].terrain_type == TERRAIN_UWATER || world[i].terrain_type == TERRAIN_WATER_SWIM || world[i].terrain_type == TERRAIN_WATER_NOSWIM) do_room_drift(i); /* water stuff, uwater and water rooms */ do_exit_autoshut(i); // port all pcs to their loadrooms... 5/23/98 -jtrhone if (ROOM_FLAGGED2(i, HTOWN_PORTAL) && world[i].people) do_hometown_portal(i); /* do the builder defined rprocs for these rooms */ if (ROOM_FLAGGED(i, RPROC)) do_room_rproc(&world[i]); } /* PORTAL ROOM IN STANNEG RoA */ if (((i = real_room(3762)) > 0) && world[i].people) { for (ch = world[i].people; ch; ch=next_ch) { next_ch = ch->next_in_room; if (IS_PC(ch)) { send_to_char("You feel your very soul being shifted to another place!\n\r",ch); act("A %Bblinding light%0 encircles $n and $e disappears.", FALSE, ch, 0, 0, TO_ROOM); switch (GET_CLASS(ch)) { case CLASS_WARRIOR: char_from_room(ch); char_to_room(ch, real_room(3706)); break; case CLASS_BARD: char_from_room(ch); char_to_room(ch, real_room(3773)); break; case CLASS_RANGER: char_from_room(ch); char_to_room(ch, real_room(3763)); break; case CLASS_CLERIC: char_from_room(ch); char_to_room(ch, real_room(3707)); break; case CLASS_MAGE: char_from_room(ch); char_to_room(ch, real_room(3708)); break; case CLASS_THIEF: char_from_room(ch); char_to_room(ch, real_room(3709)); break; case CLASS_SHAMAN: char_from_room(ch); char_to_room(ch, real_room(3710)); break; case CLASS_WARLOCK: char_from_room(ch); char_to_room(ch, real_room(598)); break; case CLASS_MONK: char_from_room(ch); char_to_room(ch, real_room(599)); break; default: break; } do_look_at_room(ch, 0, 0); } } } // check all the descriptors for room music hooks... check_room_music(); } // if player leaves world for whatever reason, set caster to NULL // for each affect he/she has void null_char_room_affects(chdata *ch) { int i; struct room_affect_type *raf; for (i = 0; i < top_of_world; i++) for (raf = world[i].room_affects; raf; raf = raf->next) if (raf->caster == ch) raf->caster = NULL; } /* goes thru room affect list and waxes each member along with ptr to it -roa */ void free_room_affects(struct room_affect_type *head) { struct room_affect_type *ths; struct room_affect_type *temp; ths = head; while(ths) { REMOVE_FROM_LIST(ths, head, next); free_log(ths, "free_room_affects"); ths = head; } } void room_affect_modify(int room, struct room_affect_type *af, BOOL add) { // add any related affects to the affect type if (add) { switch (af->spell) { case SPELL_ROCK_TO_MUD: send_to_room_not_busy("The ground suddenly becomes a mess of mud!", room); break; case SPELL_NATURES_CALTROPS: send_to_room_not_busy("From the ground springs wickedly-pointed spikes!", room); break; case SPELL_FIRESTORM: send_to_room_not_busy("A roaring fills your ears, and the area is consumed in a %B%1storm of fire%0!", room); break; case SPELL_SILENCE: send_to_room_not_busy("An aura of %Bholy silence%0 surrounds the area!",room); break; case SPELL_FIREWALL: send_to_room_not_busy("A %B%1wall of deadly fire%0 suddenly erupts!",room); break; case SPELL_ICEWALL: send_to_room_not_busy("A %B%6storm of deadly ice%0 engulfs the area!",room); break; case SPELL_TYPHOON: send_to_room_not_busy("A deadly %1typhoon%0 explodes out of nothingness!",room); break; case SPELL_VOID: send_to_room_not_busy("A %4temporal void%0 suddenly appears!",room); break; case SPELL_GASCLOUD: send_to_room_not_busy("You cough as a %2cloud of gas%0 suddenly appears!",room); break; case SPELL_BLINDWALL: send_to_room_not_busy("An uneasy %4darkness%0 engulfs the area!",room); break; case SPELL_CONFUSION: send_to_room_not_busy("Something in this area makes you feel confused!",room); break; case SKILL_NOTRACK: send_to_room_not_busy("The tracks around this area slowly fade out of view!",room); break; case SPELL_SHOWEROFLIFE: send_to_room_not_busy("A %B%6shower of heavenly rain%0 suddenly begins to fall!",room); break; case SPELL_CURSED_GROUNDS: send_to_room_not_busy("An uncomfortable feeling suddenly falls over the area!",room); break; case SPELL_ABSOLUTE_WARD: case SPELL_CIRCLE_OF_WARDING: send_to_room_not_busy("This area seems to be warded!",room); break; case SPELL_WALLOFFOG: case SPELL_OCCLUSION: send_to_room_not_busy("%BA wall of fog hangs heavy over the area%0!",room); break; case SPELL_CAMPFIRE: send_to_room_not_busy("A %B%1campfire%0 begins to warm the area!",room); break; case SPELL_AREA_OF_RETURN: break; case SPELL_PROJECT: break; default: break; } } else { switch (af->spell) { case SPELL_ROCK_TO_MUD: send_to_room_not_busy("The ground suddenly solidifies.", room); break; case SPELL_NATURES_CALTROPS: send_to_room_not_busy("The spikes slowly disappear beneath the surface of the ground.", room); break; case SPELL_FIRESTORM: // 04/23/98 -callahan send_to_room_not_busy("The %B%1storm of fire%0 slowly subsides.", room); break; case SPELL_SILENCE: send_to_room_not_busy("An aura of %Bholy silence%0 has been lifted!",room); break; case SPELL_FIREWALL: send_to_room_not_busy("A %B%1wall of deadly fire%0 disappears!",room); break; case SPELL_ICEWALL: send_to_room_not_busy("An %B%6ice storm%0 disappears!",room); break; case SPELL_TYPHOON: send_to_room_not_busy("A deadly %1typhoon%0 wavers in intensity!",room); break; case SPELL_VOID: send_to_room_not_busy("A %4temporal void%0 shimmers and disappears.",room); break; case SPELL_GASCLOUD: send_to_room_not_busy("Suddenly, the %2gas cloud%0 disperses.",room); break; case SPELL_BLINDWALL: send_to_room_not_busy("The strange %4cloak of darkness%0 has been lifted.",room); break; case SPELL_CONFUSION: send_to_room_not_busy("You no longer feel confused.",room); break; case SKILL_NOTRACK: send_to_room_not_busy("The tracks in this area slowly reappear.",room); break; case SPELL_SHOWEROFLIFE: send_to_room_not_busy("A %B%6shower of heavenly rain%0 slowly stops falling.",room); break; case SPELL_CURSED_GROUNDS: send_to_room_not_busy("The uncomfortable feeling in this area dissipates.",room); break; case SPELL_ABSOLUTE_WARD: case SPELL_CIRCLE_OF_WARDING: send_to_room_not_busy("The ward in this area dissipates.",room); break; case SPELL_WALLOFFOG: case SPELL_OCCLUSION: send_to_room_not_busy("%BThe wall of fog dissipates%0!",room); break; case SPELL_CAMPFIRE: send_to_room_not_busy("The %B%1campfire%0 dissipates!",room); break; case SPELL_AREA_OF_RETURN: if (af->caster) { sprintf(buf, "The aura of %s fades from view.", GET_NAME(af->caster)); send_to_room_not_busy(buf, room); send_to_char("Your area of return has dissipated.\n\r",af->caster); } break; case SPELL_PROJECT: if (af->caster) { sprintf(buf, "The projection of %s fades from view.", GET_NAME(af->caster)); send_to_room_not_busy(buf, room); send_to_char("A projection of yours has dissipated.\n\r",af->caster); } break; default: break; } } } // add a certain affect to room affects list void affect_to_room(int room, struct room_affect_type *af) { rmdata *rm = NULL; struct room_affect_type *affected_alloc; if (INVALID_ROOM(room)) { mudlog("SYSERR: Invalid room sent to affect_to_room.", BRF, LEV_IMM, TRUE); return; } rm = &world[room]; // create memory for it CREATE(affected_alloc, struct room_affect_type, 1); // dupe it over *affected_alloc = *af; // insert into room_affect list affected_alloc->next = rm->room_affects; rm->room_affects = affected_alloc; // do affects to room based on it's addition room_affect_modify(room, affected_alloc, TRUE); } // yank from room affect list, called when duration reaches 0 // af must NEVER BE NULL -roa void room_affect_remove(int room, struct room_affect_type *af) { rmdata *rm = NULL; struct room_affect_type *temp; if (INVALID_ROOM(room)) { mudlog("SYSERR: Invalid room sent to room_affect_remove.", BRF, LEV_IMM, TRUE); return; } rm = &world[room]; assert(rm->room_affects); REMOVE_FROM_LIST(af, rm->room_affects, next); // do affects to room based on it's removal (if any) room_affect_modify(room, af, FALSE); free_log(af, "room_affect_remove"); af = NULL; } /* Call room_affect_remove with every spell of spelltype "skill" */ void spell_affect_from_room(int spell, int room) { struct room_affect_type *hjp, *nxt; /* <-- use nxt ptr to one !! */ rmdata *rm = NULL; if (INVALID_ROOM(room)) { mudlog("SYSERR: Invalid room sent to spell_affect_from_room.", BRF, LEV_IMM, TRUE); return; } rm = &world[room]; for (hjp = rm->room_affects; hjp; hjp = nxt) { nxt = hjp->next; if (hjp->spell == spell) room_affect_remove(room, hjp); } } // check character ptrs on this one for when they die or leave game void char_affect_from_room(chdata *ch, int room) { struct room_affect_type *hjp, *nxt; /* <-- use nxt ptr to one !! */ rmdata *rm = NULL; if (INVALID_ROOM(room)) { mudlog("SYSERR: Invalid room sent to char_affect_from_room.", BRF, LEV_IMM, TRUE); return; } rm = &world[room]; for (hjp = rm->room_affects; hjp; hjp = nxt) { nxt = hjp->next; if (hjp->caster == ch) room_affect_remove(room, hjp); } } // check character ptrs on this one for when they die or leave game void char_spell_affect_from_room(chdata *ch, int spell, int room) { struct room_affect_type *hjp, *nxt; /* <-- use nxt ptr to one !! */ rmdata *rm = NULL; if (INVALID_ROOM(room)) { mudlog("SYSERR: Invalid room sent to char_spell_affect_from_room.", BRF, LEV_IMM, TRUE); return; } rm = &world[room]; for (hjp = rm->room_affects; hjp; hjp = nxt) { nxt = hjp->next; if (hjp->caster == ch && hjp->spell == spell) room_affect_remove(room, hjp); } } // check character ptrs on this one for when they die or leave game BOOL char_affects_room(chdata *ch, int room) { struct room_affect_type *hjp; rmdata *rm = NULL; if (INVALID_ROOM(room)) return FALSE; rm = &world[room]; for (hjp = rm->room_affects; hjp; hjp = hjp->next) if (hjp->caster == ch) return TRUE; return FALSE; } // return TRUE if this character casted this spell on this room struct room_affect_type *char_spell_affects_room(chdata *ch, int spell, int room) { struct room_affect_type *hjp; rmdata *rm = NULL; if (INVALID_ROOM(room)) return NULL; rm = &world[room]; for (hjp = rm->room_affects; hjp; hjp = hjp->next) if (hjp->caster == ch && hjp->spell == spell) return hjp; return NULL; } // scan list for particular spell in room affects, return it if found struct room_affect_type *spell_affects_room(int room, int spell) { struct room_affect_type *raf; rmdata *rm = NULL; if (INVALID_ROOM(room)) return NULL; rm = &world[room]; if (!rm->room_affects) return NULL; // scan list and apply any affects for (raf = rm->room_affects; raf; raf = raf->next) if (raf->spell == spell) return raf; return NULL; } BOOL room_align_probs(chdata *ch, int bitv) { if (IS_SET(bitv, RMAFF_VS_EVIL) && IS_EVIL(ch)) return TRUE; if (IS_SET(bitv, RMAFF_VS_NEUTRAL) && IS_NEUTRAL(ch)) return TRUE; if (IS_SET(bitv, RMAFF_VS_GOOD) && IS_GOOD(ch)) return TRUE; return FALSE; } // called when character enters room int check_room_affects(chdata *ch, int room) { struct room_affect_type *raf; struct song_affect *sg; struct affected_type af; int dam; rmdata *rm = NULL; if (INVALID_ROOM(room)) return CHAR_OK; rm = &world[room]; if (!rm->room_affects) return CHAR_OK; // scan list and apply any affects for (raf = rm->room_affects; raf; raf = raf->next) { switch (raf->spell) { case SPELL_FIRESTORM: // 04/23/98 -callahan if (saves_spell(ch, SPELL_FIRESTORM)) act("The %B%1storm of fire%0 passes you harmlessly by!", FALSE, ch, 0, 0, TO_CHAR); else { act("The %B%1storm of fire%0 agonizingly caresses you!", FALSE, ch, 0, 0, TO_CHAR); act("The %B%1storm of fire%0 caresses $n painfully!", FALSE, ch, 0, 0, TO_ROOM); if (raf->caster) dam = number(1, Level(raf->caster)); else dam = number(1, (LEV_IMPL / 2)); Hits(ch) -= dam; } break; case SPELL_SILENCE: // remove all songs from character entering here if (SINGING(ch)) do_finish(ch, "song", 0, 0); if (PLAYING(ch)) do_finish(ch, "tune", 0, 0); if ((sg = ch->specials.songs)) while (sg) { song_from_char(ch, sg); sg = ch->specials.songs; } act("This area is strangely %Bsilent%0!!",FALSE,ch,0,0,TO_CHAR); break; case SPELL_FIREWALL: if (saves_spell(ch, SPELL_FIREWALL)) act("You resist the %B%1firewall%0!",FALSE,ch,0,0,TO_CHAR); else { act("The %B%1firewall%0 sears your skin!",FALSE,ch,0,0,TO_CHAR); act("The %B%1firewall%0 sears $n's skin!",FALSE,ch,0,0,TO_ROOM); if (raf->caster) dam = number(1, GET_LEVEL(raf->caster)); else dam = number(1, (LEV_IMPL / 2)); GET_HIT(ch) -= dam; } break; case SPELL_ICEWALL: if (saves_spell(ch, SPELL_ICEWALL)) act("You resist the %B%6ice storm%0!",FALSE,ch,0,0,TO_CHAR); else { act("The %B%6ice storm%0 pelts your skin!",FALSE,ch,0,0,TO_CHAR); act("The %B%6ice storm%0 pelts $n's skin!",FALSE,ch,0,0,TO_ROOM); if (raf->caster) dam = number(1, GET_LEVEL(raf->caster)); else dam = number(1, (LEV_IMPL / 2)); GET_HIT(ch) -= dam * 3/2; } break; case SPELL_TYPHOON: if (saves_spell(ch, SPELL_TYPHOON)) act("You resist the %1typhoon%0!",FALSE,ch,0,0,TO_CHAR); else { act("A deadly %1typhoon%0 rampages around you!",FALSE,ch,0,0,TO_CHAR); if (raf->caster) dam = number(1, GET_LEVEL(raf->caster)); else dam = number(1, (LEV_IMPL / 2)); GET_HIT(ch) -= dam * 2; } break; case SPELL_VOID: act("A %4temporal void%0 shimmers slightly around you!",FALSE,ch,0,0,TO_CHAR); break; case SPELL_GASCLOUD: if (saves_spell(ch, SPELL_GASCLOUD) || affected_by_spell(ch, SPELL_GASCLOUD)) act("You resist the %2gas cloud%0!",FALSE,ch,0,0,TO_CHAR); else { act("You suddenly feel very sick!",FALSE,ch,0,0,TO_CHAR); act("$n suddenly looks very sick!",FALSE,ch,0,0,TO_ROOM); if (raf->caster) af.duration = GET_LEVEL(raf->caster) / 5; else af.duration = (LEV_IMPL / 2) / 5; af.type = SPELL_GASCLOUD; af.modifier = -2; af.location = APPLY_STR; af.bitvector = AFF_POISON; af.bitvector2 = 0; affect_to_char(ch, &af); af.location = APPLY_DEX; affect_to_char(ch, &af); } break; case SPELL_BLINDWALL: if (saves_spell(ch, SPELL_BLINDWALL) || affected_by_spell(ch, SPELL_BLINDWALL)) act("You resist the %4strange darkness%0!",FALSE,ch,0,0,TO_CHAR); else { act("Your vision has vanished!",FALSE,ch,0,0,TO_CHAR); act("$n's eyes turn a strange color!",FALSE,ch,0,0,TO_ROOM); if (raf->caster) { af.duration = GET_LEVEL(raf->caster) / 5; act("Visions of $N %B%1rage%0 through your mind!",FALSE,ch,0,raf->caster,TO_CHAR); } else af.duration = (LEV_IMPL / 2) / 5; af.type = SPELL_BLINDWALL; af.modifier = -4; af.location = APPLY_DEX; af.bitvector = AFF_BLIND; af.bitvector2 = 0; affect_to_char(ch, &af); } break; case SPELL_CONFUSION: if (IS_IMMORTAL(ch) && PLR_FLAGGED(ch, PLR_LOGALL)) act("A confusion spell affects this room.",FALSE,ch,0,0,TO_CHAR); break; case SKILL_NOTRACK: if (IS_IMMORTAL(ch) && PLR_FLAGGED(ch, PLR_LOGALL)) act("A notrack skill affects this room.",FALSE,ch,0,0,TO_CHAR); break; case SPELL_SHOWEROFLIFE: act("The %B%6shower of life%0 soothes your spirit!",FALSE,ch,0,0,TO_CHAR); act("The %B%6shower of life%0 soothes $n's spirit!",FALSE,ch,0,0,TO_ROOM); if (raf->caster) dam = number(1, GET_LEVEL(raf->caster)/2); else dam = number(1, (LEV_IMPL / 4)); GET_HIT(ch) += dam; GET_HIT(ch) = MIN(GET_MAX_HIT(ch), GET_HIT(ch)); break; case SPELL_CURSED_GROUNDS: if (saves_spell(ch, SPELL_CURSED_GROUNDS) || affected_by_spell(ch, SPELL_CURSE)) act("You resist the curse spread over this area!",FALSE,ch,0,0,TO_CHAR); else { act("You suddenly feel very uncomfortable!",FALSE,ch,0,0,TO_CHAR); act("$n briefly reveals a red aura!", FALSE, ch, 0, 0, TO_ROOM); if (raf->caster) act("Visions of $N %B%1rage%0 through your mind!",FALSE,ch,0,raf->caster,TO_CHAR); af.type = SPELL_CURSE; af.duration = 24 * 7; /* 7 Days */ af.modifier = -1; af.location = APPLY_HITROLL; af.bitvector = AFF_CURSE; af.bitvector2 = 0; affect_to_char(ch, &af); af.location = APPLY_SV_MAGIC; af.modifier = -30; /* Make worse */ affect_to_char(ch, &af); } break; case SPELL_ABSOLUTE_WARD: if (raf->caster != ch) act("A %4ward%0 seems to hang over the area.",FALSE,ch,0,0,TO_CHAR); break; case SPELL_CIRCLE_OF_WARDING: if (raf->caster != ch && room_align_probs(ch, raf->bitvector)) act("A %4ward%0 seems to hang over the area!",FALSE,ch,0,0,TO_CHAR); break; case SPELL_WALLOFFOG: case SPELL_OCCLUSION: // ranger add 3/27/98 -jtrhone if (raf->caster != ch) act("A %Bwall of fog%0 seems to hang over the area.",FALSE,ch,0,0,TO_CHAR); break; // ranger add 3/27/98 -jtrhone case SPELL_CAMPFIRE: act("The warmth from the %B%1campfire%0 soothes your soul!",FALSE,ch,0,0,TO_CHAR); act("The warmth from the %B%1campfire%0 soothes $n's soul!",FALSE,ch,0,0,TO_ROOM); if (raf->caster) dam = number(1, GET_LEVEL(raf->caster)/2); else dam = number(1, (LEV_IMPL / 4)); GET_HIT(ch) += dam; GET_HIT(ch) = MIN(GET_MAX_HIT(ch), GET_HIT(ch)); GET_MOVE(ch) += dam; GET_MOVE(ch) = MIN(GET_MAX_MOVE(ch), GET_MOVE(ch)); break; case SPELL_AREA_OF_RETURN: if (IS_IMMORTAL(ch) && PLR_FLAGGED(ch, PLR_LOGALL)) act("An area of return spell affects this room.",FALSE,ch,0,0,TO_CHAR); break; case SPELL_PROJECT: if (IS_IMMORTAL(ch) && PLR_FLAGGED(ch, PLR_LOGALL)) act("An projection spell affects this room.",FALSE,ch,0,0,TO_CHAR); break; default: break; } // end of switch update_pos(ch); if (GET_POS(ch) == POS_DEAD) { die(ch, FALSE); return CHAR_DIED; } } return CHAR_OK; } // update / check saves for every player in room // short and sweet? lesse if this works ok void room_affect_update(int room) { struct room_affect_type *raf, *nxtraf, dupraf; chdata *ch, *next_ch; int dir; rmdata *rm = NULL; if (INVALID_ROOM(room)) return; rm = &world[room]; for (ch = rm->people; ch; ch = next_ch) { next_ch = ch->next_in_room; check_room_affects(ch, room); } if (!rm->room_affects) return; // scan list and move special room affectual spells (ex. typhoon) for (raf = rm->room_affects; raf; raf = nxtraf) { nxtraf = raf->next; switch (raf->spell) { case SPELL_TYPHOON: // find direction to go dir = number(0, NUM_OF_DIRS - 1); // if found, transfer affects (dupe over) if (DIR(room, dir) && DIR(room, dir)->to_room > 0) { dupraf = *raf; room_affect_remove(room, raf); affect_to_room(DIR(room,dir)->to_room, &dupraf); sprintf(buf, "A deadly %%1typhoon%%0 moves %s!",dirs[dir]); send_to_room_not_busy(buf, room); sprintf(buf, "A deadly %%1typhoon%%0 arrives from %s!",rev_dir_str[dir]); send_to_room_not_busy(buf, DIR(room, dir)->to_room); } break; } } } // No longer save object files in BINARY format // save them in text format (re: objsave.c) -roa void crashsave_room(int vnum) { int rnum; char fname[128]; FILE *fp; extern int inv_count(obdata *ob); extern void extract_norents(obdata *ob); if ((rnum = real_room(vnum)) < 0) return; sprintf(fname, "rmobjs/%d.roa",vnum); if (!(fp = fopen(fname, "w"))) { sprintf(buf, "SYSERR: Error opening room object file %d",vnum); mudlog(buf, BRF, LEV_IMM, TRUE); return; } if (inv_count(world[rnum].contents) > MAX_HOUSE_OBJS) { sprintf(buf, "%%1WARNING%%0: Max room contents (%d) exceeded.\n\r" "Room contents not saved.\n\r", MAX_HOUSE_OBJS); send_to_room(buf, rnum); fclose(fp); return; } // if nothing in room, remove file and return if (!world[rnum].contents) { fclose(fp); remove(fname); return; } // get rid of the non rentables in the room (keys/mails etc) -roa extract_norents(world[rnum].contents); // check one more time just so we're not calling a function for no reason // if the room only had norents, now it has nothing, remove file and return if (!world[rnum].contents) { fclose(fp); remove(fname); return; } // save_object is recursive, just send the first object in the list // re: objsave.c if (!save_object(world[rnum].contents, fp)) { fclose(fp); send_to_room("Error saving room contents, notify an immortal...\n\r",rnum); return; } fclose(fp); send_to_room("Saving room...\n\r", rnum); REMOVE_BIT(ROOM_FLAGS2(rnum), HOUSE_CRASH | ROOM_CRASH); sprintf(buf, "SYSUPD: Room objects #%d saved.", vnum); mudlog(buf, BUG, LEV_IMM, FALSE); } // wax a room file from disk, mudlog any errors -roa void delete_room_file(int vnum) { char fname[128]; FILE *fp; sprintf(fname, "rmobjs/%d.roa",vnum); if (!(fp = fopen(fname, "r"))) { if (errno != ENOENT) { sprintf(buf, "SYSERR: Error deleting room object file #%d. (1)", vnum); mudlog(buf, BRF, LEV_IMM, TRUE); } return; } fclose(fp); if (unlink(fname) < 0) { sprintf(buf, "SYSERR: Error deleting room object file #%d. (2)", vnum); mudlog(buf, BRF, LEV_IMM, TRUE); } } void room_save_all(void) { int i; for (i=0; i < top_of_world; i++) if (ROOM_FLAGGED2(i, ROOM_CRASH)) crashsave_room(world[i].number); }