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
00035 #include <global.h>
00036 #ifndef __CEXTRACT__
00037 #include <sproto.h>
00038 #endif
00039 #include <spells.h>
00040
00041
00042 #ifndef sqr
00043 #define sqr(x) ((x)*(x))
00044 #endif
00045
00046
00066 int write_rune(object *op, object *caster, object *spell, int dir, const char *runename) {
00067 object *tmp, *rune_spell, *rune;
00068 char buf[MAX_BUF];
00069 mapstruct *m;
00070 sint16 nx, ny;
00071
00072 if (!dir) {
00073 dir = 1;
00074 }
00075
00076 nx = op->x+freearr_x[dir];
00077 ny = op->y+freearr_y[dir];
00078 m = op->map;
00079
00080 if (get_map_flags(m, &m, nx, ny, &nx, &ny)) {
00081 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00082 "Can't make a rune there!", NULL);
00083 return 0;
00084 }
00085 for (tmp = GET_MAP_OB(m, nx, ny); tmp != NULL; tmp = tmp->above)
00086 if (tmp->type == RUNE)
00087 break;
00088
00089 if (tmp) {
00090 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00091 "You can't write a rune there.", NULL);
00092 return 0;
00093 }
00094
00095 if (spell->other_arch) {
00096 rune_spell = arch_to_object(spell->other_arch);
00097 } else {
00098
00099
00100
00101
00102 int bestmatch = 0, ms;
00103
00104 if (!runename || *runename == 0) {
00105 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00106 "Write a rune of what?", NULL);
00107 return 0;
00108 }
00109
00110 rune_spell = NULL;
00111 for (tmp = op->inv; tmp; tmp = tmp->below) {
00112 if (tmp->type == SPELL) {
00113 ms = item_matched_string(op, tmp, runename);
00114 if (ms > bestmatch) {
00115 bestmatch = ms;
00116 rune_spell = tmp;
00117 }
00118 }
00119 }
00120 if (!rune_spell) {
00121 draw_ext_info_format(NDI_UNIQUE, 0, op,
00122 MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00123 "You don't know any spell named %s",
00124 "You don't know any spell named %s",
00125 runename);
00126 return 0;
00127 }
00128 if (rune_spell->skill != spell->skill) {
00129 draw_ext_info_format(NDI_UNIQUE, 0, op,
00130 MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00131 "You can't cast %s with %s",
00132 "You can't cast %s with %s",
00133 rune_spell->name, spell->name);
00134 return 0;
00135 }
00136 if (caster->path_denied&spell->path_attuned) {
00137 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00138 "%s belongs to a spell path denied to you.",
00139 "%s belongs to a spell path denied to you.",
00140 rune_spell->name);
00141 return 0;
00142 }
00143 if (caster_level(caster, rune_spell) < rune_spell->level) {
00144 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00145 "%s is beyond your ability to cast!",
00146 "%s is beyond your ability to cast!",
00147 rune_spell->name);
00148 return 0;
00149 }
00150 if (SP_level_spellpoint_cost(caster, rune_spell, SPELL_MANA) > op->stats.sp) {
00151 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00152 "You don't have enough mana.", NULL);
00153 return 0;
00154 }
00155 if (SP_level_spellpoint_cost(caster, rune_spell, SPELL_GRACE) > op->stats.grace) {
00156 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00157 "You don't have enough grace.", NULL);
00158 return 0;
00159 }
00160 op->stats.grace -= SP_level_spellpoint_cost(caster, rune_spell, SPELL_GRACE);
00161 op->stats.sp -= SP_level_spellpoint_cost(caster, rune_spell, SPELL_MANA);
00162 }
00163
00164 if (rune_spell->type == RUNE) {
00165 rune = rune_spell;
00166 } else {
00167 rune = create_archetype(GENERIC_RUNE);
00168 snprintf(buf, sizeof(buf), "You set off a rune of %s\n", rune_spell->name);
00169 rune->msg = add_string(buf);
00170 tmp = get_object();
00171 copy_object(rune_spell, tmp);
00172 insert_ob_in_ob(tmp, rune);
00173 if (spell->face != blank_face)
00174 rune->face = spell->face;
00175 }
00176 rune->level = caster_level(caster, spell);
00177 rune->stats.Cha = rune->level/2;
00178 rune->x = nx;
00179 rune->y = ny;
00180 rune->map = m;
00181 rune->direction = dir;
00182 set_owner(rune, op);
00183 set_spell_skill(op, caster, spell, rune);
00184 insert_ob_in_map(rune, m, op, 0);
00185 return 1;
00186 }
00187
00197 static void rune_attack(object *op, object *victim) {
00198 if (victim) {
00199 tag_t tag = victim->count;
00200 hit_player(victim, op->stats.dam, op, op->attacktype, 1);
00201 if (was_destroyed(victim, tag))
00202 return;
00203
00204 if (HAS_RANDOM_ITEMS(op))
00205 create_treasure(op->randomitems, op, 0, (victim->map ? victim->map->difficulty : 1), 0);
00206 if (op->inv && op->inv->type == DISEASE) {
00207 object *disease = op->inv;
00208
00209 infect_object(victim, disease, 1);
00210 remove_ob(disease);
00211 free_object(disease);
00212 }
00213 } else
00214 hit_map(op, 0, op->attacktype, 1);
00215 }
00216
00227 void spring_trap(object *trap, object *victim) {
00228 object *env;
00229 tag_t trap_tag = trap->count;
00230 rv_vector rv;
00231 int i, has_spell;
00232
00233
00234 if (trap->stats.hp <= 0)
00235 return;
00236
00237 if (QUERY_FLAG(trap, FLAG_IS_LINKED))
00238 use_trigger(trap);
00239
00240
00241 has_spell = ((trap->inv && trap->inv->type == SPELL) || (trap->other_arch && trap->other_arch->clone.type == SPELL));
00242
00243 env = object_get_env_recursive(trap);
00244
00245
00246
00247
00248 get_rangevector(env, victim, &rv, 0);
00249 if (rv.distance > 1 && !has_spell)
00250 return;
00251
00252
00253
00254
00255
00256 if (!QUERY_FLAG(victim, FLAG_ALIVE) && !has_spell)
00257 return;
00258
00259 trap->stats.hp--;
00260
00261 if (victim && victim->type == PLAYER && trap->msg != NULL)
00262 draw_ext_info(NDI_UNIQUE, 0, victim, MSG_TYPE_APPLY, MSG_TYPE_APPLY_TRAP,
00263 trap->msg, trap->msg);
00264
00265
00266
00267
00268 trap_show(trap, env);
00269
00270
00271 if (has_spell) {
00272 object *spell;
00273
00274
00275 remove_ob(trap);
00276 trap->x = victim->x;
00277 trap->y = victim->y;
00278 insert_ob_in_map(trap, victim->map, trap, 0);
00279
00280 if (was_destroyed(trap, trap_tag))
00281 return;
00282
00283 for (i = 0; i < MAX(1, trap->stats.maxhp); i++) {
00284 if (trap->inv)
00285 cast_spell(trap, trap, trap->direction, trap->inv, NULL);
00286 else {
00287 spell = arch_to_object(trap->other_arch);
00288 cast_spell(trap, trap, trap->direction, spell, NULL);
00289 free_object(spell);
00290 }
00291 }
00292 } else {
00293 rune_attack(trap, victim);
00294 if (was_destroyed(trap, trap_tag))
00295 return;
00296 }
00297
00298 if (trap->stats.hp <= 0) {
00299 trap->type = SIGN;
00300 trap->stats.food = 20;
00301 SET_FLAG(trap, FLAG_IS_USED_UP);
00302 }
00303 }
00304
00323 int dispel_rune(object *op, object *caster, object *spell, object *skill, int dir) {
00324 object *tmp, *tmp2;
00325 int searchflag = 1, mflags;
00326 sint16 x, y;
00327 mapstruct *m;
00328
00329 x = op->x+freearr_x[dir];
00330 y = op->y+freearr_y[dir];
00331 m = op->map;
00332
00333 mflags = get_map_flags(m, &m, x, y, &x, &y);
00334
00335
00336
00337
00338 if (mflags&P_OUT_OF_MAP) {
00339 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00340 "There's nothing there!", NULL);
00341 return 0;
00342 }
00343
00344
00345
00346
00347
00348
00349 if (!skill)
00350 return 0;
00351
00352 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
00353 if (tmp->type == RUNE || tmp->type == TRAP)
00354 break;
00355
00356
00357
00358
00359
00360 if (tmp->type == SIGN && !strcmp(tmp->arch->name, "rune_mark")) {
00361 remove_ob(tmp);
00362 free_object(tmp);
00363 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00364 "You wipe out the rune of marking!", NULL);
00365 return 1;
00366 }
00367
00368
00369
00370
00371 for (tmp2 = tmp->inv; tmp2 != NULL; tmp2 = tmp2->below) {
00372 if (tmp2->type == RUNE || tmp2->type == TRAP) {
00373 tmp = tmp2;
00374 searchflag = 0;
00375 break;
00376 }
00377 }
00378 if (!searchflag)
00379 break;
00380 }
00381
00382
00383 if (tmp == NULL) {
00384 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00385 "There's nothing there!", NULL);
00386 return 0;
00387 }
00388 trap_disarm(op, tmp, 0, skill);
00389 return 1;
00390 }
00391
00403 int trap_see(object *op, object *trap) {
00404 int chance;
00405
00406 chance = random_roll(0, 99, op, PREFER_HIGH);
00407
00408
00409 if ((trap->stats.Cha == 1)
00410 || (chance > MIN(95, MAX(5, ((int)((float)(op->map->difficulty+trap->level+trap->stats.Cha-op->level)/10.0*50.0)))))) {
00411 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00412 "You spot a %s!",
00413 "You spot a %s!",
00414 trap->name);
00415 return 1;
00416 }
00417 return 0;
00418 }
00419
00431 int trap_show(object *trap, object *where) {
00432 object *tmp2;
00433
00434 if (where == NULL)
00435 return 0;
00436 tmp2 = create_archetype("runedet");
00437 tmp2->face = &new_faces[GET_ANIMATION(trap, 0)];
00438 tmp2->x = where->x;
00439 tmp2->y = where->y;
00440 tmp2->map = where->map;
00441 insert_ob_in_map(tmp2, where->map, NULL, 0);
00442 return 1;
00443 }
00444
00459 int trap_disarm(object *disarmer, object *trap, int risk, object *skill) {
00460 int trapworth;
00461
00462
00463
00464 trapworth = MAX(1, trap->level)*disarmer->map->difficulty*
00465 sqr(MAX(trap->stats.dam, trap->inv ? trap->inv->level : 1))/skill->level;
00466
00467 if (!(random_roll(0, (MAX(2, MIN(20, trap->level-skill->level+5-disarmer->stats.Dex/2))-1), disarmer, PREFER_LOW))) {
00468 draw_ext_info_format(NDI_UNIQUE, 0, disarmer,
00469 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00470 "You successfully disarm the %s!",
00471 "You successfully disarm the %s!",
00472 trap->name);
00473 destroy_object(trap);
00474
00475
00476
00477 if (trap->owner && trap->owner->type != PLAYER && risk)
00478 return trapworth;
00479 else
00480 return 1;
00481 } else {
00482 draw_ext_info_format(NDI_UNIQUE, 0, disarmer,
00483 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE,
00484 "You fail to disarm the %s.",
00485 "You fail to disarm the %s.",
00486 trap->name);
00487 if (!(random_roll(0, (MAX(2, skill->level-trap->level+disarmer->stats.Dex/2-6))-1, disarmer, PREFER_LOW))
00488 && risk) {
00489 draw_ext_info(NDI_UNIQUE, 0, disarmer,
00490 MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00491 "In fact, you set it off!", NULL);
00492 spring_trap(trap, disarmer);
00493 }
00494 return 0;
00495 }
00496 }
00497
00508 void trap_adjust(object *trap, int difficulty) {
00509 int i;
00510
00511
00512
00513
00514
00515
00516 trap->level = rndm(0, difficulty-1)+rndm(0, difficulty-1);
00517 if (trap->level < 1)
00518 trap->level = 1;
00519
00520
00521 trap->stats.Cha = rndm(0, 19)+rndm(0, difficulty-1)+rndm(0, difficulty-1);
00522
00523 if (!trap->other_arch && !trap->inv) {
00524
00525
00526
00527
00528
00529 trap->stats.dam = 0;
00530 for (i = 0; i < difficulty; i++)
00531 trap->stats.dam += rndm(0, 4);
00532
00533
00534 if (trap->attacktype&AT_POISON) {
00535 trap->stats.dam = rndm(0, difficulty-1);
00536 if (trap->stats.dam < 1)
00537 trap->stats.dam = 1;
00538 }
00539
00540
00541 if (trap->attacktype&AT_DEATH)
00542 trap->stats.dam = 127;
00543 }
00544
00545 }