diff -Nurd original/include/army_ai.h new/include/army_ai.h --- original/include/army_ai.h 1970-01-01 01:00:00.000000000 +0100 +++ new/include/army_ai.h 2008-09-21 23:55:36.000000000 +0200 @@ -0,0 +1,47 @@ +#ifndef ARMY_AI_H +#define ARMY_AI_H + +/* The highest order nibble of monst::mstrategy is kept for its vanilla uses */ +/* The remaining nibbles are used for the below purposes. */ + +/* Unit knows that the hero can control the drawbridge with the tune */ +#define ARMYAI_KNOW_AVOID_DB_TUNE 0x08000000L +/* Unit knows that the hero can control the drawbridge with magic */ +#define ARMYAI_KNOW_AVOID_DB_RAY 0x04000000L +/* Units are currently not aware of the Bell of Opening */ + +/* If firing a ray at someone with both reflect ammy and + * SDSM, the ammy reflects the ray. + * + * If firing a ray at someone with multiple sources of + * reflection, they take precedence in the following order + * (highest priority at top): + * - Shield of reflection + * - Longbow of Diana + * - Amulet of reflection + * - Silver dragon scale mail + */ +#define ARMYAI_KNOW_U_REFLECT 0x02000000L +#define ARMYAI_KNOW_U_DONT_REFLECT 0x01000000L +#define ARMYAI_KNOW_U_HAVE_MR 0x00800000L +#define ARMYAI_KNOW_U_NO_MR 0x00400000L + +/* The below are not in use yet */ + +#define ARMYAI_KNOW_U_HAVE_RAY_ATTACK 0x00200000L + +#define ARMYAI_GRUNT_STRAT_GUARD 0x00080000L +#define ARMYAI_GRUNT_FIRE 0x00040000L +#define ARMYAI_GRUNT_CHARGE 0x00020000L + +#define ARMYAI_CO_FALL_BACK 0x00080000L +#define ARMYAI_CO_CHARGE 0x00040000L +#define ARMYAI_CO_PINCER 0x00020000L + +#define ARMYAI_STRAT_XMASK 0x000003e0L /* 7 bits, 0->127 */ +#define ARMYAI_STRAT_YMASK 0x0000001fL /* 5 bits, 0->31 */ + +#define ARMYAI_STRAT_GOALX(s) ((xchar)((s & STRAT_XMASK) >> 5)) +#define ARMYAI_STRAT_GOALY(s) ((xchar)((s & STRAT_YMASK))) + +#endif ARMY_AI_H diff -Nurd original/include/config.h new/include/config.h --- original/include/config.h 2003-12-08 00:39:13.000000000 +0100 +++ new/include/config.h 2008-09-21 23:55:36.000000000 +0200 @@ -314,6 +314,7 @@ * If you define the following flags, you will add not only to the * complexity of the game but also to the size of the load module. */ +#define ARMY_AI /* dungeon features */ #define SINKS /* Kitchen sinks - Janet Walz */ diff -Nurd original/src/army_ai.c new/src/army_ai.c --- original/src/army_ai.c 1970-01-01 01:00:00.000000000 +0100 +++ new/src/army_ai.c 2008-09-21 23:55:36.000000000 +0200 @@ -0,0 +1,517 @@ + +/* + * Some terminology: + * + * command range - the max range an officer can command subordinates, given in + * distance squared (to correspond with dist2() etc.) + * + * db, DB - a drawbridge (usually the whole thing: both drawbridge squares) + * + * portcullis - the DBWALL part of a drawbridge + * + * unit - an army unit, either a soldier, a sergeant, a lieutenant or + * a captain. Guards are not considered army units and are not + * handled in this file at all. Any army unit that happens to + * be covetous (shouldn't really happen) is also excluded since + * covetous monsters use monst::mstrategy for their own purposes. + */ + +/* + * Army behaviour: + * + * -Army Intelligence- + * + * Army units that notice the hero: + * - reflecting a ray + * - failing to reflect a ray + * - having obvious MR-affected attacks plink off + * - having obvious MR-affected attacks affect him + * will remember this and take it into account when deciding whether to + * zap the hero with various attack types later on. + * + * Army units that witness a drawbridge opening or closing at the command of + * the hero will be wary of stepping onto it while the hero is positioned so + * as to control the drawbridge. They differentiate between passtune control + * and spell-based control (/oOpening, /oLocking, etc.). They are ignorant of + * Bell of Opening-based control and they don't care about Force Bolt/Striking + * at all. + * + * -Command and Control- (NOT IMPLEMENTED) + * + * Officers will have a chance of receiving intelligence from subordinate units + * within command range (e.g. if a Soldier knows that the hero has reflection + * then a Captain that comes within command range of that Soldier may adopt + * this information) and also have a chance of imparting their own intelligence + * upon subordinates within range. Units who already have a piece of + * information will resist being told the opposite information by a different + * unit so a Soldier that has witnessed the hero reflecting a ray will not + * be convinced by a Sergeant trying to tell him otherwise and vice versa. + * + * -Tactical Deployment- (NOT IMPLEMENTED) + * + * Officers will decide upon some overall strategy to employ and will issue + * orders to subordinates within command range in the pursuit of this strategy. + * Soldiers will only faithfully adhere to their orders so long as an officer + * is within command range but while this is the case will follow them + * even if they conflict with the Soldiers' own information (e.g. if ordered + * to zap the hero, will do so even if the Soldier thinks the hero has + * reflection). + */ + +#include "hack.h" +#include "army_ai.h" + +/* + * Checks if a given monster is a Yendorian Army unit. + * + * Returns true if the monster is a non-covetous soldier, sergeant, lieutenant + * or captain. + */ +STATIC_OVL boolean +is_army_unit(m) + struct monst* m; +{ + /* We don't want no steenk'n covetous troops in our army! */ + /* (Because they use mstrategy for entirely different purposes) */ + return !is_covetous(m->data) && + ((m->data) == &mons[PM_SOLDIER] || + (m->data) == &mons[PM_SERGEANT] || + (m->data) == &mons[PM_LIEUTENANT] || + (m->data) == &mons[PM_CAPTAIN]); +} + +/* + * Determines if a monster can see a given drawbridge. + * + * m is the monster. + * x and y are the coordinates of the drawbridge wall (portcullis). + * + * Returns true if the monster can see any part of the drawbridge. + */ +STATIC_OVL boolean +m_canseedb(m, x, y) + struct monst* m; + int x, y; +{ + int x2 = x, y2 = y; + return (m_cansee(m, x, y) && (levl[x][y].lit) + || (find_drawbridge(&x2, &y2) + && m_cansee(m, x2, y2) && levl[x2][y2].lit)); +} + +/* + * Finds the portcullis part of a drawbridge. + * + * x and y must give the coordinate of some part of a drawbridge (either the + * bridge or the portcullis). + * + * Returns TRUE if there is a drawbridge at (x,y), FALSE if there is not. + * + * Upon exit, (x,y) always contain the coordinate of the portcullis part of + * the drawbridge if this function returns TRUE. + */ +STATIC_OVL boolean +find_portcullis(x, y) + int *x, *y; +{ + if (!find_drawbridge(x, y)) return FALSE; + + /* (x,y) is now the bridge, find the portcullis */ + switch (levl[*x][*y].drawbridgemask & DB_DIR) + { + case DB_WEST: --*x; return TRUE; + case DB_EAST: ++*x; return TRUE; + case DB_NORTH: --*y; return TRUE; + case DB_SOUTH: ++*y; return TRUE; + } + return FALSE; +} + +/* + * Called when the player causes a drawbridge to open or close. + * The function then goes on to + * determine if any units discover what is happening, updating + * their knowledge base accordingly. + * + * reason is the potential knowledge imparted by the drawbridge opening/closing, + * either ARMYAI_KNOW_AVOID_DB_TUNE or ARMYAI_KNOW_AVOID_DB_RAY. + * x and y are the coordinates of any part of the drawbridge. + */ +void +armyai_u_frob_db(x,y,reason) + int x, y; + long reason; +{ + struct monst *mm, *nmon = (struct monst *)0; + + /* We want (x,y) to be the coords of the portcullis */ + find_portcullis(&x, &y); + + /* Let's see if any units took notice */ + for(mm=fmon; mm; mm = nmon) { + nmon = mm->nmon; + if (is_army_unit(mm)) { + /* Shortcut out those already in the know */ + if (mm->mstrategy & reason) continue; + + /* IF it sees any one of the two drawbridge squares */ + if (m_canseedb(mm, x, y) + /* AND it hears the music/zap/invocation */ + && (distu(mm->mx, mm->my) <= (BOLT_LIM * BOLT_LIM) + /* OR sees you do the deed */ + || m_canseeu(mm)) + /* AND it connects the dots */ + && rn2(2)) { + /* then it realizes what's going on */ + mm->mstrategy |= reason; + } + } + } +} + +/* + * Called when the player plays the drawbridge tune, causing a + * drawbridge to open or close. + * + * x and y are the coordinates of any part of the drawbridge. + */ +void +armyai_u_frob_db_tune(x,y) + int x, y; +{ + armyai_u_frob_db(x, y, ARMYAI_KNOW_AVOID_DB_TUNE); +} + +/* + * Called when the player zaps a wand or spell causing a + * drawbridge to open or close. + * + * x and y are the coordinates of any part of the drawbridge. + */ +void +armyai_u_frob_db_ray(x,y) + int x, y; +{ + armyai_u_frob_db(x, y, ARMYAI_KNOW_AVOID_DB_RAY); +} + +/* + * Determines whether a monster thinks you're standing near + * enough to a given drawbridge to frob it with the drawbridge + * tune. + * + * m is the monster. + * x and y give the coordinate for the drawbridge's portcullis. + * + * Returns true if the monster thinks you are right next to either of + * the drawbridge's two squares. + */ +STATIC_OVL boolean +m_think_u_neardb(m, x, y) + struct monst *m; + int x, y; +{ + int xx, yy; + int mux = u.ux, muy = u.uy; + + if (!m_canseeu(m)) { + /* The monster only thinks it knows where the hero is */ + mux = m->mux; + muy = m->muy; + } + + for(yy=muy-1; yy<=muy+1; yy++) + for(xx=mux-1;xx<=mux+1;xx++) { + int xdb = xx, ydb = yy; + if(isok(xdb,ydb) && find_drawbridge(&xdb,&ydb)) { + /* Found a db near the hero - is this the same one that m is + * considering stepping onto? */ + find_portcullis(&xdb, &ydb); + if (xdb == x && ydb == y) return TRUE; + find_drawbridge(&xdb, &ydb); + if (xdb == x && ydb == y) return TRUE; + } + } + return FALSE; +} + +/* + * Checks if it is possible to zap one location from another without + * taking bounces into account. + * + * (x0, y0) is the location to zap from. + * (x1, y1) is the location to zap. + * + * Returns true if someone standing at (x0, y0) can zap location (x1, y1) + * without having to bounce the ray off of walls etc. Also takes max ray + * length into account. + * + * @TODO: Should take intervening obstacles into account (walls, etc.). + */ +STATIC_OVL boolean +canzap_direct(x0, y0, x1, y1) + int x0, y0, x1, y1; +{ + int dx = x0 - x1, dy = y0 - y1; + return (dist2(x0, y0, x1, y1) < BOLT_LIM * BOLT_LIM) + && (x0 == x1 || y0 == y1 || dx * dx == dy * dy); +} + +/* + * Determines whether a monster thinks you're standing in line + * with a given drawbridge and near enough it to zap the db with a ray. + * + * m is the monster. + * x and y give the coordinate for the drawbridge's portcullis. + * + * Returns true if the monster thinks you are in position to zap either of + * the drawbridge's two squares. + */ +STATIC_OVL boolean +m_think_u_canzapdb(m, x, y) + struct monst *m; + int x, y; +{ + int mux = u.ux, muy = u.uy; + + if (!m_canseeu(m)) { + /* The monster only thinks it knows where the hero is */ + mux = m->mux; + muy = m->muy; + } + + return canzap_direct(mux, muy, x, y) + || (find_drawbridge(&x, &y) && canzap_direct(mux, muy, x, y)); +} + +/* + * Checks if an army unit thinks that you are able to use the passtune to + * crush it with a drawbridge should it move into a given coordinate. + * + * m is an army unit. + * x and y is the coordinate it is considering moving into. + * + * Returns true if the monster is worried that the hero may crush + * it with the drawbridge passtune should it move into (x,y). + */ +STATIC_OVL boolean +m_afraid_of_db_tune(m, x, y) + struct monst *m; + int x, y; +{ + if (!find_portcullis(&x, &y)) return FALSE; + return ((m->mstrategy & ARMYAI_KNOW_AVOID_DB_TUNE) + && m_think_u_neardb(m, x, y)); +} + +/* + * Checks if an army unit thinks that you are able to use a spell to + * crush it with a drawbridge should it move into a given coordinate. + * + * m is an army unit. + * x and y is the coordinate it is considering moving into. + * + * Returns true if the monster is worried that the hero may use a spell + * to crush it with the drawbridge should it move into (x,y). + */ +STATIC_OVL boolean +m_afraid_of_db_ray(m, x, y) + struct monst *m; + int x, y; +{ + if (!find_portcullis(&x, &y)) return FALSE; + return ((m->mstrategy & ARMYAI_KNOW_AVOID_DB_RAY) + && m_think_u_canzapdb(m, x, y)); +} + +/* + * Called by the movement code to see if an army unit has information + * that would prevent it from moving into a given square. + * + * m is the monster to check - not necessarily an army unit, + * that is for this function to check. + * x and y give the coordinate of the square to (perhaps) be allowed to + * move into. + * + * Returns true if the monster doesn't want to move into the square + * given by (x,y). + */ +boolean +armyai_disallow_m_move(m, x, y) + struct monst *m; + int x, y; +{ + /* Shortcut civvies */ + if (!is_army_unit(m)) return FALSE; + + return m_afraid_of_db_tune(m, x, y) + || m_afraid_of_db_ray(m, x, y); +} + +/* + * Checks if a given monster can spot that the hero just had a spell effect + * affect/not affect him. + * + * mm is the monster doing the spotting. + * + * Returns true if the monster realized that the player just was/was not + * affected by a spell that hit him. Returns false if the monster + * is oblivious as to the event. + */ +STATIC_OVL boolean +check_spot_speffect(mm) + struct monst *mm; +{ + /* A monster notices the spell event: */ + /* IF it is within spotting range (arbitrarily chosen to be BOLT_LIM) */ + return (distu(mm->mx, mm->my) <= (BOLT_LIM * BOLT_LIM) + /* AND it either sees you or correctly guesses your location */ + && (m_canseeu(mm) || (mm->mux == u.ux && mm->muy == u.uy)) + /* AND it connects the dots */ + && rn2(2)); +} + +/* + * Called when the hero reflects a ray. This may cause units to realize + * the hero has reflection and so decide to zap him less. + */ +void +armyai_u_reflected() +{ + struct monst *mm, *nmon; + + for(mm=fmon; mm; mm = nmon) { + nmon = mm->nmon; + if (is_army_unit(mm)) { + /* Shortcut out those already in the know */ + if (mm->mstrategy & ARMYAI_KNOW_U_REFLECT) continue; + + if (check_spot_speffect(mm)) { +#ifdef DEBUG_ARMY_AI + pline("%s now knows you reflect.", Monnam(mm)); +#endif + mm->mstrategy |= ARMYAI_KNOW_U_REFLECT; + mm->mstrategy &= ~ARMYAI_KNOW_U_DONT_REFLECT; + } + } + } +} + +/* + * Called when the hero is affected by a reflectable ray. + * This may cause units to realize + * the hero doesn't have reflection and so decide to zap him more. + */ +void +armyai_u_noreflect() +{ + struct monst *mm, *nmon; + + for(mm=fmon; mm; mm = nmon) { + nmon = mm->nmon; + if (is_army_unit(mm)) { + /* Shortcut out those already in the know */ + if (mm->mstrategy & ARMYAI_KNOW_U_DONT_REFLECT) continue; + + if (check_spot_speffect(mm)) { +#ifdef DEBUG_ARMY_AI + pline("%s now knows you don't reflect.", Monnam(mm)); +#endif + mm->mstrategy |= ARMYAI_KNOW_U_DONT_REFLECT; + mm->mstrategy &= ~ARMYAI_KNOW_U_REFLECT; + } + } + } +} + +/* + * Called to determine if a monster should skip zapping the hero based on + * the reflection information the unit has about him. + * + * mm is the monster making the decision. + * + * Returns true if the monster has reason to believe it's a good idea + * NOT to zap the hero with a ray attack. + */ +boolean +armyai_m_reflect_skip(mm) + struct monst *mm; +{ + return is_army_unit(mm) && + (mm->mstrategy & ARMYAI_KNOW_U_REFLECT) && + /* Units sometimes try to zap anyway, just to probe you */ + rn2(5); +} + +/* + * Called whenever the hero flaunts his MR by shrugging off a highly visible + * spell effect. Monsters may notice this and decide not to fire MR-affected + * attacks at him. + */ +void +armyai_u_flaunt_mr() +{ + struct monst *mm, *nmon; + + for(mm=fmon; mm; mm = nmon) { + nmon = mm->nmon; + if (is_army_unit(mm)) { + /* Shortcut out those already in the know */ + if (mm->mstrategy & ARMYAI_KNOW_U_HAVE_MR) continue; + + if (check_spot_speffect(mm)) { +#ifdef DEBUG_ARMY_AI + pline("%s now knows you have MR.", Monnam(mm)); +#endif + mm->mstrategy |= ARMYAI_KNOW_U_HAVE_MR; + mm->mstrategy &= ~ARMYAI_KNOW_U_NO_MR; + } + } + } +} + +/* + * Called whenever the hero reveals his lack of MR by getting affected by a + * highly visible spell effect. Monsters may notice this and decide + * to start firing MR-affected attacks at him. + */ +void +armyai_u_lack_mr() +{ + struct monst *mm, *nmon; + + for(mm=fmon; mm; mm = nmon) { + nmon = mm->nmon; + if (is_army_unit(mm)) { + /* Shortcut out those already in the know */ + if (mm->mstrategy & ARMYAI_KNOW_U_NO_MR) continue; + + if (check_spot_speffect(mm)) { +#ifdef DEBUG_ARMY_AI + pline("%s now knows you don't have MR.", Monnam(mm)); +#endif + mm->mstrategy |= ARMYAI_KNOW_U_NO_MR; + mm->mstrategy &= ~ARMYAI_KNOW_U_HAVE_MR; + } + } + } +} + +/* + * Called to determine if a unit should skip zapping the hero based on + * the MR information the unit has about him. + * + * mm is the monster making the decision. + * + * Returns true if the monster has reason to believe it's a good idea + * NOT to zap the hero. + */ +boolean +armyai_m_mr_skip(mm) + struct monst *mm; +{ + return is_army_unit(mm) && + (mm->mstrategy & ARMYAI_KNOW_U_HAVE_MR) && + /* Units sometimes try to zap anyway, just to probe you */ + rn2(5); +} diff -Nurd original/src/mcastu.c new/src/mcastu.c --- original/src/mcastu.c 2003-12-08 00:39:13.000000000 +0100 +++ new/src/mcastu.c 2008-09-21 23:55:36.000000000 +0200 @@ -287,10 +287,18 @@ case AD_MAGM: You("are hit by a shower of missiles!"); if(Antimagic) { +#ifdef ARMY_AI + armyai_u_flaunt_mr(); +#endif shieldeff(u.ux, u.uy); pline_The("missiles bounce off!"); dmg = 0; - } else dmg = d((int)mtmp->m_lev/2 + 1,6); + } else { +#ifdef ARMY_AI + armyai_u_lack_mr(); +#endif + dmg = d((int)mtmp->m_lev/2 + 1,6); + } break; case AD_SPEL: /* wizard spell */ case AD_CLRC: /* clerical spell */ diff -Nurd original/src/mon.c new/src/mon.c --- original/src/mon.c 2003-12-08 00:39:13.000000000 +0100 +++ new/src/mon.c 2008-09-21 23:55:36.000000000 +0200 @@ -1056,6 +1056,10 @@ for(nx = max(1,x-1); nx <= maxx; nx++) for(ny = max(0,y-1); ny <= maxy; ny++) { if(nx == x && ny == y) continue; + /* bcd -- Added army AI */ +#ifdef ARMY_AI + if (armyai_disallow_m_move(mon, nx, ny)) continue; +#endif if(IS_ROCK(ntyp = levl[nx][ny].typ) && !((flag & ALLOW_WALL) && may_passwall(nx,ny)) && !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue; diff -Nurd original/src/muse.c new/src/muse.c --- original/src/muse.c 2003-12-08 00:39:13.000000000 +0100 +++ new/src/muse.c 2008-09-21 23:55:36.000000000 +0200 @@ -967,7 +967,11 @@ { register struct obj *obj; boolean ranged_stuff = lined_up(mtmp); - boolean reflection_skip = (Reflecting && rn2(2)); + boolean reflection_skip = +#ifdef ARMY_AI + armyai_m_reflect_skip(mtmp) || +#endif + (Reflecting && rn2(2)); struct obj *helmet = which_armor(mtmp, W_ARMH); m.offensive = (struct obj *)0; @@ -989,7 +993,11 @@ for(obj=mtmp->minvent; obj; obj=obj->nobj) { /* nomore(MUSE_WAN_DEATH); */ if (!reflection_skip) { - if(obj->otyp == WAN_DEATH && obj->spe > 0) { + if( +#ifdef ARMY_AI + !armyai_m_mr_skip(mtmp) && +#endif + obj->otyp == WAN_DEATH && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_DEATH; } @@ -1024,7 +1032,11 @@ m.has_offense = MUSE_WAN_LIGHTNING; } nomore(MUSE_WAN_MAGIC_MISSILE); - if(obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) { + if( +#ifdef ARMY_AI + !armyai_m_mr_skip(mtmp) && +#endif + obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_MAGIC_MISSILE; } @@ -1112,9 +1124,15 @@ if (mtmp == &youmonst) { if (zap_oseen) makeknown(WAN_STRIKING); if (Antimagic) { +#ifdef ARMY_AI + armyai_u_flaunt_mr(); +#endif shieldeff(u.ux, u.uy); pline("Boing!"); } else if (rnd(20) < 10 + u.uac) { +#ifdef ARMY_AI + armyai_u_lack_mr(); +#endif pline_The("wand hits you!"); tmp = d(2,12); if(Half_spell_damage) tmp = (tmp+1) / 2; diff -Nurd original/src/music.c new/src/music.c --- original/src/music.c 2003-12-08 00:39:13.000000000 +0100 +++ new/src/music.c 2008-09-21 23:55:36.000000000 +0200 @@ -546,6 +546,9 @@ if(isok(x,y)) if(find_drawbridge(&x,&y)) { u.uevent.uheard_tune = 2; /* tune now fully known */ +#ifdef ARMY_AI + armyai_u_frob_db_tune(x,y); +#endif if(levl[x][y].typ == DRAWBRIDGE_DOWN) close_drawbridge(x,y); else diff -Nurd original/src/zap.c new/src/zap.c --- original/src/zap.c 2003-12-08 00:39:13.000000000 +0100 +++ new/src/zap.c 2008-09-21 23:55:36.000000000 +0200 @@ -1884,9 +1884,15 @@ makeknown(WAN_STRIKING); case SPE_FORCE_BOLT: if(Antimagic) { +#ifdef ARMY_AI + armyai_u_flaunt_mr(); +#endif shieldeff(u.ux, u.uy); pline("Boing!"); } else { +#ifdef ARMY_AI + armyai_u_lack_mr(); +#endif if (ordinary) { You("bash yourself!"); damage = d(2,12); @@ -1957,9 +1963,15 @@ makeknown(WAN_MAGIC_MISSILE); case SPE_MAGIC_MISSILE: if(Antimagic) { +#ifdef ARMY_AI + armyai_u_flaunt_mr(); +#endif shieldeff(u.ux, u.uy); pline_The("missiles bounce!"); } else { +#ifdef ARMY_AI + armyai_u_lack_mr(); +#endif damage = d(4,6); pline("Idiot! You've shot yourself!"); } @@ -2315,6 +2327,9 @@ case SPE_KNOCK: /* up or down, but at closed portcullis only */ if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) { +#ifdef ARMY_AI + armyai_u_frob_db_ray(x, y); +#endif open_drawbridge(xx, yy); disclose = TRUE; } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) && @@ -2335,8 +2350,12 @@ if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) : (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) && find_drawbridge(&xx, &yy)) { - if (!striking) + if (!striking) { +#ifdef ARMY_AI + armyai_u_frob_db_ray(xx, yy); +#endif close_drawbridge(xx, yy); + } else destroy_drawbridge(xx, yy); disclose = TRUE; @@ -2680,6 +2699,9 @@ if (is_db_wall(bhitpos.x, bhitpos.y)) { if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y)) makeknown(obj->otyp); +#ifdef ARMY_AI + armyai_u_frob_db_ray(bhitpos.x, bhitpos.y); +#endif open_drawbridge(x,y); } break; @@ -2688,6 +2710,9 @@ if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y)) && levl[x][y].typ == DRAWBRIDGE_DOWN) makeknown(obj->otyp); +#ifdef ARMY_AI + armyai_u_frob_db_ray(x,y); +#endif close_drawbridge(x,y); break; case WAN_STRIKING: @@ -3075,9 +3100,15 @@ switch (abs(type) % 10) { case ZT_MAGIC_MISSILE: if (Antimagic) { +#ifdef ARMY_AI + armyai_u_flaunt_mr(); +#endif shieldeff(sx, sy); pline_The("missiles bounce off!"); } else { +#ifdef ARMY_AI + armyai_u_lack_mr(); +#endif dam = d(nd,6); exercise(A_STR, FALSE); } @@ -3141,10 +3172,17 @@ You("seem unaffected."); break; } else if (Antimagic) { +#ifdef ARMY_AI + armyai_u_flaunt_mr(); +#endif shieldeff(sx, sy); You("aren't affected."); break; - } + } else { +#ifdef ARMY_AI + armyai_u_lack_mr(); +#endif + } killer_format = KILLED_BY_AN; killer = fltxt; /* when killed by disintegration breath, don't leave corpse */ @@ -3447,6 +3485,9 @@ range -= 2; pline("%s hits you!", The(fltxt)); if (Reflecting) { +#ifdef ARMY_AI + armyai_u_reflected(); +#endif if (!Blind) { (void) ureflects("But %s reflects from your %s!", "it"); } else @@ -3455,6 +3496,9 @@ dy = -dy; shieldeff(sx, sy); } else { +#ifdef ARMY_AI + armyai_u_noreflect(); +#endif zhitu(type, nd, fltxt, sx, sy); } } else { diff -Nurd original/sys/unix/Makefile.src new/sys/unix/Makefile.src --- original/sys/unix/Makefile.src 2003-12-08 00:39:13.000000000 +0100 +++ new/sys/unix/Makefile.src 2008-09-21 23:55:36.000000000 +0200 @@ -312,7 +312,8 @@ # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific -HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ +HACKCSRC = allmain.c alloc.c apply.c army_ai.c \ + artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ @@ -369,7 +370,8 @@ # the following .o's _must_ be made before any others (for makedefs) FIRSTOBJ = monst.o objects.o -HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \ +HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o army_ai.o \ + artifact.o attrib.o ball.o \ bones.o botl.o cmd.o dbridge.o decl.o detect.o dig.o display.o dlb.o \ do.o do_name.o do_wear.o dog.o dogmove.o dokick.o dothrow.o \ drawing.o dungeon.o eat.o end.o engrave.o exper.o explode.o \ @@ -698,6 +700,7 @@ allmain.o: allmain.c $(HACK_H) alloc.o: alloc.c $(CONFIG_H) apply.o: apply.c $(HACK_H) ../include/edog.h +armyai.o: army_ai.c $(HACK_H) ../include/armyai.h artifact.o: artifact.c $(HACK_H) ../include/artifact.h ../include/artilist.h attrib.o: attrib.c $(HACK_H) ball.o: ball.c $(HACK_H)