handler.c
1 /* ************************************************************************ 2 * File: handler.c Part of CircleMUD * 3 * Usage: internal funcs: moving and finding chars/objs * 4 * * 5 * All rights reserved. See license.doc for complete information. * 6 * * 7 * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * 8 * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * 9 ************************************************************************ */ 10 11 #include "conf.h" 12 #include "sysdep.h" 13 14 15 #include "structs.h" 16 #include "utils.h" 17 #include "comm.h" 18 #include "db.h" 19 #include "handler.h" 20 #include "interpreter.h" 21 #include "spells.h" 22 23 /* local vars */ 24 int extractions_pending = 0; 25 26 /* external vars */ 27 extern struct char_data *combat_list; 28 extern const char *MENU; 29 30 /* local functions */ 31 int apply_ac(struct char_data *ch, int eq_pos); 32 void update_object(struct obj_data *obj, int use); 33 void update_char_objects(struct char_data *ch); 34 35 /* external functions */ 36 int invalid_class(struct char_data *ch, struct obj_data *obj); 37 void remove_follower(struct char_data *ch); 38 void clearMemory(struct char_data *ch); 39 ACMD(do_return); 40 41 char *fname(const char *namelist) 42 { 43 static char holder[30]; 44 char *point; 45 46 for (point = holder; isalpha(*namelist); namelist++, point++) 47 *point = *namelist; 48 49 *point = '\0'; 50 51 return (holder); 52 } 53 54 55 int isname(const char *str, const char *namelist) 56 { 57 const char *curname, *curstr; 58 59 curname = namelist; 60 for (;;) { 61 for (curstr = str;; curstr++, curname++) { 62 if (!*curstr && !isalpha(*curname)) 63 return (1); 64 65 if (!*curname) 66 return (0); 67 68 if (!*curstr || *curname == ' ') 69 break; 70 71 if (LOWER(*curstr) != LOWER(*curname)) 72 break; 73 } 74 75 /* skip to next name */ 76 77 for (; isalpha(*curname); curname++); 78 if (!*curname) 79 return (0); 80 curname++; /* first char of new name */ 81 } 82 } 83 84 85 86 void affect_modify(struct char_data *ch, byte loc, sbyte mod, 87 bitvector_t bitv, bool add) 88 { 89 if (add) 90 SET_BIT(AFF_FLAGS(ch), bitv); 91 else { 92 REMOVE_BIT(AFF_FLAGS(ch), bitv); 93 mod = -mod; 94 } 95 96 switch (loc) { 97 case APPLY_NONE: 98 break; 99 100 case APPLY_STR: 101 GET_STR(ch) += mod; 102 break; 103 case APPLY_DEX: 104 GET_DEX(ch) += mod; 105 break; 106 case APPLY_INT: 107 GET_INT(ch) += mod; 108 break; 109 case APPLY_WIS: 110 GET_WIS(ch) += mod; 111 break; 112 case APPLY_CON: 113 GET_CON(ch) += mod; 114 break; 115 case APPLY_CHA: 116 GET_CHA(ch) += mod; 117 break; 118 119 case APPLY_CLASS: 120 /* ??? GET_CLASS(ch) += mod; */ 121 break; 122 123 /* 124 * My personal thoughts on these two would be to set the person to the 125 * value of the apply. That way you won't have to worry about people 126 * making +1 level things to be imp (you restrict anything that gives 127 * immortal level of course). It also makes more sense to set someone 128 * to a class rather than adding to the class number. -gg 129 */ 130 131 case APPLY_LEVEL: 132 /* ??? GET_LEVEL(ch) += mod; */ 133 break; 134 135 case APPLY_AGE: 136 ch->player.time.birth -= (mod * SECS_PER_MUD_YEAR); 137 break; 138 139 case APPLY_CHAR_WEIGHT: 140 GET_WEIGHT(ch) += mod; 141 break; 142 143 case APPLY_CHAR_HEIGHT: 144 GET_HEIGHT(ch) += mod; 145 break; 146 147 case APPLY_MANA: 148 GET_MAX_MANA(ch) += mod; 149 break; 150 151 case APPLY_HIT: 152 GET_MAX_HIT(ch) += mod; 153 break; 154 155 case APPLY_MOVE: 156 GET_MAX_MOVE(ch) += mod; 157 break; 158 159 case APPLY_GOLD: 160 break; 161 162 case APPLY_EXP: 163 break; 164 165 case APPLY_AC: 166 GET_AC(ch) += mod; 167 break; 168 169 case APPLY_HITROLL: 170 GET_HITROLL(ch) += mod; 171 break; 172 173 case APPLY_DAMROLL: 174 GET_DAMROLL(ch) += mod; 175 break; 176 177 case APPLY_SAVING_PARA: 178 GET_SAVE(ch, SAVING_PARA) += mod; 179 break; 180 181 case APPLY_SAVING_ROD: 182 GET_SAVE(ch, SAVING_ROD) += mod; 183 break; 184 185 case APPLY_SAVING_PETRI: 186 GET_SAVE(ch, SAVING_PETRI) += mod; 187 break; 188 189 case APPLY_SAVING_BREATH: 190 GET_SAVE(ch, SAVING_BREATH) += mod; 191 break; 192 193 case APPLY_SAVING_SPELL: 194 GET_SAVE(ch, SAVING_SPELL) += mod; 195 break; 196 197 default: 198 log("SYSERR: Unknown apply adjust %d attempt (%s, affect_modify).", loc, __FILE__); 199 break; 200 201 } /* switch */ 202 } 203 204 205 206 /* This updates a character by subtracting everything he is affected by */ 207 /* restoring original abilities, and then affecting all again */ 208 void affect_total(struct char_data *ch) 209 { 210 struct affected_type *af; 211 int i, j; 212 213 for (i = 0; i < NUM_WEARS; i++) { 214 if (GET_EQ(ch, i)) 215 for (j = 0; j < MAX_OBJ_AFFECT; j++) 216 affect_modify(ch, GET_EQ(ch, i)->affected[j].location, 217 GET_EQ(ch, i)->affected[j].modifier, 218 GET_OBJ_AFFECT(GET_EQ(ch, i)), FALSE); 219 } 220 221 222 for (af = ch->affected; af; af = af->next) 223 affect_modify(ch, af->location, af->modifier, af->bitvector, FALSE); 224 225 ch->aff_abils = ch->real_abils; 226 227 for (i = 0; i < NUM_WEARS; i++) { 228 if (GET_EQ(ch, i)) 229 for (j = 0; j < MAX_OBJ_AFFECT; j++) 230 affect_modify(ch, GET_EQ(ch, i)->affected[j].location, 231 GET_EQ(ch, i)->affected[j].modifier, 232 GET_OBJ_AFFECT(GET_EQ(ch, i)), TRUE); 233 } 234 235 236 for (af = ch->affected; af; af = af->next) 237 affect_modify(ch, af->location, af->modifier, af->bitvector, TRUE); 238 239 /* Make certain values are between 0..25, not < 0 and not > 25! */ 240 241 i = (IS_NPC(ch) || GET_LEVEL(ch) >= LVL_GRGOD) ? 25 : 18; 242 243 GET_DEX(ch) = MAX(0, MIN(GET_DEX(ch), i)); 244 GET_INT(ch) = MAX(0, MIN(GET_INT(ch), i)); 245 GET_WIS(ch) = MAX(0, MIN(GET_WIS(ch), i)); 246 GET_CON(ch) = MAX(0, MIN(GET_CON(ch), i)); 247 GET_CHA(ch) = MAX(0, MIN(GET_CHA(ch), i)); 248 GET_STR(ch) = MAX(0, GET_STR(ch)); 249 250 if (IS_NPC(ch)) { 251 GET_STR(ch) = MIN(GET_STR(ch), i); 252 } else { 253 if (GET_STR(ch) > 18) { 254 i = GET_ADD(ch) + ((GET_STR(ch) - 18) * 10); 255 GET_ADD(ch) = MIN(i, 100); 256 GET_STR(ch) = 18; 257 } 258 } 259 } 260 261 262 263 /* Insert an affect_type in a char_data structure 264 Automatically sets apropriate bits and apply's */ 265 void affect_to_char(struct char_data *ch, struct affected_type *af) 266 { 267 struct affected_type *affected_alloc; 268 269 CREATE(affected_alloc, struct affected_type, 1); 270 271 *affected_alloc = *af; 272 affected_alloc->next = ch->affected; 273 ch->affected = affected_alloc; 274 275 affect_modify(ch, af->location, af->modifier, af->bitvector, TRUE); 276 affect_total(ch); 277 } 278 279 280 281 /* 282 * Remove an affected_type structure from a char (called when duration 283 * reaches zero). Pointer *af must never be NIL! Frees mem and calls 284 * affect_location_apply 285 */ 286 void affect_remove(struct char_data *ch, struct affected_type *af) 287 { 288 struct affected_type *temp; 289 290 if (ch->affected == NULL) { 291 core_dump(); 292 return; 293 } 294 295 affect_modify(ch, af->location, af->modifier, af->bitvector, FALSE); 296 REMOVE_FROM_LIST(af, ch->affected, next); 297 free(af); 298 affect_total(ch); 299 } 300 301 302 303 /* Call affect_remove with every spell of spelltype "skill" */ 304 void affect_from_char(struct char_data *ch, int type) 305 { 306 struct affected_type *hjp, *next; 307 308 for (hjp = ch->affected; hjp; hjp = next) { 309 next = hjp->next; 310 if (hjp->type == type) 311 affect_remove(ch, hjp); 312 } 313 } 314 315 316 317 /* 318 * Return TRUE if a char is affected by a spell (SPELL_XXX), 319 * FALSE indicates not affected. 320 */ 321 bool affected_by_spell(struct char_data *ch, int type) 322 { 323 struct affected_type *hjp; 324 325 for (hjp = ch->affected; hjp; hjp = hjp->next) 326 if (hjp->type == type) 327 return (TRUE); 328 329 return (FALSE); 330 } 331 332 333 334 void affect_join(struct char_data *ch, struct affected_type *af, 335 bool add_dur, bool avg_dur, bool add_mod, bool avg_mod) 336 { 337 struct affected_type *hjp, *next; 338 bool found = FALSE; 339 340 for (hjp = ch->affected; !found && hjp; hjp = next) { 341 next = hjp->next; 342 343 if ((hjp->type == af->type) && (hjp->location == af->location)) { 344 if (add_dur) 345 af->duration += hjp->duration; 346 if (avg_dur) 347 af->duration /= 2; 348 349 if (add_mod) 350 af->modifier += hjp->modifier; 351 if (avg_mod) 352 af->modifier /= 2; 353 354 affect_remove(ch, hjp); 355 affect_to_char(ch, af); 356 found = TRUE; 357 } 358 } 359 if (!found) 360 affect_to_char(ch, af); 361 } 362 363 364 /* move a player out of a room */ 365 void char_from_room(struct char_data *ch) 366 { 367 struct char_data *temp; 368 369 if (ch == NULL || IN_ROOM(ch) == NOWHERE) { 370 log("SYSERR: NULL character or NOWHERE in %s, char_from_room", __FILE__); 371 exit(1); 372 } 373 374 if (FIGHTING(ch) != NULL) 375 stop_fighting(ch); 376 377 if (GET_EQ(ch, WEAR_LIGHT) != NULL) 378 if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT) 379 if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2)) /* Light is ON */ 380 world[IN_ROOM(ch)].light--; 381 382 REMOVE_FROM_LIST(ch, world[IN_ROOM(ch)].people, next_in_room); 383 IN_ROOM(ch) = NOWHERE; 384 ch->next_in_room = NULL; 385 } 386 387 388 /* place a character in a room */ 389 void char_to_room(struct char_data *ch, room_rnum room) 390 { 391 if (ch == NULL || room == NOWHERE || room > top_of_world) 392 log("SYSERR: Illegal value(s) passed to char_to_room. (Room: %d/%d Ch: %p", 393 room, top_of_world, ch); 394 else { 395 ch->next_in_room = world[room].people; 396 world[room].people = ch; 397 IN_ROOM(ch) = room; 398 399 if (GET_EQ(ch, WEAR_LIGHT)) 400 if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT) 401 if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2)) /* Light ON */ 402 world[room].light++; 403 404 /* Stop fighting now, if we left. */ 405 if (FIGHTING(ch) && IN_ROOM(ch) != IN_ROOM(FIGHTING(ch))) { 406 stop_fighting(FIGHTING(ch)); 407 stop_fighting(ch); 408 } 409 } 410 } 411 412 413 /* give an object to a char */ 414 void obj_to_char(struct obj_data *object, struct char_data *ch) 415 { 416 if (object && ch) { 417 object->next_content = ch->carrying; 418 ch->carrying = object; 419 object->carried_by = ch; 420 IN_ROOM(object) = NOWHERE; 421 IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object); 422 IS_CARRYING_N(ch)++; 423 424 /* set flag for crash-save system, but not on mobs! */ 425 if (!IS_NPC(ch)) 426 SET_BIT(PLR_FLAGS(ch), PLR_CRASH); 427 } else 428 log("SYSERR: NULL obj (%p) or char (%p) passed to obj_to_char.", object, ch); 429 } 430 431 432 /* take an object from a char */ 433 void obj_from_char(struct obj_data *object) 434 { 435 struct obj_data *temp; 436 437 if (object == NULL) { 438 log("SYSERR: NULL object passed to obj_from_char."); 439 return; 440 } 441 REMOVE_FROM_LIST(object, object->carried_by->carrying, next_content); 442 443 /* set flag for crash-save system, but not on mobs! */ 444 if (!IS_NPC(object->carried_by)) 445 SET_BIT(PLR_FLAGS(object->carried_by), PLR_CRASH); 446 447 IS_CARRYING_W(object->carried_by) -= GET_OBJ_WEIGHT(object); 448 IS_CARRYING_N(object->carried_by)--; 449 object->carried_by = NULL; 450 object->next_content = NULL; 451 } 452 453 454 455 /* Return the effect of a piece of armor in position eq_pos */ 456 int apply_ac(struct char_data *ch, int eq_pos) 457 { 458 int factor; 459 460 if (GET_EQ(ch, eq_pos) == NULL) { 461 core_dump(); 462 return (0); 463 } 464 465 if (!(GET_OBJ_TYPE(GET_EQ(ch, eq_pos)) == ITEM_ARMOR)) 466 return (0); 467 468 switch (eq_pos) { 469 470 case WEAR_BODY: 471 factor = 3; 472 break; /* 30% */ 473 case WEAR_HEAD: 474 factor = 2; 475 break; /* 20% */ 476 case WEAR_LEGS: 477 factor = 2; 478 break; /* 20% */ 479 default: 480 factor = 1; 481 break; /* all others 10% */ 482 } 483 484 return (factor * GET_OBJ_VAL(GET_EQ(ch, eq_pos), 0)); 485 } 486 487 int invalid_align(struct char_data *ch, struct obj_data *obj) 488 { 489 if (OBJ_FLAGGED(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch)) 490 return TRUE; 491 if (OBJ_FLAGGED(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch)) 492 return TRUE; 493 if (OBJ_FLAGGED(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch)) 494 return TRUE; 495 return FALSE; 496 } 497 498 void equip_char(struct char_data *ch, struct obj_data *obj, int pos) 499 { 500 int j; 501 502 if (pos < 0 || pos >= NUM_WEARS) { 503 core_dump(); 504 return; 505 } 506 507 if (GET_EQ(ch, pos)) { 508 log("SYSERR: Char is already equipped: %s, %s", GET_NAME(ch), 509 obj->short_description); 510 return; 511 } 512 if (obj->carried_by) { 513 log("SYSERR: EQUIP: Obj is carried_by when equip."); 514 return; 515 } 516 if (IN_ROOM(obj) != NOWHERE) { 517 log("SYSERR: EQUIP: Obj is in_room when equip."); 518 return; 519 } 520 if (invalid_align(ch, obj) || invalid_class(ch, obj)) { 521 act("You are zapped by $p and instantly let go of it.", FALSE, ch, obj, 0, TO_CHAR); 522 act("$n is zapped by $p and instantly lets go of it.", FALSE, ch, obj, 0, TO_ROOM); 523 /* Changed to drop in inventory instead of the ground. */ 524 obj_to_char(obj, ch); 525 return; 526 } 527 528 GET_EQ(ch, pos) = obj; 529 obj->worn_by = ch; 530 obj->worn_on = pos; 531 532 if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) 533 GET_AC(ch) -= apply_ac(ch, pos); 534 535 if (IN_ROOM(ch) != NOWHERE) { 536 if (pos == WEAR_LIGHT && GET_OBJ_TYPE(obj) == ITEM_LIGHT) 537 if (GET_OBJ_VAL(obj, 2)) /* if light is ON */ 538 world[IN_ROOM(ch)].light++; 539 } else 540 log("SYSERR: IN_ROOM(ch) = NOWHERE when equipping char %s.", GET_NAME(ch)); 541 542 for (j = 0; j < MAX_OBJ_AFFECT; j++) 543 affect_modify(ch, obj->affected[j].location, 544 obj->affected[j].modifier, 545 GET_OBJ_AFFECT(obj), TRUE); 546 547 affect_total(ch); 548 } 549 550 551 552 struct obj_data *unequip_char(struct char_data *ch, int pos) 553 { 554 int j; 555 struct obj_data *obj; 556 557 if ((pos < 0 || pos >= NUM_WEARS) || GET_EQ(ch, pos) == NULL) { 558 core_dump(); 559 return (NULL); 560 } 561 562 obj = GET_EQ(ch, pos); 563 obj->worn_by = NULL; 564 obj->worn_on = -1; 565 566 if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) 567 GET_AC(ch) += apply_ac(ch, pos); 568 569 if (IN_ROOM(ch) != NOWHERE) { 570 if (pos == WEAR_LIGHT && GET_OBJ_TYPE(obj) == ITEM_LIGHT) 571 if (GET_OBJ_VAL(obj, 2)) /* if light is ON */ 572 world[IN_ROOM(ch)].light--; 573 } else 574 log("SYSERR: IN_ROOM(ch) = NOWHERE when unequipping char %s.", GET_NAME(ch)); 575 576 GET_EQ(ch, pos) = NULL; 577 578 for (j = 0; j < MAX_OBJ_AFFECT; j++) 579 affect_modify(ch, obj->affected[j].location, 580 obj->affected[j].modifier, 581 GET_OBJ_AFFECT(obj), FALSE); 582 583 affect_total(ch); 584 585 return (obj); 586 } 587 588 589 int get_number(char **name) 590 { 591 int i; 592 char *ppos; 593 char number[MAX_INPUT_LENGTH]; 594 595 *number = '\0'; 596 597 if ((ppos = strchr(*name, '.')) != NULL) { 598 *ppos++ = '\0'; 599 strlcpy(number, *name, sizeof(number)); 600 strcpy(*name, ppos); /* strcpy: OK (always smaller) */ 601 602 for (i = 0; *(number + i); i++) 603 if (!isdigit(*(number + i))) 604 return (0); 605 606 return (atoi(number)); 607 } 608 return (1); 609 } 610 611 612 613 /* Search a given list for an object number, and return a ptr to that obj */ 614 struct obj_data *get_obj_in_list_num(int num, struct obj_data *list) 615 { 616 struct obj_data *i; 617 618 for (i = list; i; i = i->next_content) 619 if (GET_OBJ_RNUM(i) == num) 620 return (i); 621 622 return (NULL); 623 } 624 625 626 627 /* search the entire world for an object number, and return a pointer */ 628 struct obj_data *get_obj_num(obj_rnum nr) 629 { 630 struct obj_data *i; 631 632 for (i = object_list; i; i = i->next) 633 if (GET_OBJ_RNUM(i) == nr) 634 return (i); 635 636 return (NULL); 637 } 638 639 640 641 /* search a room for a char, and return a pointer if found.. */ 642 struct char_data *get_char_room(char *name, int *number, room_rnum room) 643 { 644 struct char_data *i; 645 int num; 646 647 if (!number) { 648 number = # 649 num = get_number(&name); 650 } 651 652 if (*number == 0) 653 return (NULL); 654 655 for (i = world[room].people; i && *number; i = i->next_in_room) 656 if (isname(name, i->player.name)) 657 if (--(*number) == 0) 658 return (i); 659 660 return (NULL); 661 } 662 663 664 665 /* search all over the world for a char num, and return a pointer if found */ 666 struct char_data *get_char_num(mob_rnum nr) 667 { 668 struct char_data *i; 669 670 for (i = character_list; i; i = i->next) 671 if (GET_MOB_RNUM(i) == nr) 672 return (i); 673 674 return (NULL); 675 } 676 677 678 679 /* put an object in a room */ 680 void obj_to_room(struct obj_data *object, room_rnum room) 681 { 682 if (!object || room == NOWHERE || room > top_of_world) 683 log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)", 684 room, top_of_world, object); 685 else { 686 object->next_content = world[room].contents; 687 world[room].contents = object; 688 IN_ROOM(object) = room; 689 object->carried_by = NULL; 690 if (ROOM_FLAGGED(room, ROOM_HOUSE)) 691 SET_BIT(ROOM_FLAGS(room), ROOM_HOUSE_CRASH); 692 } 693 } 694 695 696 /* Take an object from a room */ 697 void obj_from_room(struct obj_data *object) 698 { 699 struct obj_data *temp; 700 701 if (!object || IN_ROOM(object) == NOWHERE) { 702 log("SYSERR: NULL object (%p) or obj not in a room (%d) passed to obj_from_room", 703 object, IN_ROOM(object)); 704 return; 705 } 706 707 REMOVE_FROM_LIST(object, world[IN_ROOM(object)].contents, next_content); 708 709 if (ROOM_FLAGGED(IN_ROOM(object), ROOM_HOUSE)) 710 SET_BIT(ROOM_FLAGS(IN_ROOM(object)), ROOM_HOUSE_CRASH); 711 IN_ROOM(object) = NOWHERE; 712 object->next_content = NULL; 713 } 714 715 716 /* put an object in an object (quaint) */ 717 void obj_to_obj(struct obj_data *obj, struct obj_data *obj_to) 718 { 719 struct obj_data *tmp_obj; 720 721 if (!obj || !obj_to || obj == obj_to) { 722 log("SYSERR: NULL object (%p) or same source (%p) and target (%p) obj passed to obj_to_obj.", 723 obj, obj, obj_to); 724 return; 725 } 726 727 obj->next_content = obj_to->contains; 728 obj_to->contains = obj; 729 obj->in_obj = obj_to; 730 731 for (tmp_obj = obj->in_obj; tmp_obj->in_obj; tmp_obj = tmp_obj->in_obj) 732 GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj); 733 734 /* top level object. Subtract weight from inventory if necessary. */ 735 GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj); 736 if (tmp_obj->carried_by) 737 IS_CARRYING_W(tmp_obj->carried_by) += GET_OBJ_WEIGHT(obj); 738 } 739 740 741 /* remove an object from an object */ 742 void obj_from_obj(struct obj_data *obj) 743 { 744 struct obj_data *temp, *obj_from; 745 746 if (obj->in_obj == NULL) { 747 log("SYSERR: (%s): trying to illegally extract obj from obj.", __FILE__); 748 return; 749 } 750 obj_from = obj->in_obj; 751 REMOVE_FROM_LIST(obj, obj_from->contains, next_content); 752 753 /* Subtract weight from containers container */ 754 for (temp = obj->in_obj; temp->in_obj; temp = temp->in_obj) 755 GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj); 756 757 /* Subtract weight from char that carries the object */ 758 GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj); 759 if (temp->carried_by) 760 IS_CARRYING_W(temp->carried_by) -= GET_OBJ_WEIGHT(obj); 761 762 obj->in_obj = NULL; 763 obj->next_content = NULL; 764 } 765 766 767 /* Set all carried_by to point to new owner */ 768 void object_list_new_owner(struct obj_data *list, struct char_data *ch) 769 { 770 if (list) { 771 object_list_new_owner(list->contains, ch); 772 object_list_new_owner(list->next_content, ch); 773 list->carried_by = ch; 774 } 775 } 776 777 778 /* Extract an object from the world */ 779 void extract_obj(struct obj_data *obj) 780 { 781 struct obj_data *temp; 782 783 if (obj->worn_by != NULL) 784 if (unequip_char(obj->worn_by, obj->worn_on) != obj) 785 log("SYSERR: Inconsistent worn_by and worn_on pointers!!"); 786 if (IN_ROOM(obj) != NOWHERE) 787 obj_from_room(obj); 788 else if (obj->carried_by) 789 obj_from_char(obj); 790 else if (obj->in_obj) 791 obj_from_obj(obj); 792 793 /* Get rid of the contents of the object, as well. */ 794 while (obj->contains) 795 extract_obj(obj->contains); 796 797 REMOVE_FROM_LIST(obj, object_list, next); 798 799 if (GET_OBJ_RNUM(obj) != NOTHING) 800 (obj_index[GET_OBJ_RNUM(obj)].number)--; 801 free_obj(obj); 802 } 803 804 805 806 void update_object(struct obj_data *obj, int use) 807 { 808 if (GET_OBJ_TIMER(obj) > 0) 809 GET_OBJ_TIMER(obj) -= use; 810 if (obj->contains) 811 update_object(obj->contains, use); 812 if (obj->next_content) 813 update_object(obj->next_content, use); 814 } 815 816 817 void update_char_objects(struct char_data *ch) 818 { 819 int i; 820 821 if (GET_EQ(ch, WEAR_LIGHT) != NULL) 822 if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT) 823 if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2) > 0) { 824 i = --GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2); 825 if (i == 1) { 826 send_to_char(ch, "Your light begins to flicker and fade.\r\n"); 827 act("$n's light begins to flicker and fade.", FALSE, ch, 0, 0, TO_ROOM); 828 } else if (i == 0) { 829 send_to_char(ch, "Your light sputters out and dies.\r\n"); 830 act("$n's light sputters out and dies.", FALSE, ch, 0, 0, TO_ROOM); 831 world[IN_ROOM(ch)].light--; 832 } 833 } 834 835 for (i = 0; i < NUM_WEARS; i++) 836 if (GET_EQ(ch, i)) 837 update_object(GET_EQ(ch, i), 2); 838 839 if (ch->carrying) 840 update_object(ch->carrying, 1); 841 } 842 843 844 /* Extract a ch completely from the world, and leave his stuff behind */ 845 void extract_char_final(struct char_data *ch) 846 { 847 struct char_data *k, *temp; 848 struct descriptor_data *d; 849 struct obj_data *obj; 850 int i; 851 852 if (IN_ROOM(ch) == NOWHERE) { 853 log("SYSERR: NOWHERE extracting char %s. (%s, extract_char_final)", 854 GET_NAME(ch), __FILE__); 855 exit(1); 856 } 857 858 /* 859 * We're booting the character of someone who has switched so first we 860 * need to stuff them back into their own body. This will set ch->desc 861 * we're checking below this loop to the proper value. 862 */ 863 if (!IS_NPC(ch) && !ch->desc) { 864 for (d = descriptor_list; d; d = d->next) 865 if (d->original == ch) { 866 do_return(d->character, NULL, 0, 0); 867 break; 868 } 869 } 870 871 if (ch->desc) { 872 /* 873 * This time we're extracting the body someone has switched into 874 * (not the body of someone switching as above) so we need to put 875 * the switcher back to their own body. 876 * 877 * If this body is not possessed, the owner won't have a 878 * body after the removal so dump them to the main menu. 879 */ 880 if (ch->desc->original) 881 do_return(ch, NULL, 0, 0); 882 else { 883 /* 884 * Now we boot anybody trying to log in with the same character, to 885 * help guard against duping. CON_DISCONNECT is used to close a 886 * descriptor without extracting the d->character associated with it, 887 * for being link-dead, so we want CON_CLOSE to clean everything up. 888 * If we're here, we know it's a player so no IS_NPC check required. 889 */ 890 for (d = descriptor_list; d; d = d->next) { 891 if (d == ch->desc) 892 continue; 893 if (d->character && GET_IDNUM(ch) == GET_IDNUM(d->character)) 894 STATE(d) = CON_CLOSE; 895 } 896 STATE(ch->desc) = CON_MENU; 897 write_to_output(ch->desc, "%s", MENU); 898 } 899 } 900 901 /* On with the character's assets... */ 902 903 if (ch->followers || ch->master) 904 die_follower(ch); 905 906 /* transfer objects to room, if any */ 907 while (ch->carrying) { 908 obj = ch->carrying; 909 obj_from_char(obj); 910 obj_to_room(obj, IN_ROOM(ch)); 911 } 912 913 /* transfer equipment to room, if any */ 914 for (i = 0; i < NUM_WEARS; i++) 915 if (GET_EQ(ch, i)) 916 obj_to_room(unequip_char(ch, i), IN_ROOM(ch)); 917 918 if (FIGHTING(ch)) 919 stop_fighting(ch); 920 921 for (k = combat_list; k; k = temp) { 922 temp = k->next_fighting; 923 if (FIGHTING(k) == ch) 924 stop_fighting(k); 925 } 926 /* we can't forget the hunters either... */ 927 for (temp = character_list; temp; temp = temp->next) 928 if (HUNTING(temp) == ch) 929 HUNTING(temp) = NULL; 930 931 char_from_room(ch); 932 933 if (IS_NPC(ch)) { 934 if (GET_MOB_RNUM(ch) != NOTHING) /* prototyped */ 935 mob_index[GET_MOB_RNUM(ch)].number--; 936 clearMemory(ch); 937 } else { 938 save_char(ch); 939 Crash_delete_crashfile(ch); 940 } 941 942 /* If there's a descriptor, they're in the menu now. */ 943 if (IS_NPC(ch) || !ch->desc) 944 free_char(ch); 945 } 946 947 948 /* 949 * Q: Why do we do this? 950 * A: Because trying to iterate over the character 951 * list with 'ch = ch->next' does bad things if 952 * the current character happens to die. The 953 * trivial workaround of 'vict = next_vict' 954 * doesn't work if the _next_ person in the list 955 * gets killed, for example, by an area spell. 956 * 957 * Q: Why do we leave them on the character_list? 958 * A: Because code doing 'vict = vict->next' would 959 * get really confused otherwise. 960 */ 961 void extract_char(struct char_data *ch) 962 { 963 if (IS_NPC(ch)) 964 SET_BIT(MOB_FLAGS(ch), MOB_NOTDEADYET); 965 else 966 SET_BIT(PLR_FLAGS(ch), PLR_NOTDEADYET); 967 968 extractions_pending++; 969 } 970 971 972 /* 973 * I'm not particularly pleased with the MOB/PLR 974 * hoops that have to be jumped through but it 975 * hardly calls for a completely new variable. 976 * Ideally it would be its own list, but that 977 * would change the '->next' pointer, potentially 978 * confusing some code. Ugh. -gg 3/15/2001 979 * 980 * NOTE: This doesn't handle recursive extractions. 981 */ 982 void extract_pending_chars(void) 983 { 984 struct char_data *vict, *next_vict, *prev_vict; 985 986 if (extractions_pending < 0) 987 log("SYSERR: Negative (%d) extractions pending.", extractions_pending); 988 989 for (vict = character_list, prev_vict = NULL; vict && extractions_pending; vict = next_vict) { 990 next_vict = vict->next; 991 992 if (MOB_FLAGGED(vict, MOB_NOTDEADYET)) 993 REMOVE_BIT(MOB_FLAGS(vict), MOB_NOTDEADYET); 994 else if (PLR_FLAGGED(vict, PLR_NOTDEADYET)) 995 REMOVE_BIT(PLR_FLAGS(vict), PLR_NOTDEADYET); 996 else { 997 /* Last non-free'd character to continue chain from. */ 998 prev_vict = vict; 999 continue; 1000 } 1001 1002 extract_char_final(vict); 1003 extractions_pending--; 1004 1005 if (prev_vict) 1006 prev_vict->next = next_vict; 1007 else 1008 character_list = next_vict; 1009 } 1010 1011 if (extractions_pending > 0) 1012 log("SYSERR: Couldn't find %d extractions as counted.", extractions_pending); 1013 1014 extractions_pending = 0; 1015 } 1016 1017 1018 /* *********************************************************************** 1019 * Here follows high-level versions of some earlier routines, ie functions* 1020 * which incorporate the actual player-data *. 1021 *********************************************************************** */ 1022 1023 1024 struct char_data *get_player_vis(struct char_data *ch, char *name, int *number, int inroom) 1025 { 1026 struct char_data *i; 1027 int num; 1028 1029 if (!number) { 1030 number = # 1031 num = get_number(&name); 1032 } 1033 1034 for (i = character_list; i; i = i->next) { 1035 if (IS_NPC(i)) 1036 continue; 1037 if (inroom == FIND_CHAR_ROOM && IN_ROOM(i) != IN_ROOM(ch)) 1038 continue; 1039 if (str_cmp(i->player.name, name)) /* If not same, continue */ 1040 continue; 1041 if (!CAN_SEE(ch, i)) 1042 continue; 1043 if (--(*number) != 0) 1044 continue; 1045 return (i); 1046 } 1047 1048 return (NULL); 1049 } 1050 1051 1052 struct char_data *get_char_room_vis(struct char_data *ch, char *name, int *number) 1053 { 1054 struct char_data *i; 1055 int num; 1056 1057 if (!number) { 1058 number = # 1059 num = get_number(&name); 1060 } 1061 1062 /* JE 7/18/94 :-) :-) */ 1063 if (!str_cmp(name, "self") || !str_cmp(name, "me")) 1064 return (ch); 1065 1066 /* 0.<name> means PC with name */ 1067 if (*number == 0) 1068 return (get_player_vis(ch, name, NULL, FIND_CHAR_ROOM)); 1069 1070 for (i = world[IN_ROOM(ch)].people; i && *number; i = i->next_in_room) 1071 if (isname(name, i->player.name)) 1072 if (CAN_SEE(ch, i)) 1073 if (--(*number) == 0) 1074 return (i); 1075 1076 return (NULL); 1077 } 1078 1079 1080 struct char_data *get_char_world_vis(struct char_data *ch, char *name, int *number) 1081 { 1082 struct char_data *i; 1083 int num; 1084 1085 if (!number) { 1086 number = # 1087 num = get_number(&name); 1088 } 1089 1090 if ((i = get_char_room_vis(ch, name, number)) != NULL) 1091 return (i); 1092 1093 if (*number == 0) 1094 return get_player_vis(ch, name, NULL, 0); 1095 1096 for (i = character_list; i && *number; i = i->next) { 1097 if (IN_ROOM(ch) == IN_ROOM(i)) 1098 continue; 1099 if (!isname(name, i->player.name)) 1100 continue; 1101 if (!CAN_SEE(ch, i)) 1102 continue; 1103 if (--(*number) != 0) 1104 continue; 1105 1106 return (i); 1107 } 1108 return (NULL); 1109 } 1110 1111 1112 struct char_data *get_char_vis(struct char_data *ch, char *name, int *number, int where) 1113 { 1114 if (where == FIND_CHAR_ROOM) 1115 return get_char_room_vis(ch, name, number); 1116 else if (where == FIND_CHAR_WORLD) 1117 return get_char_world_vis(ch, name, number); 1118 else 1119 return (NULL); 1120 } 1121 1122 1123 struct obj_data *get_obj_in_list_vis(struct char_data *ch, char *name, int *number, struct obj_data *list) 1124 { 1125 struct obj_data *i; 1126 int num; 1127 1128 if (!number) { 1129 number = # 1130 num = get_number(&name); 1131 } 1132 1133 if (*number == 0) 1134 return (NULL); 1135 1136 for (i = list; i && *number; i = i->next_content) 1137 if (isname(name, i->name)) 1138 if (CAN_SEE_OBJ(ch, i)) 1139 if (--(*number) == 0) 1140 return (i); 1141 1142 return (NULL); 1143 } 1144 1145 1146 /* search the entire world for an object, and return a pointer */ 1147 struct obj_data *get_obj_vis(struct char_data *ch, char *name, int *number) 1148 { 1149 struct obj_data *i; 1150 int num; 1151 1152 if (!number) { 1153 number = # 1154 num = get_number(&name); 1155 } 1156 1157 if (*number == 0) 1158 return (NULL); 1159 1160 /* scan items carried */ 1161 if ((i = get_obj_in_list_vis(ch, name, number, ch->carrying)) != NULL) 1162 return (i); 1163 1164 /* scan room */ 1165 if ((i = get_obj_in_list_vis(ch, name, number, world[IN_ROOM(ch)].contents)) != NULL) 1166 return (i); 1167 1168 /* ok.. no luck yet. scan the entire obj list */ 1169 for (i = object_list; i && *number; i = i->next) 1170 if (isname(name, i->name)) 1171 if (CAN_SEE_OBJ(ch, i)) 1172 if (--(*number) == 0) 1173 return (i); 1174 1175 return (NULL); 1176 } 1177 1178 1179 struct obj_data *get_obj_in_equip_vis(struct char_data *ch, char *arg, int *number, struct obj_data *equipment[]) 1180 { 1181 int j, num; 1182 1183 if (!number) { 1184 number = # 1185 num = get_number(&arg); 1186 } 1187 1188 if (*number == 0) 1189 return (NULL); 1190 1191 for (j = 0; j < NUM_WEARS; j++) 1192 if (equipment[j] && CAN_SEE_OBJ(ch, equipment[j]) && isname(arg, equipment[j]->name)) 1193 if (--(*number) == 0) 1194 return (equipment[j]); 1195 1196 return (NULL); 1197 } 1198 1199 1200 int get_obj_pos_in_equip_vis(struct char_data *ch, char *arg, int *number, struct obj_data *equipment[]) 1201 { 1202 int j, num; 1203 1204 if (!number) { 1205 number = # 1206 num = get_number(&arg); 1207 } 1208 1209 if (*number == 0) 1210 return (-1); 1211 1212 for (j = 0; j < NUM_WEARS; j++) 1213 if (equipment[j] && CAN_SEE_OBJ(ch, equipment[j]) && isname(arg, equipment[j]->name)) 1214 if (--(*number) == 0) 1215 return (j); 1216 1217 return (-1); 1218 } 1219 1220 1221 const char *money_desc(int amount) 1222 { 1223 int cnt; 1224 struct { 1225 int limit; 1226 const char *description; 1227 } money_table[] = { 1228 { 1, "a gold coin" }, 1229 { 10, "a tiny pile of gold coins" }, 1230 { 20, "a handful of gold coins" }, 1231 { 75, "a little pile of gold coins" }, 1232 { 200, "a small pile of gold coins" }, 1233 { 1000, "a pile of gold coins" }, 1234 { 5000, "a big pile of gold coins" }, 1235 { 10000, "a large heap of gold coins" }, 1236 { 20000, "a huge mound of gold coins" }, 1237 { 75000, "an enormous mound of gold coins" }, 1238 { 150000, "a small mountain of gold coins" }, 1239 { 250000, "a mountain of gold coins" }, 1240 { 500000, "a huge mountain of gold coins" }, 1241 { 1000000, "an enormous mountain of gold coins" }, 1242 { 0, NULL }, 1243 }; 1244 1245 if (amount <= 0) { 1246 log("SYSERR: Try to create negative or 0 money (%d).", amount); 1247 return (NULL); 1248 } 1249 1250 for (cnt = 0; money_table[cnt].limit; cnt++) 1251 if (amount <= money_table[cnt].limit) 1252 return (money_table[cnt].description); 1253 1254 return ("an absolutely colossal mountain of gold coins"); 1255 } 1256 1257 1258 struct obj_data *create_money(int amount) 1259 { 1260 struct obj_data *obj; 1261 struct extra_descr_data *new_descr; 1262 char buf[200]; 1263 1264 if (amount <= 0) { 1265 log("SYSERR: Try to create negative or 0 money. (%d)", amount); 1266 return (NULL); 1267 } 1268 obj = create_obj(); 1269 CREATE(new_descr, struct extra_descr_data, 1); 1270 1271 if (amount == 1) { 1272 obj->name = strdup("coin gold"); 1273 obj->short_description = strdup("a gold coin"); 1274 obj->description = strdup("One miserable gold coin is lying here."); 1275 new_descr->keyword = strdup("coin gold"); 1276 new_descr->description = strdup("It's just one miserable little gold coin."); 1277 } else { 1278 obj->name = strdup("coins gold"); 1279 obj->short_description = strdup(money_desc(amount)); 1280 snprintf(buf, sizeof(buf), "%s is lying here.", money_desc(amount)); 1281 obj->description = strdup(CAP(buf)); 1282 1283 new_descr->keyword = strdup("coins gold"); 1284 if (amount < 10) 1285 snprintf(buf, sizeof(buf), "There are %d coins.", amount); 1286 else if (amount < 100) 1287 snprintf(buf, sizeof(buf), "There are about %d coins.", 10 * (amount / 10)); 1288 else if (amount < 1000) 1289 snprintf(buf, sizeof(buf), "It looks to be about %d coins.", 100 * (amount / 100)); 1290 else if (amount < 100000) 1291 snprintf(buf, sizeof(buf), "You guess there are, maybe, %d coins.", 1292 1000 * ((amount / 1000) + rand_number(0, (amount / 1000)))); 1293 else 1294 strcpy(buf, "There are a LOT of coins."); /* strcpy: OK (is < 200) */ 1295 new_descr->description = strdup(buf); 1296 } 1297 1298 new_descr->next = NULL; 1299 obj->ex_description = new_descr; 1300 1301 GET_OBJ_TYPE(obj) = ITEM_MONEY; 1302 GET_OBJ_WEAR(obj) = ITEM_WEAR_TAKE; 1303 GET_OBJ_VAL(obj, 0) = amount; 1304 GET_OBJ_COST(obj) = amount; 1305 obj->item_number = NOTHING; 1306 1307 return (obj); 1308 } 1309 1310 1311 /* Generic Find, designed to find any object/character 1312 * 1313 * Calling: 1314 * *arg is the pointer containing the string to be searched for. 1315 * This string doesn't have to be a single word, the routine 1316 * extracts the next word itself. 1317 * bitv.. All those bits that you want to "search through". 1318 * Bit found will be result of the function 1319 * *ch This is the person that is trying to "find" 1320 * **tar_ch Will be NULL if no character was found, otherwise points 1321 * **tar_obj Will be NULL if no object was found, otherwise points 1322 * 1323 * The routine used to return a pointer to the next word in *arg (just 1324 * like the one_argument routine), but now it returns an integer that 1325 * describes what it filled in. 1326 */ 1327 int generic_find(char *arg, bitvector_t bitvector, struct char_data *ch, 1328 struct char_data **tar_ch, struct obj_data **tar_obj) 1329 { 1330 int i, found, number; 1331 char name_val[MAX_INPUT_LENGTH]; 1332 char *name = name_val; 1333 1334 *tar_ch = NULL; 1335 *tar_obj = NULL; 1336 1337 one_argument(arg, name); 1338 1339 if (!*name) 1340 return (0); 1341 if (!(number = get_number(&name))) 1342 return (0); 1343 1344 if (IS_SET(bitvector, FIND_CHAR_ROOM)) { /* Find person in room */ 1345 if ((*tar_ch = get_char_room_vis(ch, name, &number)) != NULL) 1346 return (FIND_CHAR_ROOM); 1347 } 1348 1349 if (IS_SET(bitvector, FIND_CHAR_WORLD)) { 1350 if ((*tar_ch = get_char_world_vis(ch, name, &number)) != NULL) 1351 return (FIND_CHAR_WORLD); 1352 } 1353 1354 if (IS_SET(bitvector, FIND_OBJ_EQUIP)) { 1355 for (found = FALSE, i = 0; i < NUM_WEARS && !found; i++) 1356 if (GET_EQ(ch, i) && isname(name, GET_EQ(ch, i)->name) && --number == 0) { 1357 *tar_obj = GET_EQ(ch, i); 1358 found = TRUE; 1359 } 1360 if (found) 1361 return (FIND_OBJ_EQUIP); 1362 } 1363 1364 if (IS_SET(bitvector, FIND_OBJ_INV)) { 1365 if ((*tar_obj = get_obj_in_list_vis(ch, name, &number, ch->carrying)) != NULL) 1366 return (FIND_OBJ_INV); 1367 } 1368 1369 if (IS_SET(bitvector, FIND_OBJ_ROOM)) { 1370 if ((*tar_obj = get_obj_in_list_vis(ch, name, &number, world[IN_ROOM(ch)].contents)) != NULL) 1371 return (FIND_OBJ_ROOM); 1372 } 1373 1374 if (IS_SET(bitvector, FIND_OBJ_WORLD)) { 1375 if ((*tar_obj = get_obj_vis(ch, name, &number))) 1376 return (FIND_OBJ_WORLD); 1377 } 1378 1379 return (0); 1380 } 1381 1382 1383 /* a function to scan for "all" or "all.x" */ 1384 int find_all_dots(char *arg) 1385 { 1386 if (!strcmp(arg, "all")) 1387 return (FIND_ALL); 1388 else if (!strncmp(arg, "all.", 4)) { 1389 strcpy(arg, arg + 4); /* strcpy: OK (always less) */ 1390 return (FIND_ALLDOT); 1391 } else 1392 return (FIND_INDIV); 1393 }