/// <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; }
/// <summary> /// Sends ability scores when rolling stats or applying bonuses. Used to avoid repetitive code. /// </summary> /// <param name="ch"></param> private void SendAbilityScores(CharData ch) { string text = String.Format( "\r\n\r\nStr: {0} Int: {1}\r\nDex: {2} Wis: {3}\r\nAgi: {4} Cha: {5}\r\nCon: {6}\r\nPow: {7}\r\n\r\n", MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrStr() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrInt() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrDex() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrWis() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrAgi() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrCha() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrCon() ), 17 ), MUDString.PadStr( StringConversion.AbilityScoreString( ch.GetCurrPow() ), 17 ) ); WriteToBuffer( text ); }
/// <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> /// This function's main access commands are wear, wield, and hold, which have the /// following flow: /// wear: Command.Wear, wear_obj, equip_hand /// wield: Command.Wield, equip_hand /// hold: Command.Hold, equip_hand /// /// We assume by this point that the character is physically able to use the item and will be able /// to equip it however specified. Those checks are performed by WearObject(), Equip(), and Hold(). /// </summary> /// <param name="ch"></param> /// <param name="obj"></param> /// <param name="type"></param> /// <returns></returns> public static bool EquipInHand(CharData ch, Object obj, int type) { int weight = 0; ObjTemplate.WearLocation firstAvail = ObjTemplate.WearLocation.none; ObjTemplate.WearLocation secondAvail = ObjTemplate.WearLocation.none; ObjTemplate.WearLocation lastAvail = ObjTemplate.WearLocation.none; Object hand1 = GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_one); Object hand2 = GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_two); Object hand3 = GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_three); Object hand4 = GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_four); if (hand1 && (hand1._itemType == ObjTemplate.ObjectType.weapon || hand1._itemType == ObjTemplate.ObjectType.ranged_weapon)) weight += hand1.GetWeight(); if (hand2 && (hand2._itemType == ObjTemplate.ObjectType.weapon || hand2._itemType == ObjTemplate.ObjectType.ranged_weapon)) weight += hand2.GetWeight(); if (hand3 && (hand3._itemType == ObjTemplate.ObjectType.weapon || hand3._itemType == ObjTemplate.ObjectType.ranged_weapon)) weight += hand3.GetWeight(); if (hand4 && (hand4._itemType == ObjTemplate.ObjectType.weapon || hand4._itemType == ObjTemplate.ObjectType.ranged_weapon)) weight += hand4.GetWeight(); if (ch.GetRace() != Race.RACE_THRIKREEN) { if (hand3) Log.Error("non-thrikreen wielding item in hand3", 0); if (hand4) Log.Error("non-thrikreen wielding item in hand4", 0); } // Find number of hand slots used and first available hand. // Be sure to handle twohanded stuff. if (hand4 && hand4.HasFlag(ObjTemplate.ITEM_TWOHANDED)) { Log.Error("Twohanded weapon in fourth hand -- this is not possible.", 0); } if (hand3 && hand3.HasFlag(ObjTemplate.ITEM_TWOHANDED)) { if (hand4) { Log.Error("Twohanded weapon in third hand with fourth hand holding twohanded weapon -- this is not possible, all twohanded must have a blank hand after it.", 0); } hand4 = hand3; } if (hand2 && hand2.HasFlag(ObjTemplate.ITEM_TWOHANDED)) { if (hand3) { Log.Error("Twohanded weapon in second hand with third hand holding twohanded weapon -- this is not possible, all twohanded must have a blank hand after it.", 0); } hand2 = hand3; } if (!ch.HasInnate(Race.RACE_EXTRA_STRONG_WIELD)) { if (hand1 && hand1.HasFlag(ObjTemplate.ITEM_TWOHANDED)) { if (hand2) { Log.Error("Twohanded weapon in second hand with first hand holding twohanded weapon -- this is not possible, all twohanded must have a blank hand after it.", 0); } hand2 = hand1; } } if (obj.HasFlag(ObjTemplate.ITEM_TWOHANDED) && !ch.HasInnate(Race.RACE_EXTRA_STRONG_WIELD)) { if (ch.GetRace() == Race.RACE_THRIKREEN && !hand4) { firstAvail = ObjTemplate.WearLocation.hand_four; lastAvail = ObjTemplate.WearLocation.hand_four; } if (ch.GetRace() == Race.RACE_THRIKREEN && !hand3) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_three; secondAvail = firstAvail; firstAvail = ObjTemplate.WearLocation.hand_three; } if (!hand2) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_two; secondAvail = firstAvail; firstAvail = ObjTemplate.WearLocation.hand_two; } if (!hand1) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_one; secondAvail = firstAvail; firstAvail = ObjTemplate.WearLocation.hand_one; } if (firstAvail == 0) { ch.SendText("Your hands are full!\r\n"); return false; } if (secondAvail == 0) { ch.SendText("You need two hands free to wield that!\r\n"); return false; } } else if (obj.HasFlag(ObjTemplate.ITEM_TWOHANDED)) { if (ch.GetRace() == Race.RACE_THRIKREEN && !hand4) { firstAvail = ObjTemplate.WearLocation.hand_four; } if (ch.GetRace() == Race.RACE_THRIKREEN && !hand3) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_three; secondAvail = firstAvail; firstAvail = ObjTemplate.WearLocation.hand_three; } if (!hand2) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_two; secondAvail = firstAvail; firstAvail = ObjTemplate.WearLocation.hand_two; } if (!hand1) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_one; secondAvail = ObjTemplate.WearLocation.hand_one; firstAvail = ObjTemplate.WearLocation.hand_one; } if (firstAvail == 0) { ch.SendText("Your hands are full!\r\n"); return false; } if (secondAvail == 0) { ch.SendText("You need two hands free to wield that!\r\n"); return false; } } else { if (ch.GetRace() == Race.RACE_THRIKREEN && !hand4) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_four; firstAvail = ObjTemplate.WearLocation.hand_four; } if (ch.GetRace() == Race.RACE_THRIKREEN && !hand3) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_three; firstAvail = ObjTemplate.WearLocation.hand_three; } if (!hand2) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_two; firstAvail = ObjTemplate.WearLocation.hand_two; } if (hand1 == null) { if (lastAvail == 0) lastAvail = ObjTemplate.WearLocation.hand_one; firstAvail = ObjTemplate.WearLocation.hand_one; } if (firstAvail == 0) { ch.SendText("Your hands are full!\r\n"); return false; } } // Successful hand availability, send message and ready the item. // Twohanded shields, held items, and lights are equipped primary. // This could annoy ogres/thris but twohanded versions of these items // are so rare it's not likely to be an issue. switch (type) { case EQUIP_HOLD: if (!obj.HasFlag(ObjTemplate.ITEM_TWOHANDED)) ch.EquipObject(ref obj, lastAvail); else ch.EquipObject(ref obj, firstAvail); break; case EQUIP_SHIELD: SocketConnection.Act("You strap $p&n to your arm.", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n straps $p&n to $s arm.", ch, obj, null, SocketConnection.MessageTarget.room); if (!obj.HasFlag(ObjTemplate.ITEM_TWOHANDED)) ch.EquipObject(ref obj, lastAvail); else ch.EquipObject(ref obj, firstAvail); break; case EQUIP_LIGHT: if (obj._itemType == ObjTemplate.ObjectType.light && obj._values[2] != 0) { SocketConnection.Act("You &n&+rli&+Rght&n $p&n and hold it before you.", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n &+Rlig&n&+rhts&n $p&n and holds it before $m.", ch, obj, null, SocketConnection.MessageTarget.room); } else { SocketConnection.Act("You hold the &+Lspent&n remains of $p&n.", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n holds the spent husk of $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); } if (!obj.HasFlag(ObjTemplate.ITEM_TWOHANDED)) ch.EquipObject(ref obj, lastAvail); else ch.EquipObject(ref obj, firstAvail); break; case EQUIP_WIELD: // Have to check for dual wield skill, and for total weight of weapons. if (firstAvail != ObjTemplate.WearLocation.hand_one) { // Those without dual wield cannot wield anything in their second hand. Include thrikreen if (!ch.IsNPC() && !ch.HasSkill("dual wield")) { ch.SendText("You lack the skills to wield a weapon in anything but your primary hand.\r\n"); return false; } } if ((weight + obj.GetWeight()) > StrengthModifier.Table[ch.GetCurrStr()].WieldWeight) { SocketConnection.Act("Your meager strength is overwhelmed by $p&n.", ch, obj, null, SocketConnection.MessageTarget.character); return false; } SocketConnection.Act("You wield $p&n.", ch, obj, null, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n brandishes $p&n.", ch, obj, null, SocketConnection.MessageTarget.room); ch.EquipObject(ref obj, firstAvail); break; } // Objects with a trap activated on wear. if (obj._trap != null && obj._trap.CheckTrigger( Trap.TriggerType.wear)) { ch.SetOffTrap(obj); if (ch.CurrentPosition == Position.dead) return false; } return true; }