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

src/ai.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 // ai.c
00022 
00023 #include "crogue.h"
00024 
00025 //{{{
00026 static int count_adjacent_tiles(int x, int y, int type)
00027 {
00028     sint xi, yi;
00029     uint count=0;
00030     
00031     for(xi=x-1; xi<=x+1; xi++)
00032     for(yi=y-1; yi<=y+1; yi++)
00033     {
00034         if(xi<0 || yi<0 || xi>=MAPSIZE_X || yi>=MAPSIZE_Y)
00035             continue;
00036         if(w->t[yi][xi].type == type)
00037             count++;
00038     }
00039     return count;
00040 }
00041 //}}}
00042 
00043 #ifdef STUB_FOR_SIZE
00044 void monstmove(sint monst) {}
00045 void webspinner_build(ushort monst, ushort tile_web, ushort tile_floor) {}
00046 void webspinner_cower(ushort monst, ushort tile_web, ushort tile_wall) {}
00047 void monst_chat(ushort monst) {}
00048 #else
00049 //{{{
00050 void monstmove(sint monst)
00051 {
00052     int flags = w->m[monst].flags;
00053     
00054     if( MDESC(monst)->flags & MONSTFLAG_REGENERATE &&
00055         w->m[monst].hps < MDESC(monst)->hps_max)
00056     {
00057         w->m[monst].hps += 1;
00058         
00059         if(player_can_see(monst))
00060             message( gettext("The %s regenerates!"), monstname(monst));
00061     }
00062     
00063     if( MDESC(monst)->power_max > w->m[monst].power ) {
00064         w->m[monst].power ++;
00065     }
00066     
00067     if(flags & (MONST_PARALYZED|MONST_CONFUSED|MONST_PET|MONST_SCARED))
00068     {
00069         if(flags & MONST_PARALYZED) {
00070             if(RANGE(20,1)==1)
00071                 w->m[monst].flags &= ~MONST_PARALYZED;
00072         } else if(flags & MONST_CONFUSED) {
00073             monstmoverandomly(monst, 1);
00074         }
00075         else if(flags & MONST_PET) {
00076             pet_move(monst);
00077         }
00078         else if(flags & MONST_SCARED) {
00079             if(!monst_detect_player(monst) && RANGE(5,1)==1)
00080                 w->m[monst].flags &= ~MONST_SCARED;
00081             if(w->m[monst].hps*2 > MDESC(monst)->hps_max && RANGE(15,1)==1)
00082             {
00083                 if(player_can_see(monst))
00084                     message(gettext("The %s regains its courage."),
00085                         monstname(monst));
00086                 w->m[monst].flags &= ~MONST_SCARED;
00087             }
00088             if(RANGE(4,1)==1)
00089                 w->m[monst].hps++;
00090             monstmoveawayfromplayer(monst);
00091         }
00092     }
00093     else if(flags & MONST_ACTIVE)
00094     {
00095         if(flags & MONST_CUST_WHEN_ACTIVE) {
00096             call_aifunc( MDESC(monst)->ai_active, monst );
00097         } else if(flags & (MONST_PEACEFUL|MONST_FRIENDLY)) {
00098             if(flags & MONST_WANDER_WHEN_IDLE)
00099                 monstmoverandomly(monst, 0);
00100             else
00101                 ;
00102         } else {
00103             if(monstcanmove(monst, w->plr.x, w->plr.y))
00104                 monstmovetowardsplayer(monst);
00105             else if(monst_is_aligned_with_plr(monst) &&
00106                       monst_attack_type(MTRIGGER_RANGED, monst, 1) )
00107                 ;
00108             else if(monst_battle_pet(monst))
00109                 ;
00110             else if(!monst_detect_player(monst))
00111                 w->m[monst].flags &= ~MONST_ACTIVE;
00112             else if(monst_attack_type(MTRIGGER_SEEN, monst, 1) )
00113                 ;
00114             else
00115                 monstmovetowardsplayer(monst);
00116         }
00117     }
00118     else
00119     {
00120         if(distancesquare(w->m[monst].x, w->m[monst].y, w->plr.x, w->plr.y)
00121            > 400)
00122             return;
00123         else if(flags & MONST_CUST_WHEN_IDLE) {
00124             call_aifunc( MDESC(monst)->ai_idle, monst );
00125         } else {
00126             if(monst_detect_player(monst))
00127                 w->m[monst].flags |= MONST_ACTIVE;
00128             if(flags & MONST_WANDER_WHEN_IDLE) {
00129                 if(flags & (MONST_PEACEFUL|MONST_FRIENDLY))
00130                     monstmoverandomly(monst, 0);
00131                 else
00132                     monstmoverandomly(monst, 1);
00133             }
00134         }
00135     }
00136 }
00137 //}}}
00138 //{{{
00139 //
00140 // 1 Randomly pick a move; if it's a web, move onto it.
00141 // 2 (50% chance) Pick the adjacent floor tile with the most webs bordering
00142 //   it, and spin a web there.
00143 //
00144 void webspinner_build(ushort monst, ushort tile_web, ushort tile_floor)
00145 {
00146     int x, y, temp;
00147     int xi, yi;
00148     int best = -1;
00149     int best_x = w->m[monst].x;
00150     int best_y = w->m[monst].y;
00151     
00152     x = w->m[monst].x + RANGE(2,0) - 1;
00153     y = w->m[monst].y + RANGE(2,0) - 1;
00154     
00155     if(w->t[y][x].type == tile_web && monstcanmove(monst, x, y))
00156     {
00157         monstmoveto(monst, x, y);
00158         return;
00159     }
00160     
00161     if(RANGE(1,0))
00162     {
00163         for(yi = w->m[monst].y-1; yi <= w->m[monst].y+1; yi++)
00164             for(xi = w->m[monst].x-1; xi <= w->m[monst].x+1; xi++)
00165             {
00166                 if(w->t[yi][xi].type != tile_floor)
00167                     continue;
00168                 if(!monstcanmove(monst, xi, yi))
00169                     continue;
00170                 temp = count_adjacent_tiles(xi, yi, tile_web);
00171                 if(temp > best)
00172                 {
00173                     best = temp;
00174                     best_x = xi;
00175                     best_y = yi;
00176                 }
00177             }
00178         monstmoveto(monst, best_x, best_y);
00179         w->t[best_y][best_x].type = tile_web;
00180     }
00181 }
00182 //}}}
00183 //{{{
00184 //
00185 // (a) minimize the number of adjacent non-wall, non-web tiles
00186 // (b) move as close to the player as possible
00187 //
00188 void webspinner_cower(ushort monst, ushort tile_web, ushort tile_wall)
00189 {
00190     int best_distance = 1000, best_webbing = 0, temp1, temp2;
00191     int xi, yi;
00192     int target;
00193     int best_x = w->m[monst].x;
00194     int best_y = w->m[monst].y;
00195     
00196             // Be more aggressive when the player is stuck in webs
00197     if(w->plr.extrinsic[STAT_FLAGS] & STAT_FLAG_ENTANGLED) {
00198         monstmovetowardsplayer(monst);
00199         return;
00200     }
00201     
00202     for(yi = w->m[monst].y-1; yi <= w->m[monst].y+1; yi++)
00203     for(xi = w->m[monst].x-1; xi <= w->m[monst].x+1; xi++)
00204     {
00205         if(w->t[yi][xi].type != tile_web)
00206             continue;
00207         target = monstbytile(xi, yi);
00208         if(target>=0 && target != monst)
00209             continue;
00210         temp1 = distancesquare(xi, yi, w->plr.x, w->plr.y);
00211         // HACKHACK: Doesn't handle non-diggable walls, doors, etc.
00212         temp2 = count_adjacent_tiles(xi, yi, tile_web)
00213               + count_adjacent_tiles(xi, yi, tile_wall);
00214         if( temp2>best_webbing ||
00215             (temp1<best_distance && temp2==best_webbing)
00216           )
00217         {
00218             best_distance = temp1;
00219             best_webbing = temp2;
00220             best_x = xi;
00221             best_y = yi;
00222         }
00223     }
00224     monstmoveto(monst, best_x, best_y);
00225 }
00226 //}}}
00227 //{{{
00228 void monst_chat(ushort monst)
00229 {
00230     if(monstcanmove(monst, w->plr.x, w->plr.y))
00231         call_chatfunc(MDESC(monst)->chatfunc, monst);
00232 }
00233 //}}}
00234 #endif
00235 

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