00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034 #include <global.h>
00035 #ifndef __CEXTRACT__
00036 #include <sproto.h>
00037 #endif
00038
00045 static void mark_inventory_as_no_drop(object *ob) {
00046 object *tmp;
00047
00048 for (tmp = ob->inv; tmp != NULL; tmp = tmp->below) {
00049 SET_FLAG(tmp, FLAG_NO_DROP);
00050 }
00051 }
00052
00067 object *get_pet_enemy(object *pet, rv_vector *rv) {
00068 object *owner, *tmp, *attacker, *tmp3;
00069 int i;
00070 sint16 x, y;
00071 mapstruct *nm;
00072 int search_arr[SIZEOFFREE];
00073 int mflags;
00074
00075 attacker = pet->attacked_by;
00076 pet->attacked_by = NULL;
00077
00078 if ((owner = get_owner(pet)) != NULL) {
00079
00080
00081
00082 if ((check_enemy(owner, rv)) == pet) {
00083 CLEAR_FLAG(pet, FLAG_FRIENDLY);
00084 remove_friendly_object(pet);
00085 pet->attack_movement &= ~PETMOVE;
00086 return owner;
00087 }
00088 } else {
00089
00090
00091
00092 CLEAR_FLAG(pet, FLAG_FRIENDLY);
00093 remove_friendly_object(pet);
00094 pet->attack_movement &= ~PETMOVE;
00095 return NULL;
00096 }
00097
00098 if (!on_same_map(pet, owner))
00099 return NULL;
00100
00101
00102 if ((tmp = check_enemy(pet, rv)) != NULL) {
00103 if (tmp == owner && !QUERY_FLAG(pet, FLAG_CONFUSED)
00104 && QUERY_FLAG(pet, FLAG_FRIENDLY))
00105
00106
00107
00108 pet->enemy = NULL;
00109 else
00110 return tmp;
00111 }
00112 get_search_arr(search_arr);
00113
00114 if (owner->type == PLAYER && owner->contr->petmode > pet_normal) {
00115 if (owner->contr->petmode == pet_sad) {
00116 tmp = find_nearest_living_creature(pet);
00117 if (tmp != NULL) {
00118 get_rangevector(pet, tmp, rv, 0);
00119 if (check_enemy(pet, rv) != NULL)
00120 return tmp;
00121 else
00122 pet->enemy = NULL;
00123 }
00124
00125
00126 pet->enemy = NULL;
00127 return NULL;
00128 }
00129 }
00130
00131
00132
00133
00134 tmp3 = NULL;
00135 for (i = 0; i < SIZEOFFREE; i++) {
00136 x = owner->x+freearr_x[search_arr[i]];
00137 y = owner->y+freearr_y[search_arr[i]];
00138 nm = owner->map;
00139
00140 mflags = get_map_flags(nm, &nm, x, y, &x, &y);
00141 if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
00142 for (tmp = GET_MAP_OB(nm, x, y); tmp != NULL; tmp = tmp->above) {
00143 object *tmp2 = tmp->head == NULL ? tmp : tmp->head;
00144
00145 if (QUERY_FLAG(tmp2, FLAG_ALIVE)
00146 && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || should_arena_attack(pet, owner, tmp2))
00147 && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
00148 && tmp2 != pet
00149 && tmp2 != owner
00150 && can_detect_enemy(pet, tmp2, rv)) {
00151 if (!can_see_enemy(pet, tmp2)) {
00152 if (tmp3 != NULL)
00153 tmp3 = tmp2;
00154 } else {
00155 pet->enemy = tmp2;
00156 if (check_enemy(pet, rv) != NULL)
00157 return tmp2;
00158 else
00159 pet->enemy = NULL;
00160 }
00161 }
00162 }
00163 }
00164 }
00165
00166
00167
00168 if (tmp3 != NULL) {
00169 pet->enemy = tmp3;
00170 if (check_enemy(pet, rv) != NULL)
00171 return tmp3;
00172 else
00173 pet->enemy = NULL;
00174 }
00175
00176
00177 if (attacker) {
00178
00179 if (attacker->count == pet->attacked_by_count) {
00180
00181
00182 if (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && on_same_map(pet, attacker)) {
00183 pet->enemy = attacker;
00184 if (check_enemy(pet, rv) != NULL)
00185 return attacker;
00186 else
00187 pet->enemy = NULL;
00188 }
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197 if (owner->type == PLAYER && owner->contr->petmode != pet_defend) {
00198 tmp3 = NULL;
00199 for (i = 0; i < SIZEOFFREE; i++) {
00200 x = pet->x+freearr_x[search_arr[i]];
00201 y = pet->y+freearr_y[search_arr[i]];
00202 nm = pet->map;
00203
00204 mflags = get_map_flags(nm, &nm, x, y, &x, &y);
00205 if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
00206 for (tmp = GET_MAP_OB(nm, x, y); tmp != NULL; tmp = tmp->above) {
00207 object *tmp2 = tmp->head == NULL ? tmp : tmp->head;
00208 if (QUERY_FLAG(tmp2, FLAG_ALIVE)
00209 && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || should_arena_attack(pet, owner, tmp2))
00210 && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
00211 && tmp2 != pet
00212 && tmp2 != owner
00213 && can_detect_enemy(pet, tmp2, rv)) {
00214 if (!can_see_enemy(pet, tmp2)) {
00215 if (tmp3 != NULL)
00216 tmp3 = tmp2;
00217 } else {
00218 pet->enemy = tmp2;
00219 if (check_enemy(pet, rv) != NULL)
00220 return tmp2;
00221 else
00222 pet->enemy = NULL;
00223 }
00224 }
00225 }
00226 }
00227 }
00228 }
00229
00230
00231
00232 if (tmp3 != NULL) {
00233 pet->enemy = tmp3;
00234 if (check_enemy(pet, rv) != NULL)
00235 return tmp3;
00236 else
00237 pet->enemy = NULL;
00238 }
00239
00240
00241 return check_enemy(pet, rv);
00242 }
00243
00250 void terminate_all_pets(object *owner) {
00251 objectlink *obl, *next;
00252
00253 for (obl = first_friendly_object; obl != NULL; obl = next) {
00254 object *ob = obl->ob;
00255 next = obl->next;
00256 if (get_owner(ob) == owner) {
00257 if (!QUERY_FLAG(ob, FLAG_REMOVED))
00258 remove_ob(ob);
00259 remove_friendly_object(ob);
00260 free_object(ob);
00261 }
00262 }
00263 }
00264
00273 void remove_all_pets(void) {
00274 objectlink *obl, *next;
00275 object *owner;
00276
00277 for (obl = first_friendly_object; obl != NULL; obl = next) {
00278 next = obl->next;
00279 if (obl->ob->type != PLAYER
00280 && QUERY_FLAG(obl->ob, FLAG_FRIENDLY)
00281 && (owner = get_owner(obl->ob)) != NULL
00282 && !on_same_map(owner, obl->ob)) {
00283
00284
00285
00286 follow_owner(obl->ob, owner);
00287 if (obl->ob && QUERY_FLAG(obl->ob, FLAG_REMOVED) && FABS(obl->ob->speed) > MIN_ACTIVE_SPEED) {
00288 object *ob = obl->ob;
00289
00290 LOG(llevMonster, "(pet failed to follow)\n");
00291 remove_friendly_object(ob);
00292 free_object(ob);
00293 }
00294 }
00295 }
00296 }
00297
00306 void follow_owner(object *ob, object *owner) {
00307 object *tmp;
00308 int dir;
00309
00310 if (!QUERY_FLAG(ob, FLAG_REMOVED))
00311 remove_ob(ob);
00312
00313 if (owner->map == NULL) {
00314 LOG(llevError, "Can't follow owner: no map.\n");
00315 return;
00316 }
00317 if (owner->map->in_memory != MAP_IN_MEMORY) {
00318 LOG(llevError, "Owner of the pet not on a map in memory!?\n");
00319 return;
00320 }
00321 dir = find_free_spot(ob, owner->map, owner->x, owner->y, 1, SIZEOFFREE);
00322
00323 if (dir == -1) {
00324 LOG(llevMonster, "No space for pet to follow, freeing %s.\n", ob->name);
00325 return;
00326 }
00327 for (tmp = ob; tmp != NULL; tmp = tmp->more) {
00328 tmp->x = owner->x+freearr_x[dir]+(tmp->arch == NULL ? 0 : tmp->arch->clone.x);
00329 tmp->y = owner->y+freearr_y[dir]+(tmp->arch == NULL ? 0 : tmp->arch->clone.y);
00330 tmp->map = owner->map;
00331 if (OUT_OF_REAL_MAP(tmp->map, tmp->x, tmp->y)) {
00332 tmp->map = get_map_from_coord(tmp->map, &tmp->x, &tmp->y);
00333 }
00334 }
00335 insert_ob_in_map(ob, ob->map, NULL, 0);
00336 if (owner->type == PLAYER)
00337 draw_ext_info(NDI_UNIQUE, 0, owner, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PET,
00338 "Your pet magically appears next to you", NULL);
00339 return;
00340 }
00341
00348 void pet_move(object *ob) {
00349 int dir, i;
00350 tag_t tag;
00351 sint16 dx, dy;
00352 object *ob2, *owner;
00353 mapstruct *m;
00354
00355
00356 if ((owner = get_owner(ob)) == NULL) {
00357 remove_ob(ob);
00358 remove_friendly_object(ob);
00359 free_object(ob);
00360 LOG(llevMonster, "Pet: no owner, leaving.\n");
00361 return;
00362 }
00363
00364
00365 if (!on_same_map(ob, owner)) {
00366 follow_owner(ob, owner);
00367 return;
00368 }
00369
00370 if (owner->type == PLAYER && owner->contr->petmode == pet_sad) {
00371
00372 for (i = 0; i < 15; i++) {
00373 dir = rndm(1, 8);
00374 dx = ob->x+freearr_x[dir];
00375 dy = ob->y+freearr_y[dir];
00376 m = ob->map;
00377 if (get_map_flags(ob->map, &m, dx, dy, &dx, &dy)&P_OUT_OF_MAP)
00378 continue;
00379 else if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m, dx, dy)))
00380 continue;
00381 else
00382 break;
00383 }
00384 } else {
00385 dir = find_dir_2(ob->x-ob->owner->x, ob->y-ob->owner->y);
00386 }
00387 ob->direction = dir;
00388
00389 tag = ob->count;
00390
00391
00392
00393 if (!(move_ob(ob, dir, ob))) {
00394 object *part;
00395
00396
00397 if (was_destroyed(ob, tag))
00398 return;
00399
00400 for (part = ob; part != NULL; part = part->more) {
00401 dx = part->x+freearr_x[dir];
00402 dy = part->y+freearr_y[dir];
00403 m = get_map_from_coord(part->map, &dx, &dy);
00404 if (!m)
00405 continue;
00406
00407 for (ob2 = GET_MAP_OB(m, dx, dy); ob2 != NULL; ob2 = ob2->above) {
00408 object *new_ob;
00409
00410 new_ob = ob2->head ? ob2->head : ob2;
00411 if (new_ob == ob)
00412 break;
00413 if (new_ob == ob->owner)
00414 return;
00415 if (get_owner(new_ob) == ob->owner)
00416 break;
00417
00418
00419
00420
00421 if (QUERY_FLAG(new_ob, FLAG_ALIVE)
00422 && !QUERY_FLAG(ob, FLAG_UNAGGRESSIVE)
00423 && !QUERY_FLAG(new_ob, FLAG_UNAGGRESSIVE)
00424 && !QUERY_FLAG(new_ob, FLAG_FRIENDLY)) {
00425 ob->enemy = new_ob;
00426 if (new_ob->enemy == NULL)
00427 new_ob->enemy = ob;
00428 return;
00429 } else if (new_ob->type == PLAYER) {
00430 draw_ext_info(NDI_UNIQUE, 0, new_ob,
00431 MSG_TYPE_MISC, MSG_SUBTYPE_NONE,
00432 "You stand in the way of someones pet.", NULL);
00433 return;
00434 }
00435 }
00436 }
00437
00438 dir = absdir(dir+4-(RANDOM()%5)-(RANDOM()%5));
00439 (void)move_ob(ob, dir, ob);
00440 }
00441 return;
00442 }
00443
00444
00445
00446
00447
00448
00449
00464 static object *fix_summon_pet(archetype *at, object *op, int dir, int is_golem) {
00465 archetype *atmp;
00466 object *tmp = NULL, *prev = NULL, *head = NULL;
00467
00468 for (atmp = at; atmp != NULL; atmp = atmp->more) {
00469 tmp = arch_to_object(atmp);
00470 if (atmp == at) {
00471 if (!is_golem)
00472 SET_FLAG(tmp, FLAG_MONSTER);
00473 set_owner(tmp, op);
00474 if (op->type == PLAYER) {
00475 tmp->stats.exp = 0;
00476 add_friendly_object(tmp);
00477 SET_FLAG(tmp, FLAG_FRIENDLY);
00478 if (is_golem)
00479 CLEAR_FLAG(tmp, FLAG_MONSTER);
00480 } else if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
00481 object *owner = get_owner(op);
00482
00483 if (owner != NULL) {
00484 set_owner(tmp, owner);
00485 tmp->attack_movement = PETMOVE;
00486 add_friendly_object(tmp);
00487 SET_FLAG(tmp, FLAG_FRIENDLY);
00488 }
00489 }
00490 if (op->type != PLAYER || !is_golem) {
00491 tmp->attack_movement = PETMOVE;
00492 tmp->speed_left = -1;
00493 tmp->type = 0;
00494 tmp->enemy = op->enemy;
00495 } else
00496 tmp->type = GOLEM;
00497 }
00498 if (head == NULL)
00499 head = tmp;
00500 tmp->x = op->x+freearr_x[dir]+tmp->arch->clone.x;
00501 tmp->y = op->y+freearr_y[dir]+tmp->arch->clone.y;
00502 tmp->map = op->map;
00503 if (tmp->invisible)
00504 tmp->invisible = 0;
00505 if (head != tmp)
00506 tmp->head = head,
00507 prev->more = tmp;
00508 prev = tmp;
00509 }
00510 head->direction = dir;
00511
00512 if (head->randomitems) {
00513 create_treasure(head->randomitems, head, GT_APPLY|GT_STARTEQUIP, 6, 0);
00514 }
00515 mark_inventory_as_no_drop(head);
00516
00517
00518 head->last_heal = 0;
00519 head->last_eat = 0;
00520 head->last_grace = 0;
00521 head->last_sp = 0;
00522 head->other_arch = NULL;
00523 head->stats.exp = 0;
00524 CLEAR_FLAG(head, FLAG_CHANGING);
00525 CLEAR_FLAG(head, FLAG_STAND_STILL);
00526 CLEAR_FLAG(head, FLAG_GENERATOR);
00527 CLEAR_FLAG(head, FLAG_SPLITTING);
00528 if (head->attacktype&AT_GHOSTHIT)
00529 head->attacktype = (AT_PHYSICAL|AT_DRAIN);
00530
00531 return head;
00532 }
00533
00541 void move_golem(object *op) {
00542 int made_attack = 0;
00543 object *tmp;
00544 tag_t tag;
00545
00546 if (QUERY_FLAG(op, FLAG_MONSTER))
00547 return;
00548
00549 if (get_owner(op) == NULL) {
00550 LOG(llevDebug, "Golem without owner destructed.\n");
00551 remove_ob(op);
00552 free_object(op);
00553 return;
00554 }
00555
00556
00557
00558
00559
00560 if (--op->stats.hp < 0) {
00561 if (op->msg)
00562 draw_ext_info(NDI_UNIQUE, 0, op->owner, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PET,
00563 op->msg, op->msg);
00564 op->owner->contr->ranges[range_golem] = NULL;
00565 op->owner->contr->golem_count = 0;
00566 remove_friendly_object(op);
00567 remove_ob(op);
00568 free_object(op);
00569 return;
00570 }
00571
00572
00573
00574
00575
00576
00577 tag = op->count;
00578 if (move_ob(op, op->direction, op))
00579 return;
00580 if (was_destroyed(op, tag))
00581 return;
00582
00583 for (tmp = op; tmp; tmp = tmp->more) {
00584 sint16 x = tmp->x+freearr_x[op->direction], y = tmp->y+freearr_y[op->direction];
00585 object *victim;
00586 mapstruct *m;
00587 int mflags;
00588
00589 m = op->map;
00590 mflags = get_map_flags(m, &m, x, y, &x, &y);
00591
00592 if (mflags&P_OUT_OF_MAP)
00593 continue;
00594
00595 for (victim = GET_MAP_OB(op->map, x, y); victim; victim = victim->above)
00596 if (QUERY_FLAG(victim, FLAG_ALIVE))
00597 break;
00598
00599
00600
00601
00602
00603
00604
00605
00606 if (victim && victim != op && victim->head != op) {
00607
00608
00609
00610
00611 if (victim->race && op->race && strstr(op->race, victim->race)) {
00612 if (op->owner)
00613 draw_ext_info_format(NDI_UNIQUE, 0, op->owner,
00614 MSG_TYPE_SPELL, MSG_TYPE_SPELL_PET,
00615 "%s avoids damaging %s.",
00616 "%s avoids damaging %s.",
00617 op->name, victim->name);
00618 } else if (victim == op->owner) {
00619 if (op->owner)
00620 draw_ext_info_format(NDI_UNIQUE, 0, op->owner,
00621 MSG_TYPE_SPELL, MSG_TYPE_SPELL_PET,
00622 "%s avoids damaging you.",
00623 "%s avoids damaging you.",
00624 op->name);
00625 } else {
00626 attack_ob(victim, op);
00627 made_attack = 1;
00628 }
00629 }
00630 }
00631 if (made_attack)
00632 update_object(op, UP_OBJ_FACE);
00633 }
00634
00648 void control_golem(object *op, int dir) {
00649 op->direction = dir;
00650 }
00651
00669 int summon_golem(object *op, object *caster, int dir, object *spob) {
00670 object *tmp;
00671 const object *god = NULL;
00672 archetype *at;
00673 char buf[MAX_BUF];
00674
00675
00676
00677
00678 if (op->type == PLAYER
00679 && op->contr->ranges[range_golem] != NULL
00680 && op->contr->golem_count == op->contr->ranges[range_golem]->count) {
00681 draw_ext_info(NDI_UNIQUE, 0, op,
00682 MSG_TYPE_SPELL, MSG_TYPE_SPELL_PET,
00683 "You dismiss your existing golem.", NULL);
00684 remove_ob(op->contr->ranges[range_golem]);
00685 free_object(op->contr->ranges[range_golem]);
00686 op->contr->ranges[range_golem] = NULL;
00687 op->contr->golem_count = -1;
00688 }
00689
00690 if (spob->other_arch)
00691 at = spob->other_arch;
00692 else if (spob->race) {
00693 god = find_god(determine_god(caster));
00694 if (!god) {
00695 draw_ext_info_format(NDI_UNIQUE, 0, op,
00696 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00697 "You must worship a god to cast %s.",
00698 "You must worship a god to cast %s.",
00699 spob->name);
00700 return 0;
00701 }
00702
00703 at = determine_holy_arch(god, spob->race);
00704 if (!at) {
00705 draw_ext_info_format(NDI_UNIQUE, 0, op,
00706 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00707 "%s has no %s for you to call.",
00708 "%s has no %s for you to call.",
00709 god->name, spob->race);
00710 return 0;
00711 }
00712 } else {
00713 LOG(llevError, "Spell %s lacks other_arch\n", spob->name);
00714 return 0;
00715 }
00716
00717 if (!dir)
00718 dir = find_free_spot(NULL, op->map, op->x, op->y, 1, SIZEOFFREE1+1);
00719
00720 if ((dir == -1)
00721 || ob_blocked(&at->clone, op->map, op->x+freearr_x[dir], op->y+freearr_y[dir])) {
00722 draw_ext_info(NDI_UNIQUE, 0, op,
00723 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00724 "There is something in the way.", NULL);
00725 return 0;
00726 }
00727
00728
00729 if (!(tmp = fix_summon_pet(at, op, dir, GOLEM))) {
00730 draw_ext_info(NDI_UNIQUE, 0, op,
00731 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00732 "Your spell fails.", NULL);
00733 return 0;
00734 }
00735
00736 if (op->type == PLAYER) {
00737 tmp->type = GOLEM;
00738 set_owner(tmp, op);
00739 set_spell_skill(op, caster, spob, tmp);
00740 op->contr->ranges[range_golem] = tmp;
00741 op->contr->golem_count = tmp->count;
00742
00743 op->contr->shoottype = range_golem;
00744 } else {
00745 if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
00746 object *owner = get_owner(op);
00747
00748 if (owner != NULL) {
00749 set_owner(tmp, owner);
00750 tmp->attack_movement = PETMOVE;
00751 add_friendly_object(tmp);
00752 SET_FLAG(tmp, FLAG_FRIENDLY);
00753 }
00754 }
00755 SET_FLAG(tmp, FLAG_MONSTER);
00756 }
00757
00758
00759 tmp->speed = FABS(tmp->speed);
00760
00761
00762
00763
00764 if (op->type == PLAYER) {
00765 tmp->stats.hp += spob->duration+SP_level_duration_adjust(caster, spob);
00766 if (!spob->stats.dam)
00767 tmp->stats.dam += SP_level_dam_adjust(caster, spob);
00768 else
00769 tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
00770 tmp->speed += .02*SP_level_range_adjust(caster, spob);
00771 tmp->speed = MIN(tmp->speed, 1.0);
00772 if (spob->attacktype)
00773 tmp->attacktype = spob->attacktype;
00774 }
00775 tmp->stats.wc -= SP_level_range_adjust(caster, spob);
00776
00777
00778
00779
00780
00781
00782
00783 tmp->stats.exp *= 1+(MAX(spob->stats.maxgrace, spob->stats.sp)/caster_level(caster, spob));
00784 tmp->speed_left = 0;
00785 tmp->direction = dir;
00786
00787
00788 if (god) {
00789 object *tmp2;
00790
00791 snprintf(buf, sizeof(buf), "%s of %s", spob->name, god->name);
00792 buf[0] = toupper(buf[0]);
00793 for (tmp2 = tmp; tmp2; tmp2 = tmp2->more) {
00794 if (tmp2->name)
00795 free_string(tmp2->name);
00796 tmp2->name = add_string(buf);
00797 }
00798 tmp->attacktype |= god->attacktype;
00799 memcpy(tmp->resist, god->resist, sizeof(tmp->resist));
00800 if (tmp->race)
00801 FREE_AND_CLEAR_STR(tmp->race);
00802 if (god->race)
00803 tmp->race = add_string(god->race);
00804 if (tmp->slaying)
00805 FREE_AND_CLEAR_STR(tmp->slaying);
00806 if (god->slaying)
00807 tmp->slaying = add_string(god->slaying);
00808
00809 if (!(tmp->attacktype&AT_PHYSICAL))
00810 tmp->attacktype |= AT_PHYSICAL;
00811 }
00812
00813 insert_ob_in_map(tmp, tmp->map, op, 0);
00814 return 1;
00815 }
00816
00817
00818
00819
00820
00821
00822
00837 static object *choose_cult_monster(object *pl, const object *god, int summon_level) {
00838 char buf[MAX_BUF];
00839 const char *race;
00840 int racenr, mon_nr, i;
00841 racelink *list;
00842 objectlink *tobl;
00843 object *otmp;
00844
00845
00846 racenr = 0;
00847 strcpy(buf, god->race);
00848 race = strtok(buf, ",");
00849 while (race) {
00850 racenr++;
00851 race = strtok(NULL, ",");
00852 }
00853
00854
00855 if (racenr > 1) {
00856 racenr = rndm(0, racenr-1);
00857 strcpy(buf, god->race);
00858 race = strtok(buf, ",");
00859 for (i = 0; i < racenr; i++)
00860 race = strtok(NULL, ",");
00861 } else
00862 race = god->race;
00863
00864
00865
00866
00867
00868
00869
00870 if ((list = find_racelink(race)) == NULL) {
00871 draw_ext_info_format(NDI_UNIQUE, 0, pl,
00872 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00873 "The spell fails! %s's creatures are beyond the range of your summons",
00874 "The spell fails! %s's creatures are beyond the range of your summons",
00875 god->name);
00876 LOG(llevDebug, "choose_cult_monster() requested non-existent aligned race!\n");
00877 return NULL;
00878 }
00879
00880
00881 mon_nr = 0;
00882 for (tobl = list->member; tobl; tobl = tobl->next) {
00883 otmp = tobl->ob;
00884 if (!otmp || !QUERY_FLAG(otmp, FLAG_MONSTER))
00885 continue;
00886 if (otmp->level <= summon_level)
00887 mon_nr++;
00888 }
00889
00890
00891
00892
00893
00894
00895 if (!mon_nr)
00896 return NULL;
00897
00898 mon_nr = rndm(0, mon_nr-1);
00899 for (tobl = list->member; tobl; tobl = tobl->next) {
00900 otmp = tobl->ob;
00901 if (!otmp || !QUERY_FLAG(otmp, FLAG_MONSTER))
00902 continue;
00903 if (otmp->level <= summon_level && !mon_nr--)
00904 return otmp;
00905 }
00906
00907 LOG(llevDebug, "choose_cult_monster() mon_nr was set, but did not find a monster\n");
00908 return NULL;
00909 }
00910
00929 int summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg) {
00930 sint16 x, y, nrof = 1, i;
00931 archetype *summon_arch;
00932 int ndir, mult;
00933
00934 if (spell_ob->other_arch) {
00935 summon_arch = spell_ob->other_arch;
00936 } else if (spell_ob->randomitems) {
00937 int level = caster_level(caster, spell_ob);
00938 treasure *tr, *lasttr = NULL;
00939
00940
00941
00942
00943
00944 for (tr = spell_ob->randomitems->items; tr; tr = tr->next) {
00945 if (level < tr->magic)
00946 break;
00947 lasttr = tr;
00948 if (stringarg && !strcmp(tr->item->name, stringarg))
00949 break;
00950 if (tr->next == NULL || tr->next->item == NULL)
00951 break;
00952 }
00953 if (!lasttr) {
00954 LOG(llevError, "Treasurelist %s did not generate a valid entry in summon_object\n", spell_ob->randomitems->name);
00955 draw_ext_info(NDI_UNIQUE, 0, op,
00956 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00957 "The spell fails to summon any monsters.", NULL);
00958 return 0;
00959 }
00960 summon_arch = lasttr->item;
00961 nrof = lasttr->nrof;
00962
00963 } else if (spell_ob->race && !strcmp(spell_ob->race, "GODCULTMON")) {
00964 const object *god = find_god(determine_god(op));
00965 object *mon, *owner;
00966 int summon_level, tries;
00967
00968 if (!god && ((owner = get_owner(op)) != NULL)) {
00969 god = find_god(determine_god(owner));
00970 }
00971
00972 if (!god)
00973 return 0;
00974
00975 if (!god->race) {
00976 draw_ext_info_format(NDI_UNIQUE, 0, op,
00977 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00978 "%s has no creatures that you may summon!",
00979 "%s has no creatures that you may summon!",
00980 god->name);
00981 return 0;
00982 }
00983
00984 summon_level = caster_level(caster, spell_ob);
00985 if (summon_level == 0)
00986 summon_level = 1;
00987 tries = 0;
00988 do {
00989 mon = choose_cult_monster(op, god, summon_level);
00990 if (!mon) {
00991 draw_ext_info_format(NDI_UNIQUE, 0, op,
00992 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00993 "%s fails to send anything.",
00994 "%s fails to send anything.",
00995 god->name);
00996 return 0;
00997 }
00998 ndir = dir;
00999 if (!ndir)
01000 ndir = find_free_spot(mon, op->map, op->x, op->y, 1, SIZEOFFREE);
01001 if (ndir == -1
01002 || ob_blocked(mon, op->map, op->x+freearr_x[ndir], op->y+freearr_y[ndir])) {
01003 ndir = -1;
01004 if (++tries == 5) {
01005 draw_ext_info(NDI_UNIQUE, 0, op,
01006 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01007 "There is something in the way.", NULL);
01008 return 0;
01009 }
01010 }
01011 } while (ndir == -1);
01012 if (mon->level > (summon_level/2))
01013 nrof = random_roll(1, 2, op, PREFER_HIGH);
01014 else
01015 nrof = die_roll(2, 2, op, PREFER_HIGH);
01016 summon_arch = mon->arch;
01017 } else {
01018 summon_arch = NULL;
01019 }
01020
01021 if (spell_ob->stats.dam)
01022 nrof += spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
01023
01024 if (!summon_arch) {
01025 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01026 "There is no monsters available for summoning.", NULL);
01027 return 0;
01028 }
01029
01030 if (dir) {
01031
01032 x = freearr_x[dir];
01033 y = freearr_y[dir];
01034 if (ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y)) {
01035 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01036 "There is something in the way.", NULL);
01037 return 0;
01038 }
01039 }
01040
01041 mult = (RANDOM()%2 ? -1 : 1);
01042
01043 for (i = 1; i <= nrof; i++) {
01044 archetype *atmp;
01045 object *prev = NULL, *head = NULL, *tmp;
01046
01047 if (dir) {
01048 ndir = absdir(dir+(i/2)*mult);
01049 mult = -mult;
01050 } else
01051 ndir = find_free_spot(&summon_arch->clone, op->map, op->x, op->y, 1, SIZEOFFREE);
01052
01053 if (ndir > 0) {
01054 x = freearr_x[ndir];
01055 y = freearr_y[ndir];
01056 }
01057
01058 if (ndir == -1 || ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y))
01059 continue;
01060
01061 for (atmp = summon_arch; atmp != NULL; atmp = atmp->more) {
01062 tmp = arch_to_object(atmp);
01063 if (atmp == summon_arch) {
01064 if (QUERY_FLAG(tmp, FLAG_MONSTER)) {
01065 set_owner(tmp, op);
01066 set_spell_skill(op, caster, spell_ob, tmp);
01067 tmp->enemy = op->enemy;
01068 tmp->type = 0;
01069 CLEAR_FLAG(tmp, FLAG_SLEEP);
01070 if (op->type == PLAYER || QUERY_FLAG(op, FLAG_FRIENDLY)) {
01071
01072 if (!QUERY_FLAG(spell_ob, FLAG_MONSTER)) {
01073 SET_FLAG(tmp, FLAG_FRIENDLY);
01074 add_friendly_object(tmp);
01075 tmp->stats.exp = 0;
01076 if (spell_ob->attack_movement)
01077 tmp->attack_movement = spell_ob->attack_movement;
01078 if (get_owner(op))
01079 set_owner(tmp, get_owner(op));
01080 }
01081 }
01082 }
01083 if (tmp->speed > MIN_ACTIVE_SPEED)
01084 tmp->speed_left = -1;
01085 }
01086 if (head == NULL)
01087 head = tmp;
01088 else {
01089 tmp->head = head;
01090 prev->more = tmp;
01091 }
01092 prev = tmp;
01093 tmp->x = op->x+x+tmp->arch->clone.x;
01094 tmp->y = op->y+y+tmp->arch->clone.y;
01095 tmp->map = get_map_from_coord(op->map, &tmp->x, &tmp->y);
01096 }
01097 head->direction = freedir[ndir];
01098 head->stats.exp = 0;
01099 head = insert_ob_in_map(head, head->map, op, 0);
01100 if (head && head->randomitems) {
01101 create_treasure(head->randomitems, head, GT_APPLY|GT_STARTEQUIP, 6, 0);
01102 }
01103 if (head != NULL) {
01104 mark_inventory_as_no_drop(head);
01105 }
01106 }
01107 return 1;
01108 }
01109
01119 static object *get_real_owner(object *ob) {
01120 object *realowner = ob;
01121
01122 if (realowner == NULL)
01123 return NULL;
01124
01125 while (get_owner(realowner) != NULL) {
01126 realowner = get_owner(realowner);
01127 }
01128 return realowner;
01129 }
01130
01146 int should_arena_attack(object *pet, object *owner, object *target) {
01147 object *rowner, *towner;
01148
01149
01150 if ((target == NULL) || (pet == NULL) || (owner == NULL))
01151 return 0;
01152
01153
01154
01155 rowner = get_real_owner(owner);
01156 if (target->type != PLAYER) {
01157 towner = get_real_owner(target);
01158 } else {
01159 towner = NULL;
01160 }
01161
01162
01163 if (rowner == NULL) {
01164 LOG(llevError, "Pet has no owner.\n");
01165 return 0;
01166 }
01167
01168
01169
01170 if (towner == NULL && target->type != PLAYER) {
01171 LOG(llevError, "Target is not a player but has no owner. We should not be here.\n");
01172 return 0;
01173 }
01174
01175
01176 if (rowner->type != PLAYER)
01177 return 0;
01178
01179
01180 if (rowner->contr->petmode != pet_arena)
01181 return 0;
01182
01183
01184 if (!(op_on_battleground(pet, NULL, NULL, NULL)
01185 && op_on_battleground(owner, NULL, NULL, NULL)
01186 && op_on_battleground(target, NULL, NULL, NULL)))
01187 return 0;
01188
01189
01190 if (target->type != PLAYER && rowner == towner)
01191 return 0;
01192
01193
01194
01195 if (target->type != PLAYER) {
01196
01197
01198 if (towner->type == PLAYER && rowner->contr->party != NULL) {
01199 if (rowner->contr->party == towner->contr->party)
01200 return 0;
01201 }
01202 } else {
01203
01204
01205 if (rowner->contr->party != NULL) {
01206 if (rowner->contr->party == target->contr->party)
01207 return 0;
01208 }
01209 }
01210
01211 return 1;
01212 }