// reformatted - Xangis // Immortals can also see a player's skill list now. public static void Skills(CharData ch, string[] str) { if( ch == null ) return; if (ch.IsNPC()) { ch.SendText("&nYou do not need any stinking skills!\r\n"); return; } CharData charData = ch; if (ch.IsImmortal() && str.Length != 0) { charData = ch.GetCharWorld(str[0]); if (!charData) { ch.SendText("No such person.\r\n"); return; } if (charData.IsNPC()) { ch.SendText("NPCs don't have skills!\r\n"); return; } } string text; string output = "&n&+rALL Abilities available for your class.&n\r\n"; output += "&n&+RLv Abilities&n\r\n"; for (int level = 1; level <= Limits.LEVEL_HERO; level++) { bool skill = true; foreach (KeyValuePair<String, Skill> kvp in Skill.SkillList) { if (kvp.Value.ClassAvailability[(int)charData.CharacterClass.ClassNumber] != level) continue; if (skill) { text = String.Format("&+Y{0}&+y:&n", MUDString.PadInt(level, 2)); output += text; skill = false; } else { output += " "; } output += " "; // Show skills as words rather than numbers for non-immortals if (((PC)charData).SkillAptitude.ContainsKey(kvp.Key)) { if (!ch.IsImmortal()) { text = String.Format("&n&+c{0} &+Y{1}&n", MUDString.PadStr(kvp.Key, 20), StringConversion.SkillString(((PC)charData).SkillAptitude[kvp.Key])); } else { text = String.Format("&n&+c{0} &+Y{1}&n", MUDString.PadStr(kvp.Key, 20), ((PC)charData).SkillAptitude[kvp.Key]); } output += text; } else { text = String.Format("&n&+c{0} &+YAvailable at level {1}.&n", MUDString.PadStr(kvp.Key, 20), level); } output += "\r\n"; } } if ((charData.IsClass(CharClass.Names.monk) || charData.IsClass(CharClass.Names.mystic))) { output += "\r\n&+WMonk Skills:&n\r\n"; foreach (KeyValuePair<String, MonkSkill> kvp in Database.MonkSkillList) { if (((PC)charData).SkillAptitude[kvp.Key] != 0) { text = String.Format(" &n&+c{0} &+Y{1}&n\r\n", MUDString.PadStr(kvp.Key, 20), StringConversion.SkillString(((PC)charData).SkillAptitude[kvp.Key])); output += text; } } output += "\r\n"; } ch.SendText(output); return; }
/// <summary> /// Search the local area for food. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Forage(CharData ch, string[] str) { if( ch == null ) return; int indexNumber; Object obj = null; int[] flist = new int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 25 }; if (!ch.InRoom) { ch.SendText("There's no foraging to be done here.\r\n"); return; } if (ch.FlightLevel != 0) { ch.SendText("Right, you're going to find something way up here.\r\n"); return; } int chance = 10 + (ch.GetCurrLuck() / 20); if (ch.IsClass(CharClass.Names.ranger) || ch.IsClass(CharClass.Names.hunter) || ch.IsImmortal()) chance = 75; if (chance < MUDMath.NumberPercent()) { ch.SendText("You don't find anything at all.\r\n"); ch.Wait += 10; return; } ch.Wait += 15; TerrainType sector = ch.InRoom.TerrainType; // TODO: FIXME: Don't use hard-coded item numbers! switch (sector) { default: ch.SendText("Nothing edible could be growing here.\r\n"); return; case TerrainType.field: flist[0] = 80; flist[1] = 84; flist[2] = 86; flist[6] = 91; flist[7] = 80; break; case TerrainType.hills: flist[0] = 82748; flist[1] = 86; flist[2] = 92; flist[6] = 94; break; case TerrainType.underground_wild: flist[0] = 3352; flist[5] = 3352; flist[6] = 7711; flist[1] = 85; flist[2] = 88; flist[7] = 82; flist[8] = 83; break; case TerrainType.swamp: flist[0] = 3352; flist[1] = 88; flist[5] = 94; flist[6] = 83; flist[7] = 89; break; case TerrainType.forest: flist[0] = 2057; flist[1] = 81651; flist[2] = 90; flist[3] = 93; flist[4] = 92; flist[5] = 90; flist[6] = 87; flist[7] = 84; break; } //end switch if (ch.IsClass(CharClass.Names.ranger) || ch.IsClass(CharClass.Names.hunter)) indexNumber = flist[MUDMath.NumberRange(0, 9)]; else indexNumber = flist[MUDMath.NumberRange(0, 4)]; if (indexNumber == 0) { ch.SendText("You find nothing edible.\r\n"); return; } string buf = String.Format("Forage: {0} found index number {1} in room {2}.", ch.Name, indexNumber, ch.InRoom.IndexNumber); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, buf); /* if (fvnum == StaticObjects.OBJECT_NUMBER_SPRING) { //don't allow endless springs for ( obj = ch.in_room.contents; obj; obj = obj.next_content ) { if (obj.pIndexData.vnum == fvnum) { Descriptor._actFlags("You notice the $p&n.", ch, obj, null, Descriptor.MessageTarget.character); return; } } } */ ObjTemplate objTemplate = Database.GetObjTemplate(indexNumber); // Foraging found an object that doesn't exist -- log an error and fail gracefully. if (objTemplate == null) { Log.Error("Forage: invalid object index number " + indexNumber + " in terrain type " + sector + "."); ch.SendText("The area appears to have been picked clean.\r\n"); return; } obj = Database.CreateObject(objTemplate, 1); obj.AddToRoom(ch.InRoom); obj.FlyLevel = 0; if (indexNumber == StaticObjects.OBJECT_NUMBER_SPRING) // give spring a timer; { obj.Timer = 10 + MUDMath.NumberRange(1, 20); } SocketConnection.Act("You find $p&n.", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n forages around and finds $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); return; }
/* * Modified to up the damage and allow for a * chance to stun victim or self * damage = (level) d2, for an average of 75 hp at level 50 * stun damage = (level) d3, for an average of 100 hp at level 50 * Player vs player damage is reduced in damage() */ /// <summary> /// Headbutt. Usable to initiate combat and during combat. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Headbutt(CharData ch, string[] str) { if( ch == null ) return; int chance; int ko; string text; /* Check player's level and class, mobs can use this skill */ if ((!ch.HasSkill("headbutt"))) { ch.SendText("Your skull is much too soft to headbutt anyone.\r\n"); return; } if (ch.IsBlind()) { return; } CharData victim = ch.Fighting; if (str.Length != 0) { if (!(victim = ch.GetCharRoom(str[0])) || victim.CurrentPosition == Position.dead) { ch.SendText("They are nowhere to be seen.\r\n"); return; } } else { if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("You aren't fighting anyone.\r\n"); return; } } /* anti headbutt me code */ if (ch == victim) { ch.SendText("You get dizzy as you ponder the mechanics of headbutting yourself.\r\n"); return; } if (ch.CurrentPosition < Position.fighting) { ch.SendText("You need to stand up to do that.\r\n"); return; } /* Check size of ch vs. victim. */ /* If ch is too small. */ /* Made it 2 sizes */ if (ch.CurrentSize - 2 > victim.CurrentSize) { SocketConnection.Act("You would crush such a small and delicate being with your mass.", ch, null, victim, SocketConnection.MessageTarget.character); return; } /* Ch 2 or more sizes larger than victim => bad! */ if (ch.CurrentSize + 1 < victim.CurrentSize) { SocketConnection.Act("You can't reach their head!", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n slams $s head into your thigh.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n slams $s head into $N's thigh.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.WaitState((Skill.SkillList["headbutt"].Delay * 9) / 10); if (victim.Fighting == null) { Combat.SetFighting(victim, ch); } return; } ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["headbutt"].Delay)); ch.PracticeSkill("headbutt"); if (!ch.Fighting) { Combat.SetFighting(ch, victim); } if (!victim.Fighting) { Combat.SetFighting(victim, ch); } /* Added a PC skill level */ // Chance was over-downgraded at some point. Was skill level - 5%, // then it was changed to skill level / 2 giving a level 50 a headbutt // success rate of about 47%. I've upped it to 4/5 of skill level, // meaning that a level 50 has a success rate of 76%, which is a good // target success rate. Keep in mind minotaur will have a success rate of // about 83%. if (ch.IsNPC()) { chance = 50 + ch.Level; } else { chance = ((PC)ch).SkillAptitude["headbutt"] * 4 / 5; } // Minotaur headbutt bonus if (ch.GetRace() == Race.RACE_MINOTAUR) { chance += 7; } if (victim.CurrentPosition < Position.fighting) { chance /= 3; } if (MUDMath.NumberPercent() < chance) /* Headbutt successful, possible KO */ { /* First give the victim a chance to dodge */ if (Combat.CheckDodge(ch, victim)) { return; } /* OK, lets settle for stun right now * a skill level of 100% has a 20% chance of stun * a skill level of 50% has a 2.5% chance of stun * a skill level of 23% has a 1% chance of stun * immortals get a 15% bonus */ // The stun math was bad. Stun was way more often that it should have // been. Now we have a flat /4 chance, meaning a the following stun chances // at each skill level: // 25 = 5% 50 = 10 % 75 = 15% 95 = 19% ko = chance / 4; if (ch.IsImmortal()) { ko += 15; } text = String.Format("Commandheadbutt: {0}&n attempting a KO with {1}%% chance.", ch.Name, ko); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, text); if (MUDMath.NumberPercent() < ko + 1) { // deal some decent damage // This was previously level d 3 which was fairly pathetic. // Level d 8 = 50 min, 400 max at level 50 with an average of 225 // PvP damage is quartered, so headbutt will do about 56 against a player. if (ch.GetRace() != Race.RACE_MINOTAUR) { Combat.InflictDamage(ch, victim, MUDMath.Dice(ch.Level, 8), "headbutt", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } else { Combat.InflictDamage(ch, victim, MUDMath.Dice(ch.Level, 9), "headbutt", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } if (victim.CurrentPosition > Position.stunned) { SocketConnection.Act("$n&n staggers about, then collapses in a heap.", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("You fall to the ground &+Wstunned&n.\r\n"); SocketConnection.Act("$n&n is &+Wstunned!&n", victim, null, null, SocketConnection.MessageTarget.room); victim.CurrentPosition = Position.stunned; victim.WaitState((Skill.SkillList["headbutt"].Delay)); text = String.Format("Commandheadbutt: {0}&n stunned {1}&n.", ch.Name, victim.Name); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, text); } } else { // just your ordinary headbutt damage // This was previously level d 2 which was fairly pathetic. // Level d 6 = 50 min, 300 max at level 50 with an average of 175 // PvP damage is quartered, so headbutt will do about 43 against a player. if (ch.GetRace() != Race.RACE_MINOTAUR) { if (!Combat.InflictDamage(ch, victim, MUDMath.Dice(ch.Level, 6), "headbutt", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon)) { // Someone blasts you in the head it'll definitely stun you for 3/4 of a second. victim.WaitState(3); } } else { if (!Combat.InflictDamage(ch, victim, MUDMath.Dice(ch.Level, 7), "headbutt", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon)) { // Someone blasts you in the head with horns it'll definitely stun you for a second. // -- Xangis victim.WaitState(4); } } } } else /* Headbutt failed, possible damgage to self, possible KO of self */ { /* Don't allow char to kill self, just mort self */ /* Give them a chance to not take any damage */ // Checking chance instead of player's level. Since this should be based on skill // this should be about right (average of 24% chance of screwing yourself at level 50 // instead of 50%, 17% chance for minos). if (MUDMath.NumberPercent() < chance) { ch.SendText("Your headbutt fails to strike its target.\r\n"); SocketConnection.Act("$n&n tries to headbutt $N&n but can't quite connect.", ch, null, victim, SocketConnection.MessageTarget.everyone_but_victim); SocketConnection.Act("$n&n bobs around you in a feeble attempt at a headbutt.", ch, null, victim, SocketConnection.MessageTarget.victim); return; } SocketConnection.Act("You bang your head against the brick wall of $N&n.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n tries a headbutt but $N&n gets the best of $m.", ch, null, victim, SocketConnection.MessageTarget.everyone_but_victim); SocketConnection.Act("$n&n bangs into you in a feeble attempt at a headbutt.", ch, null, victim, SocketConnection.MessageTarget.victim); // KO chance of 24% for normals, 17% for minos. // You have to fail three checks to get your ass kicked by KO, one for the actual skill check, // one for the damage check and finally one for the KO check. // keep in mind this KO does damage of about 100 to self at level 50, which is a hell of a lot // for a failed skill. // The chance of ko'ing yourself at each skill level is as follows: (after all 3 checks) // Skill 25 = 59.2% Skill 50 = 29.6% Skill 75 = 14.4% Skill 95 = 9.38% ko = 108 - chance; int dam; if (MUDMath.NumberPercent() < ko) { // doh! This is gonna hurt //deal some decent damage...to self! if (ch.GetRace() != Race.RACE_MINOTAUR) { dam = MUDMath.Dice(ch.Level, 3); } else { dam = MUDMath.Dice(ch.Level, 2); } if (dam > ch.Hitpoints) { dam = ch.Hitpoints + 1; } if (Combat.InflictDamage(ch, ch, dam, "headbutt", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon)) { // ch invalidated, can't send messages. return; } SocketConnection.Act("$n&n staggers about, then collapses in a heap.", ch, null, null, SocketConnection.MessageTarget.room); ch.SendText("You fall to the ground stunned.\r\n"); SocketConnection.Act("$n&n is stunned!", ch, null, null, SocketConnection.MessageTarget.room); ch.CurrentPosition = Position.stunned; ch.WaitState((Skill.SkillList["headbutt"].Delay * 2)); text = String.Format("Commandheadbutt: {0}&n stunned self.", ch.Name); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, text); } else { // Was previously level d 2, which averaged 30 damage at 20 and 75 at 50. PC to PC // damage is not quartered when it is done to yourself, so this it kind of high at the // upper levels. This has been reduced by level / 5, so the damage at 50 averages 65 // instead of 65. // Keep in mind that the real penalties come from KO and comparitively someone that // fails a bash doesen't take insane damage. dam = MUDMath.Dice(ch.Level, 2) - ch.Level / 5; if (dam > ch.Hitpoints) { dam = ch.Hitpoints + 1; } Combat.InflictDamage(ch, ch, dam, "headbutt", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } } //end if() headbutt failed return; }
/// <summary> /// Ingest a liquid. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Drink(CharData ch, string[] str) { if( ch == null ) return; Object obj = null; if (ch.IsBlind()) { return; } if (ch.Fighting || ch.CurrentPosition == Position.fighting) { ch.SendText("You can't drink while you're fighting!\r\n"); return; } if (str.Length == 0 && ch.InRoom != null) { foreach (Object iobj in ch.InRoom.Contents) { if (iobj.ItemType == ObjTemplate.ObjectType.drink_container) { obj = iobj; break; } } if (!obj) { ch.SendText("Drink what?\r\n"); return; } } else { if (!(obj = ch.GetObjHere(str[0]))) { ch.SendText("You can't find it.\r\n"); return; } } // Allow bards to get twice as drunk as other classes - Xangis if (!ch.IsNPC() && !ch.IsImmortal() && ((PC)ch).Drunk > 15 && ch.IsClass(CharClass.Names.bard) && MUDMath.NumberPercent() < ch.GetCurrAgi() - ((PC)ch).Drunk) { ch.SendText("You fail to reach your mouth. *Hic*\r\n"); return; } if (!ch.IsNPC() && !ch.IsImmortal() && ((PC)ch).Drunk > 25 && ch.IsClass(CharClass.Names.bard) && MUDMath.NumberPercent() < ch.GetCurrAgi() - ((PC)ch).Drunk) { ch.SendText("You fail to reach your mouth. *Hic*\r\n"); return; } switch (obj.ItemType) { default: ch.SendText("You can't drink from that.\r\n"); break; case ObjTemplate.ObjectType.drink_container: // -1 Means a container never goes empty. if (obj.Values[1] <= 0 && obj.Values[1] != -1) { ch.SendText("It is already &+Lempty&n.\r\n"); return; } /* No drinking if you're full */ if ((!ch.IsImmortal()) && ( (!ch.IsNPC() && ((PC)ch).Thirst > 40) || (!ch.IsNPC() && ((PC)ch).Hunger > 50))) { ch.SendText("You couldn't possibly drink any more.\r\n"); return; } int liquid; if ((liquid = obj.Values[2]) >= Liquid.Table.Length) { Log.Error("Drink: bad liquid number {0}.", liquid); liquid = obj.Values[2] = 0; } SocketConnection.Act("You drink $T from $p&n.", ch, obj, Liquid.Table[liquid].Name, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n drinks $T from $p&n.", ch, obj, Liquid.Table[liquid].Name, SocketConnection.MessageTarget.room); int amount = MUDMath.NumberRange(3, 10); if (obj.Values[0] != -1) { amount = Math.Min(amount, obj.Values[1]); } ch.AdjustDrunk(amount * Liquid.Table[liquid].DrunkValue); if (!ch.IsUndead()) { ch.AdjustHunger(amount * Liquid.Table[liquid].HungerValue); if (ch.IsAffected(Affect.AFFECT_THIRST)) { ch.AdjustThirst((amount * Liquid.Table[liquid].ThirstValue) / 12); ch.SendText("That doesn't taste as &+bwet&n as it used to.\r\n"); } else { ch.AdjustThirst(amount * Liquid.Table[liquid].ThirstValue); } } else { /* If blood */ if (Liquid.Table[liquid].Name == "blood") { ch.AdjustHunger(amount * 2); ch.AdjustThirst(amount); } } if (!ch.IsNPC() && ((PC)ch).Drunk > 10) { ch.SendText("You feel &n&+gdrunk&n.\r\n"); } if (!ch.IsNPC() && ((PC)ch).Hunger > 20) { ch.SendText("You are &n&+yfull&n.\r\n"); } if (!ch.IsNPC() && ((PC)ch).Thirst > 20) { ch.SendText("You do not feel &n&+cth&+Ci&n&+cr&+Cst&n&+cy&n.\r\n"); } if (obj.Values[3] != 0 && !CharData.CheckImmune(ch, Race.DamageType.poison)) { /* The shit was poisoned ! */ Affect af = new Affect(); ch.SendText("You choke and gag.\r\n"); SocketConnection.Act("$n chokes and gags.", ch, null, null, SocketConnection.MessageTarget.room); af.Type = Affect.AffectType.spell; af.Value = "poison"; af.Duration = 3 * amount; af.AddModifier(Affect.Apply.strength, -(obj.Level / 7 + 1)); af.SetBitvector(Affect.AFFECT_POISON); ch.CombineAffect(af); } /* HOLY_WATER and UNHOLY_WATER effects */ if ((ch.IsGood() && obj.Values[2] == 27) || (ch.IsEvil() && obj.Values[2] == 28)) { int heal = MUDMath.Dice(1, 8); if (ch.Hitpoints < ch.GetMaxHit()) { ch.Hitpoints = Math.Min(ch.Hitpoints + heal, ch.GetMaxHit()); ch.UpdatePosition(); ch.SendText("You feel a little better!\r\n"); } } if ((ch.IsEvil() && obj.Values[2] == 27) || (ch.IsGood() && obj.Values[2] == 28)) { int harm = MUDMath.Dice(1, 10); ch.Hitpoints = Math.Max(ch.Hitpoints - harm, -10); ch.SendText("You choke and feel as if you'd swallowed boiling oil!\r\n"); ch.UpdatePosition(); } /* End (UN)HOLY_WATER effects */ // -1 Means a container never goes empty. if (obj.Values[1] != -1) { obj.Values[1] -= amount; if (obj.Values[1] <= 0) { ch.SendText("The container is now &+Lempty&n.\r\n"); obj.Values[1] = 0; } } break; } return; }
/// <summary> /// Shows a character's attribute screen. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Attributes(CharData ch, string[] str) { if( ch == null ) return; string buf1 = String.Empty; if (ch.IsNPC()) { ch.SendText("&nYour attributes are as would be expected for an NPC.\r\n"); return; } if (ch.IsImmortal() && str.Length != 0) { CharData worldChar = ch.GetCharWorld(str[0]); if (!worldChar) { ch.SendText("No such person.\r\n"); return; } if (worldChar.IsNPC()) { ch.SendText("NPCs don't have skills!\r\n"); return; } } string buf = String.Format( "&+WName: &+G{0}&n &+WLevel: {1}&n\r\n", MUDString.PadStr(ch.Name, 17), ch.Level); buf1 += buf; buf = String.Format( "&+WRace:&n {0} &+WClass:&n {1} &n&+WSex:&n {2}\r\n", MUDString.PadStr(Race.RaceList[ch.GetRace()].ColorName, 16), MUDString.PadStr(ch.CharacterClass.WholistName, 16), System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(ch.GetSexString())); buf1 += buf; // Break a player's size into strings when we get around to it // -- Xangis if (!ch.IsNPC()) { buf = String.Format( "&+WHeight:&n {0} inches &+WWeight:&n {1} pounds &+WSize:&n {2}\r\n", MUDString.PadInt(((PC)ch).Height, 3), MUDString.PadInt(((PC)ch).Weight, 5), Race.SizeString(ch.CurrentSize)); } else { buf = String.Format("&+WSize:&n {0}\r\n", ch.CurrentSize); } buf1 += buf; TimeSpan time = TimeSpan.FromTicks(ch.TimePlayed.Ticks) + (DateTime.Now - ch.LogonTime); int days = (int)time.TotalHours / 24; time = (time - TimeSpan.FromDays(days)); int hours = (int)time.TotalHours; time = (time - TimeSpan.FromHours(hours)); int minutes = (int)time.TotalMinutes; // Age is a hack until we get it coded - Xangis buf = String.Format( "\r\n&+BAge:&n {0} years. &+BPlaying Time:&n {1} days {2} hours {3} minutes.\r\n", MUDString.PadInt(ch.GetAge(), 3), days, hours, minutes); buf1 += buf; // Need to create a function to display character status strings buf = String.Format("&+BStatus:&n {0}", System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(Position.PositionString(ch.CurrentPosition))); if (!ch.IsNPC() && ch.IsAffected(Affect.AFFECT_BERZERK)) { buf += ", &+Rberzerk&n"; } if (!ch.IsNPC() && ch.HasActionBit(PC.PLAYER_MEMORIZING)) { buf += ", Memorizing"; } if (ch.IsAffected(Affect.AFFECT_CASTING)) { buf += ", Casting"; } if (ch.IsAffected(Affect.AFFECT_SINGING)) { buf += ", Singing"; } if (!ch.IsNPC() && ch.HasActionBit(PC.PLAYER_MEDITATING)) { buf += ", Meditating"; } if (!ch.IsNPC() && ch.HasActionBit(PC.PLAYER_CAMPING)) { /* This is ugly and should be moved to its own function */ buf += ", Camping"; } buf += ".\r\n\r\n"; buf1 += buf; // We want players to see the same stats for levels 1-50. // Should create string converters so that we have no decimals displayed // below this point. buf = String.Format(" &+cSTR:&n {0} &+cArmor Class:&n {1}.\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrStr()), 15), ch.GetAC()); buf1 += buf; buf = String.Format(" &+cAGI:&n {0} &+cHitroll:&n {1}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrAgi()), 15), StringConversion.BonusString(ch.GetHitroll(ObjTemplate.WearLocation.hand_one))); buf1 += buf; buf = String.Format(" &+cDEX:&n {0} &+cDamroll:&n {1}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrDex()), 15), StringConversion.BonusString(ch.GetDamroll(ObjTemplate.WearLocation.hand_one))); buf1 += buf; buf = String.Format(" &+cCON:&n {0} &+cAlignment:&n {1}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrCon()), 15), StringConversion.AlignmentString(ch)); buf1 += buf; buf = String.Format(" &n&+cINT:&n {0}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrInt()), 15)); buf1 += buf; buf = String.Format(" &+cWIS:&n {0} &+BSaving Throws&n\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrWis()), 15)); buf1 += buf; buf = String.Format(" &+cPOW:&n {0} &+cParalysis:&n {1}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrPow()), 15), StringConversion.BonusString(-ch.SavingThrows[0])); buf1 += buf; buf = String.Format(" &+cCHA:&n {0} &+cRod:&n {1}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrCha()), 15), StringConversion.BonusString(-ch.SavingThrows[1])); buf1 += buf; buf = String.Format(" &+cLUK:&n {0} &+cPetrify:&n {1}\r\n", MUDString.PadStr(StringConversion.AbilityScoreString(ch.GetCurrLuck()), 15), StringConversion.BonusString(-ch.SavingThrows[2])); buf1 += buf; buf = String.Format(" &+cBreath:&n {0}\r\n", StringConversion.BonusString(-ch.SavingThrows[3])); buf1 += buf; buf = String.Format("&+BWimpy: &n{0} &+cSpell:&n {1}\r\n", MUDString.PadInt(ch.Wimpy, 4), StringConversion.BonusString(-ch.SavingThrows[4])); buf1 += buf; buf = String.Format("&+BLoad Carried: &n{0} pounds ({1})\r\n", MUDString.PadInt(ch.CarryWeight, 3), StringConversion.WeightString(ch)); buf1 += buf; ch.SendText(buf1); return; }
public static void CrashBug(CharData ch, string[] str) { if( ch == null ) return; if (str.Length == 0) { ch.SendText("Report what crash bug?\r\n"); return; } string text = String.Join(" ", str); Issue issue = new Issue(); issue.IssueDetail = new IssueEntry(ch.Name, text); issue.OpenedByImmortal = ch.IsImmortal(); issue.IssueType = Issue.Type.bug; issue.IssuePriority = Issue.Priority.highest; if (ch.InRoom != null) { issue.RoomIndexNumber = ch.InRoom.IndexNumber; } Database.IssueList.Add(issue); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_DEBUG, 0, String.Format("New CRASH BUG, issue # {0} created by {1}. Text is:\n{2}", issue.IssueNumber, ch.Name, text)); Issue.Save(); ch.SendText("Crash bug report recorded. Thank you.\r\n"); return; }
/// <summary> /// Knock a door from its hinges with brute force. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void DoorBash(CharData ch, string[] str) { if( ch == null ) return; Exit.Direction door; Room toRoom; if (ch.IsNPC() || (!ch.HasSkill("doorbash") && !ch.HasInnate(Race.RACE_DOORBASH))) { ch.SendText("You don't feel massive enough!\r\n"); return; } if (str.Length == 0) { ch.SendText("Doorbash what?\r\n"); return; } if (ch.Fighting) { ch.SendText("You can't break off your fight.\r\n"); return; } if ((door = Movement.FindDoor(ch, str[0])) >= 0) { Exit reverseExit; int chance; Exit exit = ch.InRoom.GetExit(door); if (!exit.HasFlag(Exit.ExitFlag.closed)) { ch.SendText("Calm down. It is already open.\r\n"); return; } ch.WaitState(Skill.SkillList["doorbash"].Delay); if (ch.IsNPC()) { chance = 0; } else if (!ch.HasSkill("doorbash")) { chance = 20; } else { chance = ((PC)ch).SkillAptitude["doorbash"] / 2; } if (exit.HasFlag(Exit.ExitFlag.locked)) { chance /= 2; } if (exit.HasFlag(Exit.ExitFlag.bashproof) && !ch.IsImmortal()) { SocketConnection.Act("WHAAAAM!!! You bash against the $d, but it doesn't budge.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); SocketConnection.Act("WHAAAAM!!! $n&n bashes against the $d, but it holds strong.", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); Combat.InflictDamage(ch, ch, (ch.GetMaxHit() / 20), "doorbash", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); if (exit.HasFlag(Exit.ExitFlag.spiked)) { SocketConnection.Act("You are impaled by spikes protruding from the $d!", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n is impaled by spikes protruding from the $d!", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); Combat.InflictDamage(ch, ch, (ch.GetMaxHit() / 5), "doorbash", ObjTemplate.WearLocation.none, AttackType.DamageType.pierce); } return; } if (exit.HasFlag(Exit.ExitFlag.spiked)) { SocketConnection.Act("You are impaled by spikes protruding from the $d!", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n is impaled by spikes protruding from the $d!", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); Combat.InflictDamage(ch, ch, (ch.GetMaxHit() / 5), "doorbash", ObjTemplate.WearLocation.none, AttackType.DamageType.pierce); } if ((ch.GetCurrStr() >= 20) && MUDMath.NumberPercent() < (chance + 4 * (ch.GetCurrStr() - 20))) { /* Success */ exit.RemoveFlag(Exit.ExitFlag.closed); if (exit.HasFlag(Exit.ExitFlag.locked)) { exit.RemoveFlag(Exit.ExitFlag.locked); } exit.AddFlag(Exit.ExitFlag.bashed); SocketConnection.Act("Crash! You bashed open the $d!", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n bashes open the $d!", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); Combat.InflictDamage(ch, ch, (ch.GetMaxHit() / 30), "doorbash", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); /* Bash through the other side */ if ((toRoom = Room.GetRoom(exit.IndexNumber)) && (reverseExit = toRoom.GetExit(Exit.ReverseDirection(door))) && reverseExit.TargetRoom == ch.InRoom) { reverseExit.RemoveFlag(Exit.ExitFlag.closed); if (reverseExit.HasFlag(Exit.ExitFlag.locked)) { reverseExit.RemoveFlag(Exit.ExitFlag.locked); } reverseExit.AddFlag(Exit.ExitFlag.bashed); foreach (CharData irch in toRoom.People) { SocketConnection.Act("The $d crashes open!", irch, null, reverseExit.Keyword, SocketConnection.MessageTarget.character); } // Have any aggro mobs on the other side come after the player. foreach (CharData charData in toRoom.People) { if (charData != ch && (charData.IsNPC() && !charData.IsAffected( Affect.AFFECT_CHARM)) && charData.IsAggressive(ch) && charData.IsAwake() && CharData.CanSee(charData, ch) && !charData.Fighting) { Combat.StartHating(charData, ch); Combat.StartHunting(charData, ch); } } } } else { /* Failure */ SocketConnection.Act("OW! You bash against the $d, but it doesn't budge.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n bashes against the $d, but it holds strong.", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); Combat.InflictDamage(ch, ch, (ch.GetMaxHit() / 10), "doorbash", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } } /* * Check for "guards"... anyone bashing a door is considered as * a potential aggressor, and there's a 25% chance that mobs * will do unto before being done unto. * But first...let's make sure ch ain't dead? That'd be a pain. */ if (ch.Hitpoints <= 1) return; ch.PracticeSkill("doorbash"); foreach (CharData guardChar in ch.InRoom.People) { if (guardChar != ch && guardChar.HasActionBit(MobTemplate.ACT_PROTECTOR) && (guardChar.IsNPC() && !guardChar.IsAffected( Affect.AFFECT_CHARM)) && guardChar.IsAwake() && CharData.CanSee(guardChar, ch) && !guardChar.Fighting && MUDMath.NumberBits(2) == 0) { SocketConnection.Act("$n&n is very unhappy about you trying to destroy the door.", guardChar, null, ch, SocketConnection.MessageTarget.victim); guardChar.AttackCharacter(ch); } } return; }
/// <summary> /// Capture command - restrain another character. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Capture(CharData ch, string[] str) { if( ch == null ) return; CharData victim; Affect af = new Affect(); /* Check player's level and class, allow mobs to do this too */ if ((!ch.HasSkill("capture"))) { ch.SendText("You couldn't capture a dead rat.\r\n"); return; } if (str.Length == 0) { victim = ch.Fighting; if (!victim) { ch.SendText("Capture whom?\r\n"); return; } } else /* argument supplied */ { victim = ch.GetCharRoom(str[0]); if (!victim) { ch.SendText("They aren't here.\r\n"); return; } } if (ch.Fighting && ch.Fighting != victim) { ch.SendText("Take care of the person you are fighting first!\r\n"); return; } if (!ch.IsImmortal()) { ch.WaitState(Skill.SkillList["capture"].Delay); } Object rope = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_one); if (!rope || rope.ItemType != ObjTemplate.ObjectType.rope) { rope = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_two); if (!rope || rope.ItemType != ObjTemplate.ObjectType.rope) { rope = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_three); if (!rope || rope.ItemType != ObjTemplate.ObjectType.rope) { rope = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_four); if (!rope || rope.ItemType != ObjTemplate.ObjectType.rope) rope = null; } } } if (!rope) { ch.SendText("You must have some rope to tie someone up!\r\n"); return; } rope.RemoveFromWorld(); /* only appropriately skilled PCs and uncharmed mobs */ if ((ch.IsNPC() && !ch.IsAffected( Affect.AFFECT_CHARM)) || (!ch.IsNPC() && MUDMath.NumberPercent() < ((PC)ch).SkillAptitude["capture"] / 4)) { victim.AffectStrip( Affect.AffectType.skill, "capture"); af.Value = "capture"; af.Type = Affect.AffectType.skill; af.Duration = 3 + ((ch.Level) / 8); af.SetBitvector(Affect.AFFECT_BOUND); victim.AddAffect(af); SocketConnection.Act("You have captured $M!", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n has captured you!", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n has captured $N&n.", ch, null, victim, SocketConnection.MessageTarget.everyone_but_victim); } else { SocketConnection.Act("You failed to capture $M. Uh oh!", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n tried to capture you! Get $m!", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n attempted to capture $N&n, but failed!", ch, null, victim, SocketConnection.MessageTarget.everyone_but_victim); } /* go for the one who wanted to fight :) */ if (ch.IsNPC() && ch.IsAffected( Affect.AFFECT_CHARM) && !victim.Fighting) { victim.AttackCharacter(ch.Master); } else if (!victim.Fighting) { victim.AttackCharacter(ch); } return; }
/// <summary> /// Player track command. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void TrackCommand(CharData ch, string[] str) { if( ch == null ) return; CharData victim; if (ch.IsAffected(Affect.AFFECT_TRACK)) { ch.SendText("You stop tracking.\r\n"); Combat.StopHunting(ch); ch.RemoveAffect(Affect.AFFECT_TRACK); return; } if (!ch.HasSkill("track")) { ch.SendText("You couldn't track an &+Lelephant&n in your own bedroom.\r\n"); return; } if (str.Length == 0) { ch.SendText("Whom are you trying to track?\r\n"); return; } if (ch.Riding) { ch.SendText("You can't sniff a trail mounted.\r\n"); return; } if (ch.FlightLevel != 0) { ch.SendText("You find tracks on the _ground_!\r\n"); return; } if (ch.InRoom.IsWater()) { ch.SendText("You can't track through water.\r\n"); return; } if (ch.CurrentPosition != Position.standing) { if (ch.CurrentPosition == Position.fighting) ch.SendText("You're too busy fighting .\r\n"); else ch.SendText("You must be standing to track!\r\n"); return; } /* only imps can hunt to different areas */ bool area = (ch.GetTrust() < Limits.LEVEL_OVERLORD); if (area) { victim = ch.GetCharInArea(str[0]); } else { victim = ch.GetCharWorld(str[0]); } if (!victim || (!victim.IsNPC() && (ch.IsRacewar(victim)) && !ch.IsImmortal())) { ch.SendText("You can't find a trail of anyone like that.\r\n"); return; } if (ch.InRoom == victim.InRoom) { SocketConnection.Act("You're already in $N&n's room!", ch, null, victim, SocketConnection.MessageTarget.character); return; } /* * Deduct some movement. */ if (ch.CurrentMoves > 2) { ch.CurrentMoves -= 3; } else { ch.SendText("You're too exhausted to hunt anyone!\r\n"); return; } SocketConnection.Act("$n carefully sniffs the air.", ch, null, null, SocketConnection.MessageTarget.room); ch.WaitState(Skill.SkillList["track"].Delay); Exit.Direction direction = Track.FindPath(ch.InRoom.IndexNumber, victim.InRoom.IndexNumber, ch, -40000, area); if (direction == Exit.Direction.invalid) { SocketConnection.Act("You can't sense $N&n's trail from here.", ch, null, victim, SocketConnection.MessageTarget.character); return; } /* * Give a random direction if the player misses the die roll. */ if ((ch.IsNPC() && MUDMath.NumberPercent() > 75) /* NPC @ 25% */ || (!ch.IsNPC() && MUDMath.NumberPercent() > /* PC @ norm */ ((PC)ch).SkillAptitude["track"])) { do { direction = Database.RandomDoor(); } while (!(ch.InRoom.ExitData[(int)direction]) || !(ch.InRoom.ExitData[(int)direction].TargetRoom)); } ch.PracticeSkill("track"); /* * Display the results of the search. */ ch.SetAffectBit(Affect.AFFECT_TRACK); string buf = String.Format("You sense $N&n's trail {0} from here...", direction.ToString()); SocketConnection.Act(buf, ch, null, victim, SocketConnection.MessageTarget.character); if (ch.CurrentPosition == Position.standing) { ch.Move(direction); } Combat.StartHunting(ch, victim); return; }
/// <summary> /// Cant language for thieves only. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Cant(CharData ch, string[] str) { if( ch == null ) return; string buf; if (str.Length == 0) { ch.SendText("Cant what?\r\n"); return; } if (!ch.IsClass(CharClass.Names.thief) && !ch.IsImmortal()) { ch.SendText("You speak gibberish.\r\n"); buf = String.Format("$n says, '{0}'\r\n", NounType.RandomSentence()); SocketConnection.Act(buf, ch, null, null, SocketConnection.MessageTarget.room); return; } string text = String.Join(" ", str); // We don't want to let them know they're drunk. SocketConnection.Act("You cant '&n$T&n'", ch, null, text, SocketConnection.MessageTarget.character); text = DrunkSpeech.MakeDrunk(text, ch); string random = NounType.RandomSentence(); foreach (CharData roomChar in ch.InRoom.People) { if (roomChar == ch || roomChar.IsNPC()) continue; if (roomChar.IsImmortal() || roomChar.IsClass(CharClass.Names.thief)) { buf = String.Format("{0} cants '&n$T&n'", ch.ShowNameTo(roomChar, true)); } else { buf = String.Format("{0} says, '{1}'\r\n", ch.ShowNameTo(roomChar, true), random); } SocketConnection.Act(buf, roomChar, null, SocketConnection.TranslateText(text, ch, roomChar), SocketConnection.MessageTarget.character); } return; }
/// <summary> /// Sets a character's title, cropped to a maximum length to avoid word wrap. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Title(CharData ch, string[] str) { if( ch == null ) return; int point; if (!ch || ch.IsNPC()) return; if (str.Length < 2) { ch.SendText("&nChange whose title to what?\r\n"); return; } CharData victim = ch.GetCharWorld(str[0]); if (!victim) { ch.SendText("&nThat person isn't here.\r\n"); return; } if (ch.IsSameGuild(victim) && !ch.IsImmortal()) { /* Officers and deputies can title themselves. */ if (ch == victim && ((PC)ch).GuildRank < Guild.Rank.officer) { ch.SendText("&nThey might not appreciate that.\r\n"); return; } /* Leaders can title others. */ if (ch != victim && ((PC)ch).GuildRank < Guild.Rank.leader) { ch.SendText("You can't do that to another at your rank.\r\n"); return; } } else if (!ch.IsImmortal() || (ch.Level <= victim.Level && ch != victim) || ch.IsNPC() || victim.IsNPC()) { SocketConnection.Act("$N&n might not appreciate that.", ch, null, victim, SocketConnection.MessageTarget.character); return; } string text = String.Join(" ", str, 1, (str.Length - 1)); int length = 0; for (point = 0; point < text.Length; ++point) { if (text[point] == '&') { /* Don't count color codes. */ point++; /* Skip the &n's. */ if (!(text[point] == 'N' || text[point] == 'n')) { /* Skip the &+'s and &-'s. */ if (text[point] == '+' || text[point] == '-') { point++; } else { // Cap title at max length if (++length >= Limits.MAX_TITLE_LENGTH) { text = text.Substring(0, point); break; } } } } else { // Cap title at max length. if (++length >= Limits.MAX_TITLE_LENGTH) { text = text.Substring(0, Limits.MAX_TITLE_LENGTH); break; } } } SetTitle(victim, text); ch.SendText("&nOk.\r\n"); }
/// <summary> /// Direct telepathy-like communication with another individual. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Tell(CharData ch, string[] str) { if( ch == null ) return; if (!ch.CanSpeak()) { ch.SendText("Your lips move but no sound comes out.\r\n"); return; } if (str.Length < 2) { ch.SendText("Tell what to who?\r\n"); return; } /* * PCs can receive a tell anywhere, but NPCs only can only hear them in the same room. * * get PC target first, if fails then get NPC */ CharData victim = ch.GetCharWorld(str[0]); if (!victim || (victim.IsNPC() && victim.InRoom != ch.InRoom)) { ch.SendText("They aren't here.\r\n"); return; } if (victim == ch) { ch.SendText("You listen to your own thoughts. *cricket* *cricket*\r\n"); return; } if ((ch.IsRacewar(victim)) && (!ch.IsImmortal() && !victim.IsImmortal()) && (ch.InRoom != victim.InRoom)) { ch.SendText("They aren't here.\r\n"); return; } /* Can tell to other side of racewar iff the opponent is in the same room or one of the people are Immortals. */ if ((!ch.IsImmortal() && !victim.IsImmortal()) && (ch.IsRacewar(victim)) && (victim.InRoom != ch.InRoom)) { ch.SendText("They aren't here.\r\n"); return; } if ((!ch.IsNPC() && (ch.HasActionBit(PC.PLAYER_SILENCE) || !ch.HasActionBit(PC.PLAYER_TELL) || (!victim.IsNPC() && !victim.HasActionBit(PC.PLAYER_TELL)))) || victim.InRoom.HasFlag(RoomTemplate.ROOM_SILENT)) { ch.SendText("They can't hear you.\r\n"); return; } if (!victim.Socket && !victim.IsNPC()) { SocketConnection.Act("$N&n is &+Llinkdead&n.", ch, null, victim, SocketConnection.MessageTarget.character); return; } if (!ch.IsImmortal() && !victim.IsAwake()) { SocketConnection.Act("$E isn't paying attention.", ch, null, victim, SocketConnection.MessageTarget.character); return; } if (victim.IsIgnoring(ch)) { SocketConnection.Act("$E is ignoring you.", ch, null, victim, SocketConnection.MessageTarget.character); return; } string text = String.Join(" ", str, 1, (str.Length - 1)); text = DrunkSpeech.MakeDrunk(text, ch); int position = victim.CurrentPosition; victim.CurrentPosition = Position.standing; Race.Language lang = ch.IsNPC() ? Race.RaceList[ch.GetOrigRace()].PrimaryLanguage : ((PC)ch).Speaking; if (lang == Race.Language.god || lang == Race.Language.unknown) { text = String.Format("&+WYou tell $N&+W '$t&+W'&n"); } else { text = String.Format("&+WYou tell $N&+W in {0} '$t&+W'&n", Race.LanguageTable[(int)lang]); } SocketConnection.Act(text, ch, text, victim, SocketConnection.MessageTarget.character); if (lang == Race.Language.god || lang == Race.Language.unknown) { text = String.Format("&+W$n&+W tells you '$t&+W'&n"); } else { text = String.Format("&+W$n&+W tells you in {0} '$t&+W'&n", Race.LanguageTable[(int)lang]); } SocketConnection.Act(text, ch, SocketConnection.TranslateText(text, ch, victim), victim, SocketConnection.MessageTarget.victim); victim.CurrentPosition = position; victim.ReplyTo = ch; if (victim.HasActionBit(PC.PLAYER_AFK)) { SocketConnection.Act("Just so you know, $E is &+RAFK&n.", ch, null, victim, SocketConnection.MessageTarget.character); } else if (victim.HasActionBit(PC.PLAYER_BOTTING)) { SocketConnection.Act("Just so you know, $E is a &+YBOT&n", ch, null, victim, SocketConnection.MessageTarget.character); } // players can't have talk files -- go home! Quest stuff. if (!victim.IsNPC()) { return; } bool questfound = false; foreach (QuestTemplate it in QuestTemplate.QuestList) { bool isquest = (ch.IsImmortal() && !MUDString.StringsNotEqual(text, "quest")) ? true : false; if (it.Messages == null || (it.IndexNumber != victim.MobileTemplate.IndexNumber)) continue; foreach (TalkData message in it.Messages) { if (MUDString.NameContainedIn(text, message.Keywords) || isquest) { ch.SendText("\r\n"); ch.SendText(message.Message); questfound = true; } } } // Chatterbot code. Bots won't check if a quest matched (prevents multiple statements). if (!questfound && victim.ChatBot != null) { victim.ChatBot.CheckConversation(victim, ch, text); } return; }
/// <summary> /// Innate mount summoning command for antipaladins and paladins. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void SummonMount(CharData ch, string[] str) { MobTemplate mobTemplate; Affect af = new Affect(); int mountNumber = ch.CharacterClass.CanSummonMountNumber; if (mountNumber == 0) { ch.SendText("You scream and yell for a mount. Strangely nothing comes.\r\n"); return; } if (ch.IsAffected( Affect.AFFECT_SUMMON_MOUNT_TIMER)) { ch.SendText("&nIt is too soon to accomplish that!\r\n"); return; } // Look to see if they already have a mount. foreach (CharData previousMount in Database.CharList) { if (previousMount.Master == ch && previousMount.IsNPC() && previousMount.MobileTemplate != null && (previousMount.MobileTemplate.IndexNumber == mountNumber)) { ch.SendText("You already have a mount!\r\n"); return; } } // If not let found, them summon one. mobTemplate = Database.GetMobTemplate(mountNumber); if (mobTemplate == null) { Log.Error("SummonMount: Invalid MobTemplate!", 0); return; } CharData mount = Database.CreateMobile(mobTemplate); // Simulate the poor mount running across the world. // They arrive with partially depleted moves. mount.CurrentMoves -= MUDMath.Dice(4, 40); CharData.AddFollower(mount, ch); mount.SetAffectBit(Affect.AFFECT_CHARM); mount.SetActionBit(MobTemplate.ACT_NOEXP); mount.AddToRoom(ch.InRoom); ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["summon mount"].Delay)); SocketConnection.Act("$n&n trots up to you.", mount, null, ch, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n trots up to $N&n.", mount, null, ch, SocketConnection.MessageTarget.everyone_but_victim); if (ch.IsImmortal()) { return; } af.Value = "summon mount"; af.Type = Affect.AffectType.skill; af.Duration = 48; af.SetBitvector(Affect.AFFECT_SUMMON_MOUNT_TIMER); ch.AddAffect(af); return; }
/// <summary> /// Steal an object or some coins from a victim. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Steal(CharData ch, string[] str) { if( ch == null ) return; Object obj = null; CharData victim; bool sleeping = false; string arg1 = String.Empty; string arg2 = String.Empty; string arg = String.Empty; int percent; if (!ch.HasSkill("steal") && !ch.IsAffected(Affect.AFFECT_CHARM)) { ch.SendText("Who are you trying to kid? You couldn't steal shoes from a &n&+mbl&+Mo&n&+ma&+Mte&n&+md&n corpse.\r\n"); return; } if (ch.Riding != null) { ch.SendText("You can't do that while mounted.\r\n"); return; } if (String.IsNullOrEmpty(arg1) || String.IsNullOrEmpty(arg2)) { ch.SendText("Steal what from whom?\r\n"); return; } if ((victim = ch.GetCharRoom(arg2)) == null) { ch.SendText("They aren't here.\r\n"); return; } if (victim == ch) { ch.SendText("That's pointless.\r\n"); return; } if (Combat.IsSafe(ch, victim)) return; if (!ch.IsImmortal()) { ch.WaitState(Skill.SkillList["steal"].Delay); } // Justice stuff Crime.CheckThief(ch, victim); if (ch.IsNPC()) { percent = ch.Level * 2; } else { percent = ((PC)ch).SkillAptitude["steal"]; } percent += ch.GetCurrLuck() / 20; /* Luck */ percent -= victim.Level; /* Character level vs victim's */ if (ch.GetRace() == Race.RACE_HALFLING) { // Halflings get a racial bonus percent += 10; } if (victim.IsAffected(Affect.AFFECT_CURSE)) percent += 15; if (ch.IsAffected(Affect.AFFECT_CURSE)) percent -= 15; if (!victim.IsAwake()) percent += 25; /* Sleeping characters are easier */ if (ch.CheckSneak()) percent += 10; /* Quiet characters steal better */ if (!CharData.CanSee(ch, victim)) percent += 10; /* Unseen characters steal better */ if (!MUDString.IsPrefixOf(arg1, "coins")) { percent = (int)(percent * 1.2); /* Cash is fairly easy to steal */ } else { int number = MUDString.NumberArgument(arg1, ref arg); int count = 0; foreach (Object iobj in victim.Carrying) { if (CharData.CanSeeObj(ch, iobj) && MUDString.NameContainedIn(arg, iobj.Name)) { if (++count == number) { obj = iobj; break; } } } if (!obj) { ch.SendText("You can't find it.\r\n"); return; } if (ch.Level < victim.Level) { // stealing from higher level is possible, but harder percent -= 5 * (victim.Level - ch.Level); } else { // slight bonus for mobs lower level percent += (ch.Level - victim.Level); } if (obj.WearLocation == ObjTemplate.WearLocation.none) /* Items worn are harder */ percent = (int)(percent * .8); else percent = (int)(percent * .4); } ch.PracticeSkill("steal"); if (percent > 85) percent = 85; if (percent < 2) percent = 2; if (percent < MUDMath.NumberPercent()) { /* * Failure. */ //strip sneak ch.RemoveAffect(Affect.AFFECT_SNEAK); // chance of removing invis if (ch.IsAffected(Affect.AFFECT_INVISIBLE) && MUDMath.NumberPercent() > percent) { ch.SendText("You really bungled that attempt.\r\n"); ch.RemoveAffect(Affect.AFFECT_INVISIBLE); } else { ch.SendText("Oops.\r\n"); } SocketConnection.Act("$n&n tried to steal from $N&n.", ch, null, victim, SocketConnection.MessageTarget.everyone_but_victim); if (victim.IsAwake()) { SocketConnection.Act("$n&n tried to steal from you!", ch, null, victim, SocketConnection.MessageTarget.victim); } else { sleeping = true; } // Thief flag for justice. // Added so blind mobs dont hit who ever failed steal from em. if (victim.IsNPC()) { if (!sleeping && !victim.IsBlind()) { CommandType.Interpret(victim, "kill " + ch.Name); } } else { if (!victim.IsBlind() && !sleeping && victim.IsAffected(Affect.AFFECT_BERZERK)) { victim.SendText("In your &+Rblood rage&n, you lash out in anger!\r\n"); CommandType.Interpret(victim, "kill " + ch.Name); } } /* if ( !Macros.IS_SET( ch.actflags, PC.PLAYER_THIEF ) ) { Macros.SET_BIT( ref ch.actflags, PC.PLAYER_THIEF ); buf = String.Format( "{0} became a THIEF by stealing from {1}", ch._name, victim._name ); Immtalk.Immtalk( ch, Immtalk.IMMTALK_CRIME, ch.GetTrust(), buf ); CharData.SavePlayer( ch ); } */ // } if (sleeping) { if (MUDMath.NumberPercent() < victim.GetCurrLuck()) { CommandType.Interpret(victim, "wake"); } } return; } //end failure if (!MUDString.IsPrefixOf(arg1, "coins")) { int amount = victim.GetGold() * MUDMath.NumberRange(1, 20) / 100; int amount2 = victim.GetSilver() * MUDMath.NumberRange(1, 20) / 100; int amount3 = victim.GetCopper() * MUDMath.NumberRange(1, 20) / 100; int amount4 = victim.GetPlatinum() * MUDMath.NumberRange(1, 20) / 100; if ((amount + amount2 + amount3 + amount4) <= 0) { ch.SendText("You couldn't get any &n&+wcoins&n.\r\n"); return; } ch.ReceiveGold(amount); ch.ReceiveSilver(amount2); ch.ReceiveCopper(amount3); ch.ReceivePlatinum(amount4); victim.SpendGold(amount); victim.SpendSilver(amount2); victim.SpendCopper(amount3); victim.SpendPlatinum(amount4); string text = String.Format("Success! You got {0} &+Wplatinum&n, {1} &+Ygold&n, {2} silver, and {3} &+ycopper&n.\r\n", amount2, amount3, amount, amount4); ch.SendText(text); return; } if (!ch.CanDropObject(obj) || obj.HasFlag(ObjTemplate.ITEM_INVENTORY)) { ch.SendText("You can't pry it away.\r\n"); return; } if (ch.CarryNumber + 1 > Limits.MAX_CARRY) { ch.SendText("You have your hands full.\r\n"); return; } if (ch.CarryWeight + obj.GetWeight() > ch.MaxCarryWeight()) { ch.SendText("You cannot carry that much weight.\r\n"); return; } if (obj.WearLocation != ObjTemplate.WearLocation.none) { ch.SendText("Very daring, and you got it!\r\n"); victim.UnequipObject(obj); } obj.RemoveFromChar(); obj.ObjToChar(ch); ch.SendText("Nice work.\r\n"); if (obj.Trap != null && obj.Trap.CheckTrigger( Trap.TriggerType.steal)) { ch.SetOffTrap(obj); if (ch.CurrentPosition == Position.dead) { return; } } return; }
/// <summary> /// Command to cast a spell. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Cast(CharData ch, string[] str) { if( ch == null ) return; if ((ch.IsClass(CharClass.Names.psionicist) || ch.IsClass(CharClass.Names.enslaver)) && !ch.IsImmortal()) { ch.SendText("Psionicists use the WILL command to invoke their powers.\r\n"); return; } if (ch.IsClass(CharClass.Names.bard) && !ch.IsImmortal()) { ch.SendText("Bards use the SING or PLAY commands to invoke their powers.\r\n"); return; } if (ch.Riding && ch.InRoom == ch.Riding.InRoom) { ch.SendText("You cannot cast while mounted!\r\n"); return; } if (ch.IsAffected( Affect.AFFECT_MINOR_PARA) || ch.IsAffected( Affect.AFFECT_HOLD)) { ch.SendText("You can't cast when you're paralyzed!\r\n"); return; } if (str.Length == 0) { ch.SendText("Cast what spell where?\r\n"); return; } Magic.Cast(ch, String.Join(" ", str)); }
public static void AppearanceMessage(CharData ch, string[] str) { if( ch == null ) return; CharData realChar = ch.GetChar(); if (!realChar.Authorized("appearmsg") || ch.IsImmortal() ) return; if (str.Length == 0) { ch.SendText("What do you want your appear message to say?\r\n"); } if (!ch.IsNPC()) { if (ch.StringTooLong(str[0])) { return; } ((PC)ch).ImmortalData.AppearMessage = str[0]; ch.SendText("Done.\r\n"); } return; }
/// <summary> /// Command to list all areas in the game. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Areas(CharData ch, string[] str) { if( ch == null ) return; string buf1 = String.Empty; Area area; string buf = String.Empty; foreach (Area it in Database.AreaList) { area = it; if (ch.IsImmortal()) { buf = String.Format("{0} {1} #{3}-{4} {2}\r\n", MUDString.PadStr(StringConversion.RangeString(area), 5), MUDString.PadStr(area.Author, 15), area.Name, MUDString.PadInt(area.LowIndexNumber,5), MUDString.PadInt(area.HighIndexNumber, 5)); } else { buf = String.Format("{0} {1} {2} \r\n", MUDString.PadStr(StringConversion.RangeString(area), 5), MUDString.PadStr(area.Author, 15), area.Name); } buf1 += buf; } ch.SendText(buf1); return; }
/// <summary> /// Tropy command. Shows kill data and whether certain mobs are "boring" and worth less experience. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Trophy(CharData ch, string[] str) { if( ch == null ) return; int count; CharData targetChar; if (str.Length == 0 || !ch.IsImmortal()) { targetChar = ch; } else { targetChar = ch.GetCharWorld(str[0]); if (!targetChar) { ch.SendText("No such person.\r\n"); return; } } if (targetChar.IsNPC()) { ch.SendText("Mobs don't have Trophy.\r\n"); return; } if (targetChar.Level < 5) { ch.SendText("You don't need to worry about trophy yet.\r\n"); return; } ch.SendText("&+BTrophy data:\r\n"); for (count = 0; count < Limits.MAX_LEVEL; ++count) { if (((PC)targetChar).TrophyData[count].MobIndexNumber == 0) continue; if (((PC)targetChar).TrophyData[count].NumberKilled == 0) continue; /* Added else for mobs which are removed from game. (Earlier, Trophy would crash the mud on no-longer existant mobs.) */ // TODO: Fix format of float value. string buf; if (Database.GetMobTemplate(((PC)targetChar).TrophyData[count].MobIndexNumber) != null) { buf = String.Format(" &n&+b(&+y{0:0000.00}&+b)&n {1}&n\r\n", ((float)((PC)targetChar).TrophyData[count].NumberKilled / (float)100), (Database.GetMobTemplate(((PC)targetChar).TrophyData[count].MobIndexNumber)).ShortDescription); } else if (((PC)targetChar).TrophyData[count].MobIndexNumber != 0) { buf = String.Format(" &n&+b(&+y{0:0000.00}&+b)&n ({1}) \r\n", ((float)((PC)targetChar).TrophyData[count].NumberKilled / (float)100), ((PC)targetChar).TrophyData[count].MobIndexNumber); } else { buf = String.Format(" &n&+b(&+y{0:0000.00}&+b)&n (null) \r\n", ((float)((PC)targetChar).TrophyData[count].NumberKilled / (float)100)); } ch.SendText(buf); } ch.SendText("\r\n"); return; }
public static void DisappearMessage(CharData ch, string[] str) { if( ch == null ) return; CharData realChar = ch.GetChar(); if (!realChar.Authorized("disappearmsg") || !ch.IsImmortal()) { return; } if (str.Length == 0) { ch.SendText("You need to provide a message.\r\n"); return; } if (!ch.IsNPC()) { if (ch.StringTooLong(str[0])) { return; } ((PC)ch).ImmortalData.DisappearMessage = str[0]; ch.SendText("Done.\r\n"); } return; }
/// <summary> /// Report a typo, which is logged by the issue system. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Typo(CharData ch, string[] str) { if( ch == null ) return; if (str.Length == 0) { ch.SendText("There was a Typo in your Typo report.\r\n"); return; } string text = String.Join(" ", str); Issue issue = new Issue(); issue.IssueDetail = new IssueEntry(ch.Name, text); issue.OpenedByImmortal = ch.IsImmortal(); issue.IssueType = Issue.Type.typo; issue.IssuePriority = Issue.Priority.low; if (ch.InRoom != null) { issue.RoomIndexNumber = ch.InRoom.IndexNumber; } Database.IssueList.Add(issue); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_DEBUG, 0, String.Format("New Typo, issue # {0} created by {1}. Text is:\n{2}", issue.IssueNumber, ch.Name, text)); Issue.Save(); ch.SendText("Yore typo report haz been rekorded. Thank yew.\r\n"); return; }
/// <summary> /// Used for dragging corpses into another room. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Drag(CharData ch, string[] str) { if( ch == null ) return; Object obj; Object obj2; if (ch.IsAffected( Affect.AFFECT_HOLD) || ch.IsAffected(Affect.AFFECT_MINOR_PARA)) { ch.SendText("You can't move!\r\n"); return; } if (str.Length == 0) { ch.SendText("Drag which what where?\r\n"); return; } if (str.Length == 0) { ch.SendText("You need to specify a direction.\r\n"); return; } if (!ch.IsNPC() && ch.HasActionBit(PC.PLAYER_MEMORIZING)) { ch.RemoveActionBit(PC.PLAYER_MEMORIZING); ch.SendText("You abandon your studies.\r\n"); } if (!(obj = ch.GetObjHere(str[0]))) { ch.SendText("You do not see that here.\r\n"); return; } if (obj.ItemType != ObjTemplate.ObjectType.npc_corpse && obj.ItemType != ObjTemplate.ObjectType.pc_corpse) { ch.SendText("You can only drag corpses.\r\n"); return; } if (str.Length > 2 && str[1] == "enter") { if ((obj2 = ch.GetObjHere(str[3]))) { switch (obj2.ItemType) { case ObjTemplate.ObjectType.teleport: case ObjTemplate.ObjectType.portal: if (obj2.ItemType == ObjTemplate.ObjectType.teleport && !CommandType.CheckCommandTrigger("enter", obj2.Values[1])) { ch.SendText("Nothing happens.\r\n"); return; }; Room location; if (Macros.IsSet(obj2.Values[3], ObjTemplate.PORTAL_RANDOM)) { location = Movement.GetRandomRoom(); } else { location = Room.GetRoom(obj2.Values[0]); } if (!location) { ch.SendText("That portal doesn't seem to go anywhere.\r\n"); return; } SocketConnection.Act("You drag the $p&n into $P&n.", ch, obj, obj2, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n drags the $p&n into $P&n.", ch, obj, obj2, SocketConnection.MessageTarget.room); if (obj2.Values[2] >= 0) { obj2.Values[2] -= 2; if (obj2.Values[2] <= 0) { SocketConnection.Act("$p&n fades into nothingness.", ch, obj2, null, SocketConnection.MessageTarget.room); obj2.RemoveFromRoom(); } } obj.RemoveFromRoom(); ch.RemoveFromRoom(); ch.AddToRoom(location); obj.AddToRoom(location); if (obj2.ItemType == ObjTemplate.ObjectType.portal) { SocketConnection.Act("$n&n steps out of $P&n dragging the $p&n.", ch, obj, obj2, SocketConnection.MessageTarget.room); } else { SocketConnection.Act("$n&n appears from elsewhere, dragging the $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); } CommandType.Interpret(ch, "look auto"); return; case ObjTemplate.ObjectType.vehicle: case ObjTemplate.ObjectType.ship: break; case ObjTemplate.ObjectType.other: break; default: ch.SendText("That cannot be entered.\r\n"); return; } } } Exit.Direction door = Movement.FindExit(ch, str[1]); if (door < 0) { ch.SendText("You can't drag anything that way.\r\n"); return; } if (ch.CurrentMoves < 5 && !ch.IsImmortal()) { ch.SendText("You are too exhausted to drag that anywhere.\r\n"); return; } string text = String.Format("You drag $p&n {0}.", door.ToString()); SocketConnection.Act(text, ch, obj, null, SocketConnection.MessageTarget.character); text = String.Format("$n&n drags $p&n {0}.", door.ToString()); SocketConnection.Act(text, ch, obj, null, SocketConnection.MessageTarget.room); obj.RemoveFromRoom(); ch.CurrentMoves -= 5; ch.Move(door); ch.WaitState(MUDMath.NumberRange(3, 12)); obj.AddToRoom(ch.InRoom); SocketConnection.Act("$n&n drags $p&n along behind $m.", ch, obj, null, SocketConnection.MessageTarget.room); }
public static void Ungroup(CharData ch, string[] str) { if( ch == null ) return; if (str.Length == 0) { ch.SendText("Ungroup who?\r\n"); return; } CharData victim = ch.GetCharWorld(str[0]); if (victim == null) { ch.SendText("They do not seem to exist!\r\n"); return; } if (ch != victim.GroupLeader && !ch.IsImmortal()) { SocketConnection.Act("You are not $S group leader!", ch, null, victim, SocketConnection.MessageTarget.character); return; } if (!victim.GroupLeader) { SocketConnection.Act("$N is not in a group!", ch, null, victim, SocketConnection.MessageTarget.character); victim.NextInGroup = null; return; } victim.GroupLeader.RemoveFromGroup(victim); return; }
/// <summary> /// Eat something. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Eat(CharData ch, string[] str) { if( ch == null ) return; Object obj; if (ch.IsBlind()) return; if (ch.Fighting || ch.CurrentPosition == Position.fighting) { ch.SendText("You can't eat while you're fighting!\r\n"); return; } if (str.Length == 0) { ch.SendText("Eat what?\r\n"); return; } if (!(obj = ch.GetObjCarrying(str[0]))) { ch.SendText("You do not have that item.\r\n"); return; } if (!ch.IsImmortal()) { if (obj.ItemType != ObjTemplate.ObjectType.food && obj.ItemType != ObjTemplate.ObjectType.pill) { ch.SendText("That's not edible.\r\n"); return; } if (!ch.IsNPC() && ((PC)ch).Hunger > 40) { ch.SendText("You are too full to eat more.\r\n"); return; } } SocketConnection.Act("You consume $p&n.", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n inhales $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); switch (obj.ItemType) { case ObjTemplate.ObjectType.food: if (!ch.IsNPC()) { int condition = ((PC)ch).Hunger; if (!ch.IsUndead()) { ch.AdjustHunger(obj.Values[0]); } if (((PC)ch).Hunger > 40) { ch.SendText("You are full.\r\n"); } else if (condition == 0 && ((PC)ch).Hunger > 0) { ch.SendText("You are no longer hungry.\r\n"); } } if (obj.Values[3] != 0 && !CharData.CheckImmune(ch, Race.DamageType.poison)) { /* The shit was poisoned! */ Affect af = new Affect(); SocketConnection.Act("$n chokes and gags.", ch, null, null, SocketConnection.MessageTarget.room); ch.SendText("You choke and gag.\r\n"); af.Type = Affect.AffectType.spell; af.Value = "poison"; af.Duration = 2 * obj.Values[0]; af.AddModifier(Affect.Apply.strength, -(obj.Level / 7 + 2)); af.SetBitvector(Affect.AFFECT_POISON); ch.CombineAffect(af); } break; case ObjTemplate.ObjectType.pill: { for (int i = 1; i <= 4; i++) { String spellName = SpellNumberToTextMap.GetSpellNameFromNumber(obj.Values[i]); if (String.IsNullOrEmpty(spellName)) { Log.Error("Eat: Spell number " + obj.Values[i] + " not found for pill object " + obj.ObjIndexNumber + ". Make sure it's in the SpellNumberToTextMap."); } Spell spell = StringLookup.SpellLookup(spellName); if (!spell) { Log.Error("Eat: Spell '" + spellName + "' not found for pill object " + obj.ObjIndexNumber + ". Make sure it's in the spells file."); } else { spell.Invoke(ch, obj.Values[0], ch); } } } break; } if (!ch.IsNPC() || (ch.IsNPC() && ch.IsAffected(Affect.AFFECT_CHARM))) { obj.RemoveFromWorld(); } return; }
/// <summary> /// Unlock something, like a door or a container. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Unlock(CharData ch, string[] str) { if( ch == null ) return; string arg1 = String.Empty; Exit.Direction door; if (str.Length == 0) { ch.SendText("What do you wish to unlock?\r\n"); return; } if (!MUDString.StringsNotEqual(str[0], "door") && arg1.Length != 0) { door = Movement.FindDoor(ch, arg1); } else { door = Movement.FindDoor(ch, str[0]); } if (door >= 0 && !(ch.Level < Limits.LEVEL_AVATAR && ch.InRoom.ExitData[(int)door] && ch.InRoom.ExitData[(int)door].ExitFlags != 0 && ch.InRoom.ExitData[(int)door].HasFlag(Exit.ExitFlag.secret))) { /* 'unlock door' */ Exit reverseExit; Room toRoom; Exit exit = ch.InRoom.GetExit(door); if (!exit.HasFlag(Exit.ExitFlag.closed)) { ch.SendText("It's not closed.\r\n"); return; } if (exit.Key < 0) { ch.SendText("It can't be unlocked.\r\n"); return; } if (!ch.GetKey(exit.Key) && !ch.IsImmortal()) { ch.SendText("You lack the key.\r\n"); return; } if (!exit.HasFlag(Exit.ExitFlag.locked)) { ch.SendText("It's already unlocked.\r\n"); return; } exit.RemoveFlag(Exit.ExitFlag.locked); ch.SendText("*Click*\r\n"); SocketConnection.Act("$n&n unlocks the $d.", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); if (exit.HasFlag(Exit.ExitFlag.destroys_key)) { (ch.GetKey(exit.Key)).RemoveFromWorld(); SocketConnection.Act("The $d eats the key!", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); SocketConnection.Act("The $d eats the key!", ch, null, exit.Keyword, SocketConnection.MessageTarget.room); } /* unlock the other side */ if ((toRoom = Room.GetRoom(exit.IndexNumber)) && (reverseExit = toRoom.GetExit(Exit.ReverseDirection(door))) && reverseExit.TargetRoom == ch.InRoom) { reverseExit.RemoveFlag(Exit.ExitFlag.locked); } return; } Object obj = ch.GetObjHere(str[0]); if (obj) { /* 'unlock portal' */ if (obj.ItemType == ObjTemplate.ObjectType.portal) { if (!Macros.IsSet(obj.Values[1], ObjTemplate.PORTAL_CLOSED)) { ch.SendText("It's not closed.\r\n"); return; } if (obj.Values[4] < 0) { ch.SendText("It can't be unlocked.\r\n"); return; } if (!ch.GetKey(obj.Values[4])) { ch.SendText("You lack the key.\r\n"); return; } if (!Macros.IsSet(obj.Values[3], ObjTemplate.PORTAL_LOCKED)) { ch.SendText("It's already unlocked.\r\n"); return; } Macros.RemoveBit(ref obj.Values[3], ObjTemplate.PORTAL_LOCKED); ch.SendText("*Click*\r\n"); SocketConnection.Act("$n&n unlocks $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); return; } /* 'unlock object' */ if (obj.ItemType != ObjTemplate.ObjectType.container) { ch.SendText("That is not a container.\r\n"); return; } if (!Macros.IsSet(obj.Values[1], ObjTemplate.CONTAINER_CLOSED.Vector)) { ch.SendText("It's not closed.\r\n"); return; } if (obj.Values[2] < 0) { ch.SendText("It can't be unlocked.\r\n"); return; } if (!ch.GetKey(obj.Values[2])) { ch.SendText("You lack the key.\r\n"); return; } if (!Macros.IsSet(obj.Values[1], ObjTemplate.CONTAINER_LOCKED.Vector)) { ch.SendText("It's already unlocked.\r\n"); return; } Macros.RemoveBit(ref obj.Values[1], ObjTemplate.CONTAINER_LOCKED.Vector); ch.SendText("*Click*\r\n"); SocketConnection.Act("$n&n unlocks $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); return; } return; }
/// <summary> /// Command to display your faction standings. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Faction(CharData ch, string[] str) { if( ch == null ) return; int count; string buf = "Other race reactions to you:\r\n"; for (count = 0; count < Race.RaceList.Length; count++) { if (!ch.IsImmortal()) { buf += String.Format("&+c{0}&n: &+Y{1}&n ", MUDString.PadStr(Race.RaceList[count].Name, 15), MUDString.PadStr(StringConversion.FactionString(ch.GetFaction(count)), 14)); } else { buf += String.Format("&+c{0}&n: &+Y{1}&n ", MUDString.PadStr(Race.RaceList[count].Name, 15), MUDString.PadStr(ch.GetFaction(count).ToString(), 14)); } if (count % 2 == 0) { buf += "\r\n"; } } buf += "\r\n"; ch.SendText(buf); }
/// <summary> /// Displays the "who list" based on provided paramters. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Who(CharData ch, string[] str) { if( ch == null ) return; if (ch.Fighting || (ch.CurrentPosition == Position.fighting)) { ch.SendText("&nEnd the fight first!\r\n"); return; } // Set racewar side to check Race.RacewarSide rws; // for RaceWarSide wholist if (ch.IsImmortal()) { rws = Race.RacewarSide.neutral; } else { rws = ch.GetRacewarSide(); } // Initialize races and classes to false. bool[] rgfClass = new bool[CharClass.ClassList.Length]; bool[] rgfRace = new bool[Limits.MAX_PC_RACE]; int iClass; int iRace; for (iClass = 0; iClass < CharClass.ClassList.Length; ++iClass) { rgfClass[iClass] = false; } for (iRace = 0; iRace < Limits.MAX_PC_RACE; ++iRace) { rgfRace[iRace] = false; } // Handle command arguments. int iLevelLower = 0; int iLevelUpper = Limits.MAX_LEVEL; int numbers = 0; bool immortalOnly = false; bool sorted = false; /* for sorted list */ bool fClassRestrict = false; bool fRaceRestrict = false; string name = String.Empty; for (int i = 0; i < str.Length; i++ ) { // Level numbers. if (MUDString.IsNumber(str[i])) { switch (++numbers) { case 1: Int32.TryParse(str[i], out iLevelLower); break; case 2: Int32.TryParse(str[i], out iLevelUpper); break; default: ch.SendText("&nOnly two level numbers allowed.\r\n"); return; } } else { // Look for classes to turn on. if (!MUDString.IsPrefixOf(str[i], "immortals")) { immortalOnly = true; } else if (!MUDString.IsPrefixOf(str[i], "sort")) { sorted = true; } else if (ch.IsImmortal() && !MUDString.IsPrefixOf(str[i], "good")) { rws = Race.RacewarSide.good; } else if (ch.IsImmortal() && !MUDString.IsPrefixOf(str[i], "evil")) { rws = Race.RacewarSide.evil; } else { int iClass2; for (iClass2 = 0; iClass2 < CharClass.ClassList.Length; ++iClass2) { if (!MUDString.IsPrefixOf(str[i], CharClass.ClassList[iClass2].Name)) { rgfClass[iClass2] = true; fClassRestrict = true; break; } } for (iRace = 0; iRace < Limits.MAX_PC_RACE; ++iRace) { if (!MUDString.IsPrefixOf(str[i], Race.RaceList[iRace].Name)) { rgfRace[iRace] = true; fRaceRestrict = true; break; } } if (iClass2 == CharClass.ClassList.Length && iRace == Limits.MAX_PC_RACE) { name = str[i]; } } } } // Now show characters that match our parameters. int nMatch = 0; List<String> immortals = new List<String>(); List<String> mortals = new List<String>(); /* Limits.L_DIR; Used to be Max_level.. Why change this? */ string text = String.Empty; int temp; int numPlayers = 0; for (temp = 0; temp <= Limits.MAX_LEVEL; ++temp) { /* for sorted list */ foreach (SocketConnection socket in Database.SocketList) { string cclass; CharData workingChar = (socket.Original != null) ? socket.Original : socket.Character; /* * Check for match against restrictions. * Don't use trust as that exposes trusted mortals. */ if (socket.ConnectionStatus != SocketConnection.ConnectionState.playing || !CharData.CanSee(ch, workingChar)) { continue; } if (name.Length == 0) { /* Outside level/class restrictions. */ if ((workingChar.Level < iLevelLower) || (workingChar.Level > iLevelUpper) || (fClassRestrict && !rgfClass[(int)workingChar.CharacterClass.ClassNumber]) || (fRaceRestrict && !rgfRace[workingChar.GetRace()])) continue; if (sorted != false && (workingChar.Level != temp)) continue; /* Imm only . skip non-immortals. */ if (immortalOnly && !workingChar.IsImmortal()) continue; } else if (!MUDString.NameContainedIn(workingChar.Name, name) || (workingChar.Level != temp && sorted != false)) continue; /* Opposite racewar sides, and both chars are mortals. */ if (workingChar.GetRacewarSide() != rws && rws != Race.RacewarSide.neutral && !workingChar.IsImmortal()) continue; nMatch++; /* * Figure out what to print for class. */ if (workingChar.Level >= Limits.LEVEL_HERO) { switch (workingChar.Level) { default: cclass = "&+yUnknown &n"; break; case Limits.LEVEL_OVERLORD: cclass = "&+r Overlord &n"; break; case Limits.LEVEL_GREATER_GOD: cclass = "&+mGreater God&n"; break; case Limits.LEVEL_LESSER_GOD: cclass = "&+MLesser God &n"; break; case Limits.LEVEL_DEMIGOD: cclass = "&+y Demigod &n"; break; case Limits.LEVEL_AVATAR: cclass = "&+R Avatar &n"; break; case Limits.LEVEL_HERO: cclass = "&+c Hero &n"; break; } } else { cclass = workingChar.CharacterClass.WholistName; } /* * Format it up. */ if (!workingChar.IsImmortal()) { string buf5 = String.Format("{0}{1}{2}{3}{4} {5} ({6})", workingChar.HasActionBit(PC.PLAYER_BOTTING) ? "[BOT] " : String.Empty, workingChar.HasActionBit(PC.PLAYER_AFK) ? "[AFK] " : String.Empty, workingChar.IsAffected(Affect.AFFECT_INVISIBLE) ? "*" : String.Empty, workingChar.Name, ((PC)workingChar).Title, !workingChar.IsGuild() ? String.Empty : ((PC)workingChar).GuildMembership.WhoName, Race.RaceList[workingChar.GetRace()].ColorName); text = String.Format("&+L[&n{0} {1}&+L]&n {2}\r\n", MUDString.PadInt(workingChar.Level, 2), MUDString.PadStr(cclass, 13), buf5); } else { string buf1 = String.Format("{0}{1}{2}{3}{4}", workingChar.HasActionBit(PC.PLAYER_WIZINVIS) ? "(WIZINVIS) " : String.Empty, workingChar.HasActionBit(PC.PLAYER_AFK) ? "[AFK] " : String.Empty, workingChar.HasActionBit(PC.PLAYER_BOTTING) ? "[BOT] " : String.Empty, workingChar.Name, ((PC)workingChar).Title); string buf2 = String.Format(" {0}", !workingChar.IsGuild() ? String.Empty : ((PC)workingChar).GuildMembership.WhoName); text = String.Format("&+L[&n{0}&+L]&n {1}{2}\r\n", MUDString.PadStr(cclass, 15), buf1, buf2); } if (!workingChar.IsImmortal()) { mortals.Add(text); } else { immortals.Add(text); } } if (sorted == false) { break; } } // Immortals show up above mortals because immortals are more important. ch.SendText("\r\n"); if (immortals.Count > 0) { ch.SendText("&+b-----------------------------------[ &+BIMMORTALS&+b ]-----------------------------&n\r\n"); } foreach( String who in immortals ) { ch.SendText(who); } if (mortals.Count > 0) { ch.SendText("&n&+b------------------------------------[ &+BMORTALS&n&+b ]------------------------------&n\r\n"); } foreach (String who in mortals) { ch.SendText(who); } ch.SendText("&n&+b-----------------------------------------------------------------------------&n\r\n"); foreach (SocketConnection socket in Database.SocketList) { if (socket.ConnectionStatus == SocketConnection.ConnectionState.playing) { numPlayers++; } } text = String.Format("&nYou see {0} of {1} player{2} in the game.\r\n", nMatch, numPlayers, numPlayers == 1 ? String.Empty : "s"); ch.SendText(text); return; }
/// <summary> /// Teleport to another location. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Goto(CharData ch, string[] str) { if( ch == null ) return; CharData realChar = ch.GetChar(); if (!realChar.Authorized("goto") || !ch.IsImmortal()) { return; } if (str.Length == 0) { ch.SendText("Goto where?\r\n"); return; } Room location = Room.FindLocation(ch, str[0]); if (!location) { ch.SendText("No such location.\r\n"); return; } if (location.IsPrivate()) { ch.SendText("That room is private right now.\r\n"); return; } if (ch.Fighting) { Combat.StopFighting(ch, true); } if (!ch.HasActionBit(PC.PLAYER_WIZINVIS)) { if (!ch.IsNPC() && ((PC)ch).ImmortalData.DisappearMessage.Length > 0) { SocketConnection.Act("$T", ch, null, ((PC)ch).ImmortalData.DisappearMessage, SocketConnection.MessageTarget.room); } else { SocketConnection.Act("$n disappears in a puff of smoke.", ch, null, null, SocketConnection.MessageTarget.room); } } ch.RemoveFromRoom(); ch.AddToRoom(location); if (!ch.HasActionBit(PC.PLAYER_WIZINVIS)) { if (!ch.IsNPC() && ((PC)ch).ImmortalData.AppearMessage.Length > 0) { SocketConnection.Act("$T", ch, null, ((PC)ch).ImmortalData.AppearMessage, SocketConnection.MessageTarget.room); } else { SocketConnection.Act("$n appears in a swirling mist", ch, null, null, SocketConnection.MessageTarget.room); } } CommandType.Interpret(ch, "look auto"); return; }
/// <summary> /// Psionics should be instantaneous and exempt from the casting stuff, and suffer /// lag after their power goes off. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Will(CharData ch, string[] str) { if( ch == null ) return; if (!ch.IsClass(CharClass.Names.psionicist) && !ch.IsClass(CharClass.Names.enslaver) && !ch.IsImmortal()) { ch.SendText("Your mind is much too puny for you to focus your will.\r\n"); return; } if (ch.IsClass(CharClass.Names.bard) && !ch.IsImmortal()) { ch.SendText("Bards use the SING or PLAY commands to invoke their powers.\r\n"); return; } if (ch.Riding && ch.Riding.InRoom == ch.InRoom) { ch.SendText("It's too hard to concentrate! Dismount.\r\n"); return; } // Psis should be able to will stuff when paralyzed, thus no check for para. if (str.Length == 0) { ch.SendText("Will which what where?\r\n"); return; } Magic.Cast(ch, String.Join(" ", str)); }
/// <summary> /// Old-style clunky long-form text editing. /// /// TODO: Make this work better. /// </summary> /// <param name="ch"></param> /// <param name="argument"></param> public static void StringAdd( CharData ch, string argument ) { string text = String.Empty; int buflen = ch.Socket.EditingString.Length; int arglen = argument.Length; if( argument[ 0 ] == '.' ) { string arg1 = String.Empty; string arg2 = String.Empty; string arg3 = String.Empty; argument = OneArgument( argument, ref arg1 ); argument = OneArgument( argument, ref arg2 ); argument = OneArgument( argument, ref arg3 ); if( !StringsNotEqual( arg1, ".c" ) ) { ch.SendText( "String cleared.\r\n" ); ch.Socket.EditingString = String.Empty; return; } if( !StringsNotEqual( arg1, ".s" ) ) { ch.SendText( "String so far:\r\n" ); ch.SendText( ch.Socket.EditingString ); ch.SendText( String.Empty ); return; } if( !StringsNotEqual( arg1, ".r" ) ) { if( String.IsNullOrEmpty(arg2) ) { ch.SendText( "Usage: .r \"old string\" \"new string\"\r\n" ); return; } ch.Socket.EditingString = ch.Socket.EditingString.Replace( arg2, arg3 ); text += "'" + arg2 + "' replaced with '" + arg3 + "'.\r\n"; ch.SendText( text ); return; } if( !StringsNotEqual( arg1, ".h" ) ) { ch.SendText( "Sedit help (commands on blank line):\r\n" ); ch.SendText( ".r 'old' 'new' Replace a subpublic string (requires '', \"\").\r\n" ); ch.SendText( ".h Get help (this info).\r\n" ); ch.SendText( ".s Show public string so far.\r\n" ); ch.SendText( ".c Clear public string so far.\r\n" ); ch.SendText( "@ End public string.\r\n" ); return; } ch.SendText( "StringAdd: Invalid dot command.\r\n" ); return; } if( argument[ 0 ] == '@' ) { ch.Socket.EditingString = String.Empty; return; } // Truncate strings to 4096. if( buflen + arglen >= ( 4096 - 4 ) ) { string buf1 = ch.Name; ch.SendText( "The string was too long, the last line has been skipped.\r\n" ); buf1 += " is trying to write a description that's too long."; Log.Trace( buf1 ); // Force character out of editing mode. ch.Socket.EditingString = String.Empty; return; } if( ch.IsImmortal() ) { string message = String.Format( "\r\n&+gAdding {0} chars to {1} chars leaving {2} left.&n\r\n", arglen, buflen, ( 4096 - 4 - buflen - arglen ) ); ch.SendText( message ); } text += ch.Socket.EditingString + argument + "\r\n"; ch.Socket.EditingString = text; return; }
/// <summary> /// Sing -- using a bard song without an instrument. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Sing(CharData ch, string[] str) { if( ch == null ) return; if (!ch.IsClass(CharClass.Names.bard) && !ch.IsImmortal()) { ch.SendText("You don't know how to sing.\r\n"); return; } if (ch.IsAffected(Affect.AFFECT_MINOR_PARA) || ch.IsAffected(Affect.AFFECT_HOLD)) { ch.SendText("You can't Sing when you're paralyzed!\r\n"); return; } if (ch.HasActionBit(Affect.AFFECT_MUTE)) { ch.SendText("You have no voice!\r\n"); return; } if (str.Length == 0) { if (ch.IsAffected(Affect.AFFECT_SINGING)) { ch.RemoveAffect(Affect.AFFECT_SINGING); ch.SendText("You stop singing.\r\n"); } else { ch.SendText("Sing what?\r\n"); } return; } Magic.Cast(ch, String.Join(" ", str)); }