/// <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> /// Shows available room exits. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Exits(CharData ch, string[] str) { if( ch == null ) return; Exit exit; int door; bool auto = (str.Length != 0 && !MUDString.StringsNotEqual(str[0], "auto")); if (ch.IsBlind() || !ch.InRoom) { return; } string text; if (!ch.IsNPC() && ch.Socket.Terminal == SocketConnection.TerminalType.TERMINAL_ENHANCED && auto) { text = "<exits>"; } else { text = auto ? "&+cExits: &n" : "&+cVisible exits:&n\r\n"; } bool found = false; // Show the direction with an asterisk if it // has a closed door, and in exits command it shows up as a // closed <whatever>. for (door = 0; door < Limits.MAX_DIRECTION; ++door) { exit = ch.InRoom.ExitData[door]; if (exit && exit.TargetRoom) { if (exit.HasFlag(Exit.ExitFlag.secret)) { /* Mortals do not see secret exits. */ if (ch.Level < Limits.LEVEL_AVATAR) continue; /* Mark secret exits for immortals. */ text += "&+LS&n&+c"; } if (exit.HasFlag(Exit.ExitFlag.blocked)) { /* Mortals do not see secret exits. */ if (ch.Level < Limits.LEVEL_AVATAR) continue; /* Mark secret exits for immortals. */ text += "&+yB&n&+c"; } found = true; if (auto) { if (exit.HasFlag(Exit.ExitFlag.walled) && exit.HasFlag(Exit.ExitFlag.illusion)) continue; if (exit.HasFlag(Exit.ExitFlag.closed)) text += "&n&+y#&n&+c"; // Don't show exits to impassable rooms. // Show a yellow exclamation point to those with holylight on though. if (exit.TargetRoom && exit.TargetRoom.TerrainType == TerrainType.underground_impassable) { if (!ch.HasActionBit(PC.PLAYER_GODMODE)) { continue; } text += "&+Y!&n"; } text += door.ToString(); text += " "; } else { if (exit.HasFlag(Exit.ExitFlag.walled)) { text += String.Format("&n{0} - (Walled)&n\r\n", MUDString.PadStr(door.ToString().ToUpper(), 5)); } else if (!exit.HasFlag(Exit.ExitFlag.closed)) { // gods with holylight on can go to useless exits. if (exit.TargetRoom && exit.TargetRoom.TerrainType == TerrainType.underground_impassable) { if (!ch.HasActionBit(PC.PLAYER_GODMODE)) { continue; } text += "&+Y!&n"; } text += String.Format("&n {0} - {1}&n\r\n", MUDString.PadStr(door.ToString().ToUpper(), 5), (!ch.HasInnate(Race.RACE_ULTRAVISION) && Room.GetRoom(exit.IndexNumber).IsDark()) ? "&nToo dark to tell" : exit.TargetRoom.Title); } else { text += String.Format("&+y#&n{0} - Closed {1}\r\n", MUDString.PadStr(door.ToString().ToUpper(), 5), exit.Keyword); } } } } if (!found) { text += auto ? " none" : "&nNone.\r\n"; } if (!ch.IsNPC() && ch.Socket.Terminal == SocketConnection.TerminalType.TERMINAL_ENHANCED && auto) { text += "&n</exits>"; } else if (auto) { text += "&n\r\n"; } ch.SendText(text); return; }
/// <summary> /// Assist someone in combat by joining them against their primary target. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Assist(CharData ch, string[] str) { if( ch == null ) return; CharData victim; if (!ch.IsBlind()) { ch.SendText("You can't assist the invisible.\r\n"); return; } if (ch.Fighting) { ch.SendText("You're a bit busy at the moment.\r\n"); return; } if (str.Length != 0) { victim = ch.GetCharRoom(str[0]); if (!victim) { ch.SendText("They aren't here.\r\n"); return; } } else { ch.SendText("Assist who?\r\n"); return; } if (victim == ch) { ch.SendText("You're too busy assisting yourself to assist yourself.\r\n"); return; } if (!victim.Fighting) { ch.SendText("They're not fighting anyone.\r\n"); return; } if (victim.Fighting == ch) { ch.SendText("Assist!? They're fighting YOU, fool!\r\n"); return; } SocketConnection.Act("You scream a battle cry, and assist $N&n heroically.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n leaps into the fray, valiantly assisting you.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n charges into battle and assists $N&n heroically.", ch, null, victim, SocketConnection.MessageTarget.room_vict); Combat.SingleAttack(ch, victim.Fighting, String.Empty, ObjTemplate.WearLocation.hand_one); 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> /// Kick someone. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Kick(CharData ch, string[] str) { if( ch == null ) return; int chance; int wallkickchance; /* Check player's level and class, allow mobs to do this too */ if ((!ch.HasSkill("kick"))) { ch.SendText("You'd better leave the martial arts to fighters.\r\n"); return; } if (ch.IsBlind() && !ch.Fighting) { return; } CharData victim = ch.Fighting; if (str.Length != 0) { victim = ch.GetCharRoom(str[0]); if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("They aren't here.\r\n"); return; } } else { if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("You aren't fighting anyone.\r\n"); return; } } if (victim == ch) { ch.SendText("You kick yourself for being a dummy.\r\n"); return; } ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["kick"].Delay)); if (!ch.IsNPC()) { chance = ((PC)ch).SkillAptitude["kick"]; ch.PracticeSkill("kick"); } else { chance = ch.Level * 3 / 2 + 20; } // It's much harder to kick really tiny things; imagine trying to kick // a fly. if (ch.CurrentSize > victim.CurrentSize + 5) { chance -= (ch.CurrentSize - victim.CurrentSize) * 5; } // It's harder to kick things that move faster than you. chance += ((ch.GetCurrAgi() - victim.GetCurrAgi()) / 5); // Huge bonus against incapacitated and mortally wounded foes. if (victim.CurrentPosition <= Position.incapacitated) { chance += 50; } // Damned high penalty for kicking blind if (ch.IsAffected(Affect.AFFECT_BLIND) && !victim.IsAffected(Affect.AFFECT_BLIND)) { chance /= 10; } if (ch.IsAffected(Affect.AFFECT_BLIND) && victim.IsAffected(Affect.AFFECT_BLIND)) { chance /= 4; } // If the victim is two or more sizes smaller than the kicker give them a chance // to be kicked into a wall or out of the room. // // Chance of 5% per size class difference, no maximum // (wall/room kick is 50% at a difference of 10 sizes) if (victim.CurrentSize - 1 >= ch.CurrentSize) { wallkickchance = 0; } else { wallkickchance = ((ch.CurrentSize - victim.CurrentSize) * 5) - 5; } // Check for kick success if (MUDMath.NumberPercent() < chance) { /* Check for wall kick. */ /* to be kicked out of the room (random direction). */ if (MUDMath.NumberPercent() < wallkickchance) { Exit.Direction door = Database.RandomDoor(); // Check for valid room stuff on victim Room kickedInto; Exit exit; if (victim && victim.InRoom && victim.InRoom.ExitData != null && (exit = victim.InRoom.GetExit(door)) && exit.TargetRoom && exit.ExitFlags != 0 && !exit.HasFlag(Exit.ExitFlag.secret) && !exit.HasFlag(Exit.ExitFlag.blocked) && !exit.HasFlag(Exit.ExitFlag.walled) && exit.HasFlag(Exit.ExitFlag.closed) && !Room.GetRoom(exit.IndexNumber).IsPrivate() && exit.TargetRoom.TerrainType != TerrainType.underground_impassable && (kickedInto = Room.GetRoom(exit.IndexNumber))) { Combat.StopFighting(victim, true); string buf = String.Format("$N&n is sent flying out of the room {0}ward by $n&n's mighty kick.", door.ToString()); SocketConnection.Act(buf, ch, null, victim, SocketConnection.MessageTarget.room_vict); buf = String.Format("$N&n is sent flying out of the room {0}ward by your mighty kick.", door.ToString()); SocketConnection.Act(buf, ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("You are sent flying out of the room by $n's mighty kick!", ch, null, victim, SocketConnection.MessageTarget.victim); victim.RemoveFromRoom(); victim.AddToRoom(kickedInto); SocketConnection.Act("$n&n is stunned!", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("You are stunned!\r\n"); victim.WaitState((Skill.SkillList["kick"].Delay * 9) / 10); if (victim.CurrentPosition > Position.resting) { victim.CurrentPosition = Position.resting; } } else { // If no exit in our chosen direction, must be a wall. SocketConnection.Act("$N&n is sent flying into the wall by $n&n's mighty kick.", ch, null, victim, SocketConnection.MessageTarget.room_vict); SocketConnection.Act("$N&n is sent flying into the wall by your mighty kick.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("You are smacked into the wall by $n's mighty kick!", ch, null, victim, SocketConnection.MessageTarget.victim); if (victim.CurrentPosition > Position.resting) { victim.CurrentPosition = Position.resting; } // At least a two second stun victim.WaitState(8); /* Check for stunning victim. */ if ((MUDMath.NumberPercent() * 2) > victim.GetCurrAgi()) { SocketConnection.Act("$N&n is stunned!", ch, null, victim, SocketConnection.MessageTarget.room_vict); victim.SendText("You are stunned!\r\n"); victim.WaitState((Skill.SkillList["kick"].Delay * 9) / 10); } else { victim.WaitState(1); } } // Do excessive damage compared to a normal kick Combat.InflictDamage(ch, victim, MUDMath.Dice(2, ch.Level), String.Empty, ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } // Check for wall kick (execute regular kick) else { Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, ch.Level), "kick", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } } // Check for successful kick (missed kick) else { Combat.InflictDamage(ch, victim, 0, "kick", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } return; }
/// <summary> /// Throw dirt in someone's eyes. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void DirtToss(CharData ch, string[] str) { if( ch == null ) return; int percent; /* Don't allow the unskilled to do this, check player's level */ if (!ch.HasSkill("dirt toss")) { ch.SendText("You get your feet dirty.\r\n"); return; } if (ch.IsBlind()) { ch.SendText("You can't see anything!\r\n"); return; } if (ch.FlightLevel != 0) { ch.SendText("Perhaps you should land first matey.\r\n"); return; } CharData victim = ch.Fighting; if (str.Length != 0) { if (!(victim = ch.GetCharRoom(str[0])) || victim.CurrentPosition == Position.dead) { ch.SendText("They aren't here.\r\n"); return; } } if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("You aren't fighting anyone.\r\n"); return; } if (victim == ch) { ch.SendText("How about sticking a fork your eye instead?\r\n"); return; } if (victim.IsAffected( Affect.AFFECT_BLIND)) { SocketConnection.Act("$E's already been &+Lblinded&n.", ch, null, victim, SocketConnection.MessageTarget.character); return; } if (!ch.IsNPC()) { percent = ((PC)ch).SkillAptitude["dirt toss"]; } else { percent = (ch.Level * 3) / 2 + 25; } percent += (ch.Level - victim.Level) * 2; percent += (ch.GetCurrDex() / 10); percent -= (victim.GetCurrDex() / 10); percent -= (victim.GetCurrAgi() / 10); // Why waste time listing sectors with no modifier? switch (ch.InRoom.TerrainType) { case TerrainType.inside: case TerrainType.arctic: case TerrainType.swamp: percent -= 20; break; case TerrainType.city: case TerrainType.mountain: percent -= 10; break; case TerrainType.plane_of_fire: case TerrainType.plane_of_air: case TerrainType.plane_of_water: case TerrainType.plane_ethereal: case TerrainType.plane_astral: case TerrainType.underwater_has_ground: case TerrainType.underwater_no_ground: case TerrainType.swimmable_water: case TerrainType.unswimmable_water: case TerrainType.air: case TerrainType.ocean: case TerrainType.underground_swimmable_water: case TerrainType.underground_unswimmable_water: percent = 0; break; case TerrainType.field: percent += 5; break; case TerrainType.desert: percent += 10; break; case TerrainType.plane_of_earth: percent += 15; break; default: break; } if (percent > 75) { percent = 75; } else if (percent < 5) { percent = 5; } if (percent <= 0) { ch.SendText("There isn't any &n&+ydirt&n to kick.\r\n"); return; } ch.PracticeSkill("dirt toss"); if (percent < MUDMath.NumberPercent()) { Affect af = new Affect(); SocketConnection.Act("$n is &+Lblinded&n by the &n&+ydirt&n in $s eyes!", victim, null, null, SocketConnection.MessageTarget.room); SocketConnection.Act("$n kicks &n&+ydirt&n into your eyes!", ch, null, victim, SocketConnection.MessageTarget.victim); victim.SendText("&+LYou can't see a thing!&n\r\n"); af.Value = "dirt toss"; af.Type = Affect.AffectType.skill; af.Duration = MUDMath.NumberRange(1, 2); af.AddModifier(Affect.Apply.hitroll, -4); af.SetBitvector(Affect.AFFECT_BLIND); victim.AddAffect(af); } else { ch.SendText("&+LYou kick dirt at your target!&n\r\n"); } Combat.SetFighting(victim, ch); ch.WaitState(Skill.SkillList["dirt toss"].Delay); return; }
/// <summary> /// Attempt to trip a foe. Can initiate combat with this and can use during combat. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Trip(CharData ch, string[] str) { if( ch == null ) return; int chance; /* Check player's level and class, mobs can use this skill */ if ((!ch.HasSkill("trip"))) { ch.SendText("You would just fall over if you tried to trip someone.\r\n"); return; } if (ch.IsBlind()) { return; } CharData victim = ch.Fighting; if (str.Length != 0) { victim = ch.GetCharRoom(str[0]); if (!victim) { ch.SendText("You look around, unable to find them.\r\n"); return; } } else { if (!victim) { ch.SendText("You aren't fighting anyone.\r\n"); return; } } /* anti 'trip me' code */ if (victim == ch) { ch.SendText("You don't think you're clumsy enough already?\r\n"); return; } ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["trip"].Delay)); ch.PracticeSkill("trip"); if (ch.IsNPC()) { chance = (ch.Level * 3) / 2 + 10; } else { chance = ((PC)ch).SkillAptitude["trip"]; } if (chance > 90) { chance = 90; } if ((ch.Fighting == null) && (ch != victim)) { Combat.SetFighting(ch, victim); } if ((!victim.Fighting) && (victim != ch)) { Combat.SetFighting(victim, ch); } /* Mobs do NOT auto-trip! */ if (MUDMath.NumberPercent() < chance) { victim.WaitState((Skill.SkillList["trip"].Delay * 5 / 6)); SocketConnection.Act("You trip $N&n and send $M sprawling to the &n&+yearth&n!", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n trips you and you go down!", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n trips $N&n and $E falls face-first to the &n&+yground&n!", ch, null, victim, SocketConnection.MessageTarget.room_vict); if (victim.CurrentPosition > Position.reclining) { victim.CurrentPosition = Position.reclining; } } else { SocketConnection.Act("You try to trip $N&n and fall down!", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n attempts to knock you from your feet, and falls down $sself!", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n tries to trip $N&n and tumbles to the &n&+yground&n!", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.CurrentPosition = Position.reclining; } 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> /// Rescue command. Interpose yourself between the target and their opponent so you become /// the one taking damage. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Rescue(CharData ch, string[] str) { if( ch == null ) return; CharData victim; /* Don't allow the unskilled to rescue */ if ((!ch.HasSkill("rescue"))) { ch.SendText("You'd better leave the heroic acts to warriors.\r\n"); return; } if (ch.IsAffected(Affect.AFFECT_BERZERK)) { ch.SendText("You can't rescue anyone, you're in a &+RBl&n&+ro&+Ro&n&+rd&+L Rage&n!!\r\n"); return; } if (ch.Riding) { ch.SendText("You can't do that while mounted.\r\n"); return; } if (str.Length == 0) { ch.SendText("Rescue whom?\r\n"); return; } if (!(victim = ch.GetCharRoom(str[0]))) { ch.SendText("They aren't here.\r\n"); return; } if (victim == ch) { ch.SendText("What about fleeing instead?\r\n"); return; } if (ch.Fighting == victim) { ch.SendText("Too late.\r\n"); return; } if (!victim.Fighting) { ch.SendText("That person is not fighting right now.\r\n"); return; } if (ch.IsBlind()) { return; } ch.WaitState(Skill.SkillList["rescue"].Delay); int count = 0; CharData fighter = null; foreach (CharData ifch in ch.InRoom.People) { if (ifch.Fighting == victim) { if (MUDMath.NumberRange(0, count) == 0) { fighter = ifch; break; } ++count; } } if (!fighter || !ch.CheckSkill("rescue")) { SocketConnection.Act("$n&n fails miserably in $s attempt to rescue $N&n.", ch, null, victim, SocketConnection.MessageTarget.room_vict); SocketConnection.Act("$n&n fails miserably in $s attempt to rescue you.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("You fail in your attempt to rescue $N&n.", ch, null, victim, SocketConnection.MessageTarget.character); return; } SocketConnection.Act("&+WYou leap in front of $N&n!", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("&+W$n&+W rescues you!", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("&+w$n&+w leaps in front of $N&+w taking his place in battle!&n", ch, null, victim, SocketConnection.MessageTarget.room_vict); Combat.StopFighting(fighter, false); Combat.StopFighting(victim, false); Combat.SetFighting(fighter, ch); if (!ch.Fighting) { Combat.SetFighting(ch, fighter); } return; }
/// <summary> /// Springleap. Can be used to initiate combat and can be used during combat. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Springleap(CharData ch, string[] str) { if( ch == null ) return; int chance; /* Check player's level and class, mobs can use this skill */ if ((!ch.HasSkill("springleap"))) { ch.SendText("You'd better leave the martial arts to Bruce Lee.\r\n"); return; } if (ch.GetRace() == Race.RACE_CENTAUR) { ch.SendText("Your anatomy prevents you from springleaping.\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("You don't see them here.\r\n"); return; } } else { if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("You aren't fighting anyone.\r\n"); return; } } /* springleap self */ if (ch == victim) { ch.SendText("You can't quite figure out how to do that.\r\n"); return; } /* Check size of ch vs. victim. */ /* If ch is too small. */ if (ch.CurrentSize - 2 > victim.CurrentSize) { SocketConnection.Act("Your acrobatic maneuver cannot accurately leap into such a small being.", ch, null, victim, SocketConnection.MessageTarget.character); return; } /* Ch 2 or more sizes larger than victim => bad! */ if (ch.CurrentSize + 2 < victim.CurrentSize) { SocketConnection.Act("Your acrobatic maneuver does not seem to work on someone so large.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n jumps into you, and slides down your leg.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n jumps into $N&n and slides down $S leg.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.WaitState(Skill.SkillList["springleap"].Delay); ch.CurrentPosition = Position.reclining; if (victim.Fighting == null) { Combat.SetFighting(victim, ch); } return; } ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["springleap"].Delay)); ch.PracticeSkill("springleap"); if (ch.IsNPC()) { chance = (ch.Level * 3) / 2 + 15; } else { chance = ((PC)ch).SkillAptitude["springleap"] - 5; } if (chance > 95) { chance = 95; } if (victim.CurrentPosition < Position.fighting) { chance /= 4; } if (MUDMath.NumberPercent() < chance) { ch.CurrentPosition = Position.fighting; SocketConnection.Act("&+WYour springleap knocks $N&n&+W on $S butt.&n", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("&+W$n&n&+W leaps gracefully at $N&n&+W, sending $M to the ground.&n", ch, null, victim, SocketConnection.MessageTarget.room); SocketConnection.Act("&+W$n&n&+W leaps at you, knocking you to the ground!&n", ch, null, victim, SocketConnection.MessageTarget.victim); if (victim.IsAffected(Affect.AFFECT_SINGING)) { victim.RemoveAffect(Affect.AFFECT_SINGING); SocketConnection.Act("$n&n gasps and falls silent as $e falls over backward!", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("You abort your singing!\r\n"); } if (victim.IsAffected(Affect.AFFECT_CASTING)) { victim.RemoveAffect(Affect.AFFECT_CASTING); SocketConnection.Act("$n&n no longer has any idea what $e was casting.", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("Lying on the ground, you realize you have no idea what you were just casting.\r\n"); } if (!ch.Fighting) { Combat.SetFighting(ch, victim); } if (!victim.Fighting) { Combat.SetFighting(victim, ch); } if (!Combat.CheckTumble(victim)) { victim.WaitState((Skill.SkillList["springleap"].Delay * 5 / 6)); if (victim.CurrentPosition > Position.sitting) { victim.CurrentPosition = Position.sitting; } Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, ch.Level), "springleap", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } else { Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, (ch.Level / 3)), "springleap", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); ch.SendText("You roll with the blow, finally landing on your feet.\r\n"); SocketConnection.Act("$n&n rolls with the blow, finally landing on $s feet.", victim, null, null, SocketConnection.MessageTarget.room); } } else { bool pissedOff = false; if (ch.Fighting == victim || victim.GetCurrInt() > MUDMath.NumberPercent()) { pissedOff = true; } if (pissedOff) { SocketConnection.Act("As $N&n avoids your leap you crash to the ground.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n crashes to the ground as you avoid $s springleap.", ch, null, victim, SocketConnection.MessageTarget.victim); if (!ch.Fighting) { Combat.SetFighting(ch, victim); } if (!victim.Fighting) { Combat.SetFighting(victim, ch); } } else { SocketConnection.Act("You ungracefully leap at $N and miss, landing head first!", ch, null, victim, SocketConnection.MessageTarget.character); } SocketConnection.Act("$n&n misses a springleap and falls awkwardly to the ground.", ch, null, null, SocketConnection.MessageTarget.room); ch.CurrentPosition = Position.reclining; Combat.InflictDamage(ch, ch, MUDMath.NumberRange(1, 4), "springleap", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } return; }
/// <summary> /// Bodyslam an opponent. Can only be used to initiate combat. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Bodyslam(CharData ch, string[] str) { if( ch == null ) return; CharData victim; /* Check player's level and class, mobs can use this skill */ if (!ch.HasInnate(Race.RACE_BODYSLAM)) { ch.SendText("You don't feel massive enough to manhandle that.\r\n"); return; } if (ch.IsBlind()) { return; } if (ch.Riding) { ch.SendText("You can't do that while mounted.\r\n"); return; } if (str.Length != 0) { if (!(victim = ch.GetCharRoom(str[0])) || victim.CurrentPosition == Position.dead) { ch.SendText("They aren't here.\r\n"); return; } } else { ch.SendText("Bodyslam who?\r\n"); return; } // Added size restrictions -- Xangis if (victim.CurrentSize > ch.CurrentSize) { if (ch.HasInnate(Race.RACE_SLAM_LARGER)) { // allowing centaurs to slam one size up if it's an ogre if (victim.CurrentSize > (ch.CurrentSize + 1)) { ch.SendText("You can't bodyslam something that much bigger than you.\r\n"); return; } } else { ch.SendText("You can't bodyslam something bigger than you.\r\n"); return; } } if ((ch.CurrentSize > victim.CurrentSize) && ((ch.CurrentSize - victim.CurrentSize) > 3)) { ch.SendText("They're too small to slam.\r\n"); return; } /* Bodyslam self? Ok! */ if (ch == victim) { ch.SendText("You slam yourself to the ground!\r\n"); SocketConnection.Act("$n&n throws $mself to the ground in a fit of clumsiness.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.WaitState((Skill.SkillList["bodyslam"].Delay / 2)); ch.CurrentPosition = Position.reclining; Combat.InflictDamage(ch, ch, MUDMath.NumberRange(1, 6), "bodyslam", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); return; } ch.WaitState(Skill.SkillList["bodyslam"].Delay); ch.PracticeSkill("bodyslam"); int chance = (ch.Level * 3) / 2 + 15; chance += ch.GetCurrAgi() - victim.GetCurrAgi(); chance -= (victim.Level - ch.Level); switch (victim.CurrentPosition) { case Position.dead: return; case Position.mortally_wounded: chance += 15; break; case Position.incapacitated: chance += 10; break; case Position.unconscious: chance += 5; break; case Position.stunned: chance += 3; break; case Position.sleeping: chance += 2; break; case Position.reclining: chance -= 45; break; case Position.resting: chance -= 30; break; case Position.sitting: chance -= 20; break; case Position.kneeling: chance -= 15; break; case Position.fighting: case Position.standing: default: break; } // Small penalty for the small buggers -- Xangis if (victim.CurrentSize < (ch.CurrentSize - 1)) { chance -= 15; } if (chance > 90) { chance = 90; } // Shaman bodyslam penalty. if (ch.IsClass(CharClass.Names.shaman) || ch.IsClass(CharClass.Names.druid)) { chance = (chance * 2) / 3; } if (victim.IsAffected(Affect.AFFECT_AWARE)) { chance -= 15; } else if (victim.IsAffected( Affect.AFFECT_SKL_AWARE)) { if (ch.HasSkill("springleap")) { if (ch.IsNPC()) { if (MUDMath.NumberPercent() < ((ch.Level * 3) / 2 + 15)) { chance -= 15; } } else if (MUDMath.NumberPercent() < ((PC)ch).SkillAptitude["awareness"]) { ch.PracticeSkill("awareness"); chance -= 15; } else { ch.PracticeSkill("awareness"); } } } if (!ch.Fighting) { Combat.SetFighting(ch, victim); } if (victim.Fighting == null) { Combat.SetFighting(victim, ch); } if (ch.IsNPC() || MUDMath.NumberPercent() < chance) { if (victim.IsAffected( Affect.AFFECT_SINGING)) { victim.RemoveAffect(Affect.AFFECT_SINGING); SocketConnection.Act("$n&n suddenly loses track of the key $e was singing in.", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("You get the wind knocked out of you!\r\n"); } if (victim.IsAffected( Affect.AFFECT_CASTING)) { victim.RemoveAffect(Affect.AFFECT_CASTING); SocketConnection.Act("$n&n's thoughts of casting are scattered about as $e is slammed into the ground.", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("Your brain slamming against your skull disrupts your concentration.\r\n"); } // Moved damage to bottom because it would crash when a person died, because // it still tried to access them as a valid character. Also added tumble check for // thieves. if (!Combat.CheckTumble(victim)) { victim.WaitState(Skill.SkillList["bodyslam"].Delay); victim.CurrentPosition = Position.reclining; Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, ch.Level), "bodyslam", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } else { if (!Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, (ch.Level / 3)), "bodyslam", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon)) { ch.SendText("You roll with the blow, finally landing on your feet.\r\n"); SocketConnection.Act("$n&n rolls with the blow, finally landing on $s feet.", ch, null, null, SocketConnection.MessageTarget.room); } } } else { ch.Hitpoints -= MUDMath.NumberRange(1, 5); SocketConnection.Act("As $N&n avoids your slam, you smack headfirst into the &n&+yground&n.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n throws $mself to the &n&+yground&n in a fit of clumsiness.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n misses a bodyslam on $N&n and slams $s head into the &n&+yground&n.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.CurrentPosition = Position.reclining; } return; }
/// <summary> /// Pour a liquid. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Pour(CharData ch, string[] str) { if( ch == null ) return; Object obj; string arg1 = String.Empty; string arg2 = String.Empty; if (ch.IsBlind()) return; if (!(obj = ch.GetObjCarrying(arg1))) { ch.SendText("You do not have that item.\r\n"); return; } if (obj.ItemType != ObjTemplate.ObjectType.drink_container) { ch.SendText("You can't fill that.\r\n"); return; } if (!MUDString.StringsNotEqual("out", arg2)) { ch.SendText("You pour it out.\r\n"); obj.Values[1] = 0; return; } Object otherobj = ch.GetObjHere(arg2); if (!otherobj) { ch.SendText("Pour it where?\r\n"); return; } if (otherobj.Values[2] != obj.Values[2] && otherobj.Values[1] != 0) { ch.SendText("It's got another liquid in it.\r\n"); return; } SocketConnection.Act("You fill $p&n.", ch, otherobj, null, SocketConnection.MessageTarget.character); otherobj.Values[2] = obj.Values[2]; otherobj.Values[1] += obj.Values[1]; obj.Values[1] = 0; // Over pour in code => just pour it back in the first container. if (otherobj.Values[1] > otherobj.Values[0]) { obj.Values[1] = otherobj.Values[1] - otherobj.Values[0]; otherobj.Values[1] = otherobj.Values[0]; } return; }
/// <summary> /// Looks at an object, mobile, or room. /// </summary> /// <param name="ch">The acting character.</param> /// <param name="str">Command arguments.</param> public static void LookCommand(CharData ch, string[] str) { if( ch == null ) return; // Build argument list, stripping articles. bool inside = false; List<String> args = new List<string>(str); for (int i = (args.Count - 1); i >= 0; i-- ) { if (args[i].Equals("in", StringComparison.CurrentCultureIgnoreCase) || args[i].Equals("i", StringComparison.CurrentCultureIgnoreCase)) { args.RemoveAt(i); inside = true; } else if (args[i].Equals("at", StringComparison.CurrentCultureIgnoreCase)) { args.RemoveAt(i); } } // If it's a mob that isn't switched, bail. if (ch.Socket == null) return; if (ch.CurrentPosition < Position.sleeping) { ch.SendText("&nYou can't see anything but &+Ystars&n! See how pretty!\r\n"); return; } if (ch.CurrentPosition == Position.sleeping) { ch.SendText("&nYou can't see anything, you're &+Lsleeping&n! Zzz.\r\n"); return; } if (ch.IsBlind()) return; // Look panel for ships. if ( args.Count > 0 && args[0].Equals("panel", StringComparison.CurrentCultureIgnoreCase)) { CommandType.Interpret(ch, "Lookpanel"); return; } // Look out for ships. if (args.Count > 0 && args[0].Equals("out", StringComparison.CurrentCultureIgnoreCase)) { CommandType.Interpret(ch, "Lookout"); return; } Object obj; Exit exit; string pdesc; int number = 0; string output = String.Empty; // 'look' or 'look auto' or 'look room' if (args.Count == 0 || args[0].Equals( "auto", StringComparison.CurrentCultureIgnoreCase) || args[0].Equals("room", StringComparison.CurrentCultureIgnoreCase)) { if (ch.InRoom == null) { ch.SendText("You are not in a room. You are just floating in empty space. This should never happen. You should <petition> someone for help.\r\n"); Log.Error("Character executing Commandlook command from null room: " + ch.Name); return; } if (ch.FlightLevel > 0) { switch (ch.FlightLevel) { case CharData.FlyLevel.low: ch.SendText("Hovering above "); break; case CharData.FlyLevel.medium: ch.SendText("Flying above "); break; case CharData.FlyLevel.high: ch.SendText("Flying high above "); break; } } if (!ch.HasActionBit(PC.PLAYER_GODMODE) && ch.InRoom.IsDark() && !ch.HasInnate(Race.RACE_ULTRAVISION) && !ch.IsAffected( Affect.AFFECT_ULTRAVISION)) { ch.SendText("&+lSomewhere\r\n"); } else if (!ch.HasActionBit(PC.PLAYER_GODMODE)) { String roomOpen = String.Empty; String roomClose = String.Empty; if (!ch.IsNPC() && ch.Socket.Terminal == SocketConnection.TerminalType.TERMINAL_ENHANCED) { roomOpen = "<zone>" + ch.InRoom.Area.Name + "</zone><roomTitle>"; roomClose = "</roomTitle>"; } else { roomClose = "&n\r\n"; } // Added support for both manual and automatic descriptions on the worldmap. if (!ch.InRoom.Area.HasFlag(Area.AREA_WORLDMAP) || ch.InRoom.Title.Length > 1) { output += roomOpen + ch.InRoom.Title + roomClose; } else { output += roomOpen + "No room title." + roomClose; } } else { if (!ch.IsNPC() && ch.Socket.Terminal == SocketConnection.TerminalType.TERMINAL_ENHANCED) { ch.SendText("<zone>" + ch.InRoom.Area.Name + "</zone>"); } Look.ShowRoomInfo(ch, ch.InRoom); } if (!ch.IsNPC() && !ch.HasActionBit(PC.PLAYER_GODMODE) && ch.InRoom.IsDark() && !ch.HasInnate(Race.RACE_ULTRAVISION) && !ch.IsAffected( Affect.AFFECT_ULTRAVISION)) { ch.SendText("&+LIt is pitch black...&n \r\n"); Look.ShowCharacterToCharacter(ch.InRoom.People, ch); return; } if (!ch.IsNPC() && (args.Count > 0 && (args[0].Equals("room", StringComparison.CurrentCultureIgnoreCase) || args[0].Equals("auto", StringComparison.CurrentCultureIgnoreCase)))) { String roomDescOpen = String.Empty; String roomDescClose = String.Empty; String mapSpace = String.Empty; if (!ch.IsNPC() && ch.Socket.Terminal == SocketConnection.TerminalType.TERMINAL_ENHANCED) { roomDescOpen = "<roomDescription>"; roomDescClose = "</roomDescription>"; } else { roomDescClose = "&n\r\n"; mapSpace = " "; } if( !ch.HasActionBit(PC.PLAYER_BRIEF) && !ch.InRoom.Area.HasFlag(Area.AREA_WORLDMAP)) { // Added support for both manual and automatic descriptions on the worldmap. if (ch.InRoom.Description.Length > 0) { output += roomDescOpen + " " + (ch.InRoom.Description.Trim()) + roomDescClose; } //else if (ch._inRoom.WorldmapTerrainType < Database.SystemData.MapInfo.Length) // output += roomDescOpen + mapSpace + Database.SystemData.MapInfo[ch._inRoom.WorldmapTerrainType].RoomDescription + roomDescClose; else { output += roomDescOpen + " No room description." + roomDescClose; } } } if (!String.IsNullOrEmpty(output)) { ch.SendText(output); } if (ch.InRoom.Area.HasFlag(Area.AREA_WORLDMAP)) { if (ch.HasActionBit(PC.PLAYER_MAP)) { Command.Worldmap(ch, null); } else if (!ch.IsNPC() && ch.Socket.Terminal != SocketConnection.TerminalType.TERMINAL_ENHANCED) { ch.SendText("\r\n"); } } if (ch.InRoom.HasFlag(RoomTemplate.ROOM_SILENT)) { ch.SendText("&nIt seems preternaturally quiet.\r\n"); } CommandType.Interpret(ch, "exits auto"); Look.ShowRoomAffects(ch, ch.InRoom); Look.ShowListToCharacter(ch.InRoom.Contents, ch, false, false); Look.ShowCharacterToCharacter(ch.InRoom.People, ch); return; } // 'look direction' int door = -1; if (args.Count > 0) { if ("north".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 0; else if ("east".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 1; else if ("south".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 2; else if ("west".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 3; else if ("up".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 4; else if ("down".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 5; else if ("northwest".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 6; else if ("southwest".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 7; else if ("northeast".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 8; else if ("southeast".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 9; else if ("nw".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 6; else if ("sw".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 7; else if ("ne".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 8; else if ("se".StartsWith(args[0], StringComparison.CurrentCultureIgnoreCase)) door = 9; } if (door != -1) { // If no exit data, then return. exit = ch.InRoom.ExitData[door]; if (!exit) { ch.SendText("There's nothing to see in that direction.\r\n"); return; } if (exit.HasFlag(Exit.ExitFlag.walled)) { ch.SendText("There's a wall in the way.\r\n"); return; } // Check for farsee if ((ch.IsAffected( Affect.AFFECT_FARSEE) || ch.HasActionBit(PC.PLAYER_GODMODE)) && !exit.HasFlag(Exit.ExitFlag.closed)) { if (exit.TargetRoom) { Room room = ch.InRoom; ch.RemoveFromRoom(); ch.AddToRoom(Room.GetRoom(exit.IndexNumber)); CommandType.Interpret(ch, "look"); ch.RemoveFromRoom(); ch.AddToRoom(room); return; } ch.SendText("Nothing special there.\r\n"); } if (exit.Description.Length != 0) { ch.SendText(exit.Description); } else { ch.SendText("Nothing special there.\r\n"); } if (exit.Keyword.Length != 0) { if (exit.HasFlag(Exit.ExitFlag.bashed)) SocketConnection.Act("The $d has been bashed from its &n&+whinges&n.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); else if (exit.HasFlag(Exit.ExitFlag.closed)) SocketConnection.Act("The $d is closed.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); else if (exit.HasFlag(Exit.ExitFlag.secret)) SocketConnection.Act("The $d is secret.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); else if (exit.HasFlag(Exit.ExitFlag.blocked)) SocketConnection.Act("The $d is blocked.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); } else { if (exit.HasFlag(Exit.ExitFlag.bashed)) { SocketConnection.Act("The door has been bashed from its &n&+whinges&n.", ch, null, null, SocketConnection.MessageTarget.character); } else if (exit.HasFlag(Exit.ExitFlag.closed)) SocketConnection.Act("The door is closed.", ch, null, null, SocketConnection.MessageTarget.character); else if (exit.HasFlag(Exit.ExitFlag.is_door)) SocketConnection.Act("The door is open.", ch, null, null, SocketConnection.MessageTarget.character); else if (exit.HasFlag(Exit.ExitFlag.secret)) SocketConnection.Act("The door is secret.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); else if (exit.HasFlag(Exit.ExitFlag.blocked)) SocketConnection.Act("The $d is blocked.", ch, null, exit.Keyword, SocketConnection.MessageTarget.character); } // If exit found, don't keep looking. return; } // Look inside something ('look in'). if (inside) { // 'look in' if (args.Count < 1) { ch.SendText("Look in what?\r\n"); return; } obj = ch.GetObjHere(args[0]); if (!obj) { ch.SendText("You do not see that here.\r\n"); return; } switch (obj.ItemType) { default: ch.SendText("That is not a container.\r\n"); break; case ObjTemplate.ObjectType.drink_container: if (obj.Values[1] == -1) { ch.SendText("It is full.\r\n"); break; } if (obj.Values[1] <= 0) { ch.SendText("It is empty.\r\n"); break; } output += "It's "; if (obj.Values[1] < obj.Values[0] / 4) output += "less than half"; else if (obj.Values[1] < (3 * obj.Values[0] / 4)) output += "about half"; else if (obj.Values[1] < obj.Values[0]) output += "more than half"; else output += "completely"; output += " full of a " + Liquid.Table[obj.Values[2]].Color + "liquid.\r\n"; ch.SendText(output); break; case ObjTemplate.ObjectType.quiver: case ObjTemplate.ObjectType.container: case ObjTemplate.ObjectType.npc_corpse: case ObjTemplate.ObjectType.pc_corpse: if (Macros.IsSet(obj.Values[1], ObjTemplate.CONTAINER_CLOSED.Vector)) { ch.SendText("It is closed.\r\n"); break; } SocketConnection.Act("$p&n contains:", ch, obj, null, SocketConnection.MessageTarget.character, true); Look.ShowListToCharacter(obj.Contains, ch, true, true); break; case ObjTemplate.ObjectType.portal: SocketConnection.Act("A $p&n leads to:", ch, obj, null, SocketConnection.MessageTarget.character); output += Room.GetRoom(obj.Values[0]).Title + "\r\n"; output += Room.GetRoom(obj.Values[0]).Description; output += "\r\n"; ch.SendText(output); break; } return; } // Look at another char. if (args.Count > 0) { CharData victim = ch.GetCharRoom(args[0]); if (victim != null) { Look.ShowCharacterToCharacterFull(victim, ch); return; } } // Look at an object. if (args.Count > 0) { // Check inventory. obj = ch.GetObjCarrying(args[0]); // If not in inventory, check eq. if (obj == null) obj = ch.GetObjWear(args[0]); // If not on character, check room. if (obj == null) obj = Object.GetObjFromList(ch.InRoom.Contents, ch, args[0]); // If object found, show it to the char. if (obj != null) { pdesc = (Database.GetExtraDescription(args[0], obj.ExtraDescription)); if (pdesc.Length != 0) { ch.SendText(pdesc); } else if ((pdesc = (Database.GetExtraDescription(args[0], obj.ObjIndexData.ExtraDescriptions))).Length > 0) { ch.SendText(pdesc); } else if (obj.FullDescription.Length > 0) { ch.SendText(obj.FullDescription); ch.SendText("\r\n"); } if (obj.HasAffect(Affect.AffectType.skill, "poison weapon")) { if (ch.IsClass(CharClass.Names.thief) || ch.IsClass(CharClass.Names.assassin) || MUDMath.NumberPercent() < ch.GetCurrInt() / 2) ch.SendText("It has a &+Gsickly &+Lcolored&n hue.\r\n"); } return; } } // Look at an object in the room if (args.Count > 0) { int count = 0; foreach (Object iobj in ch.InRoom.Contents) { if (CharData.CanSeeObj(ch, iobj)) { pdesc = (Database.GetExtraDescription(args[0], iobj.ExtraDescription)); if (pdesc.Length != 0) { if (++count == number) { ch.SendText(pdesc); return; } continue; } pdesc = (Database.GetExtraDescription(args[0], iobj.ObjIndexData.ExtraDescriptions)); if (pdesc.Length != 0) { if (++count == number) { ch.SendText(pdesc); return; } continue; } if (MUDString.NameContainedIn(args[0], iobj.Name)) { if (++count == number) { ch.SendText(iobj.FullDescription); ch.SendText("\r\n"); return; } continue; } } } } // Check for room extra descriptions if (args.Count > 0) { pdesc = (Database.GetExtraDescription(args[0], ch.InRoom.ExtraDescriptions)); if (!String.IsNullOrEmpty(pdesc)) { ch.SendText(pdesc); return; } } ch.SendText("You do not see that here.\r\n"); return; }
public static void Fill(CharData ch, string[] str) { if( ch == null ) return; Object fountain = null; if (ch.IsBlind()) { ch.SendText("You can't see what you're trying to fill.\r\n"); return; } if (str.Length == 0) { ch.SendText("Fill what?\r\n"); return; } Object obj = ch.GetObjCarrying(str[0]); if (!obj) { ch.SendText("You do not have that item.\r\n"); return; } bool found = false; foreach (Object fount in ch.InRoom.Contents) { if (fount.FlyLevel != ch.FlightLevel) continue; if (fount.ItemType == ObjTemplate.ObjectType.drink_container) { fountain = fount; found = true; break; } } if (!found) { ch.SendText("There is nothing to fill from here!\r\n"); return; } if (obj.ItemType != ObjTemplate.ObjectType.drink_container) { ch.SendText("You can't fill that.\r\n"); return; } if (obj.Values[1] != 0 && obj.Values[2] != fountain.Values[2]) { ch.SendText("There is already another liquid in it.\r\n"); return; } if (obj.Values[1] >= obj.Values[0]) { ch.SendText("Your container is full.\r\n"); return; } SocketConnection.Act("You fill $p&n.", ch, obj, null, SocketConnection.MessageTarget.character); obj.Values[2] = fountain.Values[2]; obj.Values[1] = obj.Values[0]; return; }
public static void WherePlayer(CharData ch, string[] str) { if( ch == null ) return; CharData victim; SocketConnection socket; string buf; bool found; if (ch.IsBlind()) return; if (str.Length == 0) { ch.SendText("&nPlayers near you:\r\n"); found = false; foreach (SocketConnection it in Database.SocketList) { socket = it; if (socket.ConnectionStatus == SocketConnection.ConnectionState.playing && (victim = socket.Character) && !victim.IsNPC() && victim.InRoom && victim.InRoom.Area == ch.InRoom.Area && CharData.CanSee(ch, victim)) { found = true; buf = String.Format("%{0} {1}\r\n", MUDString.PadStr(victim.Name, 28), victim.InRoom.Title); ch.SendText(buf); } } if (!found) ch.SendText("None\r\n"); } else if (!MUDString.IsPrefixOf(str[0], "all")) { ch.SendText("&nPlayer locations:\r\n"); found = false; foreach (SocketConnection it in Database.SocketList) { socket = it; if (socket.ConnectionStatus == SocketConnection.ConnectionState.playing && (victim = socket.Character) && !victim.IsNPC() && victim.InRoom && CharData.CanSee(ch, victim)) { found = true; buf = String.Format("{0} [{1}]{2}&n\r\n", MUDString.PadStr(victim.Name, 28), MUDString.PadInt(victim.InRoom.IndexNumber, 7), victim.InRoom.Title); ch.SendText(buf); } } if (!found) ch.SendText("None\r\n"); } else { found = false; foreach (CharData it in Database.CharList) { victim = it; if (victim.InRoom.Area == ch.InRoom.Area && CharData.CanSee(ch, victim) && MUDString.NameContainedIn(str[0], victim.Name)) { found = true; buf = String.Format("{0} {1}\r\n", MUDString.PadStr(victim.ShowNameTo(ch, true), 28), victim.InRoom.Title); ch.SendText(buf); break; } } if (!found) SocketConnection.Act("&nYou didn't find any $T.", ch, null, str[0], SocketConnection.MessageTarget.character); } return; }
/// <summary> /// Stab someone in the back. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Backstab(CharData ch, string[] str) { if( ch == null ) return; if (!ch.HasSkill("backstab")) { ch.SendText("You better leave the assassination trade to those more skilled.\r\n"); return; } if (ch.IsBlind()) { return; } if (ch.Riding) { ch.SendText("You can't get close enough while mounted.\r\n"); return; } if (str.Length == 0) { ch.SendText("Backstab whom?\r\n"); return; } CharData victim = ch.GetCharRoom(str[0]); if (!victim) { ch.SendText("They aren't here.\r\n"); return; } if (victim == ch) { ch.SendText("How can you sneak up on yourself?\r\n"); return; } Combat.Backstab(ch, victim); return; }
/// <summary> /// Charge into someone. Helps to have horns on your head. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Charge(CharData ch, string[] str) { if( ch == null ) return; CharData victim; /* Check player's level and class, mobs can use this skill */ if (!ch.HasInnate(Race.RACE_CHARGE)) { ch.SendText("You can't do that.\r\n"); return; } if (ch.IsBlind()) { return; } if (str.Length != 0) { if (!(victim = ch.GetCharRoom(str[0])) || victim.CurrentPosition == Position.dead) { ch.SendText("They aren't here.\r\n"); return; } } else { ch.SendText("Charge who?\r\n"); return; } /* charge me trap */ if (ch == victim) { ch.SendText("You chase your tail for a while.\r\n"); return; } ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["charge"].Delay)); if (!ch.Fighting) { Combat.SetFighting(ch, victim); } if (!victim.Fighting) { Combat.SetFighting(victim, ch); } // Chance is based on level of charger and victim. int chance = (ch.Level * 2) - victim.Level + 25; if (chance > 95) { chance = 95; } if (ch.IsNPC() || MUDMath.NumberPercent() < chance) { Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, ch.Level), "charge", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } else { Combat.InflictDamage(ch, victim, 0, "charge", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } return; }
/// <summary> /// Bash. Usable to initiate combat and during combat. /// </summary> /// <param name="ch"></param> /// <param name="str"></param> public static void Bash(CharData ch, string[] str) { if( ch == null ) return; int chance; /* Check player's level and class, mobs can use this skill */ if ((!ch.HasSkill("bash"))) { ch.SendText("You'd better leave that to those with more skills.\r\n"); return; } if (ch.IsBlind() && !ch.Fighting) { return; } /* Verify a target. */ CharData victim = ch.Fighting; if (str.Length != 0) { victim = ch.GetCharRoom(str[0]); if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("They aren't anywhere to be found.\r\n"); return; } } else { if (!victim || victim.CurrentPosition == Position.dead) { ch.SendText("You aren't fighting anyone.\r\n"); return; } } /* Bash self? Ok! */ // Toned down the damage cuz you can't really bash yourself // like you could with someone else. if (victim == ch) { ch.SendText("You throw yourself to the ground!\r\n"); SocketConnection.Act("$N&n knocks $mself to the ground.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.CurrentPosition = Position.kneeling; ch.WaitState((Skill.SkillList["bash"].Delay * 8) / 10); Combat.InflictDamage(ch, ch, MUDMath.NumberRange(1, 3), "bash", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); return; } /* Check size of ch vs. victim. */ /* If ch is too small. */ if (ch.CurrentSize < victim.CurrentSize) { SocketConnection.Act("$N&n is too big for you to bash!", ch, null, victim, SocketConnection.MessageTarget.character); return; } /* Ch 2 or more sizes larger than victim => bad! */ if (ch.CurrentSize - 2 > victim.CurrentSize) { SocketConnection.Act("You nearly topple over as you try to bash $N&n.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n nearly topples over as $e attempts to bash you.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n nearly topples over as $e attempts to bash $N&n.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.WaitState((Skill.SkillList["bash"].Delay)); ch.CurrentPosition = Position.kneeling; if (victim.Fighting == null) { Combat.SetFighting(victim, ch); } return; } /* Lag to basher from bash. Pets get more lag because pets are cheesy */ if (!ch.IsNPC()) { ch.WaitState(MUDMath.FuzzyNumber(Skill.SkillList["bash"].Delay)); } else { ch.WaitState((Skill.SkillList["bash"].Delay * 6 / 5)); } /* Base chance to bash, followed by chance modifications. */ if (ch.IsNPC()) { chance = (ch.Level * 3) / 2 + 15; } else { chance = ((PC)ch).SkillAptitude["bash"] - 5; } if (victim.CurrentPosition < Position.fighting) { chance /= 5; //used to be 0 } else { chance += ch.GetCurrAgi() - victim.GetCurrAgi(); } if (chance > 95) { chance = 95; } Object obj = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_one); if (!obj) { /* No primary item. */ if (!(obj = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_two))) { /* No items in hand. */ if (!ch.IsClass(CharClass.Names.paladin) && !ch.IsClass(CharClass.Names.antipaladin)) { if (!ch.IsClass(CharClass.Names.warrior)) { chance -= 25; } else { chance -= 20; } ch.SendText("You lower your shoulder and attempt to bash without a shield...\r\n"); } else { chance -= 3; // Hidden penalty for not having a shield } } else if (obj.ItemType != ObjTemplate.ObjectType.shield) { /* Secondary item isn't a shield, no primary. */ if (!ch.IsClass(CharClass.Names.paladin) && !ch.IsClass(CharClass.Names.antipaladin)) { if (!ch.IsClass(CharClass.Names.warrior)) { chance -= 25; } else { chance -= 20; } ch.SendText("Bashing without a shield is tough, but you try anyway...\r\n"); } else { chance -= 5; // Small hidden penalty for not having a shield } } /* Secondary item is a shield, no primary. */ else if (ch.IsClass(CharClass.Names.paladin) || ch.IsClass(CharClass.Names.antipaladin)) { chance += 3; // Small hidden bonus for having a shield } } else if (obj.ItemType != ObjTemplate.ObjectType.shield) { /* Primary item isn't a shield. */ if (!(obj = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_two))) { /* No secondary. */ if (!ch.IsClass(CharClass.Names.paladin) && !ch.IsClass(CharClass.Names.antipaladin)) { if (!ch.IsClass(CharClass.Names.warrior)) { chance -= 25; } else { chance -= 20; } ch.SendText("Without a shield, bashing is a wistful thought, but you try anyway...\r\n"); } else { chance -= 5; // Hidden penalty for not having a shield } } else if (obj.ItemType != ObjTemplate.ObjectType.shield) { /* Secondary item is not a shield. */ if (!ch.IsClass(CharClass.Names.paladin) && !ch.IsClass(CharClass.Names.antipaladin)) { if (!ch.IsClass(CharClass.Names.warrior)) { chance -= 25; } else { chance -= 20; } ch.SendText("Without a shield, your shoulder bash is but wishful thinking...\r\n"); } else { chance -= 5; // Hidden penalty for not having a shield } } else if (ch.IsClass(CharClass.Names.paladin) || ch.IsClass(CharClass.Names.antipaladin)) { /* Secondary is a shield. */ chance += 3; // Small hidden bonus for having a shield } else if (ch.IsClass(CharClass.Names.ranger)) { chance -= 8; } else if (ch.IsClass(CharClass.Names.warrior)) { chance -= 5; } } // Centaurs are awful damned hard to bash -- Xangis if (victim.GetRace() == Race.RACE_CENTAUR) { chance -= 25; } // damned high penalty for bashing blind if (ch.IsAffected(Affect.AFFECT_BLIND) && !victim.IsAffected(Affect.AFFECT_BLIND)) { chance /= 10; } if (ch.IsAffected(Affect.AFFECT_BLIND) && victim.IsAffected(Affect.AFFECT_BLIND)) { chance /= 4; } ch.PracticeSkill("bash"); /* Start a fight if not already in one. */ if (ch != victim) { if (!ch.Fighting) { Combat.SetFighting(ch, victim); } if (!victim.Fighting) { Combat.SetFighting(victim, ch); } } string lbuf = "Bash: " + ch.Name + " bashing " + victim.Name + " with " + chance + " chance."; ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, lbuf); /* Do the bash, deal the damage. */ if (MUDMath.NumberPercent() < chance) { /* Hit the bash. */ if (victim.IsAffected(Affect.AFFECT_SINGING)) { victim.RemoveAffect(Affect.AFFECT_SINGING); SocketConnection.Act("$n&n chokes on a note and falls silent as $e slams into the ground!", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("You abort your singing!\r\n"); } if (victim.IsAffected(Affect.AFFECT_CASTING)) { victim.RemoveAffect(Affect.AFFECT_CASTING); SocketConnection.Act("$n&n's eyes roll back in $s head and $e forgets all about $s spell.", victim, null, null, SocketConnection.MessageTarget.room); victim.SendText("Being knocked over so forcefully makes it hard to cast.\r\n"); } if (!Combat.CheckTumble(victim)) { victim.WaitState(((Skill.SkillList["bash"].Delay * 5) / 6)); if (victim.CurrentPosition > Position.kneeling) { victim.CurrentPosition = Position.kneeling; } victim.SendText("You are knocked to the ground!\r\n"); Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, ch.Level), "bash", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); } else { Combat.InflictDamage(ch, victim, MUDMath.NumberRange(1, (ch.Level / 3)), "bash", ObjTemplate.WearLocation.none, AttackType.DamageType.bludgeon); victim.SendText("You roll with the blow, finally landing on your feet.\r\n"); SocketConnection.Act("$n&n rolls with the blow, finally landing on $s feet.", victim, null, null, SocketConnection.MessageTarget.room); } } else { /* Miss the bash. */ SocketConnection.Act("As $N&n avoids your bash, you topple to the &n&+yground&n with a loud crash.", ch, null, victim, SocketConnection.MessageTarget.character); SocketConnection.Act("$n&n crashes to the &n&+yground&n as you sidestep $s bash.", ch, null, victim, SocketConnection.MessageTarget.victim); SocketConnection.Act("$n&n misses $s bash at $N&n and is driven to the &n&+yground&n.", ch, null, victim, SocketConnection.MessageTarget.room_vict); ch.CurrentPosition = Position.kneeling; } return; }
/// <summary> /// The backstab function was cloned from Command.Backstab for use by mobile AI code. /// the difference is that a mob that wants to backstab already knows their /// victim, so no need for the argument stuff /// /// Modified by to allow auto-stab for backstabbers with aggr_level set. Called /// from Commandbackstab() /// /// Added ability to stab if piercer is secondary. Useful for mercs. /// /// Reduced damage for bards and mercs. /// </summary> /// <param name="ch"></param> /// <param name="victim"></param> /// <returns></returns> public static bool Backstab(CharData ch, CharData victim) { Object obj; Object obj2; int chance = 0; int stabChance; // Can't stab if lacking the skill if (!ch.HasSkill("backstab")) { ch.SendText("Leave backstabbing to the assassins!\r\n"); return false; } if (victim == null) { ch.SendText("Pick a target!\r\n"); return false; } // Can't stab if blind if (ch.IsBlind()) return false; // Can't stab on horseback if (ch.Riding) { ch.SendText("You can't get close enough while mounted.\r\n"); return false; } // Can't stab yourself if (victim == ch) return false; victim = CheckGuarding(ch, victim); if (IsSafe(ch, victim)) return false; // is_safe could wipe out victim, as it calls procs if a boss // check and see that victim is still valid if (!victim) return false; /* Check size of ch vs. victim. */ if (victim.CurrentPosition > Position.sleeping) { /* If ch is more than 2 sizes smaller it's too small. */ if ((ch.CurrentSize - 2) > victim.CurrentSize && victim.CurrentPosition >= Position.stunned && !(ch.IsNPC() && ch.MobileTemplate.IndexNumber == 10165)) { ch.SendText("Such tiny beings evade your skills.\r\n"); return false; } /* Ch 2 or more sizes larger than victim => bad! */ if ((ch.CurrentSize + 2) < victim.CurrentSize && victim.CurrentPosition >= Position.stunned) { ch.SendText("It is rather ineffective to stab someone in the calf.\r\n"); return false; } } ObjTemplate.WearLocation hand = 0; if ((obj = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_one)) && obj.ItemType == ObjTemplate.ObjectType.weapon && (AttackType.Table[obj.Values[3]].SkillName) == "1h piercing") hand = ObjTemplate.WearLocation.hand_one; if (hand == 0 && (obj2 = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_two)) && obj2.ItemType == ObjTemplate.ObjectType.weapon && (AttackType.Table[obj2.Values[3]].SkillName) == "1h piercing") hand = ObjTemplate.WearLocation.hand_two; if (hand == 0) { ch.SendText("You need to wield a piercing weapon.\r\n"); return false; } if (!ch.IsNPC()) ch.PracticeSkill("backstab"); Crime.CheckAttemptedMurder(ch, victim); ch.WaitState(Skill.SkillList["backstab"].Delay); if (ch.IsNPC()) { stabChance = 2 * ch.Level; } else { stabChance = ((PC)ch).SkillAptitude["backstab"]; } if (Math.Abs(ch.CurrentSize - victim.CurrentSize) == 2) stabChance -= 10; switch (victim.CurrentPosition) { default: break; case Position.mortally_wounded: case Position.incapacitated: case Position.unconscious: stabChance += 80; break; case Position.stunned: case Position.sleeping: stabChance += 40; break; case Position.reclining: stabChance += 20; break; case Position.resting: case Position.sitting: stabChance += 10; break; } //end switch // Half as likely to succeed on those that are aware if (victim.IsAffected(Affect.AFFECT_AWARE) || victim.IsAffected( Affect.AFFECT_SKL_AWARE)) { chance /= 2; } string lbuf = String.Format("Command.Backstab: {0} is attempting with a {1}%% chance.", ch.Name, stabChance); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, lbuf); if (MUDMath.NumberPercent() < stabChance) { /* First hit on backstab. Check for instant kill. - Xangis */ if (ch.HasSkill("instant kill")) { if (!ch.IsNPC()) chance = ((PC)ch).SkillAptitude["instant kill"]; else chance = (ch.Level * 3) / 2 + 20; // People over level 50 get a bonus, equates to about 1-2% if (ch.Level > 50) chance += 25; chance += (ch.Level - victim.Level); // Immortals will get a bonus too if (ch.IsImmortal()) chance *= 4; // Half as likely to succeed on those that are aware if (victim.IsAffected(Affect.AFFECT_AWARE) || victim.IsAffected(Affect.AFFECT_SKL_AWARE)) { chance /= 2; } if (MUDMath.NumberRange(1, 20000) < chance) { if (!ch.IsNPC()) ch.PracticeSkill("instant kill"); { lbuf = String.Format("backstab: {0} hit an instakill on {1} with a {2} chance in hundredths of a percent.", ch.Name, victim.Name, (chance / 30)); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, lbuf); Log.Trace(lbuf); ch.WaitState(15); SingleAttack(ch, victim, "instant kill", hand); return true; } } } SingleAttack(ch, victim, "backstab", hand); /* No double stabs when the first stab kills'm. */ if (victim.CurrentPosition == Position.dead) return true; /* Case of thieves/assassins doing a double backstab. */ obj = Object.GetEquipmentOnCharacter(ch, ObjTemplate.WearLocation.hand_two); /* Stop 2nd-hand non-pierce backstabs. */ if (!ch.IsNPC() && (obj != null) && (hand != ObjTemplate.WearLocation.hand_two) && obj.ItemType == ObjTemplate.ObjectType.weapon && (AttackType.Table[obj.Values[3]].SkillName) == "1h piercing") { /* Thieves get 1/2 chance at double, assassins get 2/3. */ // Xangis - removed double stab for thieves 6-9-00 if ((ch.IsClass(CharClass.Names.assassin)) && (MUDMath.NumberPercent() < ((PC)ch).SkillAptitude["backstab"] * 2 / 3)) { lbuf = String.Format("backstab: {0} hit a double backstab.", ch.Name); ImmortalChat.SendImmortalChat(null, ImmortalChat.IMMTALK_SPAM, 0, lbuf); SingleAttack(ch, victim, "backstab", ObjTemplate.WearLocation.hand_two); } } } else /* Send a "you miss your backstab" messge & engage. */ { InflictDamage(ch, victim, 0, "backstab", ObjTemplate.WearLocation.hand_one, AttackType.DamageType.pierce); } return true; }