Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

dll/dll.c

Go to the documentation of this file.
00001 /* {{{
00002  * CalcRogue, a roguelike game for PCs, calculators and PDAs
00003  * Copyright (C) 2003 Jim Babcock
00004  * 
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  * }}} */
00019 // dll.c
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     // Repel vampires
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             /*@fallthrough@*/
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     // Place shopkeeper
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     // Fill with items
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: // Checkerboard
00556             // ##########
00557             // ## # # # #
00558             // # # # # ##
00559             // ## # # # #
00560             // # # # # ##
00561             // ## # # # #
00562             // ##########
00563             if(w->level < 3) // No checkerboard rooms above 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: // Pillars
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             // Only for odd-width rooms with size >4
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: // Smoke-filled room
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 /*      case 9: // Trap room
00614             // ##########
00615             // #^^^^^^^^#
00616             // #^^^^^^^^#
00617             // #^^^^^^^^#
00618             // #^^^^^^^^#
00619             // #^^^^^^^^#
00620             // ##########
00621             if(w->level < 5) // No trap rooms above level 5
00622                 goto retry;
00623 
00624             for(y=r->top; y<=r->bottom; y++)
00625                 for(x=r->left; x<=r->right; x++)
00626                     place_trap(x, y);
00627             break;*/
00628         case 10: // Room with fountain
00629             x = RANGE(r->right, r->left);
00630             y = RANGE(r->bottom, r->top);
00631             place_fountain(x, y);
00632             break;
00633     }
00634     
00635     // 50% chance: intrinsically light room
00636     if(RANGE(1,0)==0)
00637     {
00638         light_room(*r);
00639     }
00640 }
00641 //}}}
00642 

Generated on Thu May 20 13:12:09 2004 for CalcRogue by doxygen 1.3.6