00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025
00026 #include "crogue.h"
00027 #include "dll.h"
00028
00029 #ifndef CPROTO
00030 #include "import.h"
00031 #endif
00032
00033 #ifdef IS_CALCULATOR
00034 DLL_INTERFACE
00035
00036 DLL_ID DLL_IDENTIFICATION_NUMBER
00037 DLL_VERSION CROGUE_VERSION_MAJOR, CROGUE_VERSION_MINOR
00038 DLL_EXPORTS dll_load
00039
00040 DLL_IMPLEMENTATION
00041 #endif
00042
00043 #ifndef CPROTO
00044 const import_functions *dll_body_functions;
00045 #endif
00046
00047
00048 const void** dll_load(const void *f)
00049 {
00050 dll_body_functions = f;
00051 return (const void**)(&dll_exports);
00052 }
00053
00054 void no_op(void) {}
00055
00056 static void cause_confusion(void);
00057
00058
00059 static const stat_timer_desc spell_shield_dv_timer = {
00060 TIMER_STAT,
00061 {STATMOD_ADD, STAT_DV, 8},
00062 gettext("You are no longer protected.")
00063 };
00064
00065
00066 static const stat_timer_desc spell_shield_pv_timer = {
00067 TIMER_STAT,
00068 {STATMOD_ADD, STAT_PV, 4},
00069 NULL
00070 };
00071
00072
00073 static const stat_timer_desc spell_gain_strength_timer = {
00074 TIMER_STAT,
00075 {STATMOD_ADD, STAT_STRENGTH, 8},
00076 gettext("Your strength returns to normal.")
00077 };
00078
00079
00080 static const stat_timer_desc spell_gain_strength_timer_to = {
00081 TIMER_STAT,
00082 {STATMOD_ADD, STAT_TOUGHNESS, 4},
00083 NULL
00084 };
00085
00086
00087 static const stat_timer_desc spell_gain_strength_timer_wi = {
00088 TIMER_STAT,
00089 {STATMOD_ADD, STAT_WILLPOWER, 3},
00090 NULL
00091 };
00092
00093
00094 static const stat_timer_desc spell_heal_timer = {
00095 TIMER_STAT,
00096 {STATMOD_ADD, STAT_REGEN, 2},
00097 gettext("You stop regenerating.")
00098 };
00099
00100
00101 static const func_timer_desc adrenaline_high_timer = {
00102 TIMER_FUNC,
00103 &spell_adrenaline_high_effect,
00104 &spell_adrenaline_low
00105 };
00106
00107
00108 static const func_timer_desc adrenaline_low_timer = {
00109 TIMER_FUNC,
00110 &spell_adrenaline_low_effect,
00111 &spell_adrenaline_expire
00112 };
00113
00114
00115
00116 int tool_holysymbol(void)
00117 {
00118 int num_scared = 0, x, y, m;
00119
00120
00121 for(y=w->plr.y-1; y<=w->plr.y+1; y++)
00122 for(x=w->plr.x-1; x<=w->plr.x+1; x++)
00123 {
00124 m = monstbytile(x, y);
00125 if(m<0) continue;
00126
00127 if(MDESC(m)->flags & MONSTFLAG_VAMPIRIC)
00128 {
00129 scare_monster_force(m);
00130 num_scared++;
00131 }
00132 }
00133
00134 if(!num_scared)
00135 message(gettext("Nothing happens."));
00136
00137 timepass(1);
00138
00139 return 1;
00140 }
00141
00142
00143
00144 void spell_shield(void)
00145 {
00146 message(gettext("You are surrounded by a golden haze."));
00147 add_timer((timer_desc*)&spell_shield_dv_timer, 50);
00148 add_timer((timer_desc*)&spell_shield_pv_timer, 50);
00149 }
00150
00151
00152 void spell_confusion(void)
00153 {
00154 if( !(w->plr.extrinsic[STAT_COMPONENTS] & STAT_COMPONENT_DAGGER) )
00155 message(gettext("You need a dagger to cast that spell."));
00156 else if( w->plr.hps <= 1 && !(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_NUMB) )
00157 message(gettext("You need to rest a bit before you can use your blood for a spell."));
00158 else if( w->plr.extrinsic[STAT_COMPONENTS] & STAT_COMPONENT_GLOVES )
00159 message(gettext("You need to remove your gloves to cast that spell."));
00160 else
00161 {
00162 plr_takedamage(1, gettext("Killed by excessive blood loss"));
00163 cause_confusion();
00164 }
00165 }
00166
00167
00168 void spell_gain_strength(void)
00169 {
00170 add_timer((timer_desc*)&spell_gain_strength_timer, 100);
00171 add_timer((timer_desc*)&spell_gain_strength_timer_to, 100);
00172 add_timer((timer_desc*)&spell_gain_strength_timer_wi, 100);
00173 message(gettext("Power ripples through your body."));
00174 }
00175
00176
00177 void spell_heal(void)
00178 {
00179 add_timer((timer_desc*)&spell_heal_timer, 30);
00180 message(gettext("Your wounds heal quickly."));
00181 }
00182
00183
00184 void spell_adrenaline(void)
00185 {
00186 message(gettext("You feel a surge of adrenaline."));
00187 add_timer((timer_desc*)&adrenaline_high_timer, 20);
00188 }
00189
00190
00191 void spell_adrenaline_low(void)
00192 {
00193 message(gettext("You run out of breath."));
00194 add_timer((timer_desc*)&adrenaline_low_timer, 20);
00195 }
00196
00197
00198 void spell_adrenaline_expire(void)
00199 {
00200 message(gettext("You catch your breath."));
00201 }
00202
00203
00204 void spell_adrenaline_high_effect(void)
00205 {
00206 const stat_mod_desc speed_effect = {STATMOD_ADD, STAT_SPEED, 3};
00207 const stat_mod_desc strength_effect = {STATMOD_ADD, STAT_STRENGTH, 5};
00208 const stat_mod_desc dexterity_effect = {STATMOD_ADD, STAT_DEXTERITY, 3};
00209 const stat_mod_desc dv_effect = {STATMOD_ADD, STAT_DV, 6};
00210 apply_stat_mod_desc(NULL, &speed_effect, 0);
00211 apply_stat_mod_desc(NULL, &strength_effect, 0);
00212 apply_stat_mod_desc(NULL, &dexterity_effect, 0);
00213 apply_stat_mod_desc(NULL, &dv_effect, 0);
00214 }
00215
00216
00217 void spell_adrenaline_low_effect(void)
00218 {
00219 const stat_mod_desc speed_effect = {STATMOD_ADD, STAT_SPEED, -3};
00220 const stat_mod_desc strength_effect = {STATMOD_ADD, STAT_STRENGTH, -3};
00221 const stat_mod_desc dv_effect = {STATMOD_ADD, STAT_DV, -4};
00222 apply_stat_mod_desc(NULL, &speed_effect, 0);
00223 apply_stat_mod_desc(NULL, &strength_effect, 0);
00224 apply_stat_mod_desc(NULL, &dv_effect, 0);
00225
00226 }
00227
00228
00229
00230 static void cause_confusion(void)
00231 {
00232 int i;
00233 message(gettext("You sense chaos and confusion."));
00234
00235 for(i=0; i<MONSTERS_MAX; i++)
00236 {
00237 if(!isNull(w->m[i].type) && !monst_is_peaceful(i))
00238 confuse_monster(i);
00239 }
00240 }
00241
00242
00243
00244 void potion_hit_heal(int monst)
00245 {
00246 message(gettext("The %s looks better."), monstname(monst)),
00247 monst_heal(monst, RANGE(20,10));
00248 }
00249
00250
00251 void potion_hit_extra_heal(int monst)
00252 {
00253 message(gettext("The %s looks much better."), monstname(monst));
00254 monst_heal(monst, RANGE(70,35));
00255 }
00256
00257
00258 void potion_hit_full_heal(int monst)
00259 {
00260 message(gettext("The %s looks completely healed."), monstname(monst));
00261 monst_heal(monst, 1000);
00262 }
00263
00264
00265 void potion_hit_sickness(int monst)
00266 {
00267 message(gettext("The %s looks weaker."), monstname(monst));
00268 monst_takedamage(monst, 25, 10);
00269 }
00270
00271
00272 void potion_hit_confuse(int monst)
00273 {
00274 confuse_monster(monst);
00275 }
00276
00277
00278
00279 void read_tutorial_sign(uint x, uint y)
00280 {
00281 int sign_num = TILESPEC(x,y).ext.sign_id;
00282 char str[512] = "";
00283 const char *strptr = str;
00284
00285 switch(sign_num)
00286 {
00287
00288 case 0:
00289 sprintf(str,
00290 gettext("Welcome to CalcRogue! Look for signs like this one throughout"
00291 " this level. At any point, press '%s' to open a controls reference."),
00292 get_keyname(KEY_ACT_MENU) );
00293 break;
00294
00295
00296 case 1:
00297 sprintf(str,
00298 gettext("The + represents a door. To open it, you can move into it and it will"
00299 " open automatically. When open, it will change to a -. You can also press"
00300 " '%s' to open doors."),
00301 get_keyname(KEY_OPENDOOR) );
00302 break;
00303
00304
00305 case 2:
00306 sprintf(str, gettext("To close the door, press '%s'."),
00307 get_keyname(KEY_CLOSEDOOR) );
00308 break;
00309
00310
00311 case 3:
00312 sprintf(str,
00313 gettext("There is a monster behind this door, so before you proceed, be sure"
00314 " to pick up the sword and equip it. To equip items, press '%s'. To unequip"
00315 " them, press '%s', and to drop them press '%s'."),
00316 get_keyname(KEY_WEAR),
00317 get_keyname(KEY_TAKEOFF),
00318 get_keyname(KEY_DROP) );
00319 break;
00320
00321
00322 case 4:
00323 sprintf(str,
00324 gettext("There is a secret door behind this sign. To search for secret doors,"
00325 " press '%s'. (You may not find it on the first try.)"),
00326 get_keyname(KEY_SEARCH) );
00327 break;
00328
00329
00330 case 5:
00331 sprintf(str,
00332 gettext("You'll have to dig through this wall. To use the wand of digging you"
00333 " found, press '%s'."),
00334 get_keyname(KEY_USE) );
00335 break;
00336
00337
00338 case 6:
00339 sprintf(str,
00340 gettext("When you have equipped a bow and arrows, fire arrows by pressing"
00341 " '%s'. (You can throw/fire items that you haven't readied with '%s'.) Use"
00342 " these arrows on the bats in the next room."),
00343 get_keyname(KEY_FIRE),
00344 get_keyname(KEY_THROW) );
00345 break;
00346
00347
00348 case 7:
00349 sprintf(str,
00350 gettext("To read this spellbook, press '%s' and select it. When you have"
00351 " learned a spell, you can open a menu of the spells you can cast by pressing"
00352 " '%s'.\n"
00353 "\n"
00354 "Casting spells requires energy, which is shown on the status line as PW."
00355 " Some spells also have other requirements, and some spells require that"
00356 " you commit energy for the entire duration of the spell."),
00357 get_keyname(KEY_USE),
00358 get_keyname(KEY_CAST) );
00359 break;
00360
00361
00362 case 8:
00363 strptr =
00364 gettext("Gold adds to your score, and can be spent in shops.");
00365 break;
00366
00367
00368 case 9:
00369 sprintf(str,
00370 gettext("This ring boosts your strength when worn. To view your stats, press"
00371 " '%s'. Your base attribute is shown, and the modified attribute is in"
00372 " parentheses."),
00373 get_keyname(KEY_STATS) );
00374 break;
00375
00376
00377 case 10:
00378 strptr =
00379 gettext("The effectiveness of armor is shown in brackets in the form [DV, PV]."
00380 " DV (Defense) makes you harder to hit, while PV (Protection) reduces the"
00381 " damage hits do. Similarly, weapons use the form (Damage, To-hit) (note"
00382 " the use of parentheses, not brackets.");
00383 break;
00384
00385
00386 case 11:
00387 sprintf(str,
00388 gettext("You can run down long corridors in a single keystroke by pressing"
00389 " '%s'."),
00390 get_keyname(KEY_RUN_SOUTH) );
00391 break;
00392
00393
00394 case 12:
00395 sprintf(str,
00396 gettext("You are now ready to start a normal game. Remember, if you forget any"
00397 " of the controls, press '%s' to bring up a menu."),
00398 get_keyname(KEY_ACT_MENU) );
00399 break;
00400
00401 }
00402
00403 UI_Dialog_Default(strptr);
00404 }
00405
00406
00407 void auto_follow_connection(uint x, uint y)
00408 {
00409 filelink target_map_handle;
00410 mapdesc *target_map;
00411 const char *target_map_name;
00412
00413 switch(w->options[OPTION_AUTOFOLLOW])
00414 {
00415 case OPTION_AUTO_PROMPT:
00416 target_map_handle = TILESPEC(x,y).ext.lvl.destmap;
00417 target_map = (mapdesc*)deref_file_ptr(target_map_handle);
00418 target_map_name = (const char*)deref_file_ptr( target_map->name );
00419 message( gettext("These stairs lead to %s."), target_map_name );
00420 if(!prompt(gettext("Climb them?")))
00421 break;
00422
00423 case OPTION_AUTO_YES:
00424 follow_connection();
00425 break;
00426 }
00427 }
00428
00429
00430 void force_follow_connection(uint x, uint y)
00431 {
00432 w->t[w->plr.y][w->plr.x].flags &= ~TFLAG_OCCUPIED;
00433 w->plr.x = x;
00434 w->plr.y = y;
00435 follow_connection();
00436 }
00437
00438
00439
00440 static void light_room(room r)
00441 {
00442 int x, y;
00443 for(y=r.top-1; y<=r.bottom+1; y++)
00444 for(x=r.left-1; x<=r.right+1; x++)
00445 w->t[y][x].flags |= TFLAG_INTRINSIC_LIGHT;
00446
00447 illuminate( (r.left+r.right)/2, (r.top+r.bottom)/2, 400);
00448 }
00449
00450
00451 static void place_shop(room r, int portal_x, int portal_y)
00452 {
00453 int x, y;
00454 int perturb_x=0, perturb_y=0;
00455 int shop_type;
00456 item itm;
00457
00458 shop_type = lrand() % w->desc.numshoptypes;
00459
00460 for(y=r.top; y<=r.bottom; y++)
00461 for(x=r.left; x<=r.right; x++)
00462 {
00463 w->t[y][x].type = TILE_SHOPFLOOR;
00464 w->t[y][x].special = shop_type;
00465 }
00466 light_room(r);
00467
00468
00469 if(portal_x == r.left-1)
00470 portal_x++, r.left++;
00471 else if(portal_x == r.right+1)
00472 portal_x--, r.right--;
00473 else
00474 perturb_x = 1;
00475
00476 if(portal_y == r.top-1)
00477 portal_y++, r.top++;
00478 else if(portal_y == r.bottom+1)
00479 portal_y--, r.bottom--;
00480 else
00481 perturb_y = 1;
00482
00483 if(perturb_x)
00484 {
00485 if(w->t[portal_y][portal_x+1].type == TILE_SHOPFLOOR)
00486 portal_x++;
00487 else
00488 portal_x--;
00489 }
00490 if(perturb_y)
00491 {
00492 if(w->t[portal_y+1][portal_x].type == TILE_SHOPFLOOR)
00493 portal_y++;
00494 else
00495 portal_y--;
00496 }
00497 addmonster( portal_x, portal_y, w->shopdescs[shop_type].shopkeeper);
00498
00499
00500 for(y=r.top; y<=r.bottom; y++)
00501 for(x=r.left; x<=r.right; x++)
00502 {
00503 itm = randitem(w->shopdescs[shop_type].generate_item);
00504 itm.flags |= ITEMFLAG_UNPAID;
00505 place_item(&itm, x, y);
00506 }
00507 }
00508
00509
00510 static void place_fountain(int x, int y)
00511 {
00512 w->t[y][x].type = TILE_FOUNTAIN;
00513 w->t[y][x].special = ((RANGE(NUM_FOUNTAIN_TYPES-1, 0) << 4) + (RANGE(1,0)?RANGE(6,3):0));
00514 }
00515
00516
00517 void dll_fill_room(room *r)
00518 {
00519 int which_room;
00520 int x, y;
00521 int width, height;
00522 int num_portals = 0, portal_x=-1, portal_y=-1;
00523
00524 width = r->right - r->left + 1;
00525 height = r->bottom - r->top + 1;
00526
00527 retry:
00528 y=r->top-1;
00529 for(x=r->left-1; x<=r->right+1; x++)
00530 if(!TILEDESC(w->t[y][x]).is_wall)
00531 num_portals++, portal_x=x, portal_y=y;
00532 y=r->bottom+1;
00533 for(x=r->left-1; x<=r->right+1; x++)
00534 if(!TILEDESC(w->t[y][x]).is_wall)
00535 num_portals++, portal_x=x, portal_y=y;
00536
00537 x=r->left-1;
00538 for(y=r->top-1; y<=r->bottom+1; y++)
00539 if(!TILEDESC(w->t[y][x]).is_wall)
00540 num_portals++, portal_x=x, portal_y=y;
00541 x=r->right+1;
00542 for(y=r->top-1; y<=r->bottom+1; y++)
00543 if(!TILEDESC(w->t[y][x]).is_wall)
00544 num_portals++, portal_x=x, portal_y=y;
00545
00546 if(num_portals==1 && RANGE(9,1)>=MAPDESC_CURRENT.difficulty)
00547 {
00548 place_shop(*r, portal_x, portal_y);
00549 return;
00550 }
00551
00552 which_room = RANGE(28,0);
00553 switch(which_room)
00554 {
00555 case 0:
00556
00557
00558
00559
00560
00561
00562
00563 if(w->level < 3)
00564 goto retry;
00565
00566 for(y=r->top; y<=r->bottom; y++)
00567 for(x=r->left+(y%2); x<=r->right; x+=2)
00568 w->t[y][x].type = TILE_WALL;
00569 break;
00570
00571 case 1:
00572 case 2:
00573 case 3:
00574 case 4:
00575 case 5:
00576 case 6:
00577 case 7:
00578
00579
00580
00581
00582
00583
00584
00585
00586 if( !(width%2) || height<=4 )
00587 goto retry;
00588
00589 y=r->top + 1;
00590 for(x=r->left+1; x<r->right; x+=2)
00591 w->t[y][x].type = TILE_WALL;
00592
00593 if(r->bottom-r->top > 3)
00594 {
00595 y = r->bottom - 1;
00596 for(x=r->left+1; x<r->right; x+=2)
00597 w->t[y][x].type = TILE_WALL;
00598 }
00599 break;
00600
00601 case 8:
00602
00603
00604
00605
00606
00607
00608
00609 for(y=r->top; y<=r->bottom; y++)
00610 for(x=r->left; x<=r->right; x++)
00611 w->t[y][x].type = TILE_SMOKE;
00612 break;
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628 case 10:
00629 x = RANGE(r->right, r->left);
00630 y = RANGE(r->bottom, r->top);
00631 place_fountain(x, y);
00632 break;
00633 }
00634
00635
00636 if(RANGE(1,0)==0)
00637 {
00638 light_room(*r);
00639 }
00640 }
00641
00642