/** * Apply generation magic to an ego-item. */ void ego_apply_magic(int level) { int i, flag, x; Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag newf = new Bitflag(Object_Flag.SIZE); object_flags(ref flags); /* Extra powers */ if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_SUSTAIN) { Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.SUST); } else if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_RESIST) { Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.HRES); } else if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_POWER) { Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.PROT, Object_Flag.object_flag_type.MISC); } if (ego.xtra != 0) { this.flags.on(get_new_attr(flags, newf)); } /* Apply extra ego bonuses */ to_h += (short)Random.randcalc(ego.to_h, level, aspect.RANDOMISE); to_d += (short)Random.randcalc(ego.to_d, level, aspect.RANDOMISE); to_a += (short)Random.randcalc(ego.to_a, level, aspect.RANDOMISE); /* Apply pvals */ for (i = 0; i < ego.num_pvals; i++) { flags.copy(ego.pval_flags[i]); x = Random.randcalc(ego.pval[i], level, aspect.RANDOMISE); for (flag = flags.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = flags.next(flag + 1)) { add_pval(x, flag); } } /* Apply flags */ this.flags.union(ego.flags); return; }
public Player_State(Player_State state) { speed = state.speed; num_blows = state.num_blows; num_shots = state.num_shots; ammo_mult = state.ammo_mult; ammo_tval = state.ammo_tval; state.stat_add.CopyTo(stat_add, 0); state.stat_ind.CopyTo(stat_ind, 0); state.stat_use.CopyTo(stat_use, 0); state.stat_top.CopyTo(stat_top, 0); dis_ac = state.dis_ac; ac = state.ac; dis_to_a = state.dis_to_a; to_a = state.to_a; to_h = state.to_h; dis_to_h = state.dis_to_h; to_d = state.to_d; dis_to_d = state.dis_to_d; see_infra = state.see_infra; state.skills.CopyTo(skills, 0); noise = state.noise; heavy_wield = state.heavy_wield; /* Heavy weapon */ heavy_shoot = state.heavy_shoot; /* Heavy shooter */ icky_wield = state.icky_wield; /* Icky weapon shooter */ flags.copy(state.flags); }
/** * Match slays in flags against a chosen flag mask * * count is the number of matches * \param flags is the flagset to analyse for matches * \param mask is the flagset against which to test * \param desc[] is the array of descriptions of matching slays - can be null * \param brand[] is the array of descriptions of brands - can be null * \param mult[] is the array of multipliers of those slays - can be null * \param dedup is whether or not to remove duplicates * * desc[], brand[] and mult[] must be >= SL_MAX in size */ //Bitflags were size Object_Flag.SIZE, might be an out param public static int list_slays(Bitflag flags, Bitflag mask, string[] desc, string[] brand, int[] mult, bool dedup) { int i, count = 0; Bitflag f = new Bitflag(Object_Flag.SIZE); /* We are only interested in the flags specified in mask */ f.copy(flags); f.inter(mask); /* Remove "duplicate" flags if desired */ if (dedup) { dedup_slays(ref f); } /* Collect slays */ for (i = 0; i < list.Count(); i++) { Slay s_ptr = list[i]; if (f.has(s_ptr.object_flag.value)) { if (mult != null) { mult[count] = s_ptr.mult; } if (brand != null) { brand[count] = s_ptr.brand; } if (desc != null) { desc[count] = s_ptr.desc; } count++; } } return(count); }
/* * Remove the "bad" spells from a spell list */ static void remove_bad_spells(int m_idx, Bitflag f) { Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Bitflag f2 = new Bitflag(Monster_Spell_Flag.SIZE); Bitflag ai_flags = new Bitflag(Object_Flag.SIZE); int i; uint smart = 0; /* Stupid monsters act randomly */ if (r_ptr.flags.has(Monster_Flag.STUPID.value)) { return; } /* Take working copy of spell flags */ f2.copy(f); /* Don't heal if full */ if (m_ptr.hp >= m_ptr.maxhp) { f2.off(Monster_Spell_Flag.HEAL.value); } /* Don't haste if hasted with time remaining */ if (m_ptr.m_timed[(int)Misc.MON_TMD.FAST] > 10) { f2.off(Monster_Spell_Flag.HASTE.value); } /* Don't teleport to if the player is already next to us */ if (m_ptr.cdis == 1) { f2.off(Monster_Spell_Flag.TELE_TO.value); } /* Update acquired knowledge */ ai_flags.wipe(); if (Option.birth_ai_learn.value) { /* Occasionally forget player status */ if (Random.one_in_(100)) { m_ptr.known_pflags.wipe(); } /* Use the memorized flags */ smart = m_ptr.smart; ai_flags.copy(m_ptr.known_pflags); } /* Cheat if requested */ if (Option.birth_ai_cheat.value) { for (i = 0; i < Object_Flag.MAX.value; i++) { if (Misc.p_ptr.check_state(Object_Flag.list[i], Misc.p_ptr.state.flags)) { ai_flags.on(i); } } if (Misc.p_ptr.msp == 0) { smart |= Misc.SM_IMM_MANA; } } /* Cancel out certain flags based on knowledge */ if (!ai_flags.is_empty()) { throw new NotImplementedException(); //unset_spells(f2, ai_flags, r_ptr); } if ((smart & Misc.SM_IMM_MANA) != 0 && Random.randint0(100) < 50 * (r_ptr.flags.has(Monster_Flag.SMART.value) ? 2 : 1)) { f2.off(Monster_Spell_Flag.DRAIN_MANA.value); } /* use working copy of spell flags */ f.copy(f2); }
/* * Creatures can cast spells, shoot missiles, and breathe. * * Returns "true" if a spell (or whatever) was (successfully) cast. * * XXX XXX XXX This function could use some work, but remember to * keep it as optimized as possible, while retaining generic code. * * Verify the various "blind-ness" checks in the code. * * XXX XXX XXX Note that several effects should really not be "seen" * if the player is blind. * * Perhaps monsters should breathe at locations *near* the player, * since this would allow them to inflict "partial" damage. * * Perhaps smart monsters should decline to use "bolt" spells if * there is a monster in the way, unless they wish to kill it. * * It will not be possible to "correctly" handle the case in which a * monster attempts to attack a location which is thought to contain * the player, but which in fact is nowhere near the player, since this * might induce all sorts of messages about the attack itself, and about * the effects of the attack, which the player might or might not be in * a position to observe. Thus, for simplicity, it is probably best to * only allow "faulty" attacks by a monster if one of the important grids * (probably the initial or final grid) is in fact in view of the player. * It may be necessary to actually prevent spell attacks except when the * monster actually has line of sight to the player. Note that a monster * could be left in a bizarre situation after the player ducked behind a * pillar and then teleported away, for example. * * Note that this function attempts to optimize the use of spells for the * cases in which the monster has no spells, or has spells but cannot use * them, or has spells but they will have no "useful" effect. Note that * this function has been an efficiency bottleneck in the past. * * Note the special "MFLAG_NICE" flag, which prevents a monster from using * any spell attacks until the player has had a single chance to move. */ static bool make_attack_spell(int m_idx) { int chance, thrown_spell, rlev, failrate; Bitflag f = new Bitflag(Monster_Spell_Flag.SIZE); Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Monster_Lore l_ptr = Misc.l_list[m_ptr.r_idx]; //char m_name[80], m_poss[80], ddesc[80]; string m_name, m_poss, ddesc; /* Player position */ int px = Misc.p_ptr.px; int py = Misc.p_ptr.py; /* Extract the blind-ness */ bool blind = (Misc.p_ptr.timed[(int)Timed_Effect.BLIND] != 0 ? true : false); /* Extract the "see-able-ness" */ bool seen = (!blind && m_ptr.ml); /* Assume "normal" target */ bool normal = true; /* Handle "leaving" */ if (Misc.p_ptr.leaving) return false; /* Cannot cast spells when confused */ if (m_ptr.m_timed[(int)Misc.MON_TMD.CONF] != 0) return (false); /* Cannot cast spells when nice */ if ((m_ptr.mflag & Monster_Flag.MFLAG_NICE) != 0) return false; /* Hack -- Extract the spell probability */ chance = (r_ptr.freq_innate + r_ptr.freq_spell) / 2; /* Not allowed to cast spells */ if (chance == 0) return false; /* Only do spells occasionally */ if (Random.randint0(100) >= chance) return false; /* Hack -- require projectable player */ if (normal) { /* Check range */ if (m_ptr.cdis > Misc.MAX_RANGE) return false; /* Check path */ if (!Cave.projectable(m_ptr.fy, m_ptr.fx, py, px, Spell.PROJECT_NONE)) return false; } /* Extract the monster level */ rlev = ((r_ptr.level >= 1) ? r_ptr.level : 1); /* Extract the racial spell flags */ f.copy(r_ptr.spell_flags); /* Allow "desperate" spells */ if (r_ptr.flags.has(Monster_Flag.SMART.value) && m_ptr.hp < m_ptr.maxhp / 10 && Random.randint0(100) < 50){ throw new NotImplementedException(); ///* Require intelligent spells */ //set_spells(f, RST_HASTE | RST_ANNOY | RST_ESCAPE | RST_HEAL | RST_TACTIC | RST_SUMMON); } /* Remove the "ineffective" spells */ remove_bad_spells(m_idx, f); /* Check whether summons and bolts are worth it. */ if (!r_ptr.flags.has(Monster_Flag.STUPID.value)) { /* Check for a clean bolt shot */ if (Monster_Spell_Flag.test_spells(f, Monster_Spell_Flag.mon_spell_type.RST_BOLT) && !clean_shot(m_ptr.fy, m_ptr.fx, py, px)) /* Remove spells that will only hurt friends */ Monster_Spell_Flag.set_spells(f, ~Monster_Spell_Flag.mon_spell_type.RST_BOLT); /* Check for a possible summon */ if (!(summon_possible(m_ptr.fy, m_ptr.fx))) /* Remove summoning spells */ Monster_Spell_Flag.set_spells(f, ~Monster_Spell_Flag.mon_spell_type.RST_SUMMON); } /* No spells left */ if (f.is_empty()) return false; /* Get the monster name (or "it") */ m_name = m_ptr.monster_desc(0x00); //Nick: Capatilize the first letter. m_name = Char.ToUpper(m_name[0]) + m_name.Substring(1); /* Get the monster possessive ("his"/"her"/"its") */ m_poss = m_ptr.monster_desc(Desc.PRO2 | Desc.POSS); /* Get the "died from" name */ ddesc = m_ptr.monster_desc(Desc.SHOW | Desc.IND2); /* Choose a spell to cast */ thrown_spell = choose_attack_spell(m_idx, f); /* Abort if no spell was chosen */ if (thrown_spell == 0) return false; /* If we see an unaware monster try to cast a spell, become aware of it */ if (m_ptr.unaware) become_aware(m_idx); /* Calculate spell failure rate */ failrate = 25 - (rlev + 3) / 4; if (m_ptr.m_timed[(int)Misc.MON_TMD.FEAR] != 0) failrate += 20; /* Stupid monsters will never fail (for jellies and such) */ if (Option.birth_ai_smart.value || r_ptr.flags.has(Monster_Flag.STUPID.value)) failrate = 0; /* Check for spell failure (innate attacks never fail) */ if ((thrown_spell >= Monster_Spell_Flag.MIN_NONINNATE_SPELL) && (Random.randint0(100) < failrate)) { /* Message */ Utilities.msg("{0} tries to cast a spell, but fails.", m_name); return true; } /* Cast the spell. */ Cave.disturb(Misc.p_ptr, 1, 0); /* Special case RSF_HASTE until TMD_* and MON_TMD_* are rationalised */ if (thrown_spell == Monster_Spell_Flag.HASTE.value) { if (blind) Utilities.msg("{0} mumbles.", m_name); else Utilities.msg("{0} concentrates on {1} body.", m_name, m_poss); mon_inc_timed(m_idx, Misc.MON_TMD.FAST, 50, 0, false); } else Monster_Spell_Flag.do_mon_spell(thrown_spell, m_idx, seen); /* Remember what the monster did to us */ if (seen) { l_ptr.spell_flags.on(thrown_spell); /* Innate spell */ if (thrown_spell < Monster_Spell_Flag.MIN_NONINNATE_SPELL) { if (l_ptr.cast_innate < byte.MaxValue) l_ptr.cast_innate++; } else { /* Bolt or Ball, or Special spell */ if (l_ptr.cast_spell < byte.MaxValue) l_ptr.cast_spell++; } } /* Always take note of monsters that kill you */ if (Misc.p_ptr.is_dead && (l_ptr.deaths < short.MaxValue)) { l_ptr.deaths++; } /* A spell was cast */ return true; }
/** * Wipe an object clean and make it a standard object of the specified kind. * Was previous "object_prep", is now a constructor for Object */ public void prep(Object_Kind k, int lev, aspect rand_aspect) { int flag, x; Bitflag flags = new Bitflag(Object_Flag.SIZE); // Assign the kind and copy across data this.kind = k; this.tval = k.tval; this.sval = k.sval; this.ac = k.ac; this.dd = k.dd; this.ds = k.ds; this.weight = k.weight; // Default number this.number = 1; for(int i = 0; i < pval_flags.Length; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } // Apply pvals and then copy flags for (int i = 0; i < k.num_pvals; i++) { flags.copy(k.pval_flags[i]); flags.copy(k.pval_flags[i]); x = Random.randcalc(k.pval[i], lev, rand_aspect); for (flag = flags.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = flags.next(flag + 1)) add_pval(x, flag); } if(k.Base != null) { flags.copy(k.Base.flags); } flags.union(k.flags); // Assign charges (wands/staves only) if (tval == TVal.TV_WAND || tval == TVal.TV_STAFF) pval[Misc.DEFAULT_PVAL] = (short)Random.randcalc(k.charge, lev, rand_aspect); // Assign flagless pval for food or oil if (tval == TVal.TV_FOOD || tval == TVal.TV_POTION || tval == TVal.TV_FLASK) pval[Misc.DEFAULT_PVAL] = (short)Random.randcalc(k.pval[Misc.DEFAULT_PVAL], lev, rand_aspect); // Default fuel for lamps if (tval == TVal.TV_LIGHT) { if(sval == SVal.SV_LIGHT_TORCH) timeout = Misc.DEFAULT_TORCH; else if(sval == SVal.SV_LIGHT_LANTERN) timeout = Misc.DEFAULT_LAMP; } // Default magic to_h = (short)Random.randcalc(k.to_h, lev, rand_aspect); to_d = (short)Random.randcalc(k.to_d, lev, rand_aspect); to_a = (short)Random.randcalc(k.to_a, lev, rand_aspect); }
/* * Obtain the flags for an item */ public void object_flags(ref Bitflag flags) { flags.wipe(); if (kind == null) return; flags.copy(this.flags); }
/** * Calculate the rating for a given slay combination */ int slay_power(bool verbose, StreamWriter log_file, bool known) { Bitflag s_index = new Bitflag(Object_Flag.SIZE); Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); int sv = 0; //uint int i, j; int mult; Slay best_s_ptr = null; Monster_Race r_ptr; Monster.Monster m_ptr; //monster_type monster_type_body; string[] desc = new string[Slay.MAX.value]; // = { 0 }, * string[] brand = new string[Slay.MAX.value]; // = { 0 }; int[] s_mult = new int[Slay.MAX.value]; // = { 0 }; if (known) { object_flags(ref f); } else { object_flags_known(ref f); } /* Combine the slay bytes into an index value, return if there are none */ s_index.copy(f); Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); if (!s_index.is_inter(f2)) { return(Eval.tot_mon_power); } else { s_index.inter(f2); } /* Look in the cache to see if we know this one yet */ sv = Slay.check_slay_cache(s_index); /* If it's cached (or there are no slays), return the value */ if (sv != 0) { //file_putf(log_file, "Slay cache hit\n"); return(sv); } /* * Otherwise we need to calculate the expected average multiplier * for this combination (multiplied by the total number of * monsters, which we'll divide out later). */ for (i = 0; i < Misc.z_info.r_max; i++) { best_s_ptr = null; mult = 1; r_ptr = Misc.r_info[i]; if (r_ptr == null) { continue; } m_ptr = new Monster.Monster(); m_ptr.r_idx = (short)i; /* Find the best multiplier against this monster */ Slay.improve_attack_modifier(this, m_ptr, ref best_s_ptr, false, !known); if (best_s_ptr != null) { mult = best_s_ptr.mult; } /* Add the multiple to sv */ sv += (int)(mult * r_ptr.scaled_power); } /* * To get the expected damage for this weapon, multiply the * average damage from base dice by sv, and divide by the * total number of monsters. */ if (verbose) { /* Write info about the slay combination and multiplier */ //file_putf(log_file, "Slay multiplier for: "); j = Slay.list_slays(s_index, s_index, desc, brand, s_mult, false); //for (i = 0; i < j; i++) { // if (brand[i]) { // file_putf(log_file, brand[i]); // } else { // file_putf(log_file, desc[i]); // } // file_putf(log_file, "x%d ", s_mult[i]); //} //file_putf(log_file, "\nsv is: %d\n", sv); //file_putf(log_file, " and t_m_p is: %d \n", tot_mon_power); //file_putf(log_file, "times 1000 is: %d\n", (1000 * sv) / tot_mon_power); } /* Add to the cache */ if (Slay.fill_slay_cache(s_index, sv)) { //file_putf(log_file, "Added to slay cache\n"); } return(sv); }
/** * Create a cache of slay combinations found on ego items, and the values of * these combinations. This is to speed up slay_power(), which will be called * many times for ego items during the game. * * \param items is the set of ego types from which we are extracting slay * combinations */ public static int create_slay_cache(Ego_Item[] items) { int count = 0; Bitflag cacheme = new Bitflag(Object_Flag.SIZE); Bitflag slay_mask = new Bitflag(Object_Flag.SIZE); /* Build the slay mask */ Object_Flag.create_mask(slay_mask, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); /* Calculate necessary size of slay_cache */ Bitflag[] dupcheck = new Bitflag[Misc.z_info.e_max]; for (int i = 0; i < Misc.z_info.e_max; i++) { dupcheck[i] = new Bitflag(Object_Flag.SIZE); Ego_Item e_ptr = items[i]; //Some items are null... I guess we should just skip them...? //TODO: Find out why they are null, and see if we actually should just skip them... if (e_ptr == null) { continue; } /* Find the slay flags on this ego */ cacheme.copy(e_ptr.flags); cacheme.inter(slay_mask); /* Only consider non-empty combinations of slay flags */ if (!cacheme.is_empty()) { /* Skip previously scanned combinations */ for (int j = 0; j < i; j++) { if (cacheme.is_equal(dupcheck[j])) { continue; } } /* msg("Found a new slay combo on an ego item"); */ count++; dupcheck[i].copy(cacheme); } } /* Allocate slay_cache with an extra empty element for an iteration stop */ slay_cache = new flag_cache[count + 1]; count = 0; /* Populate the slay_cache */ for (int i = 0; i < Misc.z_info.e_max; i++) { if (!dupcheck[i].is_empty()) { slay_cache[count] = new flag_cache(); slay_cache[count].flags.copy(dupcheck[i]); slay_cache[count].value = 0; count++; /*msg("Cached a slay combination");*/ } } //From a time without garbage collection... /*for (i = 0; i < z_info.e_max; i++) * FREE(dupcheck[i]); * FREE(dupcheck);*/ /* Success */ return(0); }
/* * Remove the "bad" spells from a spell list */ static void remove_bad_spells(int m_idx, Bitflag f) { Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Bitflag f2 = new Bitflag(Monster_Spell_Flag.SIZE); Bitflag ai_flags = new Bitflag(Object_Flag.SIZE); int i; uint smart = 0; /* Stupid monsters act randomly */ if (r_ptr.flags.has(Monster_Flag.STUPID.value)) return; /* Take working copy of spell flags */ f2.copy(f); /* Don't heal if full */ if (m_ptr.hp >= m_ptr.maxhp) f2.off(Monster_Spell_Flag.HEAL.value); /* Don't haste if hasted with time remaining */ if (m_ptr.m_timed[(int)Misc.MON_TMD.FAST] > 10) f2.off(Monster_Spell_Flag.HASTE.value); /* Don't teleport to if the player is already next to us */ if (m_ptr.cdis == 1) f2.off(Monster_Spell_Flag.TELE_TO.value); /* Update acquired knowledge */ ai_flags.wipe(); if (Option.birth_ai_learn.value) { /* Occasionally forget player status */ if (Random.one_in_(100)) m_ptr.known_pflags.wipe(); /* Use the memorized flags */ smart = m_ptr.smart; ai_flags.copy(m_ptr.known_pflags); } /* Cheat if requested */ if (Option.birth_ai_cheat.value) { for (i = 0; i < Object_Flag.MAX.value; i++) if (Misc.p_ptr.check_state(Object_Flag.list[i], Misc.p_ptr.state.flags)) ai_flags.on(i); if (Misc.p_ptr.msp == 0) smart |= Misc.SM_IMM_MANA; } /* Cancel out certain flags based on knowledge */ if(!ai_flags.is_empty()) { throw new NotImplementedException(); //unset_spells(f2, ai_flags, r_ptr); } if ((smart & Misc.SM_IMM_MANA) != 0 && Random.randint0(100) < 50 * (r_ptr.flags.has(Monster_Flag.SMART.value) ? 2 : 1)) f2.off(Monster_Spell_Flag.DRAIN_MANA.value); /* use working copy of spell flags */ f.copy(f2); }
/** * Apply generation magic to an ego-item. */ void ego_apply_magic(int level) { int i, flag, x; Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag newf = new Bitflag(Object_Flag.SIZE); object_flags(ref flags); /* Extra powers */ if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_SUSTAIN) Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.SUST); else if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_RESIST) Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.HRES); else if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_POWER) Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.PROT, Object_Flag.object_flag_type.MISC); if (ego.xtra != 0) this.flags.on(get_new_attr(flags, newf)); /* Apply extra ego bonuses */ to_h += (short)Random.randcalc(ego.to_h, level, aspect.RANDOMISE); to_d += (short)Random.randcalc(ego.to_d, level, aspect.RANDOMISE); to_a += (short)Random.randcalc(ego.to_a, level, aspect.RANDOMISE); /* Apply pvals */ for (i = 0; i < ego.num_pvals; i++) { flags.copy(ego.pval_flags[i]); x = Random.randcalc(ego.pval[i], level, aspect.RANDOMISE); for (flag = flags.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = flags.next(flag + 1)) add_pval(x, flag); } /* Apply flags */ this.flags.union(ego.flags); return; }
/** * Calculate the rating for a given slay combination */ int slay_power(bool verbose, StreamWriter log_file, bool known) { Bitflag s_index = new Bitflag(Object_Flag.SIZE); Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); int sv = 0; //uint int i, j; int mult; Slay best_s_ptr = null; Monster_Race r_ptr; Monster.Monster m_ptr; //monster_type monster_type_body; string[] desc = new string[Slay.MAX.value];// = { 0 }, * string[] brand = new string[Slay.MAX.value];// = { 0 }; int[] s_mult = new int[Slay.MAX.value];// = { 0 }; if (known) object_flags(ref f); else object_flags_known(ref f); /* Combine the slay bytes into an index value, return if there are none */ s_index.copy(f); Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); if (!s_index.is_inter(f2)) return Eval.tot_mon_power; else s_index.inter(f2); /* Look in the cache to see if we know this one yet */ sv = Slay.check_slay_cache(s_index); /* If it's cached (or there are no slays), return the value */ if (sv != 0) { //file_putf(log_file, "Slay cache hit\n"); return sv; } /* * Otherwise we need to calculate the expected average multiplier * for this combination (multiplied by the total number of * monsters, which we'll divide out later). */ for (i = 0; i < Misc.z_info.r_max; i++) { best_s_ptr = null; mult = 1; r_ptr = Misc.r_info[i]; if(r_ptr == null) continue; m_ptr = new Monster.Monster(); m_ptr.r_idx = (short)i; /* Find the best multiplier against this monster */ Slay.improve_attack_modifier(this, m_ptr, ref best_s_ptr, false, !known); if (best_s_ptr != null) mult = best_s_ptr.mult; /* Add the multiple to sv */ sv += (int)(mult * r_ptr.scaled_power); } /* * To get the expected damage for this weapon, multiply the * average damage from base dice by sv, and divide by the * total number of monsters. */ if (verbose) { /* Write info about the slay combination and multiplier */ //file_putf(log_file, "Slay multiplier for: "); j = Slay.list_slays(s_index, s_index, desc, brand, s_mult, false); //for (i = 0; i < j; i++) { // if (brand[i]) { // file_putf(log_file, brand[i]); // } else { // file_putf(log_file, desc[i]); // } // file_putf(log_file, "x%d ", s_mult[i]); //} //file_putf(log_file, "\nsv is: %d\n", sv); //file_putf(log_file, " and t_m_p is: %d \n", tot_mon_power); //file_putf(log_file, "times 1000 is: %d\n", (1000 * sv) / tot_mon_power); } /* Add to the cache */ if(Slay.fill_slay_cache(s_index, sv)) { //file_putf(log_file, "Added to slay cache\n"); } return sv; }
/** * Match slays in flags against a chosen flag mask * * count is the number of matches * \param flags is the flagset to analyse for matches * \param mask is the flagset against which to test * \param desc[] is the array of descriptions of matching slays - can be null * \param brand[] is the array of descriptions of brands - can be null * \param mult[] is the array of multipliers of those slays - can be null * \param dedup is whether or not to remove duplicates * * desc[], brand[] and mult[] must be >= SL_MAX in size */ //Bitflags were size Object_Flag.SIZE, might be an out param public static int list_slays(Bitflag flags, Bitflag mask, string[] desc, string[] brand,int[] mult, bool dedup) { int i, count = 0; Bitflag f = new Bitflag(Object_Flag.SIZE); /* We are only interested in the flags specified in mask */ f.copy(flags); f.inter(mask); /* Remove "duplicate" flags if desired */ if (dedup) dedup_slays(ref f); /* Collect slays */ for (i = 0; i < list.Count(); i++) { Slay s_ptr = list[i]; if (f.has(s_ptr.object_flag.value)) { if (mult != null) mult[count] = s_ptr.mult; if (brand != null) brand[count] = s_ptr.brand; if (desc != null) desc[count] = s_ptr.desc; count++; } } return count; }
/** * Create a cache of slay combinations found on ego items, and the values of * these combinations. This is to speed up slay_power(), which will be called * many times for ego items during the game. * * \param items is the set of ego types from which we are extracting slay * combinations */ public static int create_slay_cache(Ego_Item[] items) { int count = 0; Bitflag cacheme = new Bitflag(Object_Flag.SIZE); Bitflag slay_mask = new Bitflag(Object_Flag.SIZE); /* Build the slay mask */ Object_Flag.create_mask(slay_mask, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); /* Calculate necessary size of slay_cache */ Bitflag[] dupcheck = new Bitflag[Misc.z_info.e_max]; for (int i = 0; i < Misc.z_info.e_max; i++) { dupcheck[i] = new Bitflag(Object_Flag.SIZE); Ego_Item e_ptr = items[i]; //Some items are null... I guess we should just skip them...? //TODO: Find out why they are null, and see if we actually should just skip them... if(e_ptr == null) { continue; } /* Find the slay flags on this ego */ cacheme.copy(e_ptr.flags); cacheme.inter(slay_mask); /* Only consider non-empty combinations of slay flags */ if (!cacheme.is_empty()) { /* Skip previously scanned combinations */ for (int j = 0; j < i; j++) if (cacheme.is_equal(dupcheck[j])) continue; /* msg("Found a new slay combo on an ego item"); */ count++; dupcheck[i].copy(cacheme); } } /* Allocate slay_cache with an extra empty element for an iteration stop */ slay_cache = new flag_cache[count + 1]; count = 0; /* Populate the slay_cache */ for (int i = 0; i < Misc.z_info.e_max; i++) { if (!dupcheck[i].is_empty()) { slay_cache[count] = new flag_cache(); slay_cache[count].flags.copy(dupcheck[i]); slay_cache[count].value = 0; count++; /*msg("Cached a slay combination");*/ } } //From a time without garbage collection... /*for (i = 0; i < z_info.e_max; i++) FREE(dupcheck[i]); FREE(dupcheck);*/ /* Success */ return 0; }