// Drop an item someplace around here. void fall(THING obj, bool pr) { PLACE pp; coord fpos = new coord(); if (fallpos(obj.o_pos, fpos)) { pp = INDEX(fpos.y, fpos.x); pp.p_ch = (char)obj.o_type; obj.o_pos.CopyFrom(fpos); if (cansee(fpos.y, fpos.x)) { if (pp.p_monst != null) pp.p_monst.t_oldch = (char)obj.o_type; else mvaddch(fpos.y, fpos.x, obj.o_type); } attach(ref lvl_obj, obj); return; } if (pr) { if (has_hit) { endmsg(); has_hit = false; } msg("the {0} vanishes as it hits the ground", weap_info[obj.o_which].oi_name); } discard(obj); }
// Throw the whole blamed thing away void free_list(ref THING ptr) { THING item; while (ptr != null) { item = ptr; ptr = next(item); discard(item); } }
// takes an item out of whatever linked list it might be in void detach(ref THING list, THING item) { if (list == item) list = next(item); if (prev(item) != null) item.l_prev.l_next = next(item); if (next(item) != null) item.l_next.l_prev = prev(item); item.l_next = null; item.l_prev = null; }
// Set things up when we really know what a thing is void set_know(THING obj, obj_info[] info) { string guess; info[obj.o_which].oi_know = true; obj.o_flags |= ISKNOW; guess = info[obj.o_which].oi_guess; if (!string.IsNullOrEmpty(guess)) { info[obj.o_which].oi_guess = null; } }
// Print ring bonuses string ring_num(THING obj) { if (!((obj.o_flags & ISKNOW) != 0)) return ""; switch (obj.o_which) { case R_PROTECT: case R_ADDSTR: case R_ADDDAM: case R_ADDHIT: return string.Format(" [{0}]", num(obj.o_arm, 0, RING)); } return ""; }
// add an item to the head of a list void attach(ref THING list, THING item) { if (list != null) { item.l_next = list; list.l_prev = item; item.l_prev = null; } else { item.l_next = null; item.l_prev = null; } list = item; }
// Do the actual motion on the screen done by an object traveling // across the room void do_motion(THING obj, int ydelta, int xdelta) { char ch; /* * Come fly with us ... */ obj.o_pos.CopyFrom(hero); for (; ; ) { /* * Erase the old one */ if (!ce(obj.o_pos, hero) && cansee(obj.o_pos.y, obj.o_pos.x) && !terse) { ch = chat(obj.o_pos.y, obj.o_pos.x); if (ch == FLOOR && !show_floor()) ch = ' '; mvaddch(obj.o_pos.y, obj.o_pos.x, ch); } /* * Get the new position */ obj.o_pos.y += ydelta; obj.o_pos.x += xdelta; if (step_ok(ch = winat(obj.o_pos.y, obj.o_pos.x)) && ch != DOOR) { /* * It hasn't hit anything yet, so display it * If it alright. */ if (cansee(obj.o_pos.y, obj.o_pos.x) && !terse) { mvaddch(obj.o_pos.y, obj.o_pos.x, obj.o_type); refresh(); } continue; } break; } }
// The monster attacks the player int attack(THING mp) { string mname; int oldhp; /* * Since this is an attack, stop running and any healing that was * going on at the time. */ running = false; count = 0; quiet = 0; if (to_death && !on(mp, ISTARGET)) { to_death = false; kamikaze = false; } if (mp.t_type == 'X' && mp.t_disguise != 'X' && !on(player, ISBLIND)) { mp.t_disguise = 'X'; if (on(player, ISHALU)) { mvaddch(mp.t_pos.y, mp.t_pos.x, rnd(26) + 'A'); } } mname = set_mname(mp); oldhp = pstats.s_hpt; if (roll_em(mp, player, null, false)) { if (mp.t_type != 'I') { if (has_hit) { addmsg(". "); } hit(mname, null, false); } else if (has_hit) { endmsg(); } has_hit = false; if (pstats.s_hpt <= 0) { death(mp.t_type); /* Bye bye life ... */ } else if (!kamikaze) { oldhp -= pstats.s_hpt; if (oldhp > max_hit) { max_hit = oldhp; } if (pstats.s_hpt <= max_hit) { to_death = false; } } if (!on(mp, ISCANC)) { switch (mp.t_type) { case 'A': /* * If an aquator hits, you can lose armor class. */ rust_armor(cur_armor); break; case 'I': /* * The ice monster freezes you */ player.t_flags &= ~ISRUN; if (no_command == 0) { addmsg("you are frozen"); if (!terse) { addmsg(" by the {0}", mname); } endmsg(); } no_command += rnd(2) + 2; if (no_command > BORE_LEVEL) { death('h'); } break; case 'R': /* * Rattlesnakes have poisonous bites */ if (!save(VS_POISON)) { if (!ISWEARING(R_SUSTSTR)) { chg_str(-1); if (!terse) { msg("you feel a bite in your leg and now feel weaker"); } else { msg("a bite has weakened you"); } } else if (!to_death) { if (!terse) { msg("a bite momentarily weakens you"); } else { msg("bite has no effect"); } } } break; case 'W': case 'V': /* * Wraiths might drain energy levels, and Vampires * can steal max_hp */ if (rnd(100) < (mp.t_type == 'W' ? 15 : 30)) { int fewer; if (mp.t_type == 'W') { if (pstats.s_exp == 0) { death('W'); /* All levels gone */ } if (--pstats.s_lvl == 0) { pstats.s_exp = 0; pstats.s_lvl = 1; } else { pstats.s_exp = e_levels[pstats.s_lvl - 1] + 1; } fewer = roll(1, 10); } else { fewer = roll(1, 3); } pstats.s_hpt -= fewer; max_hp -= fewer; if (pstats.s_hpt <= 0) { pstats.s_hpt = 1; } if (max_hp <= 0) { death(mp.t_type); } msg("you suddenly feel weaker"); } break; case 'F': /* * Venus Flytrap stops the poor guy from moving */ player.t_flags |= ISHELD; monsters['F' - 'A'].m_stats.s_dmg = string.Format("{0}x1", ++vf_hit); if (--pstats.s_hpt <= 0) { death('F'); } break; case 'L': { /* * Leperachaun steals some gold */ int lastpurse; lastpurse = purse; purse -= GOLDCALC(); if (!save(VS_MAGIC)) { purse -= GOLDCALC() + GOLDCALC() + GOLDCALC() + GOLDCALC(); } if (purse < 0) { purse = 0; } remove_mon(mp.t_pos, mp, false); mp = null; if (purse != lastpurse) { msg("your purse feels lighter"); } } break; case 'N': { THING obj, steal; int nobj; /* * Nymph's steal a magic item, look through the pack * and pick out one we like. */ steal = null; for (nobj = 0, obj = pack; obj != null; obj = next(obj)) { if (obj != cur_armor && obj != cur_weapon && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT] && is_magic(obj) && rnd(++nobj) == 0) { steal = obj; } } if (steal != null) { remove_mon(mp.t_pos, moat(mp.t_pos.y, mp.t_pos.x), false); mp = null; leave_pack(steal, false, false); msg("she stole {0}!", inv_name(steal, true)); discard(steal); } } break; default: break; } } } else if (mp.t_type != 'I') { if (has_hit) { addmsg(". "); has_hit = false; } if (mp.t_type == 'F') { pstats.s_hpt -= vf_hit; if (pstats.s_hpt <= 0) { death(mp.t_type); /* Bye bye life ... */ } } miss(mname, null, false); } //if (fight_flush && !to_death) //flush_type(); count = 0; status(); if (mp == null) { return(-1); } else { return(0); } }
// Find the spot for the chaser(er) to move closer to the // chasee(ee). Returns TRUE if we want to keep on chasing later // FALSE if we reach the goal. bool chase(THING tp, coord ee) { THING obj; int x, y; int curdist, thisdist; coord er = tp.t_pos; char ch; int plcnt = 1; /* * If the thing is confused, let it move randomly. Invisible * Stalkers are slightly confused all of the time, and bats are * quite confused all the time */ if ((on(tp, ISHUH) && rnd(5) != 0) || (tp.t_type == 'P' && rnd(5) == 0) || (tp.t_type == 'B' && rnd(2) == 0)) { /* * get a valid random move */ ch_ret.CopyFrom(rndmove(tp)); curdist = dist_cp(ch_ret, ee); /* * Small chance that it will become un-confused */ if (rnd(20) == 0) tp.t_flags &= ~ISHUH; } /* * Otherwise, find the empty spot next to the chaser that is * closest to the chasee. */ else { int ey, ex; /* * This will eventually hold where we move to get closer * If we can't find an empty spot, we stay where we are. */ curdist = dist_cp(er, ee); ch_ret.CopyFrom(er); ey = er.y + 1; if (ey >= NUMLINES - 1) ey = NUMLINES - 2; ex = er.x + 1; if (ex >= NUMCOLS) ex = NUMCOLS - 1; for (x = er.x - 1; x <= ex; x++) { if (x < 0) continue; tryp.x = x; for (y = er.y - 1; y <= ey; y++) { tryp.y = y; if (!diag_ok(er, tryp)) continue; ch = winat(y, x); if (step_ok(ch)) { /* * If it is a scroll, it might be a scare monster scroll * so we need to look it up to see what type it is. */ if (ch == SCROLL) { for (obj = lvl_obj; obj != null; obj = next(obj)) { if (y == obj.o_pos.y && x == obj.o_pos.x) break; } if (obj != null && obj.o_which == S_SCARE) continue; } /* * It can also be a Xeroc, which we shouldn't step on */ if ((obj = moat(y, x)) != null && obj.t_type == 'X') continue; /* * If we didn't find any scrolls at this place or it * wasn't a scare scroll, then this place counts */ thisdist = dist(y, x, ee.y, ee.x); if (thisdist < curdist) { plcnt = 1; ch_ret.CopyFrom(tryp); curdist = thisdist; } else if (thisdist == curdist && rnd(++plcnt) == 0) { ch_ret.CopyFrom(tryp); curdist = thisdist; } } } } } return (bool)(curdist != 0 && !ce(ch_ret, hero)); }
// Return TRUE if the hero can see the monster bool see_monst(THING mp) { int y, x; if (on(player, ISBLIND)) return false; if (on(mp, ISINVIS) && !on(player, CANSEE)) return false; y = mp.t_pos.y; x = mp.t_pos.x; if (dist(y, x, hero.y, hero.x) < LAMPDIST) { if (y != hero.y && x != hero.x && !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) return false; return true; } if (mp.t_room != proom) return false; return ((bool)!((mp.t_room.r_flags & ISDARK) == ISDARK)); }
// Execute a single turn of running for a monster int move_monst(THING tp) { if (!on(tp, ISSLOW) || tp.t_turn) if (do_chase(tp) == -1) return (-1); if (on(tp, ISHASTE)) if (do_chase(tp) == -1) return (-1); tp.t_turn ^= true; return (0); }
// Make one thing chase another. int do_chase(THING th) { coord cp; room rer, ree; /* room of chaser, room of chasee */ int mindist = 32767, curdist; bool stoprun = false; /* TRUE means we are there */ bool door; THING obj; rer = th.t_room; /* Find room of chaser */ if (on(th, ISGREED) && rer.r_goldval == 0) th.t_dest = hero; /* If gold has been taken, run after hero */ if (th.t_dest == hero) /* Find room of chasee */ ree = proom; else ree = roomin(th.t_dest); /* * We don't count doors as inside rooms for this routine */ door = (chat(th.t_pos.y, th.t_pos.x) == DOOR); /* * If the object of our desire is in a different room, * and we are not in a corridor, run to the door nearest to * our goal. */ over: if (rer != ree) { for (int i = 0; i < rer.r_nexits; i++) { cp = rer.r_exit[i]; curdist = dist_cp(th.t_dest, cp); if (curdist < mindist) { thisCoord.CopyFrom(cp); mindist = curdist; } } if (door) { rer = passages[flat(th.t_pos.y, th.t_pos.x) & F_PNUM]; door = false; goto over; } } else { thisCoord.CopyFrom(th.t_dest); /* * For dragons check and see if (a) the hero is on a straight * line from it, and (b) that it is within shooting distance, * but outside of striking range. */ if (th.t_type == 'D' && (th.t_pos.y == hero.y || th.t_pos.x == hero.x || Math.Abs(th.t_pos.y - hero.y) == Math.Abs(th.t_pos.x - hero.x)) && dist_cp(th.t_pos, hero) <= BOLT_LENGTH * BOLT_LENGTH && !on(th, ISCANC) && rnd(DRAGONSHOT) == 0) { delta.y = Math.Sign(hero.y - th.t_pos.y); delta.x = Math.Sign(hero.x - th.t_pos.x); if (has_hit) endmsg(); fire_bolt(th.t_pos, delta, "flame"); running = false; count = 0; quiet = 0; if (to_death && !on(th, ISTARGET)) { to_death = false; kamikaze = false; } return(0); } } /* * This now contains what we want to run to this time * so we run to it. If we hit it we either want to fight it * or stop running */ if (!chase(th, thisCoord)) { if (ce(thisCoord, hero)) { return( attack(th) ); } else if (ce(thisCoord, th.t_dest)) { for (obj = lvl_obj; obj != null; obj = next(obj)) if (th.t_dest == obj.o_pos) { detach(ref lvl_obj, obj); attach(ref th.t_pack, obj); chat(obj.o_pos.y, obj.o_pos.x, (th.t_room.r_flags & ISGONE) != 0 ? PASSAGE : FLOOR); th.t_dest = find_dest(th); break; } if (th.t_type != 'F') stoprun = true; } } else { if (th.t_type == 'F') return(0); } relocate(th, ch_ret); /* * And stop running if need be */ if (stoprun && ce(th.t_pos, th.t_dest)) th.t_flags &= ~ISRUN; return(0); }
bool on(THING thing, int flag) { return (thing.t_flags & flag) != 0; }
void moat(int y, int x, THING monst) { places[(x << 5) + y].p_monst = monst; }
// Called to put a monster to death void killed(THING tp, bool pr) { string mname; pstats.s_exp += tp.t_stats.s_exp; /* * If the monster was a venus flytrap, un-hold him */ switch (tp.t_type) { case 'F': player.t_flags &= ~ISHELD; vf_hit = 0; monsters['F' - 'A'].m_stats.s_dmg = "000x0"; break; case 'L': { THING gold; if (fallpos(tp.t_pos, tp.t_room.r_gold) && level >= max_level) { gold = new_item(); gold.o_type = GOLD; gold.o_goldval = GOLDCALC(); if (save(VS_MAGIC)) { gold.o_goldval += GOLDCALC() + GOLDCALC() + GOLDCALC() + GOLDCALC(); } attach(ref tp.t_pack, gold); } } break; } /* * Get rid of the monster. */ mname = set_mname(tp); remove_mon(tp.t_pos, tp, true); if (pr) { if (has_hit) { addmsg(". Defeated "); has_hit = false; } else { if (!terse) { addmsg("you have "); } addmsg("defeated "); } msg(mname); } /* * Do adjustments if he went up a level */ check_level(); //if (fight_flush) //flush_type(); }
// Print what we've discovered of type 'type' void print_disc(char type) { obj_info[] info = null; int i, maxnum = 0, num_found; THING obj = new THING(); int[] order = new int[Math.Max(MAXSCROLLS, Math.Max(MAXPOTIONS, Math.Max(MAXRINGS, MAXSTICKS)))]; switch (type) { case SCROLL: maxnum = MAXSCROLLS; info = scr_info; break; case POTION: maxnum = MAXPOTIONS; info = pot_info; break; case RING: maxnum = MAXRINGS; info = ring_info; break; case STICK: maxnum = MAXSTICKS; info = ws_info; break; } set_order(order, maxnum); obj.o_count = 1; obj.o_flags = 0; num_found = 0; for (i = 0; i < maxnum; i++) if (info[order[i]].oi_know || !string.IsNullOrEmpty(info[order[i]].oi_guess)) { obj.o_type = type; obj.o_which = order[i]; add_line("{0}", inv_name(obj, false)); num_found++; } if (num_found == 0) add_line(nothing(type), null); }
// Return a pointer to a null-length string string nullstr(THING ignored) { return ""; }
// Give the proper name to a potion, stick, or ring void nameit(THING obj, string type, string which, obj_info op, Func<THING, string> prfunc) { if (op.oi_know || !string.IsNullOrEmpty(op.oi_guess)) { if (obj.o_count == 1) prbuf = string.Format("A {0} ", type); else prbuf = string.Format("{0} {1}s ", obj.o_count, type); if (op.oi_know) prbuf += string.Format("of {0}{1}({2})", op.oi_name, prfunc(obj), which); else if (!string.IsNullOrEmpty(op.oi_guess)) prbuf += string.Format("called {0}{1}({2})", op.oi_guess, prfunc(obj), which); } else if (obj.o_count == 1) prbuf = string.Format("A{0} {1} {2}", vowelstr(which), which, type); else prbuf = string.Format("{0} {1} {2}s", obj.o_count, which, type); }
// Return the name of something as it would appear in an // inventory. string inv_name(THING obj, bool drop) { string pb; obj_info op; string sp; int which; pb = ""; which = obj.o_which; switch (obj.o_type) { case POTION: nameit(obj, "potion", p_colors[which], pot_info[which], nullstr); pb = prbuf; break; case RING: nameit(obj, "ring", r_stones[which], ring_info[which], ring_num); pb = prbuf; break; case STICK: nameit(obj, ws_type[which], ws_made[which], ws_info[which], charge_str); pb = prbuf; break; case SCROLL: if (obj.o_count == 1) { pb = "A scroll "; } else { pb = string.Format("{0} scrolls ", obj.o_count); } op = scr_info[which]; if (op.oi_know) pb += string.Format("of {0}", op.oi_name); else if (!string.IsNullOrEmpty(op.oi_guess)) pb += string.Format("called {0}", op.oi_guess); else pb += string.Format("titled '{0}'", s_names[which]); break; case FOOD: if (which == 1) if (obj.o_count == 1) pb = string.Format("A{0} {1}", vowelstr(fruit), fruit); else pb = string.Format("{0} {1}s", obj.o_count, fruit); else if (obj.o_count == 1) pb = "Some food"; else pb = string.Format("{0} rations of food", obj.o_count); break; case WEAPON: sp = weap_info[which].oi_name; if (obj.o_count > 1) pb = string.Format("{0} ", obj.o_count); else pb = string.Format("A{0} ", vowelstr(sp)); if ((obj.o_flags & ISKNOW) != 0) pb += string.Format("{0} {1}", num(obj.o_hplus, obj.o_dplus, WEAPON), sp); else pb += sp; if (obj.o_count > 1) pb += "s"; if (obj.o_label != null) { pb += string.Format(" called {0}", obj.o_label); } break; case ARMOR: sp = arm_info[which].oi_name; if ((obj.o_flags & ISKNOW) != 0) { pb = string.Format("{0} {1} [", num(a_class[which] - obj.o_arm, 0, ARMOR), sp); if (!terse) pb += "protection "; pb += string.Format("{0}]", 10 - obj.o_arm); } else pb = sp; if (obj.o_label != null) { pb += string.Format(" called {0}", obj.o_label); } break; case AMULET: pb = "The Amulet of Yendor"; break; case GOLD: pb = string.Format("{0} Gold pieces", obj.o_goldval); break; } if (inv_describe) { if (obj == cur_armor) pb += " (being worn)"; if (obj == cur_weapon) pb += " (weapon in hand)"; if (obj == cur_ring[LEFT]) pb += " (on left hand)"; else if (obj == cur_ring[RIGHT]) pb += " (on right hand)"; } if (drop && char.IsUpper(pb[0])) pb = pb.Substring(0, 1).ToLower() + pb.Substring(1); else if (!drop && char.IsUpper(pb[0])) pb = pb.Substring(0, 1).ToUpper() + pb.Substring(1); return pb; }
// Do special checks for dropping or unweilding|unwearing|unringing bool dropcheck(THING obj) { if (obj == null) return true; if (obj != cur_armor && obj != cur_weapon && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT]) return true; if ((obj.o_flags & ISCURSED) != 0) { msg("you can't. It appears to be cursed"); return false; } if (obj == cur_weapon) cur_weapon = null; else if (obj == cur_armor) { waste_time(); cur_armor = null; } else { cur_ring[obj == cur_ring[LEFT] ? LEFT : RIGHT] = null; switch (obj.o_which) { case R_ADDSTR: chg_str(-obj.o_arm); break; case R_SEEINVIS: unsee(0); extinguish(unsee); break; } } return true; }
static public string GetDescription(THING t) { //inventory text that shows count, pluses, and formerly if it was worn/equipped/wielded string n = ""; ObjectData d; string root = GetName(t); //essential root name switch (t.ItemType) { case Char.POTION: nameit(t, "potion", Potion.ColorsUsed[t.Which], Potion.Data[t.Which], nullstr); n = prbuf; break; case Char.RING: nameit(t, "ring", Ring.StonesUsed[t.Which], Ring.Data[t.Which], Ring.ProtectionMaybe); n = prbuf; break; case Char.STICK: nameit(t, Stick.ws_type[t.Which], Stick.ws_made[t.Which], Stick.Data[t.Which], Stick.charge_str); n = prbuf; break; case Char.SCROLL: if (t.Count == 1) { n = "A scroll "; } else { n = string.Format("{0} scrolls ", t.Count); } d = Scroll.Data[t.Which]; if (d.Know) { n += string.Format("of {0}", d.Name); } else if (!string.IsNullOrEmpty(d.Guess)) { n += string.Format("called {0}", d.Guess); } else { n += string.Format("titled \"{0}\"", Scroll.s_names[t.Which]); } break; case Char.FOOD: if (t.Which == 1) { if (t.Count == 1) { n = string.Format("A{0} {1}", vowelstr(R14.fruit), R14.fruit); } else { n = string.Format("{0} {1}s", t.Count, R14.fruit); } } else if (t.Count == 1) { n = "Some food"; } else { n = string.Format("{0} rations of food", t.Count); } break; case Char.WEAPON: if (t.Count > 1) { n = string.Format("{0} ", t.Count); } else { n = string.Format("A{0} ", vowelstr(root)); } if ((t.o_flags & ISKNOW) != 0) { n += string.Format("{0} {1} {2}", t.PlusToHit, t.PlusToDmg, root); } else { n += root; } if (t.Count > 1) { n += "s"; } if (t.o_label != null) { n += string.Format(" called {0}", t.o_label); } break; case Char.ARMOUR: if ((t.o_flags & ISKNOW) != 0) { n = string.Format("{0} {1} [", Armour.Data[t.Which].AC - t.Ac, root); if (!Agent.Terse) { n += "protection "; } n += string.Format("{0}]", 10 - t.Ac); } else { n = root; } if (t.o_label != null) { n += string.Format(" called {0}", t.o_label); } break; default: n = root; break; } return(n); }
// Set up the initial goodies for a weapon void init_weapon(THING weap, int which) { init_weaps iwp; weap.o_type = WEAPON; weap.o_which = which; iwp = init_dam[which]; weap.o_damage = iwp.iw_dam; weap.o_hurldmg = iwp.iw_hrl; weap.o_launch = iwp.iw_launch; weap.o_flags = iwp.iw_flags; weap.o_hplus = 0; weap.o_dplus = 0; if (which == DAGGER) { weap.o_count = rnd(4) + 2; weap.o_group = group++; } else if ((weap.o_flags & ISMANY) == ISMANY) { weap.o_count = rnd(8) + 8; weap.o_group = group++; } else { weap.o_count = 1; weap.o_group = 0; } }
// Return a pointer to a null-length string static string nullstr(THING ignored) { return(""); }
public static bool on(THING thing, int flag) { return((thing.t_flags & flag) != 0); }
THING next(THING ptr) { return ptr.l_next; }
//list stuff **************************************************** //detach from linked list public static THING next(THING ptr) { return(ptr.l_next); }
THING prev(THING ptr) { return ptr.l_prev; }
public static THING prev(THING ptr) { return(ptr.l_prev); }
// find the proper destination for the monster coord find_dest(THING tp) { THING obj; int prob; if ((prob = monsters[tp.t_type - 'A'].m_carry) <= 0 || tp.t_room == proom || see_monst(tp)) return hero; for (obj = lvl_obj; obj != null; obj = next(obj)) { if (obj.o_type == SCROLL && obj.o_which == S_SCARE) continue; if (roomin(obj.o_pos) == tp.t_room && rnd(100) < prob) { for (tp = mlist; tp != null; tp = next(tp)) if (tp.t_dest.Equals(obj.o_pos)) break; if (tp == null) return obj.o_pos; } } return hero; }
// Move in a random direction if the monster/person is confused coord rndmove(THING who) { THING obj; int x, y; char ch; y = ret.y = who.t_pos.y + rnd(3) - 1; x = ret.x = who.t_pos.x + rnd(3) - 1; /* * Now check to see if that's a legal move. If not, don't move. * (I.e., bump into the wall or whatever) */ if (y == who.t_pos.y && x == who.t_pos.x) return ret; if (!diag_ok(who.t_pos, ret)) goto bad; else { ch = winat(y, x); if (!step_ok(ch)) goto bad; if (ch == SCROLL) { for (obj = lvl_obj; obj != null; obj = next(obj)) if (y == obj.o_pos.y && x == obj.o_pos.x) break; if (obj != null && obj.o_which == S_SCARE) goto bad; } } return ret; bad: ret.CopyFrom(who.t_pos); return ret; }
// Make the monster's new location be the specified one, updating // all the relevant state. void relocate(THING th, coord new_loc) { room oroom; char symbol = th.t_disguise; if (!ce(new_loc, th.t_pos)) { Debug.WriteLine(string.Format("{0} moved to {1}.", symbol, new_loc)); mvaddch(th.t_pos.y, th.t_pos.x, th.t_oldch); th.t_room = roomin(new_loc); set_oldch(th, new_loc); oroom = th.t_room; moat(th.t_pos.y, th.t_pos.x, null); if (oroom != th.t_room) { Debug.WriteLine(string.Format("{0} moved into room {1}.", symbol, oroom)); th.t_dest = find_dest(th); } th.t_pos.CopyFrom(new_loc); moat(new_loc.y, new_loc.x, th); } move(new_loc.y, new_loc.x); if (see_monst(th)) addch(th.t_disguise); else if (on(player, SEEMONST)) { standout(); addch(th.t_type); standend(); } }
// Rust the given armor, if it is a legal kind to rust, and we // aren't wearing a magic ring. void rust_armor(THING arm) { if (arm == null || arm.o_type != ARMOR || arm.o_which == LEATHER || arm.o_arm >= 9) return; if (((arm.o_flags & ISPROT) != 0) || ISWEARING(R_SUSTARM)) { if (!to_death) msg("the rust vanishes instantly"); } else { arm.o_arm++; if (!terse) msg("your armor appears to be weaker now. Oh my!"); else msg("your armor weakens"); } }
// Set the oldch character for the monster void set_oldch(THING tp, coord cp) { char sch; if (ce(tp.t_pos, cp)) return; sch = tp.t_oldch; tp.t_oldch = CCHAR(mvinch(cp.y, cp.x)); if (!on(player, ISBLIND)) { if ((sch == FLOOR || tp.t_oldch == FLOOR) && ((tp.t_room.r_flags & ISDARK) != 0)) tp.t_oldch = ' '; else if (dist_cp(cp, hero) <= LAMPDIST && see_floor) tp.t_oldch = chat(cp.y, cp.x); } }
// The player attacks the monster. bool fight(coord mp, THING weap, bool thrown) { THING tp; bool did_hit = true; string mname; char ch; /* * Find the monster we want to fight */ tp = moat(mp.y, mp.x); /* * Since we are fighting, things are not quiet so no healing takes * place. */ count = 0; quiet = 0; runto(mp); /* * Let him know it was really a xeroc (if it was one). */ ch = '\0'; if (tp.t_type == 'X' && tp.t_disguise != 'X' && !on(player, ISBLIND)) { tp.t_disguise = 'X'; if (on(player, ISHALU)) { ch = (char)(rnd(26) + 'A'); mvaddch(tp.t_pos.y, tp.t_pos.x, ch); } msg(choose_str("heavy! That's a nasty critter!", "wait! That's a xeroc!")); if (!thrown) { return(false); } } mname = set_mname(tp); did_hit = false; has_hit = (terse && !to_death); if (roll_em(player, tp, weap, thrown)) { did_hit = false; if (thrown) { thunk(weap, mname, terse); } else { hit(null, mname, terse); } if (on(player, CANHUH)) { did_hit = true; tp.t_flags |= ISHUH; player.t_flags &= ~CANHUH; endmsg(); has_hit = false; msg("your hands stop glowing {0}", pick_color("red")); } if (tp.t_stats.s_hpt <= 0) { killed(tp, true); } else if (did_hit && !on(player, ISBLIND)) { msg("{0} appears confused", mname); } did_hit = true; } else if (thrown) { bounce(weap, mname, terse); } else { miss(null, mname, terse); } return(did_hit); }
// Returns true if an object radiates magic bool is_magic(THING obj) { switch (obj.o_type) { case ARMOR: return (bool)(((obj.o_flags & ISPROT) != 0) || obj.o_arm != a_class[obj.o_which]); case WEAPON: return (bool)(obj.o_hplus != 0 || obj.o_dplus != 0); case POTION: case SCROLL: case STICK: case RING: case AMULET: return true; } return false; }
// Quaff a potion from the pack public static void Quaff(THING t) { S.Log("Quaffing " + Item.GetDescription(t) + " (unfinished method)"); //THING obj, tp, mp; //bool show, trip; //obj = get_item("quaff", POTION); ///* // * Make certain that it is somethings that we want to drink // */ //if (obj == null) // return; //if (obj.ItemType != POTION) //{ // if (!Agent.Terse) // AddToLog("yuk! Why would you want to drink that?"); // else // AddToLog("that's undrinkable"); // return; //} //if (obj == CurrWeapon) // CurrWeapon = null; ///* // * Calculate the effect it has on the poor guy. // */ //trip = on(Agent.Plyr, Mob.IsTrippinBalls); //discardit = (bool)(obj.Count == 1); //leave_pack(obj, false, false); //switch (obj.Which) //{ // case P_CONFUSE: // do_pot(P_CONFUSE, !trip); // break; // case P_POISON: // pot_info[P_POISON].oi_know = true; // if (ISWEARING(R_SUSTSTR)) // AddToLog("you feel momentarily sick"); // else // { // ModifyStrength(-(rnd(3) + 1)); // AddToLog("you feel very sick now"); // come_down(0); // } // break; // case P_HEALING: // pot_info[P_HEALING].oi_know = true; // if ((pstats.Hp += RollDice(pstats.Level, 4)) > max_hp) // pstats.Hp = ++max_hp; // sight(0); // AddToLog("you begin to feel better"); // break; // case P_STRENGTH: // pot_info[P_STRENGTH].oi_know = true; // ModifyStrength(1); // AddToLog("you feel stronger, now. What bulging muscles!"); // break; // case P_MFIND: // player.t_flags |= CanSeeInvisible; // LightFuse(turn_see_fuse, 1, HUHDURATION, AFTER); // if (!turn_see(0)) // AddToLog("you have a {0} feeling for a moment, then it passes", // choose_str("normal", "strange")); // break; // case P_TFIND: // /* // * Potion of magic detection. Show the potions and scrolls // */ // show = false; // if (ItemList != null) // { // R12.wclear(hw); // for (tp = ItemList; tp != null; tp = next(tp)) // { // if (Item.IsMagic(tp)) // { // show = true; // R12.wmove(hw, tp.ItemPos.y, tp.ItemPos.x); // R12.waddch(hw, MAGIC); // pot_info[P_TFIND].oi_know = true; // } // } // for (mp = MobList; mp != null; mp = next(mp)) // { // for (tp = mp.Pack; tp != null; tp = next(tp)) // { // if (Item.IsMagic(tp)) // { // show = true; // R12.wmove(hw, mp.t_pos.y, mp.t_pos.x); // R12.waddch(hw, MAGIC); // } // } // } // } // if (show) // { // pot_info[P_TFIND].oi_know = true; // show_win("You sense the presence of magic on this level.--More--"); // } // else // AddToLog("you have a {0} feeling for a moment, then it passes", // choose_str("normal", "strange")); // break; // case P_LSD: // if (!trip) // { // if (on(player, CanSeeInvisible)) // turn_see(0); // start_daemon(visuals, 0, BEFORE); // seenstairs = seen_stairs(); // } // do_pot(P_LSD, true); // break; // case P_SEEINVIS: // show = on(player, CANSEE); // do_pot(P_SEEINVIS, false); // if (!show) // invis_on(); // sight(0); // break; // case P_RAISE: // pot_info[P_RAISE].oi_know = true; // AddToLog("you suddenly feel much more skillful"); // raise_level(); // break; // case P_XHEAL: // pot_info[P_XHEAL].oi_know = true; // if ((pstats.Hp += RollDice(pstats.Level, 8)) > max_hp) // { // if (pstats.Hp > max_hp + pstats.Level + 1) // ++max_hp; // pstats.Hp = ++max_hp; // } // sight(0); // come_down(0); // AddToLog("you begin to feel much better"); // break; // case P_HASTE: // pot_info[P_HASTE].oi_know = true; // after = false; // if (add_haste(true)) // AddToLog("you feel yourself moving much faster"); // break; // case P_RESTORE: // if (ISRING(LEFT, R_ADDSTR)) // add_str(ref pstats.Str, -cur_ring[LEFT].Ac); // if (ISRING(RIGHT, R_ADDSTR)) // add_str(ref pstats.Str, -cur_ring[RIGHT].Ac); // if (pstats.Str < max_stats.Str) // pstats.Str = max_stats.Str; // if (ISRING(LEFT, R_ADDSTR)) // add_str(ref pstats.Str, cur_ring[LEFT].Ac); // if (ISRING(RIGHT, R_ADDSTR)) // add_str(ref pstats.Str, cur_ring[RIGHT].Ac); // AddToLog("hey, this tastes great. It make you feel warm all over"); // break; // case P_BLIND: // do_pot(P_BLIND, true); // break; // case P_LEVIT: // do_pot(P_LEVIT, true); // break; //} //display___status(); ///* // * Throw the item away // */ //UpdateGuess(pot_info[obj.Which]); return; }
// Does the missile hit the monster? bool hit_monster(int y, int x, THING obj) { coord mp = new coord(); mp.y = y; mp.x = x; return fight(mp, obj, true); }
// Free up an item void discard(THING item) { }
// Roll several attacks bool roll_em(THING thatt, THING thdef, THING weap, bool hurl) { stats att, def; string cp; int ndice, nsides, def_arm; bool did_hit = false; int hplus; int dplus; int damage; att = thatt.t_stats; def = thdef.t_stats; if (weap == null) { cp = att.s_dmg; dplus = 0; hplus = 0; } else { hplus = (weap == null ? 0 : weap.o_hplus); dplus = (weap == null ? 0 : weap.o_dplus); if (weap == cur_weapon) { if (ISRING(LEFT, R_ADDDAM)) { dplus += cur_ring[LEFT].o_arm; } else if (ISRING(LEFT, R_ADDHIT)) { hplus += cur_ring[LEFT].o_arm; } if (ISRING(RIGHT, R_ADDDAM)) { dplus += cur_ring[RIGHT].o_arm; } else if (ISRING(RIGHT, R_ADDHIT)) { hplus += cur_ring[RIGHT].o_arm; } } cp = weap.o_damage; if (hurl) { if (((weap.o_flags & ISMISL) != 0) && cur_weapon != null && cur_weapon.o_which == weap.o_launch) { cp = weap.o_hurldmg; hplus += cur_weapon.o_hplus; dplus += cur_weapon.o_dplus; } else if (weap.o_launch < 0) { cp = weap.o_hurldmg; } } } /* * If the creature being attacked is not running (alseep or held) * then the attacker gets a plus four bonus to hit. */ if (!on(thdef, ISRUN)) { hplus += 4; } def_arm = def.s_arm; if (def == pstats) { if (cur_armor != null) { def_arm = cur_armor.o_arm; } if (ISRING(LEFT, R_PROTECT)) { def_arm -= cur_ring[LEFT].o_arm; } if (ISRING(RIGHT, R_PROTECT)) { def_arm -= cur_ring[RIGHT].o_arm; } } int i = 0; while (!string.IsNullOrEmpty(cp)) { ndice = atoi(cp, i); if ((i = cp.IndexOf('x', i)) == -1) { break; } nsides = atoi(cp, ++i); if (swing(att.s_lvl, def_arm, hplus + str_plus[att.s_str])) { int proll; proll = roll(ndice, nsides); damage = dplus + proll + add_dam[att.s_str]; def.s_hpt -= Math.Max(0, damage); did_hit = true; } if ((i = cp.IndexOf('/', i)) == -1) { break; } i++; } return(did_hit); }
// Pick up an object and add it to the pack. If the argument is // non-null use it as the linked_list pointer instead of gettting // it off the ground. void add_pack(THING obj, bool silent) { THING op, lp; bool from_floor; from_floor = false; if (obj == null) { if ((obj = find_obj(hero.y, hero.x)) == null) { return; } from_floor = true; } /* * Check for and deal with scare monster scrolls */ if (obj.o_type == SCROLL && obj.o_which == S_SCARE) { if ((obj.o_flags & ISFOUND) == ISFOUND) { detach(ref lvl_obj, obj); mvaddch(hero.y, hero.x, floor_ch()); chat(hero.y, hero.x, (proom.r_flags & ISGONE) == ISGONE ? PASSAGE : FLOOR); discard(obj); msg("the scroll turns to dust as you pick it up"); return; } } if (pack == null) { pack = obj; obj.o_packch = pack_char(); inpack++; } else { lp = null; for (op = pack; op != null; op = next(op)) { if (op.o_type != obj.o_type) { lp = op; } else { while (op.o_type == obj.o_type && op.o_which != obj.o_which) { lp = op; if (next(op) == null) { break; } else { op = next(op); } } if (op.o_type == obj.o_type && op.o_which == obj.o_which) { if (ISMULT(op.o_type)) { if (!pack_room(from_floor, obj)) { return; } op.o_count++; //dump_it: discard(obj); obj = op; lp = null; goto break_out; } else if (obj.o_group != 0) { lp = op; while (op.o_type == obj.o_type && op.o_which == obj.o_which && op.o_group != obj.o_group) { lp = op; if (next(op) == null) { break; } else { op = next(op); } } if (op.o_type == obj.o_type && op.o_which == obj.o_which && op.o_group == obj.o_group) { op.o_count += obj.o_count; inpack--; if (!pack_room(from_floor, obj)) { return; } //goto dump_it; discard(obj); obj = op; lp = null; goto break_out; } } else { lp = op; } } break_out: break; } } if (lp != null) { if (!pack_room(from_floor, obj)) { return; } else { obj.o_packch = pack_char(); obj.l_next = next(lp); obj.l_prev = lp; if (next(lp) != null) { next(lp).l_prev = obj; } lp.l_next = obj; } } } obj.o_flags |= ISFOUND; /* * If this was the object of something's desire, that monster will * get mad and run at the hero. */ for (op = mlist; op != null; op = next(op)) { if (op.t_dest.Equals(obj.o_pos)) { op.t_dest = hero; } } if (obj.o_type == AMULET) { amulet = true; } /* * Notify the user */ if (!silent) { if (!terse) { addmsg("you now have "); } msg("{0} ({1})", inv_name(obj, !terse), obj.o_packch); } }
// See if the object is one of the currently used items bool is_current(THING obj) { if (obj == null) return false; if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT] || obj == cur_ring[RIGHT]) { if (!terse) addmsg("That's already "); msg("in use"); return true; } return false; }
// Return the name of something as it would appear in an // inventory. string inv_name(THING obj, bool drop) { string pb; obj_info op; string sp; int which; pb = ""; which = obj.o_which; switch (obj.o_type) { case POTION: nameit(obj, "potion", p_colors[which], pot_info[which], nullstr); pb = prbuf; break; case RING: nameit(obj, "ring", r_stones[which], ring_info[which], ring_num); pb = prbuf; break; case STICK: nameit(obj, ws_type[which], ws_made[which], ws_info[which], charge_str); pb = prbuf; break; case SCROLL: if (obj.o_count == 1) { pb = "A scroll "; } else { pb = string.Format("{0} scrolls ", obj.o_count); } op = scr_info[which]; if (op.oi_know) { pb += string.Format("of {0}", op.oi_name); } else if (!string.IsNullOrEmpty(op.oi_guess)) { pb += string.Format("called {0}", op.oi_guess); } else { pb += string.Format("titled '{0}'", s_names[which]); } break; case FOOD: if (which == 1) { if (obj.o_count == 1) { pb = string.Format("A{0} {1}", vowelstr(fruit), fruit); } else { pb = string.Format("{0} {1}s", obj.o_count, fruit); } } else if (obj.o_count == 1) { pb = "Some food"; } else { pb = string.Format("{0} rations of food", obj.o_count); } break; case WEAPON: sp = weap_info[which].oi_name; if (obj.o_count > 1) { pb = string.Format("{0} ", obj.o_count); } else { pb = string.Format("A{0} ", vowelstr(sp)); } if ((obj.o_flags & ISKNOW) != 0) { pb += string.Format("{0} {1}", num(obj.o_hplus, obj.o_dplus, WEAPON), sp); } else { pb += sp; } if (obj.o_count > 1) { pb += "s"; } if (obj.o_label != null) { pb += string.Format(" called {0}", obj.o_label); } break; case ARMOR: sp = arm_info[which].oi_name; if ((obj.o_flags & ISKNOW) != 0) { pb = string.Format("{0} {1} [", num(a_class[which] - obj.o_arm, 0, ARMOR), sp); if (!terse) { pb += "protection "; } pb += string.Format("{0}]", 10 - obj.o_arm); } else { pb = sp; } if (obj.o_label != null) { pb += string.Format(" called {0}", obj.o_label); } break; case AMULET: pb = "The Amulet of Yendor"; break; case GOLD: pb = string.Format("{0} Gold pieces", obj.o_goldval); break; } if (inv_describe) { if (obj == cur_armor) { pb += " (being worn)"; } if (obj == cur_weapon) { pb += " (weapon in hand)"; } if (obj == cur_ring[LEFT]) { pb += " (on left hand)"; } else if (obj == cur_ring[RIGHT]) { pb += " (on right hand)"; } } if (drop && char.IsUpper(pb[0])) { pb = pb.Substring(0, 1).ToLower() + pb.Substring(1); } else if (!drop && char.IsUpper(pb[0])) { pb = pb.Substring(0, 1).ToUpper() + pb.Substring(1); } return(pb); }